Rust-native MCP server that reads Figma designs and generates DevupUI artifacts. One binary acts as a local stdio MCP server and a read-only client of Figma Remote MCP.
์ ์ฅ์๋ Cargo workspace์ด๋ฉฐ devup-mcp ์คํ crate, OAuthยทupstreamยทsnapshot์ ๋ด๋นํ๋ devup-mcp-figma, TSXยทtheme projection์ ๋ด๋นํ๋ devup-mcp-devup-ui, PNG ๋น๊ต library/CLI์ธ devup-mcp-visual๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. ๋ณ๋ IR/auth/server crate ์์ด MCP ์ ํ ์ค์น ๋จ์๋ devup-mcp ํ๋์
๋๋ค.
Figma ์ชฝ 4๊ฐ, ํ๋ก์ ํธ ์ชฝ 5๊ฐ, ์คํฌ 1๊ฐ, ๋ชจ๋ 10๊ฐ์ ๋๋ค.
devup_figma_export: Figma๋ฅผ ํ ๋ฒ ์์งํด ์์ฒญํoutputs๋ง ํฌ์ํฉ๋๋ค. TSX๊ฐ ์ฐ์ถ๋ฌผ์ด๊ณ ,componentTsxยทresponsiveTsxยทdevup.jsonยทsource mapยทasset manifestยทreference PNG๋ฅผ ๊ฐ์ ์์ง์์ ํจ๊ป ์ป๊ฑฐ๋,cache.artifactId๋ก ์ฌ์์ง ์์ด ์ถ๊ฐ ํฌ์ํ ์ ์์ต๋๋ค. raw snapshotยทraw payload๋ ๊ตฌํ์ด ์๋๋ผ ์ง๋จ์ ์ฐ๋ ๊ฒ์ด๋ผdebug: true๋ก๋ง ์ด๋ฆฝ๋๋ค.devup_figma_search: page, section, frame, component๋ฅผ ์ด๋ฆ์ผ๋ก ํ์. URL์node-id๊ฐ ์์ผ๋ฉด ๊ทธ ๋ ธ๋์ ๊ทธ ์๋๋ก ๋ฒ์๋ฅผ ์ขํ๊ณ , ์์ผ๋ฉด ํ์ผ ์ ์ฒด๋ฅผ ๊ฒ์ํฉ๋๋ค. ๋ ์ค ๋ฌด์์ ํ๋์ง๋ ์๋ต์scope๊ฐ ์๋ ค์ค๋๋คdevup_figma_explore: ๋งํฌ๋ ์๊ตฌ์ฌํญ/๋ผ๋ฒจ ์ฃผ๋ณ์ ์ค์ ํ๋ฉด ํ๋ณด๋ฅผ ๊ณต๊ฐ ์์๋ก ํ์devup_figma_auth: ์ฐ๊ฒฐ ์ํ ํ์ธ, ๋ธ๋ผ์ฐ์ OAuth ๋ก๊ทธ์ธ, ๋ก๊ทธ์์, ์ฌ์ ๋ฑ๋ก ์๊ฒฉ์ฆ๋ช ์ฃผ์ (configure), ์ฐ๊ฒฐ ์คํจ ์์ธ์ ์ค์ธกํด ๋ณด๊ณ ํ๋doctordevup_skills: devup-mcp๊ฐ ๋ด๋๋ ์ฝ๋์ ํ์ํ ์์ด์ ํธ ์คํฌ์ด ์ด ์ํฌ์คํ์ด์ค์ ์๋์ง ๋ณด๊ณ (status)ํ๊ณ , devup-mcp๊ฐ ํ๊ณ ์๋ ๊ฒ์ ์ค์น(install). ํ ์คํธ๋ฅผ ์๋ต์ ์ค์ด ๋ณด๋ด๋ ๊ฒ ์๋๋ผ ์คํฌ ๋๋ ํฐ๋ฆฌ์ ์ค์นํด์ ์์ด์ ํธ ์์ ์ ๋ก๋๊ฐ ์ฝ๊ฒ ํฉ๋๋ค โ ํ ๋ฒ ์ฝ์ ๋ฌธ์๋ ํ ๋ฒ ์ฐ์ด์ง๋ง, ์ค์น๋ ์คํฌ์ ์ดํ ๋ชจ๋ ์ธ์ ์ ๊ณ์ ์ ์ฉ๋ฉ๋๋คdevup_project_context: ํ๋ก์ ํธ์ ์ค์ devup.jsonํ ํฐ,openapi.json์๋ํฌ์ธํธ, Vespertide ๋ชจ๋ธ์ ์ฝ์. ์ค์ฒฉ ์ฒดํฌ์์๊ณผ ๋น๋ ์ฐ์ถ๋ฌผ ๋๋ ํฐ๋ฆฌ๋ ์ค์บ์์ ์ ์ธํ๊ณ ๋ฌด์์ ์ ์ธํ๋์ง ๋ณด๊ณdevup_ui_validate: ์์ฑํ TSX๋ฅผ ํ๋ก์ ํธ์ ์ค์ devup.json์ ๋์กฐํด ๊ฒ์ฆ.ok๋ ๊ฐ์๊ฐ ์๋๋ผ ์ฌ๊ฐ๋๋ก ํ์ devup_stack_diff: DB ๋ชจ๋ธ๋ถํฐ ์์ฑ๋ API ํด๋ผ์ด์ธํธ๊น์ง์ ์ธต๊ฐ ๋๋ฆฌํํธ ํ์ง. ๋ชจ๋ ๋ฐ๊ฒฌ์ ๋ช ์์ confidence๋ฅผ ๊ฐ์งdevup_visual_compare: ์๋น์๊ฐ ๋ง๋actual.png๋ฅผ reference PNG ํ๋์ ๋น๊ต. ์ค์ค๋ก ๋ ๋ํ์ง ์๊ณ ๋ธ๋ผ์ฐ์ ๋ฅผ ๋์ฐ์ง๋ ๋ช ๋ น์ ์คํํ์ง๋ ์์ต๋๋ค โ ๊ฒฝ๋ก๋ allowlist ์์ด์ด์ผ ํฉ๋๋ค. ๊ธฐ๋ณธ threshold๋ 0.005(0.5%). renderer ํ๊ฒฝ manifest๊ฐ ์๊ฑฐ๋ ๋ถ์์ ํ๊ฑฐ๋ ์ ํจํ์ง ์์ผ๋ฉดvisual.passed๊ฐ true์ฌ๋ ํ์ ์inconclusive์ ๋๋คdevup_feature_trace: ๋ช ์์ anchor(routePath,figmaNodeId/artifactId,operationId๋๋apiPath+method,componentPath,tableName)์์ ์ถ๋ฐํด ํ๋ฉดโAPIโ๋ผ์ฐํธโ๋ชจ๋ธโ์ปฌ๋ผ ์ฌ๋ผ์ด์ค์ acceptance matrix๋ฅผ ์ฝ์ด๋. ์๊ตฌ์ฌํญ ์ฐ๋ฌธ๋ง ์ฃผ๋ฉด ๊ฑฐ์ ํฉ๋๋ค. ๊ฐ hop์ ๊ทผ๊ฑฐ๊ฐ ์๊ฑฐ๋UNVERIFIED๋ก ํ์๋๊ณ , ์์ฑ ์ฐ์ถ๋ฌผ ์์ ๊ถยทUI ์ฌ์ฌ์ฉ ์์ยท์๋ฆผ ์ํ์ ํจ๊ป ๋ณด๊ณ ํฉ๋๋ค
devup_figma_to_ui์ devup_figma_to_json์ ๊ฐ๊ฐ devup_figma_export์ outputs: ["tsx"], outputs: ["devupJson"]์ ๋๊ธด ๊ฒ๊ณผ ๊ฐ์์ ์ ๊ฑฐํ์ต๋๋ค. ๋๊ตฌ๊ฐ ์
์ด๋ฉด ๋ชจ๋ ํด๋ผ์ด์ธํธ๊ฐ ์ธ ๊ฐ์ ์คํค๋ง๋ฅผ ์ปจํ
์คํธ์ ์ฃ๊ณ ๋ ์ด๋ ๊ฒ์ ๋ถ๋ฅผ์ง ๋งค๋ฒ ํ๋จํด์ผ ํ์ต๋๋ค.
devup-mcp๋ Figma Plugin API์ readable data property๋ฅผ raw JSON์ผ๋ก ๋ณด์กดํ๊ณ , ์๋ ค์ง์ง ์์ runtime field๋ extra, ์คํจํ getter๋ fieldErrors๋ก ์ ์งํฉ๋๋ค.
devup_figma_export๋ ์์ฒญํ outputs๊ฐ ๋ง๋๋ ํค๋ง ์ถ๊ฐํฉ๋๋ค. outputs๋ฅผ ์๋ตํ์ ๋์ ์คํค๋ง ๊ธฐ๋ณธ๊ฐ์ ["tsx"] ํ๋๋ฟ์ด๋ฉฐ, ์๋ ํ๋ ๋ฌด์์ ๋ ์์ฒญํ ์ ์๋์ง์ ๋ํ ๋ ํผ๋ฐ์ค์ด์ง ํ ๋ฒ์ ์ ๋ถ ์์ฒญํ๋ผ๋ ๋ชฉ๋ก์ด ์๋๋๋ค.
devupJson์ ๊ธฐ๋ณธ๊ฐ์์ ๋น ์ก์ต๋๋ค. ํ๋ก์ ํธ์ ์ด๋ฏธ devup.json์ด ์์ผ๋ฉด ์ฝ๋๊ฐ ๋ง์ถฐ์ผ ํ ๋์์ ๊ทธ ํ์ผ์ด์ง Figma์์ ์๋ก ๋ฝ์ ์ด๋ฆ ์งํฉ์ด ์๋๊ณ , ๊ทธ ํ์ผ์ ์ฝ๋ ๋๊ตฌ๋ devup_project_context์
๋๋ค. devupJson์ ํ๋ก์ ํธ์ ์์ง devup.json์ด ์๊ฑฐ๋, ๊ทธ ํ์ผ์ด ์ ์ํ์ง ์์ ํ ํฐ์ ์๋ก ๋ค์ผ ๋๋ง ํจ๊ป ์์ฒญํ์ธ์.
| output | ์ถ๊ฐ๋๋ ํค |
|---|---|
tsx |
tsx |
componentTsx |
componentTsx |
responsiveTsx |
responsiveTsx, responsiveSlots, (ํํ ๋ถ๊ฐํ ๊ฐ์ด ์์ผ๋ฉด) responsiveUnrepresented |
devupJson |
devupJson, themeCounts, themeCompleteness, conflicts, unresolvedVariables |
sourceMap / assetManifest / referencePng |
๊ฐ์ ์ด๋ฆ์ ํค |
rawSnapshot / rawPayload |
๊ฐ์ ์ด๋ฆ์ ํค โ debug: true ํ์ |
๊ทธ ๋ฐ์ ํญ์ ๋ถ๋ ๊ฒ์ status, quality, completeness, cache, collection, source, targetKind, failures, assetSummary, outputPaths๋ฟ์
๋๋ค.
์กฐ๊ฑด์ด ๋ง์ ๋๋ง ๋ถ๋ ํค๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
| ํค | ๋์ค๋ ์กฐ๊ฑด |
|---|---|
fidelity / completenessReport |
๊ฒฐ๊ณผ๊ฐ exact/complete๊ฐ ์๋ ๋, ๋๋ includeDiagnostics: true์ผ ๋ |
deliverable |
status๊ฐ complete์ด๊ณ TSX๋ฅผ ๋ง๋ค์์ ๋ |
warnings |
์จ๊น ๋ ธ๋์ฒ๋ผ ์คํจ๊ฐ ์๋ ์์ฐ ๋ฌธ์ ๊ฐ ์์ ๋ |
frames |
Section์์ ์ฌ๋ฌ ํ๋ฉด์ ํ ๋ฒ์ exportํ์ ๋ |
selection / nextAction |
status๊ฐ selection_required์ผ ๋ |
fidelity์ completenessReport๋ฅผ ๊ธฐ๋ณธ์์ ๋บ ์ด์ ๋ ๊นจ๋ํ ๊ฒฐ๊ณผ์์ quality๊ฐ ์ด๋ฏธ ํ ๋ง์ ๋ํ์ดํ ๋ฟ์ด๊ธฐ ๋๋ฌธ์ด๊ณ , ๊ทธ๋งํผ(์ธก์ ๊ฐ 797 B) ๋งค ์๋ต์ด ๊ฐ๋ฒผ์์ง๋๋ค.
์์ฐ์ ์๋ ๊ฒ๊ณผ ๋ชป ๋ฐ์ ๊ฒ์ด ์ ํ ๋ค๋ฅธ ์ํฉ์ธ๋ฐ ์์ ์๋ ๋ ๋ค ๋น ๋ชฉ๋ก์ผ๋ก ๋ณด์์ต๋๋ค. ์ง๊ธ์ assetSummary๊ฐ ๊ตฌ๋ถํด ์ค๋๋ค.
status:none(์์ฐ์ด ์๋ค) ยทunknown(์ค๋ ์ท์ด ๋ถ์์ ํด ํ๋จ ๋ถ๊ฐ) ยทnot-collectedยทpartialยทcollecteddiscovery:complete|incomplete,discoveryReason:index-only|snapshot-incompletediscoveredCount/collectedCount/manifestIncludedunavailable[]: ํญ๋ชฉ๋ง๋คassetId,nodeId,errorCode์reasonโhidden-node(์จ๊น ๋ ธ๋) ยทexport-failed(export ์คํจ) ยทnot-requested(์ ์ด์ ์์ฒญํ์ง ์์) ยทcapture-not-in-artifact(์์ฒญํ์ง๋ง ์ด artifact์ ๊ทธ format/scale์ด ์์)
์จ๊น ๋
ธ๋ ์คํจ๋ failures[]๊ฐ ์๋๋ผ warnings[]๋ก ๊ฐ๋๋ค. ๊ตฌํ์ ๋ง๋ ์คํจ๊ฐ ์๋๊ธฐ ๋๋ฌธ์
๋๋ค.
rawSnapshot๊ณผ rawPayload๋ ์์งํ ๋์์ธ์ raw๋ก ๋ด์ ๊ฒ์ด๋ผ debug: true ์์ด๋ ๊ฑฐ์ ๋ฉ๋๋ค. ํ๋ฉด์ ๊ตฌํํ๋ ๋ฐ๋ ํ์ ์์ต๋๋ค โ ์ค์ ์บก์ฒ 10๊ฐ ํ๋ฉด์์ tsx๊ฐ nodeยทtextยทtypographyยทassetยทlayout ๊ธฐ๋์น๋ฅผ 100% ๋ด๊ณ ์์ต๋๋ค. ์ฐ๋ ์๋ฆฌ๋ ํ๋์
๋๋ค: ํ๋ฉด์ด ์ด์ํด ๋ณด์ผ ๋ ์์ฑ๊ธฐ ํ์ธ์ง ๋์์ธ์ด ์๋ ๊ทธ๋ฐ์ง ํ์ ํ๋ ๊ฒ. ๊ทธ๋๋ ๋์์ธ์ ์ฝ๋ ์์ ๋๊ณ ์ฝ์ด์ผ ํ๊ณ , ๊ทธ๊ฒ ์ด ํ๋๊ทธ์
๋๋ค.
์๋ฌ๋ ํธ์ถ ์์ฒด๊ฐ ์๋ชป๋ ๊ฒฝ์ฐ(DEVUP_INVALID_INPUT, ์๋ node/ํ์ผ, ๋ง๋ฃยท๋ถ์ ํฉํ artifactId ๋ฑ) JSON-RPC -32602 INVALID_PARAMS๋ก, ๊ทธ ๋ฐ์ ์คํจ๋ -32603 INTERNAL_ERROR๋ก ์ต๋๋ค. ์ธ์๋ฅผ ๊ณ ์ณ ๋ค์ ๋ถ๋ฅผ ์ผ์ธ์ง ๋ฉ์ถ๊ณ ๋ณด๊ณ ํ ์ผ์ธ์ง๋ฅผ ๋ฉ์์ง๋ฅผ ํ์ฑํ์ง ์๊ณ ๊ตฌ๋ถํ ์ ์์ต๋๋ค. ์ ํํ code์ retryable์ ์์ ์ฒ๋ผ data์ ๊ทธ๋๋ก ์ค๋ฆฝ๋๋ค.
devup-mcp๋ Figma Remote MCP์ ์ง์ ๋ถ์ต๋๋ค โ OAuth discovery, Dynamic Client Registration, PKCE S256, ์ผ์์ ์ธ 127.0.0.1 callback์ ๊ตฌํํฉ๋๋ค. Figma๋ MCP Catalog์ ์น์ธ๋ client์ registration๋ง ํ์ฉํ๋ฏ๋ก ๋ฑ๋ก์ allowlist์ ์๋ client_name์ผ๋ก ์ด๋ฃจ์ด์ง๋๋ค(๊ธฐ๋ณธ๊ฐ Codex). Figma PAT๋ ์ฌ์ฉ์๊ฐ ๋ง๋ OAuth app์ ํ์ํ์ง ์์ต๋๋ค.
๋ฆด๋ฆฌ์ค๋ง๋ค devup-mcp-<version>.mcpb ํ์ผ ํ๋๊ฐ ํจ๊ป ์ฌ๋ผ๊ฐ๋๋ค. ์ด ํ๋์ Linux x86_64, Windows x86_64, macOS universal ๋ฐ์ด๋๋ฆฌ๊ฐ ๋ชจ๋ ๋ค์ด ์๊ณ , manifest.json์ server.mcp_config.platform_overrides๊ฐ ์คํ ์์ ์ ํธ์คํธ์ ์ด์์ฒด์ ์ ๋ง๋ ๋ฐ์ด๋๋ฆฌ๋ฅผ ๊ณ ๋ฆ
๋๋ค. ์ด์์ฒด์ ๋ณ๋ก ์ด๋ค ํ์ผ์ ๋ฐ์์ผ ํ๋์ง ๊ณ ๋ฅผ ํ์๊ฐ ์๊ณ , Rust ํด์ฒด์ธ๋ Node ๋ฐํ์๋ cargo install๋ ํ์ํ์ง ์์ต๋๋ค.
- Releases์์
devup-mcp-<version>.mcpb๋ฅผ ๋ฐ์ต๋๋ค. .mcpb๋ฅผ ์ง์ํ๋ ํธ์คํธ(์: Claude for macOS/Windows)์์ ํ์ผ์ ์ฝ๋๋ค.- ์ค์น ๋ํ์์์ Workspace directory์ ์ฝ๋๋ฅผ ์์ฑํ ํ๋ก์ ํธ ๋๋ ํฐ๋ฆฌ๋ฅผ ์ง์ ํฉ๋๋ค. ์ด ๋๋ ํฐ๋ฆฌ๊ฐ devup-mcp๊ฐ ํ์ผ์ ์ธ ์ ์๋ ์ ์ผํ ์์น์ด๋ฉฐ,
..ยท๋ค๋ฅธ driveยทsymlink๋ก ๊ทธ ๋ฐ์ ๊ฐ๋ฆฌํค๋ ๊ฒฝ๋ก๋ ๊ธฐ๋ก ์ ์ ๊ฑฐ์ ๋ฉ๋๋ค. ์ฌ๋ฌ root๊ฐ ํ์ํ๋ฉด ์๋ stdio ์ค์ ์ผ๋ก--allow-write-root๋ฅผ ๋ฐ๋ณตํด ๋ฑ๋กํ์ธ์.
.mcpb๋ ๊ทธ๋ฅ zip์ด๋ฏ๋ก unzip -l๋ก ๋ด์ฉ์ ํ์ธํ ์ ์๊ณ , ์์ ๋ฐ์ด๋๋ฆฌ๋ ๊ฐ์ ๋ฆด๋ฆฌ์ค์ ๋ฐ๋ก ์ฌ๋ผ๊ฐ๋ ๊ฒ๊ณผ ๊ฐ์ ํ์ผ์
๋๋ค. CI๋ pack ์งํ ์์นด์ด๋ธ๋ฅผ ๋ค์ ์ฝ์ด Unix ๋ฐ์ด๋๋ฆฌ์ ์คํ ๋นํธ๊ฐ ๋จ์ ์๋์ง ํ์ธํ๊ณ , ์์ผ๋ฉด ๋ฆด๋ฆฌ์ค๋ฅผ ๊ฒ์ํ์ง ์์ต๋๋ค. ๊ทธ๋ผ์๋ macOS์์ ์ค์น ์งํ ์๋ฒ๊ฐ EACCES๋ก ์คํจํ๋ค๋ฉด ํธ์คํธ๊ฐ ์์ถ์ ํ๋ฉด์ ๊ถํ์ ์ง์ด ๊ฒฝ์ฐ์ด๋ฉฐ(mcpb#294), ๊ทธ๋๋ ๊ฐ์ ๋ฆด๋ฆฌ์ค์ devup-mcp-macos-universal ๋ฐ์ด๋๋ฆฌ๋ฅผ ์ง์ ๋ฐ์ ์๋ stdio ์ค์ ์ผ๋ก ๋ฑ๋กํ๋ฉด ๋ฉ๋๋ค.
Rust 1.98 ์ด์์ด ํ์ํฉ๋๋ค. compile-in Figma ํ์ ํ๋ fixture๋ฅผ ์ง์ ์คํํ๋ ค๋ฉด CI์ ๋์ผํ Node.js 24๊ฐ ํ์ํ๋ฉฐ ์ ํ binary์๋ Node๊ฐ ํ์ํ์ง ์์ต๋๋ค.
cargo install --git https://github.com/dev-five-git/devup-mcp.git --branch owjs3901/figma-remote-mcp devup-mcp์ค์น ๋๋ binary ๊ต์ฒด ํ์๋ ๋จผ์ ๋ก์ปฌ ์ง๋จ์ ์คํํฉ๋๋ค.
devup-mcp --version
devup-mcp --self-check--version์ package version๊ณผ build ID๋ฅผ, --self-check๋ network/OAuth ์์ด binary,
credential backend ์ด๊ธฐํ์ server ๊ตฌ์ฑ์ ์์ ํ JSON์ผ๋ก ํ์ธํฉ๋๋ค. ๋ ๋ค ์ฑ๊ณตํ์ง๋ง
๋ฑ๋ก๋ connector๊ฐ Transport closed๋ฅผ ๋ฐํํ๋ฉด MCP host๊ฐ ๊ต์ฒด ์ process์ ์ข
๋ฃ๋
stdio pipe๋ฅผ ๋ณด์ ํ ์ํ์ด๋ฏ๋ก host์ MCP ์ฐ๊ฒฐ์ ์ฌ์์ํ๊ฑฐ๋ ๋ค์ ๋ฑ๋กํด์ผ ํฉ๋๋ค.
์๋ก ์คํ๋ server๊ฐ host๊ฐ ๋ณด์ ํ ์ด์ pipe๋ฅผ ์ค์ค๋ก ๋ณต๊ตฌํ ์๋ ์์ต๋๋ค.
์๋ฒ ์์ ์ OAuth ์ค๋น๊ฐ ์คํจํ๋ฉด ํ๋ก์ธ์ค๊ฐ ์ฃฝ์ง ์๊ณ ์ง๋จ ๊ฐ๋ฅํ ์ค๋ฅ๋ก ๋์ต๋๋ค. HTTP ํด๋ผ์ด์ธํธ ์ด๊ธฐํ๊ฐ ์คํจํ๋ฉด DEVUP_FIGMA_DIRECT_UNAVAILABLE๋ก Cannot start Figma OAuth: HTTP client initialization failed. Check TLS configuration and system certificate initialization, then restart devup-mcp.์ ํจ๊ป ์์ธ ์ฒด์ธ์ ๋ถ์ฌ ๋๋ ค์ค๋๋ค. endpoint URL์ด ์๋ชป๋์ผ๋ฉด DEVUP_INVALID_INPUT์
๋๋ค. ์์ ์๋ ์ด ๊ฒฝ๋ก๊ฐ panic์ด๋ผ ๋ฌด์์ด ์๋ชป๋๋์ง ์ ์ ์์์ต๋๋ค โ TLS๋ ์์คํ
์ธ์ฆ์ ์ค์ ์ ๋จผ์ ํ์ธํ์ธ์.
์์ค์์ ๊ฒ์ฆํ๋ ค๋ฉด ๋ค์์ ์คํํฉ๋๋ค.
cargo fmt --all -- --check
node --test crates/devup-mcp-figma/tests/explore_script_behavior.mjs
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-features
cargo test -p devup-mcp --test stdio_smoke
cargo insta test --workspace --all-features --check
cargo build --workspace --releasestdio MCP๋ฅผ ์ง์ํ๋ ํด๋ผ์ด์ธํธ์ ๋ค์๊ณผ ๊ฐ์ด ๋ฑ๋กํฉ๋๋ค.
{
"mcpServers": {
"devup-mcp": {
"command": "devup-mcp",
"args": ["--allow-write-root", "/absolute/path/to/workspace"]
}
}
}์์คํ
๋ธ๋ผ์ฐ์ ๋ devup_figma_auth์ login์ ๋ช
์์ ์ผ๋ก ํธ์ถํ ๋๋ง ์ด๋ฆฝ๋๋ค. ๋ณํ ๋๊ตฌ๋ ์๊ฒฉ์ฆ๋ช
์ด ์์ผ๋ฉด ๋ธ๋ผ์ฐ์ ๋ฅผ ์ด์ง ์๊ณ ๋ก๊ทธ์ธ์ด ํ์ํ๋ค๋ ์ค๋ฅ๋ฅผ ๋ฐํํฉ๋๋ค. ์ธ์ฆ ์ ๋ณด๋ ์ด์์ฒด์ credential store์๋ง ์ ์ฅ๋๋ฉฐ logout์ ํด๋น ์ ๋ณด๋ง ์ญ์ ํฉ๋๋ค.
{ "action": "status" }action์ status, login, logout, configure, doctor ์ค ํ๋์ด๋ฉฐ, ์คํค๋ง๊ฐ ์ด ๋ชฉ๋ก์ ๊ทธ๋๋ก ๊ฒ์ํฉ๋๋ค. status/login/logout์ ์๋ต ํํ๋ ํญ์ { "status": "connected" | "disconnected" }์
๋๋ค. Figma์ ๋ถ์ง ๋ชปํ๋ ์ด์ ๋ฅผ ์๊ณ ์ถ์ผ๋ฉด doctor๋ฅผ ํธ์ถํ์ธ์.
{ "action": "doctor" }{
"status": "disconnected",
"preferredPath": "bridge",
"preferredPathNote": "Two paths reach Figma and they are not equals. ...",
"paths": {
"bridge": {
"available": false,
"listening": true,
"port": 1993,
"attachedFiles": [],
"attachedFilesNote": "File keys the attached plugins have open. ...",
"reason": "The bridge is listening on 127.0.0.1:1993 but no plugin is attached. ..."
},
"direct": {
"available": false,
"credentialSource": "none",
"credentialSourceNote": "Where the OAuth *client registration* credential came from ...",
"tokenState": "absent",
"callbackPort": { "port": null, "free": null },
"registrationClientName": { "value": "Codex", "isDefault": true },
"reason": "์ ์ฅ๋ ์๊ฒฉ์ฆ๋ช
์์. ..."
}
},
"clientSetup": { "constraints": { ... }, "opencode": { ... }, "claudeCode": "...", "codex": "..." }
}doctor๋ ๋คํธ์ํฌ ํธ์ถ์ ์ ํ ํ์ง ์์ต๋๋ค.
๊ฒฝ๋ก๋ ๋์ด๊ณ ๋๋ฑํ์ง ์์ต๋๋ค. preferredPath๊ฐ ์ธ์ ๋ bridge์ธ ์ด์ ์
๋๋ค โ ๋ธ๋ฆฌ์ง๋ ๋ก๊ทธ์ธ๋ ํ์ ์๊ณ Figma ํ๋๋ ์ฐ์ง ์์ต๋๋ค. paths.bridge์ ์ธ ์ํ๋ ๊ณ ์น๋ ๋ฐฉ๋ฒ์ด ์๋ก ๋ค๋ฅด๋ ๊ตฌ๋ถํด์ ์ฝ์ด์ผ ํฉ๋๋ค.
listening: falseโ ์ด ํ๋ก์ธ์ค๊ฐ ๋ธ๋ฆฌ์ง ํฌํธ๋ฅผ ์์ ์ก์ง ๋ชปํ์ต๋๋ค.DEVUP_FIGMA_BRIDGE_PORT๊ฐoff์ด๊ฑฐ๋, ๋ค๋ฅธ devup-mcp๊ฐ ์ด๋ฏธ ๊ทธ ํฌํธ๋ฅผ ์ฅ๊ณ ์๋ ๊ฒฝ์ฐ์ ๋๋ค(MCP ํด๋ผ์ด์ธํธ๋ฅผ ์ฌ๋ฌ ๊ฐ ๋์ฐ๋ฉด ์ ์์ ๋๋ค). ํ๋ฌ๊ทธ์ธ์ ์๋ฌด๋ฆฌ ์คํํด๋ ์ด ํ๋ก์ธ์ค๋ก๋ ์ค์ง ์์ต๋๋ค.listening: true,attachedFiles: []โ ๋ฌธ์ ์ด๋ ค ์๋๋ฐ ์๋ฌด๋ ๋ค์ด์ค์ง ์์์ต๋๋ค. ๋์ ํ์ผ์์Devup Bridgeํ๋ฌ๊ทธ์ธ์ ์คํํ์ธ์.attachedFiles์ ํ์ผ ํค๊ฐ ์์ โ ์ ์ ๋์์ ๋๋ค. ์ด ์ํ๋ฉด ๋ก๊ทธ์ธ ์์ด ๊ทธ ํ์ผ์ ์์ง์ด ๊ทธ๋๋ก ๋ฉ๋๋ค.
paths.direct์ ์ธ ํ๋๋ ์๋ก ๋ค๋ฅธ ๊ฒ์ ๋งํ๋ฏ๋ก ํจ๊ป ์ฝ์ด์ผ ํฉ๋๋ค.
credentialSourceโ client ๋ฑ๋ก ์๊ฒฉ์ฆ๋ช (client_id/client_secret)์ด ์ด๋์ ์๋์ง.cli-arg,env,credential-store,none์ค ํ๋์ ๋๋ค.tokenStateโ ์ฌ์ฉ์์ access token ์ํ.valid,expired,absent์ค ํ๋์ ๋๋ค.availableโ ์ง๊ธ direct ๊ฒฝ๋ก๋ฅผ ์ธ ์ ์๋์ง.
credentialSource: "none"์ "์ฌ์ ๋ฑ๋ก๋ client๊ฐ ์ฃผ์
๋์ง ์์๋ค"๋ ๋ป์ผ ๋ฟ์ด๋ฉฐ, ๊ทธ ๊ฒฝ์ฐ ๋ก๊ทธ์ธ์ registrationClientName์ ์ด๋ฆ์ผ๋ก ๋์ ๋ฑ๋กํฉ๋๋ค. ๊ทธ๋ ๊ฒ ๋ก๊ทธ์ธํ ์ ์ ์ธ์
์ credentialSource: "none"๊ณผ tokenState: "valid"๋ฅผ ๋์์ ๋ณด์
๋๋ค. ์์ ์๋ ์ด ์กฐํฉ์ด ๋ชจ์์ฒ๋ผ ๋ณด์๋๋ฐ, ์ง๊ธ์ credentialSourceNote๊ฐ ์๋ต ์์์ ์ง์ ์ค๋ช
ํฉ๋๋ค.
callbackPort๋ --figma-callback-port๋ฅผ ์ง์ ํ์ ๋๋ง ์ค์ธกํ port/free๋ฅผ ๋ด๊ณ , registrationClientName์ DCR์ด ๋ณด๋ผ ์ด๋ฆ(value)๊ณผ ๊ทธ๊ฒ์ด ๊ธฐ๋ณธ๊ฐ์ธ์ง(isDefault)๋ฅผ ์๋ ค์ค๋๋ค. ์์ธํ ์ ์ฝ์ ์๋ "Figma ์ฐ๊ฒฐ ์ค์ " ์ ์ ์ฐธ๊ณ ํ์ธ์.
Figma MCP Catalog์ ์น์ธ๋ client(์: ์ง์ waitlist๋ก ๋ฑ๋กํด ๋ฐ๊ธ๋ฐ์ client)์ client_id/client_secret์ ์ด๋ฏธ ๊ฐ์ง๊ณ ์๋ค๋ฉด, devup-mcp์ ๋ค์ ์ธ ๊ฐ์ง ๋ฐฉ๋ฒ ์ค ํ๋๋ก ์ฃผ์
ํด Dynamic Client Registration์ ์์ ํ ๊ฑด๋๋ธ ์ ์์ต๋๋ค. ์ฐ์ ์์๋ ์์ ์ธ์ > ํ๊ฒฝ๋ณ์ > configure๋ก ์ ์ฅํ ๊ฐ์
๋๋ค.
- ์์ ์ธ์:
devup-mcp --figma-client-id <id> --figma-client-secret <secret> - ํ๊ฒฝ๋ณ์:
DEVUP_FIGMA_CLIENT_ID,DEVUP_FIGMA_CLIENT_SECRET - ๋๊ตฌ:
devup_figma_auth { "action": "configure", "clientId": "...", "clientSecret": "..." }โ OS credential store(์์ ์ธ์/ํ๊ฒฝ๋ณ์์๋ ๋ณ๋ ํญ๋ชฉ)์ ์ ์ฅ๋์ด ํ๋ก์ธ์ค๋ฅผ ์ฌ์์ํด๋ ์ ์ง๋ฉ๋๋ค.
์๊ฒฉ์ฆ๋ช
์ด ํด์๋๋ฉด devup_figma_auth { "action": "login" }์ registration ์๋ํฌ์ธํธ๋ฅผ ์ ํ ํธ์ถํ์ง ์๊ณ ๋ฐ๋ก authorization_code + PKCE ํ๋ฆ์ผ๋ก ์ง์
ํฉ๋๋ค. ์๊ฒฉ์ฆ๋ช
์ด ์์ผ๋ฉด DCR์ ์๋ํ๊ณ , 403์ด๋ฉด ๊ทธ๋๋ก ๋ณด๊ณ ํฉ๋๋ค. DCR ์์ฒญ์ client_name ๊ธฐ๋ณธ๊ฐ์ "Codex"์
๋๋ค(DEFAULT_CLIENT_NAME). allowlist๋ ์ด๋ฆ์ ์ ํํ ์ผ์น์์ผ ํ์ ํ๊ณ "devup-mcp"๋ ๊ฑฐ๊ธฐ์ ์์ผ๋ฏ๋ก, ๊ทธ ์ด๋ฆ์ผ๋ก ๋ณด๋ด๋ฉด ๋ฑ๋ก์ด 403์ผ๋ก ๊ฑฐ์ ๋์ด direct ๊ฒฝ๋ก ์์ฒด๊ฐ ์ฑ๋ฆฝํ์ง ์์ต๋๋ค. ์ด ๋ฑ๋ก์ Figma์๊ฒ devup-mcp๊ฐ ์๋๋ผ Codex๋ก ๊ธฐ๋ก๋ฉ๋๋ค. ๋ณธ์ธ client๊ฐ ์นดํ๋ก๊ทธ์ ์น์ธ๋๋ฉด --figma-client-name ๋๋ DEVUP_FIGMA_CLIENT_NAME์ผ๋ก ๊ทธ ์ด๋ฆ์ ๋๊ธฐ์ธ์. client_secret์ ๋ก๊ทธ, ์๋ฌ, MCP ์๋ต, doctor ์ถ๋ ฅ ์ด๋์๋ ๋
ธ์ถ๋์ง ์์ผ๋ฉฐ doctor๋ credentialSource๋ก ์กด์ฌ ์ฌ๋ถ๋ง ๋ณด๊ณ ํฉ๋๋ค.
devup-mcp๊ฐ ๋๋ ค์ฃผ๋ TSX๋ devup-ui ์ฝ๋์
๋๋ค. devup-mcp๋ง ๊น๋ฆฐ ๊ธฐ๊ณ์ ์์ด์ ํธ๋ devup-ui๋ฅผ ๋ณธ ์ ์ด ์์ต๋๋ค โ @devup-ui/react ์ปดํฌ๋ํธ๊ฐ ๋น๋ ํ์ placeholder๋ผ๋ ๊ฒ๋, $token์ด devup.json์ ๊ฐ๋ฆฌํจ๋ค๋ ๊ฒ๋, ์คํ์ผ prop์ด ๋ฐ์ํ ๋ฐฐ์ด์ ๋ฐ๋๋ค๋ ๊ฒ๋ ๋ชจ๋ฆ
๋๋ค. ๊ทธ๋์ ์ง์ด๋
๋๋ค. ์ด ์๋ฒ๋ ๊ทธ ์ถ์ธก์ ๋ณผ ์๋ ๊ณ ์น ์๋ ์์ต๋๋ค.
์๋ต์ ๊ท์น์ ๋ถ์ฌ ๋ณด๋ด๋ ๊ฒ์ผ๋ก๋ ๋ถ์กฑํฉ๋๋ค. ์์ด์ ํธ ๋ฐํ์์๋ ์ด๋ฏธ SKILL.md๋ฅผ ์ฝ์ด ์๊ธฐ ํธ๋ฆฌ๊ฑฐ๋ก ๊บผ๋ด ์ฃผ๋ ๋ก๋๊ฐ ์๊ณ , ํ ๋ฒ ๋์ ธ์ค ๋ฌธ์๋ ํ ๋ฒ ์ฝํ์ง๋ง ์ค์น๋ ์คํฌ์ ๊ทธ ๋ค ๋ชจ๋ ์ธ์
์ ๊ณ์ ์ ์ฉ๋ฉ๋๋ค. ๊ทธ๋์ devup_skills๋ ํ
์คํธ๋ฅผ ๋์ง์ง ์๊ณ ์ค์น ์ฌ๋ถ๋ฅผ ๋ณด๊ณ ํ๊ณ ์ค์นํฉ๋๋ค.
{ "action": "status" }์คํฌ๋ง๋ค installed์, ์๋๋ผ๋ฉด ๊ทธ๊ฒ์ ๋ฉ์ฐ๋ ํ ๊ฐ์ง ๋์์ ๋๋ ค์ค๋๋ค. ์ถ์ฒ์ ๋ฐ๋ผ ๋์์ด ๋ค๋ฆ
๋๋ค.
| ์คํฌ | ์ถ์ฒ | devup-mcp๊ฐ ํ๋ ์ผ |
|---|---|---|
devup-ui ยท vespera ยท vespertide |
dev-five-git (์ฐ๋ฆฌ ๊ฒ) | ๋ฐ์ด๋๋ฆฌ์ ๋ด์ฅ. {"action":"install"}์ด ๋คํธ์ํฌ ์์ด ์คํฌ ๋๋ ํฐ๋ฆฌ์ ์๋๋ค |
vercel-react-best-practices ยท vercel-react-view-transitions |
vercel-labs/agent-skills | ๋ด์ฅํ์ง ์์. ์ค์น ๋ช
๋ น npx skills add vercel-labs/agent-skills๋ฅผ ๋๊ธธ ๋ฟ, ์คํํ์ง ์์ต๋๋ค |
vercel ๊ฒ์ ๋ด์ฅํ์ง ์๋ ์ด์ ๋ ๋ ๊ฐ์ง์
๋๋ค. vercel-labs/agent-skills์๋ LICENSE ํ์ผ์ด ์์ด ์ฌ๋ฐฐํฌํ ๊ถ๋ฆฌ๊ฐ ์๊ณ , ๊ทธ ์คํฌ๋ค์ ๋จ์ผ ํ์ผ์ด ์๋๋ผ SKILL.md + AGENTS.md + ๊ท์น ํ์ผ ์์ญ ๊ฐ(ํฉ์ณ ~350 KB)๋ผ์ ์ ์ด์ ๋์ ธ์ค ๋ฌผ๊ฑด์ด ์๋๋ผ ์ค์นํ ๋ฌผ๊ฑด์
๋๋ค.
devup-mcp๋ ๊ทธ ๋ช ๋ น์ ๋์ ์คํํ์ง ์์ต๋๋ค. ๋์์ธโ์ฝ๋ ์๋ฒ๊ฐ ํจํค์ง ์ค์น๊ธฐ๋ฅผ ์คํํ๋ฉด, ๋ ์ง์คํธ๋ฆฌ ํญ๋ชฉ ํ๋๊ฐ ์ค์ผ๋์ ๋ ํ๋ฉด์ exportํ ๋ชจ๋ ๊ธฐ๊ณ์์ ์์ ์คํ์ด ๋ฉ๋๋ค.
์ค์น ์์น๋ ํ๋ก์ ํธ ์์
๋๋ค โ ์ด๋ฏธ ์๋ ๊ฒ์ ์ฐ์ ํด .claude/skills, .opencode/skill, .agents/skills ์์ผ๋ก ๊ณ ๋ฆ
๋๋ค. ํ๋ก์ ํธ ๋ฃจํธ๋ devup-mcp๊ฐ ์ธ ์ ์๋ ์ ์ผํ ๊ณณ์ด๋ผ ์ ๊ถํ์ด ํ์ ์๊ณ , ์คํฌ์ด ์ ์ฅ์๋ฅผ ๋ฐ๋ผ๋ค๋๋๋ค. ์ด๋ฏธ ๊น๋ ค ์์ผ๋ฉด ๋ค์ ์ฐ์ง ์์ต๋๋ค.
๋ด์ฅ๋ณธ์ ๊ฐ ๋ ํฌ์ SKILL.md๋ฅผ ๊ทธ๋๋ก ๋ณต์ฌํ ๊ฒ์ด๊ณ , ์๋ต๊ณผ ์ค์น๋ ํ์ผ ๋ชจ๋ ์ด๋ ์ปค๋ฐ์ธ์ง์ ์ต์ ๋ณธ URL์ ํจ๊ป ๋ต๋๋ค. ์ฌ๋ณธ์ ๋ก์ต๋๋ค โ ๊ทธ๊ฒ ๋ด์ฅ์ ์ ์งํ ๋น์ฉ์ด๊ณ , node scripts/refresh-skills.mjs๊ฐ ๊ทธ๊ฑธ ๊ฐฑ์ ํ๋ ๋ฐฉ๋ฒ์
๋๋ค(--check๋ ์ฐ์ง ์๊ณ ๋๋ฆฌํํธ๋ง ๋ณด๊ณ ). ์ฃผ์์ YAML frontmatter ๋ค์ ๋ค์ด๊ฐ๋๋ค. ---๋ 0๋ฒ์งธ ๋ฐ์ดํธ์ ์์ด์ผ ๋ก๋๊ฐ ์ฝ์ต๋๋ค.
์ค์นํ์ง ์๊ณ ์ฝ๊ธฐ๋ง ํ๋ ค๋ฉด devup://skill/devup-ui ๋ฆฌ์์ค๋ ์์ต๋๋ค. ๋ค๋ง ๊ทธ๊ฑด fallback์
๋๋ค โ ์ค์นํด์ผ ๋ก๋๊ฐ ์์์ ๊บผ๋ด ์ค๋๋ค.
์ ๋๋ ๋ ๊ณณ์์๋ง ํฉ๋๋ค. ์ธ์
๋ง๋ค ์ค๋ฆฌ๋ instructions์ ํ ์ค, ๊ทธ๋ฆฌ๊ณ devup_ui_validate๊ฐ ์๋ฐ์ ์ฐพ์๋๋ฐ devup-ui ์คํฌ์ด ์ค์ ๋ก ์์ ๋๋ง ๋ถ๋ skillGap์
๋๋ค. ์ด๋ฏธ ๊น๋ ค ์๋ ์ฌ๋์๊ฒ ๊น๋ผ๊ณ ํ๋ ๊ฒ์ ๊ทธ ํ๋๋ฅผ ๋ฌด์ํ๊ฒ ๋ง๋๋ ์์์
๋๋ค.
devup-mcp๊ฐ Figma์ ๋ถ๋ ๊ฒฝ๋ก๋ ๋์ด๊ณ , ๋๋ฑํ์ง ์์ต๋๋ค.
| ๊ฒฝ๋ก | ๋ก๊ทธ์ธ | Figma ํ๋ | ์ธ์ ์ฐ๋ |
|---|---|---|---|
๋ธ๋ฆฌ์ง (bridge) |
ํ์ ์์ | ์ฐ์ง ์์ | ๊ธฐ๋ณธ. ๋ฐ์คํฌํฑ ์ฑ์์ ํ๋ฌ๊ทธ์ธ์ ๋์ ๋๋ฉด ๊ทธ์ชฝ์ผ๋ก ์ฝ์ต๋๋ค |
์ง์ (direct) |
devup_figma_auth { action: "login" } |
์๋๋ค | ๋ธ๋ฆฌ์ง๊ฐ ๋ชป ํ๋ ์ฝ๊ธฐ์, ํ๋ฌ๊ทธ์ธ์ ๋์ธ ์ ์๋ ํ๊ฒฝ(CI ๋ฑ) |
๋ธ๋ฆฌ์ง๋ฅผ ๋จผ์ ์ฐ์ญ์์ค. direct๋ Figma๊ฐ ์ฌ์ฉ๋์ ์ธ๋ ๊ฒฝ๋ก์ด๊ณ , ํ๋ฉด ํ๋๊ฐ ์ฌ๋ฌ ๋ฒ์ ์ฝ๊ธฐ๋ฅผ ์ฐ๋ฏ๋ก ํ๋๊ฐ ๊ธ๋ฐฉ ๋ฐ๋ฅ๋ฉ๋๋ค.
ํ๋ฌ๊ทธ์ธ์ด ์ด ํ์ผ์ ๋งก๊ณ ์์ผ๋ฉด ๋ก๊ทธ์ธ์ ์๊ตฌํ์ง ์์ต๋๋ค. ์์ ์๋ ์์ง์ ์์ํ๊ธฐ ์ ์ ํ ํฐ๋ถํฐ ํ์ธํด์, ํ๋๋ฅผ ์๋ผ๋ ค๊ณ ํ๋ฌ๊ทธ์ธ์ ๋์ด ์ฌ๋์๊ฒ "๋จผ์ ํ๋ ์ฐ๋ ๊ฒฝ๋ก๋ฅผ ์ฌ์ธ์"๋ผ๊ณ ๊ฑฐ์ ํ์ต๋๋ค. ์ง๊ธ์ ๋ธ๋ฆฌ์ง๋ฅผ ๋จผ์ ๋ณด๊ณ , ์ด ํ์ผ์ ๋งก์ ํ๋ฌ๊ทธ์ธ์ด ์์ ๋๋ง ๋ก๊ทธ์ธ์ ์๊ตฌํฉ๋๋ค. ์์ง ๋์ค ๋ธ๋ฆฌ์ง๊ฐ ๋ชป ํ๋ ์ฝ๊ธฐ๊ฐ ์์ผ๋ฉด ๊ทธ ์ฝ๊ธฐ๊ฐ ์๊ธฐ ์ด์ ๋ก ๊ฑฐ์ ํ๋ฏ๋ก, ๋ฌด์์ด ์ ๋งํ๋์ง๊ฐ ๊ทธ๋๋ก ๋๋ฌ๋ฉ๋๋ค.
์ง๊ธ ์ด๋ ๊ฒฝ๋ก๊ฐ ์ด์ ์๋์ง๋ devup_figma_auth { action: "doctor" }์ paths.bridge/paths.direct๋ก ํ์ธํ์ธ์.
ํ์ฌ ๋ธ๋ฆฌ์ง๊ฐ ๋ชป ํ๋ ์ฝ๊ธฐ๋ ๋์
๋๋ค โ scope: "file"์ ๋
ธ๋ ์๋ metadata ์ฝ๊ธฐ(์ต์์ ํ์ด์ง ๋ชฉ๋ก์ด๋ผ ๊ณ์ฝ์ด ๋ค๋ฆ
๋๋ค)์ referencePng์ get_screenshot. ๊ทธ ๋ฐ์ tsx export ๊ฒฝ๋ก๋ ์ ๋ถ ๋ธ๋ฆฌ์ง๋ก ๊ฐ๋๋ค.
๊ทธ๋์ ์ฐ๋ฆฌ๊ฐ ์ง์ ๋ง๋ Figma ํ๋ฌ๊ทธ์ธ์ ํตํด ๊ฐ์ ์ฝ๊ธฐ๋ฅผ ํ ์ ์์ต๋๋ค. ์ด ๊ฒฝ๋ก๋ ํ๋๋ฅผ ์ฐ์ง ์์ต๋๋ค. ํ๋ฌ๊ทธ์ธ์ด ๋ถ์ด ์์ผ๋ฉด ์คํฌ๋ฆฝํธ ์ฝ๊ธฐ๊ฐ ๊ทธ์ชฝ์ผ๋ก ๊ฐ๊ณ , ์ ๋ถ์ด ์์ผ๋ฉด ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์๊ณ ๊ทธ๋๋ก ์๊ฒฉ ๊ฒฝ๋ก๋ก ๊ฐ๋๋ค. ์ค์นํ์ง ์์ ์ฌ๋์ ๋์์ ๋ฐ๋์ง ์์ต๋๋ค.
๋น๋๋ ํ๋ฌ๊ทธ์ธ์ด ์ ์ฅ์์ ๋ค์ด ์์ต๋๋ค(plugin/dist/). npm๋ Node๋ ํ์ ์๊ณ , ์ ์ฅ์๋ฅผ ๋ฐ์ ๋์๋ค๋ฉด ๋ฐ๋ก ๋ค์ ๋จ๊ณ๋ก ๊ฐ๋๋ค.
1. Figma ๋ฐ์คํฌํฑ ์ฑ์์ ๋ถ๋ฌ์ต๋๋ค
Figma์ ํ๋ฌ๊ทธ์ธ ๋ฑ๋ก์ ๋ฐ์คํฌํฑ ์ฑ์ ๋ฉ๋ด ๋์์ด๋ผ ์คํฌ๋ฆฝํธ๋ก ๋์ ํ ์ ์์ต๋๋ค. ์ด ์ธ ๋จ๊ณ๋ง ์ง์ ํ์๋ฉด ๋ฉ๋๋ค.
- Figma ๋ฐ์คํฌํฑ ์ฑ์ ์ฝ๋๋ค (๋ธ๋ผ์ฐ์ ํ์ ๋ก์ปฌ ํ๋ฌ๊ทธ์ธ์ ๋ชป ๋ถ๋ฌ์ต๋๋ค)
- ๋ฉ๋ด์์ Plugins โ Development โ Import plugin from manifest...
- ์ด ์ ์ฅ์์
plugin/manifest.json์ ์ ํํฉ๋๋ค
ํ ๋ฒ๋ง ํ๋ฉด ๋ฉ๋๋ค. ์ดํ์๋ ํ๋ฌ๊ทธ์ธ ๋ชฉ๋ก์ Devup Bridge๋ก ๋จ์ต๋๋ค.
์ปค๋ฐ๋ ๋ฒ๋ค์ด ์์ค์ ์ด๊ธ๋์ง ์๋๋ก CI๊ฐ ๋งค๋ฒ ๋ค์ ๋น๋ํด byte ๋จ์๋ก ๋์กฐํฉ๋๋ค. ํ๋ฌ๊ทธ์ธ ์์ค๋ฅผ ๊ณ ์ณค๋ค๋ฉด
cd plugin && npm install && npm run buildํdist/๋ฅผ ํจ๊ป ์ปค๋ฐํด์ผ ํฉ๋๋ค.
2. ์ฝ์ผ๋ ค๋ ํ์ผ์์ ํ๋ฌ๊ทธ์ธ์ ์คํํฉ๋๋ค
Figma์์ ๋์ ํ์ผ์ ์ด๊ณ Devup Bridge๋ฅผ ์คํํ๋ฉด ์ฐฝ์ด ํ๋ ๋น๋๋ค. ๊ทธ ์ฐฝ์ด ์ด๋ ค ์๋ ๋์๋ง ๋ธ๋ฆฌ์ง๊ฐ ๋์ํฉ๋๋ค. ๋ซ์ผ๋ฉด ๋ค์ ์ฝ๊ธฐ๋ถํฐ ์๊ฒฉ ๊ฒฝ๋ก๋ก ๋์๊ฐ๋๋ค.
ํ๋ฌ๊ทธ์ธ ์ฐฝ์ ํ์๋ฑ์ผ๋ก ํ๋จํฉ๋๋ค.
| ํ์ | ๋ป |
|---|---|
| ์ด๋ก | devup-mcp์ ์ฐ๊ฒฐ๋จ. ์ด ํ์ผ์ ์ฝ๊ธฐ๋ ํ๋๋ฅผ ์ฐ์ง ์์ต๋๋ค |
| ํ์ | devup-mcp๋ฅผ ์ฐพ์ง ๋ชปํจ. 2์ด๋ง๋ค ๋ค์ ์๋ํฉ๋๋ค |
ํ์์์ ์ ๋ฐ๋๋ฉด devup-mcp๊ฐ ์คํ ์ค์ธ์ง, ๊ทธ๋ฆฌ๊ณ DEVUP_FIGMA_BRIDGE_PORT=off๋ก ๊บผ ๋์ง ์์๋์ง ํ์ธํ์ธ์.
- ๊ธฐ๋ณธ์ผ๋ก ์ผ์ ธ ์์ต๋๋ค. devup-mcp๋ ์์ํ ๋
127.0.0.1:1993์ ๋๊ธฐํ๊ณ , ๊ทธ ํฌํธ๋ฅผ ์ก์ง ๋ชปํ๋ฉด ์กฐ์ฉํ ์๊ฒฉ ๊ฒฝ๋ก๋ง ์๋๋ค. ๋๋ ค๋ฉดDEVUP_FIGMA_BRIDGE_PORT=off. - ์ฝ๊ธฐ ์ ์ฉ์ ๋๋ค. ํ๋ฌ๊ทธ์ธ์ด ์คํํ๋ ์คํฌ๋ฆฝํธ๋ ๋น๋ ์์ ์ ํ๋ฌ๊ทธ์ธ ์์ ๋ฐํ ์๊ณ , devup-mcp๋ ๊ทธ์ค ์ด๋ ๊ฒ์ ์คํํ ์ง ์ด๋ฆ๋ง ๋ณด๋ ๋๋ค. ์์ผ์ผ๋ก ์ฝ๋๊ฐ ์ค๊ฐ์ง ์์ผ๋ฉฐ Figma ๋ฌธ์๋ฅผ ๋ฐ๊พธ๋ ํธ์ถ์ ์กด์ฌํ์ง ์์ต๋๋ค.
- ์ด ๊ธฐ๊ธฐ์์๋ง ๋ฉ๋๋ค. ๋๊ธฐ ์ฃผ์๋
127.0.0.1์ด๋ผ ๋ค๋ฅธ ๊ธฐ๊ธฐ์์๋ ๋ถ์ ์ ์๊ณ , ์๊ฒฉ CI์์๋ ๋ธ๋ฆฌ์ง๊ฐ ์์ผ๋ ์๋์ผ๋ก ์๊ฒฉ ๊ฒฝ๋ก๋ฅผ ์๋๋ค. - ํ์ผ์ ํ ๋ฒ์ ํ๋์ ๋๋ค. ํ๋ฌ๊ทธ์ธ์ด ์๊ธฐ ํ์ผ ํค๋ฅผ ๋ณด๊ณ ํ์ง ๋ชปํ๋ ๊ฒฝ์ฐ๊ฐ ์์ด(Dev Mode ๋ฑ), ํค ์๋ ํ๋ฌ๊ทธ์ธ์ ํผ์ ๋ถ์ด ์์ ๋๋ง ์ฝ๊ธฐ๋ฅผ ๋ฐ์ต๋๋ค. ๋ ๊ฐ ์ด์์ด๋ฉด ์ด๋ ํ์ผ์ธ์ง ์ ์ ์์ผ๋ฏ๋ก ์๊ฒฉ ๊ฒฝ๋ก๋ก ๋์ด๊ฐ๋๋ค.
- ํฌํธ๋ฅผ ๋ฐ๊พธ๋ ค๋ฉด ์ธ ๊ณณ์ ๊ฐ์ด ๊ณ ์ณ์ผ ํฉ๋๋ค. Figma๋ ํ๋ฌ๊ทธ์ธ์ด ์ ์ํ ์ ์๋ ์ฃผ์๋ฅผ manifest์ ๋ฏธ๋ฆฌ ์ ์ด ๋๊ฒ ํ๊ณ ์คํ ์ค์๋ ๋ฐ๊ฟ ์ ์์ต๋๋ค.
manifest.json์allowedDomains,src/code.ts์PORT, ๊ทธ๋ฆฌ๊ณ ํ๊ฒฝ ๋ณ์๋ฅผ ๋ชจ๋ ๊ณ ์น ๋ค ํ๋ฌ๊ทธ์ธ์ ๋ค์ ๋น๋ยท์ค์นํด์ผ ํฉ๋๋ค. ํ๋๋ง ๋ฐ๊พธ๋ฉด ์๋ฌด ๋ง ์์ด ์๊ฒฉ ๊ฒฝ๋ก๋ก ๋์๊ฐ ํ๋๋ฅผ ๊ทธ๋๋ก ์๋๋ค. ws://127.0.0.1์ ์ธ ์ ์์ต๋๋ค. Figma์allowedDomains๊ฐ ๊ทธ ์ฃผ์๋ฅผ ๊ฑฐ๋ถํด manifest ์ ์ฒด๊ฐ ๋ฌดํจ๊ฐ ๋๊ณ ํ๋ฌ๊ทธ์ธ์ด ์์ ๋ก๋๋์ง ์์ต๋๋ค.localhost์ฌ์ผ ํฉ๋๋ค.- Figma ์ฐฝ์ ๋ค๋ก ๋ณด๋ด๋ฉด ๋๋ ค์ง๋๋ค. ๋ธ๋ผ์ฐ์ ๊ฐ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ๋ฌ๊ทธ์ธ์ ๋ถ๋น ํ ๋ฒ๊ผด๋ก ๊นจ์ฐ๊ธฐ ๋๋ฌธ์, ์์์ 160ms์ธ snapshot์ด ๋ค์์๋ 11์ด๊ฐ ๋ฉ๋๋ค. ์์ง ์ค์๋ Figma๋ฅผ ์์ ๋์ธ์.
์์ธํ ๋ด๋ถ ๊ตฌ์กฐ์ ์คํฌ๋ฆฝํธ ์์ฑ ๋ฐฉ์์ plugin/README.md์ ์์ต๋๋ค.
Figma ๋ฐ์คํฌํฑ ์ฑ์ ๋ก์ปฌ Dev Mode MCP(http://127.0.0.1:3845/mcp)๋ ์ธ ๋ฒ์งธ ๊ฒฝ๋ก๋ก ์๋ดํ์ผ๋ ์ ๊ฑฐํ์ต๋๋ค. ์ฝ๊ธฐ ๋๊ตฌ 6๊ฐ(get_design_context, get_variable_defs, get_screenshot, get_motion_context, get_metadata, get_figjam)๋ง ์ ๊ณตํ๊ณ ๊ทธ์ค์ use_figma๊ฐ ์์ต๋๋ค. devup-mcp์ ์์ง์ snapshotยทexploreยทsection indexยทtheme ๋ชจ๋ use_figma๋ก ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๋ฏ๋ก ๋ก์ปฌ์์๋ ์คํํ ๋๊ตฌ ์์ฒด๊ฐ ์์ต๋๋ค. ๋๊ตฌ๋ค์ด fileKey๋ฅผ ๋ฐ์ง ์๊ณ ๋ฐ์คํฌํฑ ์ฑ์ ์ด๋ ค ์๋ ํ์ผ๋ง ๊ฐ๋ฆฌํค๋ ๊ฒ๋ ๊ฐ์ ์ด์ ๋ก ๋ง์ง ์์ต๋๋ค. "OAuth ์์ด ๋ฐ๋ก ์ธ ์ ์๋ค"๋ ์๋ด๋ ํ์ ์ ์ฐจ์ ํ๋ฆฐ ์๋ด์๊ณ , ๋ฏฟ์ ์ชฝ์ด ํ ํด์ ๋ฒ๋ฆฐ ๋ค์์ผ ์๊ฒ ๋ฉ๋๋ค.
Figma Remote MCP ๋ฑ๋ก ์๋ํฌ์ธํธ๋ POST https://api.figma.com/v1/oauth/mcp/register์
๋๋ค. ์์ฒญ ๋ณธ๋ฌธ์ client_name์ ์ ํํ ์ผ์นํ๋ allowlist๋ก๋ง ์น์ธ๋ฉ๋๋ค.
| client_name | ๊ฒฐ๊ณผ |
|---|---|
Codex |
200 (client_id + client_secret ๋ฐ๊ธ) |
Claude Code |
403 (2026-09-06 ์ค์ธก; ์ด์ ํ์๋ 200์ผ๋ก ์ ํ ์์์) |
OpenCode |
403 |
opencode |
403 |
Cursor |
403 |
VS Code |
403 |
403 ์๋ต ๋ณธ๋ฌธ์ JSON์ด ์๋๋ผ ํ๋ฌธ Forbidden์
๋๋ค. ๊ทธ๋์ ๋ง์ ํด๋ผ์ด์ธํธ๊ฐ Invalid OAuth error response ... Raw body: Forbidden์ผ๋ก ํ์ฑ๊น์ง ๊นจ์ง๋๋ค. X-Figma-Plugin-Bundle ํค๋๋ User-Agent๋ฅผ ๋ฐ๊ฟ๋ ๊ฒฐ๊ณผ๋ ๋ฐ๋์ง ์์ต๋๋ค. ์ ๊ท client ๋ฑ๋ก์ waitlist๋ฅผ ํตํด์๋ง ๊ฐ๋ฅํฉ๋๋ค: https://www.figma.com/mcp-catalog/.
redirect_uri๋ ํํ๊ฐ ๊ณ ์ ๋์ด ์์ต๋๋ค.
| redirect_uri | ๊ฒฐ๊ณผ |
|---|---|
http://127.0.0.1:<port>/callback |
200 |
http://127.0.0.1:<port>/mcp/oauth/callback |
400 |
http://localhost:<port>/mcp/oauth/callback |
400 |
๊ฒฝ๋ก๋ ์ ํํ /callback์ด์ด์ผ ํ๊ณ ํธ์คํธ๋ 127.0.0.1์ด์ด์ผ ํฉ๋๋ค (localhost ๋ถ๊ฐ). Figma PAT(figd_...)๋ Authorization: Bearer, X-Figma-Token ์ด๋ ๋ฐฉ์์ผ๋ก๋ ์๊ฒฉ MCP์์ ์ง์๋์ง ์์ต๋๋ค.
๋ก์ปฌ OAuth ์ฝ๋ฐฑ์ด ์ฐ๋ ํฌํธ๋ฅผ OS๋ ๋ณด์ ์ํํธ์จ์ด(์: ์ฌ๋ด ๋ณด์ ์์ด์ ํธ)๊ฐ ์ด๋ฏธ ์ ์ ํ๊ณ ์์ผ๋ฉด, ๋ธ๋ผ์ฐ์ ๋ ๋ฆฌ๋ค์ด๋ ํธ์ "์ฑ๊ณต"ํ ๊ฒ์ฒ๋ผ ๋ณด์ด์ง๋ง ๊ทธ ์์ฒญ์ ๋ค๋ฅธ ํ๋ก์ธ์ค๋ก ์ ๋ฌ๋ฉ๋๋ค. ํด๋ผ์ด์ธํธ๋ ์๋ฌด ์๋ฌ ์์ด Waiting for authorization... ์ํ๋ก ์์ํ ๋จ์ต๋๋ค. ๋ก๊ทธ์ธ์ด ๋ฉ์ถ ๊ฒ์ฒ๋ผ ๋ณด์ด๋ฉด ๊ฐ์ฅ ๋จผ์ ์ฝ๋ฐฑ ํฌํธ๋ฅผ ๋ค๋ฅธ ํ๋ก์ธ์ค๊ฐ ์ฐ๊ณ ์์ง ์์์ง ํ์ธํ์ธ์.
๊ธฐ๋ณธ๊ฐ์ OS๊ฐ ๋งค๋ฒ ๋น ์์ ํฌํธ๋ฅผ ๊ณจ๋ผ์ฃผ๋ฏ๋ก(0) ์ด ์ถฉ๋์ ํผํฉ๋๋ค. ์ฌ์ ๋ฑ๋กํ client์ redirect_uri๊ฐ ๊ณ ์ ํฌํธ๋ก ๋ฑ๋ก๋์ด ์์ด ํน์ ํฌํธ๋ฅผ ๊ณ ์ ํด์ผ ํ๋ค๋ฉด devup-mcp --figma-callback-port <port>๋ฅผ ์ง์ ํ์ธ์. ์ด ๊ฒฝ์ฐ devup-mcp๋ ๊ทธ ํฌํธ๊ฐ ์ด๋ฏธ ์ฌ์ฉ ์ค์ด๋ฉด ์ฐ๊ฒฐ์ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ DEVUP_FIGMA_CALLBACK_PORT_IN_USE ์ค๋ฅ๋ฅผ ์ฆ์ ๋ฐํํฉ๋๋ค. devup_figma_auth { "action": "doctor" }์ paths.direct.callbackPort.free์์๋ ์ง์ ํ ํฌํธ๊ฐ ์ค์ ๋ก ๋น์ด ์๋์ง ์ค์ธกํ ๊ฐ์ ํ์ธํ ์ ์์ต๋๋ค.
Dynamic Client Registration์ ๊ฑด๋๋ฐ๋ ค๋ฉด mcp.<name>.oauth์ ์ด๋ฏธ ๋ฐ๊ธ๋ฐ์ clientId/clientSecret์ ์ง์ ์ง์ ํฉ๋๋ค.
{
"mcp": {
"figma": {
"type": "remote",
"url": "https://mcp.figma.com/mcp",
"oauth": {
"clientId": "<allowlist๋ client_name์ผ๋ก ๋ฑ๋กํด ๋ฐ๊ธ๋ฐ์ client_id>",
"clientSecret": "<allowlist๋ client_name์ผ๋ก ๋ฑ๋กํด ๋ฐ๊ธ๋ฐ์ client_secret>",
"scope": "mcp:connect",
"callbackPort": 19876,
"redirectUri": "http://127.0.0.1:19876/callback"
}
}
}
}Codex๋ allowlist์ ์์ด ๋ณ๋ ์ค์ ์์ด ๋ฑ๋กํ ์ ์์ต๋๋ค. Claude Code๋ ํ๋
200์ด์์ผ๋ 2026-09-06 ์ค์ธก์์ 403์ผ๋ก ๊ฑฐ์ ๋์ต๋๋ค โ allowlist๋ Figma๊ฐ ๋ฐ๊ฟ ์
์์ผ๋ฉฐ, ์ ํ๋ ์ธก์ ์์ ์ ๊ธฐ๋ก์
๋๋ค.
devup-mcp๋ ์ง์ ๊ฒฝ๋ก๋ง ์๋๋ค. ํธ์คํธ(Codex)์ ๋ฑ๋ก๋ ๊ณต์ Figma MCP๋ฅผ ๋น๋ฆฌ๋
์ฐํ ๊ฒฝ๋ก๋ ๋ง๋ค์ง ์์ต๋๋ค โ devup-mcp๊ฐ ์ค์ค๋ก Codex๋ก ๋ฑ๋กํด Figma ์๊ฒฉ MCP์
๋ถ๊ณ , ์์ง์ ํ์ํ use_figma๋ฅผ ๊ทธ ์ฐ๊ฒฐ๋ก ์ง์ ๋ถ๋ฆ
๋๋ค. ํธ์คํธ์ Figma MCP๋ฅผ
๋ฐ๋ก ์ค์ ํ ํ์๊ฐ ์๊ณ , ์ค์ ๋ผ ์์ด๋ devup-mcp๋ ๊ทธ๊ฒ์ ์ฐ์ง ์์ต๋๋ค.
claude mcp add --transport http figma https://mcp.figma.com/mcp
codex mcp add figma --url https://mcp.figma.com/mcp{
"url": "https://www.figma.com/design/<file-key>/<name>?node-id=1-2",
"outputs": ["tsx"],
"componentName": "OptionalComponentName",
"rootLayout": "standalone",
"scope": "node",
"outputPaths": { "tsx": "optional/path/Component.tsx" }
}๊ฒฐ๊ณผ์๋ tsx์ ํจ๊ป status, quality, cache, collection, source๊ฐ ํฌํจ๋ฉ๋๋ค. import ๋ชฉ๋ก๊ณผ ์ฌ์ฉ token์ ๋ณ๋ ํค๋ก ๋ณด๋ด์ง ์์ต๋๋ค โ ๊ฐ๊ฐ TSX์ ์ฒซ ์ค๊ณผ ๋ณธ๋ฌธ์ $token์ด ์ด๋ฏธ ๊ฐ์ ๋ด์ฉ์ ๋ด๊ณ ์์ด, ์๋ต์ ๋ ๋ฒ ์ฃ๋ ๋งํผ์ด ๊ทธ๋๋ก ๋ญ๋น์์ต๋๋ค. Auto Layout์ Flex, ์ผ๋ฐ container๋ Box, text๋ Text๋ก ๋ณํํ๊ณ theme binding์ด ์์ผ๋ฉด JSX prop์์ $token์ ์ฐ์ ์ฌ์ฉํฉ๋๋ค. ๋ณ์ token์ ๋น์ด ์์ง ์์ Figma codeSyntax.WEB์ ์ฐ์ ํ๊ณ , ์์ผ๋ฉด ๋ณ์ ๊ฒฝ๋ก์ ๋ง์ง๋ง ์ด๋ฆ์ ์ ๊ทํํฉ๋๋ค. ๋ฐ๋ผ์ TSX์ $token, devup.json key์ source map์ด ๊ฐ์ ์ด๋ฆ์ ์ฌ์ฉํฉ๋๋ค. rootLayout ๊ธฐ๋ณธ๊ฐ์ธ standalone์ ์ ํํ root์ ํฌ๊ธฐยท์์น ์ ์ฝ๊น์ง ํฌํจํ๊ณ Figma instance์ ์ค์ ์์ ์ํ๋ฅผ ํผ์ณ ์ ์๋์ง ์์ component ์ฐธ์กฐ๋ฅผ ๋ง๋ค์ง ์์ต๋๋ค. ์ด๋ฏธ ๋ ์ด์์์ ์์ ํ React ๋ถ๋ชจ ์์ ์ฝ์
ํ ๋๋ rootLayout: "embedded"๋ก root์ ์ธ๋ถ ํฌ๊ธฐยท์์น ์ ์ฝ๋ง ์๋ตํฉ๋๋ค.
{
"url": "https://www.figma.com/design/<file-key>/<name>?node-id=1-2",
"outputs": ["devupJson"],
"scope": "file",
"outputPaths": { "devupJson": "optional/path/devup.json" }
}๊ฒฐ๊ณผ๋ theme.colors, theme.typography, theme.length, theme.shadow๋ฅผ ํฌํจํ๋ ๊ฒฐ์ ์ JSON ๋ฌธ์์ด๊ณผ counts, completeness๋ฅผ ๋ฐํํฉ๋๋ค.
outputPath๋ฅผ ์๋ตํ๋ฉด ๊ฒฐ๊ณผ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ MCP ์๋ต์๋ง ์ ์งํฉ๋๋ค. ๋ช
์ํ๋ฉด ์์ฑ๋ TSX ๋๋ devup.json๋ง ํด๋น ๊ฒฝ๋ก์ ๊ธฐ๋กํ๊ณ ์ค์ ์ ๋ ๊ฒฝ๋ก๋ฅผ ์๋ตํฉ๋๋ค. ๊ธฐ๋ณธ ํ์ฉ write root๋ devup-mcp process ์์ ๋น์์ current directory ํ๋์ด๋ฉฐ, ๊ทธ ๋ฐ์ workspace๋ ๋ฐ๋ณต ๊ฐ๋ฅํ --allow-write-root <directory> ์์ ์ธ์๋ก๋ง ์ถ๊ฐํ ์ ์์ต๋๋ค. Tool ์
๋ ฅ์ผ๋ก root ์์ฒด๋ฅผ ๋ํ ์ ์๊ณ .., ๋ค๋ฅธ drive/UNC, alternate data stream, symlink/junction์ ํตํ root ํ์ถ์ ๊ธฐ๋ก ์ ์ ๊ฑฐ์ ๋ฉ๋๋ค.
์ฌ๋ฌ text/asset output์ ๋ชจ๋ ๊ฒ์ฆํ ๋ค ๊ฐ์ directory์ exclusive ์์ ํ์ผ์ stagingํ๊ณ ํ transaction์ผ๋ก ๊ต์ฒดํฉ๋๋ค. ์ ์ runtime ์ค๋ฅ์์๋ ์ด๋ฏธ ๊ต์ฒดํ ํ์ผ์ ์ญ์์ผ๋ก ๋๋๋ฆฌ๊ณ ๊ธฐ์กด ํ์ผ์ ๋ณต๊ตฌํฉ๋๋ค. ๊ฐ๋ณ rename์ atomicํ์ง๋ง ์ฌ๋ฌ directory์ process crash๋ฅผ ๊ฐ๋ก์ง๋ฅด๋ ์์ ํ ์์์ฑ์ ์ผ๋ฐ filesystem ํน์ฑ์ ๋ณด์ฅํ์ง ์์ต๋๋ค.
{
"url": "https://www.figma.com/design/<file-key>/<name>?node-id=1-2",
"outputs": ["tsx"],
"scope": "node",
"strict": true,
"refresh": false,
"delivery": "auto"
}์ outputs๋ ์คํค๋ง ๊ธฐ๋ณธ๊ฐ๊ณผ ๊ฐ์ ๊ถ์ฅ ํธ์ถ์
๋๋ค. ์ฝ์ output๋ง ์์ฒญํ์ธ์ โ ์์ ์๋ต์ ๋ฌด์์ด ๋ค์ด์ค๋๊ฐ ํ๊ฐ ์ ์ฒด ๋ชฉ๋ก ๋ ํผ๋ฐ์ค์ด๊ณ , ๊ทธ ํ๋ฅผ ๊ทธ๋๋ก ํ ๋ฐฐ์ด์ ์ฎ๊ฒจ ์ ์ผ๋ผ๋ ๋ป์ด ์๋๋๋ค. ํนํ rawSnapshot/rawPayload๋ฅผ debug: true ์์ด outputs์ ๋ฃ์ ํธ์ถ์ ํฌ์ ์ ์ -32602๋ก ๊ฑฐ์ ๋ฉ๋๋ค. ์ค์ ๋ก ์ด ์ ์ ์์๊ฐ ํ๋ ์ฌ๋ output์ ์ ๋ถ ๋์ดํ๋ฉด์ debug๋ ๋น ๋จ๋ฆฌ๊ณ ์์๊ณ , ๊ทธ๋๋ก ๋ณต์ฌํ๋ฉด ์คํ๋์ง ์๋ ํธ์ถ์ด์์ต๋๋ค.
devup_figma_export๋ ์์ ์ ํ์ ์ํ ๋๊ตฌ์
๋๋ค.
- ํ ํธ์ถ์ ํ๋ ์ 1~3๊ฐ๋ฅผ ๊ถ์ฅํ๊ณ , ํ๋ ์ 6๊ฐยท(ํ๋ ์ ร output) 12๋จ์๊น์ง๋ง ํ์ฉํฉ๋๋ค.
- ์ํ์ ๋๋ ์ ํ์ ํ๋ฉด ์์ง์ ์์ํ๊ธฐ ์ ์ ๊ฑฐ์ ํ๋ฏ๋ก,
frameIds๋ฅผ ๋ฐฐ์น๋ก ๋๋ ๋ถ๋ฅด์ธ์. - ๊ณํ์ฉ ์ด๋ฆผ๊ฐ์ ํ๋ ์๋น 15~60์ด์ ๋๋ค. ๋ณด์ฅ์ด ์๋๋ผ ์ด๋ฆผ์ด๋ฉฐ, ํ์ด์ง๋ค์ด์ ยท๋ณต์ก๋ยท์ค๋กํ๋ง์ด ๊ฒน์น๋ฉด ๋์ด๊ฐ๋๋ค. ํด๋ผ์ด์ธํธ๋ ๋ณดํต 300์ด์์ ํ์์์ํฉ๋๋ค.
- ํ๋ ์๋ณ ํฌ์์ด ์ผ๋ถ ์คํจํด๋ ์ฑ๊ณตํ ํ๋ ์์ ์ฐ์ถ๋ฌผ์ ์ ์ง๋ฉ๋๋ค.
์ด๋ฏธ ๋
ธ๋ ID๋ฅผ ์๊ณ ์๋ค๋ฉด(๋ธ๋ฆฌํ์ ์ ํ ์๊ฑฐ๋ ์์ ํธ์ถ์ด ์๋ ค์คฌ๋ค๋ฉด) devup_figma_explore๋ฅผ ๊ฑด๋๋ฐ๊ณ frameIds์ ๋ฐ๋ก ๋๊ธฐ์ธ์. ๊ฐ๊ณ ์๋ ID๋ฅผ ๋ค์ ์ฐพ์ผ๋ ค๊ณ ํ์ํ๋ ๊ฒ์ Figma ํธ์ถ ํ๋๋ฅผ ๊ทธ๋ฅ ์ฐ๋ ์ผ์
๋๋ค. ํ์์ Section ๋งํฌ๋ฐ์ ์์ ๋ ์ฐ๋ ๋๊ตฌ์
๋๋ค.
devup_figma_export๋ ๋์ผํ node/resource acquisition์์ ์ฌ๋ฌ projection์ ์์ฑํฉ๋๋ค. ์๋ต์ cache.artifactId๋ฅผ ๋ค์ ์์ฒญ์ artifactId๋ก ๋๊ธฐ๋ฉด Figma๋ฅผ ๋ค์ ํธ์ถํ์ง ์๊ณ ๋ค๋ฅธ output์ ๋ง๋ค ์ ์์ต๋๋ค. artifactId๋ urlยทrefresh์ ๋์์ ์ธ ์ ์๊ณ , ํจ๊ป ๋ณด๋ด๋ฉด DEVUP_FIGMA_HANDOFF_INVALID๋ก ๊ฑฐ์ ๋ฉ๋๋ค. URL ์์ฒญ์ ๊ฐ์ process ์์์ 10๋ถ TTL, ์ต๋ 8๊ฐ/ํญ๋ชฉ๋น 32 MiB/์ ์ฒด 128 MiB์ธ memory-only LRU cache๋ฅผ ์ฌ์ฌ์ฉํ๋ฉฐ, refresh: true๋ ์๋ฃ cache๋ฟ ์๋๋ผ ์งํ ์ค ์์ฒญ ๊ณต์ ๋ ์ฐํํด URL์ ์๋ก ์์งํฉ๋๋ค. ๋์ผ acquisition์ ์ ํ ์์
์ด ์ทจ์๋๋๋ผ๋ ๋ซํ in-flight ํ์์ ๋ค์ ์์ฒญ์ด ์์์ ์ผ๋ก ์ ๊ฑฐํ๊ณ ๋ค์ ์์งํ๋ฏ๋ก ๊ฐ์ key๊ฐ process ์๋ช
๋์ ์ค์ผ๋์ง ์์ต๋๋ค. cache์๋ reuseKind, ageSeconds, remainingTtlSeconds, avoidedFigmaToolCalls, ์ ์์ง์ originCollection์ด ํฌํจ๋๊ณ , ์๋ต ์ต์์ collection์ ํ์ฌ ์์ฒญ์ด ์ค์ ๋ก ์คํํ ํธ์ถ๋ง ์ง๊ณํฉ๋๋ค. cache.capabilities๋ artifact์ kind(design, theme-only, search, explore, section-index), collectionScope, resourceScope, referencePng ๋ณด์ ์ฌ๋ถ, redacted assetCaptureCount์ sectionSelection๋ง ๊ณต๊ฐํฉ๋๋ค. sectionSelection์ด ๋ง์ง๋ง์ผ๋ก ๊ฒ์ฆ๋ Section ์ ํ(frameIds ๋๋ allScreens)์ ๋ณด์กดํ๋ฏ๋ก, artifact๋ฅผ ์ฌ์ฌ์ฉํ ๋ frameIds๋ฅผ ๋ค์ ๋ณด๋ด์ง ์์๋ ์ ํ์ด ์ ์ง๋ฉ๋๋ค. ์์ ์๋ artifactId๋ง ๋๊ธฐ๋ฉด ์ ํ์ด ์ฌ๋ผ์ ธ ํ๋ณด ๋ชฉ๋ก ์ ์ฒด๊ฐ ๋ค์ ๋์์์ต๋๋ค. ๋ด๋ถ artifact๋ asset IDยทformatยทscale ์ ์ฒด๋ฅผ ๋ณด์กดํ๊ณ ์ธ ๊ฐ์ด ์ ํํ ๊ฐ์ capture๋ง ์ถ๊ฐ Figma ํธ์ถ ์์ด ์ฌ์ฌ์ฉํฉ๋๋ค. ์ฌ์ฌ์ฉ ์์ฒญ์ด ์ด ๋ฒ์๋ฅผ ๋์ผ๋ฉด DEVUP_FIGMA_HANDOFF_INVALID๋ก ํฌ์๊ณผ ํ์ผ ๊ธฐ๋ก ์ ์ ๊ฑฐ์ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด node/used-resource artifact๋ก file ์ ์ฒด devupJson์ ๋ง๋ค๊ฑฐ๋ screenshot์ ์์งํ์ง ์์ artifact๋ก referencePng๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. credential, screenshot๊ณผ asset binary๋ cache key๋ ํต๊ณ์ ํฌํจํ์ง ์๊ณ , process๊ฐ ๋๋๋ฉด cache๋ ์ฌ๋ผ์ง๋๋ค.
delivery๋ auto | inline | resource์
๋๋ค. auto๋ JSON escape, base64์ structured/text ์ด์ค ํํ์ ํฌํจํ ์ค์ MCP wire ํฌ๊ธฐ๋ฅผ ๊ณ์ฐํด ๊ฐ๋ณ 256 KiBยทํฉ๊ณ 1 MiB ์ดํ๋ง inline์ผ๋ก ๋ฐํํ๊ณ , ๊ทธ๋ณด๋ค ํฐ ๊ฒฐ๊ณผ๋ native MCP ResourceLink์ devup://artifact/... URI๋ก ๋ฐ๊ฟ๋๋ค. ๋งํฌ URI๋ JSON manifest๋ฅผ ๊ฐ๋ฆฌํค๋ฏ๋ก link MIME์ application/json์ด๊ณ payload MIMEยท๊ธธ์ดยทSHA-256์ payload* metadata๋ก ๋ถ๋ฆฌํฉ๋๋ค. manifest๋ chunkUris๋ก ๋ด์ฉ ์ฒญํฌ๋ฅผ ์ง์ ๊ฐ๋ฆฌํต๋๋ค โ ๋งํฌ๋ง ๋ฐ๋ผ๊ฐ๋ฉด manifest์์ ๋งํ๊ณ ์ฒญํฌ URI ํ์์ ๋ฐ๋ก ์์๋ด ์์ผ๋ก ์กฐ๋ฆฝํด์ผ ํ๋ ๋ฌธ์ ๊ฐ ์์ด์ก์ต๋๋ค. ๋ URI ํ์์ resources/templates/list์๋ ๊ทธ๋๋ก ๊ฒ์๋ฉ๋๋ค.
devup://artifact/{artifactId}/outputs/{outputId}/manifest
devup://artifact/{artifactId}/outputs/{outputId}/chunks/{index}
``` `resource`๋ ํฌ๊ธฐ์ ๋ฌด๊ดํ๊ฒ TSX/JSON/PNG๋ฅผ bounded chunk resource๋ก ์ ๊ณตํ๋ฉฐ, binary chunk๋ base64 MCP blob์
๋๋ค. asset manifest๋ binary๋ฅผ ๋ด์ฅํ์ง ์๊ณ ๊ฐ asset์ ๋
๋ฆฝ resource URIยทMIMEยท๊ธธ์ดยทSHA-256์ ์ฐธ์กฐํ๋ฏ๋ก `resources/read`๋ก ์๋ณธ bytes๋ฅผ ์ ํํ ์ฌ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ๊ฐ์ artifact์ ์ ๊ทํํ projection์ content hash๊ฐ ๊ฐ์ resource๋ฅผ ์ฌ์ฌ์ฉํฉ๋๋ค. ํ์ผ ์ถ๋ ฅ๊ณผ ์ resource publication์ ํจ๊ป ์์ฒญํ๋ฉด resource ์กฐํ๋ฅผ reservation ๋์ ์ฐจ๋จํ ํ๋์ transaction์ผ๋ก ๋ค๋ฃจ๋ฉฐ, ํ์ผ commit์ด ์ ๋ถ ์ฑ๊ณตํ ๋ค์๋ง resource์ LRU ๋ณ๊ฒฝ์ ๊ณต๊ฐํฉ๋๋ค. ์คํจํ๋ฉด ์๋ ํ์ผ์ fingerprint๋ก ๊ฒ์ฆํด ๋ณต์ํ๊ณ ๋ณต์ ๋ถ๋ฅ backup ๊ฒฝ๋ก๋ฅผ ๊ตฌ์กฐํํด ๋ณด๊ณ ํฉ๋๋ค. ํ์ฌ transaction์ด ๋ง๋ temp๋ ์ ์ ์ข
๋ฃยทrollback์์ ์ง์ ์ ๊ฑฐํ์ง๋ง, ์์ ๊ถ์ ์ฆ๋ช
ํ ์ ์๋ pre-existing temp๋ crashยทrollback recovery backup์ ์๋ ์ญ์ ํ์ง ์์ต๋๋ค.
`referencePng`๋ ์ ํํ์ ๋๋ง ๊ณต์ read-only `get_screenshot`์ ์ ํํ ํ ๋ฒ ์ถ๊ฐ ํธ์ถํฉ๋๋ค. ๊ณต์ ๋๊ตฌ๋ ๊ธฐ๋ณธ์ผ๋ก PNG์ URL๊ณผ curl ์๋ด๋ฅผ text๋ก๋ง ๋๋ ค์ฃผ๊ณ ๊ธด ๋ณ์ 1024px๋ก ์ค์ด๋ฏ๋ก, `enableBase64Response: true`์ `maxDimension: 8192`๋ก ํธ์ถํด node ์๋ ํฌ๊ธฐ์ PNG๋ฅผ inline์ผ๋ก ๋ฐ์ต๋๋ค. ๊ฒฐ๊ณผ์ image block์ ์ ํํ ํ๋์ฌ์ผ ํ๋ฉฐ(๊ณ์ text block์ ์ฝ์ง ์์), JSON/text์ ์จ๊ธด image๋ ๋ค์ค image๋ ๊ฑฐ์ ํฉ๋๋ค. 16 MiB compressed, 8192px, 64 MiB decoded ์ํ ์์์ PNG ์ ์ฒด๋ฅผ ์ค์ decodeํ ๋ค byte length์ SHA-256์ ํ์ธํด artifact์ ๋ณด์กดํ๋ฉฐ, ๋จ์ผ ๋งํฌ node์๋ง ์ ์ฉ๋ฉ๋๋ค. ๊ทธ๋์ `referencePng`๋ฅผ `frameIds` ๋๋ `allScreens: true`์ ํจ๊ป ์์ฒญํ๋ฉด ์์ง ์ ์ ๊ฑฐ์ ๋๊ณ , Section์ ์ฌ๋ฌ Frame์ ๋จผ์ ๋ฐํ๋ canonical URL๋ณ๋ก ํ๋์ฉ ์์งํด์ผ ํฉ๋๋ค. PNG bytes๋ logยทํต๊ณยทcache key์ ํฌํจ๋์ง ์์ผ๋ฉฐ `outputPaths.referencePng`๋ฅผ ๋ช
์ํ์ง ์์ผ๋ฉด ๋์คํฌ์ ๊ธฐ๋กํ์ง ์์ต๋๋ค.
๋ชจ๋ ์๋ฃ ์๋ต์๋ ๋ค์์ฒ๋ผ ์์ฒญํ ์ฐ์ถ๋ฌผ๋ณ `quality`๊ฐ ํฌํจ๋ฉ๋๋ค.
```json
{
"status": "complete",
"quality": {
"acquisition": "complete",
"projection": "exact",
"theme": "not-requested",
"assets": "not-requested"
}
}
acquisition์ complete | expected-projection | partial | failed, projection์ exact | approximated | lossy | failed | not-requested, theme์ complete | conflicted | unresolved | not-requested, assets๋ complete | partial | failed | not-requested์
๋๋ค. ๊ฒ์ยทํ์์ ์๋์ ์ธ ์์ graph๋ expected-projection์ผ๋ก ์ ์ ์๋ฃํ์ง๋ง, ํฌํจ๋ field์ ์คํจ๋ truncation์ partial์
๋๋ค. mask/effect fallback์ lossy, absolute layout fallback์ approximated์ด๋ฉฐ includeDiagnostics: false์ฌ๋ ํ์ง ํ์ ์๋ ๋ฐ์๋ฉ๋๋ค. ์ต์์ status๋ complete | partial | failed | selection_required ์ค ํ๋์
๋๋ค. ์์ฒญํ ๋ชจ๋ ์ถ์ด ์ ํยท์์ ํ๊ณ failures[]๊ฐ ๋น์ด ์์ ๋๋ง complete์
๋๋ค. ์ถ ํ๋๋ผ๋ ์ด๊ธ๋๊ฑฐ๋ ์คํจ๊ฐ ํ๋๋ผ๋ ์ง๊ณ๋๋ฉด partial์ด๊ณ , ์์ง์ด๋ ํฌ์ ์์ฒด๊ฐ ์ฃฝ์ผ๋ฉด failed, Section ๋งํฌ์์ ์์ง ํ๋ฉด์ ๊ณ ๋ฅด์ง ์์์ผ๋ฉด selection_required์
๋๋ค.
failures[]์๋ ๋
ธ๋ ๋จ์ ํฌ์ ์คํจ, ์์ฐ export ์คํจ, Section์ ํ๋ ์ ๋จ์ ์คํจ๊ฐ ๋ชจ๋ ํจ๊ป ์ง๊ณ๋ฉ๋๋ค. ์์ ์ฒ๋ผ ์ต์์๊ฐ complete์ธ๋ฐ ์์์ ์์ฐ์ด ์คํจํด ์๋ ์ํ๋ ๋์ค์ง ์์ต๋๋ค.
strict: true๋ ๋ชจ๋ ์์ฒญ ์ถ์ด exact/complete๊ฐ ์๋๋ฉด quality์ completenessReport๋ฅผ ๋ด์ ์ค๋ฅ๋ก ๊ฑฐ์ ํฉ๋๋ค.
๋ชจ๋ ๊ณต๊ฐ TSX generator๋ ๋ฐํ ์ ์ Rust์ ๊ณ ์ ๋ TypeScript+JSX parser๋ฅผ ํต๊ณผํฉ๋๋ค. parser ์ค๋ฅ๋ ๋์์ธ ์๋ฌธ์ ๋
ธ์ถํ์ง ์๊ณ byte range์ ์ค๋ฅ category๋ง ๋ฐํํฉ๋๋ค. ์๋ต์ fidelity๋ ์์ฑ๋ mapping ์๊ฐ ์๋๋ผ ์์งํ source snapshot์์ ๋
๋ฆฝ์ ์ผ๋ก ๊ณ์ฐํ node/text segment/variable/style/asset/layout ๊ธฐ๋ ์งํฉ์ ๋ถ๋ชจ๋ก ์ฌ์ฉํ๊ณ , ๋ด๋ถ validator๊ฐ ๊ฐ ํญ๋ชฉ์ emitted | flattened | ignored ์ค ์ ํํ ํ๋๋ก ๊ฒ์ฆํ๋์ง์ ์ถ๋ณ coverageยทtyped impact count๋ฅผ ๋ด์ต๋๋ค. component set, non-default variant selector์ inline instance๋ ์ต์ข
๋ณํ ํ source identity๋ณ provenance๋ฅผ ๋ค์ ๋ง๋ค๋ฉฐ, ๋ฐ๋ณต๋ ๋์ผ text segment๋ ํ๋์ mapping์ ์ฌ์ฌ์ฉํ์ง ์๊ณ occurrence๋ณ๋ก ์๋นํ๊ณ multilineยท์ค์ฒฉ text์ asset identity๋ฅผ ๊ฒ์ฆํฉ๋๋ค. ์ ์ ์๋ codegen warning/error๋ ๊ฐ๊ฐ ์ต์ approximated/failed๋ก ๋ณด์์ ์ผ๋ก ํ์ ํ๋ฉฐ, strict๋ syntax, source-derived trace coverage, lossy/failed impact๋ฅผ ํจ๊ป ๊ฒ์ฌํฉ๋๋ค.
๋ธ๋ผ์ฐ์ ์๊ฐ ํ๊ท๋ MCP ์๋ฒ๊ฐ ์์ ๋ช
๋ น์ ์คํํ์ง ์๊ณ ์๋น์ repository๊ฐ ์ค์ font/asset/DevupUI ํ๊ฒฝ์ผ๋ก actual.png๋ฅผ ๋ง๋ ๋ค ์์ Rust devup-mcp-visual๋ก ๋น๊ตํฉ๋๋ค. renderer pinning, ๊ธฐ๋ณธ 0.5% threshold, diff PNG์ ๊ฐ์ธ์ ๋ณด ์ทจ๊ธ ๊ณ์ฝ์ docs/visual-renderer-contract.md์ ์์ต๋๋ค.
์์ฑ ์ฝ๋๋ฅผ ํ๋ฌ๊ทธ์ธ์ ๋ต์๊ณผ ์ค ๋จ์๋ก ๋ง์ถฐ๋ณด๋ฉด ๋์ด ์ผ์นํ๋ค๋ ๊ฒ๊น์ง๋ ์ ์ ์์ง๋ง, ๋ ์ค ์ด๋ ์ชฝ๋ Figma๊ฐ ๊ทธ๋ฆฌ๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์์ง๋ ๋งํด์ฃผ์ง ๋ชปํฉ๋๋ค. harness/render๋ ๊ทธ ์ง๋ฌธ์ ๋ตํฉ๋๋ค โ ๊ฐ ํ๋ฉด์ devup-ui๋ก ๋น๋ํด ํ๋ ์ ํฌ๊ธฐ ๊ทธ๋๋ก ์ด๊ณ , Figma๊ฐ ๊ฐ์ ํ๋ ์์ ๋ ๋ํ PNG์ ํฝ์
๋น๊ตํฉ๋๋ค.
cd harness/render && npm install
python scripts/acquire.py # ๋ชจ๋ยทํ
๋งยท์์
ยท๊ธฐ์ค PNG๋ฅผ ์คํ ์ค์ธ devup-mcp์์ ๊ฐ์ ธ์ด
node scripts/render.mjs # ๋น๋ยท์บก์ฒยท๋น๊ต, ํ๋ฉด๋ณ ์๊ณ๊ฐ ์ด๊ณผ ์ exit 1acquire.py๋ Figma ํธ์ถ์ fixtures/local-call-bank์ ์ ๋ฆฝํ๋ฏ๋ก ์ฌ์คํ์ ์ด๋ฏธ ์ง๋ถํ ๋งํผ ๋ฌด๋ฃ์
๋๋ค. ํ๋ฉด๋ง๋ค ์๊ธฐ ํ
๋ง๋ฅผ node scope๋ก ๋ฐ์ต๋๋ค โ ํ์ผ ํ๋์ ์ฌ๋ฌ ๋ธ๋๋ ์ปฌ๋ ์
์ด ์์ด๋ฉด primary ๊ฐ์ ํ ํฐ์ด ์๋ก ๋ฎ์ด์จ์, ๊ณต์ง ํ๋ฉด์ด Figma๊ฐ ํ๋์ผ๋ก ๊ทธ๋ฆฌ๋ ์๋ฆฌ๋ฅผ ๋ณด๋ผ์์ผ๋ก ๊ทธ๋ ธ์ต๋๋ค. devup-ui๋ ํ
๋ง๋ฅผ ๋น๋ ์์ ์ ๊ตฝ๊ธฐ ๋๋ฌธ์ ํ๋ฉด๋ค์ ํ์ํ ํ
๋ง๋ณ๋ก ๋ฌถ์ฌ ๊ทธ๋ฃน๋ง๋ค ํ ๋ฒ์ฉ ๋น๋๋ฉ๋๋ค. ๋ฆฌ์
์ ์์ฑ ์ฝ๋๊ฐ ์ ์ ํ๋ @devup-ui/reset-css ๊ทธ๋๋ก์
๋๋ค.
thresholds.json์ด ํ๋ฉด๋ณ๋ก Figma์ ๋ฒ์ด์ ธ๋ ๋๋ ์ต๋์น๋ฅผ ๋ค๊ณ ์์ต๋๋ค. ์ด๊ณผํ๋ฉด ์คํจํ๊ณ , ๋ฐ๋๋ฉด ๊ทธ๋ ๋ค๊ณ ์๋ ค์ค๋๋ค(= ์์น๋ฅผ ์กฐ์ผ ์ฐจ๋ก). ์ธก์ ๊ฐ:
| ํ๋ฉด | 1920 | 992 / 768 | 360 / 390 |
|---|---|---|---|
| popup | 0.83% | 2.19% | 3.59% |
| popup (ํ๋ฌ๊ทธ์ธ ๋ต์) | 21.06% | 7.14% | 12.02% |
| notice | 2.33% | 4.19% | 8.29% |
| about | 4.54% | 6.94% | 11.26% |
| report 1.87% ยท grid 2.96% ยท keyframes 6.71% |
์ฐจ์ด๊ฐ ์ด๋ ์๋์ง๋ ๋ณด์กฐ ๋๊ตฌ๊ฐ ๋ตํฉ๋๋ค โ bands.mjs(๊ฐ์ฅ ๋ง์ด ์ด๊ธ๋ ๊ตฌ๊ฐ), drift.mjs(๋จ์ ์ด๋์ธ์ง ์ค์ ์ฐจ์ด์ธ์ง), crop.mjs(๊ตฌ๊ฐ์ ๊ธฐ์ค/์บก์ฒ ๋๋ํ), boxes.mjs(DOM ์์๋ฅผ Figma ์ขํ์ ๋์กฐ), elements.mjs(๊ทธ๋ฆผ์ด ์ค์ ๋ก ๋ช ํฝ์
๋ก ๋์๋์ง). ๊ธด ํ๋ฉด์ ํต์งธ๋ก ์ค์ธ ์คํฌ๋ฆฐ์ท์ ์๋ฌด๊ฒ๋ ๋ณด์ฌ์ฃผ์ง ์์ต๋๋ค.
text-check.mjs๋ ํฝ์
์ด ์๋๋ผ ๊ธ์๋ฅผ ๋ด
๋๋ค. ์์ฑ๊ธฐ๋ ํ
์คํธ ๋
ธ๋์ characters๋ฅผ JSX์ ์ฐ๋๋ฐ, JSX๋ ๊ณต๋ฐฑ์ ์๊ธฐ ๊ท์น์ด ์์ต๋๋ค โ ํ ๋ฌธ์ฅ์ด ์์ค ๋ ์ค๋ก ๋๋๋ฉด ์ฌ์ด์ ๊ณต๋ฐฑ ํ๋๊ฐ ๋ค์ด๊ฐ๋๋ค. ๋์์ธ์ ๊ทธ ๊ณต๋ฐฑ์ด ์์ผ๋ฉด ํ๋ฉด์ ๋์์ธ์ ์๋ ๋จ์ด๋ฅผ ์ฐ๊ณ , ๋ฌธ๋จ์ Figma๊ฐ ๋์ง ์๋ ์๋ฆฌ์์ ๊ฐ๊น๋๋ค. JSX๋ฅผ ์ฝ์ด ๋ฌด์์ด ๊ทธ๋ ค์ง์ง ์ถ๋ก ํ๋ ๊ฑด ๊ทธ ๊ท์น์ ๋ค์ ๊ตฌํํ๋ ์ผ์ด๊ณ , ๊ทธ๋ ๊ฒ ๋๊ฒจ์ง์ผ๋ฉด ์๋ ๊ฒฐํจ์ ๋ง๋ค์ด๋
๋๋ค โ ๊ทธ๋์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ค์ ๋ก ์ฐ์ ๊ธ์๋ฅผ characters์ ๋์กฐํฉ๋๋ค. ํ์ฌ 245๊ฐ ํ
์คํธ ์ค 3๊ฐ(๊ฐ์ ๋ฌธ๋จ์ ์ธ ํญ)๊ฐ ๋์์ธ๋๋ก ์ฐํ์ง ์์ต๋๋ค.
์บก์ฒยทํ
๋งยท์์
ยท๋น๋ ์ฐ์ถ๋ฌผ์ ์ปค๋ฐํ์ง ์์ต๋๋ค(harness/render/.gitignore). ์ด ํ๋ค์ค๊ฐ ์ฐพ์๋ธ ๊ฒฐํจ์ ํ
๋ง ์ค์ฝํ, ์ปจํ
์ด๋๊ฐ ์น ํ๋ ๊ทธ๋ฆผ์ ๋งค๋ํ์คํธ ๋๋ฝ, ์๋ฆฐ fill์ crop ํ๋ ฌ, ํ์ผ์์คํ
์ด ๋ชป ๋ฐ๋ ๋ ์ด์ด ์ด๋ฆ, ํญ๋ง๋ค ํฌ๊ธฐ๊ฐ ๋ค๋ฅธ ์ฌ์ง์ ํ์ผ ๊ณต์ , ํฌ๋ช
๋ 0 ๋
ธ๋์ export ๊ฑฐ๋ถ, ๊ทธ๋ฆฌ๊ณ positioned child ๋๋จธ๋ก CSS๊ฐ ๋ชป ๋ฏธ์น๋ ๋์ด์
๋๋ค.
Section ๋งํฌ์์ TSX๋ฅผ ์์ฒญํ๋ฉด ๋จผ์ ๋ด๋ถ screen frame ํ๋ณด์ canonical URL์ selection_required๋ก ๋ฐํํฉ๋๋ค. frameIds๋ก ๊ฒํ ํ frame๋ง ๊ณ ๋ฅด๊ฑฐ๋ allScreens: true๋ก ๋ชจ๋ ํ๋ฉด์ ์๊ฐ ์์๋๋ก batch exportํ ์ ์์ผ๋ฉฐ ๋ ์ต์
์ ๋์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. sourceMap์ nodeIdยท์๋ณธ propertyยทgeneratedPropertyยทresolution์ผ๋ก ํ๋โ์์ฑ ์์ฑ์ ์ค๋ช
ํ๋ sidecar์
๋๋ค. TSX ๋ฌธ์/๋ฐ์ดํธ ์คํ์
์ ์ ๊ณตํ์ง ์์ต๋๋ค. ์์ฑ ์ฝ๋ ๋ฐ์ท๋ ์ง๋จ์ generatedSource๋ฅผ ํ์ธํฉ๋๋ค. devup.json์ JSON pointer๋ฅผ ์ฌ์ฉํฉ๋๋ค. assetManifest๋ image hash/vector/export provenance๋ฅผ ํญ์ ์ด๊ฑฐํ๊ณ , assetRequests๋ก ๋ช
์ํ ํญ๋ชฉ๋ง ๊ถ์ฅ 1โ3๊ฐ, ์ต๋ 6๊ฐยทscale 1~4 ๋ฒ์์์ read-only SVG/PNG exportํฉ๋๋ค. assetRequests๋ฅผ ์ฐ๋ ํธ์ถ์ outputs์ assetManifest๊ฐ ํจ๊ป ์์ด์ผ ํ๋ฉฐ, ๋น ๋จ๋ฆฌ๋ฉด ๊ฑฐ์ ๋ฉ๋๋ค. outputPath๋ฅผ ์ง์ ํ๋ฉด binary๋ฅผ ํด๋น ํ์ผ๋ก ๋์ฝ๋ฉํ๊ณ ์๋ต์ base64๋ฅผ ์ ๊ฑฐํ๋ฉฐ, ์๋ตํ๋ฉด ํ์ ์๋น๋ฅผ ์ํด base64๊ฐ memory-only artifact์ ํด๋น MCP ์๋ต์ ๋จ์ ์ ์์ต๋๋ค.
์์ฐ 6๊ฐ ์ด๊ณผ ์์ฒญ์ ์ธ์ฆยท์์งยทํ์ผ ์ฐ๊ธฐ ์ ์ ๊ฑฐ์ ํ๋ฉฐ recommendedBatchSize, maxAssetCount, recommendedAssetRequests, remainingAssetRequests๋ก ๋ถํ ์ ์๋ดํฉ๋๋ค. ๋๋ฆฐ ์์ฐ ํธ์ถ์ 1์ด ๋๊ธฐ ํ assetJob.jobId, ๋จ๊ณ๋ณ ํธ์ถ ๊ธฐ๋ก, ์์ฐ๋ณ ์์ง/ํ์ผ ์ํ๋ฅผ ๋จผ์ ๋ฐํํฉ๋๋ค. {"jobId":"..."}๋ก ์กฐํํ๊ณ , paused์ด๋ฉด {"jobId":"...","jobAction":"resume"}๋ก ๋ฏธ์๋ฃ ํธ์ถ๋ง ์ฌ๊ฐํฉ๋๋ค. ๋์ผ ์ธ์๋ฅผ ๋ค์ ๋ณด๋ด๋ฉด ์ ์ค๋ ์ต์ด ์๋ต์ ์์
์ ์ฐพ์ต๋๋ค. ํด๋ผ์ด์ธํธ ํ์์์์ ์์
์ ์ทจ์ํ์ง ์์ต๋๋ค. ์ฒดํฌํฌ์ธํธ๋ ๊ฐ์ ์๋ฒ ํ๋ก์ธ์ค์์ ์ต๋ 30๋ถ, ์๋ฃ ๊ฒฐ๊ณผ๋ 5๋ถ ๋ณด์กดํ๋ฉฐ ์๋ฒ ์ฌ์์ ํ์๋ ๋ณต๊ตฌ๋์ง ์์ต๋๋ค. ๊ฐ๋ณ upstream ํธ์ถ์ 90์ด์ ์ผ์์ ์งํฉ๋๋ค. ์์ฐ exported๋ ๊ฒ์ฆ๋ ๋ฐ์ดํธ ์์ง์ด๋ฉฐ, fileState=written์ ์ค์ ํ์ผ ๋ฐ์ดํธ๊น์ง ํ์ธํ ๊ฒฐ๊ณผ์
๋๋ค. ์์ธ ๊ณ์ฝ์ R3 ์์ฐ ์์
๊ณผ ๊ทผ๊ฑฐ๋ฅผ ์ฐธ์กฐํ์ธ์.
assetManifest๋ ๋ชฉ๋ก์ผ ๋ฟ ํ์ผ์ ์ฐ์ง ์์ต๋๋ค. ํ์ผ์ ์ป์ผ๋ ค๋ฉด assetRequests๋ก ๋ค์ ๋ถ๋ฅด๋, ๊ทธ ํธ์ถ์ artifactId๊ฐ ์๋๋ผ ์๋ url๋ก ํด์ผ ํฉ๋๋ค. ์์ฐ ์บก์ฒ ์์ด ์์ง๋ artifact๋ ์์ฐ ์์ฒญ์ ์ฒ๋ฆฌํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค. ๊ทธ ์กฐํฉ์ผ๋ก ๋ถ๋ฅด๋ฉด ๋ฌด์์ด ์๋์ง์ ์ด๋ป๊ฒ ๋ณต๊ตฌํ๋์ง๋ฅผ ๋ด์ ๊ฑฐ์ ํฉ๋๋ค:
This artifact was collected without the requested asset captures. Remove artifactId and call again with the original url and assetRequests.
๊ธฐ๋ณธ๊ฐ์์๋ manifest์ path์ TSX์ ์์ฐ ์ฐธ์กฐ๊ฐ ์๋ฆฌํ์์๋ก ๋จ์ต๋๋ค. ์ด๊ฒ์ด ๊ธฐ๋ณธ ๋์์ด๊ณ , assetPublicRoot๋ ์ตํธ์ธ์
๋๋ค.
์ค์ ๊ฒฝ๋ก๋ก ๋ฐ๊พธ๋ ค๋ฉด ๊ฐ์ ํธ์ถ์์ assetPublicRoot์ assetRequests.outputPath๋ฅผ ํจ๊ป ์ฃผ์ธ์. ๊ท์น์ ์ด๋ ์ต๋๋ค.
assetPublicRoot๋ URL/๋ก ์๋น๋๋ ์ด๋ฏธ ์กด์ฌํ๋ ์ ๋ ๋ก์ปฌ ๋๋ ํฐ๋ฆฌ์ฌ์ผ ํฉ๋๋ค. ์๋ ๊ฒฝ๋ก์ด๊ฑฐ๋ ์กด์ฌํ์ง ์์ผ๋ฉด ํธ์ถ์ ์ค๋ฅ์ ๋๋ค.- ๊ฐ์ ํธ์ถ์
assetRequests.outputPath๊ฐ ์ต์ ํ ๊ฐ ์์ด์ผ ํฉ๋๋ค. ์ ์ฅ๋ output ๋งคํ์ artifact์ ๋ณด์กด๋์ง ์์ผ๋ฏ๋กartifactId๋ก ์ฌ์ฌ์ฉํด๋ ์ด์ด์ง์ง ์๊ณ , ์ด ์ง์ ์ ํธ์ถ๋ง๋ค ํด์ผ ํฉ๋๋ค. outputPath๊ฐassetPublicRoot๋ฐ์ด๊ฑฐ๋ ํ์ฉ write root๋ฅผ ๋ฒ์ด๋๋ฉด ๊ฑฐ์ ๋ฉ๋๋ค.
์กฐ๊ฑด์ด ๋ง์ผ๋ฉด ๊ทธ ๋ฃจํธ ์๋์ ์ฐ์ธ ํ์ผ์ด manifest์ ๋ชจ๋ TSX output์์ percent-encoding๋ ์๋ URL๋ก ๋ฐ๋๋๋ค.
๋ด๋ณด๋ธ ๋ฐ์ดํธ๊ฐ ๋์ผํ๋ฉด ํ๋์ canonical path/outputPath๋ฅผ ๊ณต์ ํ๊ณ , ๊ทธ canonical ๊ฒฝ๋ก๋ ์๋ต์ ์ค๋ ค ๋์์ค๋ฏ๋ก ๋ฐํ๋ ๊ฒฝ๋ก๋ฅผ ๊ทธ๋๋ก ํ์ธํด ์ฐ๋ฉด ๋ฉ๋๋ค.
์ค๋ณต ์ ๊ฑฐ์ ํ๋จ ๊ธฐ์ค์ ์ข์ต๋๋ค.
- ๋์ฝ๋ํ export ๋ฐ์ดํธ์ SHA-256์ผ๋ก๋ง ํ๋จํฉ๋๋ค. ๋ ์ด์ด ์ด๋ฆ์ด๋ ๊ฒ์ฆ๋์ง ์์
imageHash๋ก๋ ํฉ์น์ง ์์ต๋๋ค. - ๋จผ์ ๋ฌด๊ฒฐ์ฑ์ ๊ฒ์ฆํฉ๋๋ค. ์์ฐ์ด ์ ๊ณ ํ
byteLengthยทsha256์ด ์ค์ ๋์ฝ๋ ๊ฒฐ๊ณผ์ ๋ค๋ฅด๋ฉด ํฉ์น๊ธฐ ์ ์ ๊ฑฐ์ ํฉ๋๋ค. - ๋ด์ฉ๊ณผ ํฌ๋งท์ด ๋ชจ๋ ๊ฐ์ ๋๋ง ๊ณต์ ํฉ๋๋ค. ํ์ ํค๋ (๋ด์ฉ ํด์, ํ์ฅ์, MIME)์ด๋ผ ๊ฐ์ ๊ทธ๋ฆผ์ SVG์ PNG๋ ๊ฐ๊ฐ ๋จ์ต๋๋ค.
- manifest์ ๋ ธ๋๋ณ ํญ๋ชฉ์ ๊ทธ๋๋ก ์ ์ง๋ฉ๋๋ค. ํฉ์ณ์ง๋ ๊ฒ์ ํ์ผ ๊ฒฝ๋ก์ด์ง ๋ชฉ๋ก์ ์ค์ด ์๋๋ฏ๋ก, ์ด๋ ๋ ธ๋๊ฐ ์ด๋ ์์ฐ์ ์ฐ๋์ง๋ ๊ณ์ ๋ณด์ ๋๋ค.
assetNamesPerNode ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ ํ true์
๋๋ค.
asset์ ํ์ผ ์ด๋ฆ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ ์ด์ด ์ด๋ฆ์
๋๋ค โ ํ๋ฌ๊ทธ์ธ์ด ๊ทธ๋ ๊ฒ ์ง๊ธฐ ๋๋ฌธ์
๋๋ค. ๊ทธ๋์ ๋์์ด๋๊ฐ ๊ฐ์ ์ด๋ฆ์ ์ค ๋
ธ๋๋ค์ ํ์ผ ํ๋๋ฅผ ๊ณต์ ํฉ๋๋ค. ๊ฐ์ ๊ทธ๋ฆผ์ด๋ฉด ๋ง์ง๋ง ์๋๋ฉด ์์ค์
๋๋ค. ํ ํ๋ฉด์์ ์ฌ๋ ๋
ธ๋๊ฐ Logo.svg ํ๋๋ฅผ ์ฃผ์ฅํ๋๋ฐ ์ค์ ๋ก๋ ์๋ก ๋ค๋ฅธ ๊ทธ๋ฆผ ๋ค์ฏ ๊ฐ์๊ณ , ํญ๋ง๋ค ๊ทธ๋ ค์ง ์ฌ์ง์ ๋ง์ง๋ง์ผ๋ก export๋ ํญ์ ํ์ผ๋ง ๋จ์ ๋ค๋ฅธ ํญ์์๋ ์์์ ํฌ๊ธฐ๊ฐ ์ด๊ธ๋ ์ฑ ๋์ด๋ฉ๋๋ค(ํ์ผ์ด ์์์ ๊ฐ์ ํฌ๊ธฐ์ด๋ฉด object-fit์ด ๋ฌด์์ด๋ ๊ฒฐ๊ณผ๊ฐ ๊ฐ์ผ๋ฏ๋ก, ํ๋ฌ๊ทธ์ธ์์๋ ์ด ๋ฌธ์ ๊ฐ ๋๋ฌ๋์ง ์์ต๋๋ค).
assetNamesPerNode๋ ๊ฐ asset์ ๊ทธ ๋
ธ๋์ ์ด๋ฆ์ผ๋ก ์ง์ด(Logo-422-6921.svg, Frame 269-422-3392.png) ๋์ ํจ๊ป ์์ฑ๋๋ค. ๊ธฐ๋ณธ๊ฐ์ true์
๋๋ค โ ๋ ๋๋งํด ๋ณด๋ฉด ์ด์ชฝ์ด Figma๊ฐ ๊ทธ๋ฆฌ๋ ๊ทธ๋ฆผ์ ๊ฐ๊น๊ณ (๊ณต์ง ํ๋ฉด 992ํญ 6.48% โ 4.19%, about 992ํญ 10.79% โ 6.94%), ํ๋ฌ๊ทธ์ธ golden 268๊ฐ๋ ๊ทธ๋๋ก ํต๊ณผํฉ๋๋ค. golden์ CodegenOptions๋ฅผ ์ง์ ์ฐ๊ณ ๊ทธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ ํ ํ๋ฌ๊ทธ์ธ๊ณผ ๋์ผํ๊ธฐ ๋๋ฌธ์
๋๋ค. ํ๋ฌ๊ทธ์ธ๊ณผ byte ๋จ์๋ก ๊ฐ์ ์ด๋ฆ์ด ํ์ํ๋ฉด assetNamesPerNode: false๋ก ๋์ญ์์ค.
๋ ์ํ์์ ์๋ก ๋ค๋ฅธ ๊ทธ๋ฆผ์ด ํ ํ์ผ์ ๊ณ์ ์ฃผ์ฅํ๋ฉด ์ฒซ ๋ฒ์งธ๋ง ๊ธฐ๋กํ๊ณ ๋๋จธ์ง๋ DEVUP_ASSET_NAME_SHARED diagnostic์ผ๋ก ๋ณด๊ณ ํฉ๋๋ค โ ์กฐ์ฉํ ๋ฎ์ด์ฐ์ง ์์ต๋๋ค.
๋ ์ด์ด ์ด๋ฆ์ด ํ์ผ์์คํ
์ด ๋ฐ์ง ๋ชปํ๋ ์ด๋ฆ์ผ ๋(ic:round-arrow-left์ฒ๋ผ ์ฝ๋ก ์ด ๋ ์ด๋ฆ์ Windows๊ฐ ๋ง๋ค์ง ๋ชปํฉ๋๋ค) ์ ๋ฌ ์์ ์ ์์ฑ ์ฝ๋์ manifest๋ฅผ ํจ๊ป ๊ฐ๋ช
ํด ๋์ด ์ด๊ธ๋์ง ์๊ฒ ํฉ๋๋ค. ์์ฑ๊ธฐ ์์ฒด๋ ํ๋ฌ๊ทธ์ธ์ ์ด๋ฆ์ ๊ทธ๋๋ก ์ฐ๋ฏ๋ก golden parity๋ ์ ์ง๋ฉ๋๋ค.
๊ฐ๋ช
๊ท์น์ ์ด๋ ์ต๋๋ค. ์์ซ์ยท-ยท_๊ฐ ์๋ ๋ฌธ์๋ฅผ -๋ก ๋ฐ๊พธ๊ณ ์๋ค -๋ฅผ ๋ผ๋ฉฐ, Windows ์์ฝ์ด(CON, NUL, COM1โฆ)์ด๊ฑฐ๋ ๋นASCII๊ฐ ์์๊ฑฐ๋ ์ด๋ฆ์ด ๋ฐ๋์๊ฑฐ๋ 120์๋ฅผ ๋์ผ๋ฉด ์๋ ์ด๋ฆ์ SHA-256 ์ 12์๋ฆฌ๋ฅผ ์ ๋ฏธ์ฌ๋ก ๋ถ์ฌ ์๋ก ๋ค๋ฅธ ์ด๋ฆ์ด ํ ํ์ผ๋ก ํฉ์ณ์ง์ง ์๊ฒ ํฉ๋๋ค. ํ์ฅ์๋ ASCII ์์ซ์ 10์๊น์ง๋ง ๋จ๊น๋๋ค.
/icons/ic:round-arrow-left.svg -> /icons/ic-round-arrow-left-b041d24e668d.svg
๊ทธ๋์ ๊ณต๋ฐฑ์ด๋ ํ๊ธ์ด ๋ ๋ ์ด์ด ์ด๋ฆ๋ ์ฝ๋์ manifest ์์ชฝ์์ ๊ฐ์ ASCII ๊ฒฝ๋ก๊ฐ ๋ฉ๋๋ค.
Section ๋งํฌ๋ ์ ์ฒด subtree๋ฅผ ์ง์ ๋ณํํ์ง ์์ต๋๋ค. selection_required.nextAction์ ๋ฐ๋ผ ํ๋ณด๋ฅผ ํ์ธํ ๋ค frameIds ๋๋ allScreens: true๋ก ํ๋ฉด๋ณ export๋ฅผ ๊ณ์ํ๋ฉฐ, ์ผ๋ถ ํ๋ฉด ์์ง์ด ์คํจํ๋ฉด ์ฑ๊ณตํ ํ๋ฉด์ ์ ์งํ๊ณ ์คํจํ node๋ failures์ ๋ณด๊ณ ํฉ๋๋ค. nextAction์ whyยทhowยทdoNot๊ณผ ํจ๊ป ์ฒซ ํ๋ณด๋ฅผ ๊ณ ๋ฅด๋ ๊ทธ๋๋ก ์คํ ๊ฐ๋ฅํ example ํธ์ถ์ ๋ด์ต๋๋ค.
์ฌ๋ฌ ํ๋ฉด์ ํ ๋ฒ์ ๋ฐ์ผ๋ฉด frames[]์ ๊ฐ ํญ๋ชฉ์ด ์๋ก ๊ฐ์ ๊ตฌ์กฐ์ธ์ง ์๋ ค์ค๋๋ค. ์์ฑ ๊ตฌ์กฐ๊ฐ ์์ ํ๋ ์๊ณผ ๊ฐ์ผ๋ฉด ๊ทธ ํ๋ ์์ structurallyIdenticalTo(๊ฐ์ ๊ตฌ์กฐ์ธ ์ฒซ ํ๋ ์์ node ID), differsOnly(์: ["assetReferences"]), comparedOutputs๊ฐ ๋ถ์ต๋๋ค. ๋ ํ๋ฉด์ด ์ ๋ง ๋ค๋ฅธ์ง ํ์ธํ๋ ค๊ณ TSX๋ฅผ ์ง์ ๋์กฐํ ํ์๊ฐ ์์ต๋๋ค.
ํ๋ฉด ํ๋ณด ํ์ ์ explore, export์ selection, allScreens๊ฐ ๊ฐ์ ๊ท์น ํ๋๋ฅผ ์๋๋ค. ์
์ด ์๋ก ๋ค๋ฅธ "ํ๋ฉด" ์ ์๋ฅผ ๊ฐ๋ ๋ฌธ์ ๊ฐ ์ฌ๋ผ์ ธ, allScreens๊ฐ ๋ฐฐ๋ยท์ฃผ์ ํ๋ ์์ ํ๋ฉด์ผ๋ก ๋ง๋ค์ด๋ด์ง ์์ต๋๋ค.
SECTION์ 2๋จ๊ณ์
๋๋ค. 1๋จ๊ณ๋ก status: "selection_required"์ ์ ํ ๋ชฉ๋ก์ ๋ฐ๊ณ , 2๋จ๊ณ๋ก nextAction.example์ ์คํํด ๊ณ ๋ฅธ ํ๋ฉด์ exportํฉ๋๋ค. ํ ๋ฒ์ Section ์ ์ฒด๋ฅผ ์์งํ๋ ค ํ์ง ๋ง์ธ์.
SECTION ๊ธฐ๋ณธ ์๋ต์ ํ๋ฉด ์ํฐํฉํธ๊ฐ ์๋ ์ ํ ๋ชฉ๋ก์
๋๋ค. selection.status์ selection.count๋ก ๋ชฉ๋ก ์กฐํ ์ํ์ ํ๋ณด ์๋ฅผ ์ ์ ์์ผ๋ฉฐ, ์ต์์ status: "selection_required"๋ ์์ง ํ๋ฉด์ ์ ํํด์ผ ํ๋ค๋ ๋ป์
๋๋ค.
๋ชฉ๋ก์ ๋ ๊ฐ๋๋ก ๋๋ฉ๋๋ค.
selection.candidates[]โ ์๋์ผ๋ก ํ๋ฉด์ด๋ผ๊ณ ํ์ ํ ํ๋ณด์ ๋๋ค.node.name,node.nodeType,node.textPreview,canonicalUrl๋ก ์๋ก ๊ตฌ๋ถํฉ๋๋ค.allScreens: true๋ ๋ฉ๋ด์ ๋ชจ๋ ํญ๋ชฉ์ด ์๋๋ผ ๋ฐ๋ก ์ด ์๋ ํ๋ฉด ํ๋ณด๋ฅผ ํ๊บผ๋ฒ์ ๊ณ ๋ฅด๋ ๊ฒ์ ๋๋ค.selection.explicitCandidates[]โ ์๋ ํ์ ์ด ํ๋ฉด์ผ๋ก ๋ณด์ง ์์ ๊ฒ๋ค์ ๋๋ค. ์์ ์ฌ๋ก, ์ฃผ์ยทํ ์คํธ, ๊ทธ๋ฆฌ๊ณ ํ๋ฉด ์น์๋ก ์ธก์ ๋์ง ์๋ ๊ธด ํ์ด์ง ๊ฐ์ ๊ฒ์ด ์ฌ๊ธฐ ๋ค์ด์ต๋๋ค.allScreens๋ ์ด๋ค์ ๊ณ ๋ฅด์ง ์์ผ๋ฏ๋ก, ํ์ํ๋ฉดframeIds๋ ๊ทธcanonicalUrl๋ก ๋ช ์์ ์ผ๋ก ์ ํํ์ธ์.
๊ธด ํ์ด์ง๋ ๋์ดยท๋น์จ ์ด๋ ์ชฝ์ผ๋ก๋ ํ๋ฉด์ผ๋ก ์ธก์ ๋์ง ์์ต๋๋ค. ๊ทธ๋ ๋ค๊ณ ๊ทธ ์์ ๋ฏ์ด ์กฐ๊ฐ๋ค๋ง ํ๋ณด๋ก ๋ด๋์ผ๋ฉด ์ ์ ํ์ด์ง ์์ฒด๋ ๋ชฉ๋ก์ ์๊ฒ ๋๋ฏ๋ก, ํ์ด์ง๋ explicitCandidates์ ํต์งธ๋ก ๋จ๊ธฐ๊ณ ๊ทธ ์์ ์๋ ์๋ ํ๋ฉด ํ๋ณด๋ ํจ๊ป ๋ณด์กดํฉ๋๋ค. ๋ ์ค ๋ฌด์์ ๊ณ ๋ฅผ์ง๋ ํธ์ถ์๊ฐ ์ ํฉ๋๋ค. ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ๋ณด์ด๋ ํ
์คํธ๋ง ๋ชจ์ ์ต๋ 120์, ์ ์ฒด ์ต๋ 2KB๋ก ์ ํํ๋ฏ๋ก ๋น์ด ์๊ฑฐ๋ ์งง์๋ ์ค์ ํ๋ฉด ๋ด์ฉ์ด ์๋ค๋ ๋ป์ ์๋๋๋ค. nextAction.example์๋ ์ฒซ ํ๋ณด๋ฅผ ์ ํํ๋ devup_figma_export ํธ์ถ ์์๊ฐ ๋ค์ด ์์ต๋๋ค. ์์์ frameIds๋ฅผ ๊ฒํ ํ ํ๋ณด ID๋ก ๋ฐ๊ฟ ํธ์ถํ๋ฉด ์ ํํ ํ๋ฉด๋ง ์์งํฉ๋๋ค.
Section ์์ frame์ด mobile / tablet / desktop์ฒ๋ผ breakpoint ์ด๋ฆ์ ๊ฐ์ง๋ฉด, ๊ทธ frame ํ๋๋ฅผ ์์ฒญํด๋ ๊ฐ์ ์ด๋ฆ ๊ท์น์ ํ์ frame์ด ํจ๊ป ์์ง๋ฉ๋๋ค(Section ์์ฒด๋ ์์ง ๋ฒ์ ๋ฐ์ด๋ฉฐ, ๊ทธ ์ด๋ฆ์ ๊ฐ frame์ parentName์ผ๋ก ์ ๋ฌ๋ฉ๋๋ค). ์ด๋ tsx๋ responsiveTsx๋ฅผ ์์ฒญํ๋ฉด ๊ฒฐ๊ณผ์ responsiveTsx๊ฐ ์ถ๊ฐ๋ฉ๋๋ค โ ์ธ ํญ์ ํ๋์ ํธ๋ฆฌ๋ก ์ ๊ณ ํญ๋ง๋ค ๋ค๋ฅธ ๊ฐ์ devup-ui ๋ฐ์ํ ๋ฐฐ์ด [mobile, sm, tablet, lg, pc]๋ก ์ด ๋ชจ๋์
๋๋ค. ๊ฐ ํญ์ด ๋์ด๋ slot์ frame ์ด๋ฆ์ด ์๋๋ผ ํญ์ผ๋ก ์ ํด์ง๋๋ค(โค480 / โค768 / โค992 / โค1280 / ๊ทธ ์ด์). ์ปดํฌ๋ํธ ์ด๋ฆ์ componentName์ด ์ฐ์ ์ด๊ณ , ์์ผ๋ฉด Section ์ด๋ฆ์ PascalCase์ Page๋ฅผ ๋ถ์
๋๋ค(about โ AboutPage).
ํ ํญ์๋ง ์๋ ๋
ธ๋๋ ๋ค๋ฅธ ํญ์์ display: none์ผ๋ก ์จ๊ธด ๋ณต์ฌ๋ณธ๊ณผ ๋ณํฉ๋๋ฉฐ, ์ด๋ ๋ณต์ฌ๋ณธ์ Section ๋ ์ด์ด ์์์ ์ฒซ ํญ์ ๊ฐ์ ๊ฐ์ง๋๋ค โ ๊ทธ๋์ ๋ฐฐ์ด์ ์ฒซ slot์ desktop ๊ฐ์ด ๋์ผ ์ ์์ต๋๋ค. ํญ๋ง๋ค ์ค๋ฐ๊ฟ ์์น๋ง ๋ค๋ฅธ ํ
์คํธ๋ <Box as="br" display={[...]} />๋ก ์ฐ๊ณ , ์ปดํฌ๋ํธ ์ธ์คํด์ค์ variant prop์ด ํญ๋ง๋ค ๋ค๋ฅด๋ฉด ๋ฐฐ์ด๋ก ์ธ ์ ์์ผ๋ฏ๋ก ๊ฐ์ฅ ๋์ ํญ์ ๊ฐ์ ์ฐ๊ณ responsiveUnrepresented์ ๋ณด๊ณ ํฉ๋๋ค. ํจ๊ป ๋ฐํ๋๋ responsiveSlots, responsiveImports, responsiveComponents๊ฐ slot๊ณผ import ๋ชฉ๋ก์
๋๋ค.
rawPayload๋ rawSnapshot์ด node ํธ๋ฆฌ๋ง ์ฐ๋ ๊ฒ๊ณผ ๋ฌ๋ฆฌ ์์ง ์ ์ฒด(variables, styles, stats, assets ํฌํจ, referencePng ์ ์ธ)๋ฅผ ์๋๋ค. ์บก์ฒ๋ฅผ fixture๋ก ๋ณด๊ดํด ์คํ๋ผ์ธ์์ ์๋ฒ์ ๊ฐ์ ํ ํฐ ์ด๋ฆ($gray200, typography="h4")์ผ๋ก ๋ณํํ๋ ค๋ฉด ์ด๊ฒ์ด ํ์ํฉ๋๋ค.
frame์ After delay ํธ๋ฆฌ๊ฑฐ๋ก ๋ค๋ฅธ frame์ Smart animateํ๋ reaction์ด ์๊ณ , ๊ทธ frame์ด ๋ค์ ๋ค์ frame์ผ๋ก ์ด์ด์ง๋ฉด ํ๋์ ์ฒด์ธ์
๋๋ค(์ฒ์ frame์ผ๋ก ๋์์ค๋ฉด ๋ฃจํ). ์ฒด์ธ์ frame๋ค์ ์์ฒญํ node์ subtree ๋ฐ์ ์๋ ํ์ frame์ด๋ฏ๋ก, ์์ฒญ ๋ฃจํธ๊ฐ ํ๋์ผ ๋ snapshot ์คํฌ๋ฆฝํธ๊ฐ ์ฒด์ธ์ ๋ฐ๋ผ๊ฐ๋ฉฐ ์ถ๊ฐ ๋ฃจํธ๋ก ํจ๊ป ์์งํฉ๋๋ค(๋ค์ค ๋ฃจํธ ์์ฒญ์ ๋ฃจํธ ๋ชฉ๋ก์ ๊ทธ๋๋ก ๋ก๋๋ค).
๋ณํ๊ธฐ๋ ํ๋ฌ๊ทธ์ธ์ getReactionProps ๊ท์น๋๋ก frame ์ฌ์ด์์ ๋ฐ๋๋ ๊ฒ โ ์์น, ํฌ๊ธฐ, opacity, ์ฒซ fill, ํ์ (๋์ delta) โ ์ ์ด๋ฆ์ด ๊ฐ์ ์์์์ ๋จผ์ ์ฐพ์ ์์๋ง๋ค animationName={keyframes({...})} / animationDuration / animationTimingFunction / animationFillMode / animationIterationCount(๋ฃจํ๋ฉด infinite)๋ก ์ฐ๊ณ , ๋ฐ๋๋ ์์์ด ์์ ๋๋ง frame ์์ฒด์ ์๋๋ค. 0%๋ ์์ frame, ๊ฐ ๋จ๊ณ๋ ๋์ฐฉ ์์ ์ ํผ์ผํธ์ ์ง์ keyframe๊ณผ ๋ค๋ฅธ ์์ฑ๋ง, ๋ฃจํ๋ 100%์์ ์์ ๊ฐ์ผ๋ก ๋ซํ๋ฉฐ duration์ ๋๋์๊ฐ๋ ๊ตฌ๊ฐ๊น์ง ์
๋๋ค. 10ms ๋ฏธ๋ง timeout์ delay๋ก ์ฐ์ง ์์ต๋๋ค. keyframes๊ฐ ์ฐ์ด๋ฉด @devup-ui/react์์ import๋ฉ๋๋ค.
snapshot์ ์๋ ๋ชฉ์ ์ง(legacy ๊ฒฝ๋ก, ๋ค์ค ๋ฃจํธ ์์ฒญ)๋ ์กฐ์ฉํ ๋ฒ๋ฆฌ์ง ์๊ณ DEVUP_CODEGEN_ANIMATION_UNREACHABLE diagnostic์ผ๋ก ๋ณด๊ณ ํฉ๋๋ค.
{
"url": "https://www.figma.com/design/<file-key>/<name>",
"query": "A : STORY-F-PROOFREAD",
"nodeTypes": ["PAGE", "SECTION", "FRAME", "COMPONENT_SET"],
"match": "normalized",
"limit": 20
}๊ฒ์ ๋ฒ์๋ URL์ด ์ ํฉ๋๋ค. node-id๊ฐ ์์ผ๋ฉด ๊ทธ ๋
ธ๋์ ๊ทธ subtree๋ง, ์์ผ๋ฉด ํ์ผ ์ ์ฒด๋ฅผ ๋ด
๋๋ค. ์๋ต์ scope๊ฐ ์ค์ ๋ก ์ด๋ ์ชฝ์ ๊ฒ์ํ๋์ง ๋ณด๊ณ ํ๋ฏ๋ก, ๊ฒฐ๊ณผ๊ฐ ๊ธฐ๋์ ๋ค๋ฅผ ๋ ๋ฒ์ ๋๋ฌธ์ธ์ง ์ด๋ฆ ๋๋ฌธ์ธ์ง ๊ตฌ๋ถํ ์ ์์ต๋๋ค. limit์ ๋ฐํํ ์ผ์น ๊ฐ์์
๋๋ค.
ํ์ผ ์ ์ฒด ๊ฒ์์ ๋จผ์ read-only Plugin API๋ก ์ค์ figma.root.children page catalog๋ฅผ ์ป๊ณ , page๋ง๋ค ํ ๋ฒ์ฉ ์ ํํ๋ ์์ query projection์ ๋ณ๋ ฌ ์คํํฉ๋๋ค. ์ ์ฒด page snapshot์ ์๋ตํ์ง ์์ผ๋ฏ๋ก ํฐ ํ์ผ์์๋ ๊ณต์ MCP text ์ํ์ ํผํฉ๋๋ค. ๊ฒฐ๊ณผ๋ ์๋ฌธ exact, Unicode NFCยท๊ณต๋ฐฑยท๋์๋ฌธ์๋ฅผ ์ ๊ทํํ exact, prefix, contains ์์ผ๋ก ์ ๋ ฌํ๊ณ match: "fuzzy"์ผ ๋๋ง ์คํ ํ์ฉ ๊ฒ์์ ์ถ๊ฐํ๋ฉฐ, node ID, type, page, ์ ์ฒด breadcrumb์ ํ์ devup_figma_export์ ๊ทธ๋๋ก ์ ๋ฌํ canonical URL์ ํฌํจํฉ๋๋ค.
{
"url": "https://www.figma.com/design/<file-key>/<name>?node-id=1-2",
"limit": 50,
"includeTextPreview": true,
"refresh": false
}์๊ตฌ์ฌํญ ์ ๋ชฉ์ด๋ ์ค๋ช
node ๋งํฌ๊ฐ ์ค์ ๊ตฌํ ํ๋ฉด์ด ์๋ ๋ devup_figma_explore๋ฅผ ๋จผ์ ํธ์ถํฉ๋๋ค. url์๋ node-id๊ฐ ์์ด์ผ ํ๊ณ (์์ผ๋ฉด DEVUP_FIGMA_NODE_NOT_FOUND), limit์ 1~100 ๋ฒ์ ๋ฐ์ด๋ฉด ๊ฑฐ์ ๋ฉ๋๋ค. anchor์ ๊ฐ์ ๊ณต๊ฐ ๋ฌถ์์ frame/component ํ๋ณด๋ฅผ ์๊ฐ ์์์ canonical URL๋ก ๋ฐํํ๋ฉฐ, ๋ค์ ์๊ตฌ์ฌํญ ์ ๋ชฉ์์ ํ์ ๋ฒ์๋ฅผ ๋๋
๋๋ค.
limit์ ๋ฐํํ ํ๋ณด ๊ฐ์์ผ ๋ฟ์ด๊ณ ๊ทธ ์ด์ ์๋ฌด๊ฒ๋ ์๋๋๋ค. ๋์์ธ์ ์ผ๋ง๋ ์ฝ์์ง๋ ๋ฐ๊พธ์ง ์์ผ๋ฏ๋ก(ํฌ์ ์์ฐ์ ํญ์ ๊ณ ์ ์
๋๋ค), limit์ ์ฌ๋ ค์ ํ ์ ์๋ ์ผ์ ๋ต์ ๊ธธ๊ฒ ๋ง๋๋ ๊ฒ๋ฟ์
๋๋ค. ์์ ์๋ limit์ด ํฌ์ ์์ฐ์ผ๋ก 4๋ฐฐ ํ๋๋ผ 30โ33์ผ๋ก ์ฌ๋ ธ๋๋ ํ๋ณด๊ฐ 23โ18๋ก ์ค์ด๋๋ ์ผ์ด ์์์ต๋๋ค.
์๋ฆฐ ์ด์ ๋ ์ด์ ๋๋ก ๋๋ ๋ณด๊ณ ํฉ๋๋ค.
truncation.candidatesโlimit์ด ๋ชฉ๋ก์ ์๋๋ค๋ ๋ป์ ๋๋ค.limit์ ์ฌ๋ฆฌ๋ฉด ๋๋จธ์ง๊ฐ ๋์ต๋๋ค.truncation.projectionโ ์์งํ ์ค๋ ์ท ์์ฒด๊ฐ ๋ถ์์ ํ๋ค๋ ๋ป์ ๋๋ค.limit์ ์๋ฌด๋ฆฌ ์ฌ๋ ค๋ ๊ทธ ํ๋ฉด๋ค์ ๋์์ค์ง ์์ต๋๋ค.
์ต์์ truncated๋ ๋์ OR์
๋๋ค. ๋์ ๊ตฌ๋ถํ์ง ๋ชปํ๋ฉด ๊ณ ์น ์ ์๋ ์ํฉ์์ limit๋ง ์ฌ๋ฆฌ๋ฉฐ ํธ์ถ์ ๋ฐ๋ณตํ๊ฒ ๋ฉ๋๋ค.
includeTextPreview๋ ๋ณ๋ ์์ฐ์ ์๋๋ค. ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ๊ตฌ์กฐ ํฌ์์ด ์ฐ๊ณ ๋จ๊ธด ๊ณต๊ฐ๋ง ์๋นํ๋ฏ๋ก, ์ผ๊ณ ๋๋ ๊ฒ์ด ํ๋ณด ๊ฐ์ยทIDยทtruncation.projection ์ค ๋ฌด์๋ ๋ฐ๊พธ์ง ์์ต๋๋ค. ๊ฐ์ ํ์ผยท์ต์
์์ ์ด๋ฏธ ์์งํ ๋ ํฐ ํ์ ๊ฒฐ๊ณผ๋ exactยทrelated-nodeยทsuperset ๋ฒ์๋ก ์ฌ์ฌ์ฉ๋๊ณ , ๋์์ ๋ค์ด์จ ํธํ ์์ฒญ๋ ๊ณต์ Figma ํธ์ถ ํ๋๋ฅผ ๊ณต์ ํฉ๋๋ค. refresh: true๋ ๋ชจ๋ ์ฌ์ฌ์ฉ์ ๊ฑด๋๋๋๋ค. ์ํ๋ ํ๋ณด์ canonical URL์ devup_figma_export์ ๋๊ฒจ ์ ํํ ํ๋ฉด๋ง ๋ณํํฉ๋๋ค.
ํ์๊ณผ ๊ฒ์์ ๋ณ์ catalog๋ฅผ ์์งํ์ง ์์ต๋๋ค. ์ ํํ UI ๋ณํ ๋จ๊ณ์์ ์ ํ subtree์ ๋ชจ๋ ๋ณด์กด ํ๋์ ์๋ VARIABLE_ALIAS์ paint/text/effect/grid style ID๋ฅผ ์ฌ๊ท์ ์ผ๋ก ์ค์บํ๊ณ , ์ค์ ์ฌ์ฉ๋ ID๋ง ๊ณต์ Figma API๋ก ์กฐํํฉ๋๋ค. outputs: ["devupJson"]์ scope: "file"์ ํจ๊ป ์ค ๊ฒฝ์ฐ์๋ง file ์ ์ฒด ๋ก์ปฌ catalog๋ฅผ ์์งํฉ๋๋ค.
sourcePolicy ํ๋ผ๋ฏธํฐ๋ auto์ direct ๋ ๋ค ๊ฐ์ ๋์์ด์์ผ๋ฏ๋ก ์ ๊ฑฐํ์ต๋๋ค โ ๋ถ๊ธฐํ์ง ์๋ ์ ํ์ง๋ ํธ์ถ์์๊ฒ ํ๋ฆด ๊ธฐํ๋ง ์ฃผ์์ต๋๋ค. ๊ฒฝ๋ก ์ ํ์ ํ๋ผ๋ฏธํฐ๊ฐ ์๋๋ผ ํ๋ฌ๊ทธ์ธ์ด ๋ถ์ด ์๋์ง๊ฐ ์ ํฉ๋๋ค: ๋ถ์ด ์์ผ๋ฉด ๋ธ๋ฆฌ์ง, ์๋๋ฉด direct์
๋๋ค. direct ๊ฒฝ๋ก๋ ์ฐ๊ฒฐ๊ณผ read-only capability catalog ์กฐํ๋ฅผ ๊ฐ๊ฐ 30์ด, ๊ฐ๋ณ tool ํธ์ถ์ 5๋ถ์ผ๋ก ์ ํํฉ๋๋ค. deadline์ ๋๊ธฐ๋ฉด ํด๋น remote session์ ํ๊ธฐํ๊ณ ๋์์ธ ์๋ฌธ ์์ด retryable timeout ๋จ๊ณ๋ง ๋ฐํํฉ๋๋ค.
์ ํํ node ๋งํฌ์ UI ๋ณํ์ ํ๋ ์ด์์ ๊ณต์ use_figma ํธ์ถ ์์์ subtree์ ์ค์ ์ฌ์ฉ ๋ฆฌ์์ค๋ฅผ ์์งํฉ๋๋ค. ์์ง ์คํฌ๋ฆฝํธ๋ checked-in manifest(devup-ui ๋ณํ๊ธฐ๊ฐ ์ค์ ๋ก ์ฝ๋ ํ๋๋ง)๋ง ํ์ธํ๊ณ โ ํ๋กํ ํ์
์ฒด์ธ ์ ์ฒด๋ฅผ ํ๊ฑฐ๋ ๋ฏธ๋ถ๋ฅ ํ๋๋ฅผ extra์ ๋ด์ง ์์ต๋๋ค โ null/๋น ๋ฐฐ์ด/๋ฏธ๋ฐ์ธ๋ฉ style ID ๊ฐ์ ๊ธฐ๋ณธ๊ฐ์ ๋ดํฌ์์ ์๋ตํฉ๋๋ค. ๊ฒฐ๊ณผ๋ ํญ์ ํ
์คํธ(devupFastSnapshotEnvelope)์ด๋ฉฐ PNG ๊ฐ์ ๋ฐ์ด๋๋ฆฌ transport๋ ์์ต๋๋ค. ํ subtree๊ฐ 15KB ํ
์คํธ ํ๋๋ฅผ ๋์ผ๋ฉด ๊ฐ์ ์คํฌ๋ฆฝํธ๋ฅผ offset์ ์ฎ๊ฒจ ๋ค์ ํธ์ถํ๋ ๋ฐฉ์์ผ๋ก ํ
์คํธ ํ์ด์ง๋ค์ด์
ํฉ๋๋ค โ ๊ฐ ๋ผ์ด๋๋ ๊ทธ ๋ผ์ด๋๊ฐ ๋ณด๋ธ node์์๋ง ๋ฆฌ์์ค๋ฅผ ์ค์บํด ์๊ธฐ ์๊ฒฐ์ ์ด๋ฉฐ, Rust๊ฐ ์ฌ๋ฌ ๋ผ์ด๋์ node์ ๋ฆฌ์์ค๋ฅผ ๋ณํฉํฉ๋๋ค. Rust๋ schemaยท๋์ IDยทnode graphยท๋ฆฌ์์ค ์ฐธ์กฐยท(ํ์ด์ง ์ค์ด ์๋ ๋์) ์์ ์์ ์ฑ์ ๋ชจ๋ ๊ฒ์ฆํ ๋ค์๋ง ๊ฒฐ๊ณผ๋ฅผ ์ฑํํฉ๋๋ค. ํ ํญ๋ชฉ์ด๋ผ๋ ๋ถ์ผ์นํ๋ฉด fast ๊ฒฐ๊ณผ ์ ์ฒด๋ฅผ ๋ฒ๋ฆฌ๊ณ ๊ธฐ์กด cursor ์์ง์ 0๋ถํฐ ์ฌ์์ํฉ๋๋ค. Section multi-root์์๋ ์ฑ๊ณตํ root์ resource๋ ๊ทธ๋๋ก ๋ณด์กดํ๊ณ ์คํจํ๊ฑฐ๋ ์ํ์ ๋์ root๋ง legacy๋ก ๋ค์ ์์งํ ๋ค ์๋ ์๊ฐ ์์๋ก ํฉ์นฉ๋๋ค. direct upstream์ ์ฐ๊ฒฐ๊ณผ read-only tool catalog๋ฅผ ํ session์์ ์ฌ์ฌ์ฉํ๊ณ 30์ด TTL, ์ฐ๊ฒฐ ์ข
๋ฃ ๋๋ transport ์ค๋ฅ ๋๋ง ์ฌ์ฐ๊ฒฐยท์ฌ๊ฒ์ฆํฉ๋๋ค. ๊ฒฐ๊ณผ์ stats์๋ figmaToolCalls, transport(text | text-paginated | legacy-cursor), fallbackUsed, node/variable/style ์์ byte ์๋ง ํฌํจ๋๋ฉฐ ์๋ณธ ๋์์ธ์ด๋ ์ธ์ฆ ์ ๋ณด๋ ํฌํจ๋์ง ์์ต๋๋ค.
์์ ์ฑ ๋ฑ๊ธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
full-local-plus-used-remote: ๋ก์ปฌ ์ ์ฒด์ ์ฌ์ฉ๋ ์ธ๋ถ token์ ๋ชจ๋ ํ์ธused-tokens: ํ๋ณดํ token๋ง ๋ณํํ์ผ๋ฉฐ ์ธ๋ถ ์ ์ฒด๋ฅผ ๋ณด์ฅํ์ง ์์resolved-values-only: ์๋ฏธ ์๋ token binding ์์ด ๊ณ์ฐ๊ฐ๋ง ํ๋ณด
scope๋ theme(ํ๋ก์ ํธ devup.json), api(openapi.json), db(Vespertide models/*.json), all์
๋๋ค. ํธ์ถ ์์ ์ ๋์คํฌ์ ์ค์ ๋ก ์๋ ํ์ผ๋ง ์ฝ๊ณ , ์ธ์
๊ฐ ์บ์ํ์ง ์์ผ๋ฉฐ, ์๋ ๊ฒ์ ์ถ์ธกํ์ง ์์ต๋๋ค. ์ค์บ ๊น์ด๋ 4๋จ๊ณ์
๋๋ค.
๋ค์ ๋๋ ํฐ๋ฆฌ๋ ์ค์บํ์ง ์์ต๋๋ค.
- ๋น๋ยท์์กด์ฑ ์ฐ์ถ๋ฌผ:
node_modules,target,dist,build,out,.next,.turbo,.nuxt,.venv,venv,__pycache__,.cache,coverage,.git - ์ค์ฒฉ ์ฒดํฌ์์:
.worktrees,.worktree,.git-worktrees
์ ์ธ๋ ์กฐ์ฉํ ์ผ์ด๋์ง ์์ต๋๋ค. ๋ฌด์ธ๊ฐ๋ฅผ ๊ฑด๋๋ฐ์์ผ๋ฉด excludedPaths[]์ path์ reason(nested-checkout-directory ๋๋ nested-git-checkout)์ผ๋ก ๋ณด๊ณ ํฉ๋๋ค. ํ์ผ์ ํ๋๋ ๋ชป ์ฐพ์๋๋ฐ ์ ์ธํ ๊ฒ์ด ์์ผ๋ฉด ๊ทธ ์ฌ์ค๋ ํจ๊ป ๋ณด๊ณ ํ๋ฏ๋ก, "์์"๊ณผ "์ ์ธํด์ ์ ๋ณด์"์ ๊ตฌ๋ถํ ์ ์์ต๋๋ค. ์์ ์๋ ์คํ
์ผ ๋ธ๋์น์ devup.json์ด ๊ถ์ ์๋ ๊ฒ๊ณผ ์์ฌ 4๊ฐ๊ฐ ๋ฐํ๋๊ณ , ์ด๋ ๊ฒ์ด ๋ง๋์ง ํ์๊ฐ ์์์ต๋๋ค.
๊ฐ์ ์ข
๋ฅ์ ํ์ผ์ด ์ฌ๋ฌ ๊ฐ์ผ ๋๋ ๊ฐ ํญ๋ชฉ์ด authority(project-root | package-local)์ appliesTo(์ ์ฉ ๋๋ ํฐ๋ฆฌ)๋ฅผ ๊ฐ๊ณ , authorityNote๊ฐ ์ด๋ ํ๋๋ ํ๋ก์ ํธ ์ ์ฒด๋ฅผ ์ง๋ฐฐํ์ง ์๋๋ค๋ ์ฌ์ค์ ์๋ ค์ค๋๋ค. ์ฝ๋๋ฅผ ์ฐ๋ ํ์ผ์ด ์ด๋ appliesTo ์์ ์๋์ง๋ก ๊ณจ๋ผ์ผ ํฉ๋๋ค.
์๋ต์ ๋ค์์ ๋ด์ต๋๋ค.
| ํ๋ | ๋ด์ฉ |
|---|---|
ok |
์ฌ๊ฐ๋๋ก ํ์ . error๊ฐ ์์ผ๋ฉด ์คํจ, strict: true๋ฉด warning๋ ์คํจ |
okReason |
clean ยท info-only ยท warnings-only ยท warnings-and-info ยท strict-warnings ยท error-violations |
violations[] |
rule, severity(info|warning|error), byteRange, message, suggestion |
violationCounts |
error / warning / info ๊ฐ์ |
themeNotes[] |
๋น์ด ์๋ ํ ํฐ ์นดํ ๊ณ ๋ฆฌ๋ฅผ ์ข ๋ฅ๋ง๋ค ํ ๋ฒ์ฉ๋ง ์์ฝ |
tokens |
referencedByTsx, definedByTheme, unknownTokenCheckRan |
checkedTokens / availableTokenCount |
์ ๋ ๊ฐ๊ณผ ๊ฐ์ ์๋ฅผ ์์ ์ด๋ฆ์ผ๋ก ์ ์ง |
themeAvailable / themeGuardrail |
ํ ๋ง๋ฅผ ์ฐพ์๋์ง, ๋ชป ์ฐพ์์ผ๋ฉด ์ |
๊ท์น์ invalid-syntax, unknown-token, hardcoded-color, hardcoded-length, unknown-prop, runtime-value์
๋๋ค.
ํ๋์ฝ๋ฉ ๊ฐ์ ํ์ ๊ธฐ์ค์ ์ผ์นํ๋ ํ ํฐ์ด ์ค์ ๋ก ์๋์ง์
๋๋ค. ์์ผ๋ฉด warning์ผ๋ก ์ฌ๋ฆฌ๊ณ ํ ํฐ ์ด๋ฆ์ ์๋ ค์ค๋๋ค. ์์ผ๋ฉด info๋ก ๋ฎ์ถ๊ณ ๊ถ๊ณ ์์ด ์ฌ์ค๋ง ์ ์ผ๋ฉฐ strict ๋ชจ๋์์๋ ์คํจ์ํค์ง ์์ต๋๋ค. ๊ทธ๋์ length ํ ํฐ์ด ํ๋๋ ์๋ ํ
๋ง๊ฐ "ํ ํฐ์ ์ฐ๋ผ"๋ ๊ถ๊ณ ๋ฅผ ๋ฐ๋ ์ผ์ ์๊ณ , ๋์ themeNotes๊ฐ "์ด ํ
๋ง์๋ length ํ ํฐ์ด ์๋ค"๊ณ ํ ๋ฒ ์๋ ค์ค๋๋ค.
checkedTokens์ availableTokenCount๋ ์๋ก ๋ค๋ฅธ ๊ฒ์ ์
๋๋ค โ ์์ ์ด TSX๊ฐ ์ฐธ์กฐํ $token ์, ๋ค๋ devup.json์ด ์ ์ํ ํ ํฐ ์์
๋๋ค. ๋น์จ์ด ์๋๋๋ค. tokens๊ฐ ๊ทธ ์ฌ์ค์ ์ด๋ฆ์ผ๋ก ๋ค์ ๋งํด ์ค๋๋ค.
๋ ์ด์ด๋ db-entity, entity-route, route-openapi, openapi-client ๋ท์ด๋ฉฐ ์๋ตํ๋ฉด ์ ๋ถ ์คํํฉ๋๋ค. ์ปดํ์ผ๋ฌ๊ฐ ์๋๋ผ ํ
์คํธ/JSON ํด๋ฆฌ์คํฑ์ด๋ฏ๋ก ๋ชจ๋ ๋ฐ๊ฒฌ์ confidence๋ฅผ ๋ฌ๊ณ ๋์ค๊ณ , ๊ทธ ๊ฐ์ low ๋๋ medium์
๋๋ค โ high๋ ์์ต๋๋ค.
_์ -์ ์ฐจ์ด๋ ๋์กฐํ ๋๋ง ์ ์ต๋๋ค. Vespera๊ฐ openapi.json์ kebab-case๋ฅผ ์ฐ๊ณ ์ฝ๋๋ ์๋ฌธ์ ์ฐ๊ธฐ ๋๋ฌธ์
๋๋ค. ๋ณด๊ณ ๋๋ ๋๋ฆฌํํธ๋ ๊ฐ ๋ ์ด์ด๊ฐ ์ค์ ๋ก ์ด ์ฒ ์ ๊ทธ๋๋ก ์ฃ๊ณ , ์ ๊ทํ๋ก ์ผ์น์ํจ ๊ฑด์๋ spellingNormalizedMatches๋ก ๋ฐ๋ก ๊ณต๊ฐํฉ๋๋ค. ๊ฐ์ ๋ผ์ฐํธ๊ฐ ์ธ๋์ค์ฝ์ดํ๊ณผ ํ์ดํํ์ผ๋ก ์์ชฝ์ ์ค๋ณต ์ ๊ณ ๋๋ ๋ฌธ์ ๋ ์ด ๋ฐฉ์์ผ๋ก ์ฌ๋ผ์ง๋๋ค.
actual.png ํ๋์ reference PNG ํ๋๋ฅผ ๋น๊ตํฉ๋๋ค. reference๋ ๊ฒฝ๋ก๋ก ์ฃผ๊ฑฐ๋ artifactId๋ก ์บ์๋ ๊ฒ์ ๊ฐ๋ฆฌํต๋๋ค. ๊ธฐ๋ณธ threshold๋ 0.005(0.5%)์ด๊ณ , ์ํ๋ฉด diff PNG๋ฅผ auto | inline | resource๋ก ๋ฐ์ต๋๋ค.
์ด ๋๊ตฌ๋ ์ค์ค๋ก ๊ทธ๋ฆฌ์ง ์์ต๋๋ค. ๋ธ๋ผ์ฐ์ ๋ฅผ ๋์ฐ์ง๋, ๋ช
๋ น์ ์คํํ์ง๋ ์์ต๋๋ค. actual.png๋ ์๋น์ repository๊ฐ ์๊ธฐ fontยทassetยทDevupUI ํ๊ฒฝ์์ ๋ง๋ค์ด ๊ฑด๋ค๋ ๊ฒ์ด๊ณ , ์ฌ๊ธฐ์๋ ์์ Rust๋ก ํฝ์
๋ง ๋น๊ตํฉ๋๋ค. ๊ฒฝ๋ก๋ allowlist ์์ด์ด์ผ ํฉ๋๋ค.
๊ทธ๋์ ํต๊ณผ ์ฌ๋ถ๋ณด๋ค ํ์ ๊ทผ๊ฑฐ๊ฐ ์ค์ํฉ๋๋ค. renderer ํ๊ฒฝ manifest๊ฐ ์๊ฑฐ๋ ๋ถ์์ ํ๊ฑฐ๋ ์ ํจํ์ง ์์ผ๋ฉด, ํฝ์
์ด ์ผ์นํด visual.passed๊ฐ true์ฌ๋ ์ต์ข
ํ์ ์ inconclusive์
๋๋ค โ ๋ฌด์์ผ๋ก ๊ทธ๋ฆฐ ๊ทธ๋ฆผ์ธ์ง ๋ชจ๋ฅด๋ ์ฑ "๊ฐ๋ค"๊ณ ๋งํ๋ ๊ฒ์ ๋ณด์ฆ์ด ์๋๊ธฐ ๋๋ฌธ์
๋๋ค. renderer pinning๊ณผ ํ๊ฒฝ manifest ๊ณ์ฝ์ docs/visual-renderer-contract.md์ ์์ต๋๋ค.
ํ๋ฉด๋ถํฐ ์ปฌ๋ผ๊น์ง ํ ๊ธฐ๋ฅ์ ์ฌ๋ผ์ด์ค๋ฅผ ์ฝ์ด acceptance matrix๋ก ๋๋ ค์ค๋๋ค. ์ถ๋ฐ์ ์ ๋ช
์์ anchor์ฌ์ผ ํฉ๋๋ค โ routePath, figmaNodeId ๋๋ artifactId, operationId ๋๋ apiPath+method, componentPath, tableName.
์๊ตฌ์ฌํญ ์ฐ๋ฌธ์ anchor๊ฐ ์๋๋๋ค. "๋ก๊ทธ์ธ ํ๋ฉด ๋ง๋ค์ด์ค" ๊ฐ์ ๋ฌธ์ฅ๋ง ์ฃผ๋ฉด ์ถ์ธกํด์ ๋ตํ์ง ์๊ณ ๊ฑฐ์ ํฉ๋๋ค. ๊ทผ๊ฑฐ ์์ด ์ด์ด ๋ถ์ธ ์ฌ๋ผ์ด์ค๋ ํ๋ ธ์ ๋ ์ด๋์ ํ๋ ธ๋์ง ์ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
๊ฐ hop์ ๊ทผ๊ฑฐ๊ฐ ์๊ฑฐ๋ UNVERIFIED๋ก ํ์๋๋ฉฐ, ์์ฑ ์ฐ์ถ๋ฌผ์ ์์ ๊ถ(๊ทธ ํ์ผ์ ์์ผ๋ก ๊ณ ์น๋ฉด ์ ๋๋์ง), ์์๊ฐ ๋งค๊ฒจ์ง UI ์ฌ์ฌ์ฉ ํ๋ณด, ๋์์ธ์ ๋ฌธ์์ด๊ณผ request/response ํ๋์ ๋์, ํ์ ์ํ ์ปค๋ฒ๋ฆฌ์ง, ๊ทธ๋ฆฌ๊ณ ์๋ฆผ์ด ์ผ์ด๋ฌ๋ค๋ฉด ๊ทธ ์ํ์ ํจ๊ป ๋ณด๊ณ ํฉ๋๋ค. requirement์ acceptanceCriteria๋ฅผ ๋๊ธฐ๋ฉด ํด์ํ์ง ์๊ณ ๊ทธ๋๋ก ์ค์ด ๋๋ ค์ค๋๋ค.
์ ์ ํ์ฑ์ ๋ฐํ์ ๋์์ ์ฆ๋ช ํ์ง ์์ต๋๋ค. ์ด ๋๊ตฌ๊ฐ "์ฐ๊ฒฐ๋ผ ์๋ค"๊ณ ๋งํ๋ ๊ฒ์ ์ฝ๋๊ฐ ๊ทธ๋ ๊ฒ ์ ํ ์๋ค๋ ๋ป์ด์ง, ์คํํ์ ๋ ๊ทธ๋ ๊ฒ ๋์ํ๋ค๋ ๋ป์ด ์๋๋๋ค.
- upstream ํธ์ถ์
get_metadata,get_variable_defs,get_design_context,get_code_connect_map,get_screenshot๊ณผ ๋ด์ฅ๋ read-onlyuse_figmascript๋ก ๋ซํ ์์ต๋๋ค. - ์ฌ์ฉ์ ์
๋ ฅ JavaScript๋ฅผ ๋ฐ์ง ์์ผ๋ฉฐ Figma document mutation API๋ฅผ ํธ์ถํ์ง ์์ต๋๋ค.
figma.io.write๋ asset export(devup_figma_export์assetRequests)์๋ง read-only๋ก ์ฌ์ฉํ๋ฉฐ Figma ํ์ผ์ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค. fast snapshot/theme envelope๋ ํญ์ ํ ์คํธ๋ก๋ง ๋ฐํ๋๋ฉฐ ๋ฐ์ด๋๋ฆฌ transport๋ฅผ ์ฐ์ง ์์ต๋๋ค. - stdout์๋ MCP frame๋ง ์ถ๋ ฅํ๊ณ trace๋ stderr๋ก ๋ณด๋ ๋๋ค.
- access token, refresh token, OAuth code, PKCE verifier๋ Debug, trace์ MCP error์ ํฌํจํ์ง ์์ต๋๋ค.
- Figma snapshot๊ณผ screenshot์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋์คํฌ์ ์ ์ฅํ์ง ์์ต๋๋ค.
- screenshot, asset, TSX resource๋ bounded memory artifact์ ๊ฐ์ TTL์ ๊ฐ์ง๋ฉฐ resource manifest์๋ ์ด๋ฆยทMIMEยทํฌ๊ธฐยทhash๋ง ๋ ธ์ถ๋ฉ๋๋ค.
- ํธํ์ฑ fixture๋ ๊ณ ์ ํ JavaScript ํ๋ฌ๊ทธ์ธ์ 268๊ฐ synthetic ์ ๋ ฅ์ ๋๋ค. ๋ณ๋์ WQUW-151 ํ๊ท fixture๋ ๊ณต์ MCP์์ read-only๋ก ์์งํ ๋์์ธ node/ํ ์คํธ/token ์ด๋ฆ๋ง ํฌํจํ๋ฉฐ OAuth token, header, callback parameter, ์ฌ์ฉ์ ๊ณ์ ยทemail์ ํฌํจํ์ง ์์ต๋๋ค.
fixtures/devup-figma-plugin์ dev-five-git/devup-figma-plugin์ ๊ณ ์ commit 243db650f1d635ab5385546a2a297eae4ea93515์์ ์์งํ 54๊ฐ test file๊ณผ 978๊ฐ passing-test inventory๋ฅผ ์ถ์ ํฉ๋๋ค. upstream test 252๊ฐ๊ฐ ๋ง๋ JSON/golden 268์์ Rust serde/codegen ๊ฒฝ๋ก์์ byte parity๋ฅผ ์ ๋ถ ์คํํ๊ณ , 666๊ฐ๋ ๊ฐ์ ๋์ ์์ญ์ ์ค์ Rust assertion์ ์ฐ๊ฒฐํ์ต๋๋ค. ๋๋จธ์ง๋ plugin module/codegen handler/iframe/notify/browser download ์๋ช
์ฃผ๊ธฐ 38๊ฐ์ read-only MCP๊ฐ ์๋์ ์ผ๋ก ์ํํ์ง ์๋ Figma document/style/import write 22๊ฐ์
๋๋ค. not_ported๋ 0๊ฐ์ด๋ฉฐ, ๋น-parity ํญ๋ชฉ๋ ๊ตฌ์ฒด์ ์ธ MCP ๊ฒฝ๊ณ test๋ฅผ ๊ฐ๋ฆฌํต๋๋ค. ์ฆ ์ ํํ ๋ณด์ฅ์ โ268/268 snapshot byte parity, 666๊ฐ ์คํ ๊ฐ๋ฅํ ๋ํ Rust assertion ์ฐ๊ฒฐ, 60๊ฐ ๋ช
์์ runtime/write ๊ฒฝ๊ณ, 978-entry inventoryโ์ด๊ณ JavaScript assertion 978๊ฐ๋ฅผ ๊ฐ๊ฐ ๋ณ๋ fixture๋ก ๋ณต์ ํ๋ค๋ ๋ป์ ์๋๋๋ค. manifest๋ LF๋ก ์ ๊ทํํ fixture์ snapshot 536๊ฐ ํ์ผ์ SHA-256์ ๊ฒ์ฆํ๊ณ , coverage registry๋ ledger๊ฐ ์ค์ Rust test symbol ๋๋ ๊ทผ๊ฑฐ๊ฐ ์๋ ๋น-parity ๋ถ๋ฅ๋ง ์ฐธ์กฐํ๋๋ก ๊ฐ์ ํฉ๋๋ค. ์์ธ ๋ถ๋ฅ์ ์คํ ๋ฐฉ๋ฒ์ fixtures/devup-figma-plugin/README.md๋ฅผ ์ฐธ๊ณ ํ์ธ์.
crates/devup-mcp/tests/live_figma_contract.rs๋ ๊ธฐ๋ณธ์ ์ผ๋ก ignore๋ฉ๋๋ค. DEVUP_MCP_LIVE_FIGMA=1์ ์ค์ ํ๊ณ ๊ณต์ MCP์ fast use_figma ๊ฒฐ๊ณผ๋ฅผ stdin์ ํ ์ค๋ก ์ ๋ฌํ๋ฉด ์ค์ payload๋ฅผ ๋์คํฌ์ ์ฐ๊ฑฐ๋ ์ถ๋ ฅํ์ง ์๊ณ envelope ๋ฌด๊ฒฐ์ฑ, serde round-trip, ์์ฒญ context, node/๋ฆฌ์์ค ์์ DevupUI codegen์ ๊ฒ์ฆํ๊ณ ์์ ํ count/hash ์์ฝ๋ง ์ถ๋ ฅํฉ๋๋ค. ๋ณ๋์ ๋น-ignore corruption test๋ ๊นจ์ง fast ์๋ต์ด legacy metadata ์์ง์ผ๋ก ์์์ ์ผ๋ก ํด๋ฐฑํ๋์ง ํ์ธํฉ๋๋ค.
crates/devup-mcp-figma/tests/explore_script_behavior.mjs๋ compile-in explore.js ์์ฒด๋ฅผ mock Figma scene graph์์ ์คํํฉ๋๋ค. ๋ ๋จ๊ณ ์ด์ ์ค์ฒฉ๋ ํ๋ฉด์ parent chain, ํ๋ฉด์ด ์๋ 1,000-node Section์ projectionLimit * 8 ๋ฐฉ๋ฌธ ์ํ, ํ์ node๋ง ๋จ๊ธฐ๋ 14,000์ ์ดํ fallback์ ๊ฒ์ฆํ๋ฉฐ CI์ Node ๋ด์ฅ test runner๋ก ์คํ๋ฉ๋๋ค. ์ ํ binary์ ๊ธฐ๋ณธ Cargo test์๋ JavaScript runtime ์์กด์ฑ์ด ์ถ๊ฐ๋์ง ์์ต๋๋ค.
legacy ๊ฒฝ๋ก์์ ์ค์ ํ์ธ๋ ๊ณต์ metadata๋ XML text content envelope์ด๋ฉฐ, local ๋ณ์/style์ catalog ํ resource ๋จ์๋ก ์์งํฉ๋๋ค. style์ consumers์ฒ๋ผ ๋จ์ผ field๊ฐ ๊ณต์ MCP์ text ์ํ(์ค์ธก 20,480 UTF-8 ๋ฐ์ดํธ, ๋๋ ๋งํผ ์๋ฆฌ๊ณ // truncated to 20kb๊ฐ ๋ถ์)์ ๋์ ์ ์์ผ๋ฏ๋ก, base field์ 320๊ฐ ๋จ์์ compact consumer relation์ ๋ถ๋ฆฌํด ์ฝ๊ณ Rust์์ ์๋ exhaustive JSON shape๋ก ์ฌ์กฐ๋ฆฝํฉ๋๋ค. legacy node snapshot๋ byte budget๊ณผ cursor๋ฅผ ์ฌ์ฉํด ๊ฐ์ ์ํ ์๋์์ ์๋ ์ฌ๊ฐํฉ๋๋ค. range์ ๋๋ฝยท์ค๋ณต์ด๋ ์์ง ์ค ๋ชฉ๋ก ๋ณ๊ฒฝ์ ์ฑ๊ณต์ผ๋ก ์จ๊ธฐ์ง ์๊ณ ์ค๋ฅ๋ก ์ฒ๋ฆฌํฉ๋๋ค.
server/mod.rs๋ MCP tool router, service construction, handoff ์ฐ๊ฒฐ๊ณผ ServerHandler๋ง ์์ ํฉ๋๋ค. projection.rs๋ TSX/theme/source-map/asset/reference output ์์ฑ๊ณผ delivery transaction์, validation.rs๋ output/schema/artifact capability ์
๋ ฅ ๊ฒ์ฆ์ ๋ด๋นํฉ๋๋ค. delivery.rs, artifacts.rs, output.rs, resources.rs, quality.rs๋ ๊ฐ๊ฐ ํฌ๊ธฐ ๊ฒฐ์ , memory artifact, allowlisted filesystem transaction, MCP resource protocol, typed ํ์ง ์ง๊ณ๋ฅผ ๋ด๋นํ๋ฉฐ source-level boundary test๊ฐ generator์ filesystem ๊ตฌํ์ด router๋ก ๋๋์์ค๋ ๊ฒ์ ๋ง์ต๋๋ค.
2026-09-01 ์ค์ ํ์ผ ๊ฒ์ฆ์์๋ 13๊ฐ page ์ ์ฒด ๊ฒ์์ผ๋ก [FR-026] ๋ณธ์ฐ์ฒด Section (4217:7743)์ ์ฐพ๊ณ , ๊ทธ ์์ 360ร740 ํ๋ฉด 10๊ฐ๋ฅผ ์๊ฐ ์์๋๋ก ์ธ๋ฑ์ฑํด A : STORY-F-PROOFREAD (3879:35518)๋ฅผ ์ ํํ ๋์์ผ๋ก ์ ํํ์ต๋๋ค. Section ์ ์ฒด fast envelope๋ 8 MiB ์์ ์ํ์ ๋์ด์๋ฏ๋ก ์ฑ๊ณต์ผ๋ก ์ค์ธํ์ง ์๊ณ , ๊ฐ ํ๋ฉด์ ๊ณต์ read-only MCP๋ก ๊ฐ๋ณ ์์งํ์ต๋๋ค. ์ด ํ๋ฉด์ ๊ฐ๊ฐ 15210๊ฐ node๋ฅผ ๊ฐ์ง๋ฉฐ ๋ชจ๋ child, styled text segment, ๋ณ์ 325๊ฐ์ text style 2~13๊ฐ์ ์ฐธ์กฐ ์์ ์ฑ์ ์ค์ JSON fixture์ DevupUI TSX snapshot์ผ๋ก ๊ฒ์ฆํฉ๋๋ค. ๋ํ proofread ํ๋ฉด์ ๊ณต์ read-only MCP 1ํ, 3๊ฐ PNG envelope ์ฒญํฌ์์ 144๊ฐ node, ๋ณ์ 20๊ฐ์ text style 11๊ฐ๋ฅผ ์์งํ๊ณ ํด๋ฐฑ์ ์์์ต๋๋ค. instance children, concrete boolean property, mixed typography, nested [1. ์ด๋ฆ], token binding๊ณผ ๊ฐ๋ณ footer stroke๋ Rust snapshot/live contract๋ก ๊ฒ์ฆํ์ต๋๋ค. ๊ฐ์ ํ์ผ์ ์ ์ฒด theme export๋ legacy ๊ณต์ read-only ํธ์ถ 89๊ฐ๋ฅผ ํตํด collection 1๊ฐ, variable 49๊ฐ, style 37๊ฐ, mode 2๊ฐ๋ฅผ ์์งํด 42,794์ devup.json์ ์์ฑํ์ผ๋ฉฐ diagnostics๋ 0๊ฐ์์ต๋๋ค. ํ์ฌ full-theme fast collector๋ ๊ฐ์ collection/variable/style ์ ์ฒด๋ฅผ ๋จ์ผ read-only use_figma ํธ์ถ๋ก ์์งํ๊ณ , envelope ๊ฒ์ฆ ์คํจ ์์๋ง ์ด legacy ๊ฒฝ๋ก๋ฅผ 0๋ถํฐ ๋ค์ ์์ํ๋๋ก contract test๋ก ๊ณ ์ ํ์ต๋๋ค.
Figma Remote MCP์์๋ JSON_REST_V1 export๊ฐ ํ์ฉ๋์ง ์์ผ๋ฏ๋ก host object๋ฅผ ๊ทธ๋๋ก REST JSON์ผ๋ก ๋ง๋ค ์ ์์ต๋๋ค. ๋์ checked-in property manifest์ runtime prototype/enumerable ํ์์ ํจ๊ป ์ฌ์ฉํด ๋ชจ๋ ๋ฐ๊ฒฌํ data field์ key์ ์ฝ๊ธฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์กดํฉ๋๋ค. ํจ์, ์ํ node object๋ ์ ์ธํ๊ฑฐ๋ id๋ก ๋ฐ๊พธ๊ณ , binary asset์ bytes ๋์ metadata๋ก ๋ํ๋ด๋ฉฐ, ํ plugin private data์ ์ค๋ฅ๋ฅผ ๋ด๋ getter๋ ์ฝ์ ์ ์์ต๋๋ค. ๋จ์ผ ๊ฐ์ด byte budget์ ๋์ผ๋ฉด key๋ฅผ ์์ ์ง ์๊ณ { "$truncated": ..., "byteLength": ... }์ DEVUP_FIELD_VALUE_TRUNCATED๋ฅผ ๋จ๊ธฐ๋ฉฐ, characters, styled segment, resource binding์ฒ๋ผ UI ๋ณํ์ ํ์ํ ๊ฐ์ ์ฐ์ ๋ณด์กดํฉ๋๋ค.
ํ์ฌ private MVP์ ๋จ์ ํ๊ณ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๊ณต์
get_metadata์ file-level page ๋ชฉ๋ก์ ์ค์ page ์ ์ฒด๋ณด๋ค ์ ๊ฒ ๋ฐํ๋ ์ ์์ต๋๋ค. ์ด๋ฆ ๊ฒ์์ Plugin API page catalog์ per-page projection์ผ๋ก ์ฐํํ๋ฉฐ ์ค์ 13๊ฐ page ํ์ผ์์ ๊ฒ์ฆํ์ต๋๋ค. - ๋งค์ฐ ํฐ computed field(์: vector
fillGeometry)๋ ํ์ฌ ๊ฐ ์ ์ฒด ๋์ ๋ช ์์ ์ธ byte-length marker๋ก ๋ณด์กด๋ฉ๋๋ค. ๋ชจ๋ ๋์ฉ๋ field ๊ฐ์ losslessํ๊ฒ exportํ๋ ๊ธฐ๋ฅ์ ํ์ wire-format ๊ฐ์ ๋์์ ๋๋ค. - exact-node fast envelope๊ฐ 8 MiB ์์ ์ํ์ ๋๊ฑฐ๋ ๊ณต์ MCP๊ฐ image transport๋ฅผ ๋ฐ๊พธ๋ฉด ์๋ legacy fallback์ด ์ฌ๋ฌ cursor call์ ์ฌ์ฉํ๋ฏ๋ก subtree ํฌ๊ธฐ์ ๋ฐ๋ผ ์๊ฐ์ด ๋์ด๋ ์ ์์ต๋๋ค.
- direct OAuth registration์ Figma MCP Catalog ์น์ธ์ด ์๋
client_name์ผ๋ก๋ ๊ฑฐ์ ๋ฉ๋๋ค. ์น์ธ๋ ์ด๋ฆ(๊ธฐ๋ณธ๊ฐCodex)์ผ๋ก๋ง ๋ฑ๋ก์ด ์ฑ๋ฆฝํ๋ฉฐ, ๊ทธ ๋ฑ๋ก์ Figma์๊ฒ ํด๋น ์ ํ์ผ๋ก ๊ธฐ๋ก๋ฉ๋๋ค. - ์ฌ์ฉ๋์ง ์์ ์ธ๋ถ Figma library ๋ณ์ ์ ์ฒด๋ Remote MCP๊ฐ ์ ๊ณตํ์ง ์์ ์ ์์ต๋๋ค.
- node/page theme scope๋ ๋ก์ปฌ ๋ณ์ API์ file-wide ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ฉฐ ์ธ๋ฐํ ์ฌ์ฉ ๋ฒ์ ํํฐ๋ ํ์ ๋ณด๊ฐ ๋์์ ๋๋ค.
- vector, mask, image, absolute layout๊ณผ ์ผ๋ถ effect๋ diagnostics๋ฅผ ํฌํจํ ์ ํ์ fallback์ ๋๋ค.
- Figma Remote MCP์
use_figmatool contract๊ฐ ๋ฐ๋๋ฉด live smoke test์ adapter ๊ฐฑ์ ์ด ํ์ํฉ๋๋ค.
์์ธ ์ค๊ณ๋ docs/superpowers/specs/2026-08-30-figma-remote-mcp-design.md๋ฅผ ์ฐธ๊ณ ํ์ธ์.
docs/superpowers/ ์๋์ planยทspec์ ์์ฑ ์์ ์ ๊ธฐ๋ก์ด์ง ํ์ฌ API ๋ฌธ์๊ฐ ์๋๋๋ค. ์๋ฅผ ๋ค์ด ์์์ ์ ๊ฑฐํ๋ค๊ณ ์ ์ devup_figma_to_ui/devup_figma_to_json์ ๊ทธ ๋ฌธ์๋ค์ ์์ง ํ์ฌ ๋๊ตฌ์ฒ๋ผ ๊ธฐ์ ํฉ๋๋ค. ํ์ฌ ๋๊ตฌ ๋ชฉ๋ก๊ณผ ๋์์ ๊ธฐ์ค์ ์ด README์ ์๋ฒ๊ฐ ๊ฒ์ํ๋ ์คํค๋งยทtool description์
๋๋ค.
absolute ์์์ด ์๋ ํ๋ ์์ ์์ฑ ์ฝ๋๊ฐ containing block์ ๋ง๋ญ๋๋ค. standalone์์๋ PAGE/SECTION ์๋์ ๋ฃจํธ๋ FIXED ์ถ์ ์๋ณธ ํฌ๊ธฐ๋ฅผ ๋ณด์กดํฉ๋๋ค. ์๋ฅผ ๋ค์ด WQUW-120์ 360ร740 ์์ง ํ๋ ์์ VStack pos="relative" w="360px" h="740px"๊ฐ ๋์ด ๋ชจ๋ฌ์ left="50%", w="100%"๊ฐ ์ด ๋ฃจํธ๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ณ์ฐ๋ฉ๋๋ค. absolute ์์์ด ์๋ ํ๋ฉด์ ๊ธฐ์กด ์ ๋ ํฌ๊ธฐ ์ ์ฑ
์ ์ ์ง๋ฉ๋๋ค.
placementContracts๋ includeDiagnostics ์์ด๋ ๋ฐํํ๋ฉฐ SECTION ์๋ต์๋ ํ๋ ์๋ณ ๋ชฉ๋ก๋ ์์ต๋๋ค. ๊ฐ ๊ณ์ฝ์ details.output, generatedRoot, sourceSize, containingBlock, parentCollected, parentIncludedInOutput, hostRequirements๋ฅผ ํจ๊ป ํ์ธํ์ธ์. ์บก์ฒ ๋ฐ ๋ถ๋ชจ๊ฐ ์์ผ๋ฉด ๊ทธ ์ฌ์ค์ ๋ช
์ํ๋ฉฐ, ์ผ๋ฐ ๋ฃจํธ๋ ์ฑ์ normal flow์ ์ฝ์
๋ฉ๋๋ค. Figma canvas์ x/y๊ฐ ์ฑ ์์ ์์น๋ฅผ ๋ปํ์ง ์์ต๋๋ค.
embedded์์๋ absolute ์์์ ๊ธฐ์ค ์์๋ ์ ์งํ์ง๋ง ๋ฃจํธ ํฌ๊ธฐ๋ ํธ์คํธ/๋ด์ฉ์ ์์กดํฉ๋๋ค. ์ด ์์กด์ด๋ absolute ๋ฃจํธ์ ์ธ๋ถ ๋ถ๋ชจ ์์กด์ hostRequirements์ projectionIssues์ ๊ทผ์ฌ๋ก ๊ธฐ๋กํฉ๋๋ค. ์ด๋ฅผ ์ถฉ์กฑํ๊ฑฐ๋ containing parent๋ฅผ standalone์ผ๋ก exportํ ํ ๋ฐฐ์น๋ฅผ ์์ฉํ์ธ์. ์ด ๊ณ์ฝ์ CSS ์์ฑ ๊ทผ๊ฑฐ์ด๋ฉฐ ๋ธ๋ผ์ฐ์ ํฝ์
๋น๊ต๋ ๋ฐ์ํ ๋์ผ์ฑ ๋ณด์ฆ์ด ์๋๋๋ค.
projectionIssues๋ includeDiagnostics ์์ด๋ ๊ทผ์ฌยท์์ค์ ๋
ธ๋, ํ๋, ์ฌ์ ์ ์๋ณธ/์ ์ฉ ๊ทผ๊ฑฐ๋ฅผ ๋ฐํํฉ๋๋ค. ๋ถ๋ฅ ๊ทผ๊ฑฐ ์๋ uncoveredLayout์ lossy์ด๋ฉฐ exact๋ ์ต์ข
์ฐ์ถ๋ฌผ๋ก ํ์ํ์ง ์์ต๋๋ค. ์จ๊น ์์ฐ ์ฐธ์กฐ๋ฅผ ์ ๊ฑฐํ๊ณ , ์ ์ธ ์์ฐ์ด ์ฌ์ ํ ํ์ํ ์ถ๋ ฅ์ ์คํจ ์ฌ์ ์ ํจ๊ป ๋ณด๋ฅํฉ๋๋ค.
quality.assets๋ ์์ฐ ๋ฐ์ดํธ ์์ง ํ์ง์ด๋ฉฐ manifest ์์ฑ ์ฑ๊ณต์ ๋ปํ์ง ์์ต๋๋ค. assetSummary.description๊ณผ excludedCount๊ฐ ๋ฏธ์์งยท๋ถ๋ถ ์์งยท์จ๊น ์ ์ธ๋ฅผ ์ค๋ช
ํฉ๋๋ค. ๋ฐ์ดํธ ์์ง์ ์์ฒญํ์ง ์์๋ค๋ฉด not-collected ์์ฝ๊ณผ quality.assets: not-requested๊ฐ ํจ๊ป ์ฌ ์ ์์ต๋๋ค.
๋ฐฐ์น ์๋ต์ recommendedBatchSize๋ ์ต๋ 3, maxFrameCount๋ 6, maxFrameOutputUnits๋ 12์
๋๋ค. ์์ธํ ์ ์๋ R1 ์๋ต ๊ณ์ฝ์ ์ฐธ๊ณ ํ์ธ์.
sourceMap.version=2๋ ๊ณต๊ฐ ์คํ์
์ ์ ๊ฑฐํ ๊ณ์ฝ์
๋๋ค. exact๋ ์๋ณธ ํ๋์ ๋์ํ๋ ์์ฑ ์์ฑ/ํ๊ทธ/ํ
์คํธ ๋งคํ์ ๊ฒ์ฆํ๋ค๋ ๋ป์
๋๋ค. ์ค ์์น, ๋ธ๋ผ์ฐ์ ํฝ์
์ผ์น, ๋ฐ์ํ ๋๋ฑ์ฑ ๋๋ ํ๋ฉด ์ ์ฒด ์์ฑ๋๋ฅผ ๋ณด์ฆํ์ง ์์ต๋๋ค. generatedProperty๋ h="740px", flex="1", aspectRatio="320 / 48"์ฒ๋ผ ์ถ๋ ฅ์ ์๋ ์์ฑ์ ๋ด์ต๋๋ค. characters๋ children, ์๋ฌต์ cross-axis stretch๋ implicit:align-self:stretch๋ก ํ์ํฉ๋๋ค. grow๋ ์ค์ flex ์์ฑ๊ณผ accounted-for-implicit-flex-grow๋ฅผ ํจ๊ป ์ฝ์ต๋๋ค. ๊ธฐ์กด sizing ๊ฒ์ฆ๊ณผ ์ง๋จ์ ์ ์ง๋ฉ๋๋ค. ๋ด๋ถ renderer/validator์ ์์น ์ ๋ณด๋ ๊ณต๊ฐ sourceMap์ ์ง๋ ฌํํ์ง ์์ต๋๋ค.
overflowDirection์ ์บก์ฒ manifest์ ํฌํจ๋ฉ๋๋ค. NONE์ ๋ช
์์ ๋น์คํฌ๋กค, JSON null์ ์์ง ์ ์๋ณธ ์์ฑ์ด ์์, ํค ๋ถ์ฌ๋ ์ด์ ์์ง๊ธฐ์ ๋ฏธ์์ง, fieldErrors.overflowDirection์ ์ฝ๊ธฐ ์คํจ์
๋๋ค. ์ธ๋ก/๊ฐ๋ก/์๋ฐฉํฅ ์คํฌ๋กค์ ๊ฐ๊ฐ overflowY="auto"/overflowX="auto"/overflow="auto"๋ก ์์ฑํฉ๋๋ค. clipsContent=true๋ ์คํฌ๋กค์ ์ทจ์ํ์ง ์์ผ๋ฉฐ, ํ ์ถ ์คํฌ๋กค์์๋ ๋ค๋ฅธ ์ถ์ clipํฉ๋๋ค. ABSOLUTE FIXED ๋์ด๋ ํ์ padding์ด ์์ด๋ ๋ช
์์ ๋์ด๋ก ๋ณด์กดํฉ๋๋ค. FILL/HUG๋ฅผ px๋ก ๊ณ ์ ํ์ง ์์ต๋๋ค.
์ผ๋ฐ ํ๋ฉด export๋ ์์ง์ด ๊ธธ์ด์ง๋ฉด ์ฝ 1์ด์ ์ด๊ธฐ ๋๊ธฐ ํ exportJob์ ๋ฐํํฉ๋๋ค(assetJob์ ํธํ ๋ณ์นญ). jobId๋ก ์ํ๋ฅผ ์กฐํํ๊ณ paused ์ํ๋ jobAction:"resume"์ผ๋ก ์ฌ๊ฐํฉ๋๋ค. calls์ frame/root IDยทpaginationยทelapsedMs์ projection ์๊ฐ์ ํ์ธํ ์ ์์ต๋๋ค. ์์ฐ์ frame-output unit๋น 5โ20์ด์ ๊ณํ์ฉ ์ถ์ ์ด๋ฉฐ ๋ณด์ฅ์ด ์๋๋๋ค. ์์ฒญ ํ๋ 6 frames/12 units์ ๋ณ๊ฐ๋ก upstream ์ง์ฐ์ job์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ์ง์ฐ ํ๋ ์์ ๋ถ๋ฆฌํ๋ ค๋ฉด ํ ํ๋ ์์ฉ ํธ์ถํ์ญ์์ค. ์์
์ ์๋ฒ ํ๋ก์ธ์ค ์์์ 30๋ถ, ์๋ฃ ์๋ต์ 5๋ถ ๋ณด์กด๋๋ฉฐ ์ฌ์์์ ๋๊ฒจ ๋ณด์กด๋์ง ์์ต๋๋ค.
artifact์ artifactState๋ expired(ํ์ธ๋ TTL ๋ง๋ฃ), evicted(ํ์ธ๋ ์บ์ ์ ๊ฑฐ), unknown(ํ์ฌ ์๋ฒ์์ ์์ธ ํ๋จ ๋ถ๊ฐ)์ ๊ตฌ๋ถํฉ๋๋ค. ์ต๊ทผ ์ ๊ฑฐ 64๊ฐ ์ด๋ด์ ๋ณต๊ตฌ metadata๊ฐ ์์ผ๋ฉด canonical URL๊ณผ ์ ํ์ nextAction.arguments๋ก ์ ๊ณตํฉ๋๋ค. URL ์๋ฌธ์ ํ์ผ ์ ๋ชฉ์ ์ ์ฅํ์ง ์์๋ ๊ฐ์ ๋์์ ๊ฐ๋ฆฌํค๋ canonical URL์ ๊ตฌ์ฑํฉ๋๋ค. metadata๊ฐ ์์ผ๋ฉด recoveryState:"unrecoverable"๋ก ๋ช
์ํ๋ฉฐ, ์๋ฒ ์ฌ์์์ด๋ผ๊ณ ๋จ์ ํ์ง ์์ต๋๋ค.
TSX ํญ๋ชฉ์ ๊ธฐ๋ณธ ํ๋๋ nodeId, property, generatedProperty, resolution์
๋๋ค. ์ ํ์ variableId๋ ์๋ณธ ๋ณ์ ํ ํฐ ์ฐธ์กฐ, styleId๋ typography/style ํ ํฐ ์ฐธ์กฐ, assetId๋ ์ด๋ฏธ์งยท๋ฒกํฐ ์์ฐ ์ฐธ์กฐ๋ฅผ ์๋ณํ ๋ ๋ถ์ต๋๋ค. ํ ํญ๋ชฉ์ ์ฌ๋ฌ ์๋ณ์๊ฐ ํจ๊ป ์์ ์ ์์ผ๋ฉฐ ํด๋น ์ฐธ์กฐ๊ฐ ์์ผ๋ฉด ์๋ตํฉ๋๋ค. devup.json ๋งคํ์ jsonPointer๋ก ํ
๋ง ์์น๋ฅผ ๊ฐ๋ฆฌํค๋ฉฐ TSX ๊ธฐ๋ณธ ํ๋๊ฐ ๋ชจ๋ ์๋ ๊ฒ์ ์๋๋๋ค.
| resolution | ์๋ฏธ์ ๊ฒ์ฆ ๋ฒ์ |
|---|---|
exact |
์๋ณธ ํ๋์ ์์ฑ ํ๊ทธยทํ ์คํธ์ ์๋ฏธ ๋งคํ. ํ๋ฉด ์ ์ฒด์ ํฝ์ /๋ฐ์ํ ๋๋ฑ์ฑ ๋ณด์ฆ์ ์๋. |
raw-fallback |
ํ ํฐ ๋๋ ์ ์ฉ ๋งคํ ๋ผ๋ฒจ์ด ์๋ ์ผ๋ฐ ์๋ณธ ๊ฐยท์์ฑ ์ ์ฑ
๋งคํ ๊ฒฝ๋ก. raw ๊ฐ์ ๋ฌด๋ณํ ๋ณต์ฌ๋ ๋ฎ์ ์ ๋ขฐ๋๋ฅผ ๋ปํ์ง ์์ผ๋ฉฐ, ๋ณ๋ ABSOLUTE component๊ฐ verified์ฌ๋ ์ด ๋ผ๋ฒจ์ ์ ์ง๋ฉ๋๋ค. |
verified-explicit-dimension |
์ฝ๊ธฐ ์ค๋ฅ ์๋ ์๋ณธ width/height ์์น์ ์์ฑ w/h/boxSize์ px ๊ฐ์ด ์ ํํ ๊ฐ์์ ํ์ธ. ๋ฐ์ํ ๋ฐฐ์น๊น์ง ๊ฒ์ฆํ ๊ฒ์ ์๋. |
accounted-for-content-sizing |
textAutoResize์ ๋ฐ๋ฅธ ๊ณ ์ ํฌ๊ธฐ ์๋ต์ ์๋ฏธ ๋งคํ. ํฐํธ ๋ฉํธ๋ฆญ๊ณผ ๋ธ๋ผ์ฐ์ ํฝ์ ์ ๋ฏธ์ธก์ . |
verified-layout-sizing |
์๋ณธ FIXED/FILL/layoutGrow ์๋์ ์์ฑ h/boxSize/flex ๊ด๊ณ๋ฅผ sizing ๊ฒ์ฆ๊ธฐ๋ก ํ์ธ. |
accounted-for-implicit-flex-stretch |
์ค์ ์์ฑ ๋ถ๋ชจ์ cross-axis stretch์ ํฌ๊ธฐ ๊ธฐ์ค์ผ๋ก ์๋ต๋ ํฌ๊ธฐ๋ฅผ ์ค๋ช . |
accounted-for-implicit-flex-grow |
์ค์ ์์ฑ ๋ถ๋ชจ์ main-axis flex-grow์ ๋จ์ ๊ณต๊ฐ์ผ๋ก ํฌ๊ธฐ๋ฅผ ์ค๋ช . |
restored-hug-after-mask-child-folding |
์ ํ mask ์์์ ์๋ณธ ํฌ๊ธฐ์ ๋
๋ฆฝ์ ์ธ ํฌ๊ธฐ ๊ธฐ์ค์ผ๋ก HUG/aspectRatio ๋ณต์. -from-absoluteBoundingBox ์ ๋ฏธ์ฌ๋ bounding box์์ ํฌ๊ธฐ๋ฅผ ์ป์ ๊ฒฝ์ฐ. |
variable-token / style-token |
์๋ณธ ๋ณ์/์คํ์ผ ID์ ์์ฑ ํ ํฐ ์ฐธ์กฐ์ ๋งคํ. |
asset |
์๋ณธ ์์ฐ ID์ ์์ฑ ์์ฐ ์์ฑ์ ๋งคํ. ๋ฐ์ด๋๋ฆฌ ์์ง ์ฑ๊ณต ์ฌ๋ถ๋ assetSummary์์ ๋ณ๋ ํ์ธ. |
variant-selector |
์๋ณธ variant ์ ํ์ ์์ฑ selector ์์ฑ๊ณผ ์ฐ๊ฒฐ. |
unverified-property-mapping |
์๋ณธ์ ๋์ํ๋ ์์ฑ ์์ฑ์ ํ์ธํ์ง ๋ชปํจ. ์ถ๊ฐ ๊ฒ์ฆ ํ์. |
variable / alias / style |
devup.json์ ์ง์ ๋ณ์ ๊ฐ / ํด์๋ ๋ณ์ alias / ์คํ์ผ์์ ๋์จ ํ ๋ง ๊ฐ๊ณผ JSON pointer. |
node๋ ๋ด๋ถ ๋
ธ๋ ๋ฒ์์ฉ์ด๋ฉฐ ๊ณต๊ฐ v2 property entries์๋ ํฌํจ๋์ง ์์ต๋๋ค.
R16์ sourceMap.resolutionSemantics๋ ์ด ๋ผ๋ฒจ ์ฌ์ ๊ณผ axis="mapping-method"๋ฅผ ์๋ต์ ํฌํจํฉ๋๋ค. Section frame์ dictionary="/resolutionSemantics"๋ก ์์ ์๋ต์ ๊ณตํต ์ฌ์ ์ ์ฐธ์กฐํ๋ฉฐ, ์ด ์ฌ์ ์ resource delivery์๋ ๋จ์ต๋๋ค. diagnostics.details.components.*.state๋ ๋ณ๋์ ์ ํ๋ ๊ฒ์ฆ ์ถ์
๋๋ค. ๊ฐ์ screen/output ์์์ nodeId์ ์๋ณธ property(width/height/x/y โ width/height/horizontal/vertical)๋ก ์ฐ๊ฒฐํฉ๋๋ค. ์๋ฅผ ๋ค์ด w="100%"์ ๋งคํ์ raw-fallback์ด์ง๋ง, ํ์ ๋ ๋์ผ FIXED ๋ถ๋ชจ ํญ์์ ํด์ํ ๊ฐ์ด ์๋ณธ ํญ๊ณผ ๊ฐ์ผ๋ฉด ABSOLUTE width๋ verified์ผ ์ ์์ต๋๋ค. ์ด ๋ ๋ผ๋ฒจ ๋ชจ๋ ํ๋ฉด ์ ์ฒด์ ํฝ์
ยท๋ฐ์ํ ๋ฑ๊ฐ์ฑ ์ธก์ ์ ์๋๋๋ค.
R16์ ์คํจํ ์น์ ์ฆ๋ช
์ blockedBy๋ฅผ ์ถ๊ฐํฉ๋๋ค. ๋ถ๋ชจ ํญ ๋ถ๋ช
(parent-width-unknown), ๋ถ๋ชจ ํญ ๋ถ์ผ์น(parent-width-unequal), ์ฝ๊ธฐ ์ค๋ฅ(read-error), ๋นFIXED sizing(non-fixed-sizing), dimension ์ถฉ๋(conflicting-dimension-props)์ ๊ตฌ๋ถํฉ๋๋ค. ์ฑ๊ณต ์ null์ด๋ฉฐ widthPreservation์๋ ๊ฐ์ ๊ฐ์ด ๋ค์ด๊ฐ๋๋ค. ์ฒซ ์ฐจ๋จ ์ด์ ๋ง ๋ณด๊ณ ํ๋ฏ๋ก ๋๋จธ์ง ์กฐ๊ฑด์ ํต๊ณผ๋ ๋ค๋ฅธ ์คํจ ๋ถ๊ธฐ์ ์คํ์ ๋ปํ์ง ์์ต๋๋ค. ์์ฐ์ ๋ถ๋ชจ percentage ์ฆ๋ช
๋์ ์ค์ ์ ํ๋ render-boundary ์ฆ๋ช
์ ์คํจ ์ด์ ๋ฅผ ๋ณด๊ณ ํฉ๋๋ค.
์ต์ข
์๋ต๊ณผ ๊ฐ frame์ verdictScope๋ status/projection์ ๊ทธ๋๋ก ํ์ํ๊ณ statusCauses์ projectionCauses๋ก ์์ธ์ ์์ฝํฉ๋๋ค. projection ์์ธ์ nodeId/screenId/output/code/property์ ๋ฏธํด๊ฒฐ component๋ฅผ ๊ฐ๋ฆฌํค๋ฏ๋ก, width/height๊ฐ verified์ฌ๋ horizontal/vertical์ด approximated์ธ ํ๋ฉด์ ์ ์ฒด ํ์ ์ ๋ฐ๋ก ์ค๋ช
ํฉ๋๋ค. diagnosticIndex๋ ๊ฐ์ ๊ฐ์ฒด์ projectionIssues ์ธ๋ฑ์ค์
๋๋ค. includeDiagnostics=false ๋ฐ resource delivery์๋ ์์ฝ์ด ์ ์ง๋ฉ๋๋ค. ์์ธํ ๋ฒ์๋ R16 ์๋ต ๊ณ์ฝ์ ์ฐธ๊ณ ํฉ๋๋ค.
ABSOLUTE ์ง๋จ์ components๋ height/width/horizontal/vertical๋ณ stateยทfidelityImpactยท์๋ณธ ๊ฐยท์์ฑ ๊ฐยท๊ฒ์ฆ ์ด์ ๋ฅผ ์ ๊ณตํฉ๋๋ค. resolutionConditions์๋ ๋จ์ ๊ทผ์ฌ ํญ๋ชฉ์ ํด์ ์กฐ๊ฑด๋ง ๋ค์ด๊ฐ๋๋ค. CENTER๋ ์๋ณธ ์ค์ฌ ์คํ์
, left/top 50%, translate ๋ฐ ์ค์ ์์ฑ ๋ถ๋ชจ ์ขํ ๊ธฐ์ค๊น์ง ํ์ธํด์ผ ๊ฒ์ฆ๋ฉ๋๋ค. MIN์ ์๋ณธ ์คํ์
๊ณผ ์์ฑ px๋ฅผ ๋น๊ตํฉ๋๋ค. MAX๋ ํฌ๊ธฐ ๊ฒ์ฆ์ ์ ์ ๋ก parentSize-offset-size์ right/bottom ์ฌ๋ฐฑ์ ๋น๊ตํฉ๋๋ค. ์ ์ฝ ํ๋ ์ ์ฒด๊ฐ ์๋ ์ด์ ์บก์ฒ๋ constraintDeclared=false๋ก ํ์ํ๋ฉฐ ์์ฑ๋ ๋ก์ปฌ ์คํ์
๋ง ๋น๊ตํ๊ณ ๋ฐ์ํ ์ ์ฝ์ ์ถ์ ํ์ง ์์ต๋๋ค. ์ฆ๋ช
๋์ง ์์ MAX/STRETCH/SCALE, ๋๋ฝ geometry ๋๋ ํ๋ ์ค๋ฅ๋ ๊ทผ์ฌ๋ก ๋จ์ต๋๋ค. ๋ช
์์ FIXED ๋์ด ๋ณด์กด์ percentage ๋๋น์ ๋๋ฑ์ฑ์ ์ฆ๋ช
ํ์ง ์์ต๋๋ค.
R14๋ ABSOLUTE ์์์ FIXED ํญ๊ณผ ์์ฑ๋ ์ง๊ณ containing block์ ํ์ px ํญ์ด ๊ฐ์ ๊ฒฝ์ฐ w="100%"์ ๋์์ ๊ฒ์ฆํฉ๋๋ค. ํน์ ํญ์ ํ์ ํ์ง ์์ผ๋ฉฐ, ์์ฑ ์ฝ๋๋ ๋ฐ๊พธ์ง ์์ต๋๋ค. ํ์ฌ ์ฆ๋ช
๋ฒ์๋ ์ฝ๊ธฐ ์ค๋ฅ๊ฐ ์๋ ๋์ผ ํฌ๊ธฐ์ FIXED ๋ถ๋ชจ, ๋ช
์์ positioning, ๋ถ๋ชจ padding/border ๋ฐ ํฌ๊ธฐ override๊ฐ ์๋ ๊ฒฝ์ฐ์
๋๋ค. ๋ถ๋ชจ ํญ์ด ์ ๋์ ์ด๊ฑฐ๋ ๊ฐ์ด ๋ค๋ฅด๋ฉด ๊ทผ์ฌ๋ก ๋จ์ต๋๋ค. appliedValue.widthPreservation์ components.width์ ๊ฐ์ ๊ทผ๊ฑฐ, ๋ถ๋ชจ ์์ฑ ํญ, resolvedPixels, sourceFields, ๊ณ์ฐ์์ด ๋ค์ด๊ฐ๋๋ค. componentSummary.verified/unresolved๋ ๋ค ํญ๋ชฉ ์ค ๊ฒ์ฆ๋ ๊ฒ๊ณผ ๋จ์ ๊ฒ์ ๋๋๋๋ค.
ABSOLUTE ์์ฐ์ components๋ boundary(์ ํํ export ๊ฒฝ๊ณยท์๋ณธ bounding box์์ ์ฐจ์ดยทsourceFieldsยท๊ณ์ฐ์), rounding(์
๋ ฅยท์์ฑ๊ฐยท์ค์ฐจ), constraintInterpretation(์ง์ ์ ์ฝยท์ฒซ ์์ ์์ยท๊ธฐ๋ณธ๊ฐ)์ ๋ถ๋ฆฌํฉ๋๋ค. ๋ฐ์ฌ๋ฆผ์ round(value*100)/100์ ์์ฑ๊ฐ์ ์ผ์น ๋ฐ ์ต๋ 0.005px ์ค์ฐจ๋ฅผ ํ์ธํ๋ฉฐ ๋ถ๋์์์ ๋น๊ต ์ฌ์ ๋ 1e-12px์
๋๋ค. ๊ฒฝ๊ณ ์ฐจ์ด๋ฅผ ๋ฐ์ฌ๋ฆผ ์ค์ฐจ๋ก ํก์ํ์ง ์์ต๋๋ค. ์์ฐ ์น์์ verified๋ ์์ง๋ render bounds ํฌ์์ ๊ฒ์ฆ์ด๋ฉฐ ์๋ณธ layout box์์ ๋์ผ์ฑ์ด๋ SVG/CSS ํฉ์ฑ ์ธก์ ์ ์๋๋๋ค. GROUP์ null/๋๋ฝ ์ ์ฝ์ ์ฒซ ์์์์ ๊ฐ์ ธ์ค๊ฑฐ๋ MIN์ผ๋ก ๊ธฐ๋ณธ ์ฒ๋ฆฌํ ๊ฒฝ์ฐ ๊ทธ ์ ์ฑ
์ assumed๋ก ํ์ํฉ๋๋ค. ์์น ๊ณ์ฐ๊ณผ ๋ฐ์ฌ๋ฆผ์ด ๋ง์๋ GROUP์ ๋ฐฐ์น ์๋์ ๊ฐ๋ค๋ ์ฆ๋ช
์ด ์์ผ๋ฉด ํด๋น ์์น ์ถ์ approximated๋ก ์ ์งํฉ๋๋ค.
๋น๋ ๋ ์ง๋จ์ ์ค๋ฅ ์์ด ์ฝ์ visible=false ๋๋ ๋ช
์์ absoluteRenderBounds=null์ accounted-for-non-rendering / fidelityImpact=none์ผ๋ก ๊ธฐ๋กํฉ๋๋ค. verification์ fieldยทfieldPresentยทvalueยทreadError๊ฐ ๊ทผ๊ฑฐ์
๋๋ค. ํ๋ ๋ถ์ฌ๋ ์ฝ๊ธฐ ์คํจ๋ unverified-non-rendering / approximated๋ก ์ ์งํ๋ฉฐ ์ฌ์์ง ์กฐ๊ฑด์ ์๋ดํฉ๋๋ค.
HUG ๊ฒ์ฆ์ ์๋ณธ๊ณผ ์ผ์นํ๋ ์์ฑ auto-layout์์ ํฌ๊ธฐ override ์์ด intrinsic sizing ์๋๋ฅผ ํํํ๋์ง ํ์ธํฉ๋๋ค. FIXED percentage ํฌ๊ธฐ๋ ์ผ์นํ๋ auto-layout๊ณผ ๋ช ์์ ์ผ๋ก ๊ฐ์ ํฌ๊ธฐ์ธ FIXED ๋ถ๋ชจ, ํ ๋๋ฆฌยทpaddingยทmin/max override ๋ถ์ฌ๊ฐ ํ์ธ๋ ์ ํ๋ ๊ฒฝ์ฐ๋ง ๊ฒ์ฆํฉ๋๋ค. CENTER ๊ฒ์ฆ์ ์๋ณธ์ ์ค์ฌ ์คํ์ 0๊ณผ ์์ฑ CSS์ ์ค์ฌ ๊ด๊ณ๋ฅผ ๋ปํฉ๋๋ค. ๋ถ๋ชจ๊ฐ ์ปค์ง ๋ ์๋ x๋ฅผ ๊ณ ์ ํ๋ค๋ ๋ป์ด ์๋๋ฉฐ, ๋ถ๋ชจ์ ๋ช ์์ px ๊ฐ์ด ๋ฐ๋๋ฉด ๋ถ๋ชจ ์์ ์ dimension coverage ์ฌ๊ฒ์ฆ์ด ์คํจํฉ๋๋ค. ๊ฒ์ฆ๋ ๋ช ์์ ํฌ๊ธฐ ๋งคํ์ canvas/derived-padding์ ์ผ๋ฐ ์๋ต ๊ท์น์ผ๋ก ์ฌ๊ฒ์ฆ ์๋ฌด๋ฅผ ๋ฉด์ ํ์ง ์์ต๋๋ค.
projectionEvidence๋ ํ์ธ๋ ๋น๋ ๋์ ๊ฒ์ฆ ์๋ฃ ABSOLUTE ํญ๋ชฉ์ ๊ทผ๊ฑฐ๋ฅผ ๋ด์ผ๋ฉฐ, includeDiagnostics=false์ฌ๋ ์ต์์ ๋ฐ ํ๋ ์ ์๋ต์ ์ ๊ณตํฉ๋๋ค. ๋ฏธํด๊ฒฐ ๊ทผ์ฌ๋ projectionIssues์ ๋จ์ผ๋ฏ๋ก ๋ ๋ฐฐ์ด์ ๊ตฌ๋ถํด ์ฝ์ต๋๋ค.
์ต์ข
TSX์ ๋ชจ๋ JSX ์์ฑ(ํํ์ยทbooleanยทspread ํฌํจ)์ ํ์๋ก ๊ฒ์ฌํฉ๋๋ค. ๊ธฐ์กด sourceMap์ ์๋ ์์ฑ์ ์์ฑ ๋จ๊ณ์ ์๋ณธ ํ๋์ ๊ณ์ฐ์ผ๋ก ๋์กฐํ๋ฉฐ, ํ์ธ๋ ํญ๋ชฉ์ DEVUP_CODEGEN_PROPERTY_EVIDENCE๋ก projectionEvidence์ ๋จ๊น๋๋ค. sourceFields, originalValue, calculation, stage, generatedProperty, elementIndex, assetId ๋ฐ details.output์ ํจ๊ป ์ฝ์ต๋๋ค. ์์ฐ ๊ฒฝ๊ณ ๋ณด์ ์ render bounds์ bounding box์ ์ฐจ์ด, ํจ๊ณผ๋ ์๋ณธ effects๋ฅผ ๊ทผ๊ฑฐ๋ก ๋จ๊น๋๋ค. ์ด ๊ทผ๊ฑฐ๋ ์์ฑ ๊ณ์ฐ์ ๋์์ด๋ฉฐ SVG/CSS ํจ๊ณผ์ ๋ธ๋ผ์ฐ์ ํฉ์ฑ ์ค์ธก์ด ์๋๋๋ค.
์ค๋ช
ํ ์ ์๋ ์์ฑ์ DEVUP_CODEGEN_PROPERTY_UNMAPPED, mappingComplete=false๋ก ํญ์ ๋ณด๊ณ ํฉ๋๋ค. ๊ฐ์ ์ ์ง๋๋ฏ๋ก ์ด ์ง๋จ์ fidelityImpact๋ none์
๋๋ค. ๋ค๋ฅธ ์์คยท๊ทผ์ฌ๊ฐ ์๋ ๊ฒฝ์ฐ quality.projection=mapping-incomplete๊ฐ ๋๋ฉฐ exact์ ์ต์ข
์๋ฃ ํ์ ์ ํ์ฉํ์ง ์์ต๋๋ค. ๊ธฐ์กด lossyยทapproximated ํ์ ์ ์ ์งํฉ๋๋ค. ๋ฐ์ํ ๋ณํฉ์ ๊ฐ๋ณ breakpoint source mapping๋ง์ผ๋ก ๋ณํฉ ์์ฑ์ ์ฆ๋ช
ํ ์ ์์ผ๋ฏ๋ก ๊ฐ์ ์ง๋จ์ ์ ๊ณตํฉ๋๋ค. strict๋ ๋งคํ ๋๋ฝ๋ ๊ฑฐ์ ํฉ๋๋ค. tsx์ componentTsx๋ฅผ ํจ๊ป ์์ฒญํ ๊ฒฝ์ฐ sourceMap.byOutput์ด ์ถ๋ ฅ๋ณ map์ ๊ตฌ๋ถํ๋ฉฐ ๊ธฐ์กด ๋จ์ผ map ํ๋๋ ํธํ์ฑ์ ์ํด ์ ์งํฉ๋๋ค.
outputPaths์ ํ๋ ์ ์ถ๋ ฅ ํค๋ frame:<nodeId>:<output>์
๋๋ค. ์: {"frame:3997:46715:tsx":"C:/allowed/Screen.tsx","frame:3997:46715:sourceMap":"C:/allowed/Screen.map.json"}. outputPathResults.supportedKeys๋ ์ด๋ฒ ํฌ์์์ ์ค์ ์ธ ์ ์๋ ํค๋ฅผ ์ด๊ฑฐํฉ๋๋ค. ํ๋ ์ ์๋ต์ ์ผ๋ฐ tsx/sourceMap ํค๋ฅผ ์ฐ๊ฑฐ๋ ๋ฏธ์ง์ยท๋ฏธ์์ฑ ์ถ๋ ฅ ํค๋ฅผ ์ฐ๋ฉด outputPathResults.diagnostics์ ๋ช
์ํ๋ฉฐ ์กฐ์ฉํ ๋ฌด์ํ์ง ์์ต๋๋ค. ์ต์์ ๋จ์ผ ์ถ๋ ฅ์ ๊ธฐ์กด ์ผ๋ฐ ํค๋ฅผ ์ฌ์ฉํฉ๋๋ค. outputPaths ์๋ต์ ์ฑ๊ณต์ ์ผ๋ก ์ปค๋ฐํ ํ์ผ๋ง ๋ํ๋
๋๋ค. ์์ฐ binary๋ ๊ณ์ assetRequests[].outputPath๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๋ช
์์ resource์ ์๋ resource ์ ํ ๋ชจ๋ nextAction.tool/arguments๋ก ๋์ผ artifact์ ์์ ๋ณธ๋ฌธ ๋์กฐ ์์๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ผ๋ฐ ํ๋ฉด์ ๋จ์ผ frameยท๋จ์ผ ์ถ๋ ฅ์ด๋ฉฐ ํ์ผ์ ๋ค์ ์ฐ์ง ์์ต๋๋ค. sizeEstimate.outputBytes๋ ๊ธฐ์กด ์ ํ ์ถ๋ ฅ์ UTF-8 ๋ฐ์ดํธ ์(PNG๋ binary ๋ฐ์ดํธ ์)์ด๊ณ minimumWireBytes๋ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ ์ธํ JSON ์ค๋ณต ์ ์ก ํํ์
๋๋ค. ์ฌํฌ์ ์๋ต์ ์ ์ฒด ํฌ๊ธฐ๋ ์ค์ธกํ์ง ์์์ผ๋ฏ๋ก ํ๋ ๋ฏธ๋ง์ ๊ฒฝ์ฐ์๋ inlineFit=unknown์
๋๋ค. ํ์คํ ํ๋๋ฅผ ๋๋ ๊ฒฝ์ฐ resource๋ฅผ ์๋ดํ๋ฉฐ, inline ํฌ๊ธฐ ์ด๊ณผ ์ ๊ธฐ์กด R12 ๊ต์ ์ธ์๋ฅผ ์ ์งํฉ๋๋ค. ์์ฐ ์์ฒญยท์ถ๋ ฅ ๊ฒฝ๋ก๊ฐ ์ฝ๋ URL์ ๊ฒฐ์ ํ๋ ๊ฒฝ์ฐ์๋ ์๋ ๊ฒฐํฉ๋ resource ์ธ์๋ฅผ ์ ์งํ์ฌ ์๋ชป๋ ๋ณธ๋ฌธ ๋์กฐ๋ฅผ ๋ฐฉ์งํฉ๋๋ค.