SuperAPI AI Directory

create-shot-list

Design & creation

View repository

Updated 10-15 21:54

About this skill

create-shot-list

Purpose

Author the scene manifest — the text-based shot list that drives downstream prompt assembly and per-scene rendering.

Replaces the role that visual storyboarding played in the older NB2 + i2v multi-keyframe architecture. With Seedance 2.0 reference-to-video, scene-by-scene image generation is no longer required — but a structured plan IS still required, because:

  1. Multi-scene ads have global decisions that don't exist inside any single prompt (product ordering, setting variety, wardrobe rotation, lighting continuity).
  2. Cost gating — at $5-10 per Seedance scene, a human needs to approve the plan before firing 4-6 scenes.
  3. Global-rule enforcement — e.g. "wardrobe must vary across scenes" (per create-ugc-style-video Decision Rule 5). Each Seedance call has no memory of other calls; the author enforces variation in the manifest.

Use this atom when:

  • The video has ≥2 distinct scenes (hook + product scenes, multi-product review, multi-setting GRWM, before/after, etc.)
  • The architecture is Seedance 2.0 reference-to-video (one prompt per scene with internal sub-beats) — OR the legacy NB2 + i2v multi-keyframe flow (one keyframe per beat)
  • A pre-render human gate is needed

Skip the manifest (or collapse to one row) for single-scene 15s ads with one product and no setting change.

Inputs

Required:

  • script.md — the locked VO/dialogue script with per-scene lines
  • idea-brief.md or equivalent — angle, format archetype, funnel stage, target platform
  • Product reference image paths (source/products/*.png or similar)
  • Avatar persona spec (from upstream casting step) including locked portrait reference path

Optional:

  • targeting-spec.md — for tone/voice continuity
  • brand-voice.md — for wardrobe/aesthetic palette
  • Reference ads — for pacing benchmarks

Output

Primary artifact: scene-manifest.yml (or .json) at the project's working/ path.

Schema:

project: <slug>                       # e.g. "video-01-three-product-grwm"
brand: <brand-name>
total_duration_seconds: <int>         # sum of all scene durations
architecture: seedance-ref            # or "nb-i2v" for legacy multi-keyframe
aspect_ratio: 9:16
target_platform: meta-paid            # | tiktok-organic | both | youtube-shorts | pinterest
funnel_stage: TOF                     # | MOF | BOF

avatar:
  persona_id: <slug>                  # link to brands/<brand>/avatars/<persona>/
  portrait_ref: assets/avatar/portrait-hero.png
  voice_character: "warm conversational American female, early-20s creator"

products:
  - id: <product-slug>
    label: "<exact brand name on package>"
    ref_image: source/products/<slug>.png
    visual_description: "powder-blue soft squeeze tube with white cap"
    common_confusions: ["NOT a moisturizer", "NOT a body wash", "NOT a serum dropper"]

scenes:
  - id: cold-open                     # ⭐ MANDATORY for UGC ads — 1s scroll-stopper teaser
    order: 0
    duration: 1                       # 0.8-1.2s; ffmpeg-trim to exact target in composite
    script: "Okay yeah, that's plumped."   # lifted VO OR 1-word interjection ("Wait —" / "Okay so —")
    source_strategy: lift_from_scene  # | standalone_render
    lift_source:                      # populated if source_strategy=lift_from_scene
      scene_id: product-1
      start_time_sec: 12.4            # absolute timestamp in source scene
      duration_sec: 1.0
    setting: { description: "inherits from lift source" }
    wardrobe: { description: "inherits from lift source" }
    framing: "extreme close-up of payoff state (e.g. post-application lips, surprised face, product mid-squeeze)"
    on_screen_ratio: 0                # not counted toward face-share budget
    sub_beats: []
    product_refs: []                  # the lift carries product context; no separate refs
    continuity:
      prev_state: null
      end_state: "viewer registers a 'wait — what just happened?' moment, primed to keep watching"
      next_compatible: [hook]
    notes: |
      Scroll-stopper cold open. Show the PAYOFF state before the SETUP state.
      Default to lifting a 0.8-1.2s slice from a later scene (free, no drift).
      Only set source_strategy=standalone_render if the lifted slice would spoil the body
      (e.g. shows product name before the reveal). Memory: feedback_ugc_scroll_stopper_cold_open.md.

  - id: hook
    order: 1
    duration: 8                       # seconds
    script: "Okay so… top 3 products I'm honestly obsessed with."
    setting:
      description: "casual bedroom corner with wooden dresser, cream wall, terracotta pot"
      lighting: "soft warm morning daylight from window on right"
    wardrobe:
      description: "cream linen tank, gold hoops, honey-blonde beachy waves"
      negations: ["NOT white-white", "NOT grey", "NOT silk", "NOT patterned"]
    framing: "wide selfie, mid-thigh to head, all 3 products visible on dresser"
    on_screen_ratio: 100              # percent — creator fully on-screen
    sub_beats: []                     # hook = single continuous shot, no internal cuts
    product_refs: [face-wash, deodorant, self-tanner]
    continuity:
      prev_state: null
      end_state: "hand rests on dresser, satisfied smile, eyes on camera"
      next_compatible: [product-1]    # downstream scene IDs that can follow
    notes: "Single take. All 3 products visible throughout. NO internal cuts."

  - id: product-1
    order: 2
    duration: 15
    script: "First — the face wash. Plant-powered, no harsh chemicals."
    setting:
      description: "casual American home bathroom, stone counter, eucalyptus stem in glass"
      lighting: "soft natural morning daylight from window above"
    wardrobe:
      description: "cream waffle robe, gold hoops, hair in soft messy top-knot"
      negations: ["NOT white-white", "NOT terry-towel", "NOT strapless"]
    framing: "mix wide / medium chest-up / close-up (varies per sub-beat)"
    on_screen_ratio: 60
    sub_beats:
      - { time: "0-3s",   type: WIDE_HOOK,      framing: "wide selfie",      action: "holds product up beside face, gentle gesture" }
      - { time: "3-7s",   type: PRODUCT_HERO,   framing: "focus pull face→product", action: "rotates product, label visible" }
      - { time: "7-11s",  type: SIDESTEP,       framing: "medium-close",     action: "pumps gel onto fingertips, shows to camera. NO water, NO lather, NO application to face." }
      - { time: "11-15s", type: REACTION_CTA,   framing: "medium-to-wide",   action: "caps product, satisfied smile, head nod" }
    product_refs: [face-wash]
    continuity:
      prev_state: "from hook's bedroom dresser"
      end_state: "satisfied smile, product capped and held beside face"
      next_compatible: [product-2]
    notes: "NSFW sidestep — fingertips show only. Lips closed between beats."

  # ... product-2, product-3, etc.

  - id: endcard
    order: 99
    duration: 4
    script: null                      # endcard is visual-only, audio = L-cut from prior scene
    setting:
      description: "HTML hyperframe — brand wordmark + tagline + CTA + cert footer over warm flat-lay BG"
      lighting: "n/a — HTML render"
    wardrobe: null                    # no avatar
    framing: "9:16 1080×1920, brand wordmark centered upper, CTA centered lower"
    on_screen_ratio: 0
    sub_beats: []
    product_refs: [face-wash, deodorant, self-tanner]
    continuity:
      prev_state: "L-cut audio from last product scene's CTA"
      end_state: "holds silent for 2s after audio ends"
    notes: "Render via HTML hyperframe atom, not Seedance. See create-end-card-html."

global_rules:
  - "Avatar identity holds via `portrait_ref` across every Seedance scene"
  - "Wardrobe MUST vary across consecutive scenes"
  - "Setting SHOULD vary across consecutive scenes"
  - "Lips remain closed between dialogue beats (no idle mouth movement)"
  - "No NSFW visual: no water, no lather, no actual body application"
  - "Each product appears in exactly one product scene (hook is the exception)"

cost_estimate:
  nb2_avatar: 0.08
  seedance_scenes: <sum>             # sum across scenes from PRICE_PER_SEC × duration
  endcard_bg: 0.08
  music: 0.40
  total_usd: <sum>

Workflow

  1. Read inputs. Load script.md, idea-brief.md, avatar persona, product refs.
  2. Decompose the script into scenes. For UGC review format: hook (8s) + N product scenes (15s each) + endcard (4s).
  3. For each scene, populate:
    • Setting + lighting that varies from neighbors (per global rule)
    • Wardrobe with explicit negations of common drift
    • Framing strategy (wide/medium/close mix vs single focal length)
    • On-screen ratio (typically 100% for hook, 50-60% for product scenes, 0% for endcard)
    • For Seedance scenes: 4 sub-beats (WIDE_HOOK / PRODUCT_HERO / SIDESTEP / REACTION_CTA) inside the 15s window
    • Continuity links to prior and next scenes
  4. Run the continuity audit (per memory feedback_continuity_audit_pass.md):
    • Walk through scenes[] in order
    • For each scene N+1, check that scenes[N].continuity.end_state is a reachable starting point for scenes[N+1].continuity.prev_state
    • Flag any time-jumps, setting jumps without explicit transition, wardrobe collisions
  5. Compute cost estimate from scene durations × resolution-keyed per-second cost.
  6. Write working/scene-manifest.yml to the project folder.
  7. Surface to operator for approval — this is the cheap pre-render gate.

Decision Rules

  1. Wardrobe must vary across consecutive scenes. Same identity portrait + different wardrobe per scene gives the ad visual rhythm. Avatar identity holds; wardrobe creates variety.
  2. Setting SHOULD vary across consecutive scenes for multi-product reviews (bathroom → bedroom → kitchen → outdoor). For single-setting ads (e.g. mirror-only GRWM), state this explicitly in global_rules.
  3. One product per scene (except the hook). Multi-product scenes inside a single Seedance call degrade label fidelity. The hook scene shows all products together but doesn't go macro on any single label.
  4. NSFW sidestep for body-application products. Reframe scenes that involve water/lather/face/body-application as: pump-onto-fingertips, twist-up-and-smell-test, or hand-only POV placement. Encode the sidestep explicitly in the scene's action field.
  5. On-screen ratio target. UGC review format aggregates ~50-60% creator on-screen. Hook = 100%, product macros (PRODUCT_HERO sub-beat) = 30%, B-roll = 0%. Sum across scenes shouldn't exceed 70% (over-talking-head reads as documentary, not UGC).
  6. Continuity audit before approval. Sequential walk per memory feedback_continuity_audit_pass.md. Catches VO/visual timing inversions, off-screen transitions, time jumps.
  7. Scene 0 (cold-open) MUST exist for UGC ads. A 0.8-1.2s scroll-stopper teasing the payoff state before the verbal hook. source_strategy=lift_from_scene is the default (free, identity/wardrobe lock for free); source_strategy=standalone_render only when the lifted slice spoils the body of the ad. The verbal hook in scene 1 (hook) is NOT a substitute — the cold open is visual scroll-stop, the verbal hook is intent framing. Memory: feedback_ugc_scroll_stopper_cold_open.md.

Quality Checks

  • For UGC ads: scenes[0].id == "cold-open" with duration in [0.8, 1.2] and a valid source_strategy. If lift_from_scene, lift_source.scene_id matches a later scene's id.
  • Every scene has a non-empty script, setting, wardrobe, framing, duration (except endcard which may have script: null, and cold-open which may inherit setting/wardrobe from its lift source).
  • sum(scenes[].duration) matches total_duration_seconds.
  • For ≥2 consecutive scenes: wardrobe text differs.
  • Every product in products[] appears in exactly one scene's product_refs (excluding the hook).
  • continuity.end_state of scene N is reachable from continuity.prev_state of scene N+1.
  • cost_estimate.total_usd matches the sum of per-scene costs.

Failure Modes

Failure Cause Recovery
Identical wardrobe across scenes Skipped Decision Rule 1 Author wardrobe variations before approval gate.
Sub-beats sum > 15s Time accounting drift Tighten each sub-beat's time window; 0-3 / 3-7 / 7-11 / 11-15 is the proven split.
NSFW sidestep not encoded Author defaulted to "apply to face" Add explicit negations in scene's action: "NO water, NO lather, NO actual face washing motion."
End-state of scene N doesn't reach start of N+1 Skipped continuity audit Run sequential audit (Decision Rule 6). Insert a transitional beat or rewrite the gap.
Total duration doesn't sum to plan Hook/endcard durations forgotten Verify sum(scenes[].duration) == total_duration_seconds.

References

  • Composing molecule: skills/molecules/ugc-ad/create-ugc-style-video (Phase 4 scene breakdown defines the structure)
  • Downstream prompt template: prompt-example.md at repo root
  • Downstream render atom: skills/atoms/video-generation/create-video-seedance-2-fal
  • Continuity audit pattern: memory feedback_continuity_audit_pass.md
  • Reference run: beauty-by-earth/video-01-three-product-grwm/working/ — see scene-{hook,facewash,deo,tanner}.json for per-scene specs