Skip to content

Latest commit

 

History

167 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Macro Recorder — LottieFiles Creator plugin

Macro Recorder records the edits you make in Creator — transform changes, fills, keyframes, structure, and more — as a named, replayable macro. It replays those steps onto whatever you select.

It is published in the Creator Extensions marketplace: extensions.lottiefiles.com/plugin/inerds/macro-recorder. Install it from there to use it; read on to build it, run it without Creator, or use it as a reference.

The user guide is published on the project wiki, a read-only mirror of docs/user-guide.md that a push to main regenerates. The other documents stay in docs/.

This repository is also an open-source reference for Creator plugin developers. Beyond the product, it documents patterns that any Creator plugin needs:

  • A panel-to-sandbox RPC protocol with a mock fallback, so every panel state is reachable without Creator (ui/gateways/, engine/protocol.ts).
  • The QuickJS sandbox constraints that the typings do not mention, above all the no-job-pump callback contract (pnpm test:quickjs enforces it).
  • The host API's real runtime surface, found by introspection (docs/runtime-api.md), and confirmed host limits with evidence (docs/limitations.md).
  • A fake host scene for tests and a browser harness that reproduce the real proxies' traps (engine/testing/fakeScene.ts, dev/harness/host-harness.html).
  • Trace-driven debugging: every dev session writes an auditable bundle of RPC traffic, snapshots, and probes (see "Diagnostics and triage").

Inside Creator, the real engine runs. The panel polls the plugin sandbox every 500ms over a small RPC protocol. The sandbox snapshots the scene, diffs it against the previous snapshot, and returns human-labeled steps. Macros persist in creator.clientStorage. Standalone, in a plain browser tab, the handshake times out and the panel falls back to mock gateways and the dev strip.

Document map:

  • docs/user-guide.md — the end-user walkthrough of every feature.
  • docs/architecture.md — the invariants behind the code's shape: the three TypeScript projects, the sandbox constraints, the proxy boundary, the recording engine, and the gateway seam.
  • docs/design-system.md — the panel's skin, deck, and rack rules.
  • docs/runtime-api.md — the host API's real runtime surface. Read it before you extend the engine; the published typings still diverge from the runtime in the places that file lists.
  • docs/limitations.md — confirmed host limits, with evidence.
  • CONTRIBUTING.md — setup, the checks a change must pass, and how a release is cut.
  • docs/contributing/ — the writing style standard, the trace-triage workflow, and the ENGINE_REV rule.
  • docs/history/ — the engineering log, the 2026-08-24 UI audit, and the v3.1 roadmap.
  • docs/releases/ — the release notes per shared build.
  • CHANGELOG.md — user-visible changes per version.

How the engine works

  • engine/ holds the pure, fully unit-tested logic both sides use: protocol, snapshot model, structural differ, labels, relative-playback math, simplification, and value editing.
  • sandbox/ is the QuickJS sandbox: RPC dispatcher, defensive proxy-to-snapshot serializer, step applier, and the clientStorage store. The sandbox has no timers — the panel owns all timing.
  • ui/gateways/rpc/ is the panel side: the RPC bridge, the tick-loop recorder gateway, and the paced step-by-step playback orchestrator.

What you select before you press Record decides what the recorder watches. Select one or more layers, and it records those layers only: their subtrees, paints, masks, trims, plain flags, and structure. A selected shape counts as its layer. Layers that appear while you record, such as duplicates and new layers, join the recording. Select nothing, and it records the whole scene, the scene settings included. The deck shows which one Record will do. An edit outside the recorded layers is dropped and counted on the recording screen, never dropped in silence. While you record, selecting one keyframed recorded layer offers to capture its keyframes and current style into the macro. Hold Option (macOS) or Alt (Windows) while you press Record, and the recording stores every layer-transform step as the value it ended at rather than as a delta.

Replay picks one of two modes. A macro that touched at most one layer applies to every selected layer: the layer's own position, rotation, and skew shift each target from its own start, scale multiplies, and everything else applies exactly. Each transform step carries a formula on the target's current value, and the pencil opens it as a verb and a number — Set to, Add, Subtract, Multiply, Divide, or Formula… for a whole expression such as v * 2 + 10, where v is that current value. Only layers are targets — a selected shape is dropped with a note, because every step addresses its layer by path. A macro that touched several layers, or that restructured the scene, replays as a scene rebuild: each step finds its layer by recorded id, then by name, then skips with a note.

Two rules govern every step:

  • Keyframes converge. A macro means "end up like this". Frame numbers are the only keyframe identity, adds upsert onto occupied frames, and removes of absent keyframes do nothing.
  • Nothing applies silently. The host discards some writes without an error, so the applier verifies and reports a note for every non-apply or adaptation. Genuine failures pause for Continue or Stop.

Pro tools are client-side data transforms: Simplify, per-step disable and edit, parameters (pinned values asked for on play), and the play options — at playhead, stagger, and repeat ×N.

Run it

From the marketplace (use it)

Install Macro Recorder from the Creator Extensions marketplace and open it from Creator's plugins menu. That is the released build; the two ways below are for developing it.

Standalone (primary dev loop)

You need Node.js 22.12 or later and pnpm (the repository pins pnpm@10.33.0 through packageManager).

pnpm install
pnpm dev

Open http://localhost:5173 and size the viewport to about 320×560, the size the plugin asks Creator for in sandbox/plugin.ts. The Dev settings strip at the panel foot (dev builds only) loads the ten demo macros, clears the store, controls the mock recorder and playback scenarios, and shows captured traces.

Inside Creator

Run pnpm dev, then add the plugin in Creator:

  1. Open creator.lottiefiles.com.
  2. Open the Plugins panel.
  3. Click the + icon at the top right.
  4. Open the Develop tab.
  5. Enter http://localhost:5173 and click Continue.

After any change under sandbox/ or engine/, remove and re-add the plugin. Creator evaluates plugin.js once and never re-fetches it, while Vite serves the panel fresh. Bump ENGINE_REV in engine/protocol.ts with every sandbox-side change; the handshake compares revisions and logs a loud plugin engine is STALE warning on mismatch.

Host harness (full loop, no Creator)

http://localhost:5173/host-harness.html emulates the host: a fake creator global, fake scene nodes, the plugin bundle, and the real panel iframe. The dev server compiles and serves plugin.js on request, so pnpm dev alone is enough — there is no build step to remember. Drive the fake scene from the console through window.harness. pnpm test:harness drives the same page without you (see scripts/ui-probe/README.md). dev/harness/sandbox-test.html reproduces Creator's opaque-origin iframe (no localStorage, no crypto.randomUUID) for the fallback paths.

Tests

pnpm test          # vitest: engine logic, reducer, demo and corpus replay (899 tests, 38 files)
pnpm test:quickjs  # builds, then drives dist/plugin.js in real QuickJS
pnpm test:ui       # opens the panel in headless Chrome and probes the DOM
pnpm test:harness  # records and replays through the host harness in headless Chrome
pnpm type-check    # tsc -b across all three project references
pnpm build         # production bundle → dist/ (manifest.json, plugin.js, ui.html)

test:quickjs exists because Creator invokes the sandbox's callback without pumping the VM job queue. A pure VM promise chain never settles there, so code that passes in a browser can be dead in Creator. The smoke test drives the real bundle with zero pumps and asserts the RPC contract holds.

pnpm test also replays the macro corpus — one saved macro per shape this plugin has ever written to storage or export — so a change to the step shape that an older macro cannot survive fails a test instead of blanking a panel (engine/testing/macros/, and see docs/contributing/macro-corpus.md).

test:ui exists because the unit tests run in Node with no DOM. It opens the panel in headless Chrome over the DevTools protocol and asks the page what paints on top, what a box measures, and what a key does under a modifier — the questions that caught a menu buried behind the deck.

test:harness exists because the other checks each see one half of the plugin. It drives the host harness in the same headless Chrome: the real sandbox bundle, the real panel, and the fake scene as the host. It records an edit, saves the macro, replays it onto other layers, and asks the fake scene what the values became. It is the only check that runs record and playback together. Both suites share one driver — see scripts/ui-probe/README.md.

Repository layout

sandbox/        The QuickJS plugin sandbox: RPC dispatcher, serializer, applier, store, manifest.
engine/         The pure engine both sides use: protocol, snapshots, differ, labels, simplify.
ui/             The React panel: state machine, gateways, components, styles, dev strip.
dev/harness/    Host-emulation pages for the dev server only. Never part of the build.
scripts/        The trace server, the QuickJS smoke test, the release bundler, and the
                release-notes helper.
docs/           User guide, architecture, design system, runtime API, limitations,
                contributing guides, release notes per version, and the history log.
.claude/        The triage agents, the /triage-traces skill, and the two installed
                LottieFiles Creator plugin skills.
.github/        CI (type-check, tests, QuickJS smoke, build) and the tag-driven Release workflow.

Each tree compiles under its own tsconfig.*.json and tsconfig.json is the solution file. pnpm bundle builds and writes release/macro-recorder-v<version>.zip with exactly the three files Creator needs, and pnpm bundle:dev writes the -dev build with the dev strip on, the name "Macro Recorder (dev)", and its own plugin id, so the dev build keeps a separate macro store in Creator. The build stamps the version into manifest.json.

Diagnostics and triage

Dev sessions write a trace bundle per record and playback run to traces/. Each bundle carries what the panel never shows: every RPC call with timing, the {prev, next} snapshot pair behind each recorded tick, and per-target probes before and after each playback step. Snapshot and probe payloads are opt-in per session (debug: true, dev builds only), so a production panel gets byte-identical responses.

To triage captured traces, run the skill in Claude Code:

/triage-traces

The skill:

  1. Lists the trace files that traces/.processed does not name yet.
  2. Fans out one read-only macro-triage agent per trace. Each agent checks env.sandboxRev first, then classifies the trace against the failure taxonomy and returns a diagnosis with evidence.
  3. Dedupes and ranks the findings.
  4. Turns each confirmed finding into a failing regression test through the macro-fixture agent before anyone writes a fix.
  5. Appends the triaged filenames to traces/.processed.

Trace bundles are large — never read one into the main context; the agents exist for that. Nothing cleans traces/ automatically; delete it when you finish. When you triage by hand, check env.sandboxRev first: a stale sandbox reproduces bugs that are already fixed.

Architecture pointers

  • ui/state/appReducer.ts — one discriminated-union state machine with five modes (idle → recording → reviewing, and idle → playing directly or through configuring, the pre-play parameter form).
  • ui/gateways/types.ts — the three gateway interfaces the panel talks to; ui/gateways/index.ts is the single real-versus-mock seam.
  • sandbox/serialize.ts and sandbox/applier.ts — the reads and the writes of Creator's live node proxies. sandbox/playback.ts and sandbox/recorder.ts touch a proxy only to resolve targets, run scene-level ops, and probe for diagnostics. Everything downstream is plain data.
  • engine/testing/fakeScene.ts — the test double for the proxy surface, shared by the harness and vitest. It reproduces the host's traps on purpose, above all that a staticValue write does nothing while keyframes exist. Never make it more permissive than the real host.

Accepted limitations (v1)

  • The layout holds a min-width: 260px and scrolls horizontally below that.
  • Sharing is Copy JSON and Import, not file export — Creator's sandboxed iframe can block downloads. docs/limitations.md tracks the host limits with their evidence.

License

MIT — see LICENSE.

About

Macro Recorder for LottieFiles Creator - records your edits as replay-able macros.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages