{
  "schema_version": 1,
  "fps": 30,
  "intervals": "[start,end), zero-based recipe-local frames. Clip-local frame = recipe frame minus this clip’s In; add any Fusion composition frame offset separately.",
  "recipes": [
    {
      "id": "title-cut",
      "evidence_id": "title-cut",
      "title": "Title hold → hard cut",
      "intent": "Introduce",
      "timeline_name": "R01_title_cut",
      "duration_frames": 150,
      "duration_s": 5.0,
      "fps": 30,
      "purpose": "Give a short premise a complete reading interval, then replace it with a recognizable work surface. The visible replacement can become a rehearsed playback cue.",
      "tracks": [
        [
          "V1",
          "paper.png",
          0,
          90
        ],
        [
          "V1",
          "context.png",
          90,
          150
        ],
        [
          "V2",
          "Text title",
          0,
          90
        ]
      ],
      "steps": [
        "Edit page → Effects → Titles → Text. Place above paper.png. Set duration to 00:00:03:00; context.png starts at recipe frame 90. No transition at the boundary.",
        "Text Inspector → Title: text “Make the work visible”; DejaVu Sans Bold; Size 72; Alignment Center; Anchor horizontal Center / vertical Center; Title Position X 960, Y 540. Color #23312e. Settings → Transform Position 0,0 and Zoom 1. Leave animation off.",
        "At frames 89 and 90 step one frame at a time: all title pixels disappear together and the full context appears. The context remains unanimated for 60 frames."
      ],
      "controls": [
        [
          "Title",
          "0–89",
          "Opacity 100%; no keyframes"
        ],
        [
          "Context",
          "90–149",
          "Zoom X/Y 1; Position X/Y 0; Rotation 0; no Dynamic Zoom"
        ]
      ],
      "reading_hold": "Complete title: frames 0–89 (3 s). Settled context: 90–149 (2 s).",
      "adaptation": "Replace the title in Text, not in a flattened video. If it wraps, rewrite or reduce Size until it fits inside x=288…1632. Extend the title hold by moving both the cut and the context clip together. Update the cue marker.",
      "deliberate_differences": "The source builds/recenters letters and scales the browser after the cut. This recipe reproduces the complete-title-to-context cut only; static title entry and a stationary browser are intentional omissions, not a claim of full typography fidelity.",
      "documentation_pages": [
        1212,
        1219,
        1246,
        1291
      ],
      "node_graph": null,
      "construction_status": "documentation-checked; not tested in Resolve",
      "render_status": "blocked: no accessible Resolve application",
      "handles": "Stills/generators need no temporal handles. For real captures reserve 15 source-time frames before and after each used interval at a 30 fps capture rate; keep those handles outside the edit. No dissolve or optical-flow handles are needed here.",
      "retiming": "100% speed. No Optical Flow, Speed Warp, frame interpolation or simulated product wait."
    },
    {
      "id": "chapter-reset",
      "evidence_id": "chapter-return",
      "title": "Chapter reset → return to context",
      "intent": "Structure",
      "timeline_name": "R02_chapter_reset",
      "duration_frames": 180,
      "duration_s": 6.0,
      "fps": 30,
      "purpose": "Separate two arguments without losing the task. Use between related demonstrations, not in the middle of an uncompleted cause-and-effect beat.",
      "tracks": [
        [
          "V1",
          "context.png",
          0,
          45
        ],
        [
          "V1",
          "paper.png",
          45,
          120
        ],
        [
          "V1",
          "context.png (duplicate)",
          120,
          180
        ],
        [
          "V2",
          "Text title",
          45,
          120
        ]
      ],
      "steps": [
        "Build three adjacent V1 clips with durations 45, 75 and 60 frames. Use the same Media Pool context asset for both outer clips; do not independently rescale the return.",
        "Add a basic Text title over paper.png only: “Now inspect the result”, DejaVu Sans Bold, Size 72, Alignment Center, Anchor horizontal Center / vertical Center, Title Position X 960 / Y 540, color #23312e. Settings → Transform Position 0,0 and Zoom 1. No animation or transitions.",
        "Compare the last pre-card frame (44) with the first return frame (120). The fixture should be identical. For real captures, preserve the visible task state, not necessarily every pixel."
      ],
      "controls": [
        [
          "All context clips",
          "0–44 and 120–179",
          "Zoom 1; Position 0,0; no keyframes"
        ],
        [
          "Title/card",
          "45–119",
          "75 frames; full-opacity title for entire card"
        ]
      ],
      "reading_hold": "Chapter title has 75 complete frames (2.5 s); returned context gets 60 frames (2 s).",
      "adaptation": "Lengthen the middle card by ripple-moving the return and every downstream marker. Replace both context instances with the same asset/state. Do not manufacture a completed backend action across the title.",
      "deliberate_differences": "Exact pixel equality on return is a fixture contract; source task identity, not identical backend state, is evidenced. Source title letter construction is not recreated.",
      "documentation_pages": [
        967,
        1212,
        1219,
        1246
      ],
      "node_graph": null,
      "construction_status": "documentation-checked; not tested in Resolve",
      "render_status": "blocked: no accessible Resolve application",
      "handles": "Stills/generators need no temporal handles. For real captures reserve 15 source-time frames before and after each used interval at a 30 fps capture rate; keep those handles outside the edit. No dissolve or optical-flow handles are needed here.",
      "retiming": "100% speed. No Optical Flow, Speed Warp, frame interpolation or simulated product wait."
    },
    {
      "id": "context-detail",
      "evidence_id": "punch-cut",
      "title": "Context → detail by hard cut",
      "intent": "Focus",
      "timeline_name": "R03_context_detail",
      "duration_frames": 120,
      "duration_s": 4.0,
      "fps": 30,
      "purpose": "Make a small target readable immediately while retaining an orientation landmark. Prefer this to a camera move when the sentence is already about the detail.",
      "tracks": [
        [
          "V1",
          "context.png wide",
          0,
          45
        ],
        [
          "V1",
          "context.png detail",
          45,
          120
        ]
      ],
      "steps": [
        "Place context.png for 120 frames. Blade at frame 45 with the Blade Edit Mode tool, then return to Selection Mode. Both sides use the same source image.",
        "Select the second clip. Inspector → Video → Transform: linked Zoom X/Y 1.8; Position X −396, Y +108; Anchor Point X/Y 0; Rotation Angle 0. Dynamic Zoom off. Do not keyframe.",
        "The focus point (1180,600) in top-left source pixels maps to the output center. Step 44→45: no intermediate scales, dissolve, or black edge."
      ],
      "controls": [
        [
          "Wide",
          "0–44",
          "Zoom 1; Position 0,0"
        ],
        [
          "Detail",
          "45–119",
          "Zoom 1.8; Position −396,+108"
        ]
      ],
      "reading_hold": "Detail is complete on frame 45 and held for 75 frames (2.5 s).",
      "adaptation": "For a new full-frame asset, pick a real landmark and target. Use the tools.py focus command to calculate translation and reject uncovered edges. Its math assumes centered anchor and equal source/timeline raster with square pixels. For an edge target, choose a legal off-center framing, a different crop, or a new capture; never silently expose empty pixels. Check scaled/cropped media separately. Extend only the detail clip.",
      "deliberate_differences": "The source uses a different crop and sidebar. The 1.8× framing is a chosen example, not a fitted source magnification. Raster sharpness must be checked at output size.",
      "documentation_pages": [
        1246,
        1247
      ],
      "node_graph": null,
      "construction_status": "documentation-checked; not tested in Resolve",
      "render_status": "blocked: no accessible Resolve application",
      "handles": "Stills/generators need no temporal handles. For real captures reserve 15 source-time frames before and after each used interval at a 30 fps capture rate; keep those handles outside the edit. No dissolve or optical-flow handles are needed here.",
      "retiming": "100% speed. No Optical Flow, Speed Warp, frame interpolation or simulated product wait."
    },
    {
      "id": "camera-push",
      "evidence_id": "camera-push",
      "title": "Push, settle, then act",
      "intent": "Focus",
      "timeline_name": "R04_camera_push",
      "duration_frames": 120,
      "duration_s": 4.0,
      "fps": 30,
      "purpose": "Guide attention from the complete surface to a target when travel itself helps orientation. Keep the consequential action after the camera settles.",
      "tracks": [
        [
          "V1",
          "context.png",
          0,
          120
        ]
      ],
      "steps": [
        "Place context.png for 120 frames. Inspector → Video → Transform; disable Dynamic Zoom, keep Anchor Point 0,0 and Rotation 0.",
        "At frame 24 add diamond keyframes for linked Zoom and Position with the first values below. At frame 39 set the second values. Do not add an action while these parameters change.",
        "Open the Edit page Keyframe/Curves Editor, enable Zoom and Position channels, select both endpoints and choose Linear. Before frame 24 and after 39 values remain constant. This unfitted motion is deliberately simple; source blur and easing are not recovered."
      ],
      "controls": [
        [
          "Zoom X/Y",
          "24 → 39",
          "1.0 → 1.8; Linear"
        ],
        [
          "Position X",
          "24 → 39",
          "0 → −396; Linear"
        ],
        [
          "Position Y",
          "24 → 39",
          "0 → +108; Linear"
        ],
        [
          "All transform values",
          "40–119",
          "Hold final values; no further keys"
        ]
      ],
      "reading_hold": "Wide frames 0–23 (0.8 s); move spans 15 frame intervals (0.5 s); settled frames 40–119 (80 frames).",
      "adaptation": "Recompute the final translation for the new target; change both position channels and zoom together. A longer clip extends only the final hold. A shorter version cannot end before frame 99 if it needs 60 settled frames. For a faster/slower move, change both endpoints deliberately, not clip speed.",
      "deliberate_differences": "Linear interpolation and no motion blur differ from the source. Only the directed push and action-after-move order are implemented. Render comparison may require a chosen eased curve; it cannot establish OpenAI’s exact curve.",
      "documentation_pages": [
        1246,
        1291,
        1302,
        1303
      ],
      "node_graph": null,
      "construction_status": "documentation-checked; not tested in Resolve",
      "render_status": "blocked: no accessible Resolve application",
      "handles": "Stills/generators need no temporal handles. For real captures reserve 15 source-time frames before and after each used interval at a 30 fps capture rate; keep those handles outside the edit. No dissolve or optical-flow handles are needed here.",
      "retiming": "100% speed. No Optical Flow, Speed Warp, frame interpolation or simulated product wait."
    },
    {
      "id": "pointer-action",
      "evidence_id": "pointer-type",
      "title": "Target → dwell → input",
      "intent": "Show cause",
      "timeline_name": "R05_pointer_action",
      "duration_frames": 180,
      "duration_s": 6.0,
      "fps": 30,
      "purpose": "Let viewers locate the intended control before text changes. A pointer is an editorial aid here, not evidence that a real click or request succeeded.",
      "tracks": [
        [
          "V1",
          "input-empty.png",
          0,
          180
        ],
        [
          "V2",
          "Text: “Arrange”",
          90,
          100
        ],
        [
          "V2",
          "Text: “Arrange these”",
          100,
          110
        ],
        [
          "V2",
          "Text: “Arrange these notes”",
          110,
          120
        ],
        [
          "V2",
          "Text: “Arrange these notes by topic.”",
          120,
          180
        ],
        [
          "V3",
          "pointer.png",
          0,
          180
        ]
      ],
      "steps": [
        "Use a full-frame transparent pointer.png. Its tip starts at source pixel (960,540). On V3 keyframe Transform Position as below; Zoom 1, Anchor Point 0,0. Choose Linear in the Edit Curves Editor.",
        "Create the first basic Text title, then duplicate it three times for the remaining word states. Title panel: DejaVu Sans Regular, Size 40, color #23312e, Alignment Left, Anchor horizontal Left / vertical Center, Title Position 960,540. Settings → Transform Position X −576 / Y −60, Zoom 1. The text block anchors at output pixel (384,600), below the parked pointer. Keep all four clips identical except for text and duration.",
        "At frame 120 the fourth native title reads “Arrange these notes by topic.” Do not replace it with the raster request.png: that would introduce a font/baseline matching problem. The word-build uses cuts, not opacity fades. Do not add a submit animation: the source interval does not establish completed submission."
      ],
      "controls": [
        [
          "Pointer Position X/Y",
          "0 and 29",
          "+340,+200 (tip at 1300,340)"
        ],
        [
          "Pointer Position X/Y",
          "59",
          "−540,0 (tip at 420,540); Linear from 29"
        ],
        [
          "Pointer",
          "60–179",
          "Stationary at target"
        ],
        [
          "Text plates",
          "90 / 100 / 110 / 120",
          "Discrete word-build; 100% opacity"
        ]
      ],
      "reading_hold": "Target dwell 60–89: 30 frames (1 s). Complete request 120–179: 60 frames (2 s).",
      "adaptation": "Replace the pointer route with the actual capture’s cursor when using real UI; never show two pointers. Change the four native title strings while retaining identical anchors, font metrics and Transform settings. Add time at target or at the final request; do not stretch the cursor travel automatically.",
      "deliberate_differences": "The source camera also reframes and its request remains unfinished inside the inspected window. The fixture finishes a shorter original request. This discrete word-build is not a recreation of source caret cadence. Text+ Write On is deliberately not specified: the inspected manual’s direction wording requires an application check.",
      "documentation_pages": [
        1212,
        1219,
        1246,
        1291,
        1303,
        2434
      ],
      "node_graph": null,
      "construction_status": "documentation-checked; not tested in Resolve",
      "render_status": "blocked: no accessible Resolve application",
      "handles": "Stills/generators need no temporal handles. For real captures reserve 15 source-time frames before and after each used interval at a 30 fps capture rate; keep those handles outside the edit. No dissolve or optical-flow handles are needed here.",
      "retiming": "100% speed. No Optical Flow, Speed Warp, frame interpolation or simulated product wait."
    },
    {
      "id": "selection-scope",
      "evidence_id": "selection-context",
      "title": "Keep a selected scope through a reframe",
      "intent": "Show cause",
      "timeline_name": "R06_selection_scope",
      "duration_frames": 150,
      "duration_s": 5.0,
      "fps": 30,
      "purpose": "Keep the selected region tied to the content it identifies while changing the outer framing. Do not imply that the requested change completed.",
      "tracks": [
        [
          "V1",
          "Fusion Composition",
          0,
          150
        ]
      ],
      "steps": [
        "Effects → Effects → Fusion Composition; set 150 frames. Open Fusion. Drag shell.png and document.png from the Media Pool into the Node Editor and rename MediaIn nodes Shell and Document.",
        "Connect the graph below. MergeDocument puts document content over Shell, limited by fixed Viewport. Add a green Background SelectionFill (#32725d, alpha 0.18, 1920×1080) through SelectionRect into MergeSelection, then place OuterCamera AFTER both content and selection.",
        "OuterCamera: Pivot .5,.5; Center .5,.5; Size 1. Keyframe Size 1 at local frame 30, 1.35 at 45; 1.35 at 105, 1 at 120. Center stays .5,.5. Select Size in Spline and choose Linear; retain flat holds."
      ],
      "controls": [
        [
          "Viewport",
          "constant",
          "Center .5,.518518519; Width .65; Height .574074074; Soft Edge 0; Corner Radius 0"
        ],
        [
          "SelectionRect",
          "constant",
          "Center .5,.625; Width .65; Height .109259259; Soft Edge 0"
        ],
        [
          "OuterCamera Size",
          "30 / 45 / 105 / 120",
          "1 / 1.35 / 1.35 / 1; Linear"
        ],
        [
          "Selection",
          "0–149",
          "Already selected; no completion or selection-onset claim"
        ]
      ],
      "reading_hold": "Selected detail is stationary for frames 46–104 (59 frames); extend that interval for dense real content. Final wide framing is held for 29 frames.",
      "adaptation": "Replace Document, then recalculate SelectionRect from the actual selected pixel rectangle using tools.fusion_rectangle. Keep the selection merge before OuterCamera. For real UI, prefer captured native selection over a synthetic highlight.",
      "deliberate_differences": "The source selection exists before the interval and its contextual request changes. This recipe isolates selection-to-content registration during reframing. It omits the presenter inset and does not reproduce the complete interaction.",
      "documentation_pages": [
        2264,
        2540,
        2542,
        2929,
        2930,
        1604
      ],
      "node_graph": "Shell → MergeDocument.Background\nDocument → MergeDocument.Foreground\nViewport [Rectangle] → MergeDocument.EffectMask\nMergeDocument → MergeSelection.Background\nSelectionFill [Background] → MergeSelection.Foreground\nSelectionRect [Rectangle] → MergeSelection.EffectMask\nMergeSelection → OuterCamera [Transform] → MediaOut1",
      "construction_status": "documentation-checked; not tested in Resolve",
      "render_status": "blocked: no accessible Resolve application",
      "handles": "Stills/generators need no temporal handles. For real captures reserve 15 source-time frames before and after each used interval at a 30 fps capture rate; keep those handles outside the edit. No dissolve or optical-flow handles are needed here.",
      "retiming": "100% speed. No Optical Flow, Speed Warp, frame interpolation or simulated product wait."
    },
    {
      "id": "masked-scroll",
      "evidence_id": "scroll-mask",
      "title": "Scroll content behind a fixed viewport",
      "intent": "Navigate",
      "timeline_name": "R07_masked_scroll",
      "duration_frames": 150,
      "duration_s": 5.0,
      "fps": 30,
      "purpose": "Bring an off-screen result into view without moving the window chrome. Reading begins after the document lands, not while it is passing through the viewport.",
      "tracks": [
        [
          "V1",
          "Fusion Composition",
          0,
          150
        ]
      ],
      "steps": [
        "Add a 150-frame Fusion Composition. Drag shell.png and document.png into Fusion as Shell and Document. Add Transform, Rectangle and Merge with Shift-Space; rename as in the graph.",
        "Connect Shell to MergeViewport’s orange Background input FIRST. Document → ScrollContent → green Foreground. Connect Viewport to MergeViewport’s blue Effect Mask input. Output goes to MediaOut1. Do not mask the Transform itself or transform the combined shell.",
        "Set Viewport and ScrollContent values below. In Spline, show ScrollContent’s displacement animation, select the endpoints and set Linear. If Center creates a Path modifier, retain a straight vertical path: no intermediate spatial controls. Inspect both the spatial route and temporal displacement."
      ],
      "controls": [
        [
          "Viewport Rectangle",
          "constant",
          "Center X .5; Y .518518519; Width .65; Height .574074074; Soft Edge 0; Corner Radius 0; Solid on; Invert off"
        ],
        [
          "ScrollContent",
          "0 and 30",
          "Center .5,.5; Pivot .5,.5; Size 1; Angle 0"
        ],
        [
          "ScrollContent Center",
          "60",
          ".5,.722222222 (240 output pixels upward); Linear from 30"
        ],
        [
          "ScrollContent",
          "61–149",
          "Hold; no outer transform"
        ]
      ],
      "reading_hold": "Pre-scroll 30 frames; travel 30 frame intervals (1 s); fully stopped result 61–149 (89 frames, 2.967 s).",
      "adaptation": "All supplied media is 1920×1080. Keep document content full-frame, even when mostly transparent. For taller captures, first normalize the canvas deliberately; do not accept an automatic fit that shrinks text. Recompute scroll distance in pixels/1080 and ensure the document covers the whole viewport at both ends. Extend the stationary tail only.",
      "deliberate_differences": "The source calendar has residual motion. The neutral list stops completely. The 240 px distance and linear travel are chosen; neither scroll physics nor exact source viewport geometry has been fitted.",
      "documentation_pages": [
        2264,
        2540,
        2542,
        2929,
        2930,
        1604
      ],
      "node_graph": "Shell [MediaIn] → MergeViewport.Background (orange)\nDocument [MediaIn] → ScrollContent [Transform] → MergeViewport.Foreground (green)\nViewport [Rectangle] → MergeViewport.EffectMask (blue)\nMergeViewport → MediaOut1",
      "construction_status": "documentation-checked; not tested in Resolve",
      "render_status": "blocked: no accessible Resolve application",
      "handles": "Stills/generators need no temporal handles. For real captures reserve 15 source-time frames before and after each used interval at a 30 fps capture rate; keep those handles outside the edit. No dissolve or optical-flow handles are needed here.",
      "retiming": "100% speed. No Optical Flow, Speed Warp, frame interpolation or simulated product wait."
    },
    {
      "id": "result-reveal",
      "evidence_id": "split-result",
      "title": "Reveal a container, then its contents",
      "intent": "Prove",
      "timeline_name": "R08_result_reveal",
      "duration_frames": 150,
      "duration_s": 5.0,
      "fps": 30,
      "purpose": "Distinguish the arrival of a result area from readable proof. Do not count the empty pane as result reading time or imply a measured application response time.",
      "tracks": [
        [
          "V1",
          "Fusion Composition",
          0,
          150
        ]
      ],
      "steps": [
        "Create a 150-frame Fusion Composition. Add shell.png, result-empty.png and result.png from the Media Pool. Connect the two Merge nodes in the graph; both foreground layers keep their full-frame geometry.",
        "PaneWindow is a Rectangle effect mask on MergeEmpty. Reveal its horizontal width while preserving the left edge at x=1020: at frame 30 Center .53125,.518518519 / Width 0; at frame 45 Center .678125,.518518519 / Width .29375. Height .574074074, Soft Edge 0, Corner Radius 0. Spline Linear for width and center displacement.",
        "MergeResult Blend stays 0 through frame 74 and is 1 from 75 onward. Use two keys 74=0, 75=1 with Linear; consecutive frames give a discrete arrival. Do not add a key at the exclusive end."
      ],
      "controls": [
        [
          "PaneWindow Width",
          "30 → 45",
          "0 → .29375; Linear"
        ],
        [
          "PaneWindow Center X",
          "30 → 45",
          ".53125 → .678125; Linear"
        ],
        [
          "PaneWindow Center Y / Height",
          "constant",
          ".518518519 / .574074074"
        ],
        [
          "MergeResult Blend",
          "74 / 75",
          "0 / 1; thereafter 1"
        ]
      ],
      "reading_hold": "Pane reveal 30–45; empty pane 46–74 (29 frames); complete result 75–149 (75 frames, 2.5 s). The empty interval is an illustrative state order, not simulated real latency.",
      "adaptation": "Replace both pane layers with matched full-frame assets. Change the mask width and center together so the left edge remains fixed. If real loading lasts longer, preserve captured state order and label any omitted time rather than fabricating a wait. Extend only the complete-result tail.",
      "deliberate_differences": "The source also narrows the conversation and moves the outer camera. This recipe isolates container-before-content staging; it does not recreate the full split-layout motion. The fixture is not a running application.",
      "documentation_pages": [
        2264,
        2542,
        1604
      ],
      "node_graph": "Shell → MergeEmpty.Background\nEmptyPane → MergeEmpty.Foreground\nPaneWindow [Rectangle] → MergeEmpty.EffectMask\nMergeEmpty → MergeResult.Background\nResult → MergeResult.Foreground\nMergeResult → MediaOut1",
      "construction_status": "documentation-checked; not tested in Resolve",
      "render_status": "blocked: no accessible Resolve application",
      "handles": "Stills/generators need no temporal handles. For real captures reserve 15 source-time frames before and after each used interval at a 30 fps capture rate; keep those handles outside the edit. No dissolve or optical-flow handles are needed here.",
      "retiming": "100% speed. No Optical Flow, Speed Warp, frame interpolation or simulated product wait."
    },
    {
      "id": "reading-hold",
      "evidence_id": "result-tour",
      "title": "Protect a complete-result reading hold",
      "intent": "Prove",
      "timeline_name": "R09_reading_hold",
      "duration_frames": 120,
      "duration_s": 4.0,
      "fps": 30,
      "purpose": "Give the audience an interval in which the evidence is complete, stable and large enough to read. A container animation or unfinished output is not a reading hold.",
      "tracks": [
        [
          "V1",
          "shell.png",
          0,
          120
        ],
        [
          "V2",
          "result.png",
          0,
          120
        ]
      ],
      "steps": [
        "Place shell.png and result.png with matching start and 120-frame duration. Inspector: Zoom 1, Position 0,0, Opacity 100%, Composite Mode Normal. No keyframes on either clip.",
        "Place a timeline marker at frame 0 named READ_START and one at the next cut named READ_END. Watch at actual meeting-view size, not only full-screen.",
        "If continuing result-reveal, use its final composite state without a framing reset. Treat this recipe’s 120 frames as additional hold only if the assembly explicitly calls for it."
      ],
      "controls": [
        [
          "All layers",
          "0–119",
          "Unchanging framing; no transition; no cursor movement"
        ]
      ],
      "reading_hold": "120 frames (4 s) are chosen for the short neutral fixture. No empirical human-reading threshold is claimed. Dense evidence needs a longer timed-recording pause or a simpler crop.",
      "adaptation": "Replace the content and test the smallest relevant labels at intended playback size. Extend this clip at 100% speed. For a real capture use a genuine stable interval; do not freeze a live clock or fake a finished app state without disclosure.",
      "deliberate_differences": "The cited native source subset verifies a short hero hold, not a universal four-second reading rule. The wider excerpt scrolls and later changes context; those later boundaries are not frame-exact here.",
      "documentation_pages": [
        967,
        1246
      ],
      "node_graph": null,
      "construction_status": "documentation-checked; not tested in Resolve",
      "render_status": "blocked: no accessible Resolve application",
      "handles": "Stills/generators need no temporal handles. For real captures reserve 15 source-time frames before and after each used interval at a 30 fps capture rate; keep those handles outside the edit. No dissolve or optical-flow handles are needed here.",
      "retiming": "100% speed. No Optical Flow, Speed Warp, frame interpolation or simulated product wait."
    },
    {
      "id": "object-continuity",
      "evidence_id": "object-context",
      "title": "Carry identity across a context cut",
      "intent": "Connect",
      "timeline_name": "R10_object_continuity",
      "duration_frames": 150,
      "duration_s": 5.0,
      "fps": 30,
      "purpose": "Use recognizable content to connect two contexts even when its size and position change. This is semantic continuity, not a pixel-matched morph.",
      "tracks": [
        [
          "V1",
          "input-empty.png",
          0,
          60
        ],
        [
          "V2",
          "request.png",
          0,
          60
        ],
        [
          "V1",
          "device-empty.png",
          60,
          150
        ],
        [
          "V2",
          "device-request.png",
          64,
          150
        ]
      ],
      "steps": [
        "Build an isolated request for frames 0–59. At frame 60 cut both layers to the empty device context. No dissolve or scaling interpolation spans the cut.",
        "Keep the device empty for four output frames, 60–63. At frame 64 add device-request.png with 100% opacity. All assets remain Zoom 1 / Position 0,0.",
        "Check the complete request text before and after the cut. It must stay “Arrange these notes by topic.” Avoid changing the promised task while preserving only a decorative shape."
      ],
      "controls": [
        [
          "Context cut",
          "59 → 60",
          "Direct replacement, no in-between geometry"
        ],
        [
          "Device request",
          "64–149",
          "Full opacity; unchanged text; no keyframes"
        ]
      ],
      "reading_hold": "Original request 60 frames (2 s). Empty context 4 frames. Re-established request 86 frames (2.867 s).",
      "adaptation": "Change request.png and device-request.png together using build_assets.py. Keep the four-frame establishment explicit; do not turn it into an alleged product latency. Extend the final device hold for longer text.",
      "deliberate_differences": "The source phone scales and text grows back rapidly. This fixture uses a static device and a direct text return. It preserves the observed context-cut/brief-empty/identity-return order, not a geometric match or identical cadence.",
      "documentation_pages": [
        1246,
        967
      ],
      "node_graph": null,
      "construction_status": "documentation-checked; not tested in Resolve",
      "render_status": "blocked: no accessible Resolve application",
      "handles": "Stills/generators need no temporal handles. For real captures reserve 15 source-time frames before and after each used interval at a 30 fps capture rate; keep those handles outside the edit. No dissolve or optical-flow handles are needed here.",
      "retiming": "100% speed. No Optical Flow, Speed Warp, frame interpolation or simulated product wait."
    },
    {
      "id": "anchored-overlay",
      "evidence_id": "caption-cut",
      "title": "Keep an overlay independent of the shot",
      "intent": "Label",
      "timeline_name": "R11_anchored_overlay",
      "duration_frames": 150,
      "duration_s": 5.0,
      "fps": 30,
      "purpose": "Keep a short identifier in screen space while the underlying shot changes. Use only when it adds information without obscuring the result.",
      "tracks": [
        [
          "V1",
          "context.png wide",
          0,
          60
        ],
        [
          "V1",
          "context.png detail",
          60,
          150
        ],
        [
          "V2",
          "Text label",
          15,
          135
        ]
      ],
      "steps": [
        "Build the wide/detail cut as context-detail but cut at frame 60. Apply Zoom 1.8 and Position −396,+108 ONLY to the second V1 clip.",
        "Add one continuous basic Text title on V2 from frame 15 to 135: “Original fixture”, DejaVu Sans Bold, Size 32, color #23312e, Alignment Left, Anchor horizontal Left / vertical Center, Title Position 960,540. In Settings → Transform set Position X −672 / Y −464, Zoom 1. This places the left anchor at output pixel (288,1004), below the window and clear of its footer. No keyframes.",
        "Do not put V2 inside a transformed compound clip. Compare overlay glyph position at frames 59 and 60; the overlay should not jump, scale, fade, or be re-rendered by a second title clip."
      ],
      "controls": [
        [
          "V1",
          "60–149",
          "Zoom 1.8; Position −396,+108"
        ],
        [
          "V2",
          "15–134",
          "Title Position 960,540; Anchor Left/Center; Settings Transform Zoom 1, Position −672,−464; Opacity 100%"
        ]
      ],
      "reading_hold": "Overlay persists 120 frames (4 s) across the cut; remove it before the next evidence beat if it competes with the subject.",
      "adaptation": "Move the overlay once in its own Inspector to clear new content. Preserve one continuous overlay clip across the underlying cut. When extending the shot, choose its disappearance independently rather than scaling its duration automatically.",
      "deliberate_differences": "The source is a presenter name/role overlay. The neutral fixture labels an artifact; no talking head is composited into the presentation. Exact font metrics, baseline position and original reveal are not recreated.",
      "documentation_pages": [
        1212,
        1219,
        1246,
        2264
      ],
      "node_graph": null,
      "construction_status": "documentation-checked; not tested in Resolve",
      "render_status": "blocked: no accessible Resolve application",
      "handles": "Stills/generators need no temporal handles. For real captures reserve 15 source-time frames before and after each used interval at a 30 fps capture rate; keep those handles outside the edit. No dissolve or optical-flow handles are needed here.",
      "retiming": "100% speed. No Optical Flow, Speed Warp, frame interpolation or simulated product wait."
    },
    {
      "id": "quiet-ending",
      "evidence_id": "quiet-ending",
      "title": "Finish proof, then release attention",
      "intent": "End",
      "timeline_name": "R12_quiet_ending",
      "duration_frames": 120,
      "duration_s": 4.0,
      "fps": 30,
      "purpose": "Let the proof finish before a small, quiet original identity. The separate talking-head ending buffer is a different timing requirement.",
      "tracks": [
        [
          "V1",
          "paper.png",
          0,
          120
        ],
        [
          "V2",
          "mark.png",
          0,
          120
        ]
      ],
      "steps": [
        "After a completed result hold, cut to paper.png with mark.png above it for 120 frames. No audio tracks are required. Leave both images at Zoom 1 and Position 0,0.",
        "Do not add a crossfade to black or borrow the source logo. This recipe implements the quiet endpoint only; no letter deletion or knot animation is included.",
        "Set the final export Out point to the last visible frame, 119, not the exclusive frame 120. In an actual two-video presentation, compute the permitted end on the shared playback timeline before setting this length."
      ],
      "controls": [
        [
          "Paper and mark",
          "0–119",
          "Static; Normal composite; full opacity; no keyframes"
        ]
      ],
      "reading_hold": "120 quiet frames (4 s) are a chosen study default, not an OBS buffer or a measured source hold.",
      "adaptation": "Replace mark.png with an original licensed mark on the same transparent canvas. Preserve generous margins. Shorten/extend the endpoint only after proof completion and the real recorded tail have been checked. Never freeze, stretch or synthesize the presenter’s wave.",
      "deliberate_differences": "The source has a wordmark-to-knot construction. Those branded mechanics are not reproduced; the five late samples establish a quiet endpoint but do not prove every intervening source frame is identical.",
      "documentation_pages": [
        967,
        1246,
        4180
      ],
      "node_graph": null,
      "construction_status": "documentation-checked; not tested in Resolve",
      "render_status": "blocked: no accessible Resolve application",
      "handles": "Stills/generators need no temporal handles. For real captures reserve 15 source-time frames before and after each used interval at a 30 fps capture rate; keep those handles outside the edit. No dissolve or optical-flow handles are needed here.",
      "retiming": "100% speed. No Optical Flow, Speed Warp, frame interpolation or simulated product wait."
    }
  ]
}
