Put the default first: a value used in several places should usually be one shared
slot referenced from every property.
Frame targetSids as the escape hatch for values that cannot share one slot, mainly
native text, where each slot carries its own document/style. Remove the brand-color
example so the docs do not encourage targetSids for values that should usually be
modeled as a shared slot.
Replace the narrow targetSids example with realistic template cases that show why one
control may fan out to multiple slots.
The updated example covers shared brand colors, branded text, and reused event content
across scenes, instead of placeholder ids like accent/heading. It also keeps the docs at
the contract level by making the same-slot-type rule explicit and avoiding implementation
details.
The ids are plain and deterministic so the example stays easy to read and assert in
tests.
A template value often belongs in several places at once — a brand color
across many fills, one headline reused at different sizes. A slot per
occurrence means editing the same value repeatedly, and the copies drift
out of sync.
Sharing a single slot solves that for uniform cases, but not for text: a
Skottie text slot carries the whole text document — font, size, fill,
stroke — so the same string in two styles or sizes can't share one slot
without collapsing to a single look. Those occurrences are forced apart
into separate slots.
targetSids reconciles both. A control writes its value to its own `sid`
plus every id it lists, and the targeted slots leave the Properties panel:
one input, many slots, always in sync. Text edits go through setText
(string only), so each layer keeps its own style. Works for any slot type;
the primary and every target must share that type.
Contract documented in references/player-contract.md.
Editable multi-word text slots (headlines, subtitles, quotes, CTAs) now
default to native Lottie box text (sz/ps) so a longer edit wraps at a
fixed width instead of overflowing; point text stays for single glyphs,
tiles, logos, and choreographed type.
Verified in the current Skottie path (canvaskit-wasm 0.41.1): wraps on
load and re-wraps on live slot edits, j/lh honored, and edit+save
preserves sz/ps/lh. Caveats captured: box text is top-aligned (no auto
vertical-centering) and does not clip to its height.
- player-contract.md: new "Point Text vs Box Text" section
- recipe-typography.md: default editable multi-word slots to box text
- output-rubric.md: eval expectation for wrapping slots
Skottie enumerates slots in unordered_map hash order, so the panel
appeared scrambled. Sort the slots memo by controls.json order;
uncontrolled slots sort last (stable sort keeps their order).
Native text slots authored as slots[id].p = { a:0, k:[{t,s}] } (or with a
missing a) render blank in Skottie: it treats the keyframe array as a static
value and resolves empty text. Document the a:1 requirement in the player
contract, correct the canonical test fixture to the render-safe shape, and add
a local structural invariant test that flags keyframed text slots missing a:1.
CanvasKit's getTextSlot mangles non-ASCII text (mojibake on save), so
read text slot values from the source JSON plus an in-memory overrides
map instead of off the animation. Edits now write to both the slot
document and its bound layer fallback.
- canvas.tsx: track text edits in a textOverrides signal, derive slots
from sourceDoc + overrides, reset overrides when the scene reloads,
and bail out of save on a failed HTTP response
- lottie.ts: add readTextSlotValue/writeTextSlotValue and export
LottieDoc; cover slot document and bound-layer shapes
- add scripts/text-slot-unicode.test.mjs and a check:text-slots script
Color slots now call commitSource() on the picker's change event (the native OS picker doesn't blur the input), so a pick persists without needing to click away; the onBlur commit stays as a harmless no-op fallback. The swatch/hex now read edits() through reactive accessors so the sidebar updates live instead of showing the stale render-time value. Alpha is preserved; scoped to the color block, no other inputs touched.
Enter now applies the current value and calls commitSource without blurring, so the edit persists immediately and survives a refresh while the input keeps focus. The existing blur-to-commit behavior is unchanged; scalar and color inputs are untouched.
setTextSlot updated the slot value (so edits persisted on commit) but did not re-shape the active canvas in canvaskit-wasm 0.41.1 - the preview only updated on reload. Worse, once setTextSlot was called it locked the layer so subsequent setText() calls no longer re-shaped, which would have made only the first edit per slot update live.
Drive the text edit path through setText(key, text, size) only, targeting each text layer bound to the slot (mapped from the source doc by t.d.sid -> layer nm). setText re-shapes on every edit AND updates the slot value (getTextSlot reflects it), so readSlots/applySlotValues still persist correctly on commit. No setTextSlot call remains in this path.
Brings text slots to live-preview parity with color/scalar/vec2, no rebuild, no camera reset. Persistence, the slot abstraction, and other slot setters are unchanged.
Verified in editor: first and second edits to the same slot both re-shape live; commit persists only the edited slot; reload shows latest value; unedited slots and layer inline text unchanged.
Editing a text slot from the properties panel did nothing because the
runtime path was broken in two places, independent of any scene:
- setTextSlot called `new ck.SlottableTextProperty(...)`, a constructor
canvaskit-wasm 0.41.1 does not expose, so the call threw before the
canvas could repaint. Pass the mutated property object to setTextSlot
directly, which this version accepts.
- applySlotValues persisted text to slots[id].p.p.t, but Skottie reads a
slotted text document at slots[id].p.k[0].s.t, so committed edits
reverted on reload. Write to the path Skottie reads (with the old flat
shape kept as a fallback).
This brings text slots to parity with color/scalar/vec2 slots: apply
live on edit, persist correctly on commit.
- Update documentation to clarify the use of native Lottie text slots, emphasizing the requirement to ship font files alongside the scene.
- Modify the export process to include font files in the project zip, ensuring proper rendering of text layers.
- Refactor scene loading to accommodate both images and fonts, improving asset management.
- Adjust type definitions to include font URLs, enhancing type safety and clarity in the codebase.
- Revise output rubric and typography references to reflect the new font handling guidelines and best practices for text rendering.
Merge cut-on-action and easing-anchor notes into a Seam Mechanics section with a
per-method table (hard cut, jump cut, motion-masked swap, continuous carry,
occlusion wipe, hold/settle cut, loop reset) covering why each seam works, the
outgoing/incoming boundary-frame conditions, supporting anchors, and when to
switch. Add a Seam Plan checklist and a Seam Verification pass.
New references/chapterization-transition-grammar.md covering when/when-not to
chapter, chapter roles, structure modes, transition grammar, cut-on-action
mechanics, easing-anchor support, and guardrails. Route dense/multi-idea prompts
to it from SKILL.md, add a motion-taste section summary and cross-link, and split
the loop-reset bullet out from the hard-cut rule.
Clarify that o goes on the start keyframe and i on the destination (final
keyframe needs no outgoing o), reframe the generic-easing principle around
locked vs offset timing, and tidy the overshoot note to end i.y ~1.08 to 1.2.
Replace conceptual Easing Intent with a curated 7-anchor palette (derive,
not presets), keyed to motion behavior not layer type. Add per-property
orchestration methods, hierarchy, distance/duration, and hard-cut/loop rules.
Document the cubic-bezier -> Lottie o/i handle mapping in lottie-spec-map, and
nudge SKILL.md to derive easing from the anchors.
The skill hardcoded localhost:3030 for all curl/navigation, but the Vite
config sets server.port without strictPort, so the server falls back to the
next free port when 3030 is taken.
This happens most often when running multiple text-to-lottie projects in
different folders at once: the second 'npm run dev' lands on 3031+, but the
skill still pointed the agent at 3030 — silently inspecting the wrong
project. Lead with the rule to trust the printed port and use <port>
throughout.
Replace the warm-near-black/cream default with a preference for pure
black/white (000/fff) contrast or another deliberate premium palette;
warm/cream tones become opt-in only when the user asks.
Hand-placed vector text has no line-height, so mixing a small label and a
large value on a shared baseline made the smaller run sink, and stacked
title/subline spacing was ad-hoc. Add a font-derived cap-center placement
formula, a type-relative vertical-rhythm rule, and QA gates so the defect
is prevented and caught.
- player-contract: cap-height baseline formula + zoomed-in alignment review
- design-taste: cap-center mixed-size rows, vertical-rhythm rule, review check
- recipe-data-stats: KPI-row alignment failure modes + acceptance checks
- output-rubric: mixed-size row / spacing eval blockers
- Changed "harness" to "framework" for better accuracy in describing Text-to-Lottie.
- Revised the description of the agent's setup process to provide clearer instructions on workspace and player functionality.
- Updated CanvasProvider to include a refetch mechanism for scene data upon external edits to the Lottie file.
- Modified loadScene function to disable caching for Lottie file fetches, ensuring the latest version is always loaded.
- Implemented a self-write tracking system in the scenes plugin to differentiate between internal and external changes, triggering live reloads only for the latter.
- Included a new References section in SKILL.md to provide a link to the Lottie format specification documentation.
- This addition aims to enhance the resourcefulness of the document for users seeking detailed information on Lottie animations.
- Deleted the controls.json file as it is no longer needed.
- Updated lottie.json to reflect changes in naming and structure, including renaming the main scene and modifying layer properties for improved clarity and functionality.
- Added context menu functionality to allow users to delete scenes and projects directly from the UI.
- Integrated deleteScene and deleteProject functions to handle deletion requests and navigation upon deletion.
- Updated SceneItem and SidebarLeft components to utilize context menus for improved user interaction.
- Enhanced CSS for context menu styling to ensure a consistent and visually appealing design.
- Implemented a dynamic color scheme toggle based on user preferences for improved accessibility.
- Updated CSS variables for light and dark themes to ensure consistent styling.
- Refined the NumericSlider component by removing default box-shadow and border styles for a cleaner appearance.
- Adjusted button styles in base.css to support dark mode while maintaining visual consistency.
- Introduced a focus-visible style to enhance keyboard navigation and accessibility.
- Applied a consistent inset border and box-shadow for focused elements, overriding default styles.
- Ensured smooth transitions for focus effects to improve user experience.
- Integrated UI context to manage the visibility of controls in SidebarLeft and SidebarRight.
- Updated App component to conditionally render ScenesContainer based on control expansion state.
- Adjusted SidebarLeft and SidebarRight widths dynamically based on control visibility for improved user experience.
- Refactored SidebarLeft to include project management features only when controls are expanded.
- Added functionality to track and report live playback state, including project, scene, frame, and playback status.
- Introduced server middleware to handle browser heartbeat updates and provide context for active projects and scenes.
- Enhanced scene metadata retrieval with last modified timestamps for better asset management.
- Updated onKeyDown function to handle space key for toggling playback.
- Implemented arrow key navigation to step through frames and seconds.
- Improved input handling to prevent key hijacking while typing in editable fields.