.studio schema #11
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
needs-info
needs-triage
question
ready-for-agent
ready-for-human
wayfinder:grilling
wayfinder:map
wayfinder:prototype
wayfinder:research
wayfinder:task
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
crowmaki/ai-studio#11
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Part of #1
Blocked by: #2
Question
What is the SQLite schema for a Project? It must cover Scenes and Lines (stable IDs), Entities, Looks, Wardrobe items, Reference sets, Tiles, Reference versions, Lock snapshots, Atlases (identified by content), Setups, Shots, Boards, Keyframes, Performances, Takes, Renditions, provenance, and queue jobs. Small assets are stored as blobs and Renditions sit in the sibling media folder (ADR-0001). Provenance must be able to grow into a chain for future Take extension.
From "Dailies review and circling" (#7): the schema needs on Take a stored
seenflag, an NG flag, a list of notes (each with optional timecode),rerolled_from(Take id), and circled-at time; a per-Shot Pinned take reference (must be circled; cleared on uncircle). Take numbers are never reused, even when a failed Take is deleted.From "Animatic duration rules" (#8), the schema must also hold: per-Line duration overrides; per-Project speaking/action rates; Shot head/tail handles and a length override; user-orderable Setup order; Cut overrides (Line or simultaneous group → Shot); and per-Take Line marks.
From "Prompt composer phrasing" (#9), fields the schema must hold:
From "Reference slot budget" (#10), things the schema must hold: a per-Project ordered list of reference categories (Keyframes, Atlases, Wardrobe, Location, Board, Props), plus an app-wide default outside the Project that seeds new ones. Per Shot: an optional stored Slot list, which is a full ordered list of concrete references plus the sent/not-sent line position, with "excluded" vs "over budget" per item and a "new" flag. An absent list means the Shot follows the Project order live. Per Take: the exact slot assignment it was sent with (which reference went in which numbered slot).
Resolution
A table-level model. The full column-by-column DDL gets written in the build issue that creates each table. Field lists from the comments above (Dailies, Animatic, Prompt composer, Slot budget) go in as written there.
Cross-cutting
d:idas a unique column.blobtable (BLAKE3 hash, media type, size, pixel dimensions). Every other table points at a hash. Unused blobs are removed by a sweep on Project open and on demand, with no reference counts.take_input,take_link) cannot be hard-deleted. Deleting it setsdeleted_atand hides it everywhere except provenance and the Dailies inputs comparison. Rows nothing has consumed are hard-deleted. Exceptions:merged_into.PRAGMA user_versionwith ordered migrations embedded instudio-core, applied in one transaction on open. Before migrating, the file is copied to<name>.studio.bak-v<N>. A file whose version is newer than the app is refused.PRAGMA application_idis set to a fixed value.journal_mode=DELETEon a clean close, so the file at rest is a single file.<name>.studio.lockfile holds the PID and host.projectrow with typed columns. Settings that are lists get their own tables:lighting,slug_lighting,reference_category_order,notation_entry(Notation entries are retired, never deleted). App-wide defaults are a JSON file in the app config directory, copied into a Project when it's created and never read again by that Project.Entities and references
character,locationandproptables with no shared parent. "Entity" stays a glossary word, not a table.look.reference_set_id,wardrobe_item.reference_set_id,prop.reference_set_id,character.voice_set_id. Alocation_lighting(location, lighting, reference_set, lighting_note)row holds each per-Lighting set. It exists only when a Scene at that Location uses that Lighting, or when the user adds it.reference_sethas an id and akind(turnaround, mannequin, location, prop or voice).tilehas aroleand anordinal.lock_snapshot(set, number)withsnapshot_tile(snapshot, tile, reference_version), immutable. The current snapshot is always the highest number. Rolling back makes a new snapshot that copies the old pick, and locking an identical pick is a no-op.atlas(input_key, blob, built_at).input_keyis a hash of the ordered snapshot IDs, the layout version and the size settings. Setups store only their grouping and never point at an Atlas. Takes record the Atlases they used. Atlases nothing needs can be dropped and rebuilt (byte-stable). See ADR-0005.Script, Setups, Shots
positionwithin their Scene. The script is frozen after import.first_line_idandlast_line_id, within one Scene. Transition and shot-direction Lines can fall inside the range.setup(scene, letter, setup_order). The letter is unique within the Scene and never reused.setup_orderis separate and the user can reorder it.shot(setup, index, next_take_number). The label is12Awhen the Setup has one Shot, otherwise12B·1. Take numbers come from the counter. When a Shot is split, its existing Takes stay on the first part.scene_cast(scene, character, look, wardrobe_item?)says how each Character appears in the Scene. Speaking Characters are added automatically, with their default Look.setup_subject(setup, character, position)says who is in frame and the<Subject N>order. A speaking Character need not be a subject (off-screen dialogue). Props are not cast; they come from Shot mentions.text,mention{kind,id},dialogue{line_id}), plus a derivedshot_mention(shot, character|prop)table that the core rewrites on every save. A merge rewrites both in one transaction.shot_slot_item(shot, position, candidate_key, state = sent/excluded/over_budget, is_new)plusshot.slot_line. Keys are logical:keyframe:<id>,atlas:<group>,wardrobe:<id>,location_angle:<tile>,board,prop:<id>. With no rows, the Shot follows the Project order live.Boards, Keyframes, Performances
panel(board, position, canvas_w, canvas_h, sketch_blob, annotations JSON). Annotation positions are normalized. Boards are edited in place, with no history. A Take records the composited blob that was sent.projectrow and changeable at any time, from a fixed list with no custom values. Shots can override it, so a Shot's effective ratio is its override, else the Project's. Changing the effective ratio makes the Shot's Takes stale. A Panel keeps the canvas it was drawn on and is barred at send time; its first new stroke re-canvases it to the current ratio. Keyframes are fitted the same way, with a warning badge. The Animatic and FCPXML timeline stay at the Project ratio, with other-ratio Shots letterboxed into it.keyframe(shot, anchor = start/end/time, at_seconds?, image_blob, origin = imported/generated/take_frame). A take_frame Keyframe records its source Take, Rendition and frame time, and its pixels are extracted into a blob. A Take made with it gets atake_link(frame_from)edge. In the slice: a Dailies action, "Use first / last frame as Keyframe for…".performance(scene, number, audio_blob, created_at), immutable. The current one is the highest number.performance_source(performance, take, …)is an edge list, and the Scene has aperformance_offflag. How Lines are marked in a Performance is left to "Marking Lines in a Performance".Takes and production
Provenance:
take_inputhas one row per thing the Take consumed, each with a real FK and the slot number it filled. Shot and Setup text fields are recorded by value or hash.take_link(take, other_take, kind)holds Take-to-Take edges, with kindsrerolled_fromandframe_fromnow andextendslater.Renditions:
rendition(take, kind = draft/final, via = draft/promotion/single-pass, state, path?), created when queued. Media folder:renditions/<rendition-id>.mp4andlatents/<rendition-id>.{video,audio}.latent, with paths stored relative to the folder. Human names exist only in the edit package and the UI.Queue: a
jobtable with one row per ComfyUI submission:queue_position,attempt, our ownprompt_id,error, and timestampsA job left
submittedis re-sent on open. The scheduling policy is left to "Render worker scheduling".Knock-ons