Skip to content

Reference sheets — design

Status: Draft for review Date: 2026-04-22 Owner: Davendra Patel Scope estimate: ~600–900 LOC across ~20 files, 1–2 focused sessions


Problem

The Seedance 2.0 Handbook (read 2026-04-22) crystallizes a rule the repo already half-implements: every reference to a generator must have exactly one job — identity, wardrobe, palette, motion-rhythm, ambience, composition, or similar. The handbook names this as anti-pattern #3 ("unassigned reference stacks") and identifies role-less references as the most common cause of character drift and style bleed.

The repo today only models Identity references (via projects/<slug>/characters/characters.json and the character-creator / character-library skills). Asset manifests hold file paths but do not tag a reference with the job it is meant to do. Storyboard scenes can bind character names, but cannot bind a palette sheet, a motion-rhythm reference, or an environment reference.

The practical consequence:

  1. A director-mode run can pass readiness + preflight with a bag of role-less reference images, and still produce drift.
  2. The approval-gate review file (storyboard.md) cannot show reviewers what each reference is supposed to control.
  3. Operators have no way to reuse, for example, a well-tuned palette/mood reference set across projects — references are implicitly one-shot.

Goal

Add reference sheets as a first-class concept in the clean-room repo, with five typed sheets, role-tagged references, per-scene bindings, validation, preflight integration, and full ops-surface visibility.

Non-goals

Deliberately out of scope for v1:

  1. Auto-generation of sheets from a brief. The natural home is an extension to the Gemini-backed analyze-template path; this spec does not couple to that.
  2. Sheet template library (reusable palette-mood sheets across projects). Follow-on after the data model is stable.
  3. Visual preview rendering (HTML/PDF reference sheet cards). Can layer on top of video-thumbnail-lab later.
  4. Retroactive migration of existing projects. New projects adopt sheets; existing projects keep working without them and only fail readiness if the operator opts in by creating a sheet.

Approach

Reference sheets live alongside characters, not replacing them (see D1 in the decision record). This keeps the existing cast hydration, character-consistency, and Go Bananas anchoring paths intact.

  • Characters stay at projects/<slug>/characters/characters.json.
  • Sheets live at projects/<slug>/references/reference-sheets.json.
  • An Identity Sheet can reference a character by name, bridging the two systems without forcing a migration.

Five sheet types, with closed role vocabularies per type (see Data Model below):

TypePurposeRole vocabulary
identityWho is in the sceneidentity · wardrobe · silhouette · age-reference
outfit-materialWhat they wear and what it's made of (plus product showcase)outfit · material · accessory · texture · product-hero · product-variant · product-in-use · packaging
environmentWhere the scene happenslocation · set-dressing · weather · time-of-day
motion-cameraHow the camera and subject movemotion-rhythm · camera-behavior · blocking · shot-framing
palette-moodThe visual feel of the scenepalette · composition · mood · lighting-reference

Data model

Canonical artifact

projects/<slug>/references/reference-sheets.json:

json
{
  "schemaVersion": 1,
  "sheets": [
    {
      "id": "sheet-001",
      "type": "identity",
      "name": "Lead — Mochi",
      "description": "Primary cast lead across all scenes.",
      "characterName": "Mochi",
      "references": [
        { "path": "refs/mochi-identity.png", "role": "identity" },
        { "path": "refs/mochi-wardrobe.png", "role": "wardrobe", "note": "only this jacket" }
      ],
      "bindings": { "sceneIndices": [1, 2, 3, 4] },
      "createdAt": "2026-04-22T10:00:00.000Z",
      "updatedAt": "2026-04-22T10:00:00.000Z"
    },
    {
      "id": "sheet-002",
      "type": "palette-mood",
      "name": "Warm dusk palette",
      "description": "Golden-hour warmth across the opening act.",
      "references": [
        { "path": "refs/dusk-01.png", "role": "palette" },
        { "path": "refs/dusk-02.png", "role": "composition" }
      ],
      "bindings": { "sceneIndices": [1, 2] }
    }
  ]
}

Field definitions

FieldRequiredPurpose
schemaVersionyesContract version; starts at 1
sheets[]yesArray of sheets
sheets[].idyesStable id. Auto-generated as sheet-<n> (next free integer) when --id is omitted; operator-chosen when provided.
sheets[].typeyesOne of the five sheet types
sheets[].nameyesHuman-readable label
sheets[].descriptionnoFree-form note
sheets[].characterNameno (identity only)Link to characters/characters.json entry
sheets[].references[]yes (may be empty at creation)Reference entries
sheets[].references[].pathyesLocal or remote reference path
sheets[].references[].roleyesMust be in the role vocabulary for the sheet type
sheets[].references[].notenoFree-form per-reference note
sheets[].bindings.sceneIndices[]noScenes this sheet binds to (empty = unbound)
sheets[].createdAt / updatedAtyesISO timestamps

Validation rules

  1. Role ∈ vocabulary for type. An identity sheet cannot carry a palette role. Validated on reference-sheet-add and reference-sheet-validate.
  2. No role collisions within a scene. A scene cannot have two bindings that supply the same role (e.g. two sheets both supplying palette for scene 3). Flagged by reference-sheet-validate as a collision.
  3. Unassigned references are errors, not warnings. Every references[] entry must carry a role.
  4. Scene indices must exist. Bindings to out-of-range scene indices fail validation.
  5. Unique sheet ids within a project.

CLI surface

Add five new subcommands under the existing vclaw video namespace:

bash
vclaw video reference-sheet-add \
  --project <slug> \
  --type <identity|outfit-material|environment|motion-camera|palette-mood> \
  --name <name> \
  [--id <sheet-id>] \
  [--description <text>] \
  [--character-name <name>] \
  [--ref <path>:<role> ...] \
  [--binding <sceneIndex> ...] \
  [--root <path>]

vclaw video reference-sheet-list --project <slug> [--type <sheet-type>] [--root <path>]

vclaw video reference-sheet-show --project <slug> --id <sheet-id> [--root <path>]

vclaw video reference-sheet-bind \
  --project <slug> \
  --id <sheet-id> \
  --scene <sceneIndex> [--scene <sceneIndex> ...] \
  [--root <path>]

vclaw video reference-sheet-validate --project <slug> [--root <path>]

Output is machine-readable JSON by default, matching existing commands.

Integration points

Readiness (src/video/readiness.ts)

  • Director-mode projects require at least one Identity Sheet bound per scene that has character references in the storyboard.
  • Fail readiness with a new failure code reference-sheet-missing-identity.

Director preflight (src/video/director-preflight.ts)

Three new checks:

  1. unassigned-role — any sheet has a reference without a role.
  2. role-vocabulary-violation — reference role not in the sheet-type vocabulary.
  3. role-collision — two sheets bound to the same scene both supply the same role (e.g. two palette sources for scene 2).

All three are blocking errors for director-mode (matching current preflight severity model). Storyboard-mode emits them as warnings.

Doctor (src/video/doctor.ts) + portfolio (src/video/doctor-portfolio.ts)

  • Per-project: count sheets, per-sheet reference-role assignment completeness, unbound sheets, role collisions.
  • Portfolio rollup: projects with no sheets at all, projects with sheets but no bindings, projects with collisions.

Status + project-index + report + CSV + Obsidian

Every ops surface grows a referenceSheets summary field:

json
{
  "referenceSheets": {
    "count": 3,
    "byType": { "identity": 1, "palette-mood": 1, "environment": 1 },
    "boundSceneCount": 4,
    "unboundSheetIds": ["sheet-003"]
  }
}

Storyboard markdown (src/video/storyboard-markdown.ts)

Director-mode review file gains a Reference sheets section showing, per scene: which sheets are bound, what role each reference plays, and any linked character. This answers the handbook's call for reviewable role clarity at the approval gate.

Obsidian export

The generated Projects/<slug>.md frontmatter gains: referenceSheetCount, referenceSheetTypes, referenceSheetCollisions. The Health.md rollup counts projects with unresolved collisions.

Which sheet types enforce in v1 (D2)

Per the decision log: all 5 sheet types ship in the schema and CLI; only the Identity Sheet is wired into blocking readiness in v1. All 5 types participate in the three preflight validation checks (unassigned-role, role-vocabulary-violation, role-collision) when sheets are present; none of the non-Identity types are required to be present.

This gives the full data-model shape on day one without forcing existing projects to backfill sheets. palette-mood was a candidate for v1 enforcement (decision-log earlier noted both), but tightening to Identity-only keeps the rollout additive — projects without a palette-mood sheet should not fail readiness.

Subsequent PRs can promote palette-mood, outfit-material, environment, and motion-camera to required-when-applicable enforcement once operators have practice authoring them.

Testing strategy

Module contracts

src/tests/reference-sheets.test.ts covers:

  1. Create / read / update / delete sheets
  2. Role vocabulary enforcement per sheet type
  3. Role-collision detection across sheets bound to the same scene
  4. Scene-index range validation
  5. Character-name linking (identity sheets only)
  6. Schema round-trip (read-after-write preserves structure)

CLI end-to-end

src/tests/cli-reference-sheets.test.ts covers:

  1. reference-sheet-add with valid role → artifact written correctly
  2. reference-sheet-add with invalid role → non-zero exit, readable error
  3. reference-sheet-list filters by type
  4. reference-sheet-show returns full sheet JSON
  5. reference-sheet-bind updates bindings idempotently
  6. reference-sheet-validate surfaces collisions and unassigned roles

Smoke

New smoke scripts/smoke-reference-sheets.mjs:

  1. initbriefstoryboardreference-sheet-add identityreference-sheet-add palette-moodreference-sheet-bindreadinessdirector-preflight → asserts both sheets appear in storyboard.md

Added to scripts/check-release-readiness-lite.sh so CI gates on it.

Backwards compatibility

Fully additive:

  • Existing projects without references/reference-sheets.json behave exactly as today. Readiness and preflight only reference-check when sheets exist.
  • The one exception: director-mode projects that have a storyboard with character bindings must now carry an Identity Sheet per character. This is a deliberate tightening — the handbook is clear that identity without a role is the root cause of character drift.
  • A migration helper vclaw video reference-sheet-migrate-from-characters is out of scope for v1 but noted in the follow-on list. Until then, operators create sheets manually; the cost is one CLI call per character.

Documentation

  • docs/REFERENCE_SHEETS.md — operator guide (what they are, why, commands, common workflows, failure-mode → fix mapping drawn from the handbook)
  • docs/CLI_REFERENCE.md — five new commands in the lifecycle section
  • docs/ARCHITECTURE.md — add a reference-sheet layer box to the flow
  • README.md — two-line mention in "Why this exists" + the artifacts list
  • docs/MASTER_PLAN_ALIGNMENT.md — add to the implemented-items list on landing

Risks

RiskMitigation
Schema churn: role vocabulary may prove wrong in practiceschemaVersion field in place from v1; role lists can extend additively
Operators feel forced to make sheets just to pass readinessReadiness only enforces sheets when the project has character bindings; storyboard-mode never blocks
Existing character-consistency machinery drifts from sheet machineryIdentity Sheets carry characterName and consistency checks read both surfaces in a single pass
Smoke bloat (release-readiness-lite already runs 5 smokes)New smoke is dry-run, completes in < 5s
Scope creep into "sheet templates" and "auto-generate sheets"Explicitly deferred in non-goals; first-class mention in a follow-on list

Follow-on work (out of v1)

  1. Promote outfit-material, environment, motion-camera to blocking enforcement
  2. Auto-generate sheets from a brief via the Gemini analyze-template path
  3. Reusable sheet library (vclaw video reference-sheet-library surface)
  4. Sheet migration helper from existing characters
  5. Visual preview cards via video-thumbnail-lab
  6. Prompt-quality preflight that uses sheet bindings to score scene prompts (closes handbook anti-patterns #1 "adjective soup" and #6 "contradictory identity descriptions")

Decisions record

D1 — Reference sheets live beside characters, not replacing them. Rationale: keeps the existing cast-hydration, character-consistency, and Go Bananas anchoring paths intact. An Identity Sheet can link to a character by name to bridge the two systems.

D2 — All 5 sheet types ship in v1; only Identity is wired into blocking readiness. All 5 types participate in the three validation checks when present. Rationale: full data-model shape on day one, strictly additive for existing projects, iterative promotion of remaining types to required-when- applicable.

D3 — Go Bananas references ship in v1. References inside a sheet can be either a local file path ({ path, role }) or a Go Bananas entity reference ({ gbRef: { kind, id }, role }). Supported kind values: character, product, scene, style-preset, reference-group. Rationale: the ReferenceEntry union is ~10 LOC, CLI flag --gb-ref is another ~10, and preflight already probes GB for characters — shipping without this would force a v2 revision almost immediately.

D4 — GB Products are modelled as extensions of the outfit-material role vocabulary (new roles: product-hero, product-variant, product-in-use, packaging). Rationale: product shots are wardrobe-adjacent in practice; a separate product-showcase sheet type would splinter the surface. Can promote to its own sheet type later if UGC-campaign workflows grow into it.

D5 — The repo keeps environment as the sheet type name; Go Bananas keeps its Scene entity name. Rationale: the naming collision is local (GB Scene = reusable environment template; storyboard scene = beat-level unit). One GB Scene can back N storyboard scenes. We document the distinction instead of renaming either side.

Addendum: Go Bananas integration

The layer stack

Go Bananas record              ← canonical generation source of truth
       ▲ anchored by gbRef or gb-id
Character / Reference entry    ← repo-side anchor to a GB entity
       ▲ held inside
Reference Sheet                ← role-tagged bundle for a project
       ▲ bound to
Storyboard scene               ← beat-level unit with characters

Entity mapping

Repo sheet typeGB entitySupported role(s)
identityGB Characteridentity, wardrobe, silhouette, age-reference
outfit-materialGB Productproduct-hero, product-variant, product-in-use, packaging
environmentGB Scenelocation, set-dressing, weather, time-of-day
palette-moodGB Style Presetpalette, composition, mood, lighting-reference
(any type)GB Reference Groupany role valid for the sheet type

ReferenceEntry union (revised)

typescript
export type ReferenceEntry =
  | { path: string; role: ReferenceRole; note?: string }
  | { gbRef: GbRef; role: ReferenceRole; note?: string };

export type GbRef = {
  kind: 'character' | 'product' | 'scene' | 'style-preset' | 'reference-group';
  id: number;
};

Schema (JSON Schema) uses oneOf with two alternatives mirroring the union.

CLI surface

Extend reference-sheet-add with an additional flag alongside --ref:

bash
--gb-ref <kind>:<id>:<role>[:<note>]

Examples:

bash
--gb-ref character:247:identity
--gb-ref scene:15:location
--gb-ref style-preset:3:palette
--gb-ref product:88:product-hero
--gb-ref reference-group:42:motion-rhythm

Preflight resolution

When GO_BANANAS_API_KEY is set, director-preflight resolves every gbRef in every sheet against the GB API:

  • kind: character → uses the existing character-probe path
  • kind: product|scene|style-preset|reference-group → uses the respective GB get_* surface
  • Unresolved entities become a blocking preflight issue: reference-sheet-orphan-gb-ref with the sheet id, entry index, and GB kind/id

No Go Bananas-side changes required

GB already exposes all five entity types with create_*, list_*, get_* APIs. V1 is repo-side only.

File list

New

  • schemas/video/artifacts/reference-sheets.schema.json
  • src/video/reference-sheets.ts
  • src/video/reference-sheet-store.ts
  • src/tests/reference-sheets.test.ts
  • src/tests/cli-reference-sheets.test.ts
  • scripts/smoke-reference-sheets.mjs
  • docs/REFERENCE_SHEETS.md

Modified

  • src/cli/vclaw.ts (add five subcommands + help text)
  • src/video/types.ts (new types)
  • src/video/readiness.ts
  • src/video/director-preflight.ts
  • src/video/doctor.ts
  • src/video/doctor-portfolio.ts
  • src/video/status.ts
  • src/video/project-index.ts
  • src/video/report.ts
  • src/video/csv-export.ts
  • src/video/obsidian-export.ts
  • src/video/storyboard-markdown.ts
  • src/index.ts
  • docs/ARCHITECTURE.md
  • docs/CLI_REFERENCE.md
  • docs/MASTER_PLAN_ALIGNMENT.md
  • README.md
  • package.json (add smoke:reference-sheets script)
  • scripts/check-release-readiness-lite.sh (add smoke)

Shipping checklist

  1. npm test green
  2. npm run check:release-readiness-lite green (includes the new smoke)
  3. npm run check:cleanroom-docs green
  4. Agent-facing docs (CLAUDE.md, AGENTS.md) reference the new concept where relevant
  5. PR description carries the design-doc link

Built to be driven by agent hosts like Claude Code, Claude Desktop, or Codex · Source-available, commercial use requires a paid license.