feat: /understand-figma — Figma design knowledge graph (foundation)#516
feat: /understand-figma — Figma design knowledge graph (foundation)#516smjeong84 wants to merge 23 commits into
Conversation
…tion) Sub-project 1 of 5: Figma REST API ingestion behind a source-adapter seam, shallow structural graph (page/screen/component/componentSet/ instance) + light design-system model (token nodes, uses_token), a new design-analyzer LLM agent, kind:"design" dashboard view with hybrid text-node + sidebar-thumbnail rendering. B/C/D/E captured as roadmap.
15 TDD tasks: schema (design types, figmaMeta, instance_of promotion), core figma module (source adapter, parse-document, tokens, merge, barrel), design-analyzer agent, /understand-figma skill + scan/merge scripts, dashboard node colors + sidebar thumbnail, incremental version skip.
…ercasing sanitizeGraph lowercases every node type, and componentSet is the only camelCase canonical NodeType. Without a lowercased-form alias it became "componentset", failed the enum check, and was dropped along with its variant_of/contains edges — silently losing all component sets from a design graph. Add componentset->componentSet alias + regression test.
The NodeType union widened with 6 design types (page/screen/component/ componentSet/instance/token). NODE_TYPE_TO_CATEGORY is Record<NodeType, NodeCategory>, so the dashboard build failed until every key was present. Group the design types under the existing "code" category (matching the runtime `?? "code"` fallback) so design graphs stay visible by default; a dedicated "design" category is deferred polish.
|
@codex review this |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c1f75440b1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (doc.version && prevVersion === doc.version && process.env.UNDERSTAND_FIGMA_FORCE !== "1") { | ||
| console.error("UP_TO_DATE"); | ||
| process.exit(0); |
There was a problem hiding this comment.
Refresh thumbnails even when the file version is unchanged
When the same Figma version is seen, this exits before renderImages runs, but the scan stores pre-signed thumbnail URLs and the code below notes they may expire after a few hours. In the common case where a user reopens or reruns /understand-figma later without any design edits, the command reports UP_TO_DATE and leaves the dashboard with expired/broken sidebar thumbnails unless they know to force a rebuild.
Useful? React with 👍 / 👎.
| function walk(n: FigmaNode) { | ||
| const consumerId = graphIdByFigmaId.get(n.id); | ||
| if (consumerId && n.styles) { |
There was a problem hiding this comment.
Carry token usage from nested Figma layers
This only emits uses_token when the node that directly owns styles is also one of the shallow structural nodes. For real screens/components where fills or text styles are applied to nested TEXT/RECTANGLE layers, consumerId is undefined, so the walker silently drops the token usage instead of attributing it to the nearest screen/component/instance; the resulting design-system graph shows token nodes but misses most consumer relationships.
Useful? React with 👍 / 👎.
| // Design node types (Figma graphs). No dedicated filter category in v1, so they | ||
| // group under "code" — matching the runtime fallback below — to stay visible by default. | ||
| page: "code", screen: "code", component: "code", componentSet: "code", instance: "code", token: "code", |
There was a problem hiding this comment.
Add design node types to exported filter state
These design types are only added to GraphView’s category map; the dashboard filter state in store.ts still initializes ALL_NODE_TYPES without page, screen, component, componentSet, instance, or token. ExportMenu.exportJSON always applies filterNodes with that default set, so exporting a freshly generated design graph with no user filters strips all design nodes and their edges from the JSON.
Useful? React with 👍 / 👎.
c1f7544 to
8d83812
Compare
…rt doesn't drop them ExportMenu.exportJSON always runs filterNodes() with filters.nodeTypes, which is initialised from ALL_NODE_TYPES. The 6 design NodeTypes (page/screen/component/componentSet/instance/token) were missing from the dashboard's local NodeType union and ALL_NODE_TYPES, so exporting a freshly loaded kind:"design" (Figma) graph with no user filters stripped every design node and its edges from the JSON. Add the design types, plus a guard test that is compile-time exhaustive over the core NodeType union (satisfies Record<NodeType, true>) and asserts at runtime that ALL_NODE_TYPES covers them — so a future core NodeType can't be added without keeping it exportable. Addresses Codex review (P2) on PR Egonex-AI#516.
extractTokens only emitted uses_token when the node that directly owns `styles` was itself a shallow structural node. Real screens/components apply fills/text styles on nested TEXT/RECTANGLE leaves, so consumerId was undefined for them and the walker silently dropped the usage — the design-system graph had token nodes but almost no consumer edges. Thread the nearest structural ancestor (screen/component/componentSet/ instance/page) down the walk and attribute a styled leaf's tokens to it. Add a regression test covering a screen whose styling lives on a nested TEXT layer. Addresses Codex review (P2) on PR Egonex-AI#516.
Screen thumbnail URLs are pre-signed and expire after a few hours. The incremental guard exited on UP_TO_DATE *before* rendering images, so a re-run with no design edits left the dashboard sidebar showing expired/broken thumbnails unless the user knew to set UNDERSTAND_FIGMA_FORCE=1. Re-render screen thumbnails and patch knowledge-graph.json in place on the UP_TO_DATE path (best-effort; never fails the run), then still skip the expensive re-parse + LLM re-analysis. Extract the shared patching logic into core applyScreenThumbnails() (used by both scan paths) with unit tests. Addresses Codex review (P2) on PR Egonex-AI#516.
|
Hi @smjeong84 and @gruming , thanks for this PR, I'll take a deeper look at this weekend. Really appreciate it! |
Why this feature?
Understand Anything already turns code (
/understand), wikis (/understand-knowledge), and business domains (/understand-domain) into interactive knowledge graphs. But a huge part of how a product actually works lives in Figma — screens, component libraries, design tokens, and (for many teams) written product/spec notes kept right inside the file. Today that knowledge is invisible to the tool, so the picture of a product stops at the code boundary./understand-figmaextends the same "analyze anything → navigable graph" idea to Figma so a newcomer can see how a product's screens, design system, and components fit together — the design-side analogue of the architecture graph/understandbuilds for code.Why it's needed (use cases):
This PR delivers the foundation only (see Scope below); the higher-value capabilities are designed for but intentionally deferred so this lands as a reviewable, self-contained unit.
What it does
/understand-figma <figma-url-or-key>:uses_tokenlinks),design-analyzeragent to add summaries / tags / screen-purpose,knowledge-graph.jsonthe rest of the tool uses, taggedkind:"design",How it's used
Prereqs: Node ≥ 22, pnpm ≥ 10, and a Figma personal access token in the environment.
Re-running is incremental: if the Figma file
versionis unchanged it printsUP_TO_DATEand skips.Design & architecture (how it fits the codebase)
Mirrors the existing "new analysis mode" pattern (
/understand-knowledge,/understand-domain): deterministic structural parsing lives in core, the LLM does semantics, and the same schema / persistence / dashboard are reused.packages/core/src/figma/(Node-only) —source/(FigmaSourceadapter seam +FigmaApiSource),parse/(parse-document,tokens),merge.ts, barrelindex.ts; thedesign-analyzeragent; the/understand-figmaskill +figma-scan.mjs/figma-merge.mjs.FigmaSourceinterface, so an offline local-JSON source can be added later with no rework — and it is deliberately kept out of the dashboard's browser-safe subpath exports./understand-dashboardauto-launch.Schema additions (additive, backward-compatible)
page,screen,component,componentSet,instance,token.instance_of,variant_of,uses_token(instance_ofpromoted from an alias to a first-class edge).FigmaMeta(passthrough, alongsidedomainMeta/knowledgeMeta):fileKey,nodeId,thumbnailUrl,dimensions,tokenKind, plus forward-lookingprototypeTargets/componentKey(recorded now so the deferred flow/code-mapping work needs no re-parse).kind:"design"added to the graph union. Existing graphs (nokind→codebase) are unaffected.Verification
pnpm --filter @understand-anything/core test→ 760 passing (incl. new figma suites:api-source,parse-document,tokens,merge, + a schema regression test).pnpm --filter @understand-anything/dashboard test→ 47 passing (incl. a guard test that fails if a design node type is ever dropped from the dashboard's visible-types set).pnpm --filter @understand-anything/core buildandpnpm --filter @understand-anything/dashboard build→ green.pnpm lint(eslint .) → clean.figma-scan.mjsfails fast with a friendly error whenFIGMA_TOKENis unset; a test asserts the token never appears in error output./understand-figma <url>against a real Figma file (needs a token) — recommended as the reviewer's acceptance check.Implemented test-first (TDD) and reviewed task-by-task. The review process caught and fixed three real issues, called out for transparency:
componentSet(the only camelCase node type) was being dropped by the schema's lowercasing sanitizer → added acomponentset → componentSetnormalization alias + regression test.page → articlealias would have rewritten designpagenodes → removed (knowledge agents emitarticledirectly).allVisibleTypes) → fixed and locked with the guard test above.Security
FIGMA_TOKENis read from the environment only; it travels solely in theX-Figma-Tokenheader and is never written to the graph,meta.json, logs, or intermediate files.api.figma.com— a departure from the otherwise fully-offline pipeline. This is documented in the skill and surfaced to the user.Scope & roadmap
This PR is the foundation (ingestion + structure + light design-system model). Deferred to their own spec → plan → PR cycles (designed for, not built here):
navigates_to+ flow view)figmaMeta.componentKey↔ the code graph)claim/entitynodes)Docs
docs/superpowers/specs/2026-06-24-understand-figma-foundation-design.md(+ Korean…-design.ko.md)docs/superpowers/plans/2026-06-24-understand-figma-foundation.mdNotes for reviewers