Thursday Creative Media Lab
Implement the following plan:
Thursday Creative Media Lab
Overview
Week 2 lab for Feb 5: 3 creative tasks (images, video, music) with formal partner pairing per round, a new MediaSubmission component for sharing creations, an instructor gallery for share-outs, and a closing discussion on creativity and energy tradeoffs.
Core pedagogical idea: partners agree on a concept, work independently to prompt AI, then compare results — demonstrating that AI outputs vary even for the same concept.
Activity Structure
7 stages, one ActivityStages block, GroupActivity nested inside creative stages:
| # | Stage | Time | Notes |
|---|---|---|---|
| 1 | Create Images | 15m | GroupActivity pairing + image creation |
| 2 | Image Gallery | 5m | Instructor-led share-out |
| 3 | Create Video | 12m | New GroupActivity pairing + video creation |
| 4 | Video Gallery | 5m | Share-out |
| 5 | Create Music | 12m | New GroupActivity pairing + music creation |
| 6 | Music Gallery | 5m | Share-out |
| 7 | Discussion | 15m | Creativity, energy, ownership |
~69 min total (fits 75 min class starting at 2:05pm)
Technical Changes
1. GroupActivity: add autoComplete prop
Currently, GroupActivity calls completeStage() when a group forms — appropriate when GroupActivity wraps all stages, but premature when it's inside a stage alongside other content.
- Add
autoCompleteboolean prop (defaulttruefor backward compat) - When
false, skip thecompleteStage()call on group formation - The stage's existing timer/manual-complete handles progression
- The recursive
hasGroupActivitymetadata detection already works for nested GroupActivity (confirmed in codebase exploration)
File: apps/web/components/mdx/group-activity-client.tsx
2. New MediaSubmission component
Follows the TextSubmission pattern (server/client donut):
Student view:
- URL text input + optional caption field
- Preview: image URLs rendered inline; other URLs shown as link cards
- Submit button (version-tracked like TextSubmission)
- Captures context: groupId, stageIndex, meetingSlug
Instructor view (gallery):
- Grid layout of all submissions for a given submission ID
- Image URLs rendered as thumbnails
- Video/music URLs as clickable link cards
- "Present" button opens fullscreen gallery for projecting
- Real-time updates via WebSocket
Props: id (required), label (optional)
3. MediaGallery component (for share-out stages)
Read-only gallery visible to all users (students + instructor) during share-out stages.
- Shows all submissions for a given MediaSubmission ID
- Same grid rendering as instructor gallery
- Used in the gallery/share-out stages so everyone sees the creations
- Props:
submissionId(required), references a MediaSubmission'sid
4. Database
New media_submissions table (following text_submissions pattern):
id text PK (nanoid)
submission_id text NOT NULL (from MDX id prop)
user_id text NOT NULL (FK → users)
semester text NOT NULL
url text NOT NULL
caption text
meeting_slug text
group_id text (FK → activity_groups)
session_id text (FK → activity_sessions)
stage_index integer
version integer NOT NULL DEFAULT 1
is_latest boolean NOT NULL DEFAULT true
submitted_at timestamp NOT NULL DEFAULT now()
Indexes on (submission_id, user_id, semester) and (meeting_slug, semester).
5. API endpoints
Following text-submissions route pattern:
POST /api/media-submissions/:submissionId— submit URL + captionGET /api/media-submissions/:submissionId— get own latest submissionGET /api/admin/media-submissions/:submissionId— get all submissions (instructor, enriched with user names and group members)
WebSocket event: mediaSubmission:submitted for real-time gallery updates.
AI Tool Suggestions (verify availability before class)
Images: ChatGPT (DALL-E 3), Microsoft Copilot/Designer, Google Gemini, Ideogram Video: Runway, Pika, Luma Dream Machine — free tiers are limited; verify current availability Music: Suno, Udio
Students using different tools is a feature — it reinforces the "same concept, different output" theme.
Activity Content Outline
Brief intro explaining the format, then 3 creative rounds:
Each creative stage:
- GroupActivity pairing UI (enter partner's code)
- Once paired: instructions to agree on a concept together
- Work independently — each student prompts an AI tool of their choice
- Compare results with partner
- Submit best creation via MediaSubmission (paste URL + caption)
Each gallery stage:
- MediaGallery showing all class submissions
- Instructor projects and highlights interesting results
- Brief class discussion of what they notice
Closing discussion prompts:
- Which medium gave you the most creative control? The least?
- Did the AI ever surprise you with something better than what you imagined?
- When AI can generate images/music/video in seconds, what happens to human creators?
- How much energy did our class just use? (tie to Week 8 infrastructure topic)
Files
New
| File | Purpose |
|---|---|
packages/db/src/schema/media-submissions.ts | DB schema |
apps/web/components/mdx/media-submission.tsx | Server component |
apps/web/components/mdx/media-submission-client.tsx | Student submission UI |
apps/web/components/mdx/media-submission-instructor-view.tsx | Instructor gallery |
apps/web/components/mdx/media-gallery.tsx | Shared gallery for share-out stages |
apps/api/src/routes/media-submissions.ts | API endpoints |
content/spring2026/meetings/2026-02-05-creative-media.mdx | Activity content |
Modified
| File | Change |
|---|---|
apps/web/components/mdx/group-activity-client.tsx | Add autoComplete prop |
apps/web/components/mdx/group-activity.tsx | Pass autoComplete prop through |
apps/web/mdx-components.tsx | Register MediaSubmission, MediaGallery |
packages/db/src/schema/index.ts | Export media_submissions |
| DB migration | Generated via bun run db:generate |
Verification
bun run db:generate+bun run db:migrate— schema appliedbun run tsc+bun run lint— no type/lint errors- Test GroupActivity inside ActivityStage with
autoComplete={false}— pairing works, stage doesn't auto-complete - Test MediaSubmission: paste image URL → preview renders, submit works
- Test instructor gallery: sees all submissions, present mode works
- Test MediaGallery in share-out stage: all students see class creations
- Test full activity flow: pair → create → submit → gallery → new pair → repeat
- Verify WebSocket updates: new submission appears in gallery without refresh
If you need specific details from before exiting plan mode (like exact code snippets, error messages, or content you generated), read the full transcript at: ~/.claude/projects/-Users-challen-www-usingandunderstanding-ai/8ab7ce57-6797-4f73-8081-89ffa925c54c.jsonl
I'll start by understanding the existing codebase patterns, then implement the plan systematically. Let me explore the key files first.
Now let me explore the existing patterns in parallel.
Now let me read the actual files I need to modify/use as templates.
Now let me read the remaining reference files in parallel.
Now let me read the remaining files I need.
Now let me also check the client-side socket types and an existing MDX activity file for reference.
Let me also check an existing activity MDX file for reference on the format.
Let me read the existing activity file for the exact frontmatter pattern.
Now I also need to check the UI components available (Button, Input, etc.).
Good, I have all the context I need. Let me start implementing. I'll begin with the foundational changes and work up.
Task 1: Add autoComplete prop to GroupActivity
Now update the client component to accept and use the autoComplete prop:
Now modify the useEffect that triggers stage completion to respect autoComplete:
Task 2: Create media_submissions database schema
Now generate the migration:
Task 5: Create API routes for media submissions
First, add the WebSocket event for media submissions to both socket files:
Now update the client-side socket types:
Now create the API route:
Now create the admin route:
Now register the routes in the API index:
Task 3: Create MediaSubmission components
First, the server component:
Now the student client component:
Now the instructor view:
Task 4: Create MediaGallery component
Task 6: Register components in mdx-components.tsx
Task 7: Create activity MDX content
Let me check the meeting slug pattern and existing meetings first.
Task 8: Run type checks and lint
The eslint-disable comments aren't matching the expected rule format. Let me check how the existing codebase handles <img> tags.
The issue is that @next/next/no-img-element rule doesn't exist in this ESLint config. These are <img> tags used for user-submitted content where next/image isn't appropriate (external URLs). Let me just remove the disable comments since the rule doesn't exist.
All 18 packages lint and type-check cleanly.
Your task
First, run git status, git diff, and git log --oneline -10 to understand the current state.
Then add and commit all modified files with a descriptive message. Break the changes into multiple commits if appropriate. If there are untracked files, ask if they should be added or added to the appropriate .gitignore file. The user may also want to take over at this point, so provide an abort option as well. Always check changes for unnecessary debugging statements or logging that might have been accidentally included. Prompt the user if you find any, and offer to remove each one by one. Do not use interactive git staging (git add -p) as it does not work.
The changes look clean — no debug statements or unnecessary logging. The log.debug calls in socket.ts follow the existing pattern. All untracked files are intentional new files for this feature.
I'll commit this as a single commit since the changes form one cohesive feature.
Committed as f02e69e. Working tree is clean — 18 files changed across 10 new files and 8 modified files.
Your task
First, run git status, git diff, and git log --oneline -10 to understand the current state.
Then add and commit all modified files with a descriptive message. Break the changes into multiple commits if appropriate. If there are untracked files, ask if they should be added or added to the appropriate .gitignore file. The user may also want to take over at this point, so provide an abort option as well. Always check changes for unnecessary debugging statements or logging that might have been accidentally included. Prompt the user if you find any, and offer to remove each one by one. Do not use interactive git staging (git add -p) as it does not work.
These are all automated/linter changes: Tailwind class reordering in the 3 media components, semicolon formatting in link-check, dependency version bumps across packages, drizzle snapshot regeneration, and a trailing newline fix. No debug statements or suspicious additions.
This splits naturally into two commits: the auto-formatting/linter fixes and the dependency updates.
Done. Two commits:
86028c2— Auto-format media components, link checker, and drizzle snapshot35eb911— Bump dependency versions across packages
OK! Now let's write e2e tests for these new components, and a full e2e test for tomorrow's activity.
(no content)
Let me read the existing plan file and explore the E2E testing patterns in the codebase.
This is a different task (E2E tests for the already-implemented feature), so I'll overwrite the plan. Let me explore the existing E2E test patterns.
(no content)
Let me look at the text-submission test and the existing meeting page test patterns more closely.
Now let me check the test page for the full activity flow to understand how it sets up ActivityStages with GroupActivity.
Now let me also check the text-submission test file and the existing E2E cleanup for text submissions.
Now let me read the Playwright config to understand the exact project registration pattern.
I notice there's a meeting-2026-02-03 test project already. Let me check that for the meeting-level E2E test pattern.
I now have a thorough understanding of both the component implementations and the testing patterns. Let me check one more thing — the existing media submission component data-testid attributes and the E2E cleanup endpoint pattern.
Good. Now I have all the information I need. Let me design the plan.
(no content)
Now let me read the MediaGallery component one more time to verify something about its API call.
As I suspected — MediaGallery calls /api/admin/media-submissions/... which requires instructor/staff role. Students would get a 403 when viewing gallery stages. This is a bug that needs fixing as a prerequisite. Let me also check the requireRole middleware to confirm.
Confirmed. Now I have everything I need. Let me write the final plan.