用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/b-editor/beutl --skill beutl-agent-timeline-from-shotlist命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Implementation guide for Beutl's ToolTabExtension (tool-tab extension). Use when adding a custom tool tab to the editor. Triggers when ToolTabExtension, IToolContext, or docking-tab implementations are needed.
Apply a consistent look or effect chain to Beutl elements through the Agent Editing Toolkit MCP tools.
Review Beutl Agent Editing Toolkit rendered stills and storyboard contact sheets with a six-axis visual-quality rubric, then translate every finding into concrete edit directives.
基于 SOC 职业分类
正在显示 SKILL.md
| name | beutl-agent-timeline-from-shotlist |
| description | Build a Beutl timeline from a shot list through the Agent Editing Toolkit MCP tools. |
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.
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.
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. |
list_creative_directions is optional divergence stimulus, not a menu to pick from.
list_creative_directions (pass a fresh seed each run to vary the stimulus) and read its recentToAvoid list. 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.derive_palette with baseHueDegrees, tonalSeed, harmonyScheme, the recorded derivationReason, and structuralSignature. 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.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 bands background, midground, and foreground. Concrete values come from the brief and derived palette, not from the grammar ranges alone.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 before apply_edit.record_creative_direction with its fingerprint (concept label, palette roles, motion verbs, structural signature) so future sessions steer away from it.These examples describe relationships to derive with derive_palette; they are not literal palettes to reuse.
text-primary is much lighter than a dark bg-base and still clears the 4.5:1 floor against the brighter bg-accent; the saturated accent is small and clears 3.0:1 against bg-base.text-primary is a dark low-saturation role, foreground is the readable material color, and the bright accent is reserved for small motion cues.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_project or open_project with a .bep project path. Paths without an extension are normalized to .bep; .beutl is reserved for exported project packages.attach_active_editor. In the in-app host, open_project/create_project open 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.create_project route rather than creating a custom generator.notes.md there before the first edit and after every apply_edit, save_project, render_storyboard, preview_quality_risks, suggest_quality_fixes, render_still, evaluate_motion_variation, evaluate_edit_quality, compare_revisions, final_preflight, and export_video result. 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.read_document and keep the returned schemaVersion.get_schema.Elements require $type: "[Beutl.ProjectSystem]:Element".Id handles when modifying existing elements.Id only for genuinely new elements/objects so the toolkit can mint one.Object to an ordinary existing Element. To place another visible item, create another Element with its own single EngineObject. Add multiple to one only for an intentional flow chain such as , , , or ; keep the parent and omit only for genuinely new child objects in that flow chain.render_storyboard to 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; pass background: true to get { status: "running", jobId } immediately, then poll read_render_job(jobId) until state is completed (its result holds the storyboard payload) — do not issue apply_edit while a background render is running; call cancel_render_job(jobId) to abort a background render you no longer need.timeSeconds to render_storyboard instead of hand-assembling contact sheets from render_still. Choose representative times for opening, reveal/development beats, settle, and final hold; use subdivisionLevel:1 or 2 to inspect the motion arc between those anchors.preview_quality_risks(videoType:<resolved>) (it does not evaluate motion). Of its categories, only elementStructure can fail the gate; shapeIntent, decorativeShapeClarity, and gradientFalloff are advisory, but fix their major findings before still rendering when they reflect a genuine accident (not a recorded creative choice). For multiple related issues, call suggest_quality_fixes(videoType:<resolved>) and apply the smallest repair. For high-tempo promos, set a styleProfile such as high-tempo-promo, kinetic-type, or high-tempo-promo 130bpm.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. Resolve critical/major issues before leaving this phase.measure_object_bounds for any text/backing-plate pair that looks misaligned in the contact sheet.evaluate_motion_variation, evaluate_edit_quality without , or in 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.SKSLScriptEffect (from list_effect_recipes) over stacking only blurred gradient shapes; SKSL is CPU-safe in still renders. Prefer SKSL over GLSL for low-context file sessions. The fine-film-grain-field recipe ships a monochrome film-grain shader; organic-shader-field ships a colored field shader — pick by intent, and validate_shader any custom SKSL before apply_edit.PixelSortEffect, ColorShift on 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 with render_still/render_storyboard. Vary the effect vocabulary instead of over-restricting to one safe effect.BlendMode whose 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 one DrawableGroup/DrawableDecorator Element so it does not knock out the whole frame — and the Clipping FilterEffect (animatable Left/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 with render_still before building a sequence on it.DropShadow fake), duplicate the drawable with duplicate_object passing wrapInGroup=true, then apply_edit the additive-bloom recipe (blur + BlendMode Plus + reduced Opacity) onto the returned so the copy glows over the untouched original. puts the original and copy under a (an ) so 's check stays clean; move the copy to a separate Element at a higher instead when it needs independent timing or z-order. Lower or switch to for bright footage that blows out.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, and SplineEasing takes 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 small apply_edit stages per beat and inspect validation after each; pass quiet: true for large patches.cameraPlan first, before per-element accents: keyframe the [role:camera-rig] DrawableGroup's TransformGroup children — TranslateTransform.X/Y for pans and whip-pans, ScaleTransform.Scale for push-in/pull-back (set TransformOrigin so the zoom centers on the shot's focal point), RotationTransform.Rotation for roll. Fetch get_examples for insert-camera-rig-push-in (nested rig) or insert-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 a Scene3D object and keyframe its Camera.Position/Camera.Target instead of faking perspective with 2D scale.Rotation3DTransform (RotationX/RotationY/RotationZ, CenterX/Y/Z, and Depth — the perspective distance, default 500) inside the TransformGroup instead of faking depth with 2D scale alone.TextBlock.SplitByCharacters=true (animatable) so glyphs composite individually — this is the enabling property behind "split-character" effects such as per-glyph ColorShift fringing or PartsSplitEffect shatter — and animate TextBlock.Spacing for tracking-in/out reveals. Stagger per-character timing rather than moving the whole block as one unit.Pen.TrimStart/Pen.TrimEnd (0-100) on a GeometryShape/shape/text stroke; for marching-dash accents set Pen.DashArray (a static float list) and animate Pen.DashOffset.Sound.Gain (percent: 100 = unity, values above 100 amplify) for fade-ins/outs and ducking under narration, set Sound.Effect to an with /// children for echo/EQ/dynamics, and use (an — the pairing rule applies) to submix multiple audio Elements.subdivisionLevel: 1 after Phase 3 motion authoring; raise to subdivisionLevel: 2 for suspicious gaps. READ the contact sheet, including every kind: "inbetween" frame, and check cutEyeTrace before 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 the cameraPlan executed: 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. If cutEyeTrace.exceedsEyeTraceBudget is 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. For logo-intro, review the single-shot motion arc instead of cuts: anticipation, reveal, easing, settle, and the final hold. Record cutContinuityActuals or motionArcActuals in notes with pass/fail, evidence frame names, cutEyeTrace displacement when present, and the repair when needed.render_still at representative shot boundaries. Treat any returned warnings as 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 — TimelineLayer lock/solo/audio-mute/video-mute and Element.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, record visibilityAnalysis.visiblePixelRatio, foregroundPixelRatio, occupiedBoundsRatio, and maxQuadrantForegroundRatio; compare activeElements against 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.RectShape remains 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.evaluate_motion_variation across 4-6 samples. If it reports low-motion-variation or poor-frame-coverage, or if the still review shows planned elements are never visible/readable, revise the edit.evaluate_edit_quality(videoType:<resolved>) with the same sample set (the full motion gate; leave staticLayout off here). For motion graphics, pass plannedForegroundElementsPerShot from quantitativePlanSheet; for motion-graphics and slideshow flows, also pass paletteRoleColors from the derive_palette roles so paletteBalance can 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. When beatGridPlan came from analyze_audio_rhythm, also pass beatTimesSeconds so audioSync advisories can flag near-miss cuts. Pass allowMinimalDensity=true only when the brief explicitly asks for minimal/negative-space density and the deviation is recorded. Only gate-failing issues (typographyReadTime, rendered typographyContrast, elementStructure, motionContinuity, and supplied-plan layerDensity) block export; shapeIntent, motionIntent, decorativeShapeClarity, gradientFalloff, tempoRhythm, paletteHarmony, and backgroundRichness major issues are advisory and do not block. Revise and re-run until passesQualityGate is true; fix genuine-accident advisory findings when time permits, or record the explicit user reason for allowing an issue.animatedPropertyCount: 0 is a blocker even when evaluate_edit_quality.passesQualityGate is true. Add explicit transform, opacity, spacing, brush, or effect animation before export.textBackgroundFit issues 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 with measure_object_bounds, lower it into the background, or replace it with a non-plate visual treatment.metrics.tempo.RequiredTimelineEventsPerSecond, TimelineEventsPerSecond, RequiredTotalEventsPerSecond, LongForegroundGapCount, and LongestForegroundEventGapSeconds. A scene is too slow if background motion hides sparse foreground changes or long foreground gaps.apply_edit made in response to Phase 4 quality or visual-review findings, call compare_revisions before the next broad fix. Record a delta ledger in notes with metric deltas, issues resolved, issues introduced, regression, and the paired still paths. If regression=true, treat the introduced/worsened axis as a rework finding before export.final_preflight/export, compare the authored result against your quantitativePlanSheet on the same four axes — not just the pass/fail gate. Gather actuals from read_document_summary for shot/Element count, evaluate_edit_quality metrics.tempo (TimelineEventsPerSecond, SlowHoldCount, LongestForegroundHoldSeconds), metrics.layerDensity (Bands, AverageForegroundLayerCount, MinimumForegroundLayerCount, BandsBelowHalfPlannedForegroundLayerCount), and evaluate_motion_variation. Confirm all four: actual shot/Element count ≥ planned shot count; actual TimelineEventsPerSecond ≥ planned edits/sec target (and ≥ RequiredTimelineEventsPerSecond); every hold ≤ its planned ceiling (no SlowHoldCount beyond named resolves); every measured time band's ForegroundLayerCount meets the planned density floor, with a Major layerDensity issue 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 pass allowMinimalDensity. 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 from beutl-agent-brief-expansion (or the coordinator explicitly requests convergence), run beutl-agent-visual-review in its convergence loop mode after the deterministic gates pass and before final_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.final_preflight(videoType:<resolved>) before export when the tool is available. For motion graphics, pass requireAnimatedProperties=true and plannedForegroundElementsPerShot from quantitativePlanSheet; for motion-graphics and slideshow flows, pass the same paletteRoleColors shape used in evaluate_edit_quality; pass beatTimesSeconds from when a music bed was analyzed. Export only when is true. If is unavailable, use the separate + + sequence above.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.render_storyboard(subdivisionLevel:1) and raise to 2 for suspicious gaps on multi-shot types. In-between frames must show bridge motion, transition consistency, or recorded hard-cut intent, and cutEyeTrace must not exceed the budget without a planned bridge or hard-cut reason. For logo-intro or any continuous single-shot piece, pass explicit timeSeconds anchors and inspect the subdivided frames as a motion arc instead of a cut-continuity pass.tempoRhythm metrics.[role:camera-rig] DrawableGroup transforms for push-ins, pans, parallax, and whip-pan cut bridges per cameraPlan; an all-locked-off piece needs an explicit recorded brief reason.IFlowOperator chains such as DrawableGroup, DrawableDecorator, SoundGroup, or ; otherwise split each visual object into its own Element.apply_edit calls; do not use list_compositions, plan_composition, or empty-scene examples as the default output path. To bootstrap from a non-template original starting point, plan_original_scaffold returns 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.list_creative_directions output as raw inspiration only. Do not copy returned seed names as the final concept title, Element/Object names, layer order, or file basename.list_compositions; do not rely on an implicit first template selection.recentToAvoid, pass the structural signature into derive_palette, and deliberately change the structural language (motion verbs, layout grid, palette family, type treatment, transition style) from recent runs; then record_creative_direction so the next run can diverge too.quiet: true to apply_edit for 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.Element boundaries from the enumerated shotBreakdownPlan. One shot normally maps to one or more Element entries with explicit Start, Length, and ZIndex; each ordinary Element contains exactly one drawable/audio EngineObject.Objects inside one Element only for explicit IFlowOperator flow chains such as DrawableGroup, DrawableDecorator, SoundGroup, or Scene3D; otherwise split compound visuals into separate Elements.[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 nested DrawableGroup parenting the content as Children — with locked background plates as separate Elements below the rig, outside the portal's ZIndex range.ZIndex; titles, logos, and overlays should be higher.Id are id-keyed. A bare id-less array merges/appends into the existing members; it does NOT replace them.{ "Id": "...", "$delete": true } for removals.FilterEffectGroup.Children chain instead of appending to it), make the FIRST element the sentinel { "$replace": true }; the following elements rebuild the array in order (omit Id to mint fresh, or reuse an Id to keep that child), and [{ "$replace": true }] alone clears it. Replacement elements cannot also carry $delete/$index/$after/$before. Keep the group's own Id so only its children change.$index, $after, or $before for ordering; do not combine ordering directives.Id means stale handle; call read_document again instead of guessing.{ "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 intentional IFlowOperator flow chain. Ordinary Elements should not receive a second Object.{ "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 omit Id.[role:camera-rig] DrawableGroup): the Objects array must pair a PortalObject immediately before the flow operator — "Objects": [{ "$type": "[Beutl.ProjectSystem]:PortalObject", "Count": <N> }, { "$type": "<DrawableGroup-discriminator>", "Name": "[role:camera-rig] ...", "Children": [...] }]. A bare flow operator without the PortalObject is rejected. Count is an inclusive ZIndex span, not an element count: every active Element with ZIndex in rig+1..rig+Count is pulled into the operator (leave Children empty then; empty rows contribute nothing). pulls no timeline rows, so with the portal as the Element's first object the operator consumes only its nested ; set to explicitly discard earlier same-Element flow. Applies to all s: , , , . See (nested) and (timeline).notes.md granular enough for another observer to reconstruct the route: every apply, save, render, evaluate, export, validation failure, and route change gets an entry.notes.md before the three-minute mark with a heartbeat such as drafting stage N patch; next tool: apply_edit; if you cannot do that, stop and report a blocker.read_operation_status when available and respond immediately with the current session/source, last successful stage, and blocker before continuing.apply_edit reports coercion or rejection, adjust the request and retry the same small stage.BEUTL_WORKSPACE.derive_palette warnings, and how you diverged from recentToAvoid.project.bep, preview.mp4, and still-*.png, or use the requested output directory slug. Record the concept name in notes instead of naming files after it.get_schema before authoring if the required drawable, media, or audio type is not already known.
footage-cut, list every available clip, duration note, usable range, and audio role. For slideshow, list supplied photos or the needed image collection. For lyric-captions, list the music bed or the reason none is needed.beutl-agent-asset-sourcing, follow its license/provenance contract, and write every downloaded or generated asset to assets/manifest.json before apply_edit.list_effect_recipes with a shader/organic intent and consider SKSLScriptEffect instead of stacking only blurred gradient shapes. Prefer SKSL over GLSL for low-context file sessions because it is CPU-safe in still renders.PixelSortEffect, ColorShift on 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 with render_still before relying on them. Do not over-restrict to a single safe effect; varying the effect vocabulary is part of avoiding monotone output.ParticleEmitter drawable (get_schema type=ParticleEmitter) instead of faking a swarm with many ellipse Elements — fake particle swarms also trip decorative-shape review. Its animatable surface covers EmitterShape (point/line/circle), EmissionRate, Lifetime, Speed/Direction/Spread, Gravity, TurbulenceScale, size/color/opacity over particle life, and ParticleDrawable — any Drawable (a glyph fragment, a GeometryShape) can be the emitted sprite.AudioWaveformDrawable, AudioSpectrumDrawable, and AudioSpectrogramDrawable render 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.beutl-agent-source-grounding before authoring layout, transform, bounds, text measurement, render scale, effect-unit, reconciliation, or live-session semantics.
TranslateTransform, TransformOrigin, backing plates, object bounds, render/export range, or when a rendered/user-observed result contradicts the plan..claude/skills/beutl-agent-source-grounding/SKILL.md, then use narrow rg/read passes over the source and tests it identifies.sourceGrounding note with assumption, evidence, rule, and uncertainty before the first relevant apply_edit.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, call analyze_audio_rhythm before authoring and record estimatedBpm, confidence, beatTimesSeconds, and strongOnsetTimesSeconds; 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: reserve RectShape for 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 foreground RectShape behind 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 timeline Element owns exactly one EngineObject. Multiple objects inside one Element are allowed only when that Element contains an IFlowOperator such as DrawableGroup, DrawableDecorator, SoundGroup, or Scene3D; otherwise split content into separate Elements. Choose DrawableGroup for multi-child grouping (camera rigs, portal intake); choose DrawableDecorator when 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 the derive_palette output 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, instantiate get_background_grammar with 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 of Element boundaries in Phase 1.quantitativePlanSheet: turn shotBreakdownPlan into 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 to evaluate_edit_quality / final_preflight as plannedForegroundElementsPerShot so metrics.layerDensity can 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:
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.metrics.tempo.RequiredTimelineEventsPerSecond; record the expected total timeline-event count that produces it.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 (rig ScaleTransform around the focal point via TransformOrigin), pan/tilt drift (rig TranslateTransform.X/Y), whip-pan (fast rig translate + blur as a cut bridge), roll (rig RotationTransform), or parallax (per-depth-band rigs translating at different amplitudes, background slowest). A camera move is authored on a named [role:camera-rig] DrawableGroup that 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 for motion-graphics briefs; an all-locked plan 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 from cameraPlan), 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 animated TranslateTransform; 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.ObjectsElementIFlowOperatorDrawableGroupDrawableDecoratorSoundGroupScene3DElement.IdIdStart, Length, and layer/Z values consistent with the enumerated shot breakdown from shotBreakdownPlan.cameraPlan assigns 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:
Objects = a PortalObject whose Count spans the content rows, then a DrawableGroup with empty Children. Count is an inclusive ZIndex span, not an element count: the portal pulls every active Element with ZIndex in rig+1..rig+Count into the group, so content keeps per-element Start/Length and 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. Fetch get_examples for insert-camera-rig-portal.DrawableGroup's Children (nested children have no Start/Length of their own); the PortalObject's Count stays 0. Fetch get_examples for insert-camera-rig-push-in.
In both patterns the Objects array must contain the PortalObject entry immediately before the flow operator — a bare IFlowOperator is rejected by apply_edit. The same portal+flow grouping works for the other IFlowOperators (DrawableDecorator, SoundGroup for 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.KeyFrameAnimation/KeyFrame (that is Phase 3) and no FilterEffect (that is Phase 2).TextBlock and shape objects, treat TranslateTransform(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 unless AlignmentX=Left/AlignmentY=Top was deliberately selected and source-grounded.GeometryShape path 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 static TranslateTransform(-boundsX, -boundsY); measure_object_bounds reports geometryBoundsOrigin and preview_quality_risks flags uncompensated offsets as geometryPathOffset.measure_object_bounds after 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.insert-new-element-skeleton example; do not inspect a full-scene starter just to learn $type placement.apply_edit stages 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). Inspect valid, changes, validation, and createdIds after each stage before continuing. Pass quiet: true for large staged patches.apply_edit returns validation_rejected, unknown_type, stale handles, invalid animation discriminator tokens, or fallback-object guidance, fix the patch from get_schema/get_examples/read_document and 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.save_project after every successful major apply_edit before continuing to the next stage; omit session unless you are deliberately disambiguating an older session id. For LiveEditor sessions, save_project should report that saving is not required/supported; record that message instead of treating it as a blocker.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 has isFallback: 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 the TransformGroup.Children order still matches transformIntentPlan, and patch the order with $before, $after, or $index before rendering if it does not. Also audit object counts: any ordinary Element with multiple objects must be split unless it contains a named IFlowOperator.staticLayoutfinal_preflightobjectIdwrapInGroup=trueDrawableGroupIFlowOperatorevaluate_edit_qualityelementStructureZIndexOpacityBlendModeScreenrender_storyboard/render_still and evaluate_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.AudioEffectGroupDelayEffectEqualizerEffectCompressorEffectLimiterEffectSoundGroupIFlowOperatorPortalObjectUseGlobalClock=false, KeyFrame.KeyTime is local to the owning timeline Element and should normally stay within 00:00:00..Element.Length. With UseGlobalClock=true, KeyFrame.KeyTime is a scene timeline time and should intersect the visible Element range.get_examples for animate-float-property-keyframes when animating an existing object, or insert-new-animated-text-keyframes when creating a new animated text object. Copy the concrete KeyFrameAnimation<T> and KeyFrame<T> discriminators from the example instead of inventing animation type names.Single, Boolean, Color, Size, or transform property. Do not hand-type or manually Unicode-escape the generic discriminator strings; invalid tokens around KeyFrameAnimation or KeyFrame mean the helper is wrong and must be rebuilt from get_examples before continuing.apply_edit.validation contains a Warning for 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 setting UseGlobalClock=true when scene timeline times were intended.TranslateTransform.X and 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 as RotationTransform, SkewTransform, or non-animated ScaleTransform before the animated TranslateTransform in the TransformGroup. 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.analyze_audio_rhythmreadyForExportfinal_preflightrender_stillevaluate_motion_variationevaluate_edit_quality(videoType:<resolved>)export_video when an encoder is available; if export is unavailable, record the reason in notes. Control output size with crf (0-51, higher = smaller; raise it to ~28-30 for full-frame grain or other hard-to-compress content) or bitrate (bits/s, ABR) — the two are mutually exclusive. For a long export, pass background: true and poll read_render_job(jobId) the same way as render_storyboard. In the final report, surface any CC-BY-SA share-alike obligations, user-supplied URL assets recorded as license: "unverified", and all required attribution text from assets/manifest.json.save_project for file sessions after final revisions. For LiveEditor sessions, call read_operation_status or save_project once near the end if you need to report that the live edit is already applied but not file-saved by the toolkit.Scene3Devaluate_edit_quality.metrics.layerDensity, not only a manual object count.[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.SKSLScriptEffect on a broad shape is often better than many low-contrast blurred ellipses for heat, ink, glass, smoke, caustics, grain, or shimmer.read_document_summary exposes the intended structure.evaluate_motion_variation; treat low adjacent-frame variation or persistent one-quadrant/sparse frame coverage as a failed self-check for motion graphics.evaluate_edit_quality reports animatedPropertyCount: 0, revise the edit to add deliberate animation on transform, opacity, typography spacing, brush, or effect parameters before export.evaluate_motion_variation passes.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. tempoRhythm defaults to a 130 BPM target, so a calm 3-act brand/logo piece trips its minor advisories harmlessly — passesQualityGate/readyForExport stay true.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.passesQualityGate must be true before final export for normal deliverables.Count: 0ChildrenClear: trueIFlowOperatorDrawableGroupDrawableDecoratorSoundGroupScene3Dget_examplesinsert-camera-rig-push-ininsert-camera-rig-portal