Skip to content

feat: /understand-figma — Figma design knowledge graph (foundation)#516

Open
smjeong84 wants to merge 23 commits into
Egonex-AI:mainfrom
smjeong84:feat/understand-figma-foundation
Open

feat: /understand-figma — Figma design knowledge graph (foundation)#516
smjeong84 wants to merge 23 commits into
Egonex-AI:mainfrom
smjeong84:feat/understand-figma-foundation

Conversation

@smjeong84

Copy link
Copy Markdown
Contributor

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-figma extends 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 /understand builds for code.

Why it's needed (use cases):

  • Onboarding — a new designer/PM/engineer explores the product's screens + design system as a graph instead of scrolling an unfamiliar Figma file.
  • Design-system insight — see components, their variants (component sets), and which design tokens each one uses.
  • A foundation for bigger wins (deferred to follow-ups): user-flow graphs from prototype links, design ↔ code mapping, design-system audits (detached instances / inconsistencies), and analysis of product specs written inside Figma.

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>:

  1. fetches the Figma document via the REST API,
  2. deterministically parses it into a structural graph (pages → screens → components / component sets / instances) plus a light design-system model (design tokens + uses_token links),
  3. runs an LLM design-analyzer agent to add summaries / tags / screen-purpose,
  4. assembles the same knowledge-graph.json the rest of the tool uses, tagged kind:"design",
  5. auto-opens the existing dashboard, which renders the design graph (per-page + "Design System" layers, design-system-first tour) with a thumbnail preview of the selected screen in the sidebar.

How it's used

Prereqs: Node ≥ 22, pnpm ≥ 10, and a Figma personal access token in the environment.

export FIGMA_TOKEN=<your token>        # create at https://www.figma.com/settings
/understand-figma https://www.figma.com/file/<KEY>/<name>
# bare key:           /understand-figma <KEY>
# scope to one page:  /understand-figma <KEY> --page "Onboarding"
# localized output:   /understand-figma <KEY> --language ko
# force re-analyze:    UNDERSTAND_FIGMA_FORCE=1 /understand-figma <KEY>

Re-running is incremental: if the Figma file version is unchanged it prints UP_TO_DATE and 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.

  • New, isolated: packages/core/src/figma/ (Node-only) — source/ (FigmaSource adapter seam + FigmaApiSource), parse/ (parse-document, tokens), merge.ts, barrel index.ts; the design-analyzer agent; the /understand-figma skill + figma-scan.mjs / figma-merge.mjs.
  • The Figma API client sits behind a FigmaSource interface, 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.
  • Reused: schema/validation, persistence, the dashboard framework, the subagent + intermediate-file orchestration, and /understand-dashboard auto-launch.

Schema additions (additive, backward-compatible)

  • NodeTypes (+6): page, screen, component, componentSet, instance, token.
  • EdgeTypes (+3): instance_of, variant_of, uses_token (instance_of promoted from an alias to a first-class edge).
  • FigmaMeta (passthrough, alongside domainMeta / knowledgeMeta): fileKey, nodeId, thumbnailUrl, dimensions, tokenKind, plus forward-looking prototypeTargets / componentKey (recorded now so the deferred flow/code-mapping work needs no re-parse).
  • kind:"design" added to the graph union. Existing graphs (no kindcodebase) are unaffected.

Verification

  • pnpm --filter @understand-anything/core test760 passing (incl. new figma suites: api-source, parse-document, tokens, merge, + a schema regression test).
  • pnpm --filter @understand-anything/dashboard test47 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 build and pnpm --filter @understand-anything/dashboard buildgreen.
  • pnpm lint (eslint .) → clean.
  • Offline safety: figma-scan.mjs fails fast with a friendly error when FIGMA_TOKEN is unset; a test asserts the token never appears in error output.
  • Not yet run here: a live end-to-end /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 a componentset → componentSet normalization alias + regression test.
  • A pre-existing page → article alias would have rewritten design page nodes → removed (knowledge agents emit article directly).
  • The dashboard's drill-in canvas filtered out design nodes (they weren't in allVisibleTypes) → fixed and locked with the guard test above.

Security

  • FIGMA_TOKEN is read from the environment only; it travels solely in the X-Figma-Token header and is never written to the graph, meta.json, logs, or intermediate files.
  • This mode makes an outbound call to 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):

  • B — user flows (prototype links → navigates_to + flow view)
  • C — design ↔ code mapping (figmaMeta.componentKey ↔ the code graph)
  • D — design-system audit (reuse rate, detached instances, inconsistencies)
  • E — analysis of product/spec text written inside Figma (→ claim/entity nodes)

Docs

  • Design spec: docs/superpowers/specs/2026-06-24-understand-figma-foundation-design.md (+ Korean …-design.ko.md)
  • Implementation plan (15 TDD tasks): docs/superpowers/plans/2026-06-24-understand-figma-foundation.md

Notes for reviewers

  • 17 commits, conventional-commit style, each task committed separately for easy review.
  • Built/verified locally on Node v20 (repo targets ≥ 22); all builds/tests/lint green regardless, but please run the live e2e on ≥ 22 with a real token.
  • A dedicated "design" dashboard view + legend category was intentionally deferred; v1 reuses the structural hierarchical view (design nodes group under the existing "code" filter and render via that view).

gruming added 20 commits June 24, 2026 16:03
…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.
@Lum1104

Lum1104 commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

@codex review this

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +25 to +27
if (doc.version && prevVersion === doc.version && process.env.UNDERSTAND_FIGMA_FORCE !== "1") {
console.error("UP_TO_DATE");
process.exit(0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines +42 to +44
function walk(n: FigmaNode) {
const consumerId = graphIdByFigmaId.get(n.id);
if (consumerId && n.styles) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines +78 to +80
// 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",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@smjeong84 smjeong84 force-pushed the feat/understand-figma-foundation branch from c1f7544 to 8d83812 Compare July 8, 2026 04:12
gruming added 3 commits July 8, 2026 13:26
…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.
@Lum1104

Lum1104 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Hi @smjeong84 and @gruming , thanks for this PR, I'll take a deeper look at this weekend. Really appreciate it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants