Skip to content

M2b: timed overlays, credits and Save to GAM - #4

Merged
davior merged 1 commit into
mainfrom
claude/funny-knuth-en5fly
Oct 16, 2026
Merged

davior merged 1 commit into
mainfrom
claude/funny-knuth-en5fly

Conversation

@davior

@davior davior commented Oct 16, 2026

Copy link
Copy Markdown
Owner

This finishes M2 of the plan of attack. Renders now draw what the VideoSpec already described but M2a only warned about: on-screen text, lower thirds and pictures. They also carry credits, and a finished render can be filed back into GAM.

Pairs with davior/gam#37 (GAM-3). Merge order doesn't matter. Against a GAM without it, Save to GAM still works, and the file lands as an ordinary upload instead of a "Video Creator" export.

What you can do

  • Scenes tab: "On screen" per scene. Add text, a name and role (lower third), or a picture from GAM.
    • Settings: position, size and colour for text; width and opacity for a picture; and a fade.
    • Timing: each one shows for the whole scene unless you choose From and Until. Those can be the scene's start or end, any narration line's start or end, or a later scene, each with an offset in seconds. Reaching into a later scene is how you hold a title through a dissolve.
  • Render tab: Credits.
    • "Credit the library's pictures, footage and music" pulls each GAM asset's credit, so you correct a credit once in GAM and every video using it follows.
    • Toggles for "Show them on a card at the end" and "Put them in the description".
    • Extra lines of your own.
  • Render list:
    • Save to GAM on a finished full render, then an In GAM ↗ link to it. Saving twice files it once; if it was deleted in GAM, it is filed again.
    • The latest render shows its description (chapters as 0:00 Title lines, then credits) with a Copy button.

How

  • Overlays are one extra video pass after the stitch (ffmpeg.build_overlay_pass). Each layer is a full-frame PNG drawn by Pillow, looped, alpha-faded at absolute times, and composited with overlay=…:enable='between(t,a,b)'.
    • Doing it per shot would have kept the shot cache, but couldn't draw across a join.
    • The pass only runs when a video has timed overlays, and it copies the sound.
  • compile.place_overlays follows place_tracks:
    • anchors default to the overlay's own scene;
    • fades are held to half the window, so the fade in and fade out never cross;
    • an orphaned or backwards span, or a picture overlay given a non-picture, is dropped with a warning and never fails the render.
  • Credits:
    • media.resolve now keeps each asset's GAM credit.
    • credits.credit_lines orders them by first use, says each once, and appends the extra lines.
    • credits_units appends end cards, splitting past 18 lines.
    • The estimate counts the card.
  • Save to GAM:
    • POST /api/renders/{id}/save-to-gam streams the file as the requester, sending source=gvc_export, origin_project_id and origin_reference_id.
    • It then names the asset "Title (vN)" and sets the description through GAM's PATCH.
    • Previews are refused: they are 480p working copies.
  • Migration: render_job.description and render_job.gam_asset_id, run by the entrypoint as usual.
  • Refactor: the scene-or-line anchor picker is now shared (AnchorSelect, spec/anchors.ts) between the Soundtrack tab and overlays.

Tests

  • Backend: pytest -q passes, 459 tests. New ones include:
    • Real-ffmpeg pixel checks:
      • a text overlay is dark before 1.0 s, drawn at 2.0 s, still drawn inside the dissolve and 1.2 s into the next scene, and gone after;
      • a lower third shows only between 0.5 s and 2.0 s.
    • Credits in a real render: the end card adds its length, and the description lists the chapters and the credits, with a credit two assets share appearing once.
    • Compiler: default spans, own-scene and beat anchors, reaching into the next scene, fade clamping, orphaned and backwards spans, and a picture overlay without a picture.
    • Credit lines and cards: ordering and de-duplication, card splitting, the description format, and the overlay-pass argv.
    • Save to GAM: the token and form fields forwarded, naming and description, idempotency, re-filing after a GAM delete, refusing previews and unfinished renders, and the owner check.
  • Migration: upgrade, downgrade and upgrade again on a fresh database.
  • Frontend: format, lint, npm test (98 tests) and build pass. New tests cover the overlay helpers, the anchor value round-trip, the editor timing a lower third to a line and a later scene, credits on and off, and Save to GAM to the In GAM link.
  • Checked by eye: a lower third with a text overlay, and a credits card, drawn at 720p.

🤖 Generated with Claude Code

https://claude.ai/code/session_016fiRJAt34ag62iPiuMkNhm


Generated by Claude Code

Text, lower thirds and pictures are drawn over the stitched video in one
extra pass, each in its window with alpha fades, so one can be held
across a join. Their anchors default to their own scene and may name a
line or a later scene; one that cannot be placed is dropped with a
warning.

Credits come from each GAM asset's credit, in order of first use and
said once, plus extra lines: as end cards (split past a screenful) and
in a description with the chapters, to paste where the video goes.

A finished full render can be saved to GAM as a gvc_export with its
project and render as origin (GAM-3), named and described, once.

The editor gets an On screen section per scene, a Credits section in
the Render tab, Save to GAM, and the description with a copy button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016fiRJAt34ag62iPiuMkNhm
@davior
davior marked this pull request as ready for review October 16, 2026 07:52
@davior
davior merged commit d84d991 into main Oct 16, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants