Commit Graph
6 Commits
Author SHA1 Message Date
Vance IngallsandClaude Fable 5 def276524b fix(core,cli,lint): close the figma brand-token loop — runtime CSS variables, --name, snippet lint
Brand-loop live test (SDS duplicate, plans/figma/brand-loop-test-plan.md)
proved the recolor chain end-to-end and surfaced three gaps:

- runtime now defines every declared composition variable as a CSS
  custom property (document root at init + scoped sub-comp hosts in the
  loader), so imported var(--slug, literal) fills resolve live — without
  this the frozen literal always won and variable-driven rebranding
  could not propagate. Slug kept byte-compatible with the figma
  importer (parity test). render --variables overrides win.
- figma component --name: variant frames are often all named
  'Platform=Desktop' and slug-collided across imports.
- imported fragments carry data-hf-snippet and the project linter skips
  composition-root rules for them.
- /figma skill documents the field-tested non-Enterprise tokens path
  (MCP get_variable_defs joined with REST boundVariables ids).

Shared-helper extractions (injectScopedStyles, flattenedRoot module,
parseHostVariableValues, rasterizeFallback, shapeCss) satisfy the
dedup/complexity audit the runtime changes tripped.

Validated live: brand-loop renders purple from the attribute alone (no
manual :root); 118 figma + 662 runtime/compiler + 331 lint tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 00:47:13 -07:00
Vance IngallsandClaude Fable 5 4c8064d4d3 fix(cli): figma component import survives unrenderable nodes (#2022)
Live testing against a real community file (Ratings) found a nested
instance node figma refuses to render as svg — which aborted the entire
component import. The rasterize loop now retries the node as png, and
only if both formats fail warns and skips THAT node (placeholder keeps
its data-figma-rasterize marker, no src) instead of failing the import.
On the file that surfaced this, the png retry recovers the node — 31/31
placeholders get assets.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 01:59:48 -07:00
Vance IngallsandClaude Fable 5 e9076324e7 feat(cli): figma import telemetry — subcommand labels, typed error codes, figma_import event (#1979)
Closes the observability gaps on the figma integration:
- withFigmaErrors takes a command label (figma:asset|tokens|component) and
  reports the failure inline before its process.exit — the top-level
  trackCommandFailures wrapper never sees self-exiting commands, so typed
  codes (NO_TOKEN, BAD_TOKEN, FORBIDDEN, RATE_LIMITED) were invisible.
  FigmaClientError codes surface as the error name for dashboarding the
  first-run funnel (NO_TOKEN -> later success = onboarding conversion).
- new figma_import event per import: phase, duration, reused (dedup
  effectiveness), tokens variables-vs-styles mode + entry count
  (Enterprise gating rate), unresolved-binding + rasterized-node counts
  (fidelity degradation). No fileKeys, node ids, names, or descriptions.
- /figma skill fires the events beacon (figma-motion / figma-shaders /
  figma-storyboard) for the MCP phases that never touch the CLI.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 23:27:58 -07:00
Vance IngallsandClaude Fable 5 3900caaaa9 feat(core,cli): media-use interop — shared index.md regen + description/entity on figma imports (#1927)
Post-release review of media-use ↔ figma coupling (spec §13.1):
- figma asset imports now regenerate .media/index.md, the agent-readable
  inventory media-use maintains — format locked byte-identical via a
  cross-runner parity test against media-use's own index-gen.mjs
- figma asset --description/--entity land in the manifest record, the
  index table, and <img alt>; component rasterize auto-describes with
  the node name. Named brand marks become visible to media-use's
  resolve --entity lookups.
- spec §13.1 records the review verdict (loose coupling correct) and
  the follow-up queue (shared media-ledger module, global cache for
  figma assets, media-use version-keyed idempotency)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 22:56:43 -07:00
Vance IngallsandClaude Fable 5 566d49382c feat(skills): reroute /figma by capability - REST/CLI for phases 1-3, MCP for 4-5 (M4) (#1873)
* feat(skills): reroute /figma by capability - REST/CLI for phases 1-3, MCP for 4-5 (M4)

Rewrites the skill from MCP-first to the spec 2 split: asset/tokens/
component route through the hyperframes figma CLI (FIGMA_TOKEN), motion/
shaders stay agent-driven over MCP (no REST equivalent). Adds two-
credential guidance, Starter rate-limit tactics (recursive:true, raw-
response cache, opt-in screenshots), the 7.1 binding flow (tokens before
components, one ask per unknown library, never value matching), and the
shader manual-export default. Catalog blurbs updated in lockstep.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(cli): register figma component subcommand

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(skills): add storyboard-to-animatic guidance to /figma

Field-tested against a real 26-scene storyboard section: the parsing
grammar (frame-sized nodes incl. loose rectangles = scenes, x-order =
time order, TEXT below the strip = director notes paired by x-overlap),
batched still export (chunk ~4 ids per render call - big frames timeout
past ~12), a note-verb -> transition vocabulary (EXPLOSION/SLIDE/MORPH/
CYCLE), and the stills-vs-component routing rule for within-scene motion
notes. Catalog blurbs updated in lockstep.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(skills): storyboard frames are keyframes, not slides

Field-tested against a second real storyboard section: frames sharing an
element (matched by name, else geometry similarity) define that element's
states through time - tween the element between states, crossfade only
when pixels genuinely differ, enter/exit unmatched children, tween frame
backgrounds as a color track. Stills demoted to fallback for frames that
don't decompose. Validated live: a 4-frame logo-rise reconstructed as one
element with four keyframes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(figma): self-explanatory first-run experience + mintlify guide

- NO_TOKEN/BAD_TOKEN errors now carry the full one-time setup (mint URL,
  read-only scope checklist, persist hint) instead of a bare pointer
- figma subcommands print clean guidance on typed client errors, not a
  stack trace (shared withFigmaErrors boundary)
- CLI help gains component subcommand, FIRST-TIME SETUP and WHAT TO
  EXPECT blocks
- /figma skill: preflight the token before the first CLI call and walk
  the user through setup up front; narrate landed-artifact + next action
  at every step
- new docs/guides/figma.mdx (setup, per-phase walkthroughs, provenance,
  troubleshooting table) wired into docs.json nav

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(figma): review fixes — missing withFigmaErrors imports, 401/403 semantics, docs accuracy

- tokens.ts/component.ts called withFigmaErrors without importing it
  (tsup doesn't typecheck, so every invocation shipped as an immediate
  ReferenceError); imports added, tsc --noEmit now clean
- error boundary widened to all Errors so bad-ref/bad-format input
  errors print their message instead of a stack trace
- 401 no longer claims 'missing scopes' (figma signals that as 403);
  new FORBIDDEN code maps non-variables 403 to scope/access guidance
- docs: asset/component refs require a node id (bare fileKey is
  tokens-only), example snippet matches real output, FORBIDDEN row
- skill: preflight counts a project-.env token as configured (CLI
  auto-loads it); BAD_TOKEN/FORBIDDEN guidance split

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(cli): present figma errors via standard errorBox

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 19:13:08 -07:00
Vance IngallsandClaude Fable 5 ee7a96147a feat(core,cli): figma component import with binding-aware node-to-html mapper (M3) (#1872)
resolveBindings: scan the full tree (boundVariables + style ids, alias
chains, children) and partition exact-ID-only against the binding index
before any CSS is emitted per spec 7.1 - never value matching.

nodeToHtml: absolute geometry at figma bounds inside a fixed-size root,
solid/linear-gradient fills, corner radius, opacity, drop shadow, blur,
text styles; resolved bindings emit var(--slug, literal), unresolved
bake literals with data-figma-unresolved; visible:false respected;
vectors/boolean ops route to a rasterize list.

hyperframes figma component: tree -> bindings -> html, rasterize
fallback via Phase-1 asset export with src backfill, registry-item
packaging, unresolved-binding guidance in output.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 18:19:01 -07:00