beutl-agent-timeline-from-shotlist
GitHub将镜头列表或分镜脚本转化为 Beutl 项目时间线。通过 Agent Editing Toolkit MCP 工具,按视频类型分类、静态分镜构建、特效与动画添加等阶段自动化生成视频工程。
Trigger Scenarios
Install
npx skills add b-editor/beutl --skill beutl-agent-timeline-from-shotlist -g -y
SKILL.md
Frontmatter
{
"name": "beutl-agent-timeline-from-shotlist",
"description": "Build a Beutl timeline from a shot list through the Agent Editing Toolkit MCP tools."
}
Beutl Agent Timeline From Shot List
Use this skill when an agent needs to turn a shot list, storyboard, or timed brief into a Beutl project through the Agent Editing Toolkit.
Workflow
Author storyboard-first: plan a fine shot breakdown, build the static layout of every shot (static storyboard) with no keyframes and no effects, lock it, then add effects, then motion. Do not animate or add effects until the static storyboard reads correctly. The phases below map to that order.
Phase -1 — Video type classification
Before classifying, check the intake. If the incoming request is terse (missing two or more of: subject specifics, target duration, mood or audience, explicit style/palette constraints, an asset inventory) or the user supplied reference images/video/URLs for the intended look, load beutl-agent-brief-expansion first and use its recorded expandedBrief as the brief for classification and Phase 0. Expanded-brief fields are derived defaults: user-stated constraints stay literal, and the derived paletteDirection feeds derive_palette inputs rather than replacing its outputs. Runs that started from brief expansion are low-effort mode and must run the visual-review convergence loop in Phase 4 (step 21a).
Classify the brief before Phase 0. Record videoType and a one-line reason in notes, then call get_started(videoType) and follow the returned type workflow. Supported values are motion-graphics, footage-cut, slideshow, lyric-captions, and logo-intro. If the brief requires source clips, photos, music, SFX, or fonts that are missing from the workspace, load beutl-agent-asset-sourcing before Phase 0, decide source-or-generate per asset, and record provenance in assets/manifest.json before placing media.
| videoType | Signals |
|---|---|
motion-graphics |
Authored graphics, kinetic type, promo/explainer/infographic motion, BPM or beat-grid language, layered background grammar, no source media inventory as the main driver. |
footage-cut |
User supplies video clips, says edit my clips/vlog/event/interview/B-roll, asks for trim/order/source audio/music bed, or needs narrative clip coverage. |
slideshow |
Photos/stills plus music, photo movie/album/memories language, per-photo duration grid, gentle Ken Burns motion, consistent transitions, caption read time. |
lyric-captions |
Lyrics, subtitles, captions, transcript, timestamp sync, per-line timing, readability and contrast as the core deliverable. |
logo-intro |
Logo animation, intro, stinger, bumper, brand mark, 3-10 seconds, single subject, anticipation/reveal/settle/hold arc. |
Pass the resolved videoType on every preview_quality_risks, suggest_quality_fixes, evaluate_edit_quality, and final_preflight call. Do not omit it after classification; omitted videoType intentionally means the legacy motion-graphics gate behavior. For motion-graphics and slideshow, pass the derived palette role colors to rendered Phase 4 quality calls as paletteRoleColors using #RRGGBB values, preferably as an array of { "role": string, "color": "#RRGGBB" } objects. If an MCP client cannot send that complex array reliably, pass paletteRoleColors as a JSON string containing the same array. If derive_palette returned #AARRGGBB, drop the alpha channel before calling the quality tools.
| videoType | Existing phases as-is | Replaced or specialized phases | Skipped unless requested |
|---|---|---|---|
motion-graphics |
Everything as written today. | None. | None. |
footage-cut |
Phase 1 staged apply_edit, read_document_summary, measure_object_bounds, Phase 4 still/quality/preflight. |
Phase 0 creative direction/palette/background grammar becomes media inventory plus cut list unless authored graphic overlays are requested; when required clips are missing, load beutl-agent-asset-sourcing and record assets/manifest.json provenance before placing media; shotBreakdownPlan becomes clip in/out/order/Start/Length; audio handling is explicit. |
derive_palette and get_background_grammar unless graphic overlays are requested; motion-graphics density/beat-grid plan conformance. |
slideshow |
Phase 1 static storyboard, measured captions, staged apply_edit, Phase 4 still/quality/preflight. |
Phase 0 becomes image ordering, per-photo duration grid, and transition vocabulary; Phase 3 uses minimal Ken Burns-style scale/translate per photo. | Background grammar and dense foreground layer planning unless captions/backing graphics need it; BPM beat-grid checks. |
lyric-captions |
Phase 1 layout, measured text/backing plates, Phase 4 still/quality/preflight. | beatGridPlan becomes a timestamp sync table; shotBreakdownPlan becomes one Element per line/caption with Start/Length from the sync table; type roles are hero line/echo/credit. |
Motion-graphics background richness and density planning; BPM-driven tempo targets unless the brief separately requests them. |
logo-intro |
Phase 1 static end-frame build, Phase 2 effects, Phase 3 motion authoring, Phase 4 still/quality/preflight. | shotBreakdownPlan collapses to one 3-10 second shot with anticipation/reveal/settle/hold; storyboard subdivision reviews the internal motion arc instead of adjacent cuts. |
Multi-shot cut-continuity planning, shot-count expectations, BPM tempo planning unless explicitly requested. |
Phase 0 — Direction and shot breakdown
- Author the creative direction yourself.
list_creative_directionsis optional divergence stimulus, not a menu to pick from.- Decide the concept, base hue, tonal seed, harmony scheme, type system, motion vocabulary, and shot structure from the brief (or from scratch when the brief is vague) before leaning on any tool. Do not anchor on returned seed names.
- Record the derivation reason before any color or background authoring: why this subject, audience, mood, keywords, and delivery surface lead to this hue family, tone, material vocabulary, and motion vocabulary. Unjustified choices are disallowed; if you cannot explain a hue/tone/motion choice, derive again instead of using it.
- Call
list_creative_directions(pass a freshseedeach run to vary the stimulus) and read itsrecentToAvoidlist. Your direction MUST differ structurally from those recent fingerprints: change the dominant motion verbs, layout, palette family, and type treatment, not just the words. Do not default to the same look every run (e.g. hero-glow-on-dark + dashed selection-marquee + magnetic letter-spacing) — that repetition is the monotony this step exists to prevent. - Call
derive_palettewithbaseHueDegrees,tonalSeed,harmonyScheme, the recordedderivationReason, andstructuralSignature. Resolve any hue-band or structural repeat warning by changing the direction, or record a concrete reason why the repeat is intentional for this brief before continuing. - Call
get_background_grammar, then instantiate the grammar in notes: one base layer, one required depth layer, optional second depth layer, one motion slot, and the three depth bandsbackground,midground, andforeground. Concrete values come from the brief and derived palette, not from the grammar ranges alone. - The required workflow is: derive direction with recorded reason ->
derive_palette-> instantiate background grammar. Any deviation, including hand-picked colors, skipped grammar, missing depth band, static background, or ignored repeat warning, requires a recorded reason in notes beforeapply_edit. - If the user prompt specifies concrete constraints (motif, style, palette, message, audience, subject), keep them literal; use the stimulus only to make the result less generic.
- Once the concept is locked, call
record_creative_directionwith its fingerprint (concept label, palette roles, motion verbs, structural signature) so future sessions steer away from it. - In notes, record the authored concept label, derivation reason, derived palette roles/hue band, background grammar slots, motion verbs, structural signature, any stimulus names you used,
derive_palettewarnings, and how you diverged fromrecentToAvoid. - Map the concept into your own named Beutl elements/objects. Do not reuse returned seed names as Element/Object names.
- For unconstrained briefs, keep project, still, and video basenames neutral, such as
project.bep,preview.mp4, andstill-*.png, or use the requested output directory slug. Record the concept name in notes instead of naming files after it.
- Inventory source media before schema authoring for media-driven types, then call
get_schemabefore authoring if the required drawable, media, or audio type is not already known.- For
footage-cut, list every available clip, duration note, usable range, and audio role. Forslideshow, list supplied photos or the needed image collection. Forlyric-captions, list the music bed or the reason none is needed. - If any required clips, photos, music, SFX, or fonts are missing, load
beutl-agent-asset-sourcing, follow its license/provenance contract, and write every downloaded or generated asset toassets/manifest.jsonbeforeapply_edit. - For organic heat, ink, glass, smoke, grain, caustic, or other procedural fields, call
list_effect_recipeswith a shader/organic intent and considerSKSLScriptEffectinstead of stacking only blurred gradient shapes. Prefer SKSL over GLSL for low-context file sessions because it is CPU-safe in still renders. - GPU/stylize effects (GLSL,
PixelSortEffect,ColorShifton split-character text) are render-guarded to skip degenerate targets rather than crash the renderer, so use them for richer looks when wanted — and they run on the bundled SwiftShader software fallback when no hardware GPU is present (slower, not skipped), so always confirm the result withrender_stillbefore relying on them. Do not over-restrict to a single safe effect; varying the effect vocabulary is part of avoiding monotone output. - For particle-like density (sparks, dust, confetti, floating tokens, glyph debris), use the real
ParticleEmitterdrawable (get_schema type=ParticleEmitter) instead of faking a swarm with many ellipse Elements — fake particle swarms also trip decorative-shape review. Its animatable surface coversEmitterShape(point/line/circle),EmissionRate,Lifetime,Speed/Direction/Spread,Gravity,TurbulenceScale, size/color/opacity over particle life, andParticleDrawable— any Drawable (a glyph fragment, aGeometryShape) can be the emitted sprite. - For music-driven briefs, the audio-reactive drawables
AudioWaveformDrawable,AudioSpectrumDrawable, andAudioSpectrogramDrawablerender real waveform/spectrum motion from an audio source with pluggable shape styles (bar, radial, mirrored bars, line, filled area, dots, block). Use them for lyric videos, visualizers, and beat-driven accents instead of hand-animating fake meters.
- For
- If source-code reading is allowed, use
beutl-agent-source-groundingbefore authoring layout, transform, bounds, text measurement, render scale, effect-unit, reconciliation, or live-session semantics.- This is mandatory when the task mentions centered placement, coordinates/origin,
TranslateTransform,TransformOrigin, backing plates, object bounds, render/export range, or when a rendered/user-observed result contradicts the plan. - Read
.claude/skills/beutl-agent-source-grounding/SKILL.md, then use narrowrg/read passes over the source and tests it identifies. - Record a
sourceGroundingnote withassumption,evidence,rule, anduncertaintybefore the first relevantapply_edit. - If the user explicitly forbids source reading, skip this step and record that limitation.
- This is mandatory when the task mentions centered placement, coordinates/origin,
- Before authoring, record a quality preflight plan in notes:
directionContract: state the objective, audience, emotional temperature, brand posture, delivery surface, one-sentence promise, and the recorded derivation reason for hue, tone, material, and motion vocabulary. The reason must tie the subject/brief to the palette seed and motion vocabulary; unjustified choices are disallowed.messageHierarchy: name the primary message, secondary emphasis, and supporting/caption information for each shot.textCasePlan: use Title Case or sentence case by default; do not use long all-caps text unless the user explicitly asked for it.typographyRolePlan: assign type roles such as hero, secondary, caption, label, and texture text before choosing sizes.readTimePlan: keep fast-beat copy to a word, phrase, or symbol; hold or split longer text.beatGridPlan: when a music bed file exists, callanalyze_audio_rhythmbefore authoring and recordestimatedBpm,confidence,beatTimesSeconds, andstrongOnsetTimesSeconds; anchor Element boundaries, accent keyframes, and transition hits to those measured beats. If no music bed exists, convert explicit BPM or fast-tempo language into a nominal beat grid instead. For 120-140 BPM, default to 130 BPM when unspecified: 1 beat is about 462 ms, 2 beats about 923 ms, and 4 beats about 1.85 s. Plan visible foreground changes every 1-2 beats, normal foreground holds around 2-4 beats, no foreground event gaps longer than 4 beats, and only named final resolves/background textures may hold longer.highTempoDensityPlan: for 120-140 BPM or roughly 1.5s shots, keep hero text to 1-3 words and supporting labels to 2-4 word tokens. Add density through nodes, particles, strokes, texture, accent motion, and secondary shapes rather than long copy. Do not count background-only drift as foreground tempo.shapeBudget: reserveRectShapefor full-frame/background plates or deliberately plain geometry; use rounded rectangles, ellipses, paths, media, strokes, or procedural texture for foreground structure. Do not leave a large persistent foregroundRectShapebehind multiple text beats unless it is an intentional named text backing plate with matching timing and measured padding. Do not use abstract glint/glow/aperture/lens ellipses as foreground decoration; replace them with parseable systems such as strokes, particles, letter fragments, editor/timeline marks, masks, media, or procedural texture.elementStructurePlan: one ordinary timelineElementowns exactly oneEngineObject. Multiple objects inside oneElementare allowed only when thatElementcontains anIFlowOperatorsuch asDrawableGroup,DrawableDecorator,SoundGroup, orScene3D; otherwise split content into separate Elements. ChooseDrawableGroupfor multi-child grouping (camera rigs, portal intake); chooseDrawableDecoratorwhen the point is applying one shared transform/effect/opacity/blend to its children as a single composited unit (group fade, shared blur/shadow) — the difference is subtle, so source-ground it when the composited result matters.roleTagPlan: name important objects/elements with role tags such as[role:background],[role:text-backing],[role:decorative], or[role:camera-rig]so MCP quality tools can distinguish real text plates from decorative accents and camera rigs from content groups.shapeIntentPlan: every large or animated foreground shape must have a clear role, purpose, and motion intent in the Element/Object name, such as[role:decorative] beat sweep,[role:text-backing] title plate, or[role:background] surface. Do not create anonymous blobs, panels, abstract light ellipses, or shapes whose job cannot be named in viewer-visible terms.paletteRoles: use thederive_paletteoutput roles (bg-base,bg-accent,foreground,text-primary,accent) and record the contrast checks. Do not hand-pick alternate colors unless the reason and contrast are recorded. Avoid dark teal plus cyan/magenta unless requested. For ambient/aperture/glow backgrounds, instantiateget_background_grammarwith at least three depth bands and at least three gradient falloff stops or a real Blur/SKSL/procedural texture so color boundaries do not read as hard bands.backgroundGrammarPlan: record the selected base layer, depth layer A, optional depth layer B, motion slot, and which authored Elements will satisfy background/midground/foreground depth bands.textPlatePlan: if text needs a backing plate, plan matching Start/Length, centered transforms, and padding for the named[role:text-backing]text/plate pair. Decorative light slashes, glass bands, and texture plates should be tagged[role:decorative], shot-limited, lower-Z background/surface elements, or non-rectangular/stroke/procedural treatments so quality review does not misclassify them as text backing plates.effectIntentPlan: name the job of each effect chain: material texture, hierarchy separation, transition energy, color grade, or text legibility.shotBreakdownPlan: derive the shot/beat count from duration × tempo before authoring (for 120-140 BPM, default 130 BPM: a 30s piece is about 65 beats). Plan a visible foreground event roughly every 1-2 beats, so a typical 30s high-tempo piece is tens of fine shots, not 6-8 coarse ones. Enumerate every shot with an index,Start,Length, primary focal point, primary message, role, planned foreground element count, and planned hold seconds. Subdivide long holds into distinct beats instead of letting one shot span many beats; only named final resolves and background textures may span multiple beats. This enumerated breakdown is the source ofElementboundaries in Phase 1.quantitativePlanSheet: turnshotBreakdownPlaninto a numeric target table on the same four axes the quality tools measure later (shot count, edits per second, hold seconds per shot, foreground elements per shot), so the plan can be checked against actuals before export. The foreground-elements-per-shot target must be passed toevaluate_edit_quality/final_preflightasplannedForegroundElementsPerShotsometrics.layerDensitycan compare authored layer density against the plan. Set every target with a deliberate 2-3× margin above the gate minimum, because execution always shrinks the plan — planning to the bare floor guarantees a below-gate result. Do not plan to the minimum; if a target only just clears the floor, raise it. Record:- Shot count:
beats = duration_sec × BPM / 60; target ≥ 2-3× a coarse 6-8 baseline AND at least one distinct shot per 1-2 beats — take the larger. A 30s high-tempo piece plans roughly 30+ fine shots, never 6-8. - Edits per second: target timeline events/sec ≥ 2-3×
metrics.tempo.RequiredTimelineEventsPerSecond; record the expected total timeline-event count that produces it. - Foreground elements per shot: target ≥ 2-3 foreground layers per shot (2-3× the single-element structural floor). Single-element shots are forbidden except a deliberately minimal named final resolve.
- Hold seconds per shot: holds are a ceiling, so keep planned holds at 1/2-1/3 of the overlong-hold threshold (the 2-3× margin applied to an upper bound); normal foreground beats stay near 2-4 beats and only named resolves/background textures hold longer.
- Shot count:
compositionPlan: define one primary focal point per enumerated shot and how grouping, alignment, scale, color, and repetition support it.motionContinuityPlan: define reveal, development, and resolution phases plus how boundaries are bridged.cameraPlan: Beutl's 2D pipeline has no scene camera, so camera (viewpoint) work must be planned explicitly as animated rig transforms — a piece where every shot is a static full-frame composition swapped by cuts reads as a slide deck, not motion graphics. For each shot or shot run, record the camera treatment:locked(deliberate static frame),push-in/pull-back(rigScaleTransformaround the focal point viaTransformOrigin),pan/tiltdrift (rigTranslateTransform.X/Y),whip-pan(fast rig translate + blur as a cut bridge),roll(rigRotationTransform), orparallax(per-depth-band rigs translating at different amplitudes, background slowest). A camera move is authored on a named[role:camera-rig]DrawableGroupthat parents the shot's content; there is no automatic inverse, so moving the camera left/up means translating the rig right/down, and zooming in means scaling the rig up. Plan at least one non-locked camera treatment per shot run formotion-graphicsbriefs; an all-lockedplan requires an explicit brief reason recorded in notes.cutContinuityPlan: for every adjacent shot pair, record the planned visible bridge across the cut: an element crossing the cut, a camera move continuing across it (matched push-in or whip-pan fromcameraPlan), a sweep, shared background continuity, overlapping transform/opacity ramp, or a deliberately documented hard-cut reason.transformIntentPlan: for every rotated moving object, state whether motion is in screen space or local/rotated space. For screen-space motion, plan static orientation transforms before the animatedTranslateTransform; for local-axis motion, state the intended axis and verification sample.verificationSamples: choose at least three still times plus the motion/quality review sample set.
Contrast Exemplars - derive, don't copy
These examples describe relationships to derive with derive_palette; they are not literal palettes to reuse.
- Good:
text-primaryis much lighter than a darkbg-baseand still clears the 4.5:1 floor against the brighterbg-accent; the saturatedaccentis small and clears 3.0:1 againstbg-base. - Good: on a light tonal seed,
text-primaryis a dark low-saturation role,foregroundis the readable material color, and the bright accent is reserved for small motion cues. - Bad: cyan text on a pale blue or bright yellow background relies on hue difference but fails luma contrast.
- Bad: three fully saturated roles at similar lightness compete; mute support colors and let one accent carry saturation.
- Bad: dark teal base plus cyan and magenta neon is only allowed when the brief explicitly asks for that look and the reason is recorded.
Phase 1 — Static storyboard
Build the static layout of every enumerated shot with NO keyframes and NO effects. The deliverable is a readable static storyboard: correct composition, hierarchy, typography, color, and layering at each shot's representative frame.
- Create or attach a session:
- Stdio/headless:
create_projectoropen_projectwith a.bepproject path. Paths without an extension are normalized to.bep;.beutlis reserved for exported project packages. - Live editor:
attach_active_editor. In the in-app host,open_project/create_projectopen the project in the running Beutl editor itself (the editor holds a single open project) and return a LiveEditor session — opening a project different from the one already open is rejected; attach or have the user close it first.
- Stdio/headless:
- If live attach fails and the task allows headless output, switch to the stdio/headless
create_projectroute rather than creating a custom generator. - When an output directory is requested, create/update
notes.mdthere before the first edit and after everyapply_edit,save_project,render_storyboard,preview_quality_risks,suggest_quality_fixes,render_still,evaluate_motion_variation,evaluate_edit_quality,compare_revisions,final_preflight, andexport_videoresult. Record success/failure, change count or verdict/path, and the next action. While drafting a large patch before the next tool call, append a short heartbeat note every few minutes with the current stage and blocker risk. - Call
read_documentand keep the returnedschemaVersion. - Build the static layout as a declarative document (Phase 1 — no motion, no effects):
- Use PascalCase property names exactly as returned by
get_schema. - New timeline
Elementsrequire$type: "[Beutl.ProjectSystem]:Element". - Use stable
Idhandles when modifying existing elements. - Omit
Idonly for genuinely new elements/objects so the toolkit can mint one. - Do not add a second
Objectto an ordinary existingElement. To place another visible item, create anotherElementwith its own singleEngineObject. Add multipleObjectsto oneElementonly for an intentionalIFlowOperatorflow chain such asDrawableGroup,DrawableDecorator,SoundGroup, orScene3D; keep the parentElement.Idand omitIdonly for genuinely new child objects in that flow chain. - Keep element
Start,Length, and layer/Z values consistent with the enumerated shot breakdown fromshotBreakdownPlan. - When
cameraPlanassigns a shot a camera move, structure that shot for it now with a named[role:camera-rig]rig Element, choosing one of two patterns so Phase 3 animates one rig transform instead of retrofitting per-element motion:- Portal (timeline) rig — preferred for multi-element shots: keep the shot's content as ordinary one-object Elements on contiguous ZIndex rows, and put the rig Element directly below them (lower ZIndex) with
Objects= aPortalObjectwhoseCountspans the content rows, then aDrawableGroupwith emptyChildren.Countis an inclusive ZIndex span, not an element count: the portal pulls every active Element with ZIndex inrig+1..rig+Countinto the group, so content keeps per-elementStart/Lengthand stays visible as timeline layers to quality metrics. Keep the pulled rows ZIndex-contiguous and time-aligned with the rig — pulled Elements render ungrouped whenever the rig Element is not active. Fetchget_examplesforinsert-camera-rig-portal. - Nested rig — for a small cluster that shares the shot's timing: parent the shot's drawables inside the
DrawableGroup'sChildren(nested children have noStart/Lengthof their own); thePortalObject'sCountstays0. Fetchget_examplesforinsert-camera-rig-push-in. In both patterns theObjectsarray must contain thePortalObjectentry immediately before the flow operator — a bareIFlowOperatoris rejected byapply_edit. The same portal+flow grouping works for the otherIFlowOperators (DrawableDecorator,SoundGroupfor audio,Scene3D). Author the rig's transform statically at the shot's end-state framing in this phase, and keep locked full-frame background plates outside the rig (below the portal's ZIndex range) — that separation is also what makes parallax possible.
- Portal (timeline) rig — preferred for multi-element shots: keep the shot's content as ordinary one-object Elements on contiguous ZIndex rows, and put the rig Element directly below them (lower ZIndex) with
- Author only static property values in this phase — no
KeyFrameAnimation/KeyFrame(that is Phase 3) and noFilterEffect(that is Phase 2). - For default-aligned
TextBlockand shape objects, treatTranslateTransform(0, 0)as centered in the scene;TranslateTransform(x, y)is an offset from the scene center. Do not use half-frame coordinates such as(960, 540)to center content in a 1920x1080 scene unlessAlignmentX=Left/AlignmentY=Topwas deliberately selected and source-grounded. - Author
GeometryShapepath coordinates with the artwork's top-left at(0, 0)(all coordinates non-negative): the drawn center lands at the alignment-resolved center plus the path bounds origin, so a path centered on(0, 0)renders up-left by half its size and scene-absolute coordinates shift by their full offset. When a path cannot be normalized, add a staticTranslateTransform(-boundsX, -boundsY);measure_object_boundsreportsgeometryBoundsOriginandpreview_quality_risksflags uncompensated offsets asgeometryPathOffset. - Use
measure_object_boundsafter creating or modifying layout-sensitive text, shape, and backing-plate pairs to confirm render-node size, scene-space center, transformed bounds, and padding before relying on still renders. - If you only need the required container shape, fetch the targeted
insert-new-element-skeletonexample; do not inspect a full-scene starter just to learn$typeplacement.
- Use PascalCase property names exactly as returned by
- Apply the static layout in small
apply_editstages that map to your enumerated shot breakdown — background/surface, then primary structure/shapes, then typography, then text backing plates — using static property values only (no motion, no effects yet). Inspectvalid,changes,validation, andcreatedIdsafter each stage before continuing. Passquiet: truefor large staged patches. - If
apply_editreturnsvalidation_rejected,unknown_type, stale handles, invalid animation discriminator tokens, or fallback-object guidance, fix the patch fromget_schema/get_examples/read_documentand retry only that stage. Do not invent shorthand values for colors, pens, animations, brushes, transforms, or effects. Do not silently fall back to cut-only timing after a keyframe failure unless the user explicitly accepts that reduced motion model. - For file sessions, call
save_projectafter every successful majorapply_editbefore continuing to the next stage; omitsessionunless you are deliberately disambiguating an older session id. For LiveEditor sessions,save_projectshould report that saving is not required/supported; record that message instead of treating it as a blocker. - After each major stage, verify with
read_document_summary. Compare every expected element name/role from your synthesized scene plan against the actual elements and revise before rendering unless the omission is recorded with a concrete reason. If any object hasisFallback: true, stop rendering and fix the patch from schema because fallback objects are placeholders, not usable visuals. Audit every object whose summary shows nested transform animation plus a static rotation/skew/scale: confirm theTransformGroup.Childrenorder still matchestransformIntentPlan, and patch the order with$before,$after, or$indexbefore rendering if it does not. Also audit object counts: any ordinary Element with multiple objects must be split unless it contains a namedIFlowOperator. - Verify the static storyboard before adding any effects or motion:
- Call
render_storyboardto render one still per enumerated shot plus a contact-sheet PNG of the whole storyboard. Review it as a static storyboard: every planned shot present, one clear focal point per shot, readable typography, the intended layering and color, and correctly aligned text/backing-plate pairs. For a scene with many Elements the synchronous call can exceed the MCP client request timeout; passbackground: trueto get{ status: "running", jobId }immediately, then pollread_render_job(jobId)untilstateiscompleted(itsresultholds the storyboard payload) — do not issueapply_editwhile a background render is running; callcancel_render_job(jobId)to abort a background render you no longer need. - For a continuous single-shot piece whose Element boundaries do not create useful auto shots, pass explicit
timeSecondstorender_storyboardinstead of hand-assembling contact sheets fromrender_still. Choose representative times for opening, reveal/development beats, settle, and final hold; usesubdivisionLevel:1or2to inspect the motion arc between those anchors. - Run
preview_quality_risks(videoType:<resolved>)(it does not evaluate motion). Of its categories, onlyelementStructurecan fail the gate;shapeIntent,decorativeShapeClarity, andgradientFalloffare advisory, but fix their major findings before still rendering when they reflect a genuine accident (not a recorded creative choice). For multiple related issues, callsuggest_quality_fixes(videoType:<resolved>)and apply the smallest repair. For high-tempo promos, set astyleProfilesuch ashigh-tempo-promo,kinetic-type, orhigh-tempo-promo 130bpm. - Run
evaluate_edit_quality(videoType:<resolved>, staticLayout:true)— the storyboard-phase gate. It skips motion checks, so the motionless storyboard is judged on composition, typography, readability, and structure only. Resolvecritical/majorissues before leaving this phase. - Use
measure_object_boundsfor any text/backing-plate pair that looks misaligned in the contact sheet. - Do NOT run
evaluate_motion_variation,evaluate_edit_qualitywithoutstaticLayout, orfinal_preflightin this phase — those are motion-phase gates and will false-block a static storyboard (identical frames read as zero motion). Iterate Phase 1 until the storyboard reads correctly; only then proceed.
Phase 2 — Effects
- Add effect chains onto the locked storyboard, one named job at a time. Do not start motion until effects read correctly on stills.
- Every effect chain needs a named job: material texture, hierarchy separation, transition energy, color grade, or text legibility. Remove decorative stacks that do not serve one.
- For organic heat, ink, glass, smoke, grain, caustic, or atmospheric fields, prefer
SKSLScriptEffect(fromlist_effect_recipes) over stacking only blurred gradient shapes; SKSL is CPU-safe in still renders. Prefer SKSL over GLSL for low-context file sessions. Thefine-film-grain-fieldrecipe ships a monochrome film-grain shader;organic-shader-fieldships a colored field shader — pick by intent, andvalidate_shaderany custom SKSL beforeapply_edit. - GPU/stylize effects (GLSL,
PixelSortEffect,ColorShifton split-character text) are render-guarded to skip degenerate targets rather than crash, and run on the SwiftShader software fallback when no hardware GPU is present (slower, not skipped); confirm every effect withrender_still/render_storyboard. Vary the effect vocabulary instead of over-restricting to one safe effect. - For masked reveals, knockouts, alpha mattes, and wipes, use the real masking mechanisms rather than covering rectangles: every Drawable has an animatable
BlendModewhose Porter-Duff modes (SrcIn,DstIn,SrcOut,DstOut,Modulate) composite it against the content below it in the same flow — scope the matte by putting mask and content inside oneDrawableGroup/DrawableDecoratorElement so it does not knock out the whole frame — and theClippingFilterEffect (animatableLeft/Top/Right/Bottom) is the rectangular wipe/crop primitive. Blend-mode matte behavior depends on flow order, so source-ground the exact compositing rule (beutl-agent-source-grounding) and verify withrender_stillbefore building a sequence on it. - For a true emissive glow/bloom (light that adds over the original, not a
DropShadowfake), duplicate the drawable withduplicate_objectpassingwrapInGroup=true, thenapply_edittheadditive-bloomrecipe (blur +BlendModePlus+ reducedOpacity) onto the returnedobjectIdso the copy glows over the untouched original.wrapInGroup=trueputs the original and copy under aDrawableGroup(anIFlowOperator) soevaluate_edit_quality'selementStructurecheck stays clean; move the copy to a separate Element at a higherZIndexinstead when it needs independent timing or z-order. LowerOpacityor switchBlendModetoScreenfor bright footage that blows out. - Re-verify with
render_storyboard/render_stillandevaluate_edit_quality(videoType:<resolved>, staticLayout:true)that effects serve their named jobs and did not break readability. Motion-phase gates still do not apply yet.
Phase 3 — Motion
- Add keyframes and animation on top of the locked storyboard and effects. Build the reveal, development, and resolution phases from
motionContinuityPlan, and animate multiple property families (transform, opacity, brush/gradient, effect parameters, text spacing) — not just X plus opacity. Vary easing families per the 12 principles: use cubic/quintic ease-out for entrances, ease-in-out for moves, and reserve linear motion for deliberate mechanical travel. The easing catalog is much wider than cubic/sine —BackEase*/ElasticEase*give overshoot and anticipation,BounceEase*gives physical settles, andSplineEasingtakes custom cubic-bezier control points; use them deliberately on accents (a bounce on every element turns cartoonish). Stagger related element starts by about 0.1-0.3 seconds and vary durations/directions so follow-through and overlapping action are visible. Apply motion in smallapply_editstages per beat and inspectvalidationafter each; passquiet: truefor large patches.
- Author the camera moves from
cameraPlanfirst, before per-element accents: keyframe the[role:camera-rig]DrawableGroup'sTransformGroupchildren —TranslateTransform.X/Yfor pans and whip-pans,ScaleTransform.Scalefor push-in/pull-back (setTransformOriginso the zoom centers on the shot's focal point),RotationTransform.Rotationfor roll. Fetchget_examplesforinsert-camera-rig-push-in(nested rig) orinsert-camera-rig-portal(timeline rig) and reuse its structure. Camera moves are slow and eased by default (a push-in of roughly 3-8% scale over the shot already defeats the static-slide feel); whip-pan bridges are the fast exception. For parallax, keyframe each depth-band rig's translate at a different amplitude (background slowest). Remember the inverse: camera-left = rig-right, camera-in = scale-up. For a true 3D dolly or orbit, use aScene3Dobject and keyframe itsCamera.Position/Camera.Targetinstead of faking perspective with 2D scale. - For perspective moves on 2D content (card flips, page turns, tilted reveals), use
Rotation3DTransform(RotationX/RotationY/RotationZ,CenterX/Y/Z, andDepth— the perspective distance, default 500) inside theTransformGroupinstead of faking depth with 2D scale alone. - For kinetic type, set
TextBlock.SplitByCharacters=true(animatable) so glyphs composite individually — this is the enabling property behind "split-character" effects such as per-glyphColorShiftfringing orPartsSplitEffectshatter — and animateTextBlock.Spacingfor tracking-in/out reveals. Stagger per-character timing rather than moving the whole block as one unit. - For line-drawing reveals ("the stroke draws itself on"), animate
Pen.TrimStart/Pen.TrimEnd(0-100) on aGeometryShape/shape/text stroke; for marching-dash accents setPen.DashArray(a static float list) and animatePen.DashOffset. - Audio is authorable, not analysis-only: keyframe
Sound.Gain(percent: 100 = unity, values above 100 amplify) for fade-ins/outs and ducking under narration, setSound.Effectto anAudioEffectGroupwithDelayEffect/EqualizerEffect/CompressorEffect/LimiterEffectchildren for echo/EQ/dynamics, and useSoundGroup(anIFlowOperator— thePortalObjectpairing rule applies) to submix multiple audio Elements. - Decide the animation clock mode deliberately. With
UseGlobalClock=false,KeyFrame.KeyTimeis local to the owning timeline Element and should normally stay within00:00:00..Element.Length. WithUseGlobalClock=true,KeyFrame.KeyTimeis a scene timeline time and should intersect the visible Element range. - For explicit keyframes, fetch
get_examplesforanimate-float-property-keyframeswhen animating an existing object, orinsert-new-animated-text-keyframeswhen creating a new animated text object. Copy the concreteKeyFrameAnimation<T>andKeyFrame<T>discriminators from the example instead of inventing animation type names. - Before authoring multiple keyframed properties, make a small local keyframe helper snippet in your draft from the MCP example and reuse that exact JSON shape for every animated
Single,Boolean,Color,Size, or transform property. Do not hand-type or manually Unicode-escape the generic discriminator strings; invalid tokens aroundKeyFrameAnimationorKeyFramemean the helper is wrong and must be rebuilt fromget_examplesbefore continuing. - If
apply_edit.validationcontains aWarningfor relative keyframes outside the Element local range, treat it as a timing bug unless the user explicitly asked for that state. Fix by either converting the keyframes to local times or settingUseGlobalClock=truewhen scene timeline times were intended. - For rotated moving shapes, do not animate only
TranslateTransform.Xand assume it will travel along the rotated visual axis. If the intended path is screen-space horizontal/vertical drift with a tilted object, put static orientation transforms such asRotationTransform,SkewTransform, or non-animatedScaleTransformbefore the animatedTranslateTransformin theTransformGroup. If the intended screen-space path is diagonal, animate both X and Y as a vector. If the intended local-axis path depends on transform order, record that explicitly and verify the order with a rendered still/motion sample before export.
Phase 4 — Motion verification and export
- Re-render the storyboard with
subdivisionLevel: 1after Phase 3 motion authoring; raise tosubdivisionLevel: 2for suspicious gaps. READ the contact sheet, including everykind: "inbetween"frame, and checkcutEyeTracebefore judging continuity. For multi-shot types (motion-graphics,footage-cut,slideshow,lyric-captions), every adjacent shot pair must show the planned continuity: an element crossing the cut, a camera move continuing across it (matched push-in, whip-pan), a sweep, shared background continuity, an overlapping transform/opacity ramp, a deliberate hard-cut reason, or a consistent slideshow transition. Also verify thecameraPlanexecuted: shots planned as push-in/pan/parallax must show visible framing change between their in-between frames — identical framing on a non-locked shot is a rework finding. If the in-between frames look identical to the anchors except for an unplanned hard swap, treat it as a rework finding and add bridge animation or transition consistency. IfcutEyeTrace.exceedsEyeTraceBudgetis true and no planned bridge or hard-cut reason exists for that pair, treat it as a rework finding: add a bridging element, sweep, or focal-point realignment. Forlogo-intro, review the single-shot motion arc instead of cuts: anticipation, reveal, easing, settle, and the final hold. RecordcutContinuityActualsormotionArcActualsin notes with pass/fail, evidence frame names,cutEyeTracedisplacement when present, and the repair when needed. - Verify with
render_stillat representative shot boundaries. Treat any returnedwarningsas a blocker for export until you have either revised the scene or recorded why the warning is acceptable. In live-editor sessions, renders honor the editor's layer state —TimelineLayerlock/solo/audio-mute/video-mute andElement.IsEnabled— so if an expected layer is missing from a still, check those flags before diagnosing your own edit as the cause. For each still, recordvisibilityAnalysis.visiblePixelRatio,foregroundPixelRatio,occupiedBoundsRatio, andmaxQuadrantForegroundRatio; compareactiveElementsagainst the planned visible elements; note the primary focal point, whether text/title elements are readable for their duration, whether effect chains still serve their named jobs, and whether foreground/background/accent density is present. Development and resolution stills should show at least three visible layer types, such as background/surface, primary motion, accent/detail, and typography; if text is present, it must have clear contrast against the background.
- If a large decorative
RectShaperemains active behind several unrelated text shots, treat it as a likely text-background-fit problem before quality review. Limit it to the shot where it belongs, move it clearly into the background/surface role, or replace it with stroke/ellipse/path/procedural texture.
- Run
evaluate_motion_variationacross 4-6 samples. If it reportslow-motion-variationorpoor-frame-coverage, or if the still review shows planned elements are never visible/readable, revise the edit. - Run
evaluate_edit_quality(videoType:<resolved>)with the same sample set (the full motion gate; leavestaticLayoutoff here). For motion graphics, passplannedForegroundElementsPerShotfromquantitativePlanSheet; for motion-graphics and slideshow flows, also passpaletteRoleColorsfrom thederive_paletteroles sopaletteBalancecan report the authored 60-30-10 area mix. Use an array of{ "role": string, "color": "#RRGGBB" }objects, or a JSON string containing that same array when the MCP client cannot send complex arrays reliably. WhenbeatGridPlancame fromanalyze_audio_rhythm, also passbeatTimesSecondssoaudioSyncadvisories can flag near-miss cuts. PassallowMinimalDensity=trueonly when the brief explicitly asks for minimal/negative-space density and the deviation is recorded. Only gate-failing issues (typographyReadTime, renderedtypographyContrast,elementStructure,motionContinuity, and supplied-planlayerDensity) block export;shapeIntent,motionIntent,decorativeShapeClarity,gradientFalloff,tempoRhythm,paletteHarmony, andbackgroundRichnessmajor issues are advisory and do not block. Revise and re-run untilpassesQualityGateis true; fix genuine-accident advisory findings when time permits, or record the explicit user reason for allowing an issue.
- For motion-graphics deliverables,
animatedPropertyCount: 0is a blocker even whenevaluate_edit_quality.passesQualityGateis true. Add explicit transform, opacity, spacing, brush, or effect animation before export. - For
textBackgroundFitissues involving decorative glass/light/texture rectangles, prefer a real design fix over suppressing the issue: constrain the rectangle's Start/Length to the intended beat, align it as a named backing plate withmeasure_object_bounds, lower it into the background, or replace it with a non-plate visual treatment. - For high-tempo/BPM briefs, inspect
metrics.tempo.RequiredTimelineEventsPerSecond,TimelineEventsPerSecond,RequiredTotalEventsPerSecond,LongForegroundGapCount, andLongestForegroundEventGapSeconds. A scene is too slow if background motion hides sparse foreground changes or long foreground gaps. - After each revision
apply_editmade in response to Phase 4 quality or visual-review findings, callcompare_revisionsbefore the next broad fix. Record a delta ledger in notes with metric deltas, issues resolved, issues introduced,regression, and the paired still paths. Ifregression=true, treat the introduced/worsened axis as a rework finding before export.
- Plan-conformance check (before finishing). Before
final_preflight/export, compare the authored result against yourquantitativePlanSheeton the same four axes — not just the pass/fail gate. Gather actuals fromread_document_summaryfor shot/Element count,evaluate_edit_qualitymetrics.tempo(TimelineEventsPerSecond,SlowHoldCount,LongestForegroundHoldSeconds),metrics.layerDensity(Bands,AverageForegroundLayerCount,MinimumForegroundLayerCount,BandsBelowHalfPlannedForegroundLayerCount), andevaluate_motion_variation. Confirm all four: actual shot/Element count ≥ planned shot count; actualTimelineEventsPerSecond≥ planned edits/sec target (and ≥RequiredTimelineEventsPerSecond); every hold ≤ its planned ceiling (noSlowHoldCountbeyond named resolves); every measured time band'sForegroundLayerCountmeets the planned density floor, with a MajorlayerDensityissue if authored density falls below half the supplied plan. Any axis short of the plan is a rework blocker — add the missing shots/events/layers and re-verify, or record a true minimal-density brief and passallowMinimalDensity. Record a conformance summary in notes: per axis, planned vs actual vs pass/fail. 21a. Convergence loop for low-effort runs. When the run started frombeutl-agent-brief-expansion(or the coordinator explicitly requests convergence), runbeutl-agent-visual-reviewin its convergence loop mode after the deterministic gates pass and beforefinal_preflight: iterate revision passes until every rubric axis scores ≥ 3 or the pass budget (default 3) is exhausted, phrasing every directive in the expanded brief's own concept vocabulary. An unconverged result hands off to the human with the delta ledger instead of exporting silently. - Prefer
final_preflight(videoType:<resolved>)before export when the tool is available. For motion graphics, passrequireAnimatedProperties=trueandplannedForegroundElementsPerShotfromquantitativePlanSheet; for motion-graphics and slideshow flows, pass the samepaletteRoleColorsshape used inevaluate_edit_quality; passbeatTimesSecondsfromanalyze_audio_rhythmwhen a music bed was analyzed. Export only whenreadyForExportis true. Iffinal_preflightis unavailable, use the separaterender_still+evaluate_motion_variation+evaluate_edit_quality(videoType:<resolved>)sequence above. - Export a short preview with
export_videowhen an encoder is available; if export is unavailable, record the reason in notes. Control output size withcrf(0-51, higher = smaller; raise it to ~28-30 for full-frame grain or other hard-to-compress content) orbitrate(bits/s, ABR) — the two are mutually exclusive. For a long export, passbackground: trueand pollread_render_job(jobId)the same way asrender_storyboard. In the final report, surface any CC-BY-SA share-alike obligations, user-supplied URL assets recorded aslicense: "unverified", and all required attribution text fromassets/manifest.json. - Save with
save_projectfor file sessions after final revisions. For LiveEditor sessions, callread_operation_statusorsave_projectonce near the end if you need to report that the live edit is already applied but not file-saved by the toolkit.
Motion Graphics Quality Bar
- Author storyboard-first: build and verify the static layout of every shot (Phase 1, via
render_storyboard+evaluate_edit_quality(staticLayout:true)) before adding effects (Phase 2) or motion (Phase 3). A storyboard that does not read clearly will not improve by animating it. - Use at least three timing phases: reveal, development, and resolution. Avoid a single continuous drift.
- After Phase 3 motion authoring, verify adjacent cuts with
render_storyboard(subdivisionLevel:1)and raise to2for suspicious gaps on multi-shot types. In-between frames must show bridge motion, transition consistency, or recorded hard-cut intent, andcutEyeTracemust not exceed the budget without a planned bridge or hard-cut reason. Forlogo-introor any continuous single-shot piece, pass explicittimeSecondsanchors and inspect the subdivided frames as a motion arc instead of a cut-continuity pass. - Build fast tempo through contrast between quick accents and held readability beats. Do not make every layer move at the same speed.
- Avoid motion monotony: do not leave most keyframe transitions linear, and do not start every animated element at the same time with the same duration and direction.
- For 120-140 BPM briefs, work from a beat grid instead of the vague word "fast". At 130 BPM, 1 beat is about 462 ms, 2 beats about 923 ms, and 4 beats about 1.85 s. Plan enough foreground element boundaries and keyframes for the piece to read as fast in
tempoRhythmmetrics. - Keep normal foreground beats near 2-4 beats. Longer holds are acceptable only for named background texture, ambient support, or a deliberate final resolve; add visible foreground events when readability requires a longer text hold. Background-only drift does not satisfy a fast-tempo brief.
- Animate multiple property families across the piece, such as transform, opacity, brush/gradient, effect parameters, and text spacing. Do not rely only on X movement plus opacity.
- Move the camera, not just the elements. A piece whose viewpoint never moves — every shot a static composition with only element-level animation, swapped by cuts — reads as a slide deck. Use
[role:camera-rig]DrawableGrouptransforms for push-ins, pans, parallax, and whip-pan cut bridges percameraPlan; an all-locked-off piece needs an explicit recorded brief reason. - Keep ordinary timeline Elements to one EngineObject. Multiple objects in one Element are reserved for
IFlowOperatorchains such asDrawableGroup,DrawableDecorator,SoundGroup, orScene3D; otherwise split each visual object into its own Element. - Every shot needs one primary focal point. Supporting text, marks, panels, and effects should sit lower in scale, contrast, timing, or density.
- Keep hero-scale typography to one primary message per beat; make captions, labels, and texture text visibly quieter before running
evaluate_edit_quality. - Readability is timed: short-lived text must be short, split across beats, or held longer. At roughly 1.5s per shot, use 1-3 words for hero text and 2-4 words or compact symbols for supporting labels.
- Maintain visual density: use layered background, foreground motion, accents, and typography/labels. A lone title over one moving shape is too sparse unless the brief asks for minimalism; verify with
metrics.layerDensity, not only a manual object count. - For fast promos, add perceived information through short typography, repeated non-rectangular nodes, particles, strokes, texture, and accent motion rather than adding long text.
- Use role tags consistently:
[role:background]for full-frame surfaces,[role:text-backing]only for real measured text plates, and[role:decorative]for glass bands, slashes, glints, or rhythm marks that should not be interpreted as backing plates. - Large or animated foreground shapes must expose role, purpose, and motion intent in names. If a shape's job cannot be stated as beat sweep, scan texture, pulse reveal, transition wipe, text backing, or another concrete intent, remove it before export.
- Do not use abstract foreground glint/glow/aperture/lens/glass ellipses as a quality shortcut. If viewers cannot parse what the shape represents without reading its layer name, replace it with strokes, particles, letter fragments, editor/timeline marks, masks, media, or procedural texture.
- For ambient/aperture/glow backgrounds, avoid hard two-stop falloff. Use at least three gradient stops, widen alpha/color transitions, add a real Blur/SKSL texture, or replace the shape with procedural surface texture.
- Use procedural texture when the concept is organic or atmospheric. A short
SKSLScriptEffecton a broad shape is often better than many low-contrast blurred ellipses for heat, ink, glass, smoke, caustics, grain, or shimmer. - Every effect chain needs a named job: material texture, hierarchy separation, transition energy, color grade, or text legibility. Remove decorative stacks that do not serve one.
- Give each major visual part a clear name in the patch so
read_document_summaryexposes the intended structure. - Treat your synthesized scene plan as a completion checklist. A final scene that omits planned accent/density elements without a recorded reason is incomplete.
- After still renders, use
evaluate_motion_variation; treat low adjacent-frame variation or persistent one-quadrant/sparse frame coverage as a failed self-check for motion graphics. - For motion graphics, a passing rendered-difference check is not enough when the document has no explicit animated properties. If
evaluate_edit_qualityreportsanimatedPropertyCount: 0, revise the edit to add deliberate animation on transform, opacity, typography spacing, brush, or effect parameters before export. - Numerical motion variation is necessary but not sufficient: planned elements must also be visibly present across representative stills, and text/title elements must be readable before export.
- A still that is mostly a smooth background after the reveal phase is not dense enough even if
evaluate_motion_variationpasses. - Held title/logo sections need real continuous motion to pass
evaluate_motion_variation(it requires ≥2% changed pixels at ≥48-per-channel delta between adjacent samples). Drift the held text and add a slow scale "breath"; a soft low-alpha ambient wash stays under the 48 delta and does NOT count as motion.tempoRhythmdefaults to a 130 BPM target, so a calm 3-act brand/logo piece trips its minor advisories harmlessly —passesQualityGate/readyForExportstay true. - Long all-caps text, overloaded visual hierarchy, unreadable short-lived copy, rendered low text contrast (
typographyContrast), foreground RectShape dominance, abstract decorative light ellipses, hard ambient gradient falloff, flat single-layer backgrounds, unclear or arbitrary animated shapes, ordinary Elements with multiple EngineObjects, sparse layer density/depth coverage, sparse high-tempo event density, long foreground event gaps, overlong high-tempo foreground holds, misaligned text backing plates, dark teal/cyan/magenta palettes, low-scoring hue-wheel palettes, dense effect stacks without a named job, repeated card shadows, low temporal variation, and unmotivated hard cuts are quality failures unless explicitly requested by the user. evaluate_edit_quality.passesQualityGatemust be true before final export for normal deliverables.
Originality Rules
- For creative briefs, build an original timeline with small staged
apply_editcalls; do not uselist_compositions,plan_composition, or empty-scene examples as the default output path. To bootstrap from a non-template original starting point,plan_original_scaffoldreturns a one-call seed-derived scaffold (background/headline/subtitle/decorative foreground) whose placeholder copy and structure you then rewrite for the brief — it is an original starting point, not a reusable template. - Treat
list_creative_directionsoutput as raw inspiration only. Do not copy returned seed names as the final concept title, Element/Object names, layer order, or file basename. - Use composition templates only when the user explicitly asks for a template, starter, quick draft, or named template style.
- When a template is explicitly requested, pick a specific returned template name from
list_compositions; do not rely on an implicit first template selection. - Treat examples as schema snippets or fallbacks. Adapt their structure to the brief instead of copying a full starter scene unchanged.
- Avoid overused no-context motifs such as orbit rings, radar sweeps, map/atlas labels, signal nodes, dashboard bars, and dark teal cyan/magenta neon unless the user asks for them.
- Cross-session variety is a hard requirement: the same brief should NOT keep producing the same video. Before locking a direction, compare it against
recentToAvoid, pass the structural signature intoderive_palette, and deliberately change the structural language (motion verbs, layout grid, palette family, type treatment, transition style) from recent runs; thenrecord_creative_directionso the next run can diverge too. - Pass
quiet: truetoapply_editfor large staged patches; the full echoed change set can exceed the response size limit, so keep individual patches small and use the compact summary while authoring.
Shot List Mapping
- Drive
Elementboundaries from the enumeratedshotBreakdownPlan. One shot normally maps to one or moreElemententries with explicitStart,Length, andZIndex; each ordinaryElementcontains exactly one drawable/audioEngineObject. - Use multiple
Objectsinside oneElementonly for explicitIFlowOperatorflow chains such asDrawableGroup,DrawableDecorator,SoundGroup, orScene3D; otherwise split compound visuals into separate Elements. - A shot with a planned camera move maps to one
[role:camera-rig]rig Element — either a portal rig (PortalObject.Count = N) pulling the shot's N contiguous content layers directly above it, or a nestedDrawableGroupparenting the content asChildren— with locked background plates as separate Elements below the rig, outside the portal's ZIndex range. - Background plates should be lower
ZIndex; titles, logos, and overlays should be higher. - Prefer explicit durations over relying on media original duration unless the brief explicitly asks to preserve source timing.
- For repeated visual treatments, duplicate structure deliberately; do not rely on implied defaults when the brief gives concrete values.
Merge-Patch Rules
- Arrays of objects with
Idare id-keyed. A bare id-less array merges/appends into the existing members; it does NOT replace them. - Use
{ "Id": "...", "$delete": true }for removals. - To wholesale-replace an id-keyed array in one patch (e.g. swap a
FilterEffectGroup.Childrenchain instead of appending to it), make the FIRST element the sentinel{ "$replace": true }; the following elements rebuild the array in order (omitIdto mint fresh, or reuse anIdto keep that child), and[{ "$replace": true }]alone clears it. Replacement elements cannot also carry$delete/$index/$after/$before. Keep the group's ownIdso only its children change. - Use
$index,$after, or$beforefor ordering; do not combine ordering directives. - Unknown
Idmeans stale handle; callread_documentagain instead of guessing. - Existing parent with new flow child example:
{ "Elements": [{ "Id": "<existing-flow-element-id>", "Objects": [{ "$type": "<discriminator-from-get_schema>", "Name": "new-flow-child" }] }] }. Use this only when the existing Element is an intentionalIFlowOperatorflow chain. Ordinary Elements should not receive a second Object. - New Element example:
{ "Elements": [{ "$type": "[Beutl.ProjectSystem]:Element", "Name": "new-element", "Start": "00:00:00", "Length": "00:00:02", "Objects": [{ "$type": "<drawable-discriminator-from-get_schema>", "Name": "new-object" }] }] }. New Elements and Objects omitId. - New flow-operator Element (e.g. a
[role:camera-rig]DrawableGroup): theObjectsarray must pair aPortalObjectimmediately before the flow operator —"Objects": [{ "$type": "[Beutl.ProjectSystem]:PortalObject", "Count": <N> }, { "$type": "<DrawableGroup-discriminator>", "Name": "[role:camera-rig] ...", "Children": [...] }]. A bare flow operator without thePortalObjectis rejected.Countis an inclusive ZIndex span, not an element count: every active Element with ZIndex inrig+1..rig+Countis pulled into the operator (leaveChildrenempty then; empty rows contribute nothing).Count: 0pulls no timeline rows, so with the portal as the Element's first object the operator consumes only its nestedChildren; setClear: trueto explicitly discard earlier same-Element flow. Applies to allIFlowOperators:DrawableGroup,DrawableDecorator,SoundGroup,Scene3D. Seeget_examplesinsert-camera-rig-push-in(nested) andinsert-camera-rig-portal(timeline).
Progress Watchdog
- Keep
notes.mdgranular enough for another observer to reconstruct the route: every apply, save, render, evaluate, export, validation failure, and route change gets an entry. - During long patch authoring between tool calls, update
notes.mdbefore the three-minute mark with a heartbeat such asdrafting stage N patch; next tool: apply_edit; if you cannot do that, stop and report a blocker. - If no tool success, saved project artifact, render/export artifact, or notes update happens for about three minutes while editing, stop and report the blocker/status instead of silently continuing.
- If the user or coordinator asks for status, call
read_operation_statuswhen available and respond immediately with the current session/source, last successful stage, and blocker before continuing.
Safety Rules
- Keep values in documented ranges. If
apply_editreports coercion or rejection, adjust the request and retry the same small stage. - Confirm destructive output overwrites only when the user explicitly asked for overwrite.
- Do not write outside
BEUTL_WORKSPACE.
Version History
- db01de7 Current 2026-08-20 13:43


