| name | Implement Video Question |
| description | Create D3 questions where students watch a video and provide written responses. The video is the primary instructional content. |
Implement Video Question
Use this skill when creating questions where students:
- Watch a video as the primary instructional content
- Provide written reflections based on the video
- Answer questions about what they observed in the video
When to Use This Pattern
Perfect for:
- "Watch this video and explain the main concept"
- Video-based instruction followed by reflection questions
- Visual demonstrations requiring written analysis
- Questions where the video IS the lesson content
Not suitable for:
- Text-only reflections without video → use implement-text-response-question
- Video as optional help/hint → use
createVideoAccordion()from shared snippets - Interactive controls + optional video help → use other question types with video accordion
Distinction from Text Response Questions
| Feature | Video Question | Text Response Question |
|---|---|---|
| Primary content | Video is the lesson | Static text/images or no media |
| Video role | Required, main instruction | Optional or absent |
| Interaction | Watch → Respond | Read/Analyze → Respond |
| Snippet | video-response.js | No snippet (uses cards directly) |
Components Required
Copy these from .claude/skills/question-types/:
Required
implement-video-question/snippets/video-response.js→createVideoResponseQuestion()snippets/cards/standard-card.js→createStandardCard()snippets/cards/video-player.js→createVideoPlayer()snippets/cards/explanation-card.js→createExplanationCard()
Quick Start
- Review the pattern guide: PATTERN.md
- Study the snippet: snippets/video-response.js
- Copy from a working example:
cat courses/IM-8th-Grade/modules/Unit-3/assignments/161-Proportion-Graphs/questions/01/attachments/chart.js
Working Examples
Reference these codebase files:
courses/IM-8th-Grade/modules/Unit-3/assignments/161-Proportion-Graphs/questions/01/attachments/chart.js
courses/IM-8th-Grade/modules/Unit-3/assignments/510-Proportion-Equations/questions/01/attachments/chart.js
courses/IM-8th-Grade/modules/Unit-3/assignments/Ramp-Up-2/questions/01/attachments/chart.js
These examples include:
- ✅ Video player with embedded video
- ✅ Explanation card for written response
- ✅ State management for response field
- ✅ Full message protocol
- ✅ Interactivity locking
State Shape
function createDefaultState() {
return {
explanation: ""
};
}
For multiple questions:
function createDefaultState() {
return {
response1: "",
response2: "",
response3: ""
};
}
Implementation Pattern (Single Response)
function buildLayout(d3, containerSelector) {
const container = d3.select(containerSelector);
container.html("").style("padding", "20px").style("overflow", "auto");
createVideoResponseQuestion(d3, container, {
videoUrl: "https://example.com/video.mp4",
videoDescription: "Watch this explanation of proportional relationships",
promptText: "What is the main concept explained in the video?",
placeholderText: "Describe the main concept in your own words...",
responseRows: 6,
stateKey: "explanation",
locked: interactivityLocked,
introTitle: "Video Reflection",
introContent: "Watch the video carefully and answer the question below."
});
}
Implementation Pattern (Multiple Responses)
function buildLayout(d3, containerSelector) {
const container = d3.select(containerSelector);
container.html("").style("padding", "20px").style("overflow", "auto");
// Intro
const introCard = createStandardCard(d3, container, {
size: "large",
title: "Video Reflection"
});
introCard.append("p").text("Watch the video and answer the questions below.");
// Video
createVideoPlayer(d3, container, "https://example.com/video.mp4", {
description: "Proportional relationships explained"
});
// Multiple response cards
const questions = [
{ prompt: "1. What is the main concept?", key: "response1" },
{ prompt: "2. How does this relate to what you know?", key: "response2" },
{ prompt: "3. Give an example from real life.", key: "response3" }
];
questions.forEach(q => {
createExplanationCard(d3, container, {
prompt: q.prompt,
value: chartState[q.key] || "",
onChange: (value) => {
chartState[q.key] = value;
sendChartState();
},
locked: interactivityLocked,
rows: 4
});
});
}
Configuration Options
Video Player Options
{
videoUrl: "https://example.com/video.mp4", // Required
videoDescription: "Watch this...", // Shown above player
autoplay: false, // Default: false
controls: true // Default: true
}
Response Card Options
{
promptText: "Question text", // Required
placeholderText: "Type here...", // Optional
responseRows: 6, // Textarea height (default: 6)
stateKey: "explanation", // Required - key in chartState
locked: interactivityLocked // Required - current lock state
}
Optional Intro Card
{
introTitle: "Video Reflection", // Optional
introContent: "Instructions..." // Optional
}
Video Hosting Best Practices
- Supported formats: MP4 (recommended), WebM
- Hosting: Use CDN or cloud storage for best performance
- File size: Keep videos under 50MB when possible
- Encoding: H.264 codec for MP4, VP9 for WebM
- Accessibility: Ensure videos have captions when possible
Common Variations
Character Count Display
const textarea = container.append("textarea");
const counter = container.append("div")
.style("text-align", "right")
.style("color", "#6b7280")
.style("font-size", "14px");
textarea.on("input", function() {
const length = this.value.length;
counter.text(`${length} characters`);
chartState.explanation = this.value;
sendChartState();
});
Numbered Questions in Separate Cards
const QUESTIONS = [
{ prompt: "What is the main concept?", placeholder: "Main concept..." },
{ prompt: "How does this relate to ratios?", placeholder: "Connection..." }
];
QUESTIONS.forEach((q, index) => {
const qCard = createStandardCard(d3, container, {
size: "medium",
title: `Question ${index + 1}`
});
qCard.append("p").text(q.prompt);
qCard.append("textarea")
.attr("rows", 4)
.style("width", "100%")
.attr("placeholder", q.placeholder)
.property("value", chartState[`q${index + 1}`])
.on("input", function() {
chartState[`q${index + 1}`] = this.value;
sendChartState();
});
});
Implementation Checklist
- Copied
video-response.jssnippet into chart.js - Copied required card components (standard-card, video-player, explanation-card)
- Created
createDefaultState()with response field(s) - Configured video URL and description
- Configured prompt text and placeholder
- Set correct stateKey for response
- Tested video playback in browser
- Tested state restoration
- Tested interactivity locking
- Verified response text is preserved
- Checked video loads and plays correctly
Tips
- Clear prompts - Tell students exactly what to observe and explain
- Adequate textarea height - Use
responseRowsattribute (6+ for detailed responses) - Placeholder guidance - Show students what kind of response you expect
- Video length - Keep videos under 3-5 minutes for best engagement
- Intro context - Set expectations before the video plays
- Auto-save - State updates automatically on every input (no submit button needed)
State Management
Initialization
function createDefaultState() {
return {
explanation: ""
};
}
State Restoration
function applyInitialState(state) {
Object.assign(chartState, state);
buildLayout(d3, containerSelector);
}
Interactivity Control
function setInteractivity(enabled) {
interactivityLocked = !enabled;
buildLayout(d3, containerSelector);
}
Related Skills
- implement-text-response-question - For text-only reflections without video
- implement-multiple-choice-question - For video + selection instead of text
- create-d3-question - Parent workflow skill
Additional Resources
- PATTERN.md - Visual pattern guide
- snippets/video-response.js - Complete snippet with examples
- ../snippets/cards/video-player.js - Video player component
- ../snippets/cards/explanation-card.js - Explanation card component