diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index 11be1739..ec51a55d 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -8,7 +8,7 @@ "name": "tempad-dev", "source": { "source": "local", - "path": "./agent-plugins/tempad-dev" + "path": "./agent-plugin/targets/codex" }, "policy": { "installation": "AVAILABLE", diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 22253231..c37cb0ce 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -3,12 +3,12 @@ "owner": { "name": "TemPad Dev" }, - "description": "Agent plugins for using TemPad Dev design evidence in coding workflows.", + "description": "Agent plugins for reading Figma evidence and authoring native designs with TemPad Dev.", "plugins": [ { "name": "tempad-dev", - "source": "./agent-plugins/tempad-dev", - "description": "Use selected Figma nodes as agent-ready evidence for project-consistent UI implementation.", + "source": "./agent-plugin/targets/claude", + "description": "Connect your coding agent to Figma. Create and edit native designs, inspect existing designs, and implement UI in your codebase.", "category": "Design" } ] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..05375bc0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Generated agent plugin targets: collapse them in diffs and reviews. +agent-plugin/targets/** linguist-generated=true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d1125dfb..122552d2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,6 +33,18 @@ jobs: - name: Install browser runtime run: pnpm --filter @tempad-dev/extension test:setup + - name: Check agent plugins + run: >- + pnpm agent-plugin:build && + test -z "$(git status --porcelain --untracked-files=all -- + agent-plugin + .plugin/marketplace.json + .agents/plugins/marketplace.json + .claude-plugin/marketplace.json)" + + - name: Check plugin installer compatibility + run: pnpm agent-plugin:check-installer + - name: Type check run: pnpm typecheck @@ -47,3 +59,6 @@ jobs: - name: Build project run: pnpm build + + - name: Check bridge compatibility + run: pnpm mcp:check-bridge diff --git a/.github/workflows/publish-mcp.yml b/.github/workflows/publish-mcp.yml index 5de2ea44..bef75708 100644 --- a/.github/workflows/publish-mcp.yml +++ b/.github/workflows/publish-mcp.yml @@ -2,6 +2,16 @@ name: publish-mcp on: workflow_dispatch: + inputs: + tag: + description: npm dist-tag + required: true + default: latest + type: choice + options: + - latest + - next + - alpha permissions: contents: read @@ -35,4 +45,8 @@ jobs: - name: Publish working-directory: packages/mcp-server - run: npm publish --access public + run: npm publish --access public --tag "${{ inputs.tag }}" + + - name: Verify published version + working-directory: packages/mcp-server + run: npm view "@tempad-dev/mcp@$(node -p "require('./package.json').version")" version diff --git a/.gitignore b/.gitignore index 82a32a28..9b392a30 100644 --- a/.gitignore +++ b/.gitignore @@ -14,8 +14,10 @@ stats-*.json .wxt web-ext.config.ts dist +.dev/ coverage .artifacts/ +.vitest-attachments/ packages/*/coverage packages/extension/tests/**/__screenshots__/ diff --git a/.lefthook.yml b/.lefthook.yml index 89dd61e1..9d57ea1e 100644 --- a/.lefthook.yml +++ b/.lefthook.yml @@ -5,16 +5,16 @@ pre-commit: group: piped: true jobs: - - name: sync-agent-plugin - glob: '{skill/SKILL.md,agent-plugins/tempad-dev/skills/figma-design-to-code/SKILL.md}' - run: pnpm sync:agent-plugin - stage_fixed: true - name: lint glob: '*.{ts,js,mjs,cjs,mts,cts,vue}' + exclude: 'agent-plugin/targets/**' run: pnpm exec eslint --fix {staged_files} stage_fixed: true - name: format glob: '*.{ts,js,mjs,cjs,mts,cts,vue,json,md,yml,yaml,css}' + # Generated targets are excluded here rather than through .oxfmtignore, which also + # excludes packages/ and would leave this job with no files to format at all. + exclude: 'agent-plugin/targets/**' run: pnpm exec oxfmt -c ./.oxfmtrc.json --ignore-path ./.gitignore {staged_files} stage_fixed: true - name: typecheck diff --git a/.oxfmtignore b/.oxfmtignore index aeae697c..ea33dca8 100644 --- a/.oxfmtignore +++ b/.oxfmtignore @@ -1,5 +1,8 @@ # Package contents are formatted by package-level scripts. packages/** +# Generated agent plugin targets. Format agent-plugin/src/ instead. +agent-plugin/targets/** + # Lockfile formatting is managed by pnpm. pnpm-lock.yaml diff --git a/.plugin/marketplace.json b/.plugin/marketplace.json new file mode 100644 index 00000000..e9332451 --- /dev/null +++ b/.plugin/marketplace.json @@ -0,0 +1,13 @@ +{ + "name": "tempad-dev", + "owner": { + "name": "TemPad Dev" + }, + "plugins": [ + { + "name": "tempad-dev", + "source": "./agent-plugin/targets/plugins-cli", + "description": "Connect your coding agent to Figma. Create and edit native designs, inspect existing designs, and implement UI in your codebase." + } + ] +} diff --git a/AGENTS.md b/AGENTS.md index 823f76e6..8d8cf306 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,121 +2,143 @@ ## Purpose -Provide a single entry point for coding agents. This file links to package-level guides and highlights repo-wide constraints and workflows. - -## Repo map (high level) - -- `packages/extension/` — Figma plugin + MCP tools implementation -- `packages/mcp-server/` — MCP server runtime -- `packages/shared/` — shared types and contracts -- `packages/plugins/` — plugin-side code and transforms -- `agent-plugins/` — shared agent plugin bundles and platform manifests - -## Start here - -- `packages/extension/AGENTS.md` -- `packages/mcp-server/AGENTS.md` -- `packages/shared/AGENTS.md` -- `packages/plugins/AGENTS.md` - -## Global conventions - -- Package manager: `pnpm` -- Prefer repo-level scripts unless a package explicitly documents otherwise. -- When creating commits, use Conventional Commits (for example: `feat: ...`, `fix: ...`, `docs: ...`, `chore: ...`). - -## Common commands - -- Typecheck: `pnpm typecheck` -- Lint (and format): `pnpm lint:fix` -- Test (watch): `pnpm test` -- Test (run): `pnpm test:run` -- Test (coverage): `pnpm test:coverage` -- Extension node tests: `pnpm --filter @tempad-dev/extension test:node` -- Extension browser tests: `pnpm --filter @tempad-dev/extension test:browser` -- Extension browser setup: `pnpm --filter @tempad-dev/extension test:setup` - -## Doc index - -- `TESTING.md` -- `docs/testing/architecture.md` -- `docs/extension/mcp-get-code-requirements.md` -- `docs/extension/mcp-get-code-design.md` -- `docs/extension/mcp-browser-gateway-design.md` -- `docs/marketing-screenshots.md` - -## Guardrails - -- Keep changes minimal and consistent with existing style. -- Avoid adding new global dependencies unless explicitly requested or approved. -- Keep pull request descriptions concise. Do not include a validation section unless explicitly requested. - -## Contributing & verification - -### Tech stack (repo-wide) - -- Package manager: `pnpm` (workspace scripts are commonly run as `pnpm -r ...`). -- Language: TypeScript. -- Extension: Vue 3 + WXT (Web Extension Toolkit). -- MCP server: Node.js 18+ + `@modelcontextprotocol/sdk` + WebSocket transport. -- Shared contracts: `zod` schemas. -- Build tool (non-extension packages): `tsdown`. - -### Key scripts - -Run these at repo root unless noted. - -- Dev extension: `pnpm dev` -- Dev site: `pnpm dev:site` -- Build everything: `pnpm build` -- Build site: `pnpm build:site` -- Build extension: `pnpm build:ext` -- Build plugins: `pnpm build:plugins` -- Build MCP: `pnpm build:mcp` -- Typecheck all packages: `pnpm typecheck` -- Lint all packages: `pnpm lint` / auto-fix: `pnpm lint:fix` -- Test all packages: `pnpm test:run` -- Coverage report: `pnpm test:coverage` -- Format: `pnpm format` -- Zip extension artifact: `pnpm zip` - -### Verification checklist (agent-driven changes) - -Pick the checks that match your change. - -1. Always - -- `pnpm typecheck` -- `pnpm lint` (or `pnpm lint:fix`) -- `pnpm test:run` - -2. Extension UI / codegen - -- `pnpm dev` -- In Figma, open TemPad Dev panel and validate the impacted section (e.g. “Inspect → Code”). - -3. Extension build / packaging - -- `pnpm build:ext` -- `pnpm zip` - -4. Rewrite subsystem - -- `pnpm --filter @tempad-dev/extension build:rewrite` -- Optional: `pnpm --filter @tempad-dev/extension tsx scripts/check-rewrite.ts` - - Requires `FIGMA_EMAIL`, `FIGMA_PASSWORD`, `FIGMA_FILE_KEY`. - -5. MCP schemas / tool behavior - -- If you change tool schemas/contracts: update `packages/shared` first, then `packages/mcp-server`, then `packages/extension`. -- Re-check payload limits and omission rules; see `docs/extension/mcp-get-code-requirements.md` and `docs/extension/mcp-get-code-design.md`. - -## Testing notes - -- Testing runbook and required checks: `TESTING.md`. -- Testing architecture and coverage model: `docs/testing/architecture.md`. -- Root coverage scope is configured in `vitest.config.ts` as the single source of truth. -- Root coverage excludes build artifacts (`**/dist/**`, `**/.output/**`) to avoid polluted reports. -- Root coverage provider is `istanbul` to avoid V8 remap parse failures under Vite 8 dependency trees. -- Extension browser tests run in Playwright via `packages/extension/vitest.browser.config.ts`. -- Do not introduce jsdom-based tests in this repository. +Use this file as the repo-wide router and source of global invariants. Read only +the package guide and conditional runbook required by the task; do not preload +every linked document. + +## Repository routing + +| Work area | Read next | Responsibility | +| ---------------------- | ------------------------------- | -------------------------------------------------------------------------- | +| `packages/extension/` | `packages/extension/AGENTS.md` | Figma extension, UI, codegen, browser runtime, and MCP tool implementation | +| `packages/mcp-server/` | `packages/mcp-server/AGENTS.md` | MCP server, Hub, transport, and tool exposure | +| `packages/shared/` | `packages/shared/AGENTS.md` | Shared schemas, types, and contracts | +| `packages/plugins/` | `packages/plugins/AGENTS.md` | Plugin transforms and sandboxed plugin-side code | +| `agent-plugin/` | This guide | Agent skills, manifests, host extras, and marketplace metadata | + +For a cross-package change, read the guides for every affected package. For a +repo-wide documentation, configuration, or release task, this root guide is the +default authority unless a routed document says otherwise. + +## Repo-wide invariants + +- Package manager: `pnpm`. Prefer repo-level scripts unless a package guide + explicitly requires a filtered command. +- Keep changes minimal and consistent with existing style. Do not add global + dependencies without explicit approval. +- When a tool schema or shared contract changes, update `packages/shared` first, + then `packages/mcp-server`, then `packages/extension`. +- Generated artifacts are not source. Follow the owning workflow and never edit + ignored or generated output to simulate a source change. +- Do not create or amend commits unless explicitly requested. When creating a + commit, use Conventional Commits. +- Keep pull request descriptions concise. Do not add a validation section unless + explicitly requested. +- Write repository documentation in English. Public Chinese documentation uses + the `.zh-Hans.md` suffix. + +## Agent plugin invariants + +- `agent-plugin/src/` is the only authored copy. Everything under + `agent-plugin/targets/` and `.dev/plugins/` is generated by `pnpm agent-plugin:build`; + never hand-edit it. The plugin is distributed through the Git marketplace, not npm. +- Every channel resolves directly from a Git ref, so each target is committed, and + each carries only what its own installer reads: + + | Channel | Target | Carries | + | ------------------------------------------ | -------------------------------------- | ------------------------------------------ | + | Agent Plugins 1.0 consumers | `agent-plugin/targets/standard` | `plugin.json`, `mcp.json` | + | `npx plugins add` (Cursor, VS Code, …) | `agent-plugin/targets/plugins-cli` | `.plugin/plugin.json`, `.mcp.json` | + | `codex plugin marketplace add` | `agent-plugin/targets/codex` | `.codex-plugin/`, `.mcp.json` | + | `claude plugin marketplace add` | `agent-plugin/targets/claude` | `.claude-plugin/`, `.mcp.json`, `clients/` | + | `npx skills add` / `gemini skills install` | `agent-plugin/targets/standard/skills` | skills only | + +- A target must not carry another channel's layout. A standard consumer projects + `plugin.json` onto the host itself, so a host layout beside it would be a second + source of truth for the same package; each host target likewise omits the standard + manifests and the other host's directory. Only Claude loads lifecycle hooks, so + only `targets/claude` carries `clients/`. +- The current `plugins` CLI reads `.plugin/marketplace.json` before the Claude + marketplace and does not read Agent Plugins 1.0 manifests. Generate that entry + to point at `targets/plugins-cli`; keep the compatibility layout separate from + `targets/standard`. Run `pnpm agent-plugin:check-installer` after packaging changes. +- `agent-plugin/src/plugin.json` and `mcp.json` own every shared manifest and MCP + field. Host-specific authored extras live under `agent-plugin/src/clients/`: + `claude/hooks.json`, `codex/interface.json` (Codex directory presentation), and + `shared/lifecycle.mjs`. +- Both skills are authored under `agent-plugin/src/skills/`. Icons, host manifests, + marketplace metadata, and every target copy are derived. +- `.dev/plugins/tempad-dev-dev/` is the one exception to the per-host split: an + ignored local build carrying both host layouts, pinned to this checkout's MCP + runtime, so one installed package can be exercised from either host while testing. +- Run `pnpm agent-plugin:build` after changing any input, inspect the tracked + generated output, and include it in the change. `agent-plugin/targets/` is marked as + generated for review; read `agent-plugin/src/` instead. Ordinary `pnpm build` must + not modify agent-plugin artifacts. +- Keep Codex and Claude development support equivalent. Both manifests must + launch the same working-tree MCP runtime. +- Release MCP configuration must use `@tempad-dev/mcp@latest`, never an alpha + tag, fixed version, or local path. +- Host integration must require only the normal TemPad Dev extension setup and + installation of the host plugin, including any host-required trust prompts. + The plugin/runtime owns connection discovery, conversation binding, and + reconnection. Manual control endpoints, environment edits, helper launches, or + agent instructions to configure the connection do not satisfy this requirement. + Do not claim full host support until feedback and host controls work through + that installation path against the actual host. +- Codex App uses MCP request metadata and native IPC for task identity, lifecycle, + comments, and interruption; do not register Codex hooks or add a hook fallback. + Claude may use installed hooks for lifecycle and Stop notices only. + Deliver comments through verified native conversation channels, never hooks. Clients + without native delivery do not expose feedback controls. Stop permanently cancels the current task independently of + host interruption and keeps its old lease fenced across ordinary reconnects. + Respect Stop without automatically replacing the task. Further design work may + explicitly begin a fresh task when necessary or requested by the user; no separate + Figma unlock or new user turn is required. +- Before preparing, running, reviewing, or asking the user to test an end-to-end + Figma authoring task, read `docs/testing/agent-authoring-evolution.md`. It is + the sole detailed runbook for runtime refresh, plugin replacement, clean-task + identity, evidence review, fix placement, and candidate promotion. + +## Core commands + +Run these from the repo root: + +| Task | Command | +| ------------------------------ | ----------------------------- | +| Development | `pnpm dev` | +| Build all packages | `pnpm build` | +| Typecheck | `pnpm typecheck` | +| Lint / auto-fix | `pnpm lint` / `pnpm lint:fix` | +| Test once | `pnpm test:run` | +| Coverage | `pnpm test:coverage` | +| Format | `pnpm format` | +| Generate agent plugin packages | `pnpm agent-plugin:build` | + +Use package-owned commands from the applicable package guide when a narrower +check is sufficient. + +## Conditional documentation + +| Task | Read first | +| ------------------------------------------------------- | --------------------------------------------------------------- | +| Test selection, required checks, or troubleshooting | `TESTING.md` | +| Test runtime or coverage architecture | `docs/testing/architecture.md` | +| Codex desktop IPC discovery, lifecycle, or feedback | `docs/engineering/codex-desktop-ipc.md` | +| End-to-end authoring evolution or live agent evaluation | `docs/testing/agent-authoring-evolution.md` | +| Extension implementation or MCP behavior | `packages/extension/AGENTS.md`, then its routed design document | +| Public agent-plugin installation or usage documentation | `agent-plugin/src/README.md` | +| Marketing screenshot work | `docs/marketing-screenshots.md` | + +## Verification + +Follow `TESTING.md` and every affected package guide. The default repository +checks are: + +1. `pnpm typecheck` +2. `pnpm lint` +3. `pnpm test:run` + +Add build, browser, packaging, rewrite, coverage, or live Figma checks only when +the routed guidance and change risk require them. Browser runtime tests must use +Playwright; do not introduce jsdom-based tests. diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e1328fd..bf638b92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,4 +2,7 @@ - Extension: [packages/extension/CHANGELOG.md](packages/extension/CHANGELOG.md) - MCP server: [packages/mcp-server/CHANGELOG.md](packages/mcp-server/CHANGELOG.md) +- Agent Plugin: [agent-plugin/src/CHANGELOG.md](agent-plugin/src/CHANGELOG.md) - Plugins SDK: [packages/plugins/CHANGELOG.md](packages/plugins/CHANGELOG.md) + +For the coordinated publication process, see [Releasing](docs/releasing.md). diff --git a/README.md b/README.md index a9aeb748..a3bd2240 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,17 @@ - Shows a screenshot of the extension panel. + TemPad Dev

-

Open handoff tooling for Figma

+

Connecting Figma with developers and their coding agents

Install on Chrome Web Store Chat on Discord Ask DeepWiki - 前往中文版 + Read in Simplified Chinese

@@ -20,17 +20,159 @@ check-script-rewrite

-

+TemPad Dev is an open-source connection between Figma, developers, and their coding agents. Inspect designs and customize code output in the browser, or let your agent read designs, create and edit native Figma content, and implement UI in your project. + +## Contents + +- [Quick start](#quick-start) +- [Agent integration](#agent-integration): [canvas design](#create-and-edit-figma-designs), [implementation](#implement-designs-in-code), [setup](#setup-guide), [connection status](#mcp-connection-status) +- [Inspect designs](#inspect-designs): [CSS and variables](#inspect-css-code), [deep select](#deep-select-mode), [measure](#measure-to-selection-mode), [scroll into view](#scroll-selection-into-view) +- [Output plugins](#output-plugins): installation, development, and sharing + +## Quick start + +1. Install TemPad Dev from the [Chrome Web Store](https://chromewebstore.google.com/detail/tempad-dev/lgoeakbaikpkihoiphamaeopmliaimpc) and open a Figma Design file. +2. Select an element to inspect its code, variables, and layout in the TemPad Dev panel. Manual inspection needs no agent setup. +3. To use a coding agent, enable **Preferences → Agent integration → MCP access**, select **Set up agents**, and follow the instructions for your client. + +The agent connection requires Node.js 22.x, 24.x, or 26+. Canvas editing also requires edit access to the Figma Design file. Setup and upgrade details for the extension, MCP server, and both skills follow below. + +## Agent integration + +Work with Figma through the coding agent or IDE you already use. TemPad Dev provides design context and canvas operations; your agent uses them alongside your instructions and project context. + +### Create and edit Figma designs + +Create screens, adjust layout and typography, or revise existing designs. The result consists of native, editable layers. Reuse accessible components, variables, and styles when the task calls for them. + +For example, after connecting your agent: + +> Create a settings screen in Figma using the available components. + +Or select an existing design and ask: + +> Adjust the spacing and typography in this screen, keeping its components and content. + +The `figma-canvas-authoring` skill guides your agent through relevant resource inspection, editing, and checking the rendered result. Writes require an editable Figma Design file; view-only files and Dev Mode remain read-only. + +### Design task controls and comments + +The task status bar follows the design anchor and shows the agent's activity and Stop/Done +controls. Stop permanently cancels the current task; reconnecting cannot resume its writes. +On compatible Codex App hosts, save element comments or add a general comment, then send the +batch with Queue or Steer. Queue clears submitted drafts after the host confirms receipt, so +another batch can be written while the queued request waits. Confirmation does not mean the +agent has completed the changes. + +In an element editor, Enter saves; Command/Ctrl+Enter saves and queues the whole batch. In the +general composer, Enter queues the batch and Command/Ctrl+Enter uses Steer. Shift+Enter adds a +newline. Claude, Codex CLI, and other clients currently have task controls without comment +sending. See the [comment guide and host validation scope](./agent-plugin/src/README.md#task-controls-and-client-enhancements). + +### Implement designs in code + +Select the design in Figma, then ask your agent in the target code project: + +> Implement the current Figma selection using this project’s components and styling conventions. + +TemPad Dev provides layout, styles, variable references, component information, and assets. The `figma-design-to-code` skill guides the agent through adapting that evidence to the repository and validating the implementation. Generated design code is a starting point; the agent produces the project implementation. + +Both workflows use the same MCP connection to Figma. Compatible clients can install the [Agent Plugin](./agent-plugin/src/README.md), which bundles the MCP configuration and both skills. Other clients can set up MCP and skills separately. + +### Setup guide + +1. Install Node.js 22.x, 24.x, or 26+ with `npx`. Keep TemPad Dev open in the Figma tab you want the agent to inspect, then enable **Preferences → Agent integration → MCP access**. When prompted, allow the loopback connection to `127.0.0.1`. Canvas authoring is available while MCP access is enabled and the current Figma Design file is editable. +2. Select **Set up agents**, choose Codex, Cursor, Claude Code, Gemini, VS Code, OpenCode, or TRAE, and follow the displayed path. Use **Other** for another compatible client. The choice only changes the instructions shown; it does not bind or activate an agent. +3. The setup flow uses native marketplace installation for Codex and Claude Code, and the portable Agent Plugin for Cursor and VS Code. Codex App integration uses native IPC without lifecycle hooks. For Gemini, OpenCode, TRAE, and other clients without compatible plugin installation, it uses the client's MCP flow plus the two standalone skills. Every command or config is shown in full for review and copying. + +For clients with separate MCP and skill installation, the setup shows each command. Gemini is one example: + + + + + Gemini setup showing the MCP installation command. + + +Scroll down in the dialog for both skill installation commands: + + + + + The complete Gemini commands for the design-to-code and canvas authoring skills. + + +For native Codex and Claude marketplace commands and portable Cursor and VS Code installation, +see the [Agent Plugin guide](./agent-plugin/src/README.md). + +All plugin and direct `npx`-based setup paths use `@tempad-dev/mcp@latest`. + +For the canvas-authoring release, use extension **0.21.0**, MCP server **0.8.0**, and Agent +Plugin **0.2.0** together. See the [upgrade guide](./agent-plugin/src/README.md#upgrading) +when updating an existing installation. + +Keep TemPad Dev open with MCP enabled while using it. If multiple Figma files are connected, click the MCP badge in the panel for the file you want the agent to inspect; that file becomes the active context. + +### MCP connection status + +When the MCP server is enabled, a badge appears in the TemPad Dev panel title bar showing the current connection status: + +- **Unavailable**: The local MCP server is not configured or not running. + + + + + MCP status badge showing Unavailable. + + +- **Inactive**: TemPad Dev is connected to a local MCP server, but this tab is not currently active because multiple Figma tabs are open. Click the badge to activate MCP for this tab (this deactivates MCP in other tabs). + - - - Shows a screenshot of the extension panel. + + + MCP status badge showing Inactive. -

+ +- **Active**: The MCP server is running, and this tab is active and ready to respond to MCP tool calls. + + + + + MCP status badge showing Active. + + +### Configuration + +For optional environment variables, see [`packages/mcp-server/README.md`](./packages/mcp-server/README.md). + +### MCP tools + +These tools are called by the agent. For everyday use, describe the task in your own words. + +- `get_code`: High-fidelity JSX/Vue + TailwindCSS code output by default, plus attached assets and the codegen preset/config used. +- `get_design_system`: An immutable, deterministic catalog. It returns compact pages of component + definitions on accessible pages plus local or directly referenced variable, collection/mode, + style, and shader definitions without inspecting canvas usage or loading every page. Cursor + continuation exposes omitted definitions; exact-ref lookup returns one bounded definition. + With `scope: "fonts"`, it queries available font families and exact native styles without + scanning file resources. +- `apply_canvas`: Creates, updates, removes, or activates exact pages and managed roots. Canvas HTML + is optional for page-only operations and native-only updates to existing stable keys inside an + exact managed root; a root can be written directly to an exact off-current page without switching + editor context. The extension resolves, validates, diffs, applies, and + structurally verifies each requested result. Authoring requires edit access to the current Figma + Design file. +- `get_screenshot`: A bounded rendered PNG for selective visual validation. +- `get_structure`: A structural outline (ids, types, geometry) for an exact node, exact managed + page, or the current selection. +- `upload_asset`: Stores a generated PNG/JPEG/GIF in the local Hub and returns an `assetHash` + for canvas authoring. +- Binary assets are returned as metadata + HTTP download URLs (`asset.url`) in tool responses. Asset MCP resources are not exposed. --- -## Key features + + +## Inspect designs ### Inspect CSS code @@ -40,7 +182,7 @@ Shows the CSS and JavaScript code for a selected element. -Select any element, and you can obtain the CSS code through the plugin's Code panel. In addition to standard CSS code, TemPad Dev also provides styles in the form of JavaScript objects, making it convenient for use in JSX and similar scenarios. +Select an element to read its CSS in the extension’s Code panel. In addition to standard CSS code, TemPad Dev also provides styles in the form of JavaScript objects, making it convenient for use in JSX and similar scenarios. @@ -89,7 +231,9 @@ When you hover over a node name section in TemPad Dev's inspect panel, a corresp --- -### Plugins + + +## Output plugins @@ -104,7 +248,7 @@ A TemPad Dev plugin is a simple JavaScript file that exports a plugin object as > [!NOTE] > Plugin code is stored in the browser's local storage. Plugins are not versioned or auto-updated, so you must manually update them from the UI. -#### Creating plugins +### Creating plugins Use the fully typed `definePlugin` function from the `@tempad-dev/plugins` package to simplify plugin creation. @@ -154,7 +298,7 @@ Additionally, you can specify a custom `title` and `lang` for the code block or For full type definitions and helper functions, see [`packages/plugins/src/index.ts`](./packages/plugins/src/index.ts). -#### Deploying a plugin +### Deploying a plugin Ensure your plugin is accessible via a URL that supports cross-origin requests, such as a GitHub repository (or Gist). For instance, you can use a raw URL: @@ -177,7 +321,7 @@ side channels, deliberate memory pressure, and unsafe generated output are outsi Review plugin sources accordingly. See [the threat model](./docs/security/local-mcp-threat-model.md) for the exact guarantees and non-goals. -#### Sharing a plugin +### Sharing a plugin You can also register the plugin into our [plugin registry file](https://github.com/ecomfe/tempad-dev/blob/main/packages/extension/plugins/available-plugins.json) so that your plugin can be installed by name directly. @@ -201,67 +345,6 @@ Current available plugins: -## Agent integration - -TemPad Dev ships an agent integration for coding agents and IDEs. The integration combines: - -- an [MCP](https://modelcontextprotocol.io/) server that lets agents pull code and context directly from the node you have selected in Figma -- an agent skill that teaches the agent how to interpret that evidence in the current repository - -Figma also provides official [remote and desktop MCP servers](https://developers.figma.com/docs/figma-mcp-server/), with the remote server recommended for most users. TemPad Dev is an open, local-control complement for teams that specifically want an inspectable browser-extension pipeline, the existing read-only inspection workflow, programmable output plugins, canonical agent-facing code/token IR, and an explicit context budget. It provides design evidence and a code starting point; the coding agent remains responsible for adapting that evidence to the repository, validating behavior, and producing the final implementation. - -With the TemPad Dev panel open and MCP enabled, the MCP server exposes: - -- `get_code`: High-fidelity JSX/Vue + TailwindCSS code output by default, plus attached assets and the codegen preset/config used. -- `get_structure`: A structural outline (ids, types, geometry) for the current selection. -- Binary assets are returned as metadata + HTTP download URLs (`asset.url`) in tool responses. Asset MCP resources are not exposed. - -### Setup guide - - - - - TemPad Dev agent setup dialog. - - -1. Install Node.js 18.20.0 or later with `npx`. Keep TemPad Dev open in the Figma tab you want the agent to inspect, then enable **Preferences → Agent integration → MCP access**. When prompted, allow the loopback connection to `127.0.0.1`. -2. Select **Set up agents**, choose Codex, Cursor, Claude Code, Gemini, VS Code, OpenCode, or TRAE, and follow the displayed path. Use **Other** for another compatible client. The choice only changes the instructions shown; it does not bind or activate an agent. -3. Prefer the direct action when offered. Every fallback command or config is shown in full for review and copying. Codex and Claude Code plugins include both MCP and the `figma-design-to-code` skill; the other paths show the two required steps separately. - -Keep TemPad Dev open with MCP enabled while using it. If multiple Figma files are connected, click the MCP badge in the panel for the file you want the agent to inspect; that file becomes the active context. - -### MCP connection status - -When the MCP server is enabled, a badge appears in the TemPad Dev panel title bar showing the current connection status: - -- **Unavailable**: The local MCP server is not configured or not running. - - - - - MCP status badge showing Unavailable. - - -- **Inactive**: TemPad Dev is connected to a local MCP server, but this tab is not currently active because multiple Figma tabs are open. Click the badge to activate MCP for this tab (this deactivates MCP in other tabs). - - - - - MCP status badge showing Inactive. - - -- **Active**: The MCP server is running, and this tab is active and ready to respond to MCP tool calls. - - - - - MCP status badge showing Active. - - -### Configuration - -For optional environment variables, see [`packages/mcp-server/README.md`](./packages/mcp-server/README.md). -

Inspect TemPad component code

diff --git a/README.zh-Hans.md b/README.zh-Hans.md index 6a6e63cd..3ab72740 100644 --- a/README.zh-Hans.md +++ b/README.zh-Hans.md @@ -2,11 +2,11 @@ - 展示扩展面板的截图。 + TemPad Dev

-

Figma 上的开放交付工具

+

连接 Figma、开发者和 coding agent 的开放工具

在 Chrome Web Store 安装 @@ -19,17 +19,151 @@ check-script-rewrite

-

+TemPad Dev 是连接 Figma、开发者和 coding agent 的开源工具。你可以直接在浏览器里检查设计、定制代码输出,也可以让 agent 读取设计、创建和修改原生 Figma 内容,并结合项目实现 UI。 + +## 目录 + +- [快速开始](#快速开始) +- [Agent 集成](#agent-集成):[画布设计](#创建和修改-figma-设计)、[代码实现](#根据设计实现代码)、[配置指南](#配置指南)、[连接状态](#mcp-连接状态) +- [检查设计](#检查设计):[CSS 与变量](#查看-css-代码)、[深度选择](#深度选择模式)、[测量](#测量到选中项模式)、[定位](#将选中项滚动到视图中) +- [输出插件](#输出插件):安装、开发与分享 + +## 快速开始 + +1. 从 [Chrome Web Store](https://chromewebstore.google.com/detail/tempad-dev/lgoeakbaikpkihoiphamaeopmliaimpc) 安装 TemPad Dev,打开 Figma Design 文件。 +2. 选中设计中的元素,在 TemPad Dev 面板查看代码、变量和布局信息。手动检查无需配置 agent。 +3. 如需使用 coding agent,启用 **Preferences → Agent integration → MCP access**,点击 **Set up agents**,按所选客户端的说明安装。 + +Agent 连接需要 Node.js 22.x、24.x 或 26+;画布编辑还需要当前 Figma Design 文件的编辑权限。扩展、MCP server 和两个 skill 的配置与升级说明见下文。 + +## Agent 集成 + +通过你已经在使用的 coding agent 或 IDE 处理 Figma 设计。TemPad Dev 提供设计信息和画布操作,agent 结合你的要求与项目上下文完成工作。 + +### 创建和修改 Figma 设计 + +在 Figma 中创建界面、调整布局和文字,或修改已有设计。结果由原生、可编辑的图层构成;任务需要时,可以复用可访问的组件、变量和样式。 + +例如,在连接好 agent 后提出: + +> 在 Figma 中使用可访问的组件创建一个设置页面。 + +也可以选中已有设计后提出: + +> 调整这个页面的间距和文字层级,保留现有组件和内容。 + +`figma-canvas-authoring` skill 指导 agent 检查相关资源、执行修改并检查实际渲染结果。写入需要可编辑的 Figma Design 文件;只读文件和 Dev Mode 中的访问仍然是只读的。 + +### 设计任务控制与评论 + +任务状态栏跟随设计锚点,显示 agent 活动状态和 Stop/Done。Stop 会永久取消当前任务, +重新连接不会恢复该任务的写入。在兼容的 Codex App 中,可以保存元素评论或添加总体评论, +再使用 Queue 或 Steer 发送整批内容。Queue 在宿主确认接收后清空已提交草稿,因此请求仍在 +排队时就可以继续写下一批;确认接收不表示 agent 已完成修改。 + +元素编辑器中,Enter 保存评论,Command/Ctrl+Enter 保存并排队整批评论;总体评论中, +Enter 排队,Command/Ctrl+Enter 使用 Steer。Shift+Enter 换行。Claude、Codex CLI 等客户端 +目前提供任务控制,但不支持发送评论。详细行为和宿主验证范围见 +[评论指南](./agent-plugin/src/README.zh-Hans.md#使用)。 + +### 根据设计实现代码 + +在 Figma 中选中要实现的设计,在目标代码项目中提出: + +> 根据当前 Figma 选区实现 UI,使用这个项目已有的组件和样式约定。 + +TemPad Dev 提供布局、样式、变量引用、组件信息和素材。`figma-design-to-code` skill 指导 agent 结合仓库实现界面,完成验证。生成的设计代码是实现起点,最终代码由 agent 适配项目。 + +这两个工作流通过同一个 MCP 连接访问 Figma。兼容客户端可以安装包含 MCP 配置和两个 skill 的 [Agent Plugin](./agent-plugin/src/README.zh-Hans.md);其它客户端可以分别配置 MCP 和 skill。 + +### 配置指南 + +1. 安装 Node.js 22.x、24.x 或 26+ 并确保 `npx` 可用。在希望 agent 检查的 Figma 标签页中保持 TemPad Dev 打开,然后启用 **Preferences → Agent integration → MCP access**。出现提示时,请允许连接到 loopback 地址 `127.0.0.1`。启用 MCP access 且当前 Figma Design 文件可编辑时,即可进行画布创作。 +2. 点击 **Set up agents**,选择 Codex、Cursor、Claude Code、Gemini、VS Code、OpenCode 或 TRAE,然后按界面显示的路径配置。其它兼容客户端请选择 **Other**。这里的选择只会切换说明,不会绑定或激活 agent。 +3. Codex 和 Claude Code 使用原生 marketplace 安装;Codex App 集成通过原生 IPC 工作,无需生命周期 hooks。Cursor 和 VS Code 使用可移植的 Agent Plugin。对 Gemini、OpenCode、TRAE 及其它尚无兼容 plugin 安装能力的客户端,则使用对应客户端的 MCP 流程并单独安装两个 skill。所有命令和 config 都会完整显示,便于检查和复制。 + +以下以 Gemini 为例,展示分别配置 MCP 和两个 skill 的安装路径: + + + + + Gemini 的 MCP 安装说明。 + + +向下滚动可查看两个 skill 的完整安装命令: + + + + + Gemini 的两个 skill 安装命令。 + + +Codex 和 Claude 的原生 marketplace 命令,以及 Cursor 和 VS Code 的可移植插件安装方式,见 +[Agent Plugin 指南](./agent-plugin/src/README.zh-Hans.md)。 + +所有 plugin 和直接使用 `npx` 的配置路径都使用 `@tempad-dev/mcp@latest`。 + +本次画布创作版本应配套使用扩展 **0.21.0**、MCP server **0.8.0** 和 Agent Plugin +**0.2.0**。更新既有安装时,请参阅 [升级指南](./agent-plugin/src/README.zh-Hans.md#升级)。 + +使用期间请保持 TemPad Dev 打开并启用 MCP。如果连接了多个 Figma 文件,请点击目标文件面板中的 MCP 徽标;该文件会成为 agent 当前访问的上下文。 + +### MCP 连接状态 + +启用 MCP 服务器后,TemPad Dev 面板标题栏中会显示一个徽标,表示当前的连接状态: + +- **Unavailable**:本地 MCP 服务器未配置或未运行。 + + + + + MCP 状态徽标,显示为 Unavailable。 + + +- **Inactive**:TemPad Dev 已连接到本地 MCP 服务器,但由于打开了多个 Figma 标签页,此标签页当前未激活。点击徽标即可为当前标签页激活 MCP(同时会停用其他标签页的 MCP)。 + - - - 展示扩展面板代码视图的截图。 + + + MCP 状态徽标,显示为 Inactive。 -

+ +- **Active**:MCP 服务器正在运行,并且当前标签页已激活,可随时响应 MCP 工具调用。 + + + + + MCP 状态徽标,显示为 Active。 + + +### 配置项 + +`@tempad-dev/mcp` 的环境变量配置请参见 [`packages/mcp-server/README.zh-Hans.md`](./packages/mcp-server/README.zh-Hans.md)。 + +### MCP 工具 + +以下工具供 agent 调用;日常使用可以直接描述任务。 + +- `get_code`:默认输出高保真的 JSX/Vue + TailwindCSS 代码,同时包含相关资源以及使用的 codegen 预设和配置。 +- `get_design_system`:创建不可变、确定性的紧凑目录,按资源类型平衡分页返回可访问页面的 + 组件定义,以及本地或被定义直接引用的变量、集合/模式、样式和 shader 定义;既不扫描 + 画布中的使用情况,也不加载所有页面。游标可继续读取遗漏定义;使用同一目录精确查询 + 某个引用时,返回该资源的有界定义。使用 `scope: "fonts"` 可查询当前可用字体家族和精确 + 原生样式,不扫描文件资源。 +- `apply_canvas`:对精确页面或托管根节点执行创建、更新、删除或激活。仅操作页面时可省略 + Canvas HTML;对精确托管根内既有稳定 key 的纯 native 更新也可省略。也可以直接把根节点写入 + 非当前的精确目标页面,而不切换编辑器上下文。扩展会在本地解析、验证、计算与实时画布的 + 差异、应用修改并校验结构。画布创作要求当前 Figma Design 文件具有编辑权限。 +- `get_screenshot`:返回一张有大小限制的渲染 PNG,用于按需视觉验证。 +- `get_structure`:精确节点、精确托管页面或当前选中节点的结构信息(id、类型、几何数据)。 +- `upload_asset`:将生成的 PNG/JPEG/GIF 存入本地 Hub,并返回供画布创作使用的 `assetHash`。 +- 二进制资源会通过工具响应中的元数据 + HTTP 下载地址(`asset.url`)提供;MCP 不再暴露 asset 资源模板。 --- -## 主要功能 + + +## 检查设计 ### 查看 CSS 代码 @@ -39,7 +173,7 @@ 展示所选元素的 CSS 和 JavaScript 代码。 -选择任意元素后,你可以在插件的 Code 面板中获取对应的 CSS 代码。除了标准的 CSS 代码之外,TemPad Dev 还会以 JavaScript 对象的形式提供样式,方便在 JSX 等场景中直接使用。 +选择元素后,你可以在扩展的 Code 面板中获取对应的 CSS 代码。除了标准的 CSS 代码之外,TemPad Dev 还会以 JavaScript 对象的形式提供样式,方便在 JSX 等场景中直接使用。 @@ -88,7 +222,9 @@ --- -### 插件 + + +## 输出插件 @@ -103,7 +239,7 @@ > [!NOTE] > 插件代码存储在浏览器的本地存储中,不支持版本管理或自动更新,需要你在 UI 中手动更新。 -#### 创建插件 +### 创建插件 使用 `@tempad-dev/plugins` 包中提供的、带完整类型定义的 `definePlugin` 函数,可以简化插件的创建过程。 @@ -153,7 +289,7 @@ export default definePlugin({ 完整的类型定义和辅助函数请参见 [`packages/plugins/src/index.ts`](./packages/plugins/src/index.ts)。 -#### 部署插件 +### 部署插件 请确保你的插件可以通过支持跨域请求的 URL 访问,例如托管在 GitHub 仓库或 Gist 中。比如可以使用 raw 地址: @@ -173,7 +309,7 @@ sandboxed extension page 内启动一个全新的 Worker,并在完成或五秒 蓄意内存压力以及不安全的生成内容不属于该边界。仍建议审查插件来源。准确保证与非目标见 [威胁模型](./docs/security/local-mcp-threat-model.md)。 -#### 分享插件 +### 分享插件 你也可以将插件注册到我们的 [插件注册表文件](https://github.com/ecomfe/tempad-dev/blob/main/packages/extension/plugins/available-plugins.json) 中,这样就可以通过插件名直接安装。 @@ -197,67 +333,6 @@ sandboxed extension page 内启动一个全新的 Worker,并在完成或五秒 -## Agent 集成 - -TemPad Dev 内置了面向编码 agent 和 IDE 的 Agent 集成。该集成包含: - -- 一个 [MCP](https://modelcontextprotocol.io/) 服务器,使 agent 可以直接从你在 Figma 中选中的节点拉取代码和上下文 -- 一个 agent skill,用于指导 agent 在当前仓库中理解并使用这些证据 - -Figma 也提供官方的 [remote 与 desktop MCP server](https://developers.figma.com/docs/figma-mcp-server/),并建议大多数用户优先使用 remote server。TemPad Dev 的定位是一个开放、强调本地控制的补充方案,适合明确需要可审计的浏览器扩展链路、现有只读检查流程、可编程输出插件、规范化的 agent-facing 代码/token IR,以及显式上下文预算的团队。TemPad Dev 提供设计证据与代码起点;最终仍由 coding agent 结合目标仓库完成适配、验证和实现。 - -打开 TemPad Dev 面板并启用 MCP 后,MCP 服务器会暴露以下能力: - -- `get_code`:默认输出高保真的 JSX/Vue + TailwindCSS 代码,同时包含相关资源以及使用的 codegen 预设和配置。 -- `get_structure`:当前选中节点的结构信息(id、类型、几何数据)。 -- 二进制资源会通过工具响应中的元数据 + HTTP 下载地址(`asset.url`)提供;MCP 不再暴露 asset 资源模板。 - -### 配置指南 - - - - - TemPad Dev agent setup 对话框。 - - -1. 安装 Node.js 18.20.0 或更高版本并确保 `npx` 可用。在希望 agent 检查的 Figma 标签页中保持 TemPad Dev 打开,然后启用 **Preferences → Agent integration → MCP access**。出现提示时,请允许连接到 loopback 地址 `127.0.0.1`。 -2. 点击 **Set up agents**,选择 Codex、Cursor、Claude Code、Gemini、VS Code、OpenCode 或 TRAE,然后按界面显示的路径配置。其它兼容客户端请选择 **Other**。这里的选择只会切换说明,不会绑定或激活 agent。 -3. 如果界面提供直接操作,请优先使用。所有备用命令和 config 都会完整显示,便于检查和复制。Codex 与 Claude Code 的 plugin 同时包含 MCP 和 `figma-design-to-code` skill;其它路径会分别展示两个必要步骤。 - -使用期间请保持 TemPad Dev 打开并启用 MCP。如果连接了多个 Figma 文件,请点击目标文件面板中的 MCP 徽标;该文件会成为 agent 当前访问的上下文。 - -### MCP 连接状态 - -启用 MCP 服务器后,TemPad Dev 面板标题栏中会显示一个徽标,表示当前的连接状态: - -- **Unavailable**:本地 MCP 服务器未配置或未运行。 - - - - - MCP 状态徽标,显示为 Unavailable。 - - -- **Inactive**:TemPad Dev 已连接到本地 MCP 服务器,但由于打开了多个 Figma 标签页,此标签页当前未激活。点击徽标即可为当前标签页激活 MCP(同时会停用其他标签页的 MCP)。 - - - - - MCP 状态徽标,显示为 Inactive。 - - -- **Active**:MCP 服务器正在运行,并且当前标签页已激活,可随时响应 MCP 工具调用。 - - - - - MCP 状态徽标,显示为 Active。 - - -### 配置项 - -`@tempad-dev/mcp` 的环境变量配置请参见 [`packages/mcp-server/README.zh-Hans.md`](./packages/mcp-server/README.zh-Hans.md)。 -

查看 TemPad 组件代码

diff --git a/TESTING.md b/TESTING.md index 66acf6b4..eb30df96 100644 --- a/TESTING.md +++ b/TESTING.md @@ -36,9 +36,20 @@ Root: - `pnpm test` (watch package-owned tests in parallel) - `pnpm test:run` (single run via package-owned `test:run` scripts) - `pnpm test:coverage` (workspace coverage) +- `pnpm mcp:check-bridge` (build the Hub and exercise legacy/current WebSocket peers through + actual MCP calls, including assets, reconnects, upgrade errors, and task routing) +- `pnpm agent-plugin:check-installer` (networked discovery smoke test with `plugins@1.3.4`; + run after `pnpm agent-plugin:build`, without installing into a host) - `pnpm --filter @tempad-dev/extension test:setup` (install extension browser runtime) - `pnpm --filter @tempad-dev/extension test:node` (extension node tests only) - `pnpm --filter @tempad-dev/extension test:browser` (extension browser tests only) +- `pnpm agent-eval:authoring [...]` (inspect comparable rollout evidence) +- `pnpm agent-eval:preflight [--checkout ] [--app-path ]` (reject an absent or partial + checkout runtime, inactive extension, or development plugin that does not match + the configured Codex desktop host before page creation) +- `pnpm agent-eval:skills ` (fingerprint the presented skill catalog) +- `pnpm agent-eval:log ` (retain the small amount + of provenance needed to trust a live authoring run) Per package: @@ -57,6 +68,9 @@ Per package: - `pnpm --filter @tempad-dev/mcp test:coverage` - `pnpm --filter @tempad-dev/shared test:run` - `pnpm --filter @tempad-dev/shared test:coverage` +- `pnpm --filter @tempad-dev/site test:run` (node and Chromium reader regressions) +- `pnpm --filter @tempad-dev/site test:browser` +- `pnpm --filter @tempad-dev/site test:setup` (install Chromium for site browser tests) ## Required checks by change type @@ -76,11 +90,44 @@ When changing extension build/runtime behavior: - `pnpm build:ext` - If packaging impacted: `pnpm zip` +When changing the Hub/extension compatibility path or legacy assets: + +- `pnpm mcp:check-bridge` runs an isolated Hub with temporary runtime, log, and asset directories + and a dedicated extension Origin. It does not connect to the user's Hub or Figma sessions. + One of the normal loopback candidate ports must be available. The old receiving schema is + frozen from extension 0.20.0 / MCP 0.7.1; do not derive it from current shared schemas. +- Keep the broker regression for new-extension/old-Hub rejection and recovery. This deterministic + transport check does not replace installed-host Queue/Steer/Stop acceptance. + +When changing agent-plugin packaging or marketplace routing: + +- `pnpm agent-plugin:build` and inspect the generated targets and all three marketplace manifests. +- `pnpm agent-plugin:check-installer` verifies both the marketplace entry and compatibility + package with the real CLI. It downloads a pinned installer outside the unit-test suite and + discovers only a temporary fixture; it does not change any installed plugins. + When changing DOM/browser runtime behavior in extension: - `pnpm --filter @tempad-dev/extension test:browser` - Use Playwright browser tests only; do not add jsdom-based tests. +When changing the end-to-end authoring evaluation process or its runtime identity gate: + +- Follow `docs/testing/agent-authoring-evolution.md`. +- Use the stable minimal open-run wrapper from the evolution runbook, varying only the product + platform and product situation by default; add a broad visual direction only when relevant + to the question. The agent chooses dimensions and screen/flow extent. Freeze the prompt, intent, + model, and reasoning effort immediately before dispatch; do not add a predicted result or evaluator-authored solution detail. +- Judge the authored result as a whole in plain language. Treat screenshots, native structure, + timing, and tool traces as clues: inspect only what can confirm or explain the judgment. Do not + introduce fixed quality axes, scores, finding counts, or promotion gates. +- Add deterministic tests for run-log integrity, runtime fingerprinting, bridge handshake, and + write-before rejection at the owning package layers. Deterministic checks do not need live-run + log entries. +- A fresh live Figma task is required only when the selected question needs agent + discoverability, visual, structural, transfer, or drift evidence; it is not a default check for + deterministic process infrastructure. + ## Coverage rules (operational) - Workspace coverage is configured in root `vitest.config.ts`. @@ -136,3 +183,4 @@ When changing DOM/browser runtime behavior in extension: - Testing architecture: `docs/testing/architecture.md` - Extension get_code requirements: `docs/extension/mcp-get-code-requirements.md` - Extension get_code design: `docs/extension/mcp-get-code-design.md` +- Agent authoring evolution: `docs/testing/agent-authoring-evolution.md` diff --git a/agent-plugin/src/CHANGELOG.md b/agent-plugin/src/CHANGELOG.md new file mode 100644 index 00000000..1e9275fc --- /dev/null +++ b/agent-plugin/src/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +## 0.2.0 + +- Routed the `plugins` CLI through its own hook-free compatibility package and marketplace, + with installer discovery checks for both skills and MCP configuration. +- Added design-task lifecycle guidance and Stop/Done controls. Codex App uses MCP metadata and + native IPC without hooks; Claude uses installed lifecycle and Stop hooks. +- Documented native Codex App comments, Queue/Steer timing, and element-editor Save & Queue + shortcuts. Other clients retain task controls without comment delivery. + +- Added `figma-canvas-authoring` for creating and editing native Figma designs, alongside the + existing `figma-design-to-code` skill. +- Added progressive references for native authoring, fonts, images, icons, resource bindings, + and scoped editing. Direct, Reuse, and Author workflows keep resource decisions tied to the task. +- Grounded new compositions in inspectable evidence and required inspection of the rendered result + plus relevant native facts, with focused repair of observed defects. +- Made the portable Agent Plugins 1.0 bundle the shared source for installation, with synchronized + Codex and Claude compatibility manifests and refreshed icons. +- Paired the plugin with extension 0.21.0 and MCP 0.8.0 through `@tempad-dev/mcp@latest`. + The MCP server requires Node.js 22.x, 24.x, or 26+. diff --git a/agent-plugin/src/README.md b/agent-plugin/src/README.md new file mode 100644 index 00000000..3e7d6d69 --- /dev/null +++ b/agent-plugin/src/README.md @@ -0,0 +1,173 @@ +# TemPad Dev Agent Plugin + +[Simplified Chinese](./README.zh-Hans.md) + +Read, edit, and implement Figma designs through your coding agent or IDE. This plugin includes: + +- `figma-canvas-authoring`: create and revise native Figma designs, reusing accessible components, variables, and styles as needed. +- `figma-design-to-code`: use Figma design context to implement UI with your project’s components and conventions. +- The TemPad Dev MCP server configuration: connect to the Figma file open in your browser. + +Requires the TemPad Dev browser extension. Canvas editing also requires edit access to the Figma Design file. For manual inspection and output plugins, see the full [user guide](https://github.com/ecomfe/tempad-dev/blob/main/README.md). + +This plugin follows [Agent Plugins 1.0](https://agent-plugins.org/) and is published from one +source as a standard package, a compatibility package for the `plugins` CLI, and a package per +native host. Prefer native installation on Codex and Claude. Codex App binds tasks over MCP +metadata and native IPC, so its plugin registers no lifecycle hooks. + +## Cursor and VS Code installation + +For Cursor and VS Code, select the corresponding target: + +```bash +npx plugins add ecomfe/tempad-dev --target cursor +npx plugins add ecomfe/tempad-dev --target vscode +``` + +The installer reads `.plugin/marketplace.json` and installs the generated `plugins-cli` +compatibility package, which contains both skills and MCP configuration without lifecycle hooks. +This path is verified with `plugins@1.3.4`. Agent Plugins 1.0 consumers can use the separate +`agent-plugin/targets/standard` package; the current `plugins` CLI does not read that format. + +## Codex and Claude installation + +Use these native marketplace flows for Codex and Claude. Claude's lifecycle hooks require +the host's normal trust review; Codex does not register hooks. +The `--sparse` paths limit checkout to the host's marketplace and generated package, including +its skills and any required hooks. Codex repeats `--sparse` for each path; Claude accepts multiple +paths after one `--sparse`. The `plugins` CLI used for Cursor and VS Code has no equivalent flag. + +### Codex + +```bash +codex plugin marketplace add ecomfe/tempad-dev --ref main --sparse .agents --sparse agent-plugin/targets/codex +codex plugin add tempad-dev@tempad-dev +``` + +You can also install **TemPad Dev** from the Codex app plugin directory after adding the +marketplace. + +### Claude Code and Claude Desktop + +```bash +claude plugin marketplace add ecomfe/tempad-dev --sparse .claude-plugin agent-plugin/targets/claude +claude plugin install tempad-dev@tempad-dev +``` + +The plugin appears in Claude Desktop after the marketplace is added. + +For clients without Agent Plugin support, follow the direct MCP and standalone skill setup in the +[complete setup guide](https://github.com/ecomfe/tempad-dev/blob/main/README.md#agent-integration). + +## Usage + +Before using the integration, open TemPad Dev in Figma, then open **Preferences → Agent +integration** and enable **MCP access**. Canvas authoring is available while the active Figma +Design file is editable. + +## Upgrading + +The canvas-authoring release pairs Agent Plugin **0.2.0**, TemPad Dev extension **0.21.0**, and +MCP server **0.8.0**. Node.js **22.x, 24.x, or 26+** is required for the MCP server. + +1. Update the browser extension and reload the Figma tab. +2. Update the installed plugin through the client or installer used originally. With standalone + setup, update both `figma-design-to-code` and `figma-canvas-authoring`. +3. Keep the release MCP configuration on `@tempad-dev/mcp@latest`; replace any previous + `@alpha` or fixed alpha version. Reconnect the MCP client and start a new task so it loads the + updated tools and skills. If a stale Hub is reported, close tasks using the old MCP server + before reconnecting. +4. Open TemPad Dev, enable **MCP access**, and click the MCP badge in the intended Figma tab when + a session choice is needed. The badge selects the file receiving tool calls. + +## Packaging source of truth + +Everything is authored once under `agent-plugin/src/` and published by +`pnpm agent-plugin:build`. Every target is generated; never edit one. + +| Path | Role | +| ---------------------------------- | ------------------------------------------------- | +| `agent-plugin/src/plugin.json` | Standard manifest; owns all shared metadata | +| `agent-plugin/src/mcp.json` | Standard MCP configuration | +| `agent-plugin/src/skills/` | Both skills | +| `agent-plugin/src/clients/claude/` | Claude lifecycle hooks | +| `agent-plugin/src/clients/codex/` | Codex directory presentation (`interface.json`) | +| `agent-plugin/src/clients/shared/` | Hook transport shared by hosts | +| `agent-plugin/targets/standard` | Generated; also the standalone skills URL | +| `agent-plugin/targets/plugins-cli` | Generated compatibility package for `plugins` CLI | +| `agent-plugin/targets/codex` | Generated Codex marketplace package | +| `agent-plugin/targets/claude` | Generated Claude marketplace package | + +Each target carries only what its own installer reads. A standard consumer projects `plugin.json` +onto the host itself, so shipping a host layout beside it would create a second source of truth for +the same package; each host target likewise omits the standard manifests and the other host's +directory. Only Claude loads lifecycle hooks, so only `targets/claude` carries `clients/`. +The `plugins-cli` package carries `.plugin/plugin.json` and `.mcp.json`; its marketplace is +generated separately so the CLI does not select the Claude package. Verify discovery through +the actual CLI with `pnpm agent-plugin:check-installer` after changing packaging. + +## Task controls and client enhancements + +Design tasks can pause and resume across turns. Figma's canvas status bar shows the +source client, a Stop control, and a counted comment entry. Stop permanently cancels +the current task; subsequent design work explicitly begins a fresh task. Lifecycle pauses can resume +with a new lease epoch and require a fresh canvas read before writing. See the +[task and client design](https://github.com/ecomfe/tempad-dev/blob/main/docs/extension/mcp-design-tasks.md). + +The normal setup is the TemPad Dev extension configuration followed by this plugin's +installation. There are no control +addresses, environment variables, or helper services for users to configure. + +Codex App binds tasks from host-supplied MCP metadata and follows native conversation +state through the existing IPC connection. Claude retains lifecycle and Stop hooks. +Comments are delivered only through native conversation messages on compatible Codex App +hosts. TemPad Dev discovers the original conversation through the App's existing local +connection. Where supported, Queue submits the batch to the host's native queue, where it waits until the +conversation is ready. As soon as the host confirms admission, TemPad Dev clears the submitted +comments and markers, stops the sending indicator, and allows another batch. This confirmation +means the host received the comments, not that the agent finished the requested changes. +When native queue admission is unavailable, Queue waits in the Hub for existing queued +messages to clear and the conversation to accept a new response. The sending indicator +remains until that admission is confirmed. If queue state cannot be checked, comments +remain saved and delivery reports an error. Compatible hosts also support native server-queue +admission; these messages may appear in Codex after its next queue refresh. +Steer adds comments to an active response or starts a response when the conversation is idle. +Failed or uncertain delivery retains drafts; uncertain delivery is not automatically resent. +Comments never fall back to hooks. + +| Editor | Enter or click the submit button | Command/Ctrl+Enter or Command/Ctrl+click | +| --------------------------------- | -------------------------------- | ---------------------------------------- | +| Element comment | Save the comment without sending | Save & Queue the whole batch | +| General comment in the status bar | Queue the whole batch | Steer the whole batch | + +A batch includes all saved element comments and the general comment. Shift+Enter inserts a +newline in either editor. Saving an element comment alone does not send it. + +Claude, Codex CLI, and other clients currently provide task status and Stop/Done without +comment controls. Previously saved drafts remain in extension-local storage. + +Stop immediately blocks further writes from the current task and permanently cancels it +once an executing operation drains. The cancelled task cannot resume. The agent respects +Stop without automatically replacing it; necessary or user-requested design work can +explicitly begin a fresh task. No separate Figma unlock is needed. Codex App Stop also +requests native interruption of the exact bound turn; a delayed Stop cannot interrupt a +newer turn. Stop and Done also remove this task's comments that are still in the native queue, +leaving unrelated messages intact. Failed cleanup is retried after reconnection; already consumed +input cannot be recalled. Local cancellation remains effective if the host is unavailable. Claude +conveys Stop at the next hooked tool boundary. Native Codex delivery is enabled +only after the exact conversation owner reports support; no manual connection setup +is required. See the task and client design for the current validation scope. + +The native adapter uses Unix sockets on macOS/Linux and Codex's local named pipe on Windows. +macOS Steer and paused native queue admission/removal have been exercised against Codex App +26.908.70816. Automatic queue execution and the complete installed-plugin/Figma UI flow still +require live verification. Windows and Linux coverage is limited to source inspection and +automated tests; it does not establish complete host support. + +With a supported connection, select an element, save its feedback draft, then send the +numbered batch from the canvas status bar. Drafts can be edited or deleted and survive +navigation and closed tabs in extension-local storage, isolated by file, agent conversation, and task. +Successful delivery clears the submitted markers together; restoring drafts never sends them. + +The agent reports the result and its Figma link in the conversation, where users can +continue with follow-up requests. Task tools return text and structured data. diff --git a/agent-plugin/src/README.zh-Hans.md b/agent-plugin/src/README.zh-Hans.md new file mode 100644 index 00000000..bc5feda9 --- /dev/null +++ b/agent-plugin/src/README.zh-Hans.md @@ -0,0 +1,130 @@ +# TemPad Dev Agent Plugin + +[English](./README.md) + +在你的 coding agent 或 IDE 中读取、编辑和实现 Figma 设计。这个插件包含: + +- `figma-canvas-authoring`:创建和修改原生 Figma 设计,按任务需要复用可访问的组件、变量和样式。 +- `figma-design-to-code`:读取 Figma 设计信息,结合项目已有组件和约定实现 UI。 +- TemPad Dev MCP server 配置:连接浏览器中打开的 Figma 文件。 + +需要安装 TemPad Dev 浏览器扩展。画布编辑还需要 Figma Design 文件的编辑权限。手动检查设计和输出插件的完整说明见 [使用指南](https://github.com/ecomfe/tempad-dev/blob/main/README.zh-Hans.md)。 + +本插件遵循 [Agent Plugins 1.0](https://agent-plugins.org/),并从同一份内容源发布一个标准包 +(供自行适配该标准的客户端使用)、一个 `plugins` CLI 兼容包,以及每个原生宿主各一个包。Codex 与 Claude 请优先使用原生安装。 +Codex App 通过 MCP 元数据和原生 IPC 绑定任务,其插件不注册生命周期 hooks。 + +## Cursor 和 VS Code 安装 + +Cursor 和 VS Code 请指定对应的 target: + +```bash +npx plugins add ecomfe/tempad-dev --target cursor +npx plugins add ecomfe/tempad-dev --target vscode +``` + +安装器读取 `.plugin/marketplace.json`,安装生成的 `plugins-cli` 兼容包,其中包含两个 skill +和 MCP 配置,不包含生命周期 hooks。此路径已通过 `plugins@1.3.4` 验证。支持 Agent Plugins 1.0 +的客户端可使用独立的 `agent-plugin/targets/standard` 标准包;当前 `plugins` CLI 不读取该格式。 + +## Codex 和 Claude 安装 + +使用以下原生 marketplace 流程。Claude 提示时,请检查并信任插件的生命周期 hooks;Codex 不注册 hooks。 +`--sparse` 将检出范围限制为对应宿主的 marketplace 和生成包,包含所需的 skill 及 hooks。 +Codex 为每个路径重复指定 `--sparse`;Claude 在一个 `--sparse` 后接受多个路径。 +Cursor 和 VS Code 使用的 `plugins` CLI 没有对应参数。 + +### Codex + +```bash +codex plugin marketplace add ecomfe/tempad-dev --ref main --sparse .agents --sparse agent-plugin/targets/codex +codex plugin add tempad-dev@tempad-dev +``` + +添加 marketplace 后,也可以从 Codex 应用的插件目录安装 **TemPad Dev**。 + +### Claude Code 和 Claude Desktop + +```bash +claude plugin marketplace add ecomfe/tempad-dev --sparse .claude-plugin agent-plugin/targets/claude +claude plugin install tempad-dev@tempad-dev +``` + +添加 marketplace 后,该插件也会出现在 Claude Desktop 中。 + +不支持 Agent Plugin 的客户端,请按照 +[完整配置指南](https://github.com/ecomfe/tempad-dev/blob/main/README.zh-Hans.md#agent-集成)直接配置 MCP 并安装独立 skill。 + +## 使用 + +使用前,请在 Figma 中打开 TemPad Dev,然后进入 **Preferences → Agent integration** +并启用 **MCP access**。启用后,只要当前 Figma Design 文件可编辑,即可进行画布创作。 + +设计任务的状态栏显示 agent 状态、Stop/Done 和评论入口。Stop 会立即阻止当前任务继续写入, +在执行中的操作结束后永久取消该任务;重新连接也不会恢复它。后续设计工作需要明确开始新任务。 + +评论目前仅支持通过兼容 Codex App 的原生会话通道发送。Queue 将整批评论交给宿主的原生队列, +等待会话可以执行时再处理。宿主确认接收后,TemPad Dev 会清空本批评论和标记、停止发送指示, +并允许继续输入下一批;这表示已接收,不表示 agent 已完成修改。如果原生入队不可用, +Queue 会在 Hub 中等待已有排队消息清空、会话能接收新回复,此时发送指示会保留到确认接收。 +如果无法确认队列状态,会保留评论并报告发送错误。兼容宿主也支持原生服务端队列入队, +这些消息可能会在 Codex 下一次刷新队列时才显示。 +Steer 会将评论追加到正在执行的回复,空闲时直接开始新回复。投递失败或结果不确定时保留草稿, +结果不确定的评论不会自动重发,也不会回退到 hooks。 + +| 编辑位置 | Enter 或点击提交按钮 | Command/Ctrl+Enter 或 Command/Ctrl+点击 | +| ------------------ | -------------------- | ---------------------------------------- | +| 元素评论 | 保存当前评论,不发送 | Save & Queue:保存当前评论并排队整批评论 | +| 状态栏中的总体评论 | 排队整批评论 | 使用 Steer 发送整批评论 | + +整批评论包含全部已保存的元素评论和总体评论;两个编辑器中都可以用 Shift+Enter 换行。 +草稿按文件、会话和任务隔离,关闭标签页后仍保留,恢复草稿不会自动发送。 + +Codex App 的任务绑定和状态同步使用 MCP 元数据及原生 IPC,不依赖 hooks。Stop 还会请求中断 +对应的 Codex 回合,迟到的 Stop 不会中断较新的回合。Stop 和 Done 会移除当前任务尚未执行的 +原生队列评论,保留其它消息;清理失败后会在重新连接时重试,已被宿主取走的输入无法撤回。 +宿主不可用时,本地取消仍然生效。Claude 保留生命周期和 Stop 通知 hooks;Claude、Codex CLI +等尚未接入原生投递的客户端提供任务状态和 Stop/Done,但不显示评论入口,已有草稿不会删除。 + +原生适配器在 macOS/Linux 上使用 Unix socket,在 Windows 上使用 Codex 的本机 Named Pipe。 +已在 macOS Codex App 26.908.70816 上实测 Steer,以及暂停状态下的原生队列入队和移除。 +自动执行和完整的已安装插件/Figma UI 流程仍待实测;Windows/Linux 的证据限于源码检查和 +自动化测试,尚不能据此宣称完整宿主支持。 + +## 升级 + +本次画布创作版本应配套使用 Agent Plugin **0.2.0**、TemPad Dev 扩展 **0.21.0** 和 MCP +server **0.8.0**。MCP server 要求 Node.js **22.x、24.x 或 26+**。 + +1. 更新浏览器扩展,并重新加载 Figma 标签页。 +2. 通过原先使用的客户端或安装器更新 plugin。独立配置时,请同时更新 + `figma-design-to-code` 和 `figma-canvas-authoring`。 +3. 正式版 MCP 配置使用 `@tempad-dev/mcp@latest`;请替换旧的 `@alpha` 或固定 alpha 版本。 + 重新连接 MCP client 并新建任务,以加载更新后的工具和 skill。若提示 Hub 过期,请先关闭 + 使用旧 MCP server 的任务,再重新连接。 +4. 打开 TemPad Dev 并启用 **MCP access**;需要选择会话时,点击目标 Figma 标签页内的 MCP + badge。实际接收工具调用的文件由该 badge 选择。 + +## 封装内容源 + +所有内容只在 `agent-plugin/src/` 下编写一次,由 `pnpm agent-plugin:build` 生成各个产物。 +所有产物都是生成的,请勿直接编辑。 + +| 路径 | 作用 | +| ---------------------------------- | -------------------------------------- | +| `agent-plugin/src/plugin.json` | 标准清单,拥有全部公共 metadata | +| `agent-plugin/src/mcp.json` | 标准 MCP 配置 | +| `agent-plugin/src/skills/` | 两个 skill | +| `agent-plugin/src/clients/claude/` | Claude 生命周期 hooks | +| `agent-plugin/src/clients/codex/` | Codex 目录展示信息(`interface.json`) | +| `agent-plugin/src/clients/shared/` | 宿主共用的 hook 传输脚本 | +| `agent-plugin/targets/standard` | 生成产物,同时是独立 skills 的安装地址 | +| `agent-plugin/targets/plugins-cli` | 为 `plugins` CLI 生成的兼容包 | +| `agent-plugin/targets/codex` | 生成的 Codex marketplace 包 | +| `agent-plugin/targets/claude` | 生成的 Claude marketplace 包 | + +每个产物只携带自己的安装方式会读取的内容。标准客户端会自行把 `plugin.json` 适配到宿主, +因此在它旁边放置宿主清单会让同一个包出现第二个事实来源;两个宿主产物同理省略标准清单 +以及对方宿主的目录。只有 Claude 会加载生命周期 hooks,因此只有 `targets/claude` 携带 `clients/`。 +`plugins-cli` 包使用 `.plugin/plugin.json` 和 `.mcp.json`,由独立生成的 marketplace 入口路由, +避免 CLI 选中 Claude 包。修改封装后运行 `pnpm agent-plugin:check-installer`,验证实际 CLI 的发现结果。 diff --git a/agent-plugin/src/assets/icon-padded.svg b/agent-plugin/src/assets/icon-padded.svg new file mode 100644 index 00000000..2e8c6946 --- /dev/null +++ b/agent-plugin/src/assets/icon-padded.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/agent-plugin/src/clients/claude/hooks.json b/agent-plugin/src/clients/claude/hooks.json new file mode 100644 index 00000000..9efe24ec --- /dev/null +++ b/agent-plugin/src/clients/claude/hooks.json @@ -0,0 +1,60 @@ +{ + "description": "Bind Figma tasks, collect user feedback at host lifecycle boundaries, and honor task Stop.", + "hooks": { + "Stop": [ + { + "hooks": [ + { + "type": "command", + "command": "node \"${CLAUDE_PLUGIN_ROOT}/clients/shared/lifecycle.mjs\" claude", + "timeout": 1 + } + ] + } + ], + "SessionEnd": [ + { + "hooks": [ + { + "type": "command", + "command": "node \"${CLAUDE_PLUGIN_ROOT}/clients/shared/lifecycle.mjs\" claude", + "timeout": 1 + } + ] + } + ], + "PostToolUse": [ + { + "hooks": [ + { + "type": "command", + "command": "node \"${CLAUDE_PLUGIN_ROOT}/clients/shared/lifecycle.mjs\" claude", + "timeout": 1 + } + ] + } + ], + "PreToolUse": [ + { + "hooks": [ + { + "type": "command", + "command": "node \"${CLAUDE_PLUGIN_ROOT}/clients/shared/lifecycle.mjs\" claude", + "timeout": 1 + } + ] + } + ], + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "node \"${CLAUDE_PLUGIN_ROOT}/clients/shared/lifecycle.mjs\" claude", + "timeout": 1 + } + ] + } + ] + } +} diff --git a/agent-plugin/src/clients/codex/interface.json b/agent-plugin/src/clients/codex/interface.json new file mode 100644 index 00000000..96e10bb6 --- /dev/null +++ b/agent-plugin/src/clients/codex/interface.json @@ -0,0 +1,24 @@ +{ + "displayName": "TemPad Dev", + "shortDescription": "Inspect, edit, and implement Figma designs with your agent.", + "longDescription": "TemPad Dev connects your coding agent to Figma. Read designs, components, variables, and assets; create and edit native Figma layers; and implement existing designs using your project’s conventions. Includes the MCP connection and skills for canvas editing and design-to-code. Requires the TemPad Dev browser extension; canvas editing also requires edit access to the Figma Design file.", + "developerName": "TemPad Dev", + "category": "Design", + "capabilities": [ + "Agent integration", + "MCP", + "Design-to-code", + "Canvas authoring", + "Design systems", + "Frontend" + ], + "websiteURL": "https://github.com/ecomfe/tempad-dev", + "defaultPrompt": [ + "Implement the selected Figma design using this project’s components and styles.", + "Create an editable settings screen in Figma using the available components.", + "Update the spacing and typography in this Figma design." + ], + "brandColor": "#0098FF", + "composerIcon": "./assets/icon-padded.svg", + "logo": "./assets/icon-padded.svg" +} diff --git a/agent-plugin/src/clients/shared/lifecycle.mjs b/agent-plugin/src/clients/shared/lifecycle.mjs new file mode 100644 index 00000000..dcf0353b --- /dev/null +++ b/agent-plugin/src/clients/shared/lifecycle.mjs @@ -0,0 +1,123 @@ +// Installed hooks exchange lifecycle identity and Stop notices with the existing Hub. They never +// launch an agent, poll a model, change host trust, or unlock a stopped Figma file. +import { randomUUID } from 'node:crypto' +import { connect } from 'node:net' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import process from 'node:process' +import { clearTimeout, setTimeout } from 'node:timers' + +let socket +const deadline = setTimeout(() => process.exit(0), 750) +try { + let text = '' + for await (const chunk of process.stdin) { + text += String(chunk) + if (text.length > 1_000_000) process.exit(0) + } + const input = JSON.parse(text) + if (typeof input.session_id !== 'string' || input.agent_id || input.subagent_id) process.exit(0) + const event = input.hook_event_name + if ( + !['PreToolUse', 'PostToolUse', 'UserPromptSubmit', 'Stop', 'Interrupt', 'SessionEnd'].includes( + event + ) + ) + process.exit(0) + let taskId + if ( + event === 'PostToolUse' && + /tempad[-_]dev.*__(?:begin_design|resume_design)$/.test(input.tool_name || '') + ) { + const response = input.tool_response + if (!response?.isError) { + let result = response?.structuredContent || response?.result?.structuredContent || response + if (!result?.taskId && Array.isArray(response?.content)) { + const text = response.content.find((value) => value.type === 'text')?.text + if (text) { + try { + result = JSON.parse(text) + } catch { + /* This tool did not return a task. */ + } + } + } + if (typeof result?.taskId === 'string') taskId = result.taskId + } + } + const identity = { + version: 1, + kind: process.argv[2] === 'claude' ? 'claude' : 'codex', + sessionId: input.session_id + } + const runtimeDir = process.env.TEMPAD_MCP_RUNTIME_DIR || join(tmpdir(), 'tempad-dev', 'run') + const path = + process.platform === 'win32' ? '\\\\.\\pipe\\tempad-mcp' : join(runtimeDir, 'mcp.sock') + socket = connect(path) + const pending = new Map() + let sequence = 0 + let buffer = '' + socket.on('data', (data) => { + buffer += data.toString() + if (buffer.length > 1_000_000) { + socket.destroy() + return + } + let index + while ((index = buffer.indexOf('\n')) >= 0) { + const line = buffer.slice(0, index) + buffer = buffer.slice(index + 1) + let message + try { + message = JSON.parse(line) + } catch { + continue + } + const entry = pending.get(message.id) + if (!entry) continue + pending.delete(message.id) + if (message.error) entry.reject(new Error('The Hub does not support this hook request.')) + else entry.resolve(message.result) + } + }) + const disconnected = () => { + for (const entry of pending.values()) entry.reject(new Error('The Hub hook connection closed.')) + pending.clear() + } + socket.on('error', disconnected) + socket.on('close', disconnected) + await new Promise((resolve, reject) => { + socket.once('connect', resolve) + socket.once('error', reject) + }) + const request = (method, params) => + new Promise((resolve, reject) => { + const id = ++sequence + pending.set(id, { resolve, reject }) + socket.write(JSON.stringify({ jsonrpc: '2.0', id, method, params }) + '\n') + }) + const result = await request('tempad/client-hook', { + ...identity, + event, + invocationId: randomUUID(), + ...(taskId ? { taskId } : {}), + ...(typeof input.turn_id === 'string' ? { turnId: input.turn_id } : {}) + }) + // Old Hubs may still offer comment batches; never emit or acknowledge those. + if ( + !result?.receiptId && + result?.output?.hookSpecificOutput?.hookEventName === event && + typeof result.output.hookSpecificOutput.additionalContext === 'string' + ) { + await new Promise((resolve, reject) => { + process.stdout.write(JSON.stringify(result.output) + '\n', (error) => + error ? reject(error) : resolve() + ) + }) + } +} catch { + // Missing/old runtimes never prevent the host from continuing, pausing, or exiting. +} finally { + socket?.destroy() + clearTimeout(deadline) +} diff --git a/agent-plugins/tempad-dev/.mcp.json b/agent-plugin/src/mcp.json similarity index 56% rename from agent-plugins/tempad-dev/.mcp.json rename to agent-plugin/src/mcp.json index 0d8ff3d7..4326590e 100644 --- a/agent-plugins/tempad-dev/.mcp.json +++ b/agent-plugin/src/mcp.json @@ -1,6 +1,8 @@ { + "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json", "mcpServers": { "tempad-dev": { + "type": "stdio", "command": "npx", "args": ["-y", "@tempad-dev/mcp@latest"] } diff --git a/agent-plugin/src/plugin.json b/agent-plugin/src/plugin.json new file mode 100644 index 00000000..78fa0ccc --- /dev/null +++ b/agent-plugin/src/plugin.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "tempad-dev", + "version": "0.2.0", + "description": "Connect your coding agent to Figma. Create and edit native designs, inspect existing designs, and implement UI in your codebase.", + "author": { + "name": "TemPad Dev" + }, + "homepage": "https://github.com/ecomfe/tempad-dev#agent-integration", + "repository": "https://github.com/ecomfe/tempad-dev", + "license": "MIT", + "keywords": [ + "figma", + "mcp", + "skill", + "agent-integration", + "design-to-code", + "canvas-authoring", + "design-system", + "frontend" + ] +} diff --git a/agent-plugin/src/skills/figma-canvas-authoring/SKILL.md b/agent-plugin/src/skills/figma-canvas-authoring/SKILL.md new file mode 100644 index 00000000..7732c78f --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/SKILL.md @@ -0,0 +1,183 @@ +--- +name: figma-canvas-authoring +description: >- + Create or update native, editable Figma designs with TemPad Dev MCP: screens, + flows, components, and requested local design-system resources, including on + an empty canvas. Use for Design in Figma work, not Figma-to-code, critique + without edits, or raw Plugin API automation. +--- + +# Design in Figma + +Deliver the smallest complete native Figma result that serves the user's +situation. Keep the working experience in view as you research, compose, and +repair. A successful tool call establishes a document change; the rendered +result and its editable structure establish whether that change served the task. + +## Establish the task + +Use the user's exact target and constraints. For an existing design, inspect +`get_code` and its pixels before changing the composition; use `get_structure` +for hierarchy, geometry, stable keys, or selected native facts. Write to a known +page directly. Create or activate a page only when the task calls for it. +Infer low-consequence gaps; ask when a missing decision would materially change +the result. Keep unrelated account, filesystem, task, and page metadata out of +product identity and content. + +Require an editable Figma Design file and the intended tab's active MCP +connection. Use the host's TemPad MCP tools for all canvas reads and writes. +If unavailable, report the integration problem and stop. Do not launch the CLI, +recreate its transport, use browser automation to set up the canvas, or emit raw +Plugin API operations. Research and asset acquisition use the host's appropriate +tools; website research uses the in-app browser when available unless the user +selected another browser. + +For new design work, call `begin_design` before research or canvas work with a short task title +and a fresh UUID `requestId`; reuse that UUID only to retry the same begin. Carry +the returned `taskId` on related TemPad tool calls. The runtime handles status and +placement feedback: do not report progress, send heartbeats, or choose coordinates +for a placeholder. Use `list_design_sessions` when the intended Figma target is +unclear, then pass its exact `sessionId` to `begin_design`. Pausing a turn preserves +the design task. Follow-up comments continue the same task, including after a completed +pass while its review remains open. After completion, pause, or lease expiry, use `resume_design` with its latest +`epoch`, carry the returned epoch as `taskEpoch`, and reread the affected canvas +with `get_structure` or `get_code` before writing. Use `get_design_task` only when +recovery needs the current state or epoch. Never replay a stale write. Stop in TemPad Dev +permanently cancels the current task after any running operation settles. Never resume +that cancelled task or automatically replace it. If further design work is necessary or +the user requests it, explicitly call `begin_design` with a fresh requestId. No separate +Figma unlock or new user turn is required. Done closes the review; a closed or replaced +task cannot resume. Do not automatically begin a replacement for comments on such a task. +Element feedback arrives as a numbered batch. Each item retains its file, page, +and node identity from draft creation. Reread every target before applying the +batch; do not substitute the current selection. +Supported hosts receive submitted feedback through native conversation messages. Do not poll for it or +set up a helper process or host control endpoint. + +Begin without waiting to choose a canvas location. Once an existing design region is +known, use `set_design_anchor` with its exact Frame node ID and `taskId`. Otherwise +the first created top-level Frame anchors automatically. The region stays stable +across reads and writes; call this tool again only to explicitly change design regions. + +## Ground and compose + +For net-new or materially redesigned interfaces without an established system, +read [style-grounding.md](references/style-grounding.md) and inspect relevant +real product screens or a permitted implementation before the first Canvas +write. The evidence must expose the interface relationships informing the new +work. Search snippets, URLs, failed retrievals, and generated concepts do not +establish a precedent. Subject imagery establishes its depicted content, not +its surrounding application's design. Try another permitted source when +retrieval fails; if none is inspectable, disclose the gap and stop. Supplied +source pixels or implementation can satisfy this boundary; mechanical edits do +not require unrelated research. + +Resolve what the person needs to recognize or change, which content and states +carry that work, and how the interface makes their consequences perceptible. +Choose the screen or flow, visual language, density, and scrolling model from +that situation. Use [visual-composition.md](references/visual-composition.md) +when forming or reconsidering a composition. Familiar structures and distinctive +ones both need a reason in the task. Research informs an independent solution; +it does not authorize copying a composition or placing reference pixels on the +canvas unless the user requested that treatment. + +When selecting or changing fonts, or when script coverage is uncertain, read +[typefaces.md](references/typefaces.md) to resolve candidates and native identities. + +Choose representations by their role in the work. Once an image, icon, diagram, +or visualization matters to the direction, read +[visual-assets.md](references/visual-assets.md) and its selected branch. Do not +silently replace the chosen content or medium to simplify sourcing or markup. +For content-bearing graphics, preserve meaningful marks and editable +relationships with native shapes, vectors, text, and groups; styled FRAME +lookalikes do not acquire drawing semantics. Read +[document-geometry.md](references/document-geometry.md) for that construction. +Ordinary UI panels, controls, backgrounds, and separators remain Canvas HTML. + +Choose resources from the task, not repetition alone: + +- **Direct:** default for a first net-new composition. Use primitives, literals, + and assets. Do not discover or create a design system just because shapes or + values repeat. +- **Reuse:** use [design-system-reuse.md](references/design-system-reuse.md) when + the user, selected source, or project evidence establishes the applicable + system. Catalog names, domain similarity, or mere file presence do not prove + relevance. +- **Author:** use [design-system-authoring.md](references/design-system-authoring.md) + when reusable resources are requested or established as part of the + deliverable. Prove the composition and one real consumer before propagation. + +For selected variables and typography styles, read +[resource-mapping.md](references/resource-mapping.md): define or discover their +identities once, then use variable utilities and text-style classes throughout +the markup. + +## Build, inspect, and repair + +For markup create or structural update, read +[canvas-html.md](references/canvas-html.md) and check its preflight before the +call. Canvas HTML is a strict native-state dialect; browser CSS assumptions do +not apply. Page-only and native-only operations omit markup. Load native +mechanics only for the capabilities selected below. + +Build a materially complete representative screen, then open its PNG before +expanding the flow or extracting resources. Judge whether the whole supports +the intended work. When it does not, focus on the particular relationship or +execution defect that explains the mismatch and repair it. A skeleton, resource +board, or generated concept does not establish the real composition. + +For updates, read [editing.md](references/editing.md). Preserve the requested +source, unrelated fields, and stable identities while updating every dependent +representation of the changed state. For larger results, split at meaningful +screen or section boundaries and carry shared roles coherently across them. + +Inspect every `apply_canvas` result, including warnings. Repair each observed +unintended defect or disclose why it remains. A local validation failure calls +for a local payload correction; it does not justify discarding a working root +or simplifying away the intended content. Open pixels again after the final +material write, covering every materially distinct screen. Verify native facts +with `get_structure` when identity, placement, editability, or representation +matters. Opened pixels prove visual access, not good judgment; a structural pass +proves only the conditions checked. + +Finish when the requested experience is coherent and observed defects are +repaired, accepted with reason, or disclosed. Report the delivered result and +material limitations, with a Figma link to the delivered nodes. A verified Direct +result is complete without an unsolicited component pass. + +Call `end_design` after the design outcome and its final verification are complete. +An optional short `summary` records the applied result in task history. +Use `outcome: "cancelled"` only when abandoning the design. Waiting for user input +or stopping a turn is a pause, not completion or cancellation. Host lifecycle hooks +handle pauses when available; do not create progress or heartbeat calls. + +## Native mechanics — load when selected + +Read the selected reference completely; do not preload the capability catalog. +Examples demonstrate syntax, not a design template. + +| Capability | Reference | +| --------------------------------------------------------------------- | ----------------------------------------------------------- | +| Exact updates, removal, or editor context | [editing.md](references/editing.md) | +| Pages, sections, groups, Booleans, masks, transforms, shapes, vectors | [document-geometry.md](references/document-geometry.md) | +| Paints, media, effects, shaders, grids, guides | [paints-effects.md](references/paints-effects.md) | +| Exact fonts, rich text, range styles, lists, hyperlinks | [rich-text.md](references/rich-text.md) | +| Components, variants, properties, Slots | [component-authoring.md](references/component-authoring.md) | +| Variables, collections, modes, bindings | [variables.md](references/variables.md) | +| CSS variable utilities and named text-style classes | [resource-mapping.md](references/resource-mapping.md) | +| Paint, Text, Effect, Grid styles | [local-styles.md](references/local-styles.md) | +| Authorized independent research, assets, inventory, or QA delegation | [delegation.md](references/delegation.md) | + +## Mutation boundaries + +Use returned IDs and stable keys as identity, never names. Create describes a +new complete root or exact new page. Update targets an exact node or page; +omissions preserve live state. `activate` always requires `page.id` or +`page.pageKey`, even when only changing selection. + +Never mutate outside scope, remove manual or unkeyed content, or remove a +component with surviving instances. An instance's definition-derived sublayers +are not authoring targets. Do not mutate remote resources, publish, detach or +reset instances, execute arbitrary JavaScript, or imitate an unresolved +resource. Use `null` only for supported links or managed resources the requested +change actually removes. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/agents/openai.yaml b/agent-plugin/src/skills/figma-canvas-authoring/agents/openai.yaml new file mode 100644 index 00000000..25e5075e --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/agents/openai.yaml @@ -0,0 +1,7 @@ +interface: + display_name: 'Design in Figma' + short_description: 'Create user-directed native Figma designs' + icon_small: './assets/icon.svg' + icon_large: './assets/icon.svg' + brand_color: '#0098FF' + default_prompt: 'Use $figma-canvas-authoring to create a native Figma design while following my resource constraints.' diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/canvas-html.md b/agent-plugin/src/skills/figma-canvas-authoring/references/canvas-html.md new file mode 100644 index 00000000..2cc27632 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/canvas-html.md @@ -0,0 +1,277 @@ +# Canvas HTML and Tailwind subset + +Canvas HTML describes desired state, not browser rendering. Use its elements for +interface structure and genuine simple UI geometry, not as a drawing medium. +Do not assemble `div` or `span` primitives to imitate a photograph, +illustration, icon, logo, texture, or other content-bearing visual; acquire the +appropriate routed raster or vector asset instead. Classes do not cover every +Figma result: use routed native bindings for gradients, media, non-shadow +effects, masks, transforms, exact fonts, and rich text. + +One `apply_canvas` markup tree may contain at most 160 elements and 12 levels. +This is a safety ceiling, not a target. Before calling, count the tree, include +only assets referenced by that call, and split larger work at meaningful screen +or section boundaries. + +Prefer supported Tailwind utilities; use arbitrary pixels only off the default +scale. Numeric spacing follows Tailwind v4's `4px` unit. Selected Figma resources +can use CSS variable utilities and `type-*` text-style classes through +[resource-mapping.md](resource-mapping.md). Arbitrary project theme extensions, +variants, plugins, viewport-dependent utilities, and CSS cascade are unsupported. + +## Contents + +- [Preflight each markup tree](#preflight-each-markup-tree) +- [Elements and identity](#elements-and-identity) +- [Layout](#layout) +- [Appearance and text](#appearance-and-text) + +## Preflight each markup tree + +Immediately before each create or structural update, scan the complete supplied +tree once: + +- require a fixed width and height on the markup root; +- give every `div` with children `flex` or `grid`, or make every child absolute + with one edge per axis and fixed parent and child dimensions; +- keep flex, grid, gap, padding, border, corner, and box-shadow classes off + `span`; +- resolve defaults and overrides before assembling each class list. Both + `text-[16px] text-[18px]` and `text-black text-white` are conflicts, not + overrides. A helper must choose the final font size, color, and line height + instead of appending them to hard-coded defaults; +- trace every `w-full`, `h-full`, and `grow` against its direct parent's axis and + the element's required dimensions; +- give a fixed-height grid explicit row tracks when its children should fill or + divide that height; omitted rows remain content-sized; +- count at most 160 elements and 12 levels, and include only assets referenced by + this call. + +Correct the complete set before calling instead of serializing until validation +reveals issues one at a time. + +## Elements and identity + +- Use `div`, `span`, or a component tag returned by the active catalog. +- Give every element one unique `data-key` of letters, numbers, `. / : _ -`. +- Use `data-node-id` only in update mode to adopt an exact live node; instance + sublayers are not authoring targets. +- When markup is supplied, every `native` key must occur as a `data-key` in that + supplied tree; existence elsewhere in the live target does not satisfy this. + For mixed structural/native edits, include each bound node under its actual + parent path, or send the omitted nodes' changes in a separate native-only update. + When only native state changes, omit markup, target the exact managed root, + and key `native` by existing stable keys in that scope. This preserves topology; + masks and node removal still require structural markup. +- Use no arbitrary attributes on `div` or `span`. Common catalog links use + `data-var-="vN"` and `data-style-="sN"`; `"none"` explicitly + unlinks that field. +- A `span` contains only text and `
` or `
` line breaks. Use + `whitespace-pre-wrap` for literal newlines or repeated spaces. A plain `&` is + literal unless it forms a semicolon-terminated entity; supported entities + decode. Canvas typography does not inherit from a parent `div`: put font and + other text utilities on each `span`/TEXT node. Put flex/grid, gaps, padding, + borders, corners, and box shadows on a parent `div`. +- A component tag is childless, includes its returned `data-ref`, and accepts + returned props plus the shared class, identity, variable, and style + attributes. + +Variable attributes use kebab-case native field names: fill, stroke, characters, +visible, dimensions/bounds, gaps, four paddings/corners/stroke sides, radius, +stroke weight, opacity, and whole-node font/line-height/letter-spacing/paragraph +fields. Style attributes are `data-style-fill`, `data-style-stroke`, +`data-style-text`, `data-style-effect`, and `data-style-grid`. Node-type and +fallback rules still apply. + +Every primitive needs one width and one height. Supported fixed forms are: + +- default spacing: `w-N`, `h-N`, `size-N` (`N * 4px`), plus `w-px`, `h-px`, `size-px` +- default width containers: `w-3xs|2xs|xs|sm|md|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl` +- exact: `w-[Npx]`, `h-[Npx]`, `size-[Npx]` +- hug: `w-fit`, `h-fit` +- hug both axes: `size-fit` +- fill: `w-full`, `h-full`, or `size-full` for both axes +- bounds: numeric, `px`, or arbitrary-pixel values with `min-w`, `max-w`, `min-h`, or `max-h`; + width bounds also accept the default container names; use `min-w-none`, `max-w-none`, + `min-h-none`, or `max-h-none` to clear a bound in an update + +Text using `w-fit` also needs `h-fit`; prefer `size-fit`. Fixed-width `h-fit` +remains valid for wrapping text. + +Create and update markup roots require fixed width and height; fill, hug, and +grow are invalid even when the live target has a sized parent. + +Use `w-full` only on a `flex-col` cross axis, `h-full` only on a `flex-row` +cross axis, and `grow` on the main axis; `grow-0` clears growth. `grow` does not +replace required dimensions—for a row track use `grow w-fit h-[3px]`. Give +growing text in constrained rows a positive `min-w-*` to prevent collapse. +Prefer a hug main axis for content stacks whose extent is not behaviorally +fixed. Otherwise budget the fixed axis as padding + gaps + fixed/minimum child +extents. A non-overflowing result is still wrong when resolved content consumes +the intended inset; compare rendered child edges with the layout's padding. +Grid children may fill cells. Direct dimension variables require fixed +fallbacks. Fixed sizes must be at least `0.01px`; native lines use `h-[0px]`. + +## Layout + +Use Auto Layout for ordinary product UI. `flex` follows CSS's horizontal default; +use `flex-row` when that direction should be explicit and `flex-col` for a +vertical stack: + +- `flex`, `flex flex-row`, or `flex flex-col` +- `items-start|center|end|baseline` +- `justify-start|center|end|between` +- `flex-wrap`, `flex-nowrap`, `content-between`, `content-normal` +- `gap-N`, `gap-x-N`, `gap-y-N`, or exact `[Npx]` +- `p`, `px`, `py`, `pt`, `pr`, `pb`, `pl` with `-N`, `-px`, or `-[Npx]` +- `box-border`, `box-content` + +New Auto Layout frames include inside strokes by default (`box-border`); +`box-content` excludes them. Center/outside strokes never affect layout, and +each nested frame owns its setting. Fixed create sizes must cover opposing +padding plus included inside strokes. Figma determines `FILL` geometry and +border-box distribution. Derive exact descendant or instance sizes from the +rendered inner box, not nominal parent size; prefer valid cross-axis fill and +exceed the box only for intentional bleed or overlap. + +`managed-content-overflow` means managed Text or INSTANCE exceeds its direct +managed Frame or Component, or a native INSTANCE contains descendant content +beyond its own fixed root. Inspect edges, clipping, rendering, and instance +bounds; resize or realign accidental overflow and retain only intentional bleed, +crop, or overlap. Property-driven content outside an INSTANCE root is a broken +component contract rather than intentional consumer overflow. + +`justify-between` uses nonnegative native Auto gap and keeps one child at the +start. Use negative `figma.autoLayout.itemSpacing` only for intentional overlap. +Omitting box-sizing on update preserves the live setting. + +`hidden` and BOOLEAN visibility remove in-flow children, changing gaps, +positions, and hug bounds. To preserve geometry, keep a fixed slot and toggle +its inner child. `absolute left-[Npx] top-[Npx]` maps to Ignore Auto Layout for +true overlays; it needs fixed offsets, cannot fill/grow, and leaves surrounding +flow unchanged. Its text and Auto Layout descendants may still hug. + +For grid use: + +- `grid grid-cols-N` +- optional `grid-rows-N` +- custom tracks: `grid-cols-[1fr_240px_fit-content(100%)]` +- optional `grid-flow-row` or `grid-flow-none` +- child placement: `col-start-N`, `row-start-N`, `col-span-N`, `row-span-N` +- child alignment: `justify-self-auto|start|center|end`, + `self-auto|start|center|end` + +Give manual grid children both row and column starts or neither. Auto-flow uses +source order without explicit starts. A height-hugging grid cannot use flexible +or automatic rows; fix either its height or row tracks. Omitting `grid-rows-*` +creates native automatic content-sized rows; increasing only the container +height does not enlarge them. + +For a coherent board larger than one call, first create one fixed parent: + +```json +{ + "mode": "create", + "markup": "
" +} +``` + +Then append one bounded screen per update. Keep the root key and classes stable, +target its returned ID, and omit previously added children so they remain in +place: + +```json +{ + "mode": "update", + "targetNodeId": "FrameID:app-board", + "markup": "
" +} +``` + +For freeform composition, omit layout classes and give each child `absolute` +with exactly one horizontal edge (`left-*` or `right-*`) and one vertical edge +(`top-*` or `bottom-*`), including negative or exact values, or use a native +relative transform. Edge placement needs fixed parent and child sizing modes; +right/bottom offsets are resolved from live bounds after each markup apply. They +are placements, not reactive CSS anchors: use Auto Layout for alignment that +must follow later mode changes without another markup apply. A plain +non-flex/grid `div` is freeform even with one child; opt into layout for every +in-flow child. Absolute children cannot grow or fill; use `static` to return one +to Auto Layout on update. + +## Appearance and text + +Frame appearance: + +- `bg-transparent|white|black`, or an exact CSS hex value +- Linear backgrounds use `bg-linear-to-t|tr|r|br|b|bl|l|tl` with exact + `from-white|black|[#hex]`, optional `via-white|black|[#hex]`, and required + `to-white|black|[#hex]` stops. Stops are fixed at 0, optional 0.5, and 1; + `bg-gradient-to-*` is accepted as a legacy alias. Do not combine a gradient + with a solid background, direct fill paints, or a fill style/variable. +- `border`, `border-N`, `border-[Npx]`; use `border-x|y|t|r|b|l` with the same widths +- `border-white|black`, or an exact CSS hex value +- `rounded`, `rounded-none|xs|sm|md|lg|xl|2xl|3xl|4xl|full`, or `rounded-[Npx]`; + prefix the value with `t`, `r`, `b`, `l`, `tl`, `tr`, `br`, or `bl` for individual sides/corners +- `overflow-hidden`, `overflow-visible` +- A clipped rounded frame does not paint its inside stroke above children. A + filled child that reaches a curved edge can therefore square off or hide the + boundary even with `overflow-hidden`; inset it, give the touching child + corners a corresponding inner radius, or add a dedicated foreground + boundary, then inspect the rendered pixels. +- Exact pixel shadow lists through `shadow-[...]` or `inset-shadow-[...]`. + Each layer needs an explicit hex, `rgb()`, or `rgba()` color and two to four + pixel lengths; use underscores for spaces, for example + `shadow-[0_8px_24px_rgba(0,0,0,0.16)]`. +- `shadow-none` and `inset-shadow-none` clear their class-owned effect stack. + Theme-dependent named scales such as `shadow-md` are unsupported: use an + explicit native style or typed effect/variable binding for a reusable token, + or resolve the governing theme before applying and provide the exact value. + +Figma accepts shadow spread only on rectangles and ellipses, or on frames, +components, and instances with a visible fill and clipping enabled. + +A new border needs weight and paint, literal or bound. Updates may change either +independently; omission preserves the other. + +New frames are transparent when background is omitted, including frames added +during update. On an existing frame, omission preserves its live background; +use `bg-transparent` to clear it. Set an explicit background when fill is +intended. + +Shared appearance: + +- `opacity-N` (`N%`) or `opacity-[0..1]`, `hidden`, `visible` +- `rotate-N`, `-rotate-N`, `rotate-none`, or `rotate-[Ndeg]` +- `mix-blend-` with `pass-through`, `normal`, `darken`, `multiply`, + `plus-darker`, `color-burn`, `lighten`, `screen`, `plus-lighter`, + `color-dodge`, `overlay`, `soft-light`, `hard-light`, `difference`, + `exclusion`, `hue`, `saturation`, `color`, or `luminosity` + +Text: + +- `font-sans|serif|mono` resolve to an editor-available family in that category, + preferring Inter, Noto Serif, and Noto Sans Mono +- `font-thin|extralight|light|normal|medium|semibold|bold|extrabold|black` +- `text-xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl` with their default line + heights, `text-SIZE/N`, or `text-[Npx]` +- `leading-none|tight|snug|normal|relaxed|loose`, `leading-N`, `leading-[Npx]`, + `leading-[N%]`, or a unitless arbitrary ratio +- `tracking-tighter|tight|normal|wide|wider|widest`, `tracking-[Npx]`, + `tracking-[N%]`, or `tracking-[Nem]` +- `text-left|center|right|justify` +- `normal-case`, `uppercase`, `lowercase`, `capitalize` +- `no-underline`, `underline`, `line-through` +- `truncate`, `line-clamp-N`, `line-clamp-none` +- `text-white|black`, an exact CSS hex value, `whitespace-pre-wrap` +- `text-shadow-[...]` for an exact pixel text-shadow list with a color and two + or three pixel lengths; `text-shadow-none` clears it + +A `span` is one TEXT node, so `bg-*` and `text-*` share its fill channel. Put +background on a parent `div` and color on its child `span`. + +Shadow classes compile to the native effect stack; never combine them with +`figma.effects` or an Effect style on that node. + +Unknown elements, attributes, classes, CSS, responsive/state prefixes, custom +themes, margins, percentages, and plugins fail closed. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/component-authoring.md b/agent-plugin/src/skills/figma-canvas-authoring/references/component-authoring.md new file mode 100644 index 00000000..99573887 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/component-authoring.md @@ -0,0 +1,294 @@ +# Author reusable components + +Use this reference after selecting a reusable local component. It explains +representation, not library strategy. New local components need no +`get_design_system`; use catalogs only for discovery or normalized library +props, and exact returned IDs for newly authored components. + +## Shared-responsibility decision + +New local components are opt-in for net-new authoring. Use Author when the user +requested reusable components before delivery, accepted a component pass after +seeing the completed design, or applicable project evidence makes a local +component deliverable part of the task. Existing components may still be Reuse +without authoring new ones. Repeated appearance, repeated data, screen count, +possible future reuse, or tool availability do not opt the user into Author. + +Make the decision from real usages after the representative composition is +visually sound: + +1. Name the shared job and compare the intended consumers. +2. Identify stable anatomy and meaningful content, media, state, availability, + label, swap, or slot differences. +3. Choose Author only when a truthful supported contract provides more + coordination value than it costs to create, migrate, and verify. Otherwise + keep the responsibility Direct; a brief reason is enough. +4. Bound Author at the smallest subtree that owns the complete shared job. Do + not infer that a parent must become reusable because a nested label, icon, + status, or button is reusable. + +Do not inventory or rank every recurring family, and do not turn repetition +into a quota. Record only selected Author responsibilities and their concrete +consumers. Before propagation, create the smallest real definition, instantiate +it once, and verify the exact reference. Then replace the selected consumers +with native instances; never leave literal lookalikes for a responsibility that +was deliberately selected as Author. Use the exact returned `rootNodeId` or +`nodeIdsByKey` entry for every usage. + +A keyed primitive cannot become an INSTANCE in place. Update its bounded +ancestor, add the instance under a new key, and remove the old key in the same +call. + +Stop component authoring if the ID is missing, the instance fails, or the +definition is empty, default-sized, or loses +properties. Do not substitute primitives or claim completion. Continue only +independent Direct work, report the degraded component result, and remove a +temporary definition only when unused and safe. Re-read a corrupt definition +and its intended usage; never rebuild it in place or remove one with instances. +Recreate only when unused. If a diagnostic would systematize primitives that +this definition replaces, reconcile the component first; independent token work +does not need to wait. + +Before handoff, reconcile only selected Author responsibilities with actual +consumers. Each selected consumer must be a native INSTANCE. Inspect the most +demanding instance through its descendants; root type and size do not prove +wrapping, slots, media, or state content fit. +Revise the contract or boundary when real content breaks it. + +Markup-only updates preserve keyed components, sets, instances, and shapes. +Restate native bindings only when changing native state; new native nodes still +need declarations or component references. + +Copy a complete recipe and change its design facts. Do not infer TemPad's +component shape from raw Plugin API calls. + +## Contents + +- [Define the contract from real usages](#define-the-contract-from-real-usages) +- [Keep source definitions discoverable](#keep-source-definitions-discoverable) +- [Component and properties](#component-and-properties) +- [Consume an authored component directly](#consume-an-authored-component-directly) +- [Variant set](#variant-set) +- [Slots and instances](#slots-and-instances) + +## Define the contract from real usages + +Compare every intended usage. Separate stable anatomy from varying content, +state, or nested substitution; map differences to the smallest supported Text, +Boolean, Instance Swap, variant, Slot, or nested-composition mechanism. Treat a +field as invariant only when real usages agree. + +Size the contract from real extremes: test the longest wrapping text, widest +label, largest nested swap, and materially different slots. Compare descendant +bounds with the INSTANCE root; screenshots can still paint invalid overflow. +If content exceeds the root, enlarge the definition, add a truthful size +variant, or move the varying region outside a smaller stable boundary. +If consumer-specific media cannot be expressed by the available instance +contract, keep that media direct and componentize the stable surrounding +responsibility; never freeze one image into every instance to retain a larger +component boundary. + +When stable anatomy should evolve together, expressible state differences +support a shared contract. Keep it local only when divergence or contract cost +outweighs coordinated change. + +If the contract cannot express a meaningful difference, revise it or keep the +responsibility local. Never force usages to share placeholder content or an +accidental default merely because outer geometry repeats. + +Model each mutually exclusive categorical concern as one variant axis; do not +replace it with Booleans that allow impossible combinations. Reserve Booleans +for independently optional content or behavior. + +Expose one choice through both a variant and independent property only when real +usages vary them independently. Keep each source variant's visible state +truthful; instance overrides do not repair accidental source defaults. + +## Keep source definitions discoverable + +Keep main components and sets visible at natural bounds in a clearly named +source area separate from screens. Never hide, clip, make transparent, or +invisibly nest them. For several families, use a top-level SECTION with +`contentsHidden: false`, discoverable definition children, and content-sized +bounds. + +Keep each real definition once, without redundant specimens. Before handoff, +use `get_structure` to verify every definition is visible and every intended +consumer is an INSTANCE. Inspect distinct source variants at readable scale; +names, content, and styling must encode the same state. + +Keep the source area operational and visually subordinate: use the smallest +content-sized container that exposes the definitions, outside the consumer +board or screen sequence. Do not turn it into a branded artboard, mood board, +visual-thesis panel, token showcase, or documentation page unless the user asks +for that deliverable. Product screenshots and presentation framing should stay +focused on the requested experience. + +## Component and properties + +This complete call creates a component with TEXT and BOOLEAN properties and +connects both properties to its label layer. + +```json +{ + "mode": "create", + "markup": "
Continue
", + "native": { + "button": { + "figma": { + "name": "Button", + "component": { + "type": "COMPONENT", + "properties": { + "label": { + "type": "TEXT", + "name": "Label", + "defaultValue": "Continue" + }, + "show-label": { + "type": "BOOLEAN", + "name": "Show label", + "defaultValue": true + } + } + } + } + }, + "button/label": { + "figma": { + "componentPropertyReferences": { + "characters": "label", + "visible": "show-label" + } + } + } + } +} +``` + +Stable keys such as `label` connect definitions and sublayer references within +one result; they are not generated Figma property names. Supported property +types are `BOOLEAN`, `TEXT`, and `INSTANCE_SWAP`, linked through `visible`, +`characters`, and `mainComponent` respectively. + +BOOLEAN properties control visibility, not styling. Hidden in-flow children +leave Auto Layout. Use this only for intentionally optional content. To preserve +geometry, toggle an inner layer inside a fixed slot, use `absolute` for a true +overlay, or use geometry-equivalent variants for whole-state changes. + +Treat `layout-affecting-visibility-property` as a contract warning. Fix it when +geometry must stay stable. Accept intentional reflow only after comparing true +and false instances for bounds, sibling positions, baselines, and clipping; one +default-state screenshot is insufficient. + +## Consume an authored component directly + +Use the exact ID returned by `apply_canvas`. For TemPad-authored components, +`componentProperties` accepts their stable definition keys. This follow-up +needs no catalog: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "screen/action": { + "component": { "id": "ComponentID:created-button" }, + "componentProperties": { "label": "Save", "show-label": true } + } + } +} +``` + +Replace the illustrative ID with the returned ID. Never invent IDs or use this +shortcut for unidentified library components. + +## Variant set + +This call creates two components in one variant set. Every direct child of a new +set must be an authored component; names encode axes as `Property=Value`. + +```json +{ + "mode": "create", + "markup": "
Continue
Continue
", + "native": { + "button-set": { + "figma": { + "name": "Button", + "component": { "type": "COMPONENT_SET" } + } + }, + "button/default": { + "figma": { + "name": "State=Default", + "component": { "type": "COMPONENT" } + } + }, + "button/hover": { + "figma": { + "name": "State=Hover", + "component": { "type": "COMPONENT" } + } + } + } +} +``` + +Consume the returned set ID and select siblings through variant properties. If +the call returns the set as `rootNodeId`, this creates Default and Hover: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "screen/default": { + "component": { "id": "ComponentSetID:created-button-set" } + }, + "screen/hover": { + "component": { "id": "ComponentSetID:created-button-set" }, + "componentProperties": { "State": "Hover" } + } + } +} +``` + +Replace the ID with returned `rootNodeId`. The set ID creates its default; +`componentProperties` selects another encoded variant. An exact child ID from +`nodeIdsByKey` may instantiate that variant directly. + +Use `descriptionMarkdown` and `documentationLink` only for real guidance, inside +`figma.component` beside `type` and `properties`: + +```json +{ + "figma": { + "name": "Button", + "component": { + "type": "COMPONENT", + "descriptionMarkdown": "Primary action" + } + } +} +``` + +Define shared properties on the component set rather than on one variant. + +## Slots and instances + +Use `figma.slot` only for an intentional flexible nested-content API. New slots +must be inside local authored components and include `property.name`; markup +children become defaults. Optional settings control stretching, empty display, +child limits, and preferred values. + +An `INSTANCE_SWAP` default uses exact live component/set ID `{ "id": "..." }` +or importable library key `{ "key": "..." }`. Preferred values require +`{ "type": "COMPONENT" | "COMPONENT_SET", "key": "..." }` and accept neither +live IDs nor catalog refs. Resolve catalog identity before authoring and never +invent it. Put advanced state under `figma.instance`; omission preserves normal +override behavior. + +Never edit a remote component, nest a main component inside another main +component, delete a component with surviving instances, or create properties +and variants that the requested component API does not need. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/delegation.md b/agent-plugin/src/skills/figma-canvas-authoring/references/delegation.md new file mode 100644 index 00000000..181b7cc9 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/delegation.md @@ -0,0 +1,82 @@ +# Delegate bounded evidence work + +Delegate evidence gathering or isolated production, never focal judgment. The +main agent synthesizes results and remains the only Canvas writer. + +## Pass the delegation gate + +Delegate only work that is: + +1. **Separable:** has a stable objective independent of evolving design choices. +2. **Compressible:** needs only a compact task-local brief. +3. **Isolated:** is read-only or produces an isolated artifact without mutating + Figma, design-system state, or another agent's files. +4. **Verifiable:** returns citations, importable asset references, exact facts, + or a bounded defect list the main agent can inspect. +5. **Worth coordinating:** gains enough from parallelism, specialist capability, + or independent review to justify handoff and synthesis. + +Keep work local if any condition fails. Do not delegate for ritual, convenience, +or another unsupported aesthetic opinion. + +## Write a complete handoff + +Give each worker one objective and its relevance, only required task evidence +and constraints, permitted tools and sources, explicit exclusions including no +Canvas writes, and an exact output contract and stop condition. The main agent +must read required Canvas references and set safety boundaries; never delegate +interpretation of this skill. Prefer fresh or minimum-context workers, pass +source evidence rather than conclusions, and avoid overlapping assignments. + +## Suitable tracks + +### Research scout + +After framing the design problem, delegate a bounded evidence question. Return: + +```txt +open decision; exact source; applicable finding; relevance; authority boundary +``` + +The scout does not choose direction. Combine questions only when their search +space is shared; use multiple scouts only for independent spaces. + +### Asset scout + +After fixing asset requirements and import contract, return one importable +`imageUrl` or `assetHash` per asset plus MIME type, dimensions, provenance, and +factual description. Return no bytes, rejected candidates, or transcript. The +main agent owns selection and integration. + +### Independent QA scout + +After a representative composition exists, provide a fresh worker its +screenshot and frozen brief without creator rationale or suspected defects. Ask +for at most eight observations: + +```txt +severity; screen/node or region; observed defect; visible evidence; violated constraint +``` + +The scout neither edits nor declares completion; the main agent checks findings +against the live canvas. + +### Inventory scout + +Use read-only inventory when independent volume warrants it, such as several +screens or icon candidates. Require exact findings and references, not a design +proposal. + +## Orchestrate conservatively + +- Default to one worker; use at most two concurrent non-overlapping workers. +- Keep a faster local critical path with the main agent. +- Only the main agent resolves intent and conflicts, chooses direction, calls + `apply_canvas`, and accepts the result. +- Resolve conflicts from evidence, not voting; discard unverifiable or + out-of-scope claims and stop when evidence is sufficient. + +Never delegate interdependent page or component construction, component +authoring plus instance placement, concurrent updates to one root, final +composition, or final acceptance. These require one ordered mutation stream and +continuous awareness of the whole. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/design-system-authoring.md b/agent-plugin/src/skills/figma-canvas-authoring/references/design-system-authoring.md new file mode 100644 index 00000000..45825de5 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/design-system-authoring.md @@ -0,0 +1,87 @@ +# Implement a selected local design system + +Use this reference only when the user or resolved plan requires new local +components, variables, or styles. It translates that plan into native resources +and verifies delivery; it does not choose component strategy, visual language, +resource inventory, or token taxonomy. + +## Establish the implementation contract + +Before writing, identify each selected resource, responsibility, concrete +consumer, meaningful variation, and exclusion. Resolve any open material +boundary first. For components, use the gate in +[component-authoring.md](component-authoring.md); screen count, one-screen scope, +and visual similarity alone neither establish nor exclude a component. + +Keep a private reconciliation map: + +```txt +selected resource -> native representation -> intended consumers +``` + +A resource is complete only when its native definition or binding exists and +every intended consumer uses it. Equivalent primitives or literals are not +coverage. + +## Translate the plan + +Use this loop: + +1. Stabilize one representative composition. +2. Author only selected resources with known consumers. +3. Exercise each contract in that composition. +4. Propagate native instances and bindings to all intended consumers. +5. Reconcile the final artifact with the map. + +Preserve the decided semantics: + +- A variable carries a semantic value consumers must bind and evolve together; + name it by role, not literal. +- A local style carries a reusable paint, text, effect, or grid definition. Do + not duplicate one decision across resource types unless required. +- A component carries a reusable responsibility. Define stable anatomy and + expose only variations required by real usages. + +Use [resource-mapping.md](resource-mapping.md) to map selected variable and text +style identities once per apply, then consume them through familiar variable +utilities and `type-*` classes. A new resource and its first consumer can share +one call. Query available fonts independently through `get_design_system` with +`scope: "fonts"`; selecting a family does not require discovering a file system. + +Consume a component through a childless instance placeholder without layout or +appearance classes. Do not make a repeated shell or wrapping top-level subtree +a component unless every consumer can use that placeholder through supported +properties. Slots do not permit markup children on instance placeholders; keep +incompatible wrappers as ordinary structure around a compatible inner boundary. + +Map each real component difference to the smallest supported mechanism: Text, +Boolean, Instance Swap, variant, Slot, or nested composition. Use one variant +axis per mutually exclusive categorical concern and Booleans only for +independently optional concerns. Do not encode arbitrary content as variants, +generate unused combinations, or freeze varying content as invariant. + +If supported native mechanisms cannot express a real usage, do not weaken or +redesign it silently. Choose another valid boundary or report the limitation. + +Read [variables.md](variables.md), [local-styles.md](local-styles.md), or +[component-authoring.md](component-authoring.md) only for selected resource +types. + +## Verify the native handoff + +Verify through representative consumers, not definitions alone: inspect native +bindings, Auto Layout, text resizing, property behavior, and every material +state. Raw literals and primitive lookalikes do not demonstrate system usage. + +For components, verify visible inspectable definitions and native INSTANCE +consumers using [component-authoring.md](component-authoring.md). For variables +and styles, inspect live bindings rather than apply input or equal values. + +Resolve warnings through real consumers, or remove a resource only when the +resolved plan no longer includes it. Tool friction, payload size, or an easy +resource type does not alter the plan. Do not create swatches, specimens, +definition panels, or redundant examples solely for verification; add +documentation only when requested. + +Finish when selected resources support all requested usages and the live Figma +structure reconciles with the map. Do not expand for imagined future needs. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/design-system-reuse.md b/agent-plugin/src/skills/figma-canvas-authoring/references/design-system-reuse.md new file mode 100644 index 00000000..11cf574f --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/design-system-reuse.md @@ -0,0 +1,59 @@ +# Reuse an existing design system + +Use this reference only when reuse is allowed and relevant. If the user rejects +a design system, use Direct. + +## Discover definitions + +Call `get_design_system` without arguments. Its immutable deterministic catalog +contains: + +- a `catalogId` scoping all short refs; +- component tags, props, source pages, and native sizes; +- variables, collections, modes, styles, and shaders as refs such as `v1`, + `k1`, `m1_2`, `s1`, and `h1`; +- `cssName` on variables and `className` on text styles for direct use in markup; +- `omitted` and `nextCursor` when more definitions remain. + +The catalog neither scans usage nor loads pages or ranks resources. Select from +returned names, pages, summaries, props, types, scopes, and defaults. Continue a +cursor or inspect an exact ref only until evidence is sufficient. + +Prefer, in order: catalog component, supported component prop, matching native +style, semantic variable, then primitive or literal for a real gap. + +When variants, anatomy, layout, or semantic meaning affect the result, inspect +the exact `ref` with the same `catalogId`. Use its `previewNodeId` with +`get_screenshot` only when appearance affects selection. Read an existing +composition with `get_code` or `get_screenshot`; catalogs do not reveal usage +conventions. Never invent refs, IDs, keys, props, or variant values. + +## Apply catalog resources + +Component tags are childless, include returned `data-ref`, and use exact props. +Omit size classes to preserve native size. Use returned CSS variable names and +text-style classes through [resource-mapping.md](resource-mapping.md). For other +native fields, bind `data-var-="vN"` or `data-style-="sN"`; put +collection modes or strict native links under `native[data-key]`. + +Replace every illustrative ref in this contract with one from the active +catalog: + +```json +{ + "mode": "create", + "catalogId": "ds_example", + "markup": "
Team settings
", + "theme": { "textStyles": { "type-body": { "ref": "s1" } } }, + "native": { + "settings": { + "variableModes": { "k1": "m1_1" } + } + } +} +``` + +If a mandatory component is absent, ask the user to open its definition page; +otherwise use the normal primitive fallback. An empty canvas does not block +catalog reuse. When reuse is unavailable, create a small coherent primitive +draft—never a token or component library solely for one screen. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/document-geometry.md b/agent-plugin/src/skills/figma-canvas-authoring/references/document-geometry.md new file mode 100644 index 00000000..1f24c0d6 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/document-geometry.md @@ -0,0 +1,124 @@ +# Document and native geometry + +Use `native[key].figma` only for state HTML and classes cannot express honestly; +it remains declarative desired state. + +## Contents + +- [Pages and containers](#pages-and-containers) +- [Shapes and vectors](#shapes-and-vectors) +- [Transforms, masks, and native state](#transforms-masks-and-native-state) + +## Pages and containers + +Top-level `page` can set a name, exact zero-based document index, solid RGBA +background, ordered guides, and explicit variable modes. Page-only create uses +a new `pageKey` plus name. Page-only update uses +an exact `id` or `pageKey` and omits markup. A create root may target an existing +or new page directly; creating pages and writing nodes preserve the user's current +page and viewport. Do not activate a page merely to write there. +Markup updates stay on the target node's page. + +Use top-level `mode: "activate"` with exact page identity when editor context or +selection matters; `selection: []` clears selection. Use top-level `mode: +"remove"` with an owned `pageKey` to delete a page. Page deletion rejects the +last page, manual or unowned content, and surviving external dependencies. + +Use: + +- `figma.section: { contentsHidden? }` for canvas organization; +- `figma.group: true` for an intrinsic group; +- `figma.booleanOperation: "UNION" | "SUBTRACT" | "INTERSECT" | "EXCLUDE"` + for non-destructive geometry. + +Sections can be canvas roots or direct children of sections; a frame cannot +contain a section. Sections require fixed pixel dimensions and freeform +children. Groups and Booleans use `w-fit h-fit` with freeform children. A new +group needs one child and a Boolean needs two. When updating an intrinsic +container's children, +describe every live direct child because order is semantic. + +Sections have no frame clipping, so omit `overflow-hidden` and +`overflow-visible`. When `targetNodeId` is an existing section, retain +`figma.section` on the root or the frame-typed markup root is rejected. + +## Shapes and vectors + +Use a childless `div` with `figma.shape`: + +- `{ "type": "RECTANGLE" }` +- `{ "type": "LINE" }` +- `{ "type": "ELLIPSE", "arc": { "startAngle", "endAngle", "innerRadius" } }` +- `{ "type": "POLYGON", "pointCount": 3 }` +- `{ "type": "STAR", "pointCount": 5, "innerRadius": 0.5 }` +- `{ "type": "VECTOR", "paths": [...] }` +- `{ "type": "VECTOR", "network": {...}, "handleMirroring": "..." }` + +Use exact uppercase `M L Q C Z` paths for already-decided custom vector +geometry. Selected icon roles use sourced SVG through [icons.md](icons.md), not +remembered paths. Use a vector network only for branching segments, per-vertex +state, or region-specific fills or styles. Never provide both. New vectors need +geometry; omission preserves it on update and an empty path or network clears +it. + +Each path item is an object. `windingRule` is `"NONE"`, `"NONZERO"`, or +`"EVENODD"`; use `"NONE"` for an open stroked path. Path data uses +whitespace-separated uppercase commands and numbers. + +Figma normalizes path geometry to tight bounds before applying markup size. The +childless `div` defines final bounds, not a preserved viewport. For alignment, +offset it by the path's minimum x/y and size it to the x/y spans; otherwise a +partial-range path stretches to the box. Verify rendered anchors because +`get_structure` returns node bounds, not path coordinates. + +This Direct recipe creates an editable branch curve: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "branch": { + "figma": { + "name": "Branch", + "shape": { + "type": "VECTOR", + "paths": [ + { + "windingRule": "NONE", + "data": "M 14 300 C 30 252 52 188 104 20" + } + ] + }, + "fills": [], + "strokes": [{ "type": "SOLID", "color": { "r": 0.447, "g": 0.314, "b": 0.231 } }], + "stroke": { "weight": 2, "cap": "ROUND", "join": "ROUND" } + } + } + } +} +``` + +## Transforms, masks, and native state + +- `figma.name` sets the display name; `data-key` remains identity. +- `locked` and `aspectRatioLocked` set interaction state. +- `relativeTransform` is a complete native 2×3 unit-axis transform; width and + height carry scale. Do not combine it with `rotate-*`. On create roots, TemPad + preserves rotation and skew but replaces translation with automatic placement. +- `stroke` carries weights, alignment, caps, joins, miter, and `dashPattern`. +- `corners` carries radii and smoothing. +- `mask` is `"ALPHA"`, `"VECTOR"`, `"LUMINANCE"`, or `null`. + +Place a mask before masked siblings inside one dedicated frame and describe all +direct siblings on update. A non-null mask needs a following sibling. Omission +preserves mask state; `null` disables it. + +After changing a mask, layout grid, or frame guide, call `get_structure` with +`options.native: true` on the smallest relevant root. Verify `native.mask` and +sibling order, or returned `native.layoutGrids` and `native.guides`; desired +bindings alone are insufficient. + +Use `{ "ref": "…" }` for catalog resources nested in native state and +`sourceCanvasKey` or `{ "canvasKey": "…" }` for same-result forward node +references. Never insert raw Plugin API calls. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/editing.md b/agent-plugin/src/skills/figma-canvas-authoring/references/editing.md new file mode 100644 index 00000000..f8653bd5 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/editing.md @@ -0,0 +1,44 @@ +# Edit an existing result + +Use this reference for an update, removal, or change of editor context. Read the +exact target and recover managed keys from structured tool results when prior +call context is unavailable. Names are labels, not identity. + +## Describe the desired change + +Trace the requested change through its visible dependents: a changed selection +may affect the working surface, label, enabled action, and summary. Preserve +unrelated content and relationships. Preserving the source does not mean +retaining stale representations of its previous state. + +Use the smallest owning target that can express the complete change: + +- For native state on existing keys, target the exact managed root and send only + `native`; omit markup to preserve topology. +- For structural changes, read `canvas-html.md`, keep `data-key` stable, and + include the affected structure. Omitted existing fields and keyed elements + retain their live state; omission is not deletion. +- `removeKeys` removes owned descendants. Top-level `mode: "remove"` removes an + exact managed root or page. Do not remove manual/unkeyed content, unmanaged + resources, or surviving external consumers. +- `mode: "activate"` requires `page.id` or `page.pageKey`, even for a + selection-only change. It changes editor context, not document state. An + exact off-current-page write does not require activation. + +Respect instance boundaries. Change an instance root or its authorized +component definition, never a definition-derived sublayer. Select only the +native references needed for the intended change. + +## Recover locally + +Read the entire mutation result. For a rejected payload, correct all reported +issues together without changing the design to fit the error. A verification +failure is rolled back by TemPad; do not assume a partial successful edit. +For an unknown transport outcome, read the exact target before retrying a create +or removal so an uncertain response does not become a duplicate mutation. + +Repair warnings where they occur. Replace a whole root only when an observed +structural defect requires it and the complete intended content can be +preserved. Reopen the affected composition after its last material write and +inspect its dependents; read back protected native facts when preservation +matters. Do not expand a local correction into an unrelated restyle. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/icons.md b/agent-plugin/src/skills/figma-canvas-authoring/references/icons.md new file mode 100644 index 00000000..b3457638 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/icons.md @@ -0,0 +1,65 @@ +# Deliver icons + +Use this reference only after the composition selects an icon role. It does not +require icons, set an icon count, or choose a family or visual style. + +Prefer permitted current-file, catalog, project, or user sources; otherwise use +a trustworthy brief-compatible source and record material license constraints. +When inspected evidence establishes a family or geometry, use that permitted +source or a compatible one. A general library is a fallback only when its +stroke or fill, optical weight, corners, negative space, and platform semantics +remain coherent. Do not diversify sources by quota. + +Import exact SVG geometry. Never redraw a known icon from memory or replace an +icon role with Unicode, emoji, TEXT, or assembled primitives. A character, +shape, or cluster that communicates an affordance, object, or semantic category +is an icon role even when beside a worded label. Before markup, scan literal +text for pictographic Unicode, emoji, and symbols and route each qualifying mark +to a permitted vector source. Simple geometry remains valid only when it is +itself the intended status or data mark, divider, decoration, or brand shape. + +Search results and snippets identify external candidates only; they establish +neither geometry nor license. Open the governing license once and fetch or open +every exact SVG used before markup. If either remains uninspected, omit an +optional icon or report a required gap instead of inventing one. + +For Direct delivery, give the icon a childless `div` whose classes supply the +decided wrapper bounds. Declare the inspected SVG document in +`assets[assetKey]` with `type: "SVG"`, then set +`native[nodeKey].figma.svg.assetKey` to that alias. An optional `color` resolves +`currentColor`; omit it for explicit-color SVGs. Figma may import a Frame with +Vector children; treat that subtree as one opaque asset and never flatten or +reconcile it. + +This complete Direct recipe demonstrates the required shape, not a design +default; its identifiers and values stand in for the already-decided role and +inspected source: + +```json +{ + "mode": "create", + "markup": "
", + "assets": { + "search": { + "type": "SVG", + "svg": "" + } + }, + "native": { + "search-icon": { + "figma": { "svg": { "assetKey": "search", "color": "#334155" } } + } + } +} +``` + +Omit `color` when it is not part of the selected source. A markup-only call +cannot deliver the SVG geometry. Once an icon source has been selected and +inspected, do not replace it with text or primitives merely to avoid the +`assets` and `native` mapping. + +For larger exact SVG, declare a Hub asset using a full lowercase SHA-256: + +```json +{ "type": "SVG", "assetHash": "" } +``` diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/images.md b/agent-plugin/src/skills/figma-canvas-authoring/references/images.md new file mode 100644 index 00000000..b019a960 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/images.md @@ -0,0 +1,120 @@ +# Deliver images and illustrations + +Use this reference only after the composition selects an image or illustration +role and the common boundaries in [visual-assets.md](visual-assets.md) establish +its subject and medium. + +Treat existing assets, rights-established remote sources, generation, and +purpose-built vectors as acquisition routes. Choose the nearest route that +satisfies content, fidelity, rights, quality, and import requirements; tools +have no global priority. Before importing a remote asset, establish its +applicable usage rights and a recoverable source. A search result, accessible +URL, CDN host, or lack of a watermark does not establish permission. Confirm +Canvas delivery before layout depends on the asset. + +When depiction is part of a record, keep it. Text, category icons, generic +placeholders, and numbered markers may index the record but cannot replace its +visual content. Source or generate an established raster role, preserve exact +vector art when vector is the real medium, or disclose the gap. + +Keep only enough trace to recover material choices, the remote source and its +applicable terms, or content distinctions. Combine role, evidence, medium, +source, rights, and import treatment in one short rationale when needed; do not +create a per-asset ceremony. Record exact creator, license, or attribution only +when the applicable terms, policy, or handoff requires it; assets sharing one +route and terms may share a trace. + +When medium is unspecified, use nearest visual evidence or ask if the choice is +material; otherwise state a low-consequence assumption. + +Use generation when the decided role needs a bespoke or fictional subject, +identity, composition, or treatment. In a prototype, a coherent generated set +may be the nearest truthful source for distinct fictional records; do not +require stock search merely because each subject is ordinary. For a real named +subject or supplied identity, use the supplied or rights-established source and +do not generate a substitute. Before generation, map each planned asset to the +subject and consumer it serves; skip ceremony that does not protect fidelity, +rights, or import. + +Compose generation and Hub import in one programmatic execution so image bytes +never enter prose or expire between calls: pass the generator's `data:` URL +directly to TemPad's `upload_asset`, read its returned `assetHash`, then declare +that hash as an IMAGE asset in `apply_canvas`. Do not regenerate an unchanged +prompt only to recover an importable URL. If generation or `upload_asset` is +unavailable, choose a rights-established public image source only when it +preserves the intended medium; otherwise disclose the required gap. Never +generate first and silently switch medium because import failed. + +Use `imageUrl` for a rights-established public IMAGE paint or same-file +`imageHash` for an existing image. For generated or other local Hub content, +declare the returned full lowercase SHA-256, then use its alias in a basic fill: + +```json +{ + "assets": { "image": { "type": "IMAGE", "assetHash": "" } }, + "native": { + "image-node": { + "figma": { + "fills": [{ "type": "IMAGE", "assetKey": "image", "scaleMode": "FILL" }] + } + } + } +} +``` + +Inline bytes and local paths are unsupported. Remote URLs must resolve directly +to accessible images, not pages or thumbnails. + +When a supplied canvas image is itself a permitted source artifact and an exact +visible subregion must carry into the result, reuse its same-file `imageHash` +instead of redrawing that content. For an axis-aligned source rectangle +`(x, y, width, height)` within an image of size `(imageWidth, imageHeight)`, and +a destination with the same aspect ratio, declare: + +```js +{ + type: "IMAGE", + imageHash: "", + scaleMode: "CROP", + imageTransform: [ + [width / imageWidth, 0, x / imageWidth], + [0, height / imageHeight, y / imageHeight] + ] +} +``` + +Supply the evaluated finite numbers, not expression strings. If the destination +aspect ratio differs, first choose an aspect-correct source rectangle rather +than stretching the subject. Open the rendered crop and verify its native IMAGE +fill; a valid transform does not prove that the intended subject was isolated. + +When the medium must remain a real image, verify with `get_structure` and +`options.native: true`; `native.imageFills` must contain the expected non-null +Figma hash. Input URLs, successful mutation, and visually similar screenshots +are not native read-back. + +The main agent owns placement, crop, and final verification. In a comparison, +make visual differences represent the subjects rather than their source files: +normalize incidental canvas padding, crop, background, viewpoint, and apparent +scale when they would bias the decision; preserve and explain differences that +are real or cannot be normalized faithfully. + +Before markup, map every content-bearing image consumer to the subject it +claims to depict. Reuse one asset and crop only when consumers represent that +same subject; distinct records require distinct assets or crops that visibly +isolate the correct subject. A composite scene may serve the composition it +depicts, but cannot stand in for several named records. Stop and source or +generate missing media instead of serializing a false mapping. + +When a gallery, carousel, or thumbnail set promises several views of one +subject, every retained view must add distinct, truthful information. Repeating +one unchanged source and crop does not satisfy that role; unrelated subjects +break identity. Use distinct sourced views, evidence-supported crops, or +generation/editing only for a named same-subject coverage need that sourcing +cannot satisfy. Otherwise reduce the views or disclose the gap. + +For repeated depictions of the same subject, keep asset identity and crop +stable unless evidence requires variation. If required media remains +unavailable, report it; omit optional media or use a neutral slot only when the +requested outcome is unchanged. A neutral slot is an explicit fallback, not +representative content or proof of reusable variation. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/local-styles.md b/agent-plugin/src/skills/figma-canvas-authoring/references/local-styles.md new file mode 100644 index 00000000..74aec685 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/local-styles.md @@ -0,0 +1,61 @@ +# Author local styles + +Use this reference only when the user or resolved system plan requires a local +style. Do not extract styles from an ordinary screen. New local resources need +no catalog; send `catalogId` only when a nested `{ "ref": "…" }` deliberately +reuses an existing resource. + +Copy this recipe and change its design facts. Style authoring keys persist +file-wide and are neither names nor IDs. Namespace keys by product and role. In +shared drafts, also prefix generic visible names that could collide; retain +established project naming when already clear. + +For whole-node typography, prefer a `theme.textStyles` alias and a `type-*` +class using [resource-mapping.md](resource-mapping.md). The recipe below shows +the explicit native binding form, also used for paint, effect, and grid styles. + +```json +{ + "mode": "create", + "markup": "
Account
", + "styles": { + "product/style/surface": { + "type": "PAINT", + "name": "Product/Color/Surface", + "paints": [{ "type": "SOLID", "color": { "r": 1, "g": 1, "b": 1 } }] + }, + "product/style/heading": { + "type": "TEXT", + "name": "Product/Typography/Heading", + "fontName": { "family": "Inter", "style": "Semi Bold" }, + "fontSize": 20, + "lineHeight": { "unit": "PIXELS", "value": 28 } + } + }, + "native": { + "card": { + "styles": { + "fill": { "styleKey": "product/style/surface" } + } + }, + "card/title": { + "styles": { + "text": { "styleKey": "product/style/heading" } + } + } + } +} +``` + +Types are `PAINT`, `TEXT`, `EFFECT`, and `GRID`, using `paints`, text fields, +`effects`, or `layoutGrids` respectively. For exact Paint, Effect, and Grid +shapes beyond this recipe, read [paints-effects.md](paints-effects.md). + +Omission preserves managed state. Top-level `null` removes a managed style only +when absence is required and all live consumers are cleared or removed in the +same result. Never mutate remote resources, invent library keys, or create a +broad style library for one screen. + +`unbound-created-style` means a same-call style lacks a `styleKey` consumer. +Bind it to a representative property performing its named role or remove it. A +swatch or unrelated binding is not coverage. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/paints-effects.md b/agent-plugin/src/skills/figma-canvas-authoring/references/paints-effects.md new file mode 100644 index 00000000..c32b82f2 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/paints-effects.md @@ -0,0 +1,111 @@ +# Paints, effects, grids, guides, and media + +Use this reference whenever the result uses a nontrivial shadow, blur, glass, +texture, noise, image paint, layered gradient material, or layout aid, including +effects expressed as Canvas HTML classes. Resolve an image or illustration's +role, subject, and medium through [visual-assets.md](visual-assets.md), then its +source and delivery through [images.md](images.md). Prefer a matching catalog +style; otherwise use direct native arrays. + +## Catalog links + +```html +
+``` + +A style owns its channel. Do not combine a non-null fill or stroke style with a +whole-node variable on the same paint. Styled strokes still need literal, +typed, or variable-bound geometry. `null` unlinks; omission preserves. + +## Resolve shadow references + +Named scales such as `shadow-md` are theme references, not portable geometry: + +- Reuse: bind the matching catalog Effect style. +- Author: create and bind a local Effect style only when the system plan requires + it. +- Direct: use an exact `shadow-[...]` class or typed `figma.effects` value. + +Never assume Tailwind defaults or create a token only to resolve a named class. +`shadow-none`, `inset-shadow-none`, and `text-shadow-none` explicitly clear. + +Treat an outer shadow's rendered halo as part of the composition. Inspect the +final PNG beyond the root edges; visible granular or noisy fringe, or a halo +that dominates the captured bounds, is a defect even when the frame itself is +intact. Preserve intended depth by tightening blur, spread, or opacity or using +smaller layered shadows, then recheck. Do not flatten established material +treatment merely to hide the defect. + +## Native paint and effect stacks + +`figma.fills` and `figma.strokes` support ordered solid, linear/radial/angular/ +diamond gradient, image/video, Pattern, and fill-shader paints. +`figma.effects` supports ordered shadows, normal/progressive blur, noise, +texture, glass, and effect shaders. + +A `SOLID` paint uses RGB `color` and optional paint-level `opacity`; only +gradient stops use RGBA colors. Keep stroke geometry, including `dashPattern`, +in `figma.stroke`, not the stroke paint. + +Use the exact gradient enum and normalized RGBA stop shape; do not translate +from CSS or Plugin API names: + +```json +{ + "figma": { + "fills": [ + { + "type": "GRADIENT_LINEAR", + "gradientTransform": [ + [1, 0, 0], + [0, 1, 0] + ], + "gradientStops": [ + { "position": 0, "color": { "r": 1, "g": 0.43, "b": 0.29, "a": 1 } }, + { "position": 1, "color": { "r": 0.16, "g": 0.09, "b": 0.24, "a": 1 } } + ] + } + ] + } +} +``` + +Other gradient enums are `GRADIENT_RADIAL`, `GRADIENT_ANGULAR`, and +`GRADIENT_DIAMOND`. + +Omission preserves a stack; `[]` clears it. Direct stacks cannot share their +channel with a literal class, whole-node variable, or style. Use variable refs +such as `{ "ref": "v1" }` and shader refs such as `{ "ref": "h1" }`; use only +returned shader property IDs and declared value shapes. + +For images, provide exactly one same-file `imageHash`, public HTTP(S) `imageUrl`, +or call-scoped `assetKey` for a full-SHA-256 Hub IMAGE asset. PNG, JPEG, and GIF +are limited to 4096×4096. For video, provide exactly one same-file `videoHash` or +public `videoUrl` for MP4, MOV, or WebM up to 100 MB. URLs must need no +credentials. Reuse `figmaImageHash`, `figmaImageHashes`, or `figmaVideoHashes` +from `get_code` only in the same file; they identify native media, not preview +bytes. + +A Pattern uses exactly one existing `sourceNodeId` or same-result +`sourceCanvasKey`. + +## Layout aids + +Prefer a matching Grid style. Otherwise `figma.layoutGrids` declares ordered +row, column, or square grids on frames, components, sets, and instances. Use +`"AUTO"` for automatic row or column count. Do not bind `sectionSize` with +`STRETCH` or `offset` with `CENTER`. + +`figma.guides` is the complete ordered X/Y guide list: omission preserves and +`[]` clears. Page guides live under `page.guides`. + +For wrapping linear Auto Layout, `figma.autoLayout` may set signed +`itemSpacing`, positive or synchronized-null `counterAxisSpacing`, and +`itemReverseZIndex`. Never declare one physical gap in both classes and native +state. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/resource-mapping.md b/agent-plugin/src/skills/figma-canvas-authoring/references/resource-mapping.md new file mode 100644 index 00000000..4d3f3db8 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/resource-mapping.md @@ -0,0 +1,138 @@ +# Use resources in Canvas classes + +Keep layout and visual composition in markup. Put a reusable value's native +identity in the catalog or a call-scoped `theme`, then reference it by class. +Variables remain bound Figma variables, including mode changes. A `type-*` +class binds an entire native TextStyle. Ordinary utilities such as `gap-4` and +`text-base` remain literals and do not create or discover resources. + +## Existing system + +When the applicable system permits reuse, discover it with `get_design_system`. +Use returned variable `cssName` and TEXT-style `className` with its `catalogId`: +`bg-(--surface)`, `gap-(--spacing-content)`, `type-body`. These are examples of +names, not assumed resources. Read a style's exact ref when its font, metrics, +or bindings affect the choice. + +The catalog uses valid WEB code syntax when available, otherwise derives a +name. It disambiguates collisions and keeps the resulting alias tied to one +exact identity for that catalog's lifetime. Use the returned name unchanged; +never derive identity from equal values, similar names, or another catalog. + +For task-specific names, add `theme.variables: { "--surface": { "ref": "v1" } }` +or `theme.textStyles: { "type-body": { "ref": "s1" } }`. Use returned refs. An +alias cannot replace another catalog alias with a different resource. A stable +authoring key and catalog ref for the same native identity may share an alias. + +## New system + +When the deliverable includes a design system, define the selected variables +and styles through `variableCollections` and `styles`. Map their stable keys in +`theme` and consume them in the same call. A primitive draft without a system +still uses ordinary classes; repetition alone does not require resource creation. + +This complete recipe illustrates the relationship. Change the design facts, +namespace resource keys for the product, and confirm the font family/style in +the environment before authoring it. + +```json +{ + "mode": "create", + "markup": "
Account settings
", + "theme": { + "variables": { + "--surface": { "variableKey": "product/color/surface" }, + "--content-gap": { "variableKey": "product/space/content" } + }, + "textStyles": { "type-body": { "styleKey": "product/type/body" } } + }, + "variableCollections": { + "product/theme": { + "name": "Product/Theme", + "modes": { "light": { "name": "Light" }, "dark": { "name": "Dark" } }, + "variables": { + "product/color/surface": { + "name": "Surface", + "type": "COLOR", + "codeSyntax": { "WEB": "var(--surface)" }, + "values": { + "light": { "r": 1, "g": 1, "b": 1 }, + "dark": { "r": 0.08, "g": 0.09, "b": 0.11 } + } + }, + "product/space/content": { + "name": "Space/Content", + "type": "FLOAT", + "values": { "light": 16, "dark": 16 } + } + } + } + }, + "styles": { + "product/type/body": { + "type": "TEXT", + "name": "Product/Typography/Body", + "fontName": { "family": "Inter", "style": "Regular" }, + "fontSize": 16, + "lineHeight": { "unit": "PIXELS", "value": 24 } + } + } +} +``` + +On later calls, retain the small `theme` mapping and omit resource definitions +unless changing them. The stable keys resolve the same native resources. The +mapping is local to the call, so different screens can use different aliases +without changing the file's naming. Authoring keys and native identities +persist; aliases do not create a second resource registry. + +Use [variables.md](variables.md) for modes, aliases, scopes, and resource updates; +use [local-styles.md](local-styles.md) for style definitions. A TextStyle may +bind selected typography primitives through its `variables` fields when those +values must change together. Do not create font-family, size, or weight tokens +solely to express a single named text role: the TextStyle can hold those facts. + +## Supported variable utilities + +Both `gap-(--space)` and `gap-[var(--space)]` work. Explicit type hints resolve +ambiguous Tailwind prefixes, for example `text-(length:--body-size)` versus +`text-(color:--foreground)`. + +| Utility | Native value | +| ---------------------------------------------------------------------- | ------------------------------------------------------- | +| `bg-(--surface)`, `text-(--foreground)`, `border-(--border)` | COLOR fill or stroke; border still needs a width | +| `w/h/size/min-w/max-w/min-h/max-h-(--value)` | FLOAT dimensions, in pixels | +| `gap/gap-x/gap-y-(--value)` | FLOAT layout gaps, in pixels; axes follow flex or grid | +| `p/px/py/pt/pr/pb/pl-(--value)` | FLOAT padding, in pixels | +| `rounded/rounded-tl/rounded-tr/rounded-br/rounded-bl-(--value)` | FLOAT corner radius, in pixels | +| `border-(length:--width)` | FLOAT stroke width, in pixels | +| `text-(length:--size)`, `leading-(--leading)`, `tracking-(--tracking)` | FLOAT font size, line height, letter spacing, in pixels | +| `font-(family-name:--family)` | STRING font family | +| `font-(--weight)` | FLOAT font weight, 1–1000 | +| `opacity-(--opacity)` | FLOAT opacity, 0–1 | + +The tool reads an initial native value itself and retains the variable binding; +do not add a second literal fallback class. Native node, layout, and scope rules +still apply. This is a bounded mapping to Figma fields, not a CSS engine: no +`calc()`, var fallbacks, arbitrary expressions, or cascade. FLOAT metrics use +the native units above, not unitless CSS line-height multipliers. + +## Typography ownership + +`type-body` consumes the whole TextStyle. Keep color, sizing, alignment, and +wrapping classes on the text node as needed; omit font, weight, size, leading, +tracking, case, and decoration overrides owned by that style. Choose another +style or explicitly unlink the style for a deliberate local treatment. Composite +typography has no single Figma variable type, so `type-*` is an explicit custom +utility convention rather than a Tailwind default or a fabricated CSS variable. + +Inline `data-var-*`, `data-style-*`, and `native` bindings remain available for +fields outside this subset, exact native fonts/styles, and explicit unlinking. +Use one mechanism per property. Unknown names, conflicting declarations, +incompatible types, and cyclic variable aliases require correction; the tool +does not guess a replacement. + +Updates preserve omitted native state. Removing a resource class or replacing +it with a literal does not unlink the existing binding: explicitly clear the +variable/style with its `data-var-*="none"`, `data-style-*="none"`, or supported +`native` null binding when that is the intended change. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/rich-text.md b/agent-plugin/src/skills/figma-canvas-authoring/references/rich-text.md new file mode 100644 index 00000000..3e26cc97 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/rich-text.md @@ -0,0 +1,52 @@ +# Rich text and hyperlinks + +Use this reference for native font application or Figma-only text behavior; +use [typefaces.md](typefaces.md) when font selection or availability needs resolving. +Use `span` for editable text. Put whole-node typography in classes, a catalog +Text style, or semantic variable bindings when possible. + +`native[key].figma.text` supports: + +- exact whole-node `fontName`, `autoRename`, vertical alignment, and leading + trim; +- paragraph indent/spacing, list spacing, hanging punctuation/list; +- whole-node hyperlink; +- ordered rich-text `ranges`. + +Do not combine `autoRename: true` with fixed `figma.name`. + +When no Text style or typography variable expresses the chosen family and +style, use the exact available Figma font: + +```json +{ + "fontName": { "family": "IBM Plex Sans", "style": "Medium" } +} +``` + +Do not combine it with `font-*` classes, linked Text styles, or font family/style +variables. Never guess family or style availability. + +Range `start` and `end` are UTF-16 offsets into final characters. Ranges must be +ordered, non-overlapping, and set at least one property; split overlapping +intentions into disjoint intervals. A range may set font name/size, case, +letter spacing, line height, complete underline state, native fills, Text/Paint +style, list options, indentation, paragraph spacing, hyperlink, and supported +text-range variables. + +Use `{ "ref": "s1" }` for a catalog range style and `{ "ref": "v1" }` for a +range variable. `null` unlinks supported styles or hyperlinks; omission +preserves. + +Hyperlinks support URLs and node targets. For a same-result target: + +```json +{ + "type": "NODE", + "value": { "canvasKey": "settings/help" } +} +``` + +The target may appear later in markup; never remove a live hyperlink target. If +a catalog component exposes text through a prop, set that prop instead of +editing internal layers. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/style-grounding.md b/agent-plugin/src/skills/figma-canvas-authoring/references/style-grounding.md new file mode 100644 index 00000000..2a83efca --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/style-grounding.md @@ -0,0 +1,80 @@ +# Ground design judgment + +Use this reference for a new direction, material redesign, or consequential +uncertainty not settled by the user or an established source. Exact reproduction +and mechanical edits use their supplied evidence directly. + +## Inspect what can change the decision + +Start with the nearest credible evidence: the supplied design or implementation, +real product states, primary platform requirements, or adjacent visual work. +Choose separate evidence for behavior and visual expression when needed. A +functional walkthrough can establish behavior without settling visual language; +a visually relevant product state or adjacent visual work can show how density, +controls, surfaces, icon/text economy, and states cohere without establishing +behavior it does not expose. One artifact may inform both only when the relevant +behavior and pixels are actually inspected. + +Open the relevant state at useful scale. A homepage or brand campaign may not +show the working interface. Search cards, prose, remembered products, generated +images, and failed retrievals are not inspected visual precedents. A content +photograph establishes what it depicts, not the surrounding application's +interaction or composition. Follow the main skill's first-write evidence +boundary when retrieval fails. + +An image-search result that exposes only a screenshot description or URL remains +a search card. Open the actual product-state pixels at useful scale before +treating them as visual grounding; otherwise use the result only as behavioral +description. + +Research is grounded when it changes, confirms, or reopens a material decision +in the new result. Retain enough source identity and context to support that +claim; do not invent a source-by-source decision report. If a source contributed +nothing consequential, do not cite it as a precedent. Generic expertise helps +interpret the evidence; its familiar defaults are not evidence about this +product. + +There is no source quota. Stop when further investigation is unlikely to change +a material choice. Do not research routine decisions for ceremony. Keep source +screens outside the authored result unless the user asked to place or reproduce +them, and preserve required source content and behavior when adapting a design. + +## Form a provisional direction + +Integrate the brief, evidence, and professional judgment into a relationship +among content, state, and action, with a visual language that makes it fitting +and perceptible. A new design needs its own solution; independence is not a +reason to discard an applicable interaction or representation because it is +harder to source or serialize. + +Before the first write, be able to state privately what the inspected pixels +changed or confirmed about the recurring visual language. A mood label or +task-themed palette is not that direction; if the same control and surface +grammar could survive a noun swap, inspect more relevant pixels or reconsider +the synthesis. + +Resolve recurring visual roles enough to try them in a real composition. The +foundation is provisional and may change after seeing pixels. It is not a +separate foundation board or permission to create components, variables, or +styles outside the task's resource scope. + +Reconsider choices whose only justification is habit or semantic association. +Ask what in the brief or inspected reality makes the proposed treatment fit. +Familiar solutions can be appropriate; choosing the opposite of a criticized +motif is no stronger evidence. Functional specificity alone does not settle +expression, and stylistic difference alone does not make the product useful. + +## Externalize unresolved visual choices + +If materially different visual hypotheses remain and a capable image-generation +tool is available, a bounded visual exploration can help you see their +consequences. Open those pixels and use them to reconsider the composition; +omit this step when the direction is already clear. + +Generated concepts are speculative sketches, not real-product evidence or +flattened Figma deliverables. Do not trust their text/data or trace them +literally. A generated subject chosen as actual product content is a separate +asset decision under `visual-assets.md`. + +Return to the representative native composition and inspect it. Let a mismatch +reopen the decision it actually challenges; otherwise complete the design. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/typefaces.md b/agent-plugin/src/skills/figma-canvas-authoring/references/typefaces.md new file mode 100644 index 00000000..185284bc --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/typefaces.md @@ -0,0 +1,48 @@ +# Choose and apply fonts + +Use this reference when selecting or changing fonts, delivering a required +family/style, or resolving uncertainty about the text's scripts. Availability +can change a provisional choice; query before committing when that matters. + +Start from applicable Text styles, typography variables, project fonts, or +supplied references. Preserve established font identities for ordinary edits. +For a new direction, form candidates from the language, text roles, density, +and visual intent. A portable `font-sans|serif|mono` category does not establish +an exact family or suitable coverage for the actual text. + +## Query what can change the choice + +`get_design_system` with `scope: "fonts"` reads the environment without scanning +file resources. It is valid for direct composition, reuse, and an independent +system, including a blank page. + +- With candidate family names, use `families: ["Noto Sans SC"]` to inspect + exact native style names and missing families in one call; batch candidates. +- Use `query: "Noto"` when the family name itself needs discovery. This searches + names, not language coverage or visual suitability. +- Continue `nextCursor` with the same filters only when more results could + affect the choice. Reuse current evidence rather than querying per text node. + +Use returned or source-established native names. For an unavailable provisional +candidate, reconsider the choice. For a required font, preserve the requirement +and disclose the delivery gap rather than silently substituting another family. + +## Apply the selected typography + +Reuse the applicable TextStyle or font variables. If a new design system is in +scope, define the selected text roles as TextStyles and consume their `type-*` +classes through [resource-mapping.md](resource-mapping.md). Font selection alone +does not require creating styles or tokens. + +For direct composition, `font-[family-name:Noto_Sans_SC] font-semibold` fixes +the family and chooses its closest available weight. Underscores encode spaces; +`\_` preserves an underscore. Use `native[key].figma.text.fontName` with exact +`{ family, style }` when the native style identity matters; see +[rich-text.md](rich-text.md). Weight matching is approximate. For variable-driven +typography, consider the family/weight/style combinations in the delivered modes. + +Inspect representative real content in the composition, including relevant +scripts, numbers, punctuation, and wrapping. Availability and successful loading +do not prove glyph coverage; a correct-looking screenshot alone does not prove +native font identity or current editability. Reopen the font choice when the +observed text challenges it, without requiring a separate specimen board. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/variables.md b/agent-plugin/src/skills/figma-canvas-authoring/references/variables.md new file mode 100644 index 00000000..692a8699 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/variables.md @@ -0,0 +1,154 @@ +# Author local variables + +Use this reference after the representative pixel check when repeated colors +may carry shared semantic roles, or when the user or resolved system plan +requires local variables. Do not extract tokens from an ordinary screen. New +resources need no catalog; send `catalogId` only for deliberate nested +`{ "ref": "…" }` reuse. + +## Contents + +- [Decide from real roles](#decide-from-real-roles) +- [Author variables](#author-variables) +- [Bind and verify](#bind-and-verify) +- [Update and remove](#update-and-remove) + +## Decide from real roles + +After any selected representative component reconciliation and before +propagation, call full `get_code` with unresolved tokens only when repeated +colors plausibly represent semantic roles whose coordinated maintenance matters. +Treat `literalClusters` as candidate locations, not a to-do list. Select a role +only when concrete consumers should evolve together; split mixed roles even +when their literal values match. Leave incidental, local, and ambiguous +repetition literal. If the diagnostic is unavailable, do not infer a system +from repetition. + +For each selected role, map concrete consumer and field to a semantic variable +key, bind every representative consumer, then re-run once to confirm the role is +exposed through `tokens` and no longer unresolved. A non-empty +`literalClusters` result is acceptable. + +Carry only selected mappings into propagation. A later apply that includes a +consumer of a selected role must bind that field in the same call; an inherited +instance binding does not cover sibling literals. Before finalization, scan each +materially distinct dependent root that uses a selected role once, fix missing +bindings for those roles, and recheck only changed roots. Do not create variables +to empty diagnostics, expand the map from literal equality, or repeat scans after +the selected roles are verified. + +## Author variables + +Copy this recipe and change its design facts. Collection and variable authoring +keys persist file-wide and are neither names nor IDs. Choose one +collision-resistant prefix for the independent system; recover existing exact +keys when intentionally updating it. Mode keys are collection-scoped. + +```json +{ + "mode": "create", + "markup": "
Account
", + "variableCollections": { + "product/theme": { + "name": "Theme", + "modes": { + "light": { "name": "Light" }, + "dark": { "name": "Dark" } + }, + "variables": { + "product/color/surface": { + "name": "Color/Surface", + "type": "COLOR", + "scopes": ["ALL_FILLS"], + "values": { + "light": { "r": 1, "g": 1, "b": 1 }, + "dark": { "r": 0.08, "g": 0.09, "b": 0.11 } + } + }, + "product/space/md": { + "name": "Spacing/Medium", + "type": "FLOAT", + "scopes": ["GAP"], + "values": { + "light": 16, + "dark": 16 + } + } + } + } + }, + "native": { + "card": { + "variables": { + "fill": { "variableKey": "product/color/surface" }, + "gap": { "variableKey": "product/space/md" } + }, + "variableModes": { + "product/theme": "dark" + } + } + } +} +``` + +A new collection needs `name` and at least one named mode. Each variable needs +`name`, `type`, and a value for every mode. Types are `BOOLEAN`, `COLOR`, +`FLOAT`, and `STRING`. Values may alias another variable: + +```json +{ "variable": { "variableKey": "…" } } +``` + +Valid scopes: + +- general: `ALL_SCOPES`, `TEXT_CONTENT`, `CORNER_RADIUS`, `WIDTH_HEIGHT`, `GAP`, + `OPACITY`; +- color: `ALL_FILLS`, `FRAME_FILL`, `SHAPE_FILL`, `TEXT_FILL`, `STROKE_COLOR`, + `EFFECT_COLOR`; +- numeric effect/stroke: `STROKE_FLOAT`, `EFFECT_FLOAT`; +- typography: `FONT_FAMILY`, `FONT_STYLE`, `FONT_WEIGHT`, `FONT_SIZE`, + `LINE_HEIGHT`, `LETTER_SPACING`, `PARAGRAPH_SPACING`, `PARAGRAPH_INDENT`. + +Use `STROKE_COLOR`, not `ALL_STROKES`. Combine neither `ALL_SCOPES` with other +scopes nor `ALL_FILLS` with `FRAME_FILL`, `SHAPE_FILL`, or `TEXT_FILL`; +`ALL_FILLS` may coexist with a non-fill scope such as `STROKE_COLOR`. + +## Bind and verify + +Bind through `native[key].variables` using the exact supported field, such as +`fill`, `stroke`, `gap`, `paddingTop`, `width`, `visible`, `fontSize`, or +`characters`. Retain a matching literal class when Figma needs an initial paint +or numeric fallback. + +Bind each variable to representative fields performing its semantic role. +Prefer `GAP` for shared gaps/padding, `WIDTH_HEIGHT` for semantic control/icon +sizes, and `CORNER_RADIUS` for shared radii. Do not tokenize viewport dimensions, +one-off crops, content-derived geometry, or optical corrections merely because +numbers repeat. + +A representative binding proves usability, not complete coverage. Bind every +consumer intended to evolve with the role; keep equal peer literals only when +incidental or independently owned. + +`apply_canvas` reports `unbound-created-variable` when a new variable lacks a +same-result consumer. Bind it to a real consumer or remove it. A staged warning +may be temporary, but final delivery must show a native binding; equal literals +do not count. + +`variable-fallback-mismatch` means a bound literal matches none of the +same-call variable's direct or aliased mode values. Align the fallback with a +real mode or bind the variable that owns the value, or the binding will silently +change the declared markup. + +## Update and remove + +After changing a variable value, update and verify every intended consumer that +cannot carry a native binding, such as `figma.svg.color`; omission leaves its +old literal in place. + +Omission preserves managed state. Top-level `null` removes a managed variable, +mode, or collection only when absence is required and all consumers are cleared +or removed in the same result. Never mutate remote resources, invent parent +collections or library keys, or build a broad token system for one screen. +Extended collections must inherit a real local or catalog collection and obey +plan limits. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/visual-assets.md b/agent-plugin/src/skills/figma-canvas-authoring/references/visual-assets.md new file mode 100644 index 00000000..eaa3d4c8 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/visual-assets.md @@ -0,0 +1,57 @@ +# Choose and preserve visual assets + +Use this reference after the design selects an icon, image, +illustration, diagram, or vector asset. It governs role, medium, source +integrity, editability, and delivery—not whether the design should contain that +asset or what the finished visual style should be. + +Research pixels and generated screen concepts remain evidence for judgment, +not canvas content. Import, reproduce, annotate, or compare them only when the +user explicitly requests that treatment. When evidence establishes that the +new product needs an asset role, acquire or author a truthful asset for the new +result instead of redrawing or embedding the reference. + +## Preserve the decided role + +Start from the composition, not an available tool or assumed asset slot. Once a +material role is selected, fulfill it faithfully; sourcing difficulty is not a +reason to replace an image, icon, visualization, or exact medium with easier +text or plausible geometry. + +Depiction is a role, not a medium. Choose raster, sourced vector, +agent-authored vector, diagram, or another medium only when the brief, inspected +evidence, or a low-consequence assumption supports it. Convenience never +changes the medium. + +Treat content-bearing visualization—such as a chart, map, waveform, notation, +document or media preview, or domain instrument—as a first-class +representation. Identify the user decision and the visual structures that make +it possible. Preserve enough context and density to act; a stylized trace or +labeled decoration is not the representation. When only topology or sequence +is intended, name and design it as a diagram. + +When recognition depends on a subject's real appearance—such as a person, +product, food, place, room, photograph, cover, or shared-media preview—preserve +that distinction with a real sourced or generated image unless the brief or +inspected evidence independently establishes an illustrated language. + +Preserve editability semantics. Build changing diagram labels, shapes, and +relationships as native structure; use an opaque SVG only when exact vector art +is the asset. An SVG wrapper with Vector descendants does not make a diagram +model editable. If editable primitives cannot carry a required representation, +use an evidence-supported native, vector, or raster base with changing overlays +editable, or disclose the gap. + +For material assets retain enough evidence for identity and content fidelity, +provenance and applicable rights, source quality, and Canvas-compatible form. +Never silently change subject, style, or medium. Crops, masks, overlays, and +retouching must preserve the depicted subject; do not hide distinctive branding +or features to make one subject represent another. + +## Load only the selected branch + +- For an icon role, read [icons.md](icons.md). +- For an image or illustration, read [images.md](images.md). + +For diagrams and other custom vector art, use the source and editability +boundaries above, then load only the required geometry or paint mechanics. diff --git a/agent-plugin/src/skills/figma-canvas-authoring/references/visual-composition.md b/agent-plugin/src/skills/figma-canvas-authoring/references/visual-composition.md new file mode 100644 index 00000000..27993d33 --- /dev/null +++ b/agent-plugin/src/skills/figma-canvas-authoring/references/visual-composition.md @@ -0,0 +1,64 @@ +# Compose a product interface + +Use this reference when forming or reconsidering a composition. Keep the +person's working experience in view; use the questions below only where they +help resolve a decision. They are not independent quality axes. + +## Find the working relationship + +What is the person attending to, and what can they do with it in the depicted +state? Does the chosen screen or flow expose the user's central work, or merely +promise it through a button whose destination is absent? What changes across +states, and what must remain perceptible while that happens? Arrange content, +controls, and context so their relationship is understandable in the rendered +whole. + +A familiar shell may be the right answer. Reconsider it when it hides the +working object, requires unnecessary reading or navigation, or survives only +because task-specific nouns make it look relevant. Novelty and decoration do +not repair that mismatch. + +As content grows, what extends: the document or an owned scrolling region? +Choose document flow, a fixed workspace, or a hybrid from product behavior; +check that making room has not silently redefined the device or window viewport. +Density and control scale follow platform, frequency, precision, and environment +of use. In frequent expert work, inspect the real product's interaction economy +before carrying over the spacing and repeated explanations of an occasional +consumer journey. Preserve legibility and suitable targets in either case. + +## Make meaning perceptible + +What should someone notice now, and what should stay available without +competing? Resolve type, position, scale, color, contrast, media, depth, and space +together. Repeated roles need recognizable treatment; differences need to carry +meaning in this task. An expressive role does not by itself justify the first +familiar palette, shape, or effect. + +Choose text, icons, images, and graphics by recognition, comparison, +manipulation, and expression. Familiar iconographic affordances can reduce the +reading and space required by repeated controls; words can be more precise. +Inspect that tradeoff at actual size, including when every action has become +text. Source selected icons through `visual-assets.md`; sourcing effort is not +a design reason to drop their role. + +A working graphic must carry the distinctions needed for the decision. Check +whether its marks, scale, context, and state make the relevant comparison or +manipulation possible. Changing a label does not change what the marks encode. This is a question +of represented meaning, not a quota for detail or a preferred graphic style. Use `visual-assets.md` for truthful +source and native representation. + +## Learn from the rendered result + +Open the representative composition at useful scale. Mentally follow the +central action through its visible consequences. Does the selected state agree +with the working surface, available action, and result? If the experience breaks, +inspect the particulars that explain where and why. + +Judge spacing from visible relationships: nested insets, seams, baselines, +grouping, and repeated rhythm. Nominal padding or a non-overflowing bounding box +does not prove that the intended space survived native layout. Repair the +owning relationship instead of decorating over it. + +Carry resolved shared roles into dependent screens while allowing their layouts +to differ with the work. Stop when the requested whole is coherent and the +observed defects are resolved; do not keep polishing to fill a checklist. diff --git a/agent-plugin/src/skills/figma-design-to-code/SKILL.md b/agent-plugin/src/skills/figma-design-to-code/SKILL.md new file mode 100644 index 00000000..a5bb5f20 --- /dev/null +++ b/agent-plugin/src/skills/figma-design-to-code/SKILL.md @@ -0,0 +1,177 @@ +--- +name: figma-design-to-code +description: >- + Implement or update project-consistent UI code from a visible Figma selection + or nodeId using TemPad Dev MCP. Use when the user wants Figma UI recreated, + ported, or integrated into the target project's framework, styling system, + tokens, assets, and existing components. Do not use for design critique, + product invention, generic code review, or guessing states, responsiveness, + or behavior not evidenced by Figma, the project, or the user. +--- + +# Implement Figma design in code + +Turn visible Figma evidence into the smallest project-native implementation +that preserves the intended result. Keep that result focal: project files, +TemPad output, rules, and tool calls are evidence for the implementation, not +deliverables to reproduce mechanically. + +Require TemPad Dev MCP to provide trustworthy design evidence for the current +selection or an exact `nodeId` inside the user's established scope. Never +reconstruct the design from memory, screenshots alone, or `get_structure` +metadata. + +## Evidence and authority + +Use each source only for what it can establish: + +- **The user** sets scope, requirements, prohibitions, and missing product or + implementation decisions. +- **The project** sets framework, file placement, component boundaries, + styling, tokens, assets, dependencies, and verification conventions. +- **TemPad Dev** sets visible structure and rendered design facts. + +Follow project instruction files for concerns outside Figma-to-code +translation. Do not add policy for routing, analytics, i18n, CMS, or other +orthogonal systems. + +TemPad can establish visible hierarchy, layout, spacing, typography, color, +effects, token references, exported assets, and codegen unit context. It cannot +establish unevidenced states, responsive behavior, business logic, navigation, +validation, analytics, or project conventions. Treat `get_structure` as +hierarchy and geometry evidence only, never as missing style truth. + +## Workflow + +### 1. Establish the implementation envelope + +Read only local evidence that can change this implementation, in this order: + +1. applicable `AGENTS.md` or equivalent instructions; +2. relevant design-system, token, component, and asset guidance; +3. the nearest comparable implementation and reusable primitives; +4. framework, styling, and check configuration needed for this task. + +Determine the target file or component boundary, framework, styling method, +token and asset paths, reuse candidates, dependency constraints, and narrowest +relevant checks. Inspect Tailwind version and theme scales only when the +project actually uses Tailwind-compatible tooling. + +Do not inventory the repository broadly after the needed envelope is clear. If +a missing project decision would materially change the result, ask before +implementation. + +### 2. Read the design at the requested scope + +Call TemPad Dev's `get_code` before implementing: + +- use `resolveTokens: false` by default; +- omit `nodeId` for the current single selection; pass one only when the user + supplied it or TemPad returned the exact ID for a targeted read inside the + user's established scope; +- set `preferredLang` from the established project target; +- keep TemPad's default vector behavior unless the user explicitly requests + asset-preserving vector fidelity and the active MCP version supports it. + +Use `resolveTokens: true` only when the user explicitly does not want design +token references. Treat returned `lang` as authoritative because plugin +configuration may override `preferredLang`. + +Retain the returned `code`, `lang`, `warnings`, `assets`, `tokens`, and +`codegen` facts that bear on the implementation. Use +`codegen.config.{cssUnit,rootFontSize,scale}` for exact unit conversion. + +Prefer one top-level read that preserves the requested composition. If the +tool is unavailable, points at the wrong file, or returns incomplete evidence, +read [recovery.md](references/recovery.md) before doing anything else. + +### 3. Separate facts, adaptations, and gaps + +Before editing, distinguish: + +- **design facts** to preserve; +- **project-native adaptations** supported by existing components, tokens, + utilities, or asset conventions; +- **unevidenced product decisions** that must remain unimplemented or be asked. + +Map by rendered value and semantics, not by a convenient name. A familiar +component or token is a candidate, not proof of equivalence. If more than one +material implementation path remains equally plausible, ask the user. Infer +only low-consequence details and report any inference that affects the result. + +### 4. Implement the smallest coherent change + +- Keep the established framework, styling system, file placement, imports, and + abstraction level. Do not introduce a parallel system. +- Reuse an existing primitive only when its semantics and rendered behavior fit + without guessing. Do not force reuse that erases design facts. +- Preserve exact rendered values unless project evidence proves an equivalent + token, utility, or component. For `rem` output, convert with TemPad's actual + `cssUnit`, `rootFontSize`, and `scale`. +- Preserve intentional uncommon output, including pseudo-elements, filters, + masks, blend and backdrop effects, gradients, and non-default compositing, + unless a documented project constraint requires an adaptation. +- Implement only evidenced states and responsiveness. Do not invent hover, + loading, error, empty, disabled, or responsive behavior. +- Use native semantic elements and preserve keyboard access and accessible + names when an established primitive does not already provide them. +- Add no runtime or build dependency without user approval unless the user has + explicitly waived that constraint. +- Keep `data-hint-*` attributes out of shipped code. + +When TemPad returns relevant entries, load only the matching protocol: + +- assets: read [Assets](references/assets-and-tokens.md#assets) and follow the + project's asset delivery path; +- token references: read [Tokens](references/assets-and-tokens.md#tokens) and + follow the project's token workflow. + +Read both when both are present and skip both when neither is present. + +Do not enter a visual tuning loop. Change the implementation again only when +new project, design, tool, or verification evidence identifies a concrete +defect. + +### 5. Verify in the project's real workflow + +Run the narrowest relevant checks defined by project instructions and scripts. +Repair implementation failures and rerun the affected checks. Use an existing +preview, screenshot, or comparison workflow when available; do not invent a +universal verification matrix. + +If no runnable check exists, report the implementation as unverified. Do not +claim visual completion without a real project comparison path; ask the user +to confirm the rendered result against Figma. + +## Hard stops + +Stop instead of shipping when: + +- TemPad is unavailable, unauthorized, inactive on the intended file, or + cannot provide a trustworthy visible parent composition; +- the target is unreadable or not visible; +- project, design, and user evidence still conflict after targeted recovery; +- a missing decision would materially change behavior, structure, dependency, + asset delivery, or token mapping; +- required assets cannot be retrieved or stored under project policy. + +If blocked, give at most three concrete actions that would unblock the task. + +## Handoff + +Report: + +- what changed and where; +- only the relevant adaptation, inference, warning, asset/token handling, or + residual visual risk; +- checks run, their result, and what remains unverified. + +Keep absent concerns absent from the handoff. Do not produce a compliance +checklist for branches the task never used. + +## Decision example + +If TemPad emits `padding: 15px` and the project has a `space-4` token worth +`16px`, preserve `15px` unless project evidence explicitly makes the token the +intended mapping. Project consistency selects the representation; it does not +authorize changing the visible design. diff --git a/agent-plugin/src/skills/figma-design-to-code/agents/openai.yaml b/agent-plugin/src/skills/figma-design-to-code/agents/openai.yaml new file mode 100644 index 00000000..406fbf6e --- /dev/null +++ b/agent-plugin/src/skills/figma-design-to-code/agents/openai.yaml @@ -0,0 +1,7 @@ +interface: + display_name: 'Figma Design to Code' + short_description: 'Implement project-consistent UI code from Figma' + icon_small: './assets/icon.svg' + icon_large: './assets/icon.svg' + brand_color: '#0098FF' + default_prompt: 'Use $figma-design-to-code to implement the selected Figma design in the current project.' diff --git a/agent-plugin/src/skills/figma-design-to-code/references/assets-and-tokens.md b/agent-plugin/src/skills/figma-design-to-code/references/assets-and-tokens.md new file mode 100644 index 00000000..01dec4a6 --- /dev/null +++ b/agent-plugin/src/skills/figma-design-to-code/references/assets-and-tokens.md @@ -0,0 +1,47 @@ +# Translate assets and tokens + +Read this reference only when `get_code` returns `assets` or `tokens`. + +## Assets + +Follow the project's established asset and icon policy before TemPad delivery +details. + +- Download bytes only from a TemPad-provided `asset.url`. Never substitute a + public internet asset. +- Treat assets as files to store or reference, not text evidence to parse. +- If project policy forbids storing them, reference TemPad URLs only when the + user accepts the local-server dependency, and report it. +- Treat emitted `` markup as design truth for structure, + size, and instance color. Refactor delivery only through an existing project + SVG path. +- If upload falls back to inline SVG, preserve that markup rather than + resynthesizing the vector. +- `themeable: true` permits one contextual color channel, usually + `currentColor`; drive it through the established wrapper or icon convention. + Preserve internal palettes when `themeable` is absent. +- Do not invent a new SVG pipeline, multi-color props, or custom variables. + +If a required asset cannot be retrieved or represented under project policy, +stop rather than draw or substitute it from memory. + +## Tokens + +Preserve token usage when the target project can carry or map it safely. +Token facts may be direct values or mode-specific values keyed by +`Collection:Mode`; preserve aliases between variables when present. + +- Map to an existing project token only when value, reference behavior, + semantics, and relevant mode agree. A similar name is insufficient. +- Preserve TemPad token references through the project's normal token workflow + when that workflow can accept them. +- Add a token only when the project already defines how and this task calls for + it. +- If landing location, mode, or mapping remains ambiguous, use the exact + rendered value and report the fallback. +- Use hint metadata only while reasoning about a mode; never ship hint + attributes. + +When tokens and explicit rendered values disagree, do not silently choose. +Narrow the design evidence or ask the user which source expresses the intended +state. diff --git a/agent-plugin/src/skills/figma-design-to-code/references/recovery.md b/agent-plugin/src/skills/figma-design-to-code/references/recovery.md new file mode 100644 index 00000000..88cf1e89 --- /dev/null +++ b/agent-plugin/src/skills/figma-design-to-code/references/recovery.md @@ -0,0 +1,54 @@ +# Recover trustworthy design evidence + +Read this reference only when TemPad is unavailable, a `get_code` call warns +or fails, or the requested selection cannot fit in one trustworthy response. + +## Connection and target failures + +For a transient transport failure, retry once. Do not blind-retry invalid +selection, hidden node, wrong file, deterministic budget, or depth errors. + +If TemPad is unavailable or active on the wrong file, stop and ask the user to: + +1. enable MCP access in TemPad Dev **Preferences > Agent integration**; +2. keep the intended TemPad Dev and Figma tab active; +3. use the MCP badge in the panel to activate the intended file when multiple + Figma tabs are open. + +Do not edit code while design evidence is untrustworthy. + +## Incomplete `get_code` results + +Preserve the largest trustworthy parent composition and narrow only the +missing evidence: + +- **`depth-cap`**: keep the returned top-level composition, then use returned + `data-hint-id` values for targeted child `get_code` calls. +- **budget overflow or shell response**: keep the returned parent shell, then + fetch omitted children separately. Use the smallest parent that still proves + their shared layout. Plain string truncation is not evidence. +- **hierarchy, geometry, or overlap uncertainty**: call TemPad Dev's + `get_structure` only to resolve that uncertainty or select a narrower retry + target. + +Never rebuild a missing parent from child metadata. If no trustworthy parent +shell can be recovered, stop the full implementation and ask the user to +narrow the selection or choose the highest-priority subtree. + +If a budget error requires user action, report its consumption, limit, and +overage from the tool response. + +## Resolve contradictions + +Prefer the evidence source with authority over the disputed fact: project +evidence for implementation conventions, `get_code` for visible design, and +the user for product intent. Narrow the read once when the conflict may be a +scope problem. If the sources still disagree, stop rather than choose silently. + +## Worked example + +When a large frame returns a usable header-and-grid shell but omits three cards, +keep the shell as the parent layout, fetch only those card subtrees, and insert +them into the known grid. If the response contains cards but no trustworthy +grid shell, do not infer columns or spacing from `get_structure`; request a +narrower parent selection. diff --git a/agent-plugin/targets/claude/.claude-plugin/plugin.json b/agent-plugin/targets/claude/.claude-plugin/plugin.json new file mode 100644 index 00000000..2e7ebcd5 --- /dev/null +++ b/agent-plugin/targets/claude/.claude-plugin/plugin.json @@ -0,0 +1,24 @@ +{ + "name": "tempad-dev", + "version": "0.2.0", + "description": "Connect your coding agent to Figma. Create and edit native designs, inspect existing designs, and implement UI in your codebase.", + "author": { + "name": "TemPad Dev" + }, + "homepage": "https://github.com/ecomfe/tempad-dev#agent-integration", + "repository": "https://github.com/ecomfe/tempad-dev", + "license": "MIT", + "keywords": [ + "figma", + "mcp", + "skill", + "agent-integration", + "design-to-code", + "canvas-authoring", + "design-system", + "frontend" + ], + "skills": "./skills/", + "hooks": "./clients/claude/hooks.json", + "mcpServers": "./.mcp.json" +} diff --git a/agent-plugin/targets/claude/.mcp.json b/agent-plugin/targets/claude/.mcp.json new file mode 100644 index 00000000..3789c234 --- /dev/null +++ b/agent-plugin/targets/claude/.mcp.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "tempad-dev": { + "command": "npx", + "args": [ + "-y", + "@tempad-dev/mcp@latest" + ] + } + } +} diff --git a/agent-plugin/targets/claude/CHANGELOG.md b/agent-plugin/targets/claude/CHANGELOG.md new file mode 100644 index 00000000..1e9275fc --- /dev/null +++ b/agent-plugin/targets/claude/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +## 0.2.0 + +- Routed the `plugins` CLI through its own hook-free compatibility package and marketplace, + with installer discovery checks for both skills and MCP configuration. +- Added design-task lifecycle guidance and Stop/Done controls. Codex App uses MCP metadata and + native IPC without hooks; Claude uses installed lifecycle and Stop hooks. +- Documented native Codex App comments, Queue/Steer timing, and element-editor Save & Queue + shortcuts. Other clients retain task controls without comment delivery. + +- Added `figma-canvas-authoring` for creating and editing native Figma designs, alongside the + existing `figma-design-to-code` skill. +- Added progressive references for native authoring, fonts, images, icons, resource bindings, + and scoped editing. Direct, Reuse, and Author workflows keep resource decisions tied to the task. +- Grounded new compositions in inspectable evidence and required inspection of the rendered result + plus relevant native facts, with focused repair of observed defects. +- Made the portable Agent Plugins 1.0 bundle the shared source for installation, with synchronized + Codex and Claude compatibility manifests and refreshed icons. +- Paired the plugin with extension 0.21.0 and MCP 0.8.0 through `@tempad-dev/mcp@latest`. + The MCP server requires Node.js 22.x, 24.x, or 26+. diff --git a/agent-plugin/targets/claude/README.md b/agent-plugin/targets/claude/README.md new file mode 100644 index 00000000..3e7d6d69 --- /dev/null +++ b/agent-plugin/targets/claude/README.md @@ -0,0 +1,173 @@ +# TemPad Dev Agent Plugin + +[Simplified Chinese](./README.zh-Hans.md) + +Read, edit, and implement Figma designs through your coding agent or IDE. This plugin includes: + +- `figma-canvas-authoring`: create and revise native Figma designs, reusing accessible components, variables, and styles as needed. +- `figma-design-to-code`: use Figma design context to implement UI with your project’s components and conventions. +- The TemPad Dev MCP server configuration: connect to the Figma file open in your browser. + +Requires the TemPad Dev browser extension. Canvas editing also requires edit access to the Figma Design file. For manual inspection and output plugins, see the full [user guide](https://github.com/ecomfe/tempad-dev/blob/main/README.md). + +This plugin follows [Agent Plugins 1.0](https://agent-plugins.org/) and is published from one +source as a standard package, a compatibility package for the `plugins` CLI, and a package per +native host. Prefer native installation on Codex and Claude. Codex App binds tasks over MCP +metadata and native IPC, so its plugin registers no lifecycle hooks. + +## Cursor and VS Code installation + +For Cursor and VS Code, select the corresponding target: + +```bash +npx plugins add ecomfe/tempad-dev --target cursor +npx plugins add ecomfe/tempad-dev --target vscode +``` + +The installer reads `.plugin/marketplace.json` and installs the generated `plugins-cli` +compatibility package, which contains both skills and MCP configuration without lifecycle hooks. +This path is verified with `plugins@1.3.4`. Agent Plugins 1.0 consumers can use the separate +`agent-plugin/targets/standard` package; the current `plugins` CLI does not read that format. + +## Codex and Claude installation + +Use these native marketplace flows for Codex and Claude. Claude's lifecycle hooks require +the host's normal trust review; Codex does not register hooks. +The `--sparse` paths limit checkout to the host's marketplace and generated package, including +its skills and any required hooks. Codex repeats `--sparse` for each path; Claude accepts multiple +paths after one `--sparse`. The `plugins` CLI used for Cursor and VS Code has no equivalent flag. + +### Codex + +```bash +codex plugin marketplace add ecomfe/tempad-dev --ref main --sparse .agents --sparse agent-plugin/targets/codex +codex plugin add tempad-dev@tempad-dev +``` + +You can also install **TemPad Dev** from the Codex app plugin directory after adding the +marketplace. + +### Claude Code and Claude Desktop + +```bash +claude plugin marketplace add ecomfe/tempad-dev --sparse .claude-plugin agent-plugin/targets/claude +claude plugin install tempad-dev@tempad-dev +``` + +The plugin appears in Claude Desktop after the marketplace is added. + +For clients without Agent Plugin support, follow the direct MCP and standalone skill setup in the +[complete setup guide](https://github.com/ecomfe/tempad-dev/blob/main/README.md#agent-integration). + +## Usage + +Before using the integration, open TemPad Dev in Figma, then open **Preferences → Agent +integration** and enable **MCP access**. Canvas authoring is available while the active Figma +Design file is editable. + +## Upgrading + +The canvas-authoring release pairs Agent Plugin **0.2.0**, TemPad Dev extension **0.21.0**, and +MCP server **0.8.0**. Node.js **22.x, 24.x, or 26+** is required for the MCP server. + +1. Update the browser extension and reload the Figma tab. +2. Update the installed plugin through the client or installer used originally. With standalone + setup, update both `figma-design-to-code` and `figma-canvas-authoring`. +3. Keep the release MCP configuration on `@tempad-dev/mcp@latest`; replace any previous + `@alpha` or fixed alpha version. Reconnect the MCP client and start a new task so it loads the + updated tools and skills. If a stale Hub is reported, close tasks using the old MCP server + before reconnecting. +4. Open TemPad Dev, enable **MCP access**, and click the MCP badge in the intended Figma tab when + a session choice is needed. The badge selects the file receiving tool calls. + +## Packaging source of truth + +Everything is authored once under `agent-plugin/src/` and published by +`pnpm agent-plugin:build`. Every target is generated; never edit one. + +| Path | Role | +| ---------------------------------- | ------------------------------------------------- | +| `agent-plugin/src/plugin.json` | Standard manifest; owns all shared metadata | +| `agent-plugin/src/mcp.json` | Standard MCP configuration | +| `agent-plugin/src/skills/` | Both skills | +| `agent-plugin/src/clients/claude/` | Claude lifecycle hooks | +| `agent-plugin/src/clients/codex/` | Codex directory presentation (`interface.json`) | +| `agent-plugin/src/clients/shared/` | Hook transport shared by hosts | +| `agent-plugin/targets/standard` | Generated; also the standalone skills URL | +| `agent-plugin/targets/plugins-cli` | Generated compatibility package for `plugins` CLI | +| `agent-plugin/targets/codex` | Generated Codex marketplace package | +| `agent-plugin/targets/claude` | Generated Claude marketplace package | + +Each target carries only what its own installer reads. A standard consumer projects `plugin.json` +onto the host itself, so shipping a host layout beside it would create a second source of truth for +the same package; each host target likewise omits the standard manifests and the other host's +directory. Only Claude loads lifecycle hooks, so only `targets/claude` carries `clients/`. +The `plugins-cli` package carries `.plugin/plugin.json` and `.mcp.json`; its marketplace is +generated separately so the CLI does not select the Claude package. Verify discovery through +the actual CLI with `pnpm agent-plugin:check-installer` after changing packaging. + +## Task controls and client enhancements + +Design tasks can pause and resume across turns. Figma's canvas status bar shows the +source client, a Stop control, and a counted comment entry. Stop permanently cancels +the current task; subsequent design work explicitly begins a fresh task. Lifecycle pauses can resume +with a new lease epoch and require a fresh canvas read before writing. See the +[task and client design](https://github.com/ecomfe/tempad-dev/blob/main/docs/extension/mcp-design-tasks.md). + +The normal setup is the TemPad Dev extension configuration followed by this plugin's +installation. There are no control +addresses, environment variables, or helper services for users to configure. + +Codex App binds tasks from host-supplied MCP metadata and follows native conversation +state through the existing IPC connection. Claude retains lifecycle and Stop hooks. +Comments are delivered only through native conversation messages on compatible Codex App +hosts. TemPad Dev discovers the original conversation through the App's existing local +connection. Where supported, Queue submits the batch to the host's native queue, where it waits until the +conversation is ready. As soon as the host confirms admission, TemPad Dev clears the submitted +comments and markers, stops the sending indicator, and allows another batch. This confirmation +means the host received the comments, not that the agent finished the requested changes. +When native queue admission is unavailable, Queue waits in the Hub for existing queued +messages to clear and the conversation to accept a new response. The sending indicator +remains until that admission is confirmed. If queue state cannot be checked, comments +remain saved and delivery reports an error. Compatible hosts also support native server-queue +admission; these messages may appear in Codex after its next queue refresh. +Steer adds comments to an active response or starts a response when the conversation is idle. +Failed or uncertain delivery retains drafts; uncertain delivery is not automatically resent. +Comments never fall back to hooks. + +| Editor | Enter or click the submit button | Command/Ctrl+Enter or Command/Ctrl+click | +| --------------------------------- | -------------------------------- | ---------------------------------------- | +| Element comment | Save the comment without sending | Save & Queue the whole batch | +| General comment in the status bar | Queue the whole batch | Steer the whole batch | + +A batch includes all saved element comments and the general comment. Shift+Enter inserts a +newline in either editor. Saving an element comment alone does not send it. + +Claude, Codex CLI, and other clients currently provide task status and Stop/Done without +comment controls. Previously saved drafts remain in extension-local storage. + +Stop immediately blocks further writes from the current task and permanently cancels it +once an executing operation drains. The cancelled task cannot resume. The agent respects +Stop without automatically replacing it; necessary or user-requested design work can +explicitly begin a fresh task. No separate Figma unlock is needed. Codex App Stop also +requests native interruption of the exact bound turn; a delayed Stop cannot interrupt a +newer turn. Stop and Done also remove this task's comments that are still in the native queue, +leaving unrelated messages intact. Failed cleanup is retried after reconnection; already consumed +input cannot be recalled. Local cancellation remains effective if the host is unavailable. Claude +conveys Stop at the next hooked tool boundary. Native Codex delivery is enabled +only after the exact conversation owner reports support; no manual connection setup +is required. See the task and client design for the current validation scope. + +The native adapter uses Unix sockets on macOS/Linux and Codex's local named pipe on Windows. +macOS Steer and paused native queue admission/removal have been exercised against Codex App +26.908.70816. Automatic queue execution and the complete installed-plugin/Figma UI flow still +require live verification. Windows and Linux coverage is limited to source inspection and +automated tests; it does not establish complete host support. + +With a supported connection, select an element, save its feedback draft, then send the +numbered batch from the canvas status bar. Drafts can be edited or deleted and survive +navigation and closed tabs in extension-local storage, isolated by file, agent conversation, and task. +Successful delivery clears the submitted markers together; restoring drafts never sends them. + +The agent reports the result and its Figma link in the conversation, where users can +continue with follow-up requests. Task tools return text and structured data. diff --git a/agent-plugin/targets/claude/README.zh-Hans.md b/agent-plugin/targets/claude/README.zh-Hans.md new file mode 100644 index 00000000..bc5feda9 --- /dev/null +++ b/agent-plugin/targets/claude/README.zh-Hans.md @@ -0,0 +1,130 @@ +# TemPad Dev Agent Plugin + +[English](./README.md) + +在你的 coding agent 或 IDE 中读取、编辑和实现 Figma 设计。这个插件包含: + +- `figma-canvas-authoring`:创建和修改原生 Figma 设计,按任务需要复用可访问的组件、变量和样式。 +- `figma-design-to-code`:读取 Figma 设计信息,结合项目已有组件和约定实现 UI。 +- TemPad Dev MCP server 配置:连接浏览器中打开的 Figma 文件。 + +需要安装 TemPad Dev 浏览器扩展。画布编辑还需要 Figma Design 文件的编辑权限。手动检查设计和输出插件的完整说明见 [使用指南](https://github.com/ecomfe/tempad-dev/blob/main/README.zh-Hans.md)。 + +本插件遵循 [Agent Plugins 1.0](https://agent-plugins.org/),并从同一份内容源发布一个标准包 +(供自行适配该标准的客户端使用)、一个 `plugins` CLI 兼容包,以及每个原生宿主各一个包。Codex 与 Claude 请优先使用原生安装。 +Codex App 通过 MCP 元数据和原生 IPC 绑定任务,其插件不注册生命周期 hooks。 + +## Cursor 和 VS Code 安装 + +Cursor 和 VS Code 请指定对应的 target: + +```bash +npx plugins add ecomfe/tempad-dev --target cursor +npx plugins add ecomfe/tempad-dev --target vscode +``` + +安装器读取 `.plugin/marketplace.json`,安装生成的 `plugins-cli` 兼容包,其中包含两个 skill +和 MCP 配置,不包含生命周期 hooks。此路径已通过 `plugins@1.3.4` 验证。支持 Agent Plugins 1.0 +的客户端可使用独立的 `agent-plugin/targets/standard` 标准包;当前 `plugins` CLI 不读取该格式。 + +## Codex 和 Claude 安装 + +使用以下原生 marketplace 流程。Claude 提示时,请检查并信任插件的生命周期 hooks;Codex 不注册 hooks。 +`--sparse` 将检出范围限制为对应宿主的 marketplace 和生成包,包含所需的 skill 及 hooks。 +Codex 为每个路径重复指定 `--sparse`;Claude 在一个 `--sparse` 后接受多个路径。 +Cursor 和 VS Code 使用的 `plugins` CLI 没有对应参数。 + +### Codex + +```bash +codex plugin marketplace add ecomfe/tempad-dev --ref main --sparse .agents --sparse agent-plugin/targets/codex +codex plugin add tempad-dev@tempad-dev +``` + +添加 marketplace 后,也可以从 Codex 应用的插件目录安装 **TemPad Dev**。 + +### Claude Code 和 Claude Desktop + +```bash +claude plugin marketplace add ecomfe/tempad-dev --sparse .claude-plugin agent-plugin/targets/claude +claude plugin install tempad-dev@tempad-dev +``` + +添加 marketplace 后,该插件也会出现在 Claude Desktop 中。 + +不支持 Agent Plugin 的客户端,请按照 +[完整配置指南](https://github.com/ecomfe/tempad-dev/blob/main/README.zh-Hans.md#agent-集成)直接配置 MCP 并安装独立 skill。 + +## 使用 + +使用前,请在 Figma 中打开 TemPad Dev,然后进入 **Preferences → Agent integration** +并启用 **MCP access**。启用后,只要当前 Figma Design 文件可编辑,即可进行画布创作。 + +设计任务的状态栏显示 agent 状态、Stop/Done 和评论入口。Stop 会立即阻止当前任务继续写入, +在执行中的操作结束后永久取消该任务;重新连接也不会恢复它。后续设计工作需要明确开始新任务。 + +评论目前仅支持通过兼容 Codex App 的原生会话通道发送。Queue 将整批评论交给宿主的原生队列, +等待会话可以执行时再处理。宿主确认接收后,TemPad Dev 会清空本批评论和标记、停止发送指示, +并允许继续输入下一批;这表示已接收,不表示 agent 已完成修改。如果原生入队不可用, +Queue 会在 Hub 中等待已有排队消息清空、会话能接收新回复,此时发送指示会保留到确认接收。 +如果无法确认队列状态,会保留评论并报告发送错误。兼容宿主也支持原生服务端队列入队, +这些消息可能会在 Codex 下一次刷新队列时才显示。 +Steer 会将评论追加到正在执行的回复,空闲时直接开始新回复。投递失败或结果不确定时保留草稿, +结果不确定的评论不会自动重发,也不会回退到 hooks。 + +| 编辑位置 | Enter 或点击提交按钮 | Command/Ctrl+Enter 或 Command/Ctrl+点击 | +| ------------------ | -------------------- | ---------------------------------------- | +| 元素评论 | 保存当前评论,不发送 | Save & Queue:保存当前评论并排队整批评论 | +| 状态栏中的总体评论 | 排队整批评论 | 使用 Steer 发送整批评论 | + +整批评论包含全部已保存的元素评论和总体评论;两个编辑器中都可以用 Shift+Enter 换行。 +草稿按文件、会话和任务隔离,关闭标签页后仍保留,恢复草稿不会自动发送。 + +Codex App 的任务绑定和状态同步使用 MCP 元数据及原生 IPC,不依赖 hooks。Stop 还会请求中断 +对应的 Codex 回合,迟到的 Stop 不会中断较新的回合。Stop 和 Done 会移除当前任务尚未执行的 +原生队列评论,保留其它消息;清理失败后会在重新连接时重试,已被宿主取走的输入无法撤回。 +宿主不可用时,本地取消仍然生效。Claude 保留生命周期和 Stop 通知 hooks;Claude、Codex CLI +等尚未接入原生投递的客户端提供任务状态和 Stop/Done,但不显示评论入口,已有草稿不会删除。 + +原生适配器在 macOS/Linux 上使用 Unix socket,在 Windows 上使用 Codex 的本机 Named Pipe。 +已在 macOS Codex App 26.908.70816 上实测 Steer,以及暂停状态下的原生队列入队和移除。 +自动执行和完整的已安装插件/Figma UI 流程仍待实测;Windows/Linux 的证据限于源码检查和 +自动化测试,尚不能据此宣称完整宿主支持。 + +## 升级 + +本次画布创作版本应配套使用 Agent Plugin **0.2.0**、TemPad Dev 扩展 **0.21.0** 和 MCP +server **0.8.0**。MCP server 要求 Node.js **22.x、24.x 或 26+**。 + +1. 更新浏览器扩展,并重新加载 Figma 标签页。 +2. 通过原先使用的客户端或安装器更新 plugin。独立配置时,请同时更新 + `figma-design-to-code` 和 `figma-canvas-authoring`。 +3. 正式版 MCP 配置使用 `@tempad-dev/mcp@latest`;请替换旧的 `@alpha` 或固定 alpha 版本。 + 重新连接 MCP client 并新建任务,以加载更新后的工具和 skill。若提示 Hub 过期,请先关闭 + 使用旧 MCP server 的任务,再重新连接。 +4. 打开 TemPad Dev 并启用 **MCP access**;需要选择会话时,点击目标 Figma 标签页内的 MCP + badge。实际接收工具调用的文件由该 badge 选择。 + +## 封装内容源 + +所有内容只在 `agent-plugin/src/` 下编写一次,由 `pnpm agent-plugin:build` 生成各个产物。 +所有产物都是生成的,请勿直接编辑。 + +| 路径 | 作用 | +| ---------------------------------- | -------------------------------------- | +| `agent-plugin/src/plugin.json` | 标准清单,拥有全部公共 metadata | +| `agent-plugin/src/mcp.json` | 标准 MCP 配置 | +| `agent-plugin/src/skills/` | 两个 skill | +| `agent-plugin/src/clients/claude/` | Claude 生命周期 hooks | +| `agent-plugin/src/clients/codex/` | Codex 目录展示信息(`interface.json`) | +| `agent-plugin/src/clients/shared/` | 宿主共用的 hook 传输脚本 | +| `agent-plugin/targets/standard` | 生成产物,同时是独立 skills 的安装地址 | +| `agent-plugin/targets/plugins-cli` | 为 `plugins` CLI 生成的兼容包 | +| `agent-plugin/targets/codex` | 生成的 Codex marketplace 包 | +| `agent-plugin/targets/claude` | 生成的 Claude marketplace 包 | + +每个产物只携带自己的安装方式会读取的内容。标准客户端会自行把 `plugin.json` 适配到宿主, +因此在它旁边放置宿主清单会让同一个包出现第二个事实来源;两个宿主产物同理省略标准清单 +以及对方宿主的目录。只有 Claude 会加载生命周期 hooks,因此只有 `targets/claude` 携带 `clients/`。 +`plugins-cli` 包使用 `.plugin/plugin.json` 和 `.mcp.json`,由独立生成的 marketplace 入口路由, +避免 CLI 选中 Claude 包。修改封装后运行 `pnpm agent-plugin:check-installer`,验证实际 CLI 的发现结果。 diff --git a/agent-plugin/targets/claude/assets/icon-padded.svg b/agent-plugin/targets/claude/assets/icon-padded.svg new file mode 100644 index 00000000..2e8c6946 --- /dev/null +++ b/agent-plugin/targets/claude/assets/icon-padded.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/agent-plugin/targets/claude/assets/icon.png b/agent-plugin/targets/claude/assets/icon.png new file mode 100644 index 00000000..5d1f6bf2 Binary files /dev/null and b/agent-plugin/targets/claude/assets/icon.png differ diff --git a/agent-plugin/targets/claude/clients/claude/hooks.json b/agent-plugin/targets/claude/clients/claude/hooks.json new file mode 100644 index 00000000..9efe24ec --- /dev/null +++ b/agent-plugin/targets/claude/clients/claude/hooks.json @@ -0,0 +1,60 @@ +{ + "description": "Bind Figma tasks, collect user feedback at host lifecycle boundaries, and honor task Stop.", + "hooks": { + "Stop": [ + { + "hooks": [ + { + "type": "command", + "command": "node \"${CLAUDE_PLUGIN_ROOT}/clients/shared/lifecycle.mjs\" claude", + "timeout": 1 + } + ] + } + ], + "SessionEnd": [ + { + "hooks": [ + { + "type": "command", + "command": "node \"${CLAUDE_PLUGIN_ROOT}/clients/shared/lifecycle.mjs\" claude", + "timeout": 1 + } + ] + } + ], + "PostToolUse": [ + { + "hooks": [ + { + "type": "command", + "command": "node \"${CLAUDE_PLUGIN_ROOT}/clients/shared/lifecycle.mjs\" claude", + "timeout": 1 + } + ] + } + ], + "PreToolUse": [ + { + "hooks": [ + { + "type": "command", + "command": "node \"${CLAUDE_PLUGIN_ROOT}/clients/shared/lifecycle.mjs\" claude", + "timeout": 1 + } + ] + } + ], + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "node \"${CLAUDE_PLUGIN_ROOT}/clients/shared/lifecycle.mjs\" claude", + "timeout": 1 + } + ] + } + ] + } +} diff --git a/agent-plugin/targets/claude/clients/shared/lifecycle.mjs b/agent-plugin/targets/claude/clients/shared/lifecycle.mjs new file mode 100644 index 00000000..dcf0353b --- /dev/null +++ b/agent-plugin/targets/claude/clients/shared/lifecycle.mjs @@ -0,0 +1,123 @@ +// Installed hooks exchange lifecycle identity and Stop notices with the existing Hub. They never +// launch an agent, poll a model, change host trust, or unlock a stopped Figma file. +import { randomUUID } from 'node:crypto' +import { connect } from 'node:net' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import process from 'node:process' +import { clearTimeout, setTimeout } from 'node:timers' + +let socket +const deadline = setTimeout(() => process.exit(0), 750) +try { + let text = '' + for await (const chunk of process.stdin) { + text += String(chunk) + if (text.length > 1_000_000) process.exit(0) + } + const input = JSON.parse(text) + if (typeof input.session_id !== 'string' || input.agent_id || input.subagent_id) process.exit(0) + const event = input.hook_event_name + if ( + !['PreToolUse', 'PostToolUse', 'UserPromptSubmit', 'Stop', 'Interrupt', 'SessionEnd'].includes( + event + ) + ) + process.exit(0) + let taskId + if ( + event === 'PostToolUse' && + /tempad[-_]dev.*__(?:begin_design|resume_design)$/.test(input.tool_name || '') + ) { + const response = input.tool_response + if (!response?.isError) { + let result = response?.structuredContent || response?.result?.structuredContent || response + if (!result?.taskId && Array.isArray(response?.content)) { + const text = response.content.find((value) => value.type === 'text')?.text + if (text) { + try { + result = JSON.parse(text) + } catch { + /* This tool did not return a task. */ + } + } + } + if (typeof result?.taskId === 'string') taskId = result.taskId + } + } + const identity = { + version: 1, + kind: process.argv[2] === 'claude' ? 'claude' : 'codex', + sessionId: input.session_id + } + const runtimeDir = process.env.TEMPAD_MCP_RUNTIME_DIR || join(tmpdir(), 'tempad-dev', 'run') + const path = + process.platform === 'win32' ? '\\\\.\\pipe\\tempad-mcp' : join(runtimeDir, 'mcp.sock') + socket = connect(path) + const pending = new Map() + let sequence = 0 + let buffer = '' + socket.on('data', (data) => { + buffer += data.toString() + if (buffer.length > 1_000_000) { + socket.destroy() + return + } + let index + while ((index = buffer.indexOf('\n')) >= 0) { + const line = buffer.slice(0, index) + buffer = buffer.slice(index + 1) + let message + try { + message = JSON.parse(line) + } catch { + continue + } + const entry = pending.get(message.id) + if (!entry) continue + pending.delete(message.id) + if (message.error) entry.reject(new Error('The Hub does not support this hook request.')) + else entry.resolve(message.result) + } + }) + const disconnected = () => { + for (const entry of pending.values()) entry.reject(new Error('The Hub hook connection closed.')) + pending.clear() + } + socket.on('error', disconnected) + socket.on('close', disconnected) + await new Promise((resolve, reject) => { + socket.once('connect', resolve) + socket.once('error', reject) + }) + const request = (method, params) => + new Promise((resolve, reject) => { + const id = ++sequence + pending.set(id, { resolve, reject }) + socket.write(JSON.stringify({ jsonrpc: '2.0', id, method, params }) + '\n') + }) + const result = await request('tempad/client-hook', { + ...identity, + event, + invocationId: randomUUID(), + ...(taskId ? { taskId } : {}), + ...(typeof input.turn_id === 'string' ? { turnId: input.turn_id } : {}) + }) + // Old Hubs may still offer comment batches; never emit or acknowledge those. + if ( + !result?.receiptId && + result?.output?.hookSpecificOutput?.hookEventName === event && + typeof result.output.hookSpecificOutput.additionalContext === 'string' + ) { + await new Promise((resolve, reject) => { + process.stdout.write(JSON.stringify(result.output) + '\n', (error) => + error ? reject(error) : resolve() + ) + }) + } +} catch { + // Missing/old runtimes never prevent the host from continuing, pausing, or exiting. +} finally { + socket?.destroy() + clearTimeout(deadline) +} diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/SKILL.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/SKILL.md new file mode 100644 index 00000000..7732c78f --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/SKILL.md @@ -0,0 +1,183 @@ +--- +name: figma-canvas-authoring +description: >- + Create or update native, editable Figma designs with TemPad Dev MCP: screens, + flows, components, and requested local design-system resources, including on + an empty canvas. Use for Design in Figma work, not Figma-to-code, critique + without edits, or raw Plugin API automation. +--- + +# Design in Figma + +Deliver the smallest complete native Figma result that serves the user's +situation. Keep the working experience in view as you research, compose, and +repair. A successful tool call establishes a document change; the rendered +result and its editable structure establish whether that change served the task. + +## Establish the task + +Use the user's exact target and constraints. For an existing design, inspect +`get_code` and its pixels before changing the composition; use `get_structure` +for hierarchy, geometry, stable keys, or selected native facts. Write to a known +page directly. Create or activate a page only when the task calls for it. +Infer low-consequence gaps; ask when a missing decision would materially change +the result. Keep unrelated account, filesystem, task, and page metadata out of +product identity and content. + +Require an editable Figma Design file and the intended tab's active MCP +connection. Use the host's TemPad MCP tools for all canvas reads and writes. +If unavailable, report the integration problem and stop. Do not launch the CLI, +recreate its transport, use browser automation to set up the canvas, or emit raw +Plugin API operations. Research and asset acquisition use the host's appropriate +tools; website research uses the in-app browser when available unless the user +selected another browser. + +For new design work, call `begin_design` before research or canvas work with a short task title +and a fresh UUID `requestId`; reuse that UUID only to retry the same begin. Carry +the returned `taskId` on related TemPad tool calls. The runtime handles status and +placement feedback: do not report progress, send heartbeats, or choose coordinates +for a placeholder. Use `list_design_sessions` when the intended Figma target is +unclear, then pass its exact `sessionId` to `begin_design`. Pausing a turn preserves +the design task. Follow-up comments continue the same task, including after a completed +pass while its review remains open. After completion, pause, or lease expiry, use `resume_design` with its latest +`epoch`, carry the returned epoch as `taskEpoch`, and reread the affected canvas +with `get_structure` or `get_code` before writing. Use `get_design_task` only when +recovery needs the current state or epoch. Never replay a stale write. Stop in TemPad Dev +permanently cancels the current task after any running operation settles. Never resume +that cancelled task or automatically replace it. If further design work is necessary or +the user requests it, explicitly call `begin_design` with a fresh requestId. No separate +Figma unlock or new user turn is required. Done closes the review; a closed or replaced +task cannot resume. Do not automatically begin a replacement for comments on such a task. +Element feedback arrives as a numbered batch. Each item retains its file, page, +and node identity from draft creation. Reread every target before applying the +batch; do not substitute the current selection. +Supported hosts receive submitted feedback through native conversation messages. Do not poll for it or +set up a helper process or host control endpoint. + +Begin without waiting to choose a canvas location. Once an existing design region is +known, use `set_design_anchor` with its exact Frame node ID and `taskId`. Otherwise +the first created top-level Frame anchors automatically. The region stays stable +across reads and writes; call this tool again only to explicitly change design regions. + +## Ground and compose + +For net-new or materially redesigned interfaces without an established system, +read [style-grounding.md](references/style-grounding.md) and inspect relevant +real product screens or a permitted implementation before the first Canvas +write. The evidence must expose the interface relationships informing the new +work. Search snippets, URLs, failed retrievals, and generated concepts do not +establish a precedent. Subject imagery establishes its depicted content, not +its surrounding application's design. Try another permitted source when +retrieval fails; if none is inspectable, disclose the gap and stop. Supplied +source pixels or implementation can satisfy this boundary; mechanical edits do +not require unrelated research. + +Resolve what the person needs to recognize or change, which content and states +carry that work, and how the interface makes their consequences perceptible. +Choose the screen or flow, visual language, density, and scrolling model from +that situation. Use [visual-composition.md](references/visual-composition.md) +when forming or reconsidering a composition. Familiar structures and distinctive +ones both need a reason in the task. Research informs an independent solution; +it does not authorize copying a composition or placing reference pixels on the +canvas unless the user requested that treatment. + +When selecting or changing fonts, or when script coverage is uncertain, read +[typefaces.md](references/typefaces.md) to resolve candidates and native identities. + +Choose representations by their role in the work. Once an image, icon, diagram, +or visualization matters to the direction, read +[visual-assets.md](references/visual-assets.md) and its selected branch. Do not +silently replace the chosen content or medium to simplify sourcing or markup. +For content-bearing graphics, preserve meaningful marks and editable +relationships with native shapes, vectors, text, and groups; styled FRAME +lookalikes do not acquire drawing semantics. Read +[document-geometry.md](references/document-geometry.md) for that construction. +Ordinary UI panels, controls, backgrounds, and separators remain Canvas HTML. + +Choose resources from the task, not repetition alone: + +- **Direct:** default for a first net-new composition. Use primitives, literals, + and assets. Do not discover or create a design system just because shapes or + values repeat. +- **Reuse:** use [design-system-reuse.md](references/design-system-reuse.md) when + the user, selected source, or project evidence establishes the applicable + system. Catalog names, domain similarity, or mere file presence do not prove + relevance. +- **Author:** use [design-system-authoring.md](references/design-system-authoring.md) + when reusable resources are requested or established as part of the + deliverable. Prove the composition and one real consumer before propagation. + +For selected variables and typography styles, read +[resource-mapping.md](references/resource-mapping.md): define or discover their +identities once, then use variable utilities and text-style classes throughout +the markup. + +## Build, inspect, and repair + +For markup create or structural update, read +[canvas-html.md](references/canvas-html.md) and check its preflight before the +call. Canvas HTML is a strict native-state dialect; browser CSS assumptions do +not apply. Page-only and native-only operations omit markup. Load native +mechanics only for the capabilities selected below. + +Build a materially complete representative screen, then open its PNG before +expanding the flow or extracting resources. Judge whether the whole supports +the intended work. When it does not, focus on the particular relationship or +execution defect that explains the mismatch and repair it. A skeleton, resource +board, or generated concept does not establish the real composition. + +For updates, read [editing.md](references/editing.md). Preserve the requested +source, unrelated fields, and stable identities while updating every dependent +representation of the changed state. For larger results, split at meaningful +screen or section boundaries and carry shared roles coherently across them. + +Inspect every `apply_canvas` result, including warnings. Repair each observed +unintended defect or disclose why it remains. A local validation failure calls +for a local payload correction; it does not justify discarding a working root +or simplifying away the intended content. Open pixels again after the final +material write, covering every materially distinct screen. Verify native facts +with `get_structure` when identity, placement, editability, or representation +matters. Opened pixels prove visual access, not good judgment; a structural pass +proves only the conditions checked. + +Finish when the requested experience is coherent and observed defects are +repaired, accepted with reason, or disclosed. Report the delivered result and +material limitations, with a Figma link to the delivered nodes. A verified Direct +result is complete without an unsolicited component pass. + +Call `end_design` after the design outcome and its final verification are complete. +An optional short `summary` records the applied result in task history. +Use `outcome: "cancelled"` only when abandoning the design. Waiting for user input +or stopping a turn is a pause, not completion or cancellation. Host lifecycle hooks +handle pauses when available; do not create progress or heartbeat calls. + +## Native mechanics — load when selected + +Read the selected reference completely; do not preload the capability catalog. +Examples demonstrate syntax, not a design template. + +| Capability | Reference | +| --------------------------------------------------------------------- | ----------------------------------------------------------- | +| Exact updates, removal, or editor context | [editing.md](references/editing.md) | +| Pages, sections, groups, Booleans, masks, transforms, shapes, vectors | [document-geometry.md](references/document-geometry.md) | +| Paints, media, effects, shaders, grids, guides | [paints-effects.md](references/paints-effects.md) | +| Exact fonts, rich text, range styles, lists, hyperlinks | [rich-text.md](references/rich-text.md) | +| Components, variants, properties, Slots | [component-authoring.md](references/component-authoring.md) | +| Variables, collections, modes, bindings | [variables.md](references/variables.md) | +| CSS variable utilities and named text-style classes | [resource-mapping.md](references/resource-mapping.md) | +| Paint, Text, Effect, Grid styles | [local-styles.md](references/local-styles.md) | +| Authorized independent research, assets, inventory, or QA delegation | [delegation.md](references/delegation.md) | + +## Mutation boundaries + +Use returned IDs and stable keys as identity, never names. Create describes a +new complete root or exact new page. Update targets an exact node or page; +omissions preserve live state. `activate` always requires `page.id` or +`page.pageKey`, even when only changing selection. + +Never mutate outside scope, remove manual or unkeyed content, or remove a +component with surviving instances. An instance's definition-derived sublayers +are not authoring targets. Do not mutate remote resources, publish, detach or +reset instances, execute arbitrary JavaScript, or imitate an unresolved +resource. Use `null` only for supported links or managed resources the requested +change actually removes. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/agents/openai.yaml b/agent-plugin/targets/claude/skills/figma-canvas-authoring/agents/openai.yaml new file mode 100644 index 00000000..25e5075e --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/agents/openai.yaml @@ -0,0 +1,7 @@ +interface: + display_name: 'Design in Figma' + short_description: 'Create user-directed native Figma designs' + icon_small: './assets/icon.svg' + icon_large: './assets/icon.svg' + brand_color: '#0098FF' + default_prompt: 'Use $figma-canvas-authoring to create a native Figma design while following my resource constraints.' diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/assets/icon.svg b/agent-plugin/targets/claude/skills/figma-canvas-authoring/assets/icon.svg new file mode 100644 index 00000000..2e8c6946 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/assets/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/canvas-html.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/canvas-html.md new file mode 100644 index 00000000..2cc27632 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/canvas-html.md @@ -0,0 +1,277 @@ +# Canvas HTML and Tailwind subset + +Canvas HTML describes desired state, not browser rendering. Use its elements for +interface structure and genuine simple UI geometry, not as a drawing medium. +Do not assemble `div` or `span` primitives to imitate a photograph, +illustration, icon, logo, texture, or other content-bearing visual; acquire the +appropriate routed raster or vector asset instead. Classes do not cover every +Figma result: use routed native bindings for gradients, media, non-shadow +effects, masks, transforms, exact fonts, and rich text. + +One `apply_canvas` markup tree may contain at most 160 elements and 12 levels. +This is a safety ceiling, not a target. Before calling, count the tree, include +only assets referenced by that call, and split larger work at meaningful screen +or section boundaries. + +Prefer supported Tailwind utilities; use arbitrary pixels only off the default +scale. Numeric spacing follows Tailwind v4's `4px` unit. Selected Figma resources +can use CSS variable utilities and `type-*` text-style classes through +[resource-mapping.md](resource-mapping.md). Arbitrary project theme extensions, +variants, plugins, viewport-dependent utilities, and CSS cascade are unsupported. + +## Contents + +- [Preflight each markup tree](#preflight-each-markup-tree) +- [Elements and identity](#elements-and-identity) +- [Layout](#layout) +- [Appearance and text](#appearance-and-text) + +## Preflight each markup tree + +Immediately before each create or structural update, scan the complete supplied +tree once: + +- require a fixed width and height on the markup root; +- give every `div` with children `flex` or `grid`, or make every child absolute + with one edge per axis and fixed parent and child dimensions; +- keep flex, grid, gap, padding, border, corner, and box-shadow classes off + `span`; +- resolve defaults and overrides before assembling each class list. Both + `text-[16px] text-[18px]` and `text-black text-white` are conflicts, not + overrides. A helper must choose the final font size, color, and line height + instead of appending them to hard-coded defaults; +- trace every `w-full`, `h-full`, and `grow` against its direct parent's axis and + the element's required dimensions; +- give a fixed-height grid explicit row tracks when its children should fill or + divide that height; omitted rows remain content-sized; +- count at most 160 elements and 12 levels, and include only assets referenced by + this call. + +Correct the complete set before calling instead of serializing until validation +reveals issues one at a time. + +## Elements and identity + +- Use `div`, `span`, or a component tag returned by the active catalog. +- Give every element one unique `data-key` of letters, numbers, `. / : _ -`. +- Use `data-node-id` only in update mode to adopt an exact live node; instance + sublayers are not authoring targets. +- When markup is supplied, every `native` key must occur as a `data-key` in that + supplied tree; existence elsewhere in the live target does not satisfy this. + For mixed structural/native edits, include each bound node under its actual + parent path, or send the omitted nodes' changes in a separate native-only update. + When only native state changes, omit markup, target the exact managed root, + and key `native` by existing stable keys in that scope. This preserves topology; + masks and node removal still require structural markup. +- Use no arbitrary attributes on `div` or `span`. Common catalog links use + `data-var-="vN"` and `data-style-="sN"`; `"none"` explicitly + unlinks that field. +- A `span` contains only text and `
` or `
` line breaks. Use + `whitespace-pre-wrap` for literal newlines or repeated spaces. A plain `&` is + literal unless it forms a semicolon-terminated entity; supported entities + decode. Canvas typography does not inherit from a parent `div`: put font and + other text utilities on each `span`/TEXT node. Put flex/grid, gaps, padding, + borders, corners, and box shadows on a parent `div`. +- A component tag is childless, includes its returned `data-ref`, and accepts + returned props plus the shared class, identity, variable, and style + attributes. + +Variable attributes use kebab-case native field names: fill, stroke, characters, +visible, dimensions/bounds, gaps, four paddings/corners/stroke sides, radius, +stroke weight, opacity, and whole-node font/line-height/letter-spacing/paragraph +fields. Style attributes are `data-style-fill`, `data-style-stroke`, +`data-style-text`, `data-style-effect`, and `data-style-grid`. Node-type and +fallback rules still apply. + +Every primitive needs one width and one height. Supported fixed forms are: + +- default spacing: `w-N`, `h-N`, `size-N` (`N * 4px`), plus `w-px`, `h-px`, `size-px` +- default width containers: `w-3xs|2xs|xs|sm|md|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl` +- exact: `w-[Npx]`, `h-[Npx]`, `size-[Npx]` +- hug: `w-fit`, `h-fit` +- hug both axes: `size-fit` +- fill: `w-full`, `h-full`, or `size-full` for both axes +- bounds: numeric, `px`, or arbitrary-pixel values with `min-w`, `max-w`, `min-h`, or `max-h`; + width bounds also accept the default container names; use `min-w-none`, `max-w-none`, + `min-h-none`, or `max-h-none` to clear a bound in an update + +Text using `w-fit` also needs `h-fit`; prefer `size-fit`. Fixed-width `h-fit` +remains valid for wrapping text. + +Create and update markup roots require fixed width and height; fill, hug, and +grow are invalid even when the live target has a sized parent. + +Use `w-full` only on a `flex-col` cross axis, `h-full` only on a `flex-row` +cross axis, and `grow` on the main axis; `grow-0` clears growth. `grow` does not +replace required dimensions—for a row track use `grow w-fit h-[3px]`. Give +growing text in constrained rows a positive `min-w-*` to prevent collapse. +Prefer a hug main axis for content stacks whose extent is not behaviorally +fixed. Otherwise budget the fixed axis as padding + gaps + fixed/minimum child +extents. A non-overflowing result is still wrong when resolved content consumes +the intended inset; compare rendered child edges with the layout's padding. +Grid children may fill cells. Direct dimension variables require fixed +fallbacks. Fixed sizes must be at least `0.01px`; native lines use `h-[0px]`. + +## Layout + +Use Auto Layout for ordinary product UI. `flex` follows CSS's horizontal default; +use `flex-row` when that direction should be explicit and `flex-col` for a +vertical stack: + +- `flex`, `flex flex-row`, or `flex flex-col` +- `items-start|center|end|baseline` +- `justify-start|center|end|between` +- `flex-wrap`, `flex-nowrap`, `content-between`, `content-normal` +- `gap-N`, `gap-x-N`, `gap-y-N`, or exact `[Npx]` +- `p`, `px`, `py`, `pt`, `pr`, `pb`, `pl` with `-N`, `-px`, or `-[Npx]` +- `box-border`, `box-content` + +New Auto Layout frames include inside strokes by default (`box-border`); +`box-content` excludes them. Center/outside strokes never affect layout, and +each nested frame owns its setting. Fixed create sizes must cover opposing +padding plus included inside strokes. Figma determines `FILL` geometry and +border-box distribution. Derive exact descendant or instance sizes from the +rendered inner box, not nominal parent size; prefer valid cross-axis fill and +exceed the box only for intentional bleed or overlap. + +`managed-content-overflow` means managed Text or INSTANCE exceeds its direct +managed Frame or Component, or a native INSTANCE contains descendant content +beyond its own fixed root. Inspect edges, clipping, rendering, and instance +bounds; resize or realign accidental overflow and retain only intentional bleed, +crop, or overlap. Property-driven content outside an INSTANCE root is a broken +component contract rather than intentional consumer overflow. + +`justify-between` uses nonnegative native Auto gap and keeps one child at the +start. Use negative `figma.autoLayout.itemSpacing` only for intentional overlap. +Omitting box-sizing on update preserves the live setting. + +`hidden` and BOOLEAN visibility remove in-flow children, changing gaps, +positions, and hug bounds. To preserve geometry, keep a fixed slot and toggle +its inner child. `absolute left-[Npx] top-[Npx]` maps to Ignore Auto Layout for +true overlays; it needs fixed offsets, cannot fill/grow, and leaves surrounding +flow unchanged. Its text and Auto Layout descendants may still hug. + +For grid use: + +- `grid grid-cols-N` +- optional `grid-rows-N` +- custom tracks: `grid-cols-[1fr_240px_fit-content(100%)]` +- optional `grid-flow-row` or `grid-flow-none` +- child placement: `col-start-N`, `row-start-N`, `col-span-N`, `row-span-N` +- child alignment: `justify-self-auto|start|center|end`, + `self-auto|start|center|end` + +Give manual grid children both row and column starts or neither. Auto-flow uses +source order without explicit starts. A height-hugging grid cannot use flexible +or automatic rows; fix either its height or row tracks. Omitting `grid-rows-*` +creates native automatic content-sized rows; increasing only the container +height does not enlarge them. + +For a coherent board larger than one call, first create one fixed parent: + +```json +{ + "mode": "create", + "markup": "
" +} +``` + +Then append one bounded screen per update. Keep the root key and classes stable, +target its returned ID, and omit previously added children so they remain in +place: + +```json +{ + "mode": "update", + "targetNodeId": "FrameID:app-board", + "markup": "
" +} +``` + +For freeform composition, omit layout classes and give each child `absolute` +with exactly one horizontal edge (`left-*` or `right-*`) and one vertical edge +(`top-*` or `bottom-*`), including negative or exact values, or use a native +relative transform. Edge placement needs fixed parent and child sizing modes; +right/bottom offsets are resolved from live bounds after each markup apply. They +are placements, not reactive CSS anchors: use Auto Layout for alignment that +must follow later mode changes without another markup apply. A plain +non-flex/grid `div` is freeform even with one child; opt into layout for every +in-flow child. Absolute children cannot grow or fill; use `static` to return one +to Auto Layout on update. + +## Appearance and text + +Frame appearance: + +- `bg-transparent|white|black`, or an exact CSS hex value +- Linear backgrounds use `bg-linear-to-t|tr|r|br|b|bl|l|tl` with exact + `from-white|black|[#hex]`, optional `via-white|black|[#hex]`, and required + `to-white|black|[#hex]` stops. Stops are fixed at 0, optional 0.5, and 1; + `bg-gradient-to-*` is accepted as a legacy alias. Do not combine a gradient + with a solid background, direct fill paints, or a fill style/variable. +- `border`, `border-N`, `border-[Npx]`; use `border-x|y|t|r|b|l` with the same widths +- `border-white|black`, or an exact CSS hex value +- `rounded`, `rounded-none|xs|sm|md|lg|xl|2xl|3xl|4xl|full`, or `rounded-[Npx]`; + prefix the value with `t`, `r`, `b`, `l`, `tl`, `tr`, `br`, or `bl` for individual sides/corners +- `overflow-hidden`, `overflow-visible` +- A clipped rounded frame does not paint its inside stroke above children. A + filled child that reaches a curved edge can therefore square off or hide the + boundary even with `overflow-hidden`; inset it, give the touching child + corners a corresponding inner radius, or add a dedicated foreground + boundary, then inspect the rendered pixels. +- Exact pixel shadow lists through `shadow-[...]` or `inset-shadow-[...]`. + Each layer needs an explicit hex, `rgb()`, or `rgba()` color and two to four + pixel lengths; use underscores for spaces, for example + `shadow-[0_8px_24px_rgba(0,0,0,0.16)]`. +- `shadow-none` and `inset-shadow-none` clear their class-owned effect stack. + Theme-dependent named scales such as `shadow-md` are unsupported: use an + explicit native style or typed effect/variable binding for a reusable token, + or resolve the governing theme before applying and provide the exact value. + +Figma accepts shadow spread only on rectangles and ellipses, or on frames, +components, and instances with a visible fill and clipping enabled. + +A new border needs weight and paint, literal or bound. Updates may change either +independently; omission preserves the other. + +New frames are transparent when background is omitted, including frames added +during update. On an existing frame, omission preserves its live background; +use `bg-transparent` to clear it. Set an explicit background when fill is +intended. + +Shared appearance: + +- `opacity-N` (`N%`) or `opacity-[0..1]`, `hidden`, `visible` +- `rotate-N`, `-rotate-N`, `rotate-none`, or `rotate-[Ndeg]` +- `mix-blend-` with `pass-through`, `normal`, `darken`, `multiply`, + `plus-darker`, `color-burn`, `lighten`, `screen`, `plus-lighter`, + `color-dodge`, `overlay`, `soft-light`, `hard-light`, `difference`, + `exclusion`, `hue`, `saturation`, `color`, or `luminosity` + +Text: + +- `font-sans|serif|mono` resolve to an editor-available family in that category, + preferring Inter, Noto Serif, and Noto Sans Mono +- `font-thin|extralight|light|normal|medium|semibold|bold|extrabold|black` +- `text-xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl` with their default line + heights, `text-SIZE/N`, or `text-[Npx]` +- `leading-none|tight|snug|normal|relaxed|loose`, `leading-N`, `leading-[Npx]`, + `leading-[N%]`, or a unitless arbitrary ratio +- `tracking-tighter|tight|normal|wide|wider|widest`, `tracking-[Npx]`, + `tracking-[N%]`, or `tracking-[Nem]` +- `text-left|center|right|justify` +- `normal-case`, `uppercase`, `lowercase`, `capitalize` +- `no-underline`, `underline`, `line-through` +- `truncate`, `line-clamp-N`, `line-clamp-none` +- `text-white|black`, an exact CSS hex value, `whitespace-pre-wrap` +- `text-shadow-[...]` for an exact pixel text-shadow list with a color and two + or three pixel lengths; `text-shadow-none` clears it + +A `span` is one TEXT node, so `bg-*` and `text-*` share its fill channel. Put +background on a parent `div` and color on its child `span`. + +Shadow classes compile to the native effect stack; never combine them with +`figma.effects` or an Effect style on that node. + +Unknown elements, attributes, classes, CSS, responsive/state prefixes, custom +themes, margins, percentages, and plugins fail closed. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/component-authoring.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/component-authoring.md new file mode 100644 index 00000000..99573887 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/component-authoring.md @@ -0,0 +1,294 @@ +# Author reusable components + +Use this reference after selecting a reusable local component. It explains +representation, not library strategy. New local components need no +`get_design_system`; use catalogs only for discovery or normalized library +props, and exact returned IDs for newly authored components. + +## Shared-responsibility decision + +New local components are opt-in for net-new authoring. Use Author when the user +requested reusable components before delivery, accepted a component pass after +seeing the completed design, or applicable project evidence makes a local +component deliverable part of the task. Existing components may still be Reuse +without authoring new ones. Repeated appearance, repeated data, screen count, +possible future reuse, or tool availability do not opt the user into Author. + +Make the decision from real usages after the representative composition is +visually sound: + +1. Name the shared job and compare the intended consumers. +2. Identify stable anatomy and meaningful content, media, state, availability, + label, swap, or slot differences. +3. Choose Author only when a truthful supported contract provides more + coordination value than it costs to create, migrate, and verify. Otherwise + keep the responsibility Direct; a brief reason is enough. +4. Bound Author at the smallest subtree that owns the complete shared job. Do + not infer that a parent must become reusable because a nested label, icon, + status, or button is reusable. + +Do not inventory or rank every recurring family, and do not turn repetition +into a quota. Record only selected Author responsibilities and their concrete +consumers. Before propagation, create the smallest real definition, instantiate +it once, and verify the exact reference. Then replace the selected consumers +with native instances; never leave literal lookalikes for a responsibility that +was deliberately selected as Author. Use the exact returned `rootNodeId` or +`nodeIdsByKey` entry for every usage. + +A keyed primitive cannot become an INSTANCE in place. Update its bounded +ancestor, add the instance under a new key, and remove the old key in the same +call. + +Stop component authoring if the ID is missing, the instance fails, or the +definition is empty, default-sized, or loses +properties. Do not substitute primitives or claim completion. Continue only +independent Direct work, report the degraded component result, and remove a +temporary definition only when unused and safe. Re-read a corrupt definition +and its intended usage; never rebuild it in place or remove one with instances. +Recreate only when unused. If a diagnostic would systematize primitives that +this definition replaces, reconcile the component first; independent token work +does not need to wait. + +Before handoff, reconcile only selected Author responsibilities with actual +consumers. Each selected consumer must be a native INSTANCE. Inspect the most +demanding instance through its descendants; root type and size do not prove +wrapping, slots, media, or state content fit. +Revise the contract or boundary when real content breaks it. + +Markup-only updates preserve keyed components, sets, instances, and shapes. +Restate native bindings only when changing native state; new native nodes still +need declarations or component references. + +Copy a complete recipe and change its design facts. Do not infer TemPad's +component shape from raw Plugin API calls. + +## Contents + +- [Define the contract from real usages](#define-the-contract-from-real-usages) +- [Keep source definitions discoverable](#keep-source-definitions-discoverable) +- [Component and properties](#component-and-properties) +- [Consume an authored component directly](#consume-an-authored-component-directly) +- [Variant set](#variant-set) +- [Slots and instances](#slots-and-instances) + +## Define the contract from real usages + +Compare every intended usage. Separate stable anatomy from varying content, +state, or nested substitution; map differences to the smallest supported Text, +Boolean, Instance Swap, variant, Slot, or nested-composition mechanism. Treat a +field as invariant only when real usages agree. + +Size the contract from real extremes: test the longest wrapping text, widest +label, largest nested swap, and materially different slots. Compare descendant +bounds with the INSTANCE root; screenshots can still paint invalid overflow. +If content exceeds the root, enlarge the definition, add a truthful size +variant, or move the varying region outside a smaller stable boundary. +If consumer-specific media cannot be expressed by the available instance +contract, keep that media direct and componentize the stable surrounding +responsibility; never freeze one image into every instance to retain a larger +component boundary. + +When stable anatomy should evolve together, expressible state differences +support a shared contract. Keep it local only when divergence or contract cost +outweighs coordinated change. + +If the contract cannot express a meaningful difference, revise it or keep the +responsibility local. Never force usages to share placeholder content or an +accidental default merely because outer geometry repeats. + +Model each mutually exclusive categorical concern as one variant axis; do not +replace it with Booleans that allow impossible combinations. Reserve Booleans +for independently optional content or behavior. + +Expose one choice through both a variant and independent property only when real +usages vary them independently. Keep each source variant's visible state +truthful; instance overrides do not repair accidental source defaults. + +## Keep source definitions discoverable + +Keep main components and sets visible at natural bounds in a clearly named +source area separate from screens. Never hide, clip, make transparent, or +invisibly nest them. For several families, use a top-level SECTION with +`contentsHidden: false`, discoverable definition children, and content-sized +bounds. + +Keep each real definition once, without redundant specimens. Before handoff, +use `get_structure` to verify every definition is visible and every intended +consumer is an INSTANCE. Inspect distinct source variants at readable scale; +names, content, and styling must encode the same state. + +Keep the source area operational and visually subordinate: use the smallest +content-sized container that exposes the definitions, outside the consumer +board or screen sequence. Do not turn it into a branded artboard, mood board, +visual-thesis panel, token showcase, or documentation page unless the user asks +for that deliverable. Product screenshots and presentation framing should stay +focused on the requested experience. + +## Component and properties + +This complete call creates a component with TEXT and BOOLEAN properties and +connects both properties to its label layer. + +```json +{ + "mode": "create", + "markup": "
Continue
", + "native": { + "button": { + "figma": { + "name": "Button", + "component": { + "type": "COMPONENT", + "properties": { + "label": { + "type": "TEXT", + "name": "Label", + "defaultValue": "Continue" + }, + "show-label": { + "type": "BOOLEAN", + "name": "Show label", + "defaultValue": true + } + } + } + } + }, + "button/label": { + "figma": { + "componentPropertyReferences": { + "characters": "label", + "visible": "show-label" + } + } + } + } +} +``` + +Stable keys such as `label` connect definitions and sublayer references within +one result; they are not generated Figma property names. Supported property +types are `BOOLEAN`, `TEXT`, and `INSTANCE_SWAP`, linked through `visible`, +`characters`, and `mainComponent` respectively. + +BOOLEAN properties control visibility, not styling. Hidden in-flow children +leave Auto Layout. Use this only for intentionally optional content. To preserve +geometry, toggle an inner layer inside a fixed slot, use `absolute` for a true +overlay, or use geometry-equivalent variants for whole-state changes. + +Treat `layout-affecting-visibility-property` as a contract warning. Fix it when +geometry must stay stable. Accept intentional reflow only after comparing true +and false instances for bounds, sibling positions, baselines, and clipping; one +default-state screenshot is insufficient. + +## Consume an authored component directly + +Use the exact ID returned by `apply_canvas`. For TemPad-authored components, +`componentProperties` accepts their stable definition keys. This follow-up +needs no catalog: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "screen/action": { + "component": { "id": "ComponentID:created-button" }, + "componentProperties": { "label": "Save", "show-label": true } + } + } +} +``` + +Replace the illustrative ID with the returned ID. Never invent IDs or use this +shortcut for unidentified library components. + +## Variant set + +This call creates two components in one variant set. Every direct child of a new +set must be an authored component; names encode axes as `Property=Value`. + +```json +{ + "mode": "create", + "markup": "
Continue
Continue
", + "native": { + "button-set": { + "figma": { + "name": "Button", + "component": { "type": "COMPONENT_SET" } + } + }, + "button/default": { + "figma": { + "name": "State=Default", + "component": { "type": "COMPONENT" } + } + }, + "button/hover": { + "figma": { + "name": "State=Hover", + "component": { "type": "COMPONENT" } + } + } + } +} +``` + +Consume the returned set ID and select siblings through variant properties. If +the call returns the set as `rootNodeId`, this creates Default and Hover: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "screen/default": { + "component": { "id": "ComponentSetID:created-button-set" } + }, + "screen/hover": { + "component": { "id": "ComponentSetID:created-button-set" }, + "componentProperties": { "State": "Hover" } + } + } +} +``` + +Replace the ID with returned `rootNodeId`. The set ID creates its default; +`componentProperties` selects another encoded variant. An exact child ID from +`nodeIdsByKey` may instantiate that variant directly. + +Use `descriptionMarkdown` and `documentationLink` only for real guidance, inside +`figma.component` beside `type` and `properties`: + +```json +{ + "figma": { + "name": "Button", + "component": { + "type": "COMPONENT", + "descriptionMarkdown": "Primary action" + } + } +} +``` + +Define shared properties on the component set rather than on one variant. + +## Slots and instances + +Use `figma.slot` only for an intentional flexible nested-content API. New slots +must be inside local authored components and include `property.name`; markup +children become defaults. Optional settings control stretching, empty display, +child limits, and preferred values. + +An `INSTANCE_SWAP` default uses exact live component/set ID `{ "id": "..." }` +or importable library key `{ "key": "..." }`. Preferred values require +`{ "type": "COMPONENT" | "COMPONENT_SET", "key": "..." }` and accept neither +live IDs nor catalog refs. Resolve catalog identity before authoring and never +invent it. Put advanced state under `figma.instance`; omission preserves normal +override behavior. + +Never edit a remote component, nest a main component inside another main +component, delete a component with surviving instances, or create properties +and variants that the requested component API does not need. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/delegation.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/delegation.md new file mode 100644 index 00000000..181b7cc9 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/delegation.md @@ -0,0 +1,82 @@ +# Delegate bounded evidence work + +Delegate evidence gathering or isolated production, never focal judgment. The +main agent synthesizes results and remains the only Canvas writer. + +## Pass the delegation gate + +Delegate only work that is: + +1. **Separable:** has a stable objective independent of evolving design choices. +2. **Compressible:** needs only a compact task-local brief. +3. **Isolated:** is read-only or produces an isolated artifact without mutating + Figma, design-system state, or another agent's files. +4. **Verifiable:** returns citations, importable asset references, exact facts, + or a bounded defect list the main agent can inspect. +5. **Worth coordinating:** gains enough from parallelism, specialist capability, + or independent review to justify handoff and synthesis. + +Keep work local if any condition fails. Do not delegate for ritual, convenience, +or another unsupported aesthetic opinion. + +## Write a complete handoff + +Give each worker one objective and its relevance, only required task evidence +and constraints, permitted tools and sources, explicit exclusions including no +Canvas writes, and an exact output contract and stop condition. The main agent +must read required Canvas references and set safety boundaries; never delegate +interpretation of this skill. Prefer fresh or minimum-context workers, pass +source evidence rather than conclusions, and avoid overlapping assignments. + +## Suitable tracks + +### Research scout + +After framing the design problem, delegate a bounded evidence question. Return: + +```txt +open decision; exact source; applicable finding; relevance; authority boundary +``` + +The scout does not choose direction. Combine questions only when their search +space is shared; use multiple scouts only for independent spaces. + +### Asset scout + +After fixing asset requirements and import contract, return one importable +`imageUrl` or `assetHash` per asset plus MIME type, dimensions, provenance, and +factual description. Return no bytes, rejected candidates, or transcript. The +main agent owns selection and integration. + +### Independent QA scout + +After a representative composition exists, provide a fresh worker its +screenshot and frozen brief without creator rationale or suspected defects. Ask +for at most eight observations: + +```txt +severity; screen/node or region; observed defect; visible evidence; violated constraint +``` + +The scout neither edits nor declares completion; the main agent checks findings +against the live canvas. + +### Inventory scout + +Use read-only inventory when independent volume warrants it, such as several +screens or icon candidates. Require exact findings and references, not a design +proposal. + +## Orchestrate conservatively + +- Default to one worker; use at most two concurrent non-overlapping workers. +- Keep a faster local critical path with the main agent. +- Only the main agent resolves intent and conflicts, chooses direction, calls + `apply_canvas`, and accepts the result. +- Resolve conflicts from evidence, not voting; discard unverifiable or + out-of-scope claims and stop when evidence is sufficient. + +Never delegate interdependent page or component construction, component +authoring plus instance placement, concurrent updates to one root, final +composition, or final acceptance. These require one ordered mutation stream and +continuous awareness of the whole. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/design-system-authoring.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/design-system-authoring.md new file mode 100644 index 00000000..45825de5 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/design-system-authoring.md @@ -0,0 +1,87 @@ +# Implement a selected local design system + +Use this reference only when the user or resolved plan requires new local +components, variables, or styles. It translates that plan into native resources +and verifies delivery; it does not choose component strategy, visual language, +resource inventory, or token taxonomy. + +## Establish the implementation contract + +Before writing, identify each selected resource, responsibility, concrete +consumer, meaningful variation, and exclusion. Resolve any open material +boundary first. For components, use the gate in +[component-authoring.md](component-authoring.md); screen count, one-screen scope, +and visual similarity alone neither establish nor exclude a component. + +Keep a private reconciliation map: + +```txt +selected resource -> native representation -> intended consumers +``` + +A resource is complete only when its native definition or binding exists and +every intended consumer uses it. Equivalent primitives or literals are not +coverage. + +## Translate the plan + +Use this loop: + +1. Stabilize one representative composition. +2. Author only selected resources with known consumers. +3. Exercise each contract in that composition. +4. Propagate native instances and bindings to all intended consumers. +5. Reconcile the final artifact with the map. + +Preserve the decided semantics: + +- A variable carries a semantic value consumers must bind and evolve together; + name it by role, not literal. +- A local style carries a reusable paint, text, effect, or grid definition. Do + not duplicate one decision across resource types unless required. +- A component carries a reusable responsibility. Define stable anatomy and + expose only variations required by real usages. + +Use [resource-mapping.md](resource-mapping.md) to map selected variable and text +style identities once per apply, then consume them through familiar variable +utilities and `type-*` classes. A new resource and its first consumer can share +one call. Query available fonts independently through `get_design_system` with +`scope: "fonts"`; selecting a family does not require discovering a file system. + +Consume a component through a childless instance placeholder without layout or +appearance classes. Do not make a repeated shell or wrapping top-level subtree +a component unless every consumer can use that placeholder through supported +properties. Slots do not permit markup children on instance placeholders; keep +incompatible wrappers as ordinary structure around a compatible inner boundary. + +Map each real component difference to the smallest supported mechanism: Text, +Boolean, Instance Swap, variant, Slot, or nested composition. Use one variant +axis per mutually exclusive categorical concern and Booleans only for +independently optional concerns. Do not encode arbitrary content as variants, +generate unused combinations, or freeze varying content as invariant. + +If supported native mechanisms cannot express a real usage, do not weaken or +redesign it silently. Choose another valid boundary or report the limitation. + +Read [variables.md](variables.md), [local-styles.md](local-styles.md), or +[component-authoring.md](component-authoring.md) only for selected resource +types. + +## Verify the native handoff + +Verify through representative consumers, not definitions alone: inspect native +bindings, Auto Layout, text resizing, property behavior, and every material +state. Raw literals and primitive lookalikes do not demonstrate system usage. + +For components, verify visible inspectable definitions and native INSTANCE +consumers using [component-authoring.md](component-authoring.md). For variables +and styles, inspect live bindings rather than apply input or equal values. + +Resolve warnings through real consumers, or remove a resource only when the +resolved plan no longer includes it. Tool friction, payload size, or an easy +resource type does not alter the plan. Do not create swatches, specimens, +definition panels, or redundant examples solely for verification; add +documentation only when requested. + +Finish when selected resources support all requested usages and the live Figma +structure reconciles with the map. Do not expand for imagined future needs. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/design-system-reuse.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/design-system-reuse.md new file mode 100644 index 00000000..11cf574f --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/design-system-reuse.md @@ -0,0 +1,59 @@ +# Reuse an existing design system + +Use this reference only when reuse is allowed and relevant. If the user rejects +a design system, use Direct. + +## Discover definitions + +Call `get_design_system` without arguments. Its immutable deterministic catalog +contains: + +- a `catalogId` scoping all short refs; +- component tags, props, source pages, and native sizes; +- variables, collections, modes, styles, and shaders as refs such as `v1`, + `k1`, `m1_2`, `s1`, and `h1`; +- `cssName` on variables and `className` on text styles for direct use in markup; +- `omitted` and `nextCursor` when more definitions remain. + +The catalog neither scans usage nor loads pages or ranks resources. Select from +returned names, pages, summaries, props, types, scopes, and defaults. Continue a +cursor or inspect an exact ref only until evidence is sufficient. + +Prefer, in order: catalog component, supported component prop, matching native +style, semantic variable, then primitive or literal for a real gap. + +When variants, anatomy, layout, or semantic meaning affect the result, inspect +the exact `ref` with the same `catalogId`. Use its `previewNodeId` with +`get_screenshot` only when appearance affects selection. Read an existing +composition with `get_code` or `get_screenshot`; catalogs do not reveal usage +conventions. Never invent refs, IDs, keys, props, or variant values. + +## Apply catalog resources + +Component tags are childless, include returned `data-ref`, and use exact props. +Omit size classes to preserve native size. Use returned CSS variable names and +text-style classes through [resource-mapping.md](resource-mapping.md). For other +native fields, bind `data-var-="vN"` or `data-style-="sN"`; put +collection modes or strict native links under `native[data-key]`. + +Replace every illustrative ref in this contract with one from the active +catalog: + +```json +{ + "mode": "create", + "catalogId": "ds_example", + "markup": "
Team settings
", + "theme": { "textStyles": { "type-body": { "ref": "s1" } } }, + "native": { + "settings": { + "variableModes": { "k1": "m1_1" } + } + } +} +``` + +If a mandatory component is absent, ask the user to open its definition page; +otherwise use the normal primitive fallback. An empty canvas does not block +catalog reuse. When reuse is unavailable, create a small coherent primitive +draft—never a token or component library solely for one screen. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/document-geometry.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/document-geometry.md new file mode 100644 index 00000000..1f24c0d6 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/document-geometry.md @@ -0,0 +1,124 @@ +# Document and native geometry + +Use `native[key].figma` only for state HTML and classes cannot express honestly; +it remains declarative desired state. + +## Contents + +- [Pages and containers](#pages-and-containers) +- [Shapes and vectors](#shapes-and-vectors) +- [Transforms, masks, and native state](#transforms-masks-and-native-state) + +## Pages and containers + +Top-level `page` can set a name, exact zero-based document index, solid RGBA +background, ordered guides, and explicit variable modes. Page-only create uses +a new `pageKey` plus name. Page-only update uses +an exact `id` or `pageKey` and omits markup. A create root may target an existing +or new page directly; creating pages and writing nodes preserve the user's current +page and viewport. Do not activate a page merely to write there. +Markup updates stay on the target node's page. + +Use top-level `mode: "activate"` with exact page identity when editor context or +selection matters; `selection: []` clears selection. Use top-level `mode: +"remove"` with an owned `pageKey` to delete a page. Page deletion rejects the +last page, manual or unowned content, and surviving external dependencies. + +Use: + +- `figma.section: { contentsHidden? }` for canvas organization; +- `figma.group: true` for an intrinsic group; +- `figma.booleanOperation: "UNION" | "SUBTRACT" | "INTERSECT" | "EXCLUDE"` + for non-destructive geometry. + +Sections can be canvas roots or direct children of sections; a frame cannot +contain a section. Sections require fixed pixel dimensions and freeform +children. Groups and Booleans use `w-fit h-fit` with freeform children. A new +group needs one child and a Boolean needs two. When updating an intrinsic +container's children, +describe every live direct child because order is semantic. + +Sections have no frame clipping, so omit `overflow-hidden` and +`overflow-visible`. When `targetNodeId` is an existing section, retain +`figma.section` on the root or the frame-typed markup root is rejected. + +## Shapes and vectors + +Use a childless `div` with `figma.shape`: + +- `{ "type": "RECTANGLE" }` +- `{ "type": "LINE" }` +- `{ "type": "ELLIPSE", "arc": { "startAngle", "endAngle", "innerRadius" } }` +- `{ "type": "POLYGON", "pointCount": 3 }` +- `{ "type": "STAR", "pointCount": 5, "innerRadius": 0.5 }` +- `{ "type": "VECTOR", "paths": [...] }` +- `{ "type": "VECTOR", "network": {...}, "handleMirroring": "..." }` + +Use exact uppercase `M L Q C Z` paths for already-decided custom vector +geometry. Selected icon roles use sourced SVG through [icons.md](icons.md), not +remembered paths. Use a vector network only for branching segments, per-vertex +state, or region-specific fills or styles. Never provide both. New vectors need +geometry; omission preserves it on update and an empty path or network clears +it. + +Each path item is an object. `windingRule` is `"NONE"`, `"NONZERO"`, or +`"EVENODD"`; use `"NONE"` for an open stroked path. Path data uses +whitespace-separated uppercase commands and numbers. + +Figma normalizes path geometry to tight bounds before applying markup size. The +childless `div` defines final bounds, not a preserved viewport. For alignment, +offset it by the path's minimum x/y and size it to the x/y spans; otherwise a +partial-range path stretches to the box. Verify rendered anchors because +`get_structure` returns node bounds, not path coordinates. + +This Direct recipe creates an editable branch curve: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "branch": { + "figma": { + "name": "Branch", + "shape": { + "type": "VECTOR", + "paths": [ + { + "windingRule": "NONE", + "data": "M 14 300 C 30 252 52 188 104 20" + } + ] + }, + "fills": [], + "strokes": [{ "type": "SOLID", "color": { "r": 0.447, "g": 0.314, "b": 0.231 } }], + "stroke": { "weight": 2, "cap": "ROUND", "join": "ROUND" } + } + } + } +} +``` + +## Transforms, masks, and native state + +- `figma.name` sets the display name; `data-key` remains identity. +- `locked` and `aspectRatioLocked` set interaction state. +- `relativeTransform` is a complete native 2×3 unit-axis transform; width and + height carry scale. Do not combine it with `rotate-*`. On create roots, TemPad + preserves rotation and skew but replaces translation with automatic placement. +- `stroke` carries weights, alignment, caps, joins, miter, and `dashPattern`. +- `corners` carries radii and smoothing. +- `mask` is `"ALPHA"`, `"VECTOR"`, `"LUMINANCE"`, or `null`. + +Place a mask before masked siblings inside one dedicated frame and describe all +direct siblings on update. A non-null mask needs a following sibling. Omission +preserves mask state; `null` disables it. + +After changing a mask, layout grid, or frame guide, call `get_structure` with +`options.native: true` on the smallest relevant root. Verify `native.mask` and +sibling order, or returned `native.layoutGrids` and `native.guides`; desired +bindings alone are insufficient. + +Use `{ "ref": "…" }` for catalog resources nested in native state and +`sourceCanvasKey` or `{ "canvasKey": "…" }` for same-result forward node +references. Never insert raw Plugin API calls. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/editing.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/editing.md new file mode 100644 index 00000000..f8653bd5 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/editing.md @@ -0,0 +1,44 @@ +# Edit an existing result + +Use this reference for an update, removal, or change of editor context. Read the +exact target and recover managed keys from structured tool results when prior +call context is unavailable. Names are labels, not identity. + +## Describe the desired change + +Trace the requested change through its visible dependents: a changed selection +may affect the working surface, label, enabled action, and summary. Preserve +unrelated content and relationships. Preserving the source does not mean +retaining stale representations of its previous state. + +Use the smallest owning target that can express the complete change: + +- For native state on existing keys, target the exact managed root and send only + `native`; omit markup to preserve topology. +- For structural changes, read `canvas-html.md`, keep `data-key` stable, and + include the affected structure. Omitted existing fields and keyed elements + retain their live state; omission is not deletion. +- `removeKeys` removes owned descendants. Top-level `mode: "remove"` removes an + exact managed root or page. Do not remove manual/unkeyed content, unmanaged + resources, or surviving external consumers. +- `mode: "activate"` requires `page.id` or `page.pageKey`, even for a + selection-only change. It changes editor context, not document state. An + exact off-current-page write does not require activation. + +Respect instance boundaries. Change an instance root or its authorized +component definition, never a definition-derived sublayer. Select only the +native references needed for the intended change. + +## Recover locally + +Read the entire mutation result. For a rejected payload, correct all reported +issues together without changing the design to fit the error. A verification +failure is rolled back by TemPad; do not assume a partial successful edit. +For an unknown transport outcome, read the exact target before retrying a create +or removal so an uncertain response does not become a duplicate mutation. + +Repair warnings where they occur. Replace a whole root only when an observed +structural defect requires it and the complete intended content can be +preserved. Reopen the affected composition after its last material write and +inspect its dependents; read back protected native facts when preservation +matters. Do not expand a local correction into an unrelated restyle. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/icons.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/icons.md new file mode 100644 index 00000000..b3457638 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/icons.md @@ -0,0 +1,65 @@ +# Deliver icons + +Use this reference only after the composition selects an icon role. It does not +require icons, set an icon count, or choose a family or visual style. + +Prefer permitted current-file, catalog, project, or user sources; otherwise use +a trustworthy brief-compatible source and record material license constraints. +When inspected evidence establishes a family or geometry, use that permitted +source or a compatible one. A general library is a fallback only when its +stroke or fill, optical weight, corners, negative space, and platform semantics +remain coherent. Do not diversify sources by quota. + +Import exact SVG geometry. Never redraw a known icon from memory or replace an +icon role with Unicode, emoji, TEXT, or assembled primitives. A character, +shape, or cluster that communicates an affordance, object, or semantic category +is an icon role even when beside a worded label. Before markup, scan literal +text for pictographic Unicode, emoji, and symbols and route each qualifying mark +to a permitted vector source. Simple geometry remains valid only when it is +itself the intended status or data mark, divider, decoration, or brand shape. + +Search results and snippets identify external candidates only; they establish +neither geometry nor license. Open the governing license once and fetch or open +every exact SVG used before markup. If either remains uninspected, omit an +optional icon or report a required gap instead of inventing one. + +For Direct delivery, give the icon a childless `div` whose classes supply the +decided wrapper bounds. Declare the inspected SVG document in +`assets[assetKey]` with `type: "SVG"`, then set +`native[nodeKey].figma.svg.assetKey` to that alias. An optional `color` resolves +`currentColor`; omit it for explicit-color SVGs. Figma may import a Frame with +Vector children; treat that subtree as one opaque asset and never flatten or +reconcile it. + +This complete Direct recipe demonstrates the required shape, not a design +default; its identifiers and values stand in for the already-decided role and +inspected source: + +```json +{ + "mode": "create", + "markup": "
", + "assets": { + "search": { + "type": "SVG", + "svg": "" + } + }, + "native": { + "search-icon": { + "figma": { "svg": { "assetKey": "search", "color": "#334155" } } + } + } +} +``` + +Omit `color` when it is not part of the selected source. A markup-only call +cannot deliver the SVG geometry. Once an icon source has been selected and +inspected, do not replace it with text or primitives merely to avoid the +`assets` and `native` mapping. + +For larger exact SVG, declare a Hub asset using a full lowercase SHA-256: + +```json +{ "type": "SVG", "assetHash": "" } +``` diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/images.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/images.md new file mode 100644 index 00000000..b019a960 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/images.md @@ -0,0 +1,120 @@ +# Deliver images and illustrations + +Use this reference only after the composition selects an image or illustration +role and the common boundaries in [visual-assets.md](visual-assets.md) establish +its subject and medium. + +Treat existing assets, rights-established remote sources, generation, and +purpose-built vectors as acquisition routes. Choose the nearest route that +satisfies content, fidelity, rights, quality, and import requirements; tools +have no global priority. Before importing a remote asset, establish its +applicable usage rights and a recoverable source. A search result, accessible +URL, CDN host, or lack of a watermark does not establish permission. Confirm +Canvas delivery before layout depends on the asset. + +When depiction is part of a record, keep it. Text, category icons, generic +placeholders, and numbered markers may index the record but cannot replace its +visual content. Source or generate an established raster role, preserve exact +vector art when vector is the real medium, or disclose the gap. + +Keep only enough trace to recover material choices, the remote source and its +applicable terms, or content distinctions. Combine role, evidence, medium, +source, rights, and import treatment in one short rationale when needed; do not +create a per-asset ceremony. Record exact creator, license, or attribution only +when the applicable terms, policy, or handoff requires it; assets sharing one +route and terms may share a trace. + +When medium is unspecified, use nearest visual evidence or ask if the choice is +material; otherwise state a low-consequence assumption. + +Use generation when the decided role needs a bespoke or fictional subject, +identity, composition, or treatment. In a prototype, a coherent generated set +may be the nearest truthful source for distinct fictional records; do not +require stock search merely because each subject is ordinary. For a real named +subject or supplied identity, use the supplied or rights-established source and +do not generate a substitute. Before generation, map each planned asset to the +subject and consumer it serves; skip ceremony that does not protect fidelity, +rights, or import. + +Compose generation and Hub import in one programmatic execution so image bytes +never enter prose or expire between calls: pass the generator's `data:` URL +directly to TemPad's `upload_asset`, read its returned `assetHash`, then declare +that hash as an IMAGE asset in `apply_canvas`. Do not regenerate an unchanged +prompt only to recover an importable URL. If generation or `upload_asset` is +unavailable, choose a rights-established public image source only when it +preserves the intended medium; otherwise disclose the required gap. Never +generate first and silently switch medium because import failed. + +Use `imageUrl` for a rights-established public IMAGE paint or same-file +`imageHash` for an existing image. For generated or other local Hub content, +declare the returned full lowercase SHA-256, then use its alias in a basic fill: + +```json +{ + "assets": { "image": { "type": "IMAGE", "assetHash": "" } }, + "native": { + "image-node": { + "figma": { + "fills": [{ "type": "IMAGE", "assetKey": "image", "scaleMode": "FILL" }] + } + } + } +} +``` + +Inline bytes and local paths are unsupported. Remote URLs must resolve directly +to accessible images, not pages or thumbnails. + +When a supplied canvas image is itself a permitted source artifact and an exact +visible subregion must carry into the result, reuse its same-file `imageHash` +instead of redrawing that content. For an axis-aligned source rectangle +`(x, y, width, height)` within an image of size `(imageWidth, imageHeight)`, and +a destination with the same aspect ratio, declare: + +```js +{ + type: "IMAGE", + imageHash: "", + scaleMode: "CROP", + imageTransform: [ + [width / imageWidth, 0, x / imageWidth], + [0, height / imageHeight, y / imageHeight] + ] +} +``` + +Supply the evaluated finite numbers, not expression strings. If the destination +aspect ratio differs, first choose an aspect-correct source rectangle rather +than stretching the subject. Open the rendered crop and verify its native IMAGE +fill; a valid transform does not prove that the intended subject was isolated. + +When the medium must remain a real image, verify with `get_structure` and +`options.native: true`; `native.imageFills` must contain the expected non-null +Figma hash. Input URLs, successful mutation, and visually similar screenshots +are not native read-back. + +The main agent owns placement, crop, and final verification. In a comparison, +make visual differences represent the subjects rather than their source files: +normalize incidental canvas padding, crop, background, viewpoint, and apparent +scale when they would bias the decision; preserve and explain differences that +are real or cannot be normalized faithfully. + +Before markup, map every content-bearing image consumer to the subject it +claims to depict. Reuse one asset and crop only when consumers represent that +same subject; distinct records require distinct assets or crops that visibly +isolate the correct subject. A composite scene may serve the composition it +depicts, but cannot stand in for several named records. Stop and source or +generate missing media instead of serializing a false mapping. + +When a gallery, carousel, or thumbnail set promises several views of one +subject, every retained view must add distinct, truthful information. Repeating +one unchanged source and crop does not satisfy that role; unrelated subjects +break identity. Use distinct sourced views, evidence-supported crops, or +generation/editing only for a named same-subject coverage need that sourcing +cannot satisfy. Otherwise reduce the views or disclose the gap. + +For repeated depictions of the same subject, keep asset identity and crop +stable unless evidence requires variation. If required media remains +unavailable, report it; omit optional media or use a neutral slot only when the +requested outcome is unchanged. A neutral slot is an explicit fallback, not +representative content or proof of reusable variation. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/local-styles.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/local-styles.md new file mode 100644 index 00000000..74aec685 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/local-styles.md @@ -0,0 +1,61 @@ +# Author local styles + +Use this reference only when the user or resolved system plan requires a local +style. Do not extract styles from an ordinary screen. New local resources need +no catalog; send `catalogId` only when a nested `{ "ref": "…" }` deliberately +reuses an existing resource. + +Copy this recipe and change its design facts. Style authoring keys persist +file-wide and are neither names nor IDs. Namespace keys by product and role. In +shared drafts, also prefix generic visible names that could collide; retain +established project naming when already clear. + +For whole-node typography, prefer a `theme.textStyles` alias and a `type-*` +class using [resource-mapping.md](resource-mapping.md). The recipe below shows +the explicit native binding form, also used for paint, effect, and grid styles. + +```json +{ + "mode": "create", + "markup": "
Account
", + "styles": { + "product/style/surface": { + "type": "PAINT", + "name": "Product/Color/Surface", + "paints": [{ "type": "SOLID", "color": { "r": 1, "g": 1, "b": 1 } }] + }, + "product/style/heading": { + "type": "TEXT", + "name": "Product/Typography/Heading", + "fontName": { "family": "Inter", "style": "Semi Bold" }, + "fontSize": 20, + "lineHeight": { "unit": "PIXELS", "value": 28 } + } + }, + "native": { + "card": { + "styles": { + "fill": { "styleKey": "product/style/surface" } + } + }, + "card/title": { + "styles": { + "text": { "styleKey": "product/style/heading" } + } + } + } +} +``` + +Types are `PAINT`, `TEXT`, `EFFECT`, and `GRID`, using `paints`, text fields, +`effects`, or `layoutGrids` respectively. For exact Paint, Effect, and Grid +shapes beyond this recipe, read [paints-effects.md](paints-effects.md). + +Omission preserves managed state. Top-level `null` removes a managed style only +when absence is required and all live consumers are cleared or removed in the +same result. Never mutate remote resources, invent library keys, or create a +broad style library for one screen. + +`unbound-created-style` means a same-call style lacks a `styleKey` consumer. +Bind it to a representative property performing its named role or remove it. A +swatch or unrelated binding is not coverage. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/paints-effects.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/paints-effects.md new file mode 100644 index 00000000..c32b82f2 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/paints-effects.md @@ -0,0 +1,111 @@ +# Paints, effects, grids, guides, and media + +Use this reference whenever the result uses a nontrivial shadow, blur, glass, +texture, noise, image paint, layered gradient material, or layout aid, including +effects expressed as Canvas HTML classes. Resolve an image or illustration's +role, subject, and medium through [visual-assets.md](visual-assets.md), then its +source and delivery through [images.md](images.md). Prefer a matching catalog +style; otherwise use direct native arrays. + +## Catalog links + +```html +
+``` + +A style owns its channel. Do not combine a non-null fill or stroke style with a +whole-node variable on the same paint. Styled strokes still need literal, +typed, or variable-bound geometry. `null` unlinks; omission preserves. + +## Resolve shadow references + +Named scales such as `shadow-md` are theme references, not portable geometry: + +- Reuse: bind the matching catalog Effect style. +- Author: create and bind a local Effect style only when the system plan requires + it. +- Direct: use an exact `shadow-[...]` class or typed `figma.effects` value. + +Never assume Tailwind defaults or create a token only to resolve a named class. +`shadow-none`, `inset-shadow-none`, and `text-shadow-none` explicitly clear. + +Treat an outer shadow's rendered halo as part of the composition. Inspect the +final PNG beyond the root edges; visible granular or noisy fringe, or a halo +that dominates the captured bounds, is a defect even when the frame itself is +intact. Preserve intended depth by tightening blur, spread, or opacity or using +smaller layered shadows, then recheck. Do not flatten established material +treatment merely to hide the defect. + +## Native paint and effect stacks + +`figma.fills` and `figma.strokes` support ordered solid, linear/radial/angular/ +diamond gradient, image/video, Pattern, and fill-shader paints. +`figma.effects` supports ordered shadows, normal/progressive blur, noise, +texture, glass, and effect shaders. + +A `SOLID` paint uses RGB `color` and optional paint-level `opacity`; only +gradient stops use RGBA colors. Keep stroke geometry, including `dashPattern`, +in `figma.stroke`, not the stroke paint. + +Use the exact gradient enum and normalized RGBA stop shape; do not translate +from CSS or Plugin API names: + +```json +{ + "figma": { + "fills": [ + { + "type": "GRADIENT_LINEAR", + "gradientTransform": [ + [1, 0, 0], + [0, 1, 0] + ], + "gradientStops": [ + { "position": 0, "color": { "r": 1, "g": 0.43, "b": 0.29, "a": 1 } }, + { "position": 1, "color": { "r": 0.16, "g": 0.09, "b": 0.24, "a": 1 } } + ] + } + ] + } +} +``` + +Other gradient enums are `GRADIENT_RADIAL`, `GRADIENT_ANGULAR`, and +`GRADIENT_DIAMOND`. + +Omission preserves a stack; `[]` clears it. Direct stacks cannot share their +channel with a literal class, whole-node variable, or style. Use variable refs +such as `{ "ref": "v1" }` and shader refs such as `{ "ref": "h1" }`; use only +returned shader property IDs and declared value shapes. + +For images, provide exactly one same-file `imageHash`, public HTTP(S) `imageUrl`, +or call-scoped `assetKey` for a full-SHA-256 Hub IMAGE asset. PNG, JPEG, and GIF +are limited to 4096×4096. For video, provide exactly one same-file `videoHash` or +public `videoUrl` for MP4, MOV, or WebM up to 100 MB. URLs must need no +credentials. Reuse `figmaImageHash`, `figmaImageHashes`, or `figmaVideoHashes` +from `get_code` only in the same file; they identify native media, not preview +bytes. + +A Pattern uses exactly one existing `sourceNodeId` or same-result +`sourceCanvasKey`. + +## Layout aids + +Prefer a matching Grid style. Otherwise `figma.layoutGrids` declares ordered +row, column, or square grids on frames, components, sets, and instances. Use +`"AUTO"` for automatic row or column count. Do not bind `sectionSize` with +`STRETCH` or `offset` with `CENTER`. + +`figma.guides` is the complete ordered X/Y guide list: omission preserves and +`[]` clears. Page guides live under `page.guides`. + +For wrapping linear Auto Layout, `figma.autoLayout` may set signed +`itemSpacing`, positive or synchronized-null `counterAxisSpacing`, and +`itemReverseZIndex`. Never declare one physical gap in both classes and native +state. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/resource-mapping.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/resource-mapping.md new file mode 100644 index 00000000..4d3f3db8 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/resource-mapping.md @@ -0,0 +1,138 @@ +# Use resources in Canvas classes + +Keep layout and visual composition in markup. Put a reusable value's native +identity in the catalog or a call-scoped `theme`, then reference it by class. +Variables remain bound Figma variables, including mode changes. A `type-*` +class binds an entire native TextStyle. Ordinary utilities such as `gap-4` and +`text-base` remain literals and do not create or discover resources. + +## Existing system + +When the applicable system permits reuse, discover it with `get_design_system`. +Use returned variable `cssName` and TEXT-style `className` with its `catalogId`: +`bg-(--surface)`, `gap-(--spacing-content)`, `type-body`. These are examples of +names, not assumed resources. Read a style's exact ref when its font, metrics, +or bindings affect the choice. + +The catalog uses valid WEB code syntax when available, otherwise derives a +name. It disambiguates collisions and keeps the resulting alias tied to one +exact identity for that catalog's lifetime. Use the returned name unchanged; +never derive identity from equal values, similar names, or another catalog. + +For task-specific names, add `theme.variables: { "--surface": { "ref": "v1" } }` +or `theme.textStyles: { "type-body": { "ref": "s1" } }`. Use returned refs. An +alias cannot replace another catalog alias with a different resource. A stable +authoring key and catalog ref for the same native identity may share an alias. + +## New system + +When the deliverable includes a design system, define the selected variables +and styles through `variableCollections` and `styles`. Map their stable keys in +`theme` and consume them in the same call. A primitive draft without a system +still uses ordinary classes; repetition alone does not require resource creation. + +This complete recipe illustrates the relationship. Change the design facts, +namespace resource keys for the product, and confirm the font family/style in +the environment before authoring it. + +```json +{ + "mode": "create", + "markup": "
Account settings
", + "theme": { + "variables": { + "--surface": { "variableKey": "product/color/surface" }, + "--content-gap": { "variableKey": "product/space/content" } + }, + "textStyles": { "type-body": { "styleKey": "product/type/body" } } + }, + "variableCollections": { + "product/theme": { + "name": "Product/Theme", + "modes": { "light": { "name": "Light" }, "dark": { "name": "Dark" } }, + "variables": { + "product/color/surface": { + "name": "Surface", + "type": "COLOR", + "codeSyntax": { "WEB": "var(--surface)" }, + "values": { + "light": { "r": 1, "g": 1, "b": 1 }, + "dark": { "r": 0.08, "g": 0.09, "b": 0.11 } + } + }, + "product/space/content": { + "name": "Space/Content", + "type": "FLOAT", + "values": { "light": 16, "dark": 16 } + } + } + } + }, + "styles": { + "product/type/body": { + "type": "TEXT", + "name": "Product/Typography/Body", + "fontName": { "family": "Inter", "style": "Regular" }, + "fontSize": 16, + "lineHeight": { "unit": "PIXELS", "value": 24 } + } + } +} +``` + +On later calls, retain the small `theme` mapping and omit resource definitions +unless changing them. The stable keys resolve the same native resources. The +mapping is local to the call, so different screens can use different aliases +without changing the file's naming. Authoring keys and native identities +persist; aliases do not create a second resource registry. + +Use [variables.md](variables.md) for modes, aliases, scopes, and resource updates; +use [local-styles.md](local-styles.md) for style definitions. A TextStyle may +bind selected typography primitives through its `variables` fields when those +values must change together. Do not create font-family, size, or weight tokens +solely to express a single named text role: the TextStyle can hold those facts. + +## Supported variable utilities + +Both `gap-(--space)` and `gap-[var(--space)]` work. Explicit type hints resolve +ambiguous Tailwind prefixes, for example `text-(length:--body-size)` versus +`text-(color:--foreground)`. + +| Utility | Native value | +| ---------------------------------------------------------------------- | ------------------------------------------------------- | +| `bg-(--surface)`, `text-(--foreground)`, `border-(--border)` | COLOR fill or stroke; border still needs a width | +| `w/h/size/min-w/max-w/min-h/max-h-(--value)` | FLOAT dimensions, in pixels | +| `gap/gap-x/gap-y-(--value)` | FLOAT layout gaps, in pixels; axes follow flex or grid | +| `p/px/py/pt/pr/pb/pl-(--value)` | FLOAT padding, in pixels | +| `rounded/rounded-tl/rounded-tr/rounded-br/rounded-bl-(--value)` | FLOAT corner radius, in pixels | +| `border-(length:--width)` | FLOAT stroke width, in pixels | +| `text-(length:--size)`, `leading-(--leading)`, `tracking-(--tracking)` | FLOAT font size, line height, letter spacing, in pixels | +| `font-(family-name:--family)` | STRING font family | +| `font-(--weight)` | FLOAT font weight, 1–1000 | +| `opacity-(--opacity)` | FLOAT opacity, 0–1 | + +The tool reads an initial native value itself and retains the variable binding; +do not add a second literal fallback class. Native node, layout, and scope rules +still apply. This is a bounded mapping to Figma fields, not a CSS engine: no +`calc()`, var fallbacks, arbitrary expressions, or cascade. FLOAT metrics use +the native units above, not unitless CSS line-height multipliers. + +## Typography ownership + +`type-body` consumes the whole TextStyle. Keep color, sizing, alignment, and +wrapping classes on the text node as needed; omit font, weight, size, leading, +tracking, case, and decoration overrides owned by that style. Choose another +style or explicitly unlink the style for a deliberate local treatment. Composite +typography has no single Figma variable type, so `type-*` is an explicit custom +utility convention rather than a Tailwind default or a fabricated CSS variable. + +Inline `data-var-*`, `data-style-*`, and `native` bindings remain available for +fields outside this subset, exact native fonts/styles, and explicit unlinking. +Use one mechanism per property. Unknown names, conflicting declarations, +incompatible types, and cyclic variable aliases require correction; the tool +does not guess a replacement. + +Updates preserve omitted native state. Removing a resource class or replacing +it with a literal does not unlink the existing binding: explicitly clear the +variable/style with its `data-var-*="none"`, `data-style-*="none"`, or supported +`native` null binding when that is the intended change. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/rich-text.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/rich-text.md new file mode 100644 index 00000000..3e26cc97 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/rich-text.md @@ -0,0 +1,52 @@ +# Rich text and hyperlinks + +Use this reference for native font application or Figma-only text behavior; +use [typefaces.md](typefaces.md) when font selection or availability needs resolving. +Use `span` for editable text. Put whole-node typography in classes, a catalog +Text style, or semantic variable bindings when possible. + +`native[key].figma.text` supports: + +- exact whole-node `fontName`, `autoRename`, vertical alignment, and leading + trim; +- paragraph indent/spacing, list spacing, hanging punctuation/list; +- whole-node hyperlink; +- ordered rich-text `ranges`. + +Do not combine `autoRename: true` with fixed `figma.name`. + +When no Text style or typography variable expresses the chosen family and +style, use the exact available Figma font: + +```json +{ + "fontName": { "family": "IBM Plex Sans", "style": "Medium" } +} +``` + +Do not combine it with `font-*` classes, linked Text styles, or font family/style +variables. Never guess family or style availability. + +Range `start` and `end` are UTF-16 offsets into final characters. Ranges must be +ordered, non-overlapping, and set at least one property; split overlapping +intentions into disjoint intervals. A range may set font name/size, case, +letter spacing, line height, complete underline state, native fills, Text/Paint +style, list options, indentation, paragraph spacing, hyperlink, and supported +text-range variables. + +Use `{ "ref": "s1" }` for a catalog range style and `{ "ref": "v1" }` for a +range variable. `null` unlinks supported styles or hyperlinks; omission +preserves. + +Hyperlinks support URLs and node targets. For a same-result target: + +```json +{ + "type": "NODE", + "value": { "canvasKey": "settings/help" } +} +``` + +The target may appear later in markup; never remove a live hyperlink target. If +a catalog component exposes text through a prop, set that prop instead of +editing internal layers. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/style-grounding.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/style-grounding.md new file mode 100644 index 00000000..2a83efca --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/style-grounding.md @@ -0,0 +1,80 @@ +# Ground design judgment + +Use this reference for a new direction, material redesign, or consequential +uncertainty not settled by the user or an established source. Exact reproduction +and mechanical edits use their supplied evidence directly. + +## Inspect what can change the decision + +Start with the nearest credible evidence: the supplied design or implementation, +real product states, primary platform requirements, or adjacent visual work. +Choose separate evidence for behavior and visual expression when needed. A +functional walkthrough can establish behavior without settling visual language; +a visually relevant product state or adjacent visual work can show how density, +controls, surfaces, icon/text economy, and states cohere without establishing +behavior it does not expose. One artifact may inform both only when the relevant +behavior and pixels are actually inspected. + +Open the relevant state at useful scale. A homepage or brand campaign may not +show the working interface. Search cards, prose, remembered products, generated +images, and failed retrievals are not inspected visual precedents. A content +photograph establishes what it depicts, not the surrounding application's +interaction or composition. Follow the main skill's first-write evidence +boundary when retrieval fails. + +An image-search result that exposes only a screenshot description or URL remains +a search card. Open the actual product-state pixels at useful scale before +treating them as visual grounding; otherwise use the result only as behavioral +description. + +Research is grounded when it changes, confirms, or reopens a material decision +in the new result. Retain enough source identity and context to support that +claim; do not invent a source-by-source decision report. If a source contributed +nothing consequential, do not cite it as a precedent. Generic expertise helps +interpret the evidence; its familiar defaults are not evidence about this +product. + +There is no source quota. Stop when further investigation is unlikely to change +a material choice. Do not research routine decisions for ceremony. Keep source +screens outside the authored result unless the user asked to place or reproduce +them, and preserve required source content and behavior when adapting a design. + +## Form a provisional direction + +Integrate the brief, evidence, and professional judgment into a relationship +among content, state, and action, with a visual language that makes it fitting +and perceptible. A new design needs its own solution; independence is not a +reason to discard an applicable interaction or representation because it is +harder to source or serialize. + +Before the first write, be able to state privately what the inspected pixels +changed or confirmed about the recurring visual language. A mood label or +task-themed palette is not that direction; if the same control and surface +grammar could survive a noun swap, inspect more relevant pixels or reconsider +the synthesis. + +Resolve recurring visual roles enough to try them in a real composition. The +foundation is provisional and may change after seeing pixels. It is not a +separate foundation board or permission to create components, variables, or +styles outside the task's resource scope. + +Reconsider choices whose only justification is habit or semantic association. +Ask what in the brief or inspected reality makes the proposed treatment fit. +Familiar solutions can be appropriate; choosing the opposite of a criticized +motif is no stronger evidence. Functional specificity alone does not settle +expression, and stylistic difference alone does not make the product useful. + +## Externalize unresolved visual choices + +If materially different visual hypotheses remain and a capable image-generation +tool is available, a bounded visual exploration can help you see their +consequences. Open those pixels and use them to reconsider the composition; +omit this step when the direction is already clear. + +Generated concepts are speculative sketches, not real-product evidence or +flattened Figma deliverables. Do not trust their text/data or trace them +literally. A generated subject chosen as actual product content is a separate +asset decision under `visual-assets.md`. + +Return to the representative native composition and inspect it. Let a mismatch +reopen the decision it actually challenges; otherwise complete the design. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/typefaces.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/typefaces.md new file mode 100644 index 00000000..185284bc --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/typefaces.md @@ -0,0 +1,48 @@ +# Choose and apply fonts + +Use this reference when selecting or changing fonts, delivering a required +family/style, or resolving uncertainty about the text's scripts. Availability +can change a provisional choice; query before committing when that matters. + +Start from applicable Text styles, typography variables, project fonts, or +supplied references. Preserve established font identities for ordinary edits. +For a new direction, form candidates from the language, text roles, density, +and visual intent. A portable `font-sans|serif|mono` category does not establish +an exact family or suitable coverage for the actual text. + +## Query what can change the choice + +`get_design_system` with `scope: "fonts"` reads the environment without scanning +file resources. It is valid for direct composition, reuse, and an independent +system, including a blank page. + +- With candidate family names, use `families: ["Noto Sans SC"]` to inspect + exact native style names and missing families in one call; batch candidates. +- Use `query: "Noto"` when the family name itself needs discovery. This searches + names, not language coverage or visual suitability. +- Continue `nextCursor` with the same filters only when more results could + affect the choice. Reuse current evidence rather than querying per text node. + +Use returned or source-established native names. For an unavailable provisional +candidate, reconsider the choice. For a required font, preserve the requirement +and disclose the delivery gap rather than silently substituting another family. + +## Apply the selected typography + +Reuse the applicable TextStyle or font variables. If a new design system is in +scope, define the selected text roles as TextStyles and consume their `type-*` +classes through [resource-mapping.md](resource-mapping.md). Font selection alone +does not require creating styles or tokens. + +For direct composition, `font-[family-name:Noto_Sans_SC] font-semibold` fixes +the family and chooses its closest available weight. Underscores encode spaces; +`\_` preserves an underscore. Use `native[key].figma.text.fontName` with exact +`{ family, style }` when the native style identity matters; see +[rich-text.md](rich-text.md). Weight matching is approximate. For variable-driven +typography, consider the family/weight/style combinations in the delivered modes. + +Inspect representative real content in the composition, including relevant +scripts, numbers, punctuation, and wrapping. Availability and successful loading +do not prove glyph coverage; a correct-looking screenshot alone does not prove +native font identity or current editability. Reopen the font choice when the +observed text challenges it, without requiring a separate specimen board. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/variables.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/variables.md new file mode 100644 index 00000000..692a8699 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/variables.md @@ -0,0 +1,154 @@ +# Author local variables + +Use this reference after the representative pixel check when repeated colors +may carry shared semantic roles, or when the user or resolved system plan +requires local variables. Do not extract tokens from an ordinary screen. New +resources need no catalog; send `catalogId` only for deliberate nested +`{ "ref": "…" }` reuse. + +## Contents + +- [Decide from real roles](#decide-from-real-roles) +- [Author variables](#author-variables) +- [Bind and verify](#bind-and-verify) +- [Update and remove](#update-and-remove) + +## Decide from real roles + +After any selected representative component reconciliation and before +propagation, call full `get_code` with unresolved tokens only when repeated +colors plausibly represent semantic roles whose coordinated maintenance matters. +Treat `literalClusters` as candidate locations, not a to-do list. Select a role +only when concrete consumers should evolve together; split mixed roles even +when their literal values match. Leave incidental, local, and ambiguous +repetition literal. If the diagnostic is unavailable, do not infer a system +from repetition. + +For each selected role, map concrete consumer and field to a semantic variable +key, bind every representative consumer, then re-run once to confirm the role is +exposed through `tokens` and no longer unresolved. A non-empty +`literalClusters` result is acceptable. + +Carry only selected mappings into propagation. A later apply that includes a +consumer of a selected role must bind that field in the same call; an inherited +instance binding does not cover sibling literals. Before finalization, scan each +materially distinct dependent root that uses a selected role once, fix missing +bindings for those roles, and recheck only changed roots. Do not create variables +to empty diagnostics, expand the map from literal equality, or repeat scans after +the selected roles are verified. + +## Author variables + +Copy this recipe and change its design facts. Collection and variable authoring +keys persist file-wide and are neither names nor IDs. Choose one +collision-resistant prefix for the independent system; recover existing exact +keys when intentionally updating it. Mode keys are collection-scoped. + +```json +{ + "mode": "create", + "markup": "
Account
", + "variableCollections": { + "product/theme": { + "name": "Theme", + "modes": { + "light": { "name": "Light" }, + "dark": { "name": "Dark" } + }, + "variables": { + "product/color/surface": { + "name": "Color/Surface", + "type": "COLOR", + "scopes": ["ALL_FILLS"], + "values": { + "light": { "r": 1, "g": 1, "b": 1 }, + "dark": { "r": 0.08, "g": 0.09, "b": 0.11 } + } + }, + "product/space/md": { + "name": "Spacing/Medium", + "type": "FLOAT", + "scopes": ["GAP"], + "values": { + "light": 16, + "dark": 16 + } + } + } + } + }, + "native": { + "card": { + "variables": { + "fill": { "variableKey": "product/color/surface" }, + "gap": { "variableKey": "product/space/md" } + }, + "variableModes": { + "product/theme": "dark" + } + } + } +} +``` + +A new collection needs `name` and at least one named mode. Each variable needs +`name`, `type`, and a value for every mode. Types are `BOOLEAN`, `COLOR`, +`FLOAT`, and `STRING`. Values may alias another variable: + +```json +{ "variable": { "variableKey": "…" } } +``` + +Valid scopes: + +- general: `ALL_SCOPES`, `TEXT_CONTENT`, `CORNER_RADIUS`, `WIDTH_HEIGHT`, `GAP`, + `OPACITY`; +- color: `ALL_FILLS`, `FRAME_FILL`, `SHAPE_FILL`, `TEXT_FILL`, `STROKE_COLOR`, + `EFFECT_COLOR`; +- numeric effect/stroke: `STROKE_FLOAT`, `EFFECT_FLOAT`; +- typography: `FONT_FAMILY`, `FONT_STYLE`, `FONT_WEIGHT`, `FONT_SIZE`, + `LINE_HEIGHT`, `LETTER_SPACING`, `PARAGRAPH_SPACING`, `PARAGRAPH_INDENT`. + +Use `STROKE_COLOR`, not `ALL_STROKES`. Combine neither `ALL_SCOPES` with other +scopes nor `ALL_FILLS` with `FRAME_FILL`, `SHAPE_FILL`, or `TEXT_FILL`; +`ALL_FILLS` may coexist with a non-fill scope such as `STROKE_COLOR`. + +## Bind and verify + +Bind through `native[key].variables` using the exact supported field, such as +`fill`, `stroke`, `gap`, `paddingTop`, `width`, `visible`, `fontSize`, or +`characters`. Retain a matching literal class when Figma needs an initial paint +or numeric fallback. + +Bind each variable to representative fields performing its semantic role. +Prefer `GAP` for shared gaps/padding, `WIDTH_HEIGHT` for semantic control/icon +sizes, and `CORNER_RADIUS` for shared radii. Do not tokenize viewport dimensions, +one-off crops, content-derived geometry, or optical corrections merely because +numbers repeat. + +A representative binding proves usability, not complete coverage. Bind every +consumer intended to evolve with the role; keep equal peer literals only when +incidental or independently owned. + +`apply_canvas` reports `unbound-created-variable` when a new variable lacks a +same-result consumer. Bind it to a real consumer or remove it. A staged warning +may be temporary, but final delivery must show a native binding; equal literals +do not count. + +`variable-fallback-mismatch` means a bound literal matches none of the +same-call variable's direct or aliased mode values. Align the fallback with a +real mode or bind the variable that owns the value, or the binding will silently +change the declared markup. + +## Update and remove + +After changing a variable value, update and verify every intended consumer that +cannot carry a native binding, such as `figma.svg.color`; omission leaves its +old literal in place. + +Omission preserves managed state. Top-level `null` removes a managed variable, +mode, or collection only when absence is required and all consumers are cleared +or removed in the same result. Never mutate remote resources, invent parent +collections or library keys, or build a broad token system for one screen. +Extended collections must inherit a real local or catalog collection and obey +plan limits. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/visual-assets.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/visual-assets.md new file mode 100644 index 00000000..eaa3d4c8 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/visual-assets.md @@ -0,0 +1,57 @@ +# Choose and preserve visual assets + +Use this reference after the design selects an icon, image, +illustration, diagram, or vector asset. It governs role, medium, source +integrity, editability, and delivery—not whether the design should contain that +asset or what the finished visual style should be. + +Research pixels and generated screen concepts remain evidence for judgment, +not canvas content. Import, reproduce, annotate, or compare them only when the +user explicitly requests that treatment. When evidence establishes that the +new product needs an asset role, acquire or author a truthful asset for the new +result instead of redrawing or embedding the reference. + +## Preserve the decided role + +Start from the composition, not an available tool or assumed asset slot. Once a +material role is selected, fulfill it faithfully; sourcing difficulty is not a +reason to replace an image, icon, visualization, or exact medium with easier +text or plausible geometry. + +Depiction is a role, not a medium. Choose raster, sourced vector, +agent-authored vector, diagram, or another medium only when the brief, inspected +evidence, or a low-consequence assumption supports it. Convenience never +changes the medium. + +Treat content-bearing visualization—such as a chart, map, waveform, notation, +document or media preview, or domain instrument—as a first-class +representation. Identify the user decision and the visual structures that make +it possible. Preserve enough context and density to act; a stylized trace or +labeled decoration is not the representation. When only topology or sequence +is intended, name and design it as a diagram. + +When recognition depends on a subject's real appearance—such as a person, +product, food, place, room, photograph, cover, or shared-media preview—preserve +that distinction with a real sourced or generated image unless the brief or +inspected evidence independently establishes an illustrated language. + +Preserve editability semantics. Build changing diagram labels, shapes, and +relationships as native structure; use an opaque SVG only when exact vector art +is the asset. An SVG wrapper with Vector descendants does not make a diagram +model editable. If editable primitives cannot carry a required representation, +use an evidence-supported native, vector, or raster base with changing overlays +editable, or disclose the gap. + +For material assets retain enough evidence for identity and content fidelity, +provenance and applicable rights, source quality, and Canvas-compatible form. +Never silently change subject, style, or medium. Crops, masks, overlays, and +retouching must preserve the depicted subject; do not hide distinctive branding +or features to make one subject represent another. + +## Load only the selected branch + +- For an icon role, read [icons.md](icons.md). +- For an image or illustration, read [images.md](images.md). + +For diagrams and other custom vector art, use the source and editability +boundaries above, then load only the required geometry or paint mechanics. diff --git a/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/visual-composition.md b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/visual-composition.md new file mode 100644 index 00000000..27993d33 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-canvas-authoring/references/visual-composition.md @@ -0,0 +1,64 @@ +# Compose a product interface + +Use this reference when forming or reconsidering a composition. Keep the +person's working experience in view; use the questions below only where they +help resolve a decision. They are not independent quality axes. + +## Find the working relationship + +What is the person attending to, and what can they do with it in the depicted +state? Does the chosen screen or flow expose the user's central work, or merely +promise it through a button whose destination is absent? What changes across +states, and what must remain perceptible while that happens? Arrange content, +controls, and context so their relationship is understandable in the rendered +whole. + +A familiar shell may be the right answer. Reconsider it when it hides the +working object, requires unnecessary reading or navigation, or survives only +because task-specific nouns make it look relevant. Novelty and decoration do +not repair that mismatch. + +As content grows, what extends: the document or an owned scrolling region? +Choose document flow, a fixed workspace, or a hybrid from product behavior; +check that making room has not silently redefined the device or window viewport. +Density and control scale follow platform, frequency, precision, and environment +of use. In frequent expert work, inspect the real product's interaction economy +before carrying over the spacing and repeated explanations of an occasional +consumer journey. Preserve legibility and suitable targets in either case. + +## Make meaning perceptible + +What should someone notice now, and what should stay available without +competing? Resolve type, position, scale, color, contrast, media, depth, and space +together. Repeated roles need recognizable treatment; differences need to carry +meaning in this task. An expressive role does not by itself justify the first +familiar palette, shape, or effect. + +Choose text, icons, images, and graphics by recognition, comparison, +manipulation, and expression. Familiar iconographic affordances can reduce the +reading and space required by repeated controls; words can be more precise. +Inspect that tradeoff at actual size, including when every action has become +text. Source selected icons through `visual-assets.md`; sourcing effort is not +a design reason to drop their role. + +A working graphic must carry the distinctions needed for the decision. Check +whether its marks, scale, context, and state make the relevant comparison or +manipulation possible. Changing a label does not change what the marks encode. This is a question +of represented meaning, not a quota for detail or a preferred graphic style. Use `visual-assets.md` for truthful +source and native representation. + +## Learn from the rendered result + +Open the representative composition at useful scale. Mentally follow the +central action through its visible consequences. Does the selected state agree +with the working surface, available action, and result? If the experience breaks, +inspect the particulars that explain where and why. + +Judge spacing from visible relationships: nested insets, seams, baselines, +grouping, and repeated rhythm. Nominal padding or a non-overflowing bounding box +does not prove that the intended space survived native layout. Repair the +owning relationship instead of decorating over it. + +Carry resolved shared roles into dependent screens while allowing their layouts +to differ with the work. Stop when the requested whole is coherent and the +observed defects are resolved; do not keep polishing to fill a checklist. diff --git a/agent-plugin/targets/claude/skills/figma-design-to-code/SKILL.md b/agent-plugin/targets/claude/skills/figma-design-to-code/SKILL.md new file mode 100644 index 00000000..a5bb5f20 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-design-to-code/SKILL.md @@ -0,0 +1,177 @@ +--- +name: figma-design-to-code +description: >- + Implement or update project-consistent UI code from a visible Figma selection + or nodeId using TemPad Dev MCP. Use when the user wants Figma UI recreated, + ported, or integrated into the target project's framework, styling system, + tokens, assets, and existing components. Do not use for design critique, + product invention, generic code review, or guessing states, responsiveness, + or behavior not evidenced by Figma, the project, or the user. +--- + +# Implement Figma design in code + +Turn visible Figma evidence into the smallest project-native implementation +that preserves the intended result. Keep that result focal: project files, +TemPad output, rules, and tool calls are evidence for the implementation, not +deliverables to reproduce mechanically. + +Require TemPad Dev MCP to provide trustworthy design evidence for the current +selection or an exact `nodeId` inside the user's established scope. Never +reconstruct the design from memory, screenshots alone, or `get_structure` +metadata. + +## Evidence and authority + +Use each source only for what it can establish: + +- **The user** sets scope, requirements, prohibitions, and missing product or + implementation decisions. +- **The project** sets framework, file placement, component boundaries, + styling, tokens, assets, dependencies, and verification conventions. +- **TemPad Dev** sets visible structure and rendered design facts. + +Follow project instruction files for concerns outside Figma-to-code +translation. Do not add policy for routing, analytics, i18n, CMS, or other +orthogonal systems. + +TemPad can establish visible hierarchy, layout, spacing, typography, color, +effects, token references, exported assets, and codegen unit context. It cannot +establish unevidenced states, responsive behavior, business logic, navigation, +validation, analytics, or project conventions. Treat `get_structure` as +hierarchy and geometry evidence only, never as missing style truth. + +## Workflow + +### 1. Establish the implementation envelope + +Read only local evidence that can change this implementation, in this order: + +1. applicable `AGENTS.md` or equivalent instructions; +2. relevant design-system, token, component, and asset guidance; +3. the nearest comparable implementation and reusable primitives; +4. framework, styling, and check configuration needed for this task. + +Determine the target file or component boundary, framework, styling method, +token and asset paths, reuse candidates, dependency constraints, and narrowest +relevant checks. Inspect Tailwind version and theme scales only when the +project actually uses Tailwind-compatible tooling. + +Do not inventory the repository broadly after the needed envelope is clear. If +a missing project decision would materially change the result, ask before +implementation. + +### 2. Read the design at the requested scope + +Call TemPad Dev's `get_code` before implementing: + +- use `resolveTokens: false` by default; +- omit `nodeId` for the current single selection; pass one only when the user + supplied it or TemPad returned the exact ID for a targeted read inside the + user's established scope; +- set `preferredLang` from the established project target; +- keep TemPad's default vector behavior unless the user explicitly requests + asset-preserving vector fidelity and the active MCP version supports it. + +Use `resolveTokens: true` only when the user explicitly does not want design +token references. Treat returned `lang` as authoritative because plugin +configuration may override `preferredLang`. + +Retain the returned `code`, `lang`, `warnings`, `assets`, `tokens`, and +`codegen` facts that bear on the implementation. Use +`codegen.config.{cssUnit,rootFontSize,scale}` for exact unit conversion. + +Prefer one top-level read that preserves the requested composition. If the +tool is unavailable, points at the wrong file, or returns incomplete evidence, +read [recovery.md](references/recovery.md) before doing anything else. + +### 3. Separate facts, adaptations, and gaps + +Before editing, distinguish: + +- **design facts** to preserve; +- **project-native adaptations** supported by existing components, tokens, + utilities, or asset conventions; +- **unevidenced product decisions** that must remain unimplemented or be asked. + +Map by rendered value and semantics, not by a convenient name. A familiar +component or token is a candidate, not proof of equivalence. If more than one +material implementation path remains equally plausible, ask the user. Infer +only low-consequence details and report any inference that affects the result. + +### 4. Implement the smallest coherent change + +- Keep the established framework, styling system, file placement, imports, and + abstraction level. Do not introduce a parallel system. +- Reuse an existing primitive only when its semantics and rendered behavior fit + without guessing. Do not force reuse that erases design facts. +- Preserve exact rendered values unless project evidence proves an equivalent + token, utility, or component. For `rem` output, convert with TemPad's actual + `cssUnit`, `rootFontSize`, and `scale`. +- Preserve intentional uncommon output, including pseudo-elements, filters, + masks, blend and backdrop effects, gradients, and non-default compositing, + unless a documented project constraint requires an adaptation. +- Implement only evidenced states and responsiveness. Do not invent hover, + loading, error, empty, disabled, or responsive behavior. +- Use native semantic elements and preserve keyboard access and accessible + names when an established primitive does not already provide them. +- Add no runtime or build dependency without user approval unless the user has + explicitly waived that constraint. +- Keep `data-hint-*` attributes out of shipped code. + +When TemPad returns relevant entries, load only the matching protocol: + +- assets: read [Assets](references/assets-and-tokens.md#assets) and follow the + project's asset delivery path; +- token references: read [Tokens](references/assets-and-tokens.md#tokens) and + follow the project's token workflow. + +Read both when both are present and skip both when neither is present. + +Do not enter a visual tuning loop. Change the implementation again only when +new project, design, tool, or verification evidence identifies a concrete +defect. + +### 5. Verify in the project's real workflow + +Run the narrowest relevant checks defined by project instructions and scripts. +Repair implementation failures and rerun the affected checks. Use an existing +preview, screenshot, or comparison workflow when available; do not invent a +universal verification matrix. + +If no runnable check exists, report the implementation as unverified. Do not +claim visual completion without a real project comparison path; ask the user +to confirm the rendered result against Figma. + +## Hard stops + +Stop instead of shipping when: + +- TemPad is unavailable, unauthorized, inactive on the intended file, or + cannot provide a trustworthy visible parent composition; +- the target is unreadable or not visible; +- project, design, and user evidence still conflict after targeted recovery; +- a missing decision would materially change behavior, structure, dependency, + asset delivery, or token mapping; +- required assets cannot be retrieved or stored under project policy. + +If blocked, give at most three concrete actions that would unblock the task. + +## Handoff + +Report: + +- what changed and where; +- only the relevant adaptation, inference, warning, asset/token handling, or + residual visual risk; +- checks run, their result, and what remains unverified. + +Keep absent concerns absent from the handoff. Do not produce a compliance +checklist for branches the task never used. + +## Decision example + +If TemPad emits `padding: 15px` and the project has a `space-4` token worth +`16px`, preserve `15px` unless project evidence explicitly makes the token the +intended mapping. Project consistency selects the representation; it does not +authorize changing the visible design. diff --git a/agent-plugin/targets/claude/skills/figma-design-to-code/agents/openai.yaml b/agent-plugin/targets/claude/skills/figma-design-to-code/agents/openai.yaml new file mode 100644 index 00000000..406fbf6e --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-design-to-code/agents/openai.yaml @@ -0,0 +1,7 @@ +interface: + display_name: 'Figma Design to Code' + short_description: 'Implement project-consistent UI code from Figma' + icon_small: './assets/icon.svg' + icon_large: './assets/icon.svg' + brand_color: '#0098FF' + default_prompt: 'Use $figma-design-to-code to implement the selected Figma design in the current project.' diff --git a/agent-plugin/targets/claude/skills/figma-design-to-code/assets/icon.svg b/agent-plugin/targets/claude/skills/figma-design-to-code/assets/icon.svg new file mode 100644 index 00000000..2e8c6946 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-design-to-code/assets/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/agent-plugin/targets/claude/skills/figma-design-to-code/references/assets-and-tokens.md b/agent-plugin/targets/claude/skills/figma-design-to-code/references/assets-and-tokens.md new file mode 100644 index 00000000..01dec4a6 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-design-to-code/references/assets-and-tokens.md @@ -0,0 +1,47 @@ +# Translate assets and tokens + +Read this reference only when `get_code` returns `assets` or `tokens`. + +## Assets + +Follow the project's established asset and icon policy before TemPad delivery +details. + +- Download bytes only from a TemPad-provided `asset.url`. Never substitute a + public internet asset. +- Treat assets as files to store or reference, not text evidence to parse. +- If project policy forbids storing them, reference TemPad URLs only when the + user accepts the local-server dependency, and report it. +- Treat emitted `` markup as design truth for structure, + size, and instance color. Refactor delivery only through an existing project + SVG path. +- If upload falls back to inline SVG, preserve that markup rather than + resynthesizing the vector. +- `themeable: true` permits one contextual color channel, usually + `currentColor`; drive it through the established wrapper or icon convention. + Preserve internal palettes when `themeable` is absent. +- Do not invent a new SVG pipeline, multi-color props, or custom variables. + +If a required asset cannot be retrieved or represented under project policy, +stop rather than draw or substitute it from memory. + +## Tokens + +Preserve token usage when the target project can carry or map it safely. +Token facts may be direct values or mode-specific values keyed by +`Collection:Mode`; preserve aliases between variables when present. + +- Map to an existing project token only when value, reference behavior, + semantics, and relevant mode agree. A similar name is insufficient. +- Preserve TemPad token references through the project's normal token workflow + when that workflow can accept them. +- Add a token only when the project already defines how and this task calls for + it. +- If landing location, mode, or mapping remains ambiguous, use the exact + rendered value and report the fallback. +- Use hint metadata only while reasoning about a mode; never ship hint + attributes. + +When tokens and explicit rendered values disagree, do not silently choose. +Narrow the design evidence or ask the user which source expresses the intended +state. diff --git a/agent-plugin/targets/claude/skills/figma-design-to-code/references/recovery.md b/agent-plugin/targets/claude/skills/figma-design-to-code/references/recovery.md new file mode 100644 index 00000000..88cf1e89 --- /dev/null +++ b/agent-plugin/targets/claude/skills/figma-design-to-code/references/recovery.md @@ -0,0 +1,54 @@ +# Recover trustworthy design evidence + +Read this reference only when TemPad is unavailable, a `get_code` call warns +or fails, or the requested selection cannot fit in one trustworthy response. + +## Connection and target failures + +For a transient transport failure, retry once. Do not blind-retry invalid +selection, hidden node, wrong file, deterministic budget, or depth errors. + +If TemPad is unavailable or active on the wrong file, stop and ask the user to: + +1. enable MCP access in TemPad Dev **Preferences > Agent integration**; +2. keep the intended TemPad Dev and Figma tab active; +3. use the MCP badge in the panel to activate the intended file when multiple + Figma tabs are open. + +Do not edit code while design evidence is untrustworthy. + +## Incomplete `get_code` results + +Preserve the largest trustworthy parent composition and narrow only the +missing evidence: + +- **`depth-cap`**: keep the returned top-level composition, then use returned + `data-hint-id` values for targeted child `get_code` calls. +- **budget overflow or shell response**: keep the returned parent shell, then + fetch omitted children separately. Use the smallest parent that still proves + their shared layout. Plain string truncation is not evidence. +- **hierarchy, geometry, or overlap uncertainty**: call TemPad Dev's + `get_structure` only to resolve that uncertainty or select a narrower retry + target. + +Never rebuild a missing parent from child metadata. If no trustworthy parent +shell can be recovered, stop the full implementation and ask the user to +narrow the selection or choose the highest-priority subtree. + +If a budget error requires user action, report its consumption, limit, and +overage from the tool response. + +## Resolve contradictions + +Prefer the evidence source with authority over the disputed fact: project +evidence for implementation conventions, `get_code` for visible design, and +the user for product intent. Narrow the read once when the conflict may be a +scope problem. If the sources still disagree, stop rather than choose silently. + +## Worked example + +When a large frame returns a usable header-and-grid shell but omits three cards, +keep the shell as the parent layout, fetch only those card subtrees, and insert +them into the known grid. If the response contains cards but no trustworthy +grid shell, do not infer columns or spacing from `get_structure`; request a +narrower parent selection. diff --git a/agent-plugin/targets/codex/.codex-plugin/plugin.json b/agent-plugin/targets/codex/.codex-plugin/plugin.json new file mode 100644 index 00000000..833ede6f --- /dev/null +++ b/agent-plugin/targets/codex/.codex-plugin/plugin.json @@ -0,0 +1,47 @@ +{ + "name": "tempad-dev", + "version": "0.2.0", + "description": "Connect your coding agent to Figma. Create and edit native designs, inspect existing designs, and implement UI in your codebase.", + "author": { + "name": "TemPad Dev" + }, + "homepage": "https://github.com/ecomfe/tempad-dev#agent-integration", + "repository": "https://github.com/ecomfe/tempad-dev", + "license": "MIT", + "keywords": [ + "figma", + "mcp", + "skill", + "agent-integration", + "design-to-code", + "canvas-authoring", + "design-system", + "frontend" + ], + "skills": "./skills/", + "interface": { + "displayName": "TemPad Dev", + "shortDescription": "Inspect, edit, and implement Figma designs with your agent.", + "longDescription": "TemPad Dev connects your coding agent to Figma. Read designs, components, variables, and assets; create and edit native Figma layers; and implement existing designs using your project’s conventions. Includes the MCP connection and skills for canvas editing and design-to-code. Requires the TemPad Dev browser extension; canvas editing also requires edit access to the Figma Design file.", + "developerName": "TemPad Dev", + "category": "Design", + "capabilities": [ + "Agent integration", + "MCP", + "Design-to-code", + "Canvas authoring", + "Design systems", + "Frontend" + ], + "websiteURL": "https://github.com/ecomfe/tempad-dev", + "defaultPrompt": [ + "Implement the selected Figma design using this project’s components and styles.", + "Create an editable settings screen in Figma using the available components.", + "Update the spacing and typography in this Figma design." + ], + "brandColor": "#0098FF", + "composerIcon": "./assets/icon-padded.svg", + "logo": "./assets/icon-padded.svg" + }, + "mcpServers": "./.mcp.json" +} diff --git a/agent-plugin/targets/codex/.mcp.json b/agent-plugin/targets/codex/.mcp.json new file mode 100644 index 00000000..3789c234 --- /dev/null +++ b/agent-plugin/targets/codex/.mcp.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "tempad-dev": { + "command": "npx", + "args": [ + "-y", + "@tempad-dev/mcp@latest" + ] + } + } +} diff --git a/agent-plugin/targets/codex/CHANGELOG.md b/agent-plugin/targets/codex/CHANGELOG.md new file mode 100644 index 00000000..1e9275fc --- /dev/null +++ b/agent-plugin/targets/codex/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +## 0.2.0 + +- Routed the `plugins` CLI through its own hook-free compatibility package and marketplace, + with installer discovery checks for both skills and MCP configuration. +- Added design-task lifecycle guidance and Stop/Done controls. Codex App uses MCP metadata and + native IPC without hooks; Claude uses installed lifecycle and Stop hooks. +- Documented native Codex App comments, Queue/Steer timing, and element-editor Save & Queue + shortcuts. Other clients retain task controls without comment delivery. + +- Added `figma-canvas-authoring` for creating and editing native Figma designs, alongside the + existing `figma-design-to-code` skill. +- Added progressive references for native authoring, fonts, images, icons, resource bindings, + and scoped editing. Direct, Reuse, and Author workflows keep resource decisions tied to the task. +- Grounded new compositions in inspectable evidence and required inspection of the rendered result + plus relevant native facts, with focused repair of observed defects. +- Made the portable Agent Plugins 1.0 bundle the shared source for installation, with synchronized + Codex and Claude compatibility manifests and refreshed icons. +- Paired the plugin with extension 0.21.0 and MCP 0.8.0 through `@tempad-dev/mcp@latest`. + The MCP server requires Node.js 22.x, 24.x, or 26+. diff --git a/agent-plugin/targets/codex/README.md b/agent-plugin/targets/codex/README.md new file mode 100644 index 00000000..3e7d6d69 --- /dev/null +++ b/agent-plugin/targets/codex/README.md @@ -0,0 +1,173 @@ +# TemPad Dev Agent Plugin + +[Simplified Chinese](./README.zh-Hans.md) + +Read, edit, and implement Figma designs through your coding agent or IDE. This plugin includes: + +- `figma-canvas-authoring`: create and revise native Figma designs, reusing accessible components, variables, and styles as needed. +- `figma-design-to-code`: use Figma design context to implement UI with your project’s components and conventions. +- The TemPad Dev MCP server configuration: connect to the Figma file open in your browser. + +Requires the TemPad Dev browser extension. Canvas editing also requires edit access to the Figma Design file. For manual inspection and output plugins, see the full [user guide](https://github.com/ecomfe/tempad-dev/blob/main/README.md). + +This plugin follows [Agent Plugins 1.0](https://agent-plugins.org/) and is published from one +source as a standard package, a compatibility package for the `plugins` CLI, and a package per +native host. Prefer native installation on Codex and Claude. Codex App binds tasks over MCP +metadata and native IPC, so its plugin registers no lifecycle hooks. + +## Cursor and VS Code installation + +For Cursor and VS Code, select the corresponding target: + +```bash +npx plugins add ecomfe/tempad-dev --target cursor +npx plugins add ecomfe/tempad-dev --target vscode +``` + +The installer reads `.plugin/marketplace.json` and installs the generated `plugins-cli` +compatibility package, which contains both skills and MCP configuration without lifecycle hooks. +This path is verified with `plugins@1.3.4`. Agent Plugins 1.0 consumers can use the separate +`agent-plugin/targets/standard` package; the current `plugins` CLI does not read that format. + +## Codex and Claude installation + +Use these native marketplace flows for Codex and Claude. Claude's lifecycle hooks require +the host's normal trust review; Codex does not register hooks. +The `--sparse` paths limit checkout to the host's marketplace and generated package, including +its skills and any required hooks. Codex repeats `--sparse` for each path; Claude accepts multiple +paths after one `--sparse`. The `plugins` CLI used for Cursor and VS Code has no equivalent flag. + +### Codex + +```bash +codex plugin marketplace add ecomfe/tempad-dev --ref main --sparse .agents --sparse agent-plugin/targets/codex +codex plugin add tempad-dev@tempad-dev +``` + +You can also install **TemPad Dev** from the Codex app plugin directory after adding the +marketplace. + +### Claude Code and Claude Desktop + +```bash +claude plugin marketplace add ecomfe/tempad-dev --sparse .claude-plugin agent-plugin/targets/claude +claude plugin install tempad-dev@tempad-dev +``` + +The plugin appears in Claude Desktop after the marketplace is added. + +For clients without Agent Plugin support, follow the direct MCP and standalone skill setup in the +[complete setup guide](https://github.com/ecomfe/tempad-dev/blob/main/README.md#agent-integration). + +## Usage + +Before using the integration, open TemPad Dev in Figma, then open **Preferences → Agent +integration** and enable **MCP access**. Canvas authoring is available while the active Figma +Design file is editable. + +## Upgrading + +The canvas-authoring release pairs Agent Plugin **0.2.0**, TemPad Dev extension **0.21.0**, and +MCP server **0.8.0**. Node.js **22.x, 24.x, or 26+** is required for the MCP server. + +1. Update the browser extension and reload the Figma tab. +2. Update the installed plugin through the client or installer used originally. With standalone + setup, update both `figma-design-to-code` and `figma-canvas-authoring`. +3. Keep the release MCP configuration on `@tempad-dev/mcp@latest`; replace any previous + `@alpha` or fixed alpha version. Reconnect the MCP client and start a new task so it loads the + updated tools and skills. If a stale Hub is reported, close tasks using the old MCP server + before reconnecting. +4. Open TemPad Dev, enable **MCP access**, and click the MCP badge in the intended Figma tab when + a session choice is needed. The badge selects the file receiving tool calls. + +## Packaging source of truth + +Everything is authored once under `agent-plugin/src/` and published by +`pnpm agent-plugin:build`. Every target is generated; never edit one. + +| Path | Role | +| ---------------------------------- | ------------------------------------------------- | +| `agent-plugin/src/plugin.json` | Standard manifest; owns all shared metadata | +| `agent-plugin/src/mcp.json` | Standard MCP configuration | +| `agent-plugin/src/skills/` | Both skills | +| `agent-plugin/src/clients/claude/` | Claude lifecycle hooks | +| `agent-plugin/src/clients/codex/` | Codex directory presentation (`interface.json`) | +| `agent-plugin/src/clients/shared/` | Hook transport shared by hosts | +| `agent-plugin/targets/standard` | Generated; also the standalone skills URL | +| `agent-plugin/targets/plugins-cli` | Generated compatibility package for `plugins` CLI | +| `agent-plugin/targets/codex` | Generated Codex marketplace package | +| `agent-plugin/targets/claude` | Generated Claude marketplace package | + +Each target carries only what its own installer reads. A standard consumer projects `plugin.json` +onto the host itself, so shipping a host layout beside it would create a second source of truth for +the same package; each host target likewise omits the standard manifests and the other host's +directory. Only Claude loads lifecycle hooks, so only `targets/claude` carries `clients/`. +The `plugins-cli` package carries `.plugin/plugin.json` and `.mcp.json`; its marketplace is +generated separately so the CLI does not select the Claude package. Verify discovery through +the actual CLI with `pnpm agent-plugin:check-installer` after changing packaging. + +## Task controls and client enhancements + +Design tasks can pause and resume across turns. Figma's canvas status bar shows the +source client, a Stop control, and a counted comment entry. Stop permanently cancels +the current task; subsequent design work explicitly begins a fresh task. Lifecycle pauses can resume +with a new lease epoch and require a fresh canvas read before writing. See the +[task and client design](https://github.com/ecomfe/tempad-dev/blob/main/docs/extension/mcp-design-tasks.md). + +The normal setup is the TemPad Dev extension configuration followed by this plugin's +installation. There are no control +addresses, environment variables, or helper services for users to configure. + +Codex App binds tasks from host-supplied MCP metadata and follows native conversation +state through the existing IPC connection. Claude retains lifecycle and Stop hooks. +Comments are delivered only through native conversation messages on compatible Codex App +hosts. TemPad Dev discovers the original conversation through the App's existing local +connection. Where supported, Queue submits the batch to the host's native queue, where it waits until the +conversation is ready. As soon as the host confirms admission, TemPad Dev clears the submitted +comments and markers, stops the sending indicator, and allows another batch. This confirmation +means the host received the comments, not that the agent finished the requested changes. +When native queue admission is unavailable, Queue waits in the Hub for existing queued +messages to clear and the conversation to accept a new response. The sending indicator +remains until that admission is confirmed. If queue state cannot be checked, comments +remain saved and delivery reports an error. Compatible hosts also support native server-queue +admission; these messages may appear in Codex after its next queue refresh. +Steer adds comments to an active response or starts a response when the conversation is idle. +Failed or uncertain delivery retains drafts; uncertain delivery is not automatically resent. +Comments never fall back to hooks. + +| Editor | Enter or click the submit button | Command/Ctrl+Enter or Command/Ctrl+click | +| --------------------------------- | -------------------------------- | ---------------------------------------- | +| Element comment | Save the comment without sending | Save & Queue the whole batch | +| General comment in the status bar | Queue the whole batch | Steer the whole batch | + +A batch includes all saved element comments and the general comment. Shift+Enter inserts a +newline in either editor. Saving an element comment alone does not send it. + +Claude, Codex CLI, and other clients currently provide task status and Stop/Done without +comment controls. Previously saved drafts remain in extension-local storage. + +Stop immediately blocks further writes from the current task and permanently cancels it +once an executing operation drains. The cancelled task cannot resume. The agent respects +Stop without automatically replacing it; necessary or user-requested design work can +explicitly begin a fresh task. No separate Figma unlock is needed. Codex App Stop also +requests native interruption of the exact bound turn; a delayed Stop cannot interrupt a +newer turn. Stop and Done also remove this task's comments that are still in the native queue, +leaving unrelated messages intact. Failed cleanup is retried after reconnection; already consumed +input cannot be recalled. Local cancellation remains effective if the host is unavailable. Claude +conveys Stop at the next hooked tool boundary. Native Codex delivery is enabled +only after the exact conversation owner reports support; no manual connection setup +is required. See the task and client design for the current validation scope. + +The native adapter uses Unix sockets on macOS/Linux and Codex's local named pipe on Windows. +macOS Steer and paused native queue admission/removal have been exercised against Codex App +26.908.70816. Automatic queue execution and the complete installed-plugin/Figma UI flow still +require live verification. Windows and Linux coverage is limited to source inspection and +automated tests; it does not establish complete host support. + +With a supported connection, select an element, save its feedback draft, then send the +numbered batch from the canvas status bar. Drafts can be edited or deleted and survive +navigation and closed tabs in extension-local storage, isolated by file, agent conversation, and task. +Successful delivery clears the submitted markers together; restoring drafts never sends them. + +The agent reports the result and its Figma link in the conversation, where users can +continue with follow-up requests. Task tools return text and structured data. diff --git a/agent-plugin/targets/codex/README.zh-Hans.md b/agent-plugin/targets/codex/README.zh-Hans.md new file mode 100644 index 00000000..bc5feda9 --- /dev/null +++ b/agent-plugin/targets/codex/README.zh-Hans.md @@ -0,0 +1,130 @@ +# TemPad Dev Agent Plugin + +[English](./README.md) + +在你的 coding agent 或 IDE 中读取、编辑和实现 Figma 设计。这个插件包含: + +- `figma-canvas-authoring`:创建和修改原生 Figma 设计,按任务需要复用可访问的组件、变量和样式。 +- `figma-design-to-code`:读取 Figma 设计信息,结合项目已有组件和约定实现 UI。 +- TemPad Dev MCP server 配置:连接浏览器中打开的 Figma 文件。 + +需要安装 TemPad Dev 浏览器扩展。画布编辑还需要 Figma Design 文件的编辑权限。手动检查设计和输出插件的完整说明见 [使用指南](https://github.com/ecomfe/tempad-dev/blob/main/README.zh-Hans.md)。 + +本插件遵循 [Agent Plugins 1.0](https://agent-plugins.org/),并从同一份内容源发布一个标准包 +(供自行适配该标准的客户端使用)、一个 `plugins` CLI 兼容包,以及每个原生宿主各一个包。Codex 与 Claude 请优先使用原生安装。 +Codex App 通过 MCP 元数据和原生 IPC 绑定任务,其插件不注册生命周期 hooks。 + +## Cursor 和 VS Code 安装 + +Cursor 和 VS Code 请指定对应的 target: + +```bash +npx plugins add ecomfe/tempad-dev --target cursor +npx plugins add ecomfe/tempad-dev --target vscode +``` + +安装器读取 `.plugin/marketplace.json`,安装生成的 `plugins-cli` 兼容包,其中包含两个 skill +和 MCP 配置,不包含生命周期 hooks。此路径已通过 `plugins@1.3.4` 验证。支持 Agent Plugins 1.0 +的客户端可使用独立的 `agent-plugin/targets/standard` 标准包;当前 `plugins` CLI 不读取该格式。 + +## Codex 和 Claude 安装 + +使用以下原生 marketplace 流程。Claude 提示时,请检查并信任插件的生命周期 hooks;Codex 不注册 hooks。 +`--sparse` 将检出范围限制为对应宿主的 marketplace 和生成包,包含所需的 skill 及 hooks。 +Codex 为每个路径重复指定 `--sparse`;Claude 在一个 `--sparse` 后接受多个路径。 +Cursor 和 VS Code 使用的 `plugins` CLI 没有对应参数。 + +### Codex + +```bash +codex plugin marketplace add ecomfe/tempad-dev --ref main --sparse .agents --sparse agent-plugin/targets/codex +codex plugin add tempad-dev@tempad-dev +``` + +添加 marketplace 后,也可以从 Codex 应用的插件目录安装 **TemPad Dev**。 + +### Claude Code 和 Claude Desktop + +```bash +claude plugin marketplace add ecomfe/tempad-dev --sparse .claude-plugin agent-plugin/targets/claude +claude plugin install tempad-dev@tempad-dev +``` + +添加 marketplace 后,该插件也会出现在 Claude Desktop 中。 + +不支持 Agent Plugin 的客户端,请按照 +[完整配置指南](https://github.com/ecomfe/tempad-dev/blob/main/README.zh-Hans.md#agent-集成)直接配置 MCP 并安装独立 skill。 + +## 使用 + +使用前,请在 Figma 中打开 TemPad Dev,然后进入 **Preferences → Agent integration** +并启用 **MCP access**。启用后,只要当前 Figma Design 文件可编辑,即可进行画布创作。 + +设计任务的状态栏显示 agent 状态、Stop/Done 和评论入口。Stop 会立即阻止当前任务继续写入, +在执行中的操作结束后永久取消该任务;重新连接也不会恢复它。后续设计工作需要明确开始新任务。 + +评论目前仅支持通过兼容 Codex App 的原生会话通道发送。Queue 将整批评论交给宿主的原生队列, +等待会话可以执行时再处理。宿主确认接收后,TemPad Dev 会清空本批评论和标记、停止发送指示, +并允许继续输入下一批;这表示已接收,不表示 agent 已完成修改。如果原生入队不可用, +Queue 会在 Hub 中等待已有排队消息清空、会话能接收新回复,此时发送指示会保留到确认接收。 +如果无法确认队列状态,会保留评论并报告发送错误。兼容宿主也支持原生服务端队列入队, +这些消息可能会在 Codex 下一次刷新队列时才显示。 +Steer 会将评论追加到正在执行的回复,空闲时直接开始新回复。投递失败或结果不确定时保留草稿, +结果不确定的评论不会自动重发,也不会回退到 hooks。 + +| 编辑位置 | Enter 或点击提交按钮 | Command/Ctrl+Enter 或 Command/Ctrl+点击 | +| ------------------ | -------------------- | ---------------------------------------- | +| 元素评论 | 保存当前评论,不发送 | Save & Queue:保存当前评论并排队整批评论 | +| 状态栏中的总体评论 | 排队整批评论 | 使用 Steer 发送整批评论 | + +整批评论包含全部已保存的元素评论和总体评论;两个编辑器中都可以用 Shift+Enter 换行。 +草稿按文件、会话和任务隔离,关闭标签页后仍保留,恢复草稿不会自动发送。 + +Codex App 的任务绑定和状态同步使用 MCP 元数据及原生 IPC,不依赖 hooks。Stop 还会请求中断 +对应的 Codex 回合,迟到的 Stop 不会中断较新的回合。Stop 和 Done 会移除当前任务尚未执行的 +原生队列评论,保留其它消息;清理失败后会在重新连接时重试,已被宿主取走的输入无法撤回。 +宿主不可用时,本地取消仍然生效。Claude 保留生命周期和 Stop 通知 hooks;Claude、Codex CLI +等尚未接入原生投递的客户端提供任务状态和 Stop/Done,但不显示评论入口,已有草稿不会删除。 + +原生适配器在 macOS/Linux 上使用 Unix socket,在 Windows 上使用 Codex 的本机 Named Pipe。 +已在 macOS Codex App 26.908.70816 上实测 Steer,以及暂停状态下的原生队列入队和移除。 +自动执行和完整的已安装插件/Figma UI 流程仍待实测;Windows/Linux 的证据限于源码检查和 +自动化测试,尚不能据此宣称完整宿主支持。 + +## 升级 + +本次画布创作版本应配套使用 Agent Plugin **0.2.0**、TemPad Dev 扩展 **0.21.0** 和 MCP +server **0.8.0**。MCP server 要求 Node.js **22.x、24.x 或 26+**。 + +1. 更新浏览器扩展,并重新加载 Figma 标签页。 +2. 通过原先使用的客户端或安装器更新 plugin。独立配置时,请同时更新 + `figma-design-to-code` 和 `figma-canvas-authoring`。 +3. 正式版 MCP 配置使用 `@tempad-dev/mcp@latest`;请替换旧的 `@alpha` 或固定 alpha 版本。 + 重新连接 MCP client 并新建任务,以加载更新后的工具和 skill。若提示 Hub 过期,请先关闭 + 使用旧 MCP server 的任务,再重新连接。 +4. 打开 TemPad Dev 并启用 **MCP access**;需要选择会话时,点击目标 Figma 标签页内的 MCP + badge。实际接收工具调用的文件由该 badge 选择。 + +## 封装内容源 + +所有内容只在 `agent-plugin/src/` 下编写一次,由 `pnpm agent-plugin:build` 生成各个产物。 +所有产物都是生成的,请勿直接编辑。 + +| 路径 | 作用 | +| ---------------------------------- | -------------------------------------- | +| `agent-plugin/src/plugin.json` | 标准清单,拥有全部公共 metadata | +| `agent-plugin/src/mcp.json` | 标准 MCP 配置 | +| `agent-plugin/src/skills/` | 两个 skill | +| `agent-plugin/src/clients/claude/` | Claude 生命周期 hooks | +| `agent-plugin/src/clients/codex/` | Codex 目录展示信息(`interface.json`) | +| `agent-plugin/src/clients/shared/` | 宿主共用的 hook 传输脚本 | +| `agent-plugin/targets/standard` | 生成产物,同时是独立 skills 的安装地址 | +| `agent-plugin/targets/plugins-cli` | 为 `plugins` CLI 生成的兼容包 | +| `agent-plugin/targets/codex` | 生成的 Codex marketplace 包 | +| `agent-plugin/targets/claude` | 生成的 Claude marketplace 包 | + +每个产物只携带自己的安装方式会读取的内容。标准客户端会自行把 `plugin.json` 适配到宿主, +因此在它旁边放置宿主清单会让同一个包出现第二个事实来源;两个宿主产物同理省略标准清单 +以及对方宿主的目录。只有 Claude 会加载生命周期 hooks,因此只有 `targets/claude` 携带 `clients/`。 +`plugins-cli` 包使用 `.plugin/plugin.json` 和 `.mcp.json`,由独立生成的 marketplace 入口路由, +避免 CLI 选中 Claude 包。修改封装后运行 `pnpm agent-plugin:check-installer`,验证实际 CLI 的发现结果。 diff --git a/agent-plugin/targets/codex/assets/icon-padded.svg b/agent-plugin/targets/codex/assets/icon-padded.svg new file mode 100644 index 00000000..2e8c6946 --- /dev/null +++ b/agent-plugin/targets/codex/assets/icon-padded.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/agent-plugin/targets/codex/assets/icon.png b/agent-plugin/targets/codex/assets/icon.png new file mode 100644 index 00000000..5d1f6bf2 Binary files /dev/null and b/agent-plugin/targets/codex/assets/icon.png differ diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/SKILL.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/SKILL.md new file mode 100644 index 00000000..7732c78f --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/SKILL.md @@ -0,0 +1,183 @@ +--- +name: figma-canvas-authoring +description: >- + Create or update native, editable Figma designs with TemPad Dev MCP: screens, + flows, components, and requested local design-system resources, including on + an empty canvas. Use for Design in Figma work, not Figma-to-code, critique + without edits, or raw Plugin API automation. +--- + +# Design in Figma + +Deliver the smallest complete native Figma result that serves the user's +situation. Keep the working experience in view as you research, compose, and +repair. A successful tool call establishes a document change; the rendered +result and its editable structure establish whether that change served the task. + +## Establish the task + +Use the user's exact target and constraints. For an existing design, inspect +`get_code` and its pixels before changing the composition; use `get_structure` +for hierarchy, geometry, stable keys, or selected native facts. Write to a known +page directly. Create or activate a page only when the task calls for it. +Infer low-consequence gaps; ask when a missing decision would materially change +the result. Keep unrelated account, filesystem, task, and page metadata out of +product identity and content. + +Require an editable Figma Design file and the intended tab's active MCP +connection. Use the host's TemPad MCP tools for all canvas reads and writes. +If unavailable, report the integration problem and stop. Do not launch the CLI, +recreate its transport, use browser automation to set up the canvas, or emit raw +Plugin API operations. Research and asset acquisition use the host's appropriate +tools; website research uses the in-app browser when available unless the user +selected another browser. + +For new design work, call `begin_design` before research or canvas work with a short task title +and a fresh UUID `requestId`; reuse that UUID only to retry the same begin. Carry +the returned `taskId` on related TemPad tool calls. The runtime handles status and +placement feedback: do not report progress, send heartbeats, or choose coordinates +for a placeholder. Use `list_design_sessions` when the intended Figma target is +unclear, then pass its exact `sessionId` to `begin_design`. Pausing a turn preserves +the design task. Follow-up comments continue the same task, including after a completed +pass while its review remains open. After completion, pause, or lease expiry, use `resume_design` with its latest +`epoch`, carry the returned epoch as `taskEpoch`, and reread the affected canvas +with `get_structure` or `get_code` before writing. Use `get_design_task` only when +recovery needs the current state or epoch. Never replay a stale write. Stop in TemPad Dev +permanently cancels the current task after any running operation settles. Never resume +that cancelled task or automatically replace it. If further design work is necessary or +the user requests it, explicitly call `begin_design` with a fresh requestId. No separate +Figma unlock or new user turn is required. Done closes the review; a closed or replaced +task cannot resume. Do not automatically begin a replacement for comments on such a task. +Element feedback arrives as a numbered batch. Each item retains its file, page, +and node identity from draft creation. Reread every target before applying the +batch; do not substitute the current selection. +Supported hosts receive submitted feedback through native conversation messages. Do not poll for it or +set up a helper process or host control endpoint. + +Begin without waiting to choose a canvas location. Once an existing design region is +known, use `set_design_anchor` with its exact Frame node ID and `taskId`. Otherwise +the first created top-level Frame anchors automatically. The region stays stable +across reads and writes; call this tool again only to explicitly change design regions. + +## Ground and compose + +For net-new or materially redesigned interfaces without an established system, +read [style-grounding.md](references/style-grounding.md) and inspect relevant +real product screens or a permitted implementation before the first Canvas +write. The evidence must expose the interface relationships informing the new +work. Search snippets, URLs, failed retrievals, and generated concepts do not +establish a precedent. Subject imagery establishes its depicted content, not +its surrounding application's design. Try another permitted source when +retrieval fails; if none is inspectable, disclose the gap and stop. Supplied +source pixels or implementation can satisfy this boundary; mechanical edits do +not require unrelated research. + +Resolve what the person needs to recognize or change, which content and states +carry that work, and how the interface makes their consequences perceptible. +Choose the screen or flow, visual language, density, and scrolling model from +that situation. Use [visual-composition.md](references/visual-composition.md) +when forming or reconsidering a composition. Familiar structures and distinctive +ones both need a reason in the task. Research informs an independent solution; +it does not authorize copying a composition or placing reference pixels on the +canvas unless the user requested that treatment. + +When selecting or changing fonts, or when script coverage is uncertain, read +[typefaces.md](references/typefaces.md) to resolve candidates and native identities. + +Choose representations by their role in the work. Once an image, icon, diagram, +or visualization matters to the direction, read +[visual-assets.md](references/visual-assets.md) and its selected branch. Do not +silently replace the chosen content or medium to simplify sourcing or markup. +For content-bearing graphics, preserve meaningful marks and editable +relationships with native shapes, vectors, text, and groups; styled FRAME +lookalikes do not acquire drawing semantics. Read +[document-geometry.md](references/document-geometry.md) for that construction. +Ordinary UI panels, controls, backgrounds, and separators remain Canvas HTML. + +Choose resources from the task, not repetition alone: + +- **Direct:** default for a first net-new composition. Use primitives, literals, + and assets. Do not discover or create a design system just because shapes or + values repeat. +- **Reuse:** use [design-system-reuse.md](references/design-system-reuse.md) when + the user, selected source, or project evidence establishes the applicable + system. Catalog names, domain similarity, or mere file presence do not prove + relevance. +- **Author:** use [design-system-authoring.md](references/design-system-authoring.md) + when reusable resources are requested or established as part of the + deliverable. Prove the composition and one real consumer before propagation. + +For selected variables and typography styles, read +[resource-mapping.md](references/resource-mapping.md): define or discover their +identities once, then use variable utilities and text-style classes throughout +the markup. + +## Build, inspect, and repair + +For markup create or structural update, read +[canvas-html.md](references/canvas-html.md) and check its preflight before the +call. Canvas HTML is a strict native-state dialect; browser CSS assumptions do +not apply. Page-only and native-only operations omit markup. Load native +mechanics only for the capabilities selected below. + +Build a materially complete representative screen, then open its PNG before +expanding the flow or extracting resources. Judge whether the whole supports +the intended work. When it does not, focus on the particular relationship or +execution defect that explains the mismatch and repair it. A skeleton, resource +board, or generated concept does not establish the real composition. + +For updates, read [editing.md](references/editing.md). Preserve the requested +source, unrelated fields, and stable identities while updating every dependent +representation of the changed state. For larger results, split at meaningful +screen or section boundaries and carry shared roles coherently across them. + +Inspect every `apply_canvas` result, including warnings. Repair each observed +unintended defect or disclose why it remains. A local validation failure calls +for a local payload correction; it does not justify discarding a working root +or simplifying away the intended content. Open pixels again after the final +material write, covering every materially distinct screen. Verify native facts +with `get_structure` when identity, placement, editability, or representation +matters. Opened pixels prove visual access, not good judgment; a structural pass +proves only the conditions checked. + +Finish when the requested experience is coherent and observed defects are +repaired, accepted with reason, or disclosed. Report the delivered result and +material limitations, with a Figma link to the delivered nodes. A verified Direct +result is complete without an unsolicited component pass. + +Call `end_design` after the design outcome and its final verification are complete. +An optional short `summary` records the applied result in task history. +Use `outcome: "cancelled"` only when abandoning the design. Waiting for user input +or stopping a turn is a pause, not completion or cancellation. Host lifecycle hooks +handle pauses when available; do not create progress or heartbeat calls. + +## Native mechanics — load when selected + +Read the selected reference completely; do not preload the capability catalog. +Examples demonstrate syntax, not a design template. + +| Capability | Reference | +| --------------------------------------------------------------------- | ----------------------------------------------------------- | +| Exact updates, removal, or editor context | [editing.md](references/editing.md) | +| Pages, sections, groups, Booleans, masks, transforms, shapes, vectors | [document-geometry.md](references/document-geometry.md) | +| Paints, media, effects, shaders, grids, guides | [paints-effects.md](references/paints-effects.md) | +| Exact fonts, rich text, range styles, lists, hyperlinks | [rich-text.md](references/rich-text.md) | +| Components, variants, properties, Slots | [component-authoring.md](references/component-authoring.md) | +| Variables, collections, modes, bindings | [variables.md](references/variables.md) | +| CSS variable utilities and named text-style classes | [resource-mapping.md](references/resource-mapping.md) | +| Paint, Text, Effect, Grid styles | [local-styles.md](references/local-styles.md) | +| Authorized independent research, assets, inventory, or QA delegation | [delegation.md](references/delegation.md) | + +## Mutation boundaries + +Use returned IDs and stable keys as identity, never names. Create describes a +new complete root or exact new page. Update targets an exact node or page; +omissions preserve live state. `activate` always requires `page.id` or +`page.pageKey`, even when only changing selection. + +Never mutate outside scope, remove manual or unkeyed content, or remove a +component with surviving instances. An instance's definition-derived sublayers +are not authoring targets. Do not mutate remote resources, publish, detach or +reset instances, execute arbitrary JavaScript, or imitate an unresolved +resource. Use `null` only for supported links or managed resources the requested +change actually removes. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/agents/openai.yaml b/agent-plugin/targets/codex/skills/figma-canvas-authoring/agents/openai.yaml new file mode 100644 index 00000000..25e5075e --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/agents/openai.yaml @@ -0,0 +1,7 @@ +interface: + display_name: 'Design in Figma' + short_description: 'Create user-directed native Figma designs' + icon_small: './assets/icon.svg' + icon_large: './assets/icon.svg' + brand_color: '#0098FF' + default_prompt: 'Use $figma-canvas-authoring to create a native Figma design while following my resource constraints.' diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/assets/icon.svg b/agent-plugin/targets/codex/skills/figma-canvas-authoring/assets/icon.svg new file mode 100644 index 00000000..2e8c6946 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/assets/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/canvas-html.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/canvas-html.md new file mode 100644 index 00000000..2cc27632 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/canvas-html.md @@ -0,0 +1,277 @@ +# Canvas HTML and Tailwind subset + +Canvas HTML describes desired state, not browser rendering. Use its elements for +interface structure and genuine simple UI geometry, not as a drawing medium. +Do not assemble `div` or `span` primitives to imitate a photograph, +illustration, icon, logo, texture, or other content-bearing visual; acquire the +appropriate routed raster or vector asset instead. Classes do not cover every +Figma result: use routed native bindings for gradients, media, non-shadow +effects, masks, transforms, exact fonts, and rich text. + +One `apply_canvas` markup tree may contain at most 160 elements and 12 levels. +This is a safety ceiling, not a target. Before calling, count the tree, include +only assets referenced by that call, and split larger work at meaningful screen +or section boundaries. + +Prefer supported Tailwind utilities; use arbitrary pixels only off the default +scale. Numeric spacing follows Tailwind v4's `4px` unit. Selected Figma resources +can use CSS variable utilities and `type-*` text-style classes through +[resource-mapping.md](resource-mapping.md). Arbitrary project theme extensions, +variants, plugins, viewport-dependent utilities, and CSS cascade are unsupported. + +## Contents + +- [Preflight each markup tree](#preflight-each-markup-tree) +- [Elements and identity](#elements-and-identity) +- [Layout](#layout) +- [Appearance and text](#appearance-and-text) + +## Preflight each markup tree + +Immediately before each create or structural update, scan the complete supplied +tree once: + +- require a fixed width and height on the markup root; +- give every `div` with children `flex` or `grid`, or make every child absolute + with one edge per axis and fixed parent and child dimensions; +- keep flex, grid, gap, padding, border, corner, and box-shadow classes off + `span`; +- resolve defaults and overrides before assembling each class list. Both + `text-[16px] text-[18px]` and `text-black text-white` are conflicts, not + overrides. A helper must choose the final font size, color, and line height + instead of appending them to hard-coded defaults; +- trace every `w-full`, `h-full`, and `grow` against its direct parent's axis and + the element's required dimensions; +- give a fixed-height grid explicit row tracks when its children should fill or + divide that height; omitted rows remain content-sized; +- count at most 160 elements and 12 levels, and include only assets referenced by + this call. + +Correct the complete set before calling instead of serializing until validation +reveals issues one at a time. + +## Elements and identity + +- Use `div`, `span`, or a component tag returned by the active catalog. +- Give every element one unique `data-key` of letters, numbers, `. / : _ -`. +- Use `data-node-id` only in update mode to adopt an exact live node; instance + sublayers are not authoring targets. +- When markup is supplied, every `native` key must occur as a `data-key` in that + supplied tree; existence elsewhere in the live target does not satisfy this. + For mixed structural/native edits, include each bound node under its actual + parent path, or send the omitted nodes' changes in a separate native-only update. + When only native state changes, omit markup, target the exact managed root, + and key `native` by existing stable keys in that scope. This preserves topology; + masks and node removal still require structural markup. +- Use no arbitrary attributes on `div` or `span`. Common catalog links use + `data-var-="vN"` and `data-style-="sN"`; `"none"` explicitly + unlinks that field. +- A `span` contains only text and `
` or `
` line breaks. Use + `whitespace-pre-wrap` for literal newlines or repeated spaces. A plain `&` is + literal unless it forms a semicolon-terminated entity; supported entities + decode. Canvas typography does not inherit from a parent `div`: put font and + other text utilities on each `span`/TEXT node. Put flex/grid, gaps, padding, + borders, corners, and box shadows on a parent `div`. +- A component tag is childless, includes its returned `data-ref`, and accepts + returned props plus the shared class, identity, variable, and style + attributes. + +Variable attributes use kebab-case native field names: fill, stroke, characters, +visible, dimensions/bounds, gaps, four paddings/corners/stroke sides, radius, +stroke weight, opacity, and whole-node font/line-height/letter-spacing/paragraph +fields. Style attributes are `data-style-fill`, `data-style-stroke`, +`data-style-text`, `data-style-effect`, and `data-style-grid`. Node-type and +fallback rules still apply. + +Every primitive needs one width and one height. Supported fixed forms are: + +- default spacing: `w-N`, `h-N`, `size-N` (`N * 4px`), plus `w-px`, `h-px`, `size-px` +- default width containers: `w-3xs|2xs|xs|sm|md|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl` +- exact: `w-[Npx]`, `h-[Npx]`, `size-[Npx]` +- hug: `w-fit`, `h-fit` +- hug both axes: `size-fit` +- fill: `w-full`, `h-full`, or `size-full` for both axes +- bounds: numeric, `px`, or arbitrary-pixel values with `min-w`, `max-w`, `min-h`, or `max-h`; + width bounds also accept the default container names; use `min-w-none`, `max-w-none`, + `min-h-none`, or `max-h-none` to clear a bound in an update + +Text using `w-fit` also needs `h-fit`; prefer `size-fit`. Fixed-width `h-fit` +remains valid for wrapping text. + +Create and update markup roots require fixed width and height; fill, hug, and +grow are invalid even when the live target has a sized parent. + +Use `w-full` only on a `flex-col` cross axis, `h-full` only on a `flex-row` +cross axis, and `grow` on the main axis; `grow-0` clears growth. `grow` does not +replace required dimensions—for a row track use `grow w-fit h-[3px]`. Give +growing text in constrained rows a positive `min-w-*` to prevent collapse. +Prefer a hug main axis for content stacks whose extent is not behaviorally +fixed. Otherwise budget the fixed axis as padding + gaps + fixed/minimum child +extents. A non-overflowing result is still wrong when resolved content consumes +the intended inset; compare rendered child edges with the layout's padding. +Grid children may fill cells. Direct dimension variables require fixed +fallbacks. Fixed sizes must be at least `0.01px`; native lines use `h-[0px]`. + +## Layout + +Use Auto Layout for ordinary product UI. `flex` follows CSS's horizontal default; +use `flex-row` when that direction should be explicit and `flex-col` for a +vertical stack: + +- `flex`, `flex flex-row`, or `flex flex-col` +- `items-start|center|end|baseline` +- `justify-start|center|end|between` +- `flex-wrap`, `flex-nowrap`, `content-between`, `content-normal` +- `gap-N`, `gap-x-N`, `gap-y-N`, or exact `[Npx]` +- `p`, `px`, `py`, `pt`, `pr`, `pb`, `pl` with `-N`, `-px`, or `-[Npx]` +- `box-border`, `box-content` + +New Auto Layout frames include inside strokes by default (`box-border`); +`box-content` excludes them. Center/outside strokes never affect layout, and +each nested frame owns its setting. Fixed create sizes must cover opposing +padding plus included inside strokes. Figma determines `FILL` geometry and +border-box distribution. Derive exact descendant or instance sizes from the +rendered inner box, not nominal parent size; prefer valid cross-axis fill and +exceed the box only for intentional bleed or overlap. + +`managed-content-overflow` means managed Text or INSTANCE exceeds its direct +managed Frame or Component, or a native INSTANCE contains descendant content +beyond its own fixed root. Inspect edges, clipping, rendering, and instance +bounds; resize or realign accidental overflow and retain only intentional bleed, +crop, or overlap. Property-driven content outside an INSTANCE root is a broken +component contract rather than intentional consumer overflow. + +`justify-between` uses nonnegative native Auto gap and keeps one child at the +start. Use negative `figma.autoLayout.itemSpacing` only for intentional overlap. +Omitting box-sizing on update preserves the live setting. + +`hidden` and BOOLEAN visibility remove in-flow children, changing gaps, +positions, and hug bounds. To preserve geometry, keep a fixed slot and toggle +its inner child. `absolute left-[Npx] top-[Npx]` maps to Ignore Auto Layout for +true overlays; it needs fixed offsets, cannot fill/grow, and leaves surrounding +flow unchanged. Its text and Auto Layout descendants may still hug. + +For grid use: + +- `grid grid-cols-N` +- optional `grid-rows-N` +- custom tracks: `grid-cols-[1fr_240px_fit-content(100%)]` +- optional `grid-flow-row` or `grid-flow-none` +- child placement: `col-start-N`, `row-start-N`, `col-span-N`, `row-span-N` +- child alignment: `justify-self-auto|start|center|end`, + `self-auto|start|center|end` + +Give manual grid children both row and column starts or neither. Auto-flow uses +source order without explicit starts. A height-hugging grid cannot use flexible +or automatic rows; fix either its height or row tracks. Omitting `grid-rows-*` +creates native automatic content-sized rows; increasing only the container +height does not enlarge them. + +For a coherent board larger than one call, first create one fixed parent: + +```json +{ + "mode": "create", + "markup": "
" +} +``` + +Then append one bounded screen per update. Keep the root key and classes stable, +target its returned ID, and omit previously added children so they remain in +place: + +```json +{ + "mode": "update", + "targetNodeId": "FrameID:app-board", + "markup": "
" +} +``` + +For freeform composition, omit layout classes and give each child `absolute` +with exactly one horizontal edge (`left-*` or `right-*`) and one vertical edge +(`top-*` or `bottom-*`), including negative or exact values, or use a native +relative transform. Edge placement needs fixed parent and child sizing modes; +right/bottom offsets are resolved from live bounds after each markup apply. They +are placements, not reactive CSS anchors: use Auto Layout for alignment that +must follow later mode changes without another markup apply. A plain +non-flex/grid `div` is freeform even with one child; opt into layout for every +in-flow child. Absolute children cannot grow or fill; use `static` to return one +to Auto Layout on update. + +## Appearance and text + +Frame appearance: + +- `bg-transparent|white|black`, or an exact CSS hex value +- Linear backgrounds use `bg-linear-to-t|tr|r|br|b|bl|l|tl` with exact + `from-white|black|[#hex]`, optional `via-white|black|[#hex]`, and required + `to-white|black|[#hex]` stops. Stops are fixed at 0, optional 0.5, and 1; + `bg-gradient-to-*` is accepted as a legacy alias. Do not combine a gradient + with a solid background, direct fill paints, or a fill style/variable. +- `border`, `border-N`, `border-[Npx]`; use `border-x|y|t|r|b|l` with the same widths +- `border-white|black`, or an exact CSS hex value +- `rounded`, `rounded-none|xs|sm|md|lg|xl|2xl|3xl|4xl|full`, or `rounded-[Npx]`; + prefix the value with `t`, `r`, `b`, `l`, `tl`, `tr`, `br`, or `bl` for individual sides/corners +- `overflow-hidden`, `overflow-visible` +- A clipped rounded frame does not paint its inside stroke above children. A + filled child that reaches a curved edge can therefore square off or hide the + boundary even with `overflow-hidden`; inset it, give the touching child + corners a corresponding inner radius, or add a dedicated foreground + boundary, then inspect the rendered pixels. +- Exact pixel shadow lists through `shadow-[...]` or `inset-shadow-[...]`. + Each layer needs an explicit hex, `rgb()`, or `rgba()` color and two to four + pixel lengths; use underscores for spaces, for example + `shadow-[0_8px_24px_rgba(0,0,0,0.16)]`. +- `shadow-none` and `inset-shadow-none` clear their class-owned effect stack. + Theme-dependent named scales such as `shadow-md` are unsupported: use an + explicit native style or typed effect/variable binding for a reusable token, + or resolve the governing theme before applying and provide the exact value. + +Figma accepts shadow spread only on rectangles and ellipses, or on frames, +components, and instances with a visible fill and clipping enabled. + +A new border needs weight and paint, literal or bound. Updates may change either +independently; omission preserves the other. + +New frames are transparent when background is omitted, including frames added +during update. On an existing frame, omission preserves its live background; +use `bg-transparent` to clear it. Set an explicit background when fill is +intended. + +Shared appearance: + +- `opacity-N` (`N%`) or `opacity-[0..1]`, `hidden`, `visible` +- `rotate-N`, `-rotate-N`, `rotate-none`, or `rotate-[Ndeg]` +- `mix-blend-` with `pass-through`, `normal`, `darken`, `multiply`, + `plus-darker`, `color-burn`, `lighten`, `screen`, `plus-lighter`, + `color-dodge`, `overlay`, `soft-light`, `hard-light`, `difference`, + `exclusion`, `hue`, `saturation`, `color`, or `luminosity` + +Text: + +- `font-sans|serif|mono` resolve to an editor-available family in that category, + preferring Inter, Noto Serif, and Noto Sans Mono +- `font-thin|extralight|light|normal|medium|semibold|bold|extrabold|black` +- `text-xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl` with their default line + heights, `text-SIZE/N`, or `text-[Npx]` +- `leading-none|tight|snug|normal|relaxed|loose`, `leading-N`, `leading-[Npx]`, + `leading-[N%]`, or a unitless arbitrary ratio +- `tracking-tighter|tight|normal|wide|wider|widest`, `tracking-[Npx]`, + `tracking-[N%]`, or `tracking-[Nem]` +- `text-left|center|right|justify` +- `normal-case`, `uppercase`, `lowercase`, `capitalize` +- `no-underline`, `underline`, `line-through` +- `truncate`, `line-clamp-N`, `line-clamp-none` +- `text-white|black`, an exact CSS hex value, `whitespace-pre-wrap` +- `text-shadow-[...]` for an exact pixel text-shadow list with a color and two + or three pixel lengths; `text-shadow-none` clears it + +A `span` is one TEXT node, so `bg-*` and `text-*` share its fill channel. Put +background on a parent `div` and color on its child `span`. + +Shadow classes compile to the native effect stack; never combine them with +`figma.effects` or an Effect style on that node. + +Unknown elements, attributes, classes, CSS, responsive/state prefixes, custom +themes, margins, percentages, and plugins fail closed. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/component-authoring.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/component-authoring.md new file mode 100644 index 00000000..99573887 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/component-authoring.md @@ -0,0 +1,294 @@ +# Author reusable components + +Use this reference after selecting a reusable local component. It explains +representation, not library strategy. New local components need no +`get_design_system`; use catalogs only for discovery or normalized library +props, and exact returned IDs for newly authored components. + +## Shared-responsibility decision + +New local components are opt-in for net-new authoring. Use Author when the user +requested reusable components before delivery, accepted a component pass after +seeing the completed design, or applicable project evidence makes a local +component deliverable part of the task. Existing components may still be Reuse +without authoring new ones. Repeated appearance, repeated data, screen count, +possible future reuse, or tool availability do not opt the user into Author. + +Make the decision from real usages after the representative composition is +visually sound: + +1. Name the shared job and compare the intended consumers. +2. Identify stable anatomy and meaningful content, media, state, availability, + label, swap, or slot differences. +3. Choose Author only when a truthful supported contract provides more + coordination value than it costs to create, migrate, and verify. Otherwise + keep the responsibility Direct; a brief reason is enough. +4. Bound Author at the smallest subtree that owns the complete shared job. Do + not infer that a parent must become reusable because a nested label, icon, + status, or button is reusable. + +Do not inventory or rank every recurring family, and do not turn repetition +into a quota. Record only selected Author responsibilities and their concrete +consumers. Before propagation, create the smallest real definition, instantiate +it once, and verify the exact reference. Then replace the selected consumers +with native instances; never leave literal lookalikes for a responsibility that +was deliberately selected as Author. Use the exact returned `rootNodeId` or +`nodeIdsByKey` entry for every usage. + +A keyed primitive cannot become an INSTANCE in place. Update its bounded +ancestor, add the instance under a new key, and remove the old key in the same +call. + +Stop component authoring if the ID is missing, the instance fails, or the +definition is empty, default-sized, or loses +properties. Do not substitute primitives or claim completion. Continue only +independent Direct work, report the degraded component result, and remove a +temporary definition only when unused and safe. Re-read a corrupt definition +and its intended usage; never rebuild it in place or remove one with instances. +Recreate only when unused. If a diagnostic would systematize primitives that +this definition replaces, reconcile the component first; independent token work +does not need to wait. + +Before handoff, reconcile only selected Author responsibilities with actual +consumers. Each selected consumer must be a native INSTANCE. Inspect the most +demanding instance through its descendants; root type and size do not prove +wrapping, slots, media, or state content fit. +Revise the contract or boundary when real content breaks it. + +Markup-only updates preserve keyed components, sets, instances, and shapes. +Restate native bindings only when changing native state; new native nodes still +need declarations or component references. + +Copy a complete recipe and change its design facts. Do not infer TemPad's +component shape from raw Plugin API calls. + +## Contents + +- [Define the contract from real usages](#define-the-contract-from-real-usages) +- [Keep source definitions discoverable](#keep-source-definitions-discoverable) +- [Component and properties](#component-and-properties) +- [Consume an authored component directly](#consume-an-authored-component-directly) +- [Variant set](#variant-set) +- [Slots and instances](#slots-and-instances) + +## Define the contract from real usages + +Compare every intended usage. Separate stable anatomy from varying content, +state, or nested substitution; map differences to the smallest supported Text, +Boolean, Instance Swap, variant, Slot, or nested-composition mechanism. Treat a +field as invariant only when real usages agree. + +Size the contract from real extremes: test the longest wrapping text, widest +label, largest nested swap, and materially different slots. Compare descendant +bounds with the INSTANCE root; screenshots can still paint invalid overflow. +If content exceeds the root, enlarge the definition, add a truthful size +variant, or move the varying region outside a smaller stable boundary. +If consumer-specific media cannot be expressed by the available instance +contract, keep that media direct and componentize the stable surrounding +responsibility; never freeze one image into every instance to retain a larger +component boundary. + +When stable anatomy should evolve together, expressible state differences +support a shared contract. Keep it local only when divergence or contract cost +outweighs coordinated change. + +If the contract cannot express a meaningful difference, revise it or keep the +responsibility local. Never force usages to share placeholder content or an +accidental default merely because outer geometry repeats. + +Model each mutually exclusive categorical concern as one variant axis; do not +replace it with Booleans that allow impossible combinations. Reserve Booleans +for independently optional content or behavior. + +Expose one choice through both a variant and independent property only when real +usages vary them independently. Keep each source variant's visible state +truthful; instance overrides do not repair accidental source defaults. + +## Keep source definitions discoverable + +Keep main components and sets visible at natural bounds in a clearly named +source area separate from screens. Never hide, clip, make transparent, or +invisibly nest them. For several families, use a top-level SECTION with +`contentsHidden: false`, discoverable definition children, and content-sized +bounds. + +Keep each real definition once, without redundant specimens. Before handoff, +use `get_structure` to verify every definition is visible and every intended +consumer is an INSTANCE. Inspect distinct source variants at readable scale; +names, content, and styling must encode the same state. + +Keep the source area operational and visually subordinate: use the smallest +content-sized container that exposes the definitions, outside the consumer +board or screen sequence. Do not turn it into a branded artboard, mood board, +visual-thesis panel, token showcase, or documentation page unless the user asks +for that deliverable. Product screenshots and presentation framing should stay +focused on the requested experience. + +## Component and properties + +This complete call creates a component with TEXT and BOOLEAN properties and +connects both properties to its label layer. + +```json +{ + "mode": "create", + "markup": "
Continue
", + "native": { + "button": { + "figma": { + "name": "Button", + "component": { + "type": "COMPONENT", + "properties": { + "label": { + "type": "TEXT", + "name": "Label", + "defaultValue": "Continue" + }, + "show-label": { + "type": "BOOLEAN", + "name": "Show label", + "defaultValue": true + } + } + } + } + }, + "button/label": { + "figma": { + "componentPropertyReferences": { + "characters": "label", + "visible": "show-label" + } + } + } + } +} +``` + +Stable keys such as `label` connect definitions and sublayer references within +one result; they are not generated Figma property names. Supported property +types are `BOOLEAN`, `TEXT`, and `INSTANCE_SWAP`, linked through `visible`, +`characters`, and `mainComponent` respectively. + +BOOLEAN properties control visibility, not styling. Hidden in-flow children +leave Auto Layout. Use this only for intentionally optional content. To preserve +geometry, toggle an inner layer inside a fixed slot, use `absolute` for a true +overlay, or use geometry-equivalent variants for whole-state changes. + +Treat `layout-affecting-visibility-property` as a contract warning. Fix it when +geometry must stay stable. Accept intentional reflow only after comparing true +and false instances for bounds, sibling positions, baselines, and clipping; one +default-state screenshot is insufficient. + +## Consume an authored component directly + +Use the exact ID returned by `apply_canvas`. For TemPad-authored components, +`componentProperties` accepts their stable definition keys. This follow-up +needs no catalog: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "screen/action": { + "component": { "id": "ComponentID:created-button" }, + "componentProperties": { "label": "Save", "show-label": true } + } + } +} +``` + +Replace the illustrative ID with the returned ID. Never invent IDs or use this +shortcut for unidentified library components. + +## Variant set + +This call creates two components in one variant set. Every direct child of a new +set must be an authored component; names encode axes as `Property=Value`. + +```json +{ + "mode": "create", + "markup": "
Continue
Continue
", + "native": { + "button-set": { + "figma": { + "name": "Button", + "component": { "type": "COMPONENT_SET" } + } + }, + "button/default": { + "figma": { + "name": "State=Default", + "component": { "type": "COMPONENT" } + } + }, + "button/hover": { + "figma": { + "name": "State=Hover", + "component": { "type": "COMPONENT" } + } + } + } +} +``` + +Consume the returned set ID and select siblings through variant properties. If +the call returns the set as `rootNodeId`, this creates Default and Hover: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "screen/default": { + "component": { "id": "ComponentSetID:created-button-set" } + }, + "screen/hover": { + "component": { "id": "ComponentSetID:created-button-set" }, + "componentProperties": { "State": "Hover" } + } + } +} +``` + +Replace the ID with returned `rootNodeId`. The set ID creates its default; +`componentProperties` selects another encoded variant. An exact child ID from +`nodeIdsByKey` may instantiate that variant directly. + +Use `descriptionMarkdown` and `documentationLink` only for real guidance, inside +`figma.component` beside `type` and `properties`: + +```json +{ + "figma": { + "name": "Button", + "component": { + "type": "COMPONENT", + "descriptionMarkdown": "Primary action" + } + } +} +``` + +Define shared properties on the component set rather than on one variant. + +## Slots and instances + +Use `figma.slot` only for an intentional flexible nested-content API. New slots +must be inside local authored components and include `property.name`; markup +children become defaults. Optional settings control stretching, empty display, +child limits, and preferred values. + +An `INSTANCE_SWAP` default uses exact live component/set ID `{ "id": "..." }` +or importable library key `{ "key": "..." }`. Preferred values require +`{ "type": "COMPONENT" | "COMPONENT_SET", "key": "..." }` and accept neither +live IDs nor catalog refs. Resolve catalog identity before authoring and never +invent it. Put advanced state under `figma.instance`; omission preserves normal +override behavior. + +Never edit a remote component, nest a main component inside another main +component, delete a component with surviving instances, or create properties +and variants that the requested component API does not need. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/delegation.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/delegation.md new file mode 100644 index 00000000..181b7cc9 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/delegation.md @@ -0,0 +1,82 @@ +# Delegate bounded evidence work + +Delegate evidence gathering or isolated production, never focal judgment. The +main agent synthesizes results and remains the only Canvas writer. + +## Pass the delegation gate + +Delegate only work that is: + +1. **Separable:** has a stable objective independent of evolving design choices. +2. **Compressible:** needs only a compact task-local brief. +3. **Isolated:** is read-only or produces an isolated artifact without mutating + Figma, design-system state, or another agent's files. +4. **Verifiable:** returns citations, importable asset references, exact facts, + or a bounded defect list the main agent can inspect. +5. **Worth coordinating:** gains enough from parallelism, specialist capability, + or independent review to justify handoff and synthesis. + +Keep work local if any condition fails. Do not delegate for ritual, convenience, +or another unsupported aesthetic opinion. + +## Write a complete handoff + +Give each worker one objective and its relevance, only required task evidence +and constraints, permitted tools and sources, explicit exclusions including no +Canvas writes, and an exact output contract and stop condition. The main agent +must read required Canvas references and set safety boundaries; never delegate +interpretation of this skill. Prefer fresh or minimum-context workers, pass +source evidence rather than conclusions, and avoid overlapping assignments. + +## Suitable tracks + +### Research scout + +After framing the design problem, delegate a bounded evidence question. Return: + +```txt +open decision; exact source; applicable finding; relevance; authority boundary +``` + +The scout does not choose direction. Combine questions only when their search +space is shared; use multiple scouts only for independent spaces. + +### Asset scout + +After fixing asset requirements and import contract, return one importable +`imageUrl` or `assetHash` per asset plus MIME type, dimensions, provenance, and +factual description. Return no bytes, rejected candidates, or transcript. The +main agent owns selection and integration. + +### Independent QA scout + +After a representative composition exists, provide a fresh worker its +screenshot and frozen brief without creator rationale or suspected defects. Ask +for at most eight observations: + +```txt +severity; screen/node or region; observed defect; visible evidence; violated constraint +``` + +The scout neither edits nor declares completion; the main agent checks findings +against the live canvas. + +### Inventory scout + +Use read-only inventory when independent volume warrants it, such as several +screens or icon candidates. Require exact findings and references, not a design +proposal. + +## Orchestrate conservatively + +- Default to one worker; use at most two concurrent non-overlapping workers. +- Keep a faster local critical path with the main agent. +- Only the main agent resolves intent and conflicts, chooses direction, calls + `apply_canvas`, and accepts the result. +- Resolve conflicts from evidence, not voting; discard unverifiable or + out-of-scope claims and stop when evidence is sufficient. + +Never delegate interdependent page or component construction, component +authoring plus instance placement, concurrent updates to one root, final +composition, or final acceptance. These require one ordered mutation stream and +continuous awareness of the whole. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/design-system-authoring.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/design-system-authoring.md new file mode 100644 index 00000000..45825de5 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/design-system-authoring.md @@ -0,0 +1,87 @@ +# Implement a selected local design system + +Use this reference only when the user or resolved plan requires new local +components, variables, or styles. It translates that plan into native resources +and verifies delivery; it does not choose component strategy, visual language, +resource inventory, or token taxonomy. + +## Establish the implementation contract + +Before writing, identify each selected resource, responsibility, concrete +consumer, meaningful variation, and exclusion. Resolve any open material +boundary first. For components, use the gate in +[component-authoring.md](component-authoring.md); screen count, one-screen scope, +and visual similarity alone neither establish nor exclude a component. + +Keep a private reconciliation map: + +```txt +selected resource -> native representation -> intended consumers +``` + +A resource is complete only when its native definition or binding exists and +every intended consumer uses it. Equivalent primitives or literals are not +coverage. + +## Translate the plan + +Use this loop: + +1. Stabilize one representative composition. +2. Author only selected resources with known consumers. +3. Exercise each contract in that composition. +4. Propagate native instances and bindings to all intended consumers. +5. Reconcile the final artifact with the map. + +Preserve the decided semantics: + +- A variable carries a semantic value consumers must bind and evolve together; + name it by role, not literal. +- A local style carries a reusable paint, text, effect, or grid definition. Do + not duplicate one decision across resource types unless required. +- A component carries a reusable responsibility. Define stable anatomy and + expose only variations required by real usages. + +Use [resource-mapping.md](resource-mapping.md) to map selected variable and text +style identities once per apply, then consume them through familiar variable +utilities and `type-*` classes. A new resource and its first consumer can share +one call. Query available fonts independently through `get_design_system` with +`scope: "fonts"`; selecting a family does not require discovering a file system. + +Consume a component through a childless instance placeholder without layout or +appearance classes. Do not make a repeated shell or wrapping top-level subtree +a component unless every consumer can use that placeholder through supported +properties. Slots do not permit markup children on instance placeholders; keep +incompatible wrappers as ordinary structure around a compatible inner boundary. + +Map each real component difference to the smallest supported mechanism: Text, +Boolean, Instance Swap, variant, Slot, or nested composition. Use one variant +axis per mutually exclusive categorical concern and Booleans only for +independently optional concerns. Do not encode arbitrary content as variants, +generate unused combinations, or freeze varying content as invariant. + +If supported native mechanisms cannot express a real usage, do not weaken or +redesign it silently. Choose another valid boundary or report the limitation. + +Read [variables.md](variables.md), [local-styles.md](local-styles.md), or +[component-authoring.md](component-authoring.md) only for selected resource +types. + +## Verify the native handoff + +Verify through representative consumers, not definitions alone: inspect native +bindings, Auto Layout, text resizing, property behavior, and every material +state. Raw literals and primitive lookalikes do not demonstrate system usage. + +For components, verify visible inspectable definitions and native INSTANCE +consumers using [component-authoring.md](component-authoring.md). For variables +and styles, inspect live bindings rather than apply input or equal values. + +Resolve warnings through real consumers, or remove a resource only when the +resolved plan no longer includes it. Tool friction, payload size, or an easy +resource type does not alter the plan. Do not create swatches, specimens, +definition panels, or redundant examples solely for verification; add +documentation only when requested. + +Finish when selected resources support all requested usages and the live Figma +structure reconciles with the map. Do not expand for imagined future needs. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/design-system-reuse.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/design-system-reuse.md new file mode 100644 index 00000000..11cf574f --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/design-system-reuse.md @@ -0,0 +1,59 @@ +# Reuse an existing design system + +Use this reference only when reuse is allowed and relevant. If the user rejects +a design system, use Direct. + +## Discover definitions + +Call `get_design_system` without arguments. Its immutable deterministic catalog +contains: + +- a `catalogId` scoping all short refs; +- component tags, props, source pages, and native sizes; +- variables, collections, modes, styles, and shaders as refs such as `v1`, + `k1`, `m1_2`, `s1`, and `h1`; +- `cssName` on variables and `className` on text styles for direct use in markup; +- `omitted` and `nextCursor` when more definitions remain. + +The catalog neither scans usage nor loads pages or ranks resources. Select from +returned names, pages, summaries, props, types, scopes, and defaults. Continue a +cursor or inspect an exact ref only until evidence is sufficient. + +Prefer, in order: catalog component, supported component prop, matching native +style, semantic variable, then primitive or literal for a real gap. + +When variants, anatomy, layout, or semantic meaning affect the result, inspect +the exact `ref` with the same `catalogId`. Use its `previewNodeId` with +`get_screenshot` only when appearance affects selection. Read an existing +composition with `get_code` or `get_screenshot`; catalogs do not reveal usage +conventions. Never invent refs, IDs, keys, props, or variant values. + +## Apply catalog resources + +Component tags are childless, include returned `data-ref`, and use exact props. +Omit size classes to preserve native size. Use returned CSS variable names and +text-style classes through [resource-mapping.md](resource-mapping.md). For other +native fields, bind `data-var-="vN"` or `data-style-="sN"`; put +collection modes or strict native links under `native[data-key]`. + +Replace every illustrative ref in this contract with one from the active +catalog: + +```json +{ + "mode": "create", + "catalogId": "ds_example", + "markup": "
Team settings
", + "theme": { "textStyles": { "type-body": { "ref": "s1" } } }, + "native": { + "settings": { + "variableModes": { "k1": "m1_1" } + } + } +} +``` + +If a mandatory component is absent, ask the user to open its definition page; +otherwise use the normal primitive fallback. An empty canvas does not block +catalog reuse. When reuse is unavailable, create a small coherent primitive +draft—never a token or component library solely for one screen. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/document-geometry.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/document-geometry.md new file mode 100644 index 00000000..1f24c0d6 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/document-geometry.md @@ -0,0 +1,124 @@ +# Document and native geometry + +Use `native[key].figma` only for state HTML and classes cannot express honestly; +it remains declarative desired state. + +## Contents + +- [Pages and containers](#pages-and-containers) +- [Shapes and vectors](#shapes-and-vectors) +- [Transforms, masks, and native state](#transforms-masks-and-native-state) + +## Pages and containers + +Top-level `page` can set a name, exact zero-based document index, solid RGBA +background, ordered guides, and explicit variable modes. Page-only create uses +a new `pageKey` plus name. Page-only update uses +an exact `id` or `pageKey` and omits markup. A create root may target an existing +or new page directly; creating pages and writing nodes preserve the user's current +page and viewport. Do not activate a page merely to write there. +Markup updates stay on the target node's page. + +Use top-level `mode: "activate"` with exact page identity when editor context or +selection matters; `selection: []` clears selection. Use top-level `mode: +"remove"` with an owned `pageKey` to delete a page. Page deletion rejects the +last page, manual or unowned content, and surviving external dependencies. + +Use: + +- `figma.section: { contentsHidden? }` for canvas organization; +- `figma.group: true` for an intrinsic group; +- `figma.booleanOperation: "UNION" | "SUBTRACT" | "INTERSECT" | "EXCLUDE"` + for non-destructive geometry. + +Sections can be canvas roots or direct children of sections; a frame cannot +contain a section. Sections require fixed pixel dimensions and freeform +children. Groups and Booleans use `w-fit h-fit` with freeform children. A new +group needs one child and a Boolean needs two. When updating an intrinsic +container's children, +describe every live direct child because order is semantic. + +Sections have no frame clipping, so omit `overflow-hidden` and +`overflow-visible`. When `targetNodeId` is an existing section, retain +`figma.section` on the root or the frame-typed markup root is rejected. + +## Shapes and vectors + +Use a childless `div` with `figma.shape`: + +- `{ "type": "RECTANGLE" }` +- `{ "type": "LINE" }` +- `{ "type": "ELLIPSE", "arc": { "startAngle", "endAngle", "innerRadius" } }` +- `{ "type": "POLYGON", "pointCount": 3 }` +- `{ "type": "STAR", "pointCount": 5, "innerRadius": 0.5 }` +- `{ "type": "VECTOR", "paths": [...] }` +- `{ "type": "VECTOR", "network": {...}, "handleMirroring": "..." }` + +Use exact uppercase `M L Q C Z` paths for already-decided custom vector +geometry. Selected icon roles use sourced SVG through [icons.md](icons.md), not +remembered paths. Use a vector network only for branching segments, per-vertex +state, or region-specific fills or styles. Never provide both. New vectors need +geometry; omission preserves it on update and an empty path or network clears +it. + +Each path item is an object. `windingRule` is `"NONE"`, `"NONZERO"`, or +`"EVENODD"`; use `"NONE"` for an open stroked path. Path data uses +whitespace-separated uppercase commands and numbers. + +Figma normalizes path geometry to tight bounds before applying markup size. The +childless `div` defines final bounds, not a preserved viewport. For alignment, +offset it by the path's minimum x/y and size it to the x/y spans; otherwise a +partial-range path stretches to the box. Verify rendered anchors because +`get_structure` returns node bounds, not path coordinates. + +This Direct recipe creates an editable branch curve: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "branch": { + "figma": { + "name": "Branch", + "shape": { + "type": "VECTOR", + "paths": [ + { + "windingRule": "NONE", + "data": "M 14 300 C 30 252 52 188 104 20" + } + ] + }, + "fills": [], + "strokes": [{ "type": "SOLID", "color": { "r": 0.447, "g": 0.314, "b": 0.231 } }], + "stroke": { "weight": 2, "cap": "ROUND", "join": "ROUND" } + } + } + } +} +``` + +## Transforms, masks, and native state + +- `figma.name` sets the display name; `data-key` remains identity. +- `locked` and `aspectRatioLocked` set interaction state. +- `relativeTransform` is a complete native 2×3 unit-axis transform; width and + height carry scale. Do not combine it with `rotate-*`. On create roots, TemPad + preserves rotation and skew but replaces translation with automatic placement. +- `stroke` carries weights, alignment, caps, joins, miter, and `dashPattern`. +- `corners` carries radii and smoothing. +- `mask` is `"ALPHA"`, `"VECTOR"`, `"LUMINANCE"`, or `null`. + +Place a mask before masked siblings inside one dedicated frame and describe all +direct siblings on update. A non-null mask needs a following sibling. Omission +preserves mask state; `null` disables it. + +After changing a mask, layout grid, or frame guide, call `get_structure` with +`options.native: true` on the smallest relevant root. Verify `native.mask` and +sibling order, or returned `native.layoutGrids` and `native.guides`; desired +bindings alone are insufficient. + +Use `{ "ref": "…" }` for catalog resources nested in native state and +`sourceCanvasKey` or `{ "canvasKey": "…" }` for same-result forward node +references. Never insert raw Plugin API calls. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/editing.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/editing.md new file mode 100644 index 00000000..f8653bd5 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/editing.md @@ -0,0 +1,44 @@ +# Edit an existing result + +Use this reference for an update, removal, or change of editor context. Read the +exact target and recover managed keys from structured tool results when prior +call context is unavailable. Names are labels, not identity. + +## Describe the desired change + +Trace the requested change through its visible dependents: a changed selection +may affect the working surface, label, enabled action, and summary. Preserve +unrelated content and relationships. Preserving the source does not mean +retaining stale representations of its previous state. + +Use the smallest owning target that can express the complete change: + +- For native state on existing keys, target the exact managed root and send only + `native`; omit markup to preserve topology. +- For structural changes, read `canvas-html.md`, keep `data-key` stable, and + include the affected structure. Omitted existing fields and keyed elements + retain their live state; omission is not deletion. +- `removeKeys` removes owned descendants. Top-level `mode: "remove"` removes an + exact managed root or page. Do not remove manual/unkeyed content, unmanaged + resources, or surviving external consumers. +- `mode: "activate"` requires `page.id` or `page.pageKey`, even for a + selection-only change. It changes editor context, not document state. An + exact off-current-page write does not require activation. + +Respect instance boundaries. Change an instance root or its authorized +component definition, never a definition-derived sublayer. Select only the +native references needed for the intended change. + +## Recover locally + +Read the entire mutation result. For a rejected payload, correct all reported +issues together without changing the design to fit the error. A verification +failure is rolled back by TemPad; do not assume a partial successful edit. +For an unknown transport outcome, read the exact target before retrying a create +or removal so an uncertain response does not become a duplicate mutation. + +Repair warnings where they occur. Replace a whole root only when an observed +structural defect requires it and the complete intended content can be +preserved. Reopen the affected composition after its last material write and +inspect its dependents; read back protected native facts when preservation +matters. Do not expand a local correction into an unrelated restyle. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/icons.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/icons.md new file mode 100644 index 00000000..b3457638 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/icons.md @@ -0,0 +1,65 @@ +# Deliver icons + +Use this reference only after the composition selects an icon role. It does not +require icons, set an icon count, or choose a family or visual style. + +Prefer permitted current-file, catalog, project, or user sources; otherwise use +a trustworthy brief-compatible source and record material license constraints. +When inspected evidence establishes a family or geometry, use that permitted +source or a compatible one. A general library is a fallback only when its +stroke or fill, optical weight, corners, negative space, and platform semantics +remain coherent. Do not diversify sources by quota. + +Import exact SVG geometry. Never redraw a known icon from memory or replace an +icon role with Unicode, emoji, TEXT, or assembled primitives. A character, +shape, or cluster that communicates an affordance, object, or semantic category +is an icon role even when beside a worded label. Before markup, scan literal +text for pictographic Unicode, emoji, and symbols and route each qualifying mark +to a permitted vector source. Simple geometry remains valid only when it is +itself the intended status or data mark, divider, decoration, or brand shape. + +Search results and snippets identify external candidates only; they establish +neither geometry nor license. Open the governing license once and fetch or open +every exact SVG used before markup. If either remains uninspected, omit an +optional icon or report a required gap instead of inventing one. + +For Direct delivery, give the icon a childless `div` whose classes supply the +decided wrapper bounds. Declare the inspected SVG document in +`assets[assetKey]` with `type: "SVG"`, then set +`native[nodeKey].figma.svg.assetKey` to that alias. An optional `color` resolves +`currentColor`; omit it for explicit-color SVGs. Figma may import a Frame with +Vector children; treat that subtree as one opaque asset and never flatten or +reconcile it. + +This complete Direct recipe demonstrates the required shape, not a design +default; its identifiers and values stand in for the already-decided role and +inspected source: + +```json +{ + "mode": "create", + "markup": "
", + "assets": { + "search": { + "type": "SVG", + "svg": "" + } + }, + "native": { + "search-icon": { + "figma": { "svg": { "assetKey": "search", "color": "#334155" } } + } + } +} +``` + +Omit `color` when it is not part of the selected source. A markup-only call +cannot deliver the SVG geometry. Once an icon source has been selected and +inspected, do not replace it with text or primitives merely to avoid the +`assets` and `native` mapping. + +For larger exact SVG, declare a Hub asset using a full lowercase SHA-256: + +```json +{ "type": "SVG", "assetHash": "" } +``` diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/images.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/images.md new file mode 100644 index 00000000..b019a960 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/images.md @@ -0,0 +1,120 @@ +# Deliver images and illustrations + +Use this reference only after the composition selects an image or illustration +role and the common boundaries in [visual-assets.md](visual-assets.md) establish +its subject and medium. + +Treat existing assets, rights-established remote sources, generation, and +purpose-built vectors as acquisition routes. Choose the nearest route that +satisfies content, fidelity, rights, quality, and import requirements; tools +have no global priority. Before importing a remote asset, establish its +applicable usage rights and a recoverable source. A search result, accessible +URL, CDN host, or lack of a watermark does not establish permission. Confirm +Canvas delivery before layout depends on the asset. + +When depiction is part of a record, keep it. Text, category icons, generic +placeholders, and numbered markers may index the record but cannot replace its +visual content. Source or generate an established raster role, preserve exact +vector art when vector is the real medium, or disclose the gap. + +Keep only enough trace to recover material choices, the remote source and its +applicable terms, or content distinctions. Combine role, evidence, medium, +source, rights, and import treatment in one short rationale when needed; do not +create a per-asset ceremony. Record exact creator, license, or attribution only +when the applicable terms, policy, or handoff requires it; assets sharing one +route and terms may share a trace. + +When medium is unspecified, use nearest visual evidence or ask if the choice is +material; otherwise state a low-consequence assumption. + +Use generation when the decided role needs a bespoke or fictional subject, +identity, composition, or treatment. In a prototype, a coherent generated set +may be the nearest truthful source for distinct fictional records; do not +require stock search merely because each subject is ordinary. For a real named +subject or supplied identity, use the supplied or rights-established source and +do not generate a substitute. Before generation, map each planned asset to the +subject and consumer it serves; skip ceremony that does not protect fidelity, +rights, or import. + +Compose generation and Hub import in one programmatic execution so image bytes +never enter prose or expire between calls: pass the generator's `data:` URL +directly to TemPad's `upload_asset`, read its returned `assetHash`, then declare +that hash as an IMAGE asset in `apply_canvas`. Do not regenerate an unchanged +prompt only to recover an importable URL. If generation or `upload_asset` is +unavailable, choose a rights-established public image source only when it +preserves the intended medium; otherwise disclose the required gap. Never +generate first and silently switch medium because import failed. + +Use `imageUrl` for a rights-established public IMAGE paint or same-file +`imageHash` for an existing image. For generated or other local Hub content, +declare the returned full lowercase SHA-256, then use its alias in a basic fill: + +```json +{ + "assets": { "image": { "type": "IMAGE", "assetHash": "" } }, + "native": { + "image-node": { + "figma": { + "fills": [{ "type": "IMAGE", "assetKey": "image", "scaleMode": "FILL" }] + } + } + } +} +``` + +Inline bytes and local paths are unsupported. Remote URLs must resolve directly +to accessible images, not pages or thumbnails. + +When a supplied canvas image is itself a permitted source artifact and an exact +visible subregion must carry into the result, reuse its same-file `imageHash` +instead of redrawing that content. For an axis-aligned source rectangle +`(x, y, width, height)` within an image of size `(imageWidth, imageHeight)`, and +a destination with the same aspect ratio, declare: + +```js +{ + type: "IMAGE", + imageHash: "", + scaleMode: "CROP", + imageTransform: [ + [width / imageWidth, 0, x / imageWidth], + [0, height / imageHeight, y / imageHeight] + ] +} +``` + +Supply the evaluated finite numbers, not expression strings. If the destination +aspect ratio differs, first choose an aspect-correct source rectangle rather +than stretching the subject. Open the rendered crop and verify its native IMAGE +fill; a valid transform does not prove that the intended subject was isolated. + +When the medium must remain a real image, verify with `get_structure` and +`options.native: true`; `native.imageFills` must contain the expected non-null +Figma hash. Input URLs, successful mutation, and visually similar screenshots +are not native read-back. + +The main agent owns placement, crop, and final verification. In a comparison, +make visual differences represent the subjects rather than their source files: +normalize incidental canvas padding, crop, background, viewpoint, and apparent +scale when they would bias the decision; preserve and explain differences that +are real or cannot be normalized faithfully. + +Before markup, map every content-bearing image consumer to the subject it +claims to depict. Reuse one asset and crop only when consumers represent that +same subject; distinct records require distinct assets or crops that visibly +isolate the correct subject. A composite scene may serve the composition it +depicts, but cannot stand in for several named records. Stop and source or +generate missing media instead of serializing a false mapping. + +When a gallery, carousel, or thumbnail set promises several views of one +subject, every retained view must add distinct, truthful information. Repeating +one unchanged source and crop does not satisfy that role; unrelated subjects +break identity. Use distinct sourced views, evidence-supported crops, or +generation/editing only for a named same-subject coverage need that sourcing +cannot satisfy. Otherwise reduce the views or disclose the gap. + +For repeated depictions of the same subject, keep asset identity and crop +stable unless evidence requires variation. If required media remains +unavailable, report it; omit optional media or use a neutral slot only when the +requested outcome is unchanged. A neutral slot is an explicit fallback, not +representative content or proof of reusable variation. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/local-styles.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/local-styles.md new file mode 100644 index 00000000..74aec685 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/local-styles.md @@ -0,0 +1,61 @@ +# Author local styles + +Use this reference only when the user or resolved system plan requires a local +style. Do not extract styles from an ordinary screen. New local resources need +no catalog; send `catalogId` only when a nested `{ "ref": "…" }` deliberately +reuses an existing resource. + +Copy this recipe and change its design facts. Style authoring keys persist +file-wide and are neither names nor IDs. Namespace keys by product and role. In +shared drafts, also prefix generic visible names that could collide; retain +established project naming when already clear. + +For whole-node typography, prefer a `theme.textStyles` alias and a `type-*` +class using [resource-mapping.md](resource-mapping.md). The recipe below shows +the explicit native binding form, also used for paint, effect, and grid styles. + +```json +{ + "mode": "create", + "markup": "
Account
", + "styles": { + "product/style/surface": { + "type": "PAINT", + "name": "Product/Color/Surface", + "paints": [{ "type": "SOLID", "color": { "r": 1, "g": 1, "b": 1 } }] + }, + "product/style/heading": { + "type": "TEXT", + "name": "Product/Typography/Heading", + "fontName": { "family": "Inter", "style": "Semi Bold" }, + "fontSize": 20, + "lineHeight": { "unit": "PIXELS", "value": 28 } + } + }, + "native": { + "card": { + "styles": { + "fill": { "styleKey": "product/style/surface" } + } + }, + "card/title": { + "styles": { + "text": { "styleKey": "product/style/heading" } + } + } + } +} +``` + +Types are `PAINT`, `TEXT`, `EFFECT`, and `GRID`, using `paints`, text fields, +`effects`, or `layoutGrids` respectively. For exact Paint, Effect, and Grid +shapes beyond this recipe, read [paints-effects.md](paints-effects.md). + +Omission preserves managed state. Top-level `null` removes a managed style only +when absence is required and all live consumers are cleared or removed in the +same result. Never mutate remote resources, invent library keys, or create a +broad style library for one screen. + +`unbound-created-style` means a same-call style lacks a `styleKey` consumer. +Bind it to a representative property performing its named role or remove it. A +swatch or unrelated binding is not coverage. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/paints-effects.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/paints-effects.md new file mode 100644 index 00000000..c32b82f2 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/paints-effects.md @@ -0,0 +1,111 @@ +# Paints, effects, grids, guides, and media + +Use this reference whenever the result uses a nontrivial shadow, blur, glass, +texture, noise, image paint, layered gradient material, or layout aid, including +effects expressed as Canvas HTML classes. Resolve an image or illustration's +role, subject, and medium through [visual-assets.md](visual-assets.md), then its +source and delivery through [images.md](images.md). Prefer a matching catalog +style; otherwise use direct native arrays. + +## Catalog links + +```html +
+``` + +A style owns its channel. Do not combine a non-null fill or stroke style with a +whole-node variable on the same paint. Styled strokes still need literal, +typed, or variable-bound geometry. `null` unlinks; omission preserves. + +## Resolve shadow references + +Named scales such as `shadow-md` are theme references, not portable geometry: + +- Reuse: bind the matching catalog Effect style. +- Author: create and bind a local Effect style only when the system plan requires + it. +- Direct: use an exact `shadow-[...]` class or typed `figma.effects` value. + +Never assume Tailwind defaults or create a token only to resolve a named class. +`shadow-none`, `inset-shadow-none`, and `text-shadow-none` explicitly clear. + +Treat an outer shadow's rendered halo as part of the composition. Inspect the +final PNG beyond the root edges; visible granular or noisy fringe, or a halo +that dominates the captured bounds, is a defect even when the frame itself is +intact. Preserve intended depth by tightening blur, spread, or opacity or using +smaller layered shadows, then recheck. Do not flatten established material +treatment merely to hide the defect. + +## Native paint and effect stacks + +`figma.fills` and `figma.strokes` support ordered solid, linear/radial/angular/ +diamond gradient, image/video, Pattern, and fill-shader paints. +`figma.effects` supports ordered shadows, normal/progressive blur, noise, +texture, glass, and effect shaders. + +A `SOLID` paint uses RGB `color` and optional paint-level `opacity`; only +gradient stops use RGBA colors. Keep stroke geometry, including `dashPattern`, +in `figma.stroke`, not the stroke paint. + +Use the exact gradient enum and normalized RGBA stop shape; do not translate +from CSS or Plugin API names: + +```json +{ + "figma": { + "fills": [ + { + "type": "GRADIENT_LINEAR", + "gradientTransform": [ + [1, 0, 0], + [0, 1, 0] + ], + "gradientStops": [ + { "position": 0, "color": { "r": 1, "g": 0.43, "b": 0.29, "a": 1 } }, + { "position": 1, "color": { "r": 0.16, "g": 0.09, "b": 0.24, "a": 1 } } + ] + } + ] + } +} +``` + +Other gradient enums are `GRADIENT_RADIAL`, `GRADIENT_ANGULAR`, and +`GRADIENT_DIAMOND`. + +Omission preserves a stack; `[]` clears it. Direct stacks cannot share their +channel with a literal class, whole-node variable, or style. Use variable refs +such as `{ "ref": "v1" }` and shader refs such as `{ "ref": "h1" }`; use only +returned shader property IDs and declared value shapes. + +For images, provide exactly one same-file `imageHash`, public HTTP(S) `imageUrl`, +or call-scoped `assetKey` for a full-SHA-256 Hub IMAGE asset. PNG, JPEG, and GIF +are limited to 4096×4096. For video, provide exactly one same-file `videoHash` or +public `videoUrl` for MP4, MOV, or WebM up to 100 MB. URLs must need no +credentials. Reuse `figmaImageHash`, `figmaImageHashes`, or `figmaVideoHashes` +from `get_code` only in the same file; they identify native media, not preview +bytes. + +A Pattern uses exactly one existing `sourceNodeId` or same-result +`sourceCanvasKey`. + +## Layout aids + +Prefer a matching Grid style. Otherwise `figma.layoutGrids` declares ordered +row, column, or square grids on frames, components, sets, and instances. Use +`"AUTO"` for automatic row or column count. Do not bind `sectionSize` with +`STRETCH` or `offset` with `CENTER`. + +`figma.guides` is the complete ordered X/Y guide list: omission preserves and +`[]` clears. Page guides live under `page.guides`. + +For wrapping linear Auto Layout, `figma.autoLayout` may set signed +`itemSpacing`, positive or synchronized-null `counterAxisSpacing`, and +`itemReverseZIndex`. Never declare one physical gap in both classes and native +state. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/resource-mapping.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/resource-mapping.md new file mode 100644 index 00000000..4d3f3db8 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/resource-mapping.md @@ -0,0 +1,138 @@ +# Use resources in Canvas classes + +Keep layout and visual composition in markup. Put a reusable value's native +identity in the catalog or a call-scoped `theme`, then reference it by class. +Variables remain bound Figma variables, including mode changes. A `type-*` +class binds an entire native TextStyle. Ordinary utilities such as `gap-4` and +`text-base` remain literals and do not create or discover resources. + +## Existing system + +When the applicable system permits reuse, discover it with `get_design_system`. +Use returned variable `cssName` and TEXT-style `className` with its `catalogId`: +`bg-(--surface)`, `gap-(--spacing-content)`, `type-body`. These are examples of +names, not assumed resources. Read a style's exact ref when its font, metrics, +or bindings affect the choice. + +The catalog uses valid WEB code syntax when available, otherwise derives a +name. It disambiguates collisions and keeps the resulting alias tied to one +exact identity for that catalog's lifetime. Use the returned name unchanged; +never derive identity from equal values, similar names, or another catalog. + +For task-specific names, add `theme.variables: { "--surface": { "ref": "v1" } }` +or `theme.textStyles: { "type-body": { "ref": "s1" } }`. Use returned refs. An +alias cannot replace another catalog alias with a different resource. A stable +authoring key and catalog ref for the same native identity may share an alias. + +## New system + +When the deliverable includes a design system, define the selected variables +and styles through `variableCollections` and `styles`. Map their stable keys in +`theme` and consume them in the same call. A primitive draft without a system +still uses ordinary classes; repetition alone does not require resource creation. + +This complete recipe illustrates the relationship. Change the design facts, +namespace resource keys for the product, and confirm the font family/style in +the environment before authoring it. + +```json +{ + "mode": "create", + "markup": "
Account settings
", + "theme": { + "variables": { + "--surface": { "variableKey": "product/color/surface" }, + "--content-gap": { "variableKey": "product/space/content" } + }, + "textStyles": { "type-body": { "styleKey": "product/type/body" } } + }, + "variableCollections": { + "product/theme": { + "name": "Product/Theme", + "modes": { "light": { "name": "Light" }, "dark": { "name": "Dark" } }, + "variables": { + "product/color/surface": { + "name": "Surface", + "type": "COLOR", + "codeSyntax": { "WEB": "var(--surface)" }, + "values": { + "light": { "r": 1, "g": 1, "b": 1 }, + "dark": { "r": 0.08, "g": 0.09, "b": 0.11 } + } + }, + "product/space/content": { + "name": "Space/Content", + "type": "FLOAT", + "values": { "light": 16, "dark": 16 } + } + } + } + }, + "styles": { + "product/type/body": { + "type": "TEXT", + "name": "Product/Typography/Body", + "fontName": { "family": "Inter", "style": "Regular" }, + "fontSize": 16, + "lineHeight": { "unit": "PIXELS", "value": 24 } + } + } +} +``` + +On later calls, retain the small `theme` mapping and omit resource definitions +unless changing them. The stable keys resolve the same native resources. The +mapping is local to the call, so different screens can use different aliases +without changing the file's naming. Authoring keys and native identities +persist; aliases do not create a second resource registry. + +Use [variables.md](variables.md) for modes, aliases, scopes, and resource updates; +use [local-styles.md](local-styles.md) for style definitions. A TextStyle may +bind selected typography primitives through its `variables` fields when those +values must change together. Do not create font-family, size, or weight tokens +solely to express a single named text role: the TextStyle can hold those facts. + +## Supported variable utilities + +Both `gap-(--space)` and `gap-[var(--space)]` work. Explicit type hints resolve +ambiguous Tailwind prefixes, for example `text-(length:--body-size)` versus +`text-(color:--foreground)`. + +| Utility | Native value | +| ---------------------------------------------------------------------- | ------------------------------------------------------- | +| `bg-(--surface)`, `text-(--foreground)`, `border-(--border)` | COLOR fill or stroke; border still needs a width | +| `w/h/size/min-w/max-w/min-h/max-h-(--value)` | FLOAT dimensions, in pixels | +| `gap/gap-x/gap-y-(--value)` | FLOAT layout gaps, in pixels; axes follow flex or grid | +| `p/px/py/pt/pr/pb/pl-(--value)` | FLOAT padding, in pixels | +| `rounded/rounded-tl/rounded-tr/rounded-br/rounded-bl-(--value)` | FLOAT corner radius, in pixels | +| `border-(length:--width)` | FLOAT stroke width, in pixels | +| `text-(length:--size)`, `leading-(--leading)`, `tracking-(--tracking)` | FLOAT font size, line height, letter spacing, in pixels | +| `font-(family-name:--family)` | STRING font family | +| `font-(--weight)` | FLOAT font weight, 1–1000 | +| `opacity-(--opacity)` | FLOAT opacity, 0–1 | + +The tool reads an initial native value itself and retains the variable binding; +do not add a second literal fallback class. Native node, layout, and scope rules +still apply. This is a bounded mapping to Figma fields, not a CSS engine: no +`calc()`, var fallbacks, arbitrary expressions, or cascade. FLOAT metrics use +the native units above, not unitless CSS line-height multipliers. + +## Typography ownership + +`type-body` consumes the whole TextStyle. Keep color, sizing, alignment, and +wrapping classes on the text node as needed; omit font, weight, size, leading, +tracking, case, and decoration overrides owned by that style. Choose another +style or explicitly unlink the style for a deliberate local treatment. Composite +typography has no single Figma variable type, so `type-*` is an explicit custom +utility convention rather than a Tailwind default or a fabricated CSS variable. + +Inline `data-var-*`, `data-style-*`, and `native` bindings remain available for +fields outside this subset, exact native fonts/styles, and explicit unlinking. +Use one mechanism per property. Unknown names, conflicting declarations, +incompatible types, and cyclic variable aliases require correction; the tool +does not guess a replacement. + +Updates preserve omitted native state. Removing a resource class or replacing +it with a literal does not unlink the existing binding: explicitly clear the +variable/style with its `data-var-*="none"`, `data-style-*="none"`, or supported +`native` null binding when that is the intended change. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/rich-text.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/rich-text.md new file mode 100644 index 00000000..3e26cc97 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/rich-text.md @@ -0,0 +1,52 @@ +# Rich text and hyperlinks + +Use this reference for native font application or Figma-only text behavior; +use [typefaces.md](typefaces.md) when font selection or availability needs resolving. +Use `span` for editable text. Put whole-node typography in classes, a catalog +Text style, or semantic variable bindings when possible. + +`native[key].figma.text` supports: + +- exact whole-node `fontName`, `autoRename`, vertical alignment, and leading + trim; +- paragraph indent/spacing, list spacing, hanging punctuation/list; +- whole-node hyperlink; +- ordered rich-text `ranges`. + +Do not combine `autoRename: true` with fixed `figma.name`. + +When no Text style or typography variable expresses the chosen family and +style, use the exact available Figma font: + +```json +{ + "fontName": { "family": "IBM Plex Sans", "style": "Medium" } +} +``` + +Do not combine it with `font-*` classes, linked Text styles, or font family/style +variables. Never guess family or style availability. + +Range `start` and `end` are UTF-16 offsets into final characters. Ranges must be +ordered, non-overlapping, and set at least one property; split overlapping +intentions into disjoint intervals. A range may set font name/size, case, +letter spacing, line height, complete underline state, native fills, Text/Paint +style, list options, indentation, paragraph spacing, hyperlink, and supported +text-range variables. + +Use `{ "ref": "s1" }` for a catalog range style and `{ "ref": "v1" }` for a +range variable. `null` unlinks supported styles or hyperlinks; omission +preserves. + +Hyperlinks support URLs and node targets. For a same-result target: + +```json +{ + "type": "NODE", + "value": { "canvasKey": "settings/help" } +} +``` + +The target may appear later in markup; never remove a live hyperlink target. If +a catalog component exposes text through a prop, set that prop instead of +editing internal layers. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/style-grounding.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/style-grounding.md new file mode 100644 index 00000000..2a83efca --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/style-grounding.md @@ -0,0 +1,80 @@ +# Ground design judgment + +Use this reference for a new direction, material redesign, or consequential +uncertainty not settled by the user or an established source. Exact reproduction +and mechanical edits use their supplied evidence directly. + +## Inspect what can change the decision + +Start with the nearest credible evidence: the supplied design or implementation, +real product states, primary platform requirements, or adjacent visual work. +Choose separate evidence for behavior and visual expression when needed. A +functional walkthrough can establish behavior without settling visual language; +a visually relevant product state or adjacent visual work can show how density, +controls, surfaces, icon/text economy, and states cohere without establishing +behavior it does not expose. One artifact may inform both only when the relevant +behavior and pixels are actually inspected. + +Open the relevant state at useful scale. A homepage or brand campaign may not +show the working interface. Search cards, prose, remembered products, generated +images, and failed retrievals are not inspected visual precedents. A content +photograph establishes what it depicts, not the surrounding application's +interaction or composition. Follow the main skill's first-write evidence +boundary when retrieval fails. + +An image-search result that exposes only a screenshot description or URL remains +a search card. Open the actual product-state pixels at useful scale before +treating them as visual grounding; otherwise use the result only as behavioral +description. + +Research is grounded when it changes, confirms, or reopens a material decision +in the new result. Retain enough source identity and context to support that +claim; do not invent a source-by-source decision report. If a source contributed +nothing consequential, do not cite it as a precedent. Generic expertise helps +interpret the evidence; its familiar defaults are not evidence about this +product. + +There is no source quota. Stop when further investigation is unlikely to change +a material choice. Do not research routine decisions for ceremony. Keep source +screens outside the authored result unless the user asked to place or reproduce +them, and preserve required source content and behavior when adapting a design. + +## Form a provisional direction + +Integrate the brief, evidence, and professional judgment into a relationship +among content, state, and action, with a visual language that makes it fitting +and perceptible. A new design needs its own solution; independence is not a +reason to discard an applicable interaction or representation because it is +harder to source or serialize. + +Before the first write, be able to state privately what the inspected pixels +changed or confirmed about the recurring visual language. A mood label or +task-themed palette is not that direction; if the same control and surface +grammar could survive a noun swap, inspect more relevant pixels or reconsider +the synthesis. + +Resolve recurring visual roles enough to try them in a real composition. The +foundation is provisional and may change after seeing pixels. It is not a +separate foundation board or permission to create components, variables, or +styles outside the task's resource scope. + +Reconsider choices whose only justification is habit or semantic association. +Ask what in the brief or inspected reality makes the proposed treatment fit. +Familiar solutions can be appropriate; choosing the opposite of a criticized +motif is no stronger evidence. Functional specificity alone does not settle +expression, and stylistic difference alone does not make the product useful. + +## Externalize unresolved visual choices + +If materially different visual hypotheses remain and a capable image-generation +tool is available, a bounded visual exploration can help you see their +consequences. Open those pixels and use them to reconsider the composition; +omit this step when the direction is already clear. + +Generated concepts are speculative sketches, not real-product evidence or +flattened Figma deliverables. Do not trust their text/data or trace them +literally. A generated subject chosen as actual product content is a separate +asset decision under `visual-assets.md`. + +Return to the representative native composition and inspect it. Let a mismatch +reopen the decision it actually challenges; otherwise complete the design. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/typefaces.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/typefaces.md new file mode 100644 index 00000000..185284bc --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/typefaces.md @@ -0,0 +1,48 @@ +# Choose and apply fonts + +Use this reference when selecting or changing fonts, delivering a required +family/style, or resolving uncertainty about the text's scripts. Availability +can change a provisional choice; query before committing when that matters. + +Start from applicable Text styles, typography variables, project fonts, or +supplied references. Preserve established font identities for ordinary edits. +For a new direction, form candidates from the language, text roles, density, +and visual intent. A portable `font-sans|serif|mono` category does not establish +an exact family or suitable coverage for the actual text. + +## Query what can change the choice + +`get_design_system` with `scope: "fonts"` reads the environment without scanning +file resources. It is valid for direct composition, reuse, and an independent +system, including a blank page. + +- With candidate family names, use `families: ["Noto Sans SC"]` to inspect + exact native style names and missing families in one call; batch candidates. +- Use `query: "Noto"` when the family name itself needs discovery. This searches + names, not language coverage or visual suitability. +- Continue `nextCursor` with the same filters only when more results could + affect the choice. Reuse current evidence rather than querying per text node. + +Use returned or source-established native names. For an unavailable provisional +candidate, reconsider the choice. For a required font, preserve the requirement +and disclose the delivery gap rather than silently substituting another family. + +## Apply the selected typography + +Reuse the applicable TextStyle or font variables. If a new design system is in +scope, define the selected text roles as TextStyles and consume their `type-*` +classes through [resource-mapping.md](resource-mapping.md). Font selection alone +does not require creating styles or tokens. + +For direct composition, `font-[family-name:Noto_Sans_SC] font-semibold` fixes +the family and chooses its closest available weight. Underscores encode spaces; +`\_` preserves an underscore. Use `native[key].figma.text.fontName` with exact +`{ family, style }` when the native style identity matters; see +[rich-text.md](rich-text.md). Weight matching is approximate. For variable-driven +typography, consider the family/weight/style combinations in the delivered modes. + +Inspect representative real content in the composition, including relevant +scripts, numbers, punctuation, and wrapping. Availability and successful loading +do not prove glyph coverage; a correct-looking screenshot alone does not prove +native font identity or current editability. Reopen the font choice when the +observed text challenges it, without requiring a separate specimen board. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/variables.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/variables.md new file mode 100644 index 00000000..692a8699 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/variables.md @@ -0,0 +1,154 @@ +# Author local variables + +Use this reference after the representative pixel check when repeated colors +may carry shared semantic roles, or when the user or resolved system plan +requires local variables. Do not extract tokens from an ordinary screen. New +resources need no catalog; send `catalogId` only for deliberate nested +`{ "ref": "…" }` reuse. + +## Contents + +- [Decide from real roles](#decide-from-real-roles) +- [Author variables](#author-variables) +- [Bind and verify](#bind-and-verify) +- [Update and remove](#update-and-remove) + +## Decide from real roles + +After any selected representative component reconciliation and before +propagation, call full `get_code` with unresolved tokens only when repeated +colors plausibly represent semantic roles whose coordinated maintenance matters. +Treat `literalClusters` as candidate locations, not a to-do list. Select a role +only when concrete consumers should evolve together; split mixed roles even +when their literal values match. Leave incidental, local, and ambiguous +repetition literal. If the diagnostic is unavailable, do not infer a system +from repetition. + +For each selected role, map concrete consumer and field to a semantic variable +key, bind every representative consumer, then re-run once to confirm the role is +exposed through `tokens` and no longer unresolved. A non-empty +`literalClusters` result is acceptable. + +Carry only selected mappings into propagation. A later apply that includes a +consumer of a selected role must bind that field in the same call; an inherited +instance binding does not cover sibling literals. Before finalization, scan each +materially distinct dependent root that uses a selected role once, fix missing +bindings for those roles, and recheck only changed roots. Do not create variables +to empty diagnostics, expand the map from literal equality, or repeat scans after +the selected roles are verified. + +## Author variables + +Copy this recipe and change its design facts. Collection and variable authoring +keys persist file-wide and are neither names nor IDs. Choose one +collision-resistant prefix for the independent system; recover existing exact +keys when intentionally updating it. Mode keys are collection-scoped. + +```json +{ + "mode": "create", + "markup": "
Account
", + "variableCollections": { + "product/theme": { + "name": "Theme", + "modes": { + "light": { "name": "Light" }, + "dark": { "name": "Dark" } + }, + "variables": { + "product/color/surface": { + "name": "Color/Surface", + "type": "COLOR", + "scopes": ["ALL_FILLS"], + "values": { + "light": { "r": 1, "g": 1, "b": 1 }, + "dark": { "r": 0.08, "g": 0.09, "b": 0.11 } + } + }, + "product/space/md": { + "name": "Spacing/Medium", + "type": "FLOAT", + "scopes": ["GAP"], + "values": { + "light": 16, + "dark": 16 + } + } + } + } + }, + "native": { + "card": { + "variables": { + "fill": { "variableKey": "product/color/surface" }, + "gap": { "variableKey": "product/space/md" } + }, + "variableModes": { + "product/theme": "dark" + } + } + } +} +``` + +A new collection needs `name` and at least one named mode. Each variable needs +`name`, `type`, and a value for every mode. Types are `BOOLEAN`, `COLOR`, +`FLOAT`, and `STRING`. Values may alias another variable: + +```json +{ "variable": { "variableKey": "…" } } +``` + +Valid scopes: + +- general: `ALL_SCOPES`, `TEXT_CONTENT`, `CORNER_RADIUS`, `WIDTH_HEIGHT`, `GAP`, + `OPACITY`; +- color: `ALL_FILLS`, `FRAME_FILL`, `SHAPE_FILL`, `TEXT_FILL`, `STROKE_COLOR`, + `EFFECT_COLOR`; +- numeric effect/stroke: `STROKE_FLOAT`, `EFFECT_FLOAT`; +- typography: `FONT_FAMILY`, `FONT_STYLE`, `FONT_WEIGHT`, `FONT_SIZE`, + `LINE_HEIGHT`, `LETTER_SPACING`, `PARAGRAPH_SPACING`, `PARAGRAPH_INDENT`. + +Use `STROKE_COLOR`, not `ALL_STROKES`. Combine neither `ALL_SCOPES` with other +scopes nor `ALL_FILLS` with `FRAME_FILL`, `SHAPE_FILL`, or `TEXT_FILL`; +`ALL_FILLS` may coexist with a non-fill scope such as `STROKE_COLOR`. + +## Bind and verify + +Bind through `native[key].variables` using the exact supported field, such as +`fill`, `stroke`, `gap`, `paddingTop`, `width`, `visible`, `fontSize`, or +`characters`. Retain a matching literal class when Figma needs an initial paint +or numeric fallback. + +Bind each variable to representative fields performing its semantic role. +Prefer `GAP` for shared gaps/padding, `WIDTH_HEIGHT` for semantic control/icon +sizes, and `CORNER_RADIUS` for shared radii. Do not tokenize viewport dimensions, +one-off crops, content-derived geometry, or optical corrections merely because +numbers repeat. + +A representative binding proves usability, not complete coverage. Bind every +consumer intended to evolve with the role; keep equal peer literals only when +incidental or independently owned. + +`apply_canvas` reports `unbound-created-variable` when a new variable lacks a +same-result consumer. Bind it to a real consumer or remove it. A staged warning +may be temporary, but final delivery must show a native binding; equal literals +do not count. + +`variable-fallback-mismatch` means a bound literal matches none of the +same-call variable's direct or aliased mode values. Align the fallback with a +real mode or bind the variable that owns the value, or the binding will silently +change the declared markup. + +## Update and remove + +After changing a variable value, update and verify every intended consumer that +cannot carry a native binding, such as `figma.svg.color`; omission leaves its +old literal in place. + +Omission preserves managed state. Top-level `null` removes a managed variable, +mode, or collection only when absence is required and all consumers are cleared +or removed in the same result. Never mutate remote resources, invent parent +collections or library keys, or build a broad token system for one screen. +Extended collections must inherit a real local or catalog collection and obey +plan limits. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/visual-assets.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/visual-assets.md new file mode 100644 index 00000000..eaa3d4c8 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/visual-assets.md @@ -0,0 +1,57 @@ +# Choose and preserve visual assets + +Use this reference after the design selects an icon, image, +illustration, diagram, or vector asset. It governs role, medium, source +integrity, editability, and delivery—not whether the design should contain that +asset or what the finished visual style should be. + +Research pixels and generated screen concepts remain evidence for judgment, +not canvas content. Import, reproduce, annotate, or compare them only when the +user explicitly requests that treatment. When evidence establishes that the +new product needs an asset role, acquire or author a truthful asset for the new +result instead of redrawing or embedding the reference. + +## Preserve the decided role + +Start from the composition, not an available tool or assumed asset slot. Once a +material role is selected, fulfill it faithfully; sourcing difficulty is not a +reason to replace an image, icon, visualization, or exact medium with easier +text or plausible geometry. + +Depiction is a role, not a medium. Choose raster, sourced vector, +agent-authored vector, diagram, or another medium only when the brief, inspected +evidence, or a low-consequence assumption supports it. Convenience never +changes the medium. + +Treat content-bearing visualization—such as a chart, map, waveform, notation, +document or media preview, or domain instrument—as a first-class +representation. Identify the user decision and the visual structures that make +it possible. Preserve enough context and density to act; a stylized trace or +labeled decoration is not the representation. When only topology or sequence +is intended, name and design it as a diagram. + +When recognition depends on a subject's real appearance—such as a person, +product, food, place, room, photograph, cover, or shared-media preview—preserve +that distinction with a real sourced or generated image unless the brief or +inspected evidence independently establishes an illustrated language. + +Preserve editability semantics. Build changing diagram labels, shapes, and +relationships as native structure; use an opaque SVG only when exact vector art +is the asset. An SVG wrapper with Vector descendants does not make a diagram +model editable. If editable primitives cannot carry a required representation, +use an evidence-supported native, vector, or raster base with changing overlays +editable, or disclose the gap. + +For material assets retain enough evidence for identity and content fidelity, +provenance and applicable rights, source quality, and Canvas-compatible form. +Never silently change subject, style, or medium. Crops, masks, overlays, and +retouching must preserve the depicted subject; do not hide distinctive branding +or features to make one subject represent another. + +## Load only the selected branch + +- For an icon role, read [icons.md](icons.md). +- For an image or illustration, read [images.md](images.md). + +For diagrams and other custom vector art, use the source and editability +boundaries above, then load only the required geometry or paint mechanics. diff --git a/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/visual-composition.md b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/visual-composition.md new file mode 100644 index 00000000..27993d33 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-canvas-authoring/references/visual-composition.md @@ -0,0 +1,64 @@ +# Compose a product interface + +Use this reference when forming or reconsidering a composition. Keep the +person's working experience in view; use the questions below only where they +help resolve a decision. They are not independent quality axes. + +## Find the working relationship + +What is the person attending to, and what can they do with it in the depicted +state? Does the chosen screen or flow expose the user's central work, or merely +promise it through a button whose destination is absent? What changes across +states, and what must remain perceptible while that happens? Arrange content, +controls, and context so their relationship is understandable in the rendered +whole. + +A familiar shell may be the right answer. Reconsider it when it hides the +working object, requires unnecessary reading or navigation, or survives only +because task-specific nouns make it look relevant. Novelty and decoration do +not repair that mismatch. + +As content grows, what extends: the document or an owned scrolling region? +Choose document flow, a fixed workspace, or a hybrid from product behavior; +check that making room has not silently redefined the device or window viewport. +Density and control scale follow platform, frequency, precision, and environment +of use. In frequent expert work, inspect the real product's interaction economy +before carrying over the spacing and repeated explanations of an occasional +consumer journey. Preserve legibility and suitable targets in either case. + +## Make meaning perceptible + +What should someone notice now, and what should stay available without +competing? Resolve type, position, scale, color, contrast, media, depth, and space +together. Repeated roles need recognizable treatment; differences need to carry +meaning in this task. An expressive role does not by itself justify the first +familiar palette, shape, or effect. + +Choose text, icons, images, and graphics by recognition, comparison, +manipulation, and expression. Familiar iconographic affordances can reduce the +reading and space required by repeated controls; words can be more precise. +Inspect that tradeoff at actual size, including when every action has become +text. Source selected icons through `visual-assets.md`; sourcing effort is not +a design reason to drop their role. + +A working graphic must carry the distinctions needed for the decision. Check +whether its marks, scale, context, and state make the relevant comparison or +manipulation possible. Changing a label does not change what the marks encode. This is a question +of represented meaning, not a quota for detail or a preferred graphic style. Use `visual-assets.md` for truthful +source and native representation. + +## Learn from the rendered result + +Open the representative composition at useful scale. Mentally follow the +central action through its visible consequences. Does the selected state agree +with the working surface, available action, and result? If the experience breaks, +inspect the particulars that explain where and why. + +Judge spacing from visible relationships: nested insets, seams, baselines, +grouping, and repeated rhythm. Nominal padding or a non-overflowing bounding box +does not prove that the intended space survived native layout. Repair the +owning relationship instead of decorating over it. + +Carry resolved shared roles into dependent screens while allowing their layouts +to differ with the work. Stop when the requested whole is coherent and the +observed defects are resolved; do not keep polishing to fill a checklist. diff --git a/agent-plugin/targets/codex/skills/figma-design-to-code/SKILL.md b/agent-plugin/targets/codex/skills/figma-design-to-code/SKILL.md new file mode 100644 index 00000000..a5bb5f20 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-design-to-code/SKILL.md @@ -0,0 +1,177 @@ +--- +name: figma-design-to-code +description: >- + Implement or update project-consistent UI code from a visible Figma selection + or nodeId using TemPad Dev MCP. Use when the user wants Figma UI recreated, + ported, or integrated into the target project's framework, styling system, + tokens, assets, and existing components. Do not use for design critique, + product invention, generic code review, or guessing states, responsiveness, + or behavior not evidenced by Figma, the project, or the user. +--- + +# Implement Figma design in code + +Turn visible Figma evidence into the smallest project-native implementation +that preserves the intended result. Keep that result focal: project files, +TemPad output, rules, and tool calls are evidence for the implementation, not +deliverables to reproduce mechanically. + +Require TemPad Dev MCP to provide trustworthy design evidence for the current +selection or an exact `nodeId` inside the user's established scope. Never +reconstruct the design from memory, screenshots alone, or `get_structure` +metadata. + +## Evidence and authority + +Use each source only for what it can establish: + +- **The user** sets scope, requirements, prohibitions, and missing product or + implementation decisions. +- **The project** sets framework, file placement, component boundaries, + styling, tokens, assets, dependencies, and verification conventions. +- **TemPad Dev** sets visible structure and rendered design facts. + +Follow project instruction files for concerns outside Figma-to-code +translation. Do not add policy for routing, analytics, i18n, CMS, or other +orthogonal systems. + +TemPad can establish visible hierarchy, layout, spacing, typography, color, +effects, token references, exported assets, and codegen unit context. It cannot +establish unevidenced states, responsive behavior, business logic, navigation, +validation, analytics, or project conventions. Treat `get_structure` as +hierarchy and geometry evidence only, never as missing style truth. + +## Workflow + +### 1. Establish the implementation envelope + +Read only local evidence that can change this implementation, in this order: + +1. applicable `AGENTS.md` or equivalent instructions; +2. relevant design-system, token, component, and asset guidance; +3. the nearest comparable implementation and reusable primitives; +4. framework, styling, and check configuration needed for this task. + +Determine the target file or component boundary, framework, styling method, +token and asset paths, reuse candidates, dependency constraints, and narrowest +relevant checks. Inspect Tailwind version and theme scales only when the +project actually uses Tailwind-compatible tooling. + +Do not inventory the repository broadly after the needed envelope is clear. If +a missing project decision would materially change the result, ask before +implementation. + +### 2. Read the design at the requested scope + +Call TemPad Dev's `get_code` before implementing: + +- use `resolveTokens: false` by default; +- omit `nodeId` for the current single selection; pass one only when the user + supplied it or TemPad returned the exact ID for a targeted read inside the + user's established scope; +- set `preferredLang` from the established project target; +- keep TemPad's default vector behavior unless the user explicitly requests + asset-preserving vector fidelity and the active MCP version supports it. + +Use `resolveTokens: true` only when the user explicitly does not want design +token references. Treat returned `lang` as authoritative because plugin +configuration may override `preferredLang`. + +Retain the returned `code`, `lang`, `warnings`, `assets`, `tokens`, and +`codegen` facts that bear on the implementation. Use +`codegen.config.{cssUnit,rootFontSize,scale}` for exact unit conversion. + +Prefer one top-level read that preserves the requested composition. If the +tool is unavailable, points at the wrong file, or returns incomplete evidence, +read [recovery.md](references/recovery.md) before doing anything else. + +### 3. Separate facts, adaptations, and gaps + +Before editing, distinguish: + +- **design facts** to preserve; +- **project-native adaptations** supported by existing components, tokens, + utilities, or asset conventions; +- **unevidenced product decisions** that must remain unimplemented or be asked. + +Map by rendered value and semantics, not by a convenient name. A familiar +component or token is a candidate, not proof of equivalence. If more than one +material implementation path remains equally plausible, ask the user. Infer +only low-consequence details and report any inference that affects the result. + +### 4. Implement the smallest coherent change + +- Keep the established framework, styling system, file placement, imports, and + abstraction level. Do not introduce a parallel system. +- Reuse an existing primitive only when its semantics and rendered behavior fit + without guessing. Do not force reuse that erases design facts. +- Preserve exact rendered values unless project evidence proves an equivalent + token, utility, or component. For `rem` output, convert with TemPad's actual + `cssUnit`, `rootFontSize`, and `scale`. +- Preserve intentional uncommon output, including pseudo-elements, filters, + masks, blend and backdrop effects, gradients, and non-default compositing, + unless a documented project constraint requires an adaptation. +- Implement only evidenced states and responsiveness. Do not invent hover, + loading, error, empty, disabled, or responsive behavior. +- Use native semantic elements and preserve keyboard access and accessible + names when an established primitive does not already provide them. +- Add no runtime or build dependency without user approval unless the user has + explicitly waived that constraint. +- Keep `data-hint-*` attributes out of shipped code. + +When TemPad returns relevant entries, load only the matching protocol: + +- assets: read [Assets](references/assets-and-tokens.md#assets) and follow the + project's asset delivery path; +- token references: read [Tokens](references/assets-and-tokens.md#tokens) and + follow the project's token workflow. + +Read both when both are present and skip both when neither is present. + +Do not enter a visual tuning loop. Change the implementation again only when +new project, design, tool, or verification evidence identifies a concrete +defect. + +### 5. Verify in the project's real workflow + +Run the narrowest relevant checks defined by project instructions and scripts. +Repair implementation failures and rerun the affected checks. Use an existing +preview, screenshot, or comparison workflow when available; do not invent a +universal verification matrix. + +If no runnable check exists, report the implementation as unverified. Do not +claim visual completion without a real project comparison path; ask the user +to confirm the rendered result against Figma. + +## Hard stops + +Stop instead of shipping when: + +- TemPad is unavailable, unauthorized, inactive on the intended file, or + cannot provide a trustworthy visible parent composition; +- the target is unreadable or not visible; +- project, design, and user evidence still conflict after targeted recovery; +- a missing decision would materially change behavior, structure, dependency, + asset delivery, or token mapping; +- required assets cannot be retrieved or stored under project policy. + +If blocked, give at most three concrete actions that would unblock the task. + +## Handoff + +Report: + +- what changed and where; +- only the relevant adaptation, inference, warning, asset/token handling, or + residual visual risk; +- checks run, their result, and what remains unverified. + +Keep absent concerns absent from the handoff. Do not produce a compliance +checklist for branches the task never used. + +## Decision example + +If TemPad emits `padding: 15px` and the project has a `space-4` token worth +`16px`, preserve `15px` unless project evidence explicitly makes the token the +intended mapping. Project consistency selects the representation; it does not +authorize changing the visible design. diff --git a/agent-plugin/targets/codex/skills/figma-design-to-code/agents/openai.yaml b/agent-plugin/targets/codex/skills/figma-design-to-code/agents/openai.yaml new file mode 100644 index 00000000..406fbf6e --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-design-to-code/agents/openai.yaml @@ -0,0 +1,7 @@ +interface: + display_name: 'Figma Design to Code' + short_description: 'Implement project-consistent UI code from Figma' + icon_small: './assets/icon.svg' + icon_large: './assets/icon.svg' + brand_color: '#0098FF' + default_prompt: 'Use $figma-design-to-code to implement the selected Figma design in the current project.' diff --git a/agent-plugin/targets/codex/skills/figma-design-to-code/assets/icon.svg b/agent-plugin/targets/codex/skills/figma-design-to-code/assets/icon.svg new file mode 100644 index 00000000..2e8c6946 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-design-to-code/assets/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/agent-plugin/targets/codex/skills/figma-design-to-code/references/assets-and-tokens.md b/agent-plugin/targets/codex/skills/figma-design-to-code/references/assets-and-tokens.md new file mode 100644 index 00000000..01dec4a6 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-design-to-code/references/assets-and-tokens.md @@ -0,0 +1,47 @@ +# Translate assets and tokens + +Read this reference only when `get_code` returns `assets` or `tokens`. + +## Assets + +Follow the project's established asset and icon policy before TemPad delivery +details. + +- Download bytes only from a TemPad-provided `asset.url`. Never substitute a + public internet asset. +- Treat assets as files to store or reference, not text evidence to parse. +- If project policy forbids storing them, reference TemPad URLs only when the + user accepts the local-server dependency, and report it. +- Treat emitted `` markup as design truth for structure, + size, and instance color. Refactor delivery only through an existing project + SVG path. +- If upload falls back to inline SVG, preserve that markup rather than + resynthesizing the vector. +- `themeable: true` permits one contextual color channel, usually + `currentColor`; drive it through the established wrapper or icon convention. + Preserve internal palettes when `themeable` is absent. +- Do not invent a new SVG pipeline, multi-color props, or custom variables. + +If a required asset cannot be retrieved or represented under project policy, +stop rather than draw or substitute it from memory. + +## Tokens + +Preserve token usage when the target project can carry or map it safely. +Token facts may be direct values or mode-specific values keyed by +`Collection:Mode`; preserve aliases between variables when present. + +- Map to an existing project token only when value, reference behavior, + semantics, and relevant mode agree. A similar name is insufficient. +- Preserve TemPad token references through the project's normal token workflow + when that workflow can accept them. +- Add a token only when the project already defines how and this task calls for + it. +- If landing location, mode, or mapping remains ambiguous, use the exact + rendered value and report the fallback. +- Use hint metadata only while reasoning about a mode; never ship hint + attributes. + +When tokens and explicit rendered values disagree, do not silently choose. +Narrow the design evidence or ask the user which source expresses the intended +state. diff --git a/agent-plugin/targets/codex/skills/figma-design-to-code/references/recovery.md b/agent-plugin/targets/codex/skills/figma-design-to-code/references/recovery.md new file mode 100644 index 00000000..88cf1e89 --- /dev/null +++ b/agent-plugin/targets/codex/skills/figma-design-to-code/references/recovery.md @@ -0,0 +1,54 @@ +# Recover trustworthy design evidence + +Read this reference only when TemPad is unavailable, a `get_code` call warns +or fails, or the requested selection cannot fit in one trustworthy response. + +## Connection and target failures + +For a transient transport failure, retry once. Do not blind-retry invalid +selection, hidden node, wrong file, deterministic budget, or depth errors. + +If TemPad is unavailable or active on the wrong file, stop and ask the user to: + +1. enable MCP access in TemPad Dev **Preferences > Agent integration**; +2. keep the intended TemPad Dev and Figma tab active; +3. use the MCP badge in the panel to activate the intended file when multiple + Figma tabs are open. + +Do not edit code while design evidence is untrustworthy. + +## Incomplete `get_code` results + +Preserve the largest trustworthy parent composition and narrow only the +missing evidence: + +- **`depth-cap`**: keep the returned top-level composition, then use returned + `data-hint-id` values for targeted child `get_code` calls. +- **budget overflow or shell response**: keep the returned parent shell, then + fetch omitted children separately. Use the smallest parent that still proves + their shared layout. Plain string truncation is not evidence. +- **hierarchy, geometry, or overlap uncertainty**: call TemPad Dev's + `get_structure` only to resolve that uncertainty or select a narrower retry + target. + +Never rebuild a missing parent from child metadata. If no trustworthy parent +shell can be recovered, stop the full implementation and ask the user to +narrow the selection or choose the highest-priority subtree. + +If a budget error requires user action, report its consumption, limit, and +overage from the tool response. + +## Resolve contradictions + +Prefer the evidence source with authority over the disputed fact: project +evidence for implementation conventions, `get_code` for visible design, and +the user for product intent. Narrow the read once when the conflict may be a +scope problem. If the sources still disagree, stop rather than choose silently. + +## Worked example + +When a large frame returns a usable header-and-grid shell but omits three cards, +keep the shell as the parent layout, fetch only those card subtrees, and insert +them into the known grid. If the response contains cards but no trustworthy +grid shell, do not infer columns or spacing from `get_structure`; request a +narrower parent selection. diff --git a/agent-plugin/targets/plugins-cli/.mcp.json b/agent-plugin/targets/plugins-cli/.mcp.json new file mode 100644 index 00000000..3789c234 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/.mcp.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "tempad-dev": { + "command": "npx", + "args": [ + "-y", + "@tempad-dev/mcp@latest" + ] + } + } +} diff --git a/agent-plugin/targets/plugins-cli/.plugin/plugin.json b/agent-plugin/targets/plugins-cli/.plugin/plugin.json new file mode 100644 index 00000000..33a40b43 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/.plugin/plugin.json @@ -0,0 +1,21 @@ +{ + "name": "tempad-dev", + "version": "0.2.0", + "description": "Connect your coding agent to Figma. Create and edit native designs, inspect existing designs, and implement UI in your codebase.", + "author": { + "name": "TemPad Dev" + }, + "homepage": "https://github.com/ecomfe/tempad-dev#agent-integration", + "repository": "https://github.com/ecomfe/tempad-dev", + "license": "MIT", + "keywords": [ + "figma", + "mcp", + "skill", + "agent-integration", + "design-to-code", + "canvas-authoring", + "design-system", + "frontend" + ] +} diff --git a/agent-plugin/targets/plugins-cli/CHANGELOG.md b/agent-plugin/targets/plugins-cli/CHANGELOG.md new file mode 100644 index 00000000..1e9275fc --- /dev/null +++ b/agent-plugin/targets/plugins-cli/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +## 0.2.0 + +- Routed the `plugins` CLI through its own hook-free compatibility package and marketplace, + with installer discovery checks for both skills and MCP configuration. +- Added design-task lifecycle guidance and Stop/Done controls. Codex App uses MCP metadata and + native IPC without hooks; Claude uses installed lifecycle and Stop hooks. +- Documented native Codex App comments, Queue/Steer timing, and element-editor Save & Queue + shortcuts. Other clients retain task controls without comment delivery. + +- Added `figma-canvas-authoring` for creating and editing native Figma designs, alongside the + existing `figma-design-to-code` skill. +- Added progressive references for native authoring, fonts, images, icons, resource bindings, + and scoped editing. Direct, Reuse, and Author workflows keep resource decisions tied to the task. +- Grounded new compositions in inspectable evidence and required inspection of the rendered result + plus relevant native facts, with focused repair of observed defects. +- Made the portable Agent Plugins 1.0 bundle the shared source for installation, with synchronized + Codex and Claude compatibility manifests and refreshed icons. +- Paired the plugin with extension 0.21.0 and MCP 0.8.0 through `@tempad-dev/mcp@latest`. + The MCP server requires Node.js 22.x, 24.x, or 26+. diff --git a/agent-plugin/targets/plugins-cli/README.md b/agent-plugin/targets/plugins-cli/README.md new file mode 100644 index 00000000..3e7d6d69 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/README.md @@ -0,0 +1,173 @@ +# TemPad Dev Agent Plugin + +[Simplified Chinese](./README.zh-Hans.md) + +Read, edit, and implement Figma designs through your coding agent or IDE. This plugin includes: + +- `figma-canvas-authoring`: create and revise native Figma designs, reusing accessible components, variables, and styles as needed. +- `figma-design-to-code`: use Figma design context to implement UI with your project’s components and conventions. +- The TemPad Dev MCP server configuration: connect to the Figma file open in your browser. + +Requires the TemPad Dev browser extension. Canvas editing also requires edit access to the Figma Design file. For manual inspection and output plugins, see the full [user guide](https://github.com/ecomfe/tempad-dev/blob/main/README.md). + +This plugin follows [Agent Plugins 1.0](https://agent-plugins.org/) and is published from one +source as a standard package, a compatibility package for the `plugins` CLI, and a package per +native host. Prefer native installation on Codex and Claude. Codex App binds tasks over MCP +metadata and native IPC, so its plugin registers no lifecycle hooks. + +## Cursor and VS Code installation + +For Cursor and VS Code, select the corresponding target: + +```bash +npx plugins add ecomfe/tempad-dev --target cursor +npx plugins add ecomfe/tempad-dev --target vscode +``` + +The installer reads `.plugin/marketplace.json` and installs the generated `plugins-cli` +compatibility package, which contains both skills and MCP configuration without lifecycle hooks. +This path is verified with `plugins@1.3.4`. Agent Plugins 1.0 consumers can use the separate +`agent-plugin/targets/standard` package; the current `plugins` CLI does not read that format. + +## Codex and Claude installation + +Use these native marketplace flows for Codex and Claude. Claude's lifecycle hooks require +the host's normal trust review; Codex does not register hooks. +The `--sparse` paths limit checkout to the host's marketplace and generated package, including +its skills and any required hooks. Codex repeats `--sparse` for each path; Claude accepts multiple +paths after one `--sparse`. The `plugins` CLI used for Cursor and VS Code has no equivalent flag. + +### Codex + +```bash +codex plugin marketplace add ecomfe/tempad-dev --ref main --sparse .agents --sparse agent-plugin/targets/codex +codex plugin add tempad-dev@tempad-dev +``` + +You can also install **TemPad Dev** from the Codex app plugin directory after adding the +marketplace. + +### Claude Code and Claude Desktop + +```bash +claude plugin marketplace add ecomfe/tempad-dev --sparse .claude-plugin agent-plugin/targets/claude +claude plugin install tempad-dev@tempad-dev +``` + +The plugin appears in Claude Desktop after the marketplace is added. + +For clients without Agent Plugin support, follow the direct MCP and standalone skill setup in the +[complete setup guide](https://github.com/ecomfe/tempad-dev/blob/main/README.md#agent-integration). + +## Usage + +Before using the integration, open TemPad Dev in Figma, then open **Preferences → Agent +integration** and enable **MCP access**. Canvas authoring is available while the active Figma +Design file is editable. + +## Upgrading + +The canvas-authoring release pairs Agent Plugin **0.2.0**, TemPad Dev extension **0.21.0**, and +MCP server **0.8.0**. Node.js **22.x, 24.x, or 26+** is required for the MCP server. + +1. Update the browser extension and reload the Figma tab. +2. Update the installed plugin through the client or installer used originally. With standalone + setup, update both `figma-design-to-code` and `figma-canvas-authoring`. +3. Keep the release MCP configuration on `@tempad-dev/mcp@latest`; replace any previous + `@alpha` or fixed alpha version. Reconnect the MCP client and start a new task so it loads the + updated tools and skills. If a stale Hub is reported, close tasks using the old MCP server + before reconnecting. +4. Open TemPad Dev, enable **MCP access**, and click the MCP badge in the intended Figma tab when + a session choice is needed. The badge selects the file receiving tool calls. + +## Packaging source of truth + +Everything is authored once under `agent-plugin/src/` and published by +`pnpm agent-plugin:build`. Every target is generated; never edit one. + +| Path | Role | +| ---------------------------------- | ------------------------------------------------- | +| `agent-plugin/src/plugin.json` | Standard manifest; owns all shared metadata | +| `agent-plugin/src/mcp.json` | Standard MCP configuration | +| `agent-plugin/src/skills/` | Both skills | +| `agent-plugin/src/clients/claude/` | Claude lifecycle hooks | +| `agent-plugin/src/clients/codex/` | Codex directory presentation (`interface.json`) | +| `agent-plugin/src/clients/shared/` | Hook transport shared by hosts | +| `agent-plugin/targets/standard` | Generated; also the standalone skills URL | +| `agent-plugin/targets/plugins-cli` | Generated compatibility package for `plugins` CLI | +| `agent-plugin/targets/codex` | Generated Codex marketplace package | +| `agent-plugin/targets/claude` | Generated Claude marketplace package | + +Each target carries only what its own installer reads. A standard consumer projects `plugin.json` +onto the host itself, so shipping a host layout beside it would create a second source of truth for +the same package; each host target likewise omits the standard manifests and the other host's +directory. Only Claude loads lifecycle hooks, so only `targets/claude` carries `clients/`. +The `plugins-cli` package carries `.plugin/plugin.json` and `.mcp.json`; its marketplace is +generated separately so the CLI does not select the Claude package. Verify discovery through +the actual CLI with `pnpm agent-plugin:check-installer` after changing packaging. + +## Task controls and client enhancements + +Design tasks can pause and resume across turns. Figma's canvas status bar shows the +source client, a Stop control, and a counted comment entry. Stop permanently cancels +the current task; subsequent design work explicitly begins a fresh task. Lifecycle pauses can resume +with a new lease epoch and require a fresh canvas read before writing. See the +[task and client design](https://github.com/ecomfe/tempad-dev/blob/main/docs/extension/mcp-design-tasks.md). + +The normal setup is the TemPad Dev extension configuration followed by this plugin's +installation. There are no control +addresses, environment variables, or helper services for users to configure. + +Codex App binds tasks from host-supplied MCP metadata and follows native conversation +state through the existing IPC connection. Claude retains lifecycle and Stop hooks. +Comments are delivered only through native conversation messages on compatible Codex App +hosts. TemPad Dev discovers the original conversation through the App's existing local +connection. Where supported, Queue submits the batch to the host's native queue, where it waits until the +conversation is ready. As soon as the host confirms admission, TemPad Dev clears the submitted +comments and markers, stops the sending indicator, and allows another batch. This confirmation +means the host received the comments, not that the agent finished the requested changes. +When native queue admission is unavailable, Queue waits in the Hub for existing queued +messages to clear and the conversation to accept a new response. The sending indicator +remains until that admission is confirmed. If queue state cannot be checked, comments +remain saved and delivery reports an error. Compatible hosts also support native server-queue +admission; these messages may appear in Codex after its next queue refresh. +Steer adds comments to an active response or starts a response when the conversation is idle. +Failed or uncertain delivery retains drafts; uncertain delivery is not automatically resent. +Comments never fall back to hooks. + +| Editor | Enter or click the submit button | Command/Ctrl+Enter or Command/Ctrl+click | +| --------------------------------- | -------------------------------- | ---------------------------------------- | +| Element comment | Save the comment without sending | Save & Queue the whole batch | +| General comment in the status bar | Queue the whole batch | Steer the whole batch | + +A batch includes all saved element comments and the general comment. Shift+Enter inserts a +newline in either editor. Saving an element comment alone does not send it. + +Claude, Codex CLI, and other clients currently provide task status and Stop/Done without +comment controls. Previously saved drafts remain in extension-local storage. + +Stop immediately blocks further writes from the current task and permanently cancels it +once an executing operation drains. The cancelled task cannot resume. The agent respects +Stop without automatically replacing it; necessary or user-requested design work can +explicitly begin a fresh task. No separate Figma unlock is needed. Codex App Stop also +requests native interruption of the exact bound turn; a delayed Stop cannot interrupt a +newer turn. Stop and Done also remove this task's comments that are still in the native queue, +leaving unrelated messages intact. Failed cleanup is retried after reconnection; already consumed +input cannot be recalled. Local cancellation remains effective if the host is unavailable. Claude +conveys Stop at the next hooked tool boundary. Native Codex delivery is enabled +only after the exact conversation owner reports support; no manual connection setup +is required. See the task and client design for the current validation scope. + +The native adapter uses Unix sockets on macOS/Linux and Codex's local named pipe on Windows. +macOS Steer and paused native queue admission/removal have been exercised against Codex App +26.908.70816. Automatic queue execution and the complete installed-plugin/Figma UI flow still +require live verification. Windows and Linux coverage is limited to source inspection and +automated tests; it does not establish complete host support. + +With a supported connection, select an element, save its feedback draft, then send the +numbered batch from the canvas status bar. Drafts can be edited or deleted and survive +navigation and closed tabs in extension-local storage, isolated by file, agent conversation, and task. +Successful delivery clears the submitted markers together; restoring drafts never sends them. + +The agent reports the result and its Figma link in the conversation, where users can +continue with follow-up requests. Task tools return text and structured data. diff --git a/agent-plugin/targets/plugins-cli/README.zh-Hans.md b/agent-plugin/targets/plugins-cli/README.zh-Hans.md new file mode 100644 index 00000000..bc5feda9 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/README.zh-Hans.md @@ -0,0 +1,130 @@ +# TemPad Dev Agent Plugin + +[English](./README.md) + +在你的 coding agent 或 IDE 中读取、编辑和实现 Figma 设计。这个插件包含: + +- `figma-canvas-authoring`:创建和修改原生 Figma 设计,按任务需要复用可访问的组件、变量和样式。 +- `figma-design-to-code`:读取 Figma 设计信息,结合项目已有组件和约定实现 UI。 +- TemPad Dev MCP server 配置:连接浏览器中打开的 Figma 文件。 + +需要安装 TemPad Dev 浏览器扩展。画布编辑还需要 Figma Design 文件的编辑权限。手动检查设计和输出插件的完整说明见 [使用指南](https://github.com/ecomfe/tempad-dev/blob/main/README.zh-Hans.md)。 + +本插件遵循 [Agent Plugins 1.0](https://agent-plugins.org/),并从同一份内容源发布一个标准包 +(供自行适配该标准的客户端使用)、一个 `plugins` CLI 兼容包,以及每个原生宿主各一个包。Codex 与 Claude 请优先使用原生安装。 +Codex App 通过 MCP 元数据和原生 IPC 绑定任务,其插件不注册生命周期 hooks。 + +## Cursor 和 VS Code 安装 + +Cursor 和 VS Code 请指定对应的 target: + +```bash +npx plugins add ecomfe/tempad-dev --target cursor +npx plugins add ecomfe/tempad-dev --target vscode +``` + +安装器读取 `.plugin/marketplace.json`,安装生成的 `plugins-cli` 兼容包,其中包含两个 skill +和 MCP 配置,不包含生命周期 hooks。此路径已通过 `plugins@1.3.4` 验证。支持 Agent Plugins 1.0 +的客户端可使用独立的 `agent-plugin/targets/standard` 标准包;当前 `plugins` CLI 不读取该格式。 + +## Codex 和 Claude 安装 + +使用以下原生 marketplace 流程。Claude 提示时,请检查并信任插件的生命周期 hooks;Codex 不注册 hooks。 +`--sparse` 将检出范围限制为对应宿主的 marketplace 和生成包,包含所需的 skill 及 hooks。 +Codex 为每个路径重复指定 `--sparse`;Claude 在一个 `--sparse` 后接受多个路径。 +Cursor 和 VS Code 使用的 `plugins` CLI 没有对应参数。 + +### Codex + +```bash +codex plugin marketplace add ecomfe/tempad-dev --ref main --sparse .agents --sparse agent-plugin/targets/codex +codex plugin add tempad-dev@tempad-dev +``` + +添加 marketplace 后,也可以从 Codex 应用的插件目录安装 **TemPad Dev**。 + +### Claude Code 和 Claude Desktop + +```bash +claude plugin marketplace add ecomfe/tempad-dev --sparse .claude-plugin agent-plugin/targets/claude +claude plugin install tempad-dev@tempad-dev +``` + +添加 marketplace 后,该插件也会出现在 Claude Desktop 中。 + +不支持 Agent Plugin 的客户端,请按照 +[完整配置指南](https://github.com/ecomfe/tempad-dev/blob/main/README.zh-Hans.md#agent-集成)直接配置 MCP 并安装独立 skill。 + +## 使用 + +使用前,请在 Figma 中打开 TemPad Dev,然后进入 **Preferences → Agent integration** +并启用 **MCP access**。启用后,只要当前 Figma Design 文件可编辑,即可进行画布创作。 + +设计任务的状态栏显示 agent 状态、Stop/Done 和评论入口。Stop 会立即阻止当前任务继续写入, +在执行中的操作结束后永久取消该任务;重新连接也不会恢复它。后续设计工作需要明确开始新任务。 + +评论目前仅支持通过兼容 Codex App 的原生会话通道发送。Queue 将整批评论交给宿主的原生队列, +等待会话可以执行时再处理。宿主确认接收后,TemPad Dev 会清空本批评论和标记、停止发送指示, +并允许继续输入下一批;这表示已接收,不表示 agent 已完成修改。如果原生入队不可用, +Queue 会在 Hub 中等待已有排队消息清空、会话能接收新回复,此时发送指示会保留到确认接收。 +如果无法确认队列状态,会保留评论并报告发送错误。兼容宿主也支持原生服务端队列入队, +这些消息可能会在 Codex 下一次刷新队列时才显示。 +Steer 会将评论追加到正在执行的回复,空闲时直接开始新回复。投递失败或结果不确定时保留草稿, +结果不确定的评论不会自动重发,也不会回退到 hooks。 + +| 编辑位置 | Enter 或点击提交按钮 | Command/Ctrl+Enter 或 Command/Ctrl+点击 | +| ------------------ | -------------------- | ---------------------------------------- | +| 元素评论 | 保存当前评论,不发送 | Save & Queue:保存当前评论并排队整批评论 | +| 状态栏中的总体评论 | 排队整批评论 | 使用 Steer 发送整批评论 | + +整批评论包含全部已保存的元素评论和总体评论;两个编辑器中都可以用 Shift+Enter 换行。 +草稿按文件、会话和任务隔离,关闭标签页后仍保留,恢复草稿不会自动发送。 + +Codex App 的任务绑定和状态同步使用 MCP 元数据及原生 IPC,不依赖 hooks。Stop 还会请求中断 +对应的 Codex 回合,迟到的 Stop 不会中断较新的回合。Stop 和 Done 会移除当前任务尚未执行的 +原生队列评论,保留其它消息;清理失败后会在重新连接时重试,已被宿主取走的输入无法撤回。 +宿主不可用时,本地取消仍然生效。Claude 保留生命周期和 Stop 通知 hooks;Claude、Codex CLI +等尚未接入原生投递的客户端提供任务状态和 Stop/Done,但不显示评论入口,已有草稿不会删除。 + +原生适配器在 macOS/Linux 上使用 Unix socket,在 Windows 上使用 Codex 的本机 Named Pipe。 +已在 macOS Codex App 26.908.70816 上实测 Steer,以及暂停状态下的原生队列入队和移除。 +自动执行和完整的已安装插件/Figma UI 流程仍待实测;Windows/Linux 的证据限于源码检查和 +自动化测试,尚不能据此宣称完整宿主支持。 + +## 升级 + +本次画布创作版本应配套使用 Agent Plugin **0.2.0**、TemPad Dev 扩展 **0.21.0** 和 MCP +server **0.8.0**。MCP server 要求 Node.js **22.x、24.x 或 26+**。 + +1. 更新浏览器扩展,并重新加载 Figma 标签页。 +2. 通过原先使用的客户端或安装器更新 plugin。独立配置时,请同时更新 + `figma-design-to-code` 和 `figma-canvas-authoring`。 +3. 正式版 MCP 配置使用 `@tempad-dev/mcp@latest`;请替换旧的 `@alpha` 或固定 alpha 版本。 + 重新连接 MCP client 并新建任务,以加载更新后的工具和 skill。若提示 Hub 过期,请先关闭 + 使用旧 MCP server 的任务,再重新连接。 +4. 打开 TemPad Dev 并启用 **MCP access**;需要选择会话时,点击目标 Figma 标签页内的 MCP + badge。实际接收工具调用的文件由该 badge 选择。 + +## 封装内容源 + +所有内容只在 `agent-plugin/src/` 下编写一次,由 `pnpm agent-plugin:build` 生成各个产物。 +所有产物都是生成的,请勿直接编辑。 + +| 路径 | 作用 | +| ---------------------------------- | -------------------------------------- | +| `agent-plugin/src/plugin.json` | 标准清单,拥有全部公共 metadata | +| `agent-plugin/src/mcp.json` | 标准 MCP 配置 | +| `agent-plugin/src/skills/` | 两个 skill | +| `agent-plugin/src/clients/claude/` | Claude 生命周期 hooks | +| `agent-plugin/src/clients/codex/` | Codex 目录展示信息(`interface.json`) | +| `agent-plugin/src/clients/shared/` | 宿主共用的 hook 传输脚本 | +| `agent-plugin/targets/standard` | 生成产物,同时是独立 skills 的安装地址 | +| `agent-plugin/targets/plugins-cli` | 为 `plugins` CLI 生成的兼容包 | +| `agent-plugin/targets/codex` | 生成的 Codex marketplace 包 | +| `agent-plugin/targets/claude` | 生成的 Claude marketplace 包 | + +每个产物只携带自己的安装方式会读取的内容。标准客户端会自行把 `plugin.json` 适配到宿主, +因此在它旁边放置宿主清单会让同一个包出现第二个事实来源;两个宿主产物同理省略标准清单 +以及对方宿主的目录。只有 Claude 会加载生命周期 hooks,因此只有 `targets/claude` 携带 `clients/`。 +`plugins-cli` 包使用 `.plugin/plugin.json` 和 `.mcp.json`,由独立生成的 marketplace 入口路由, +避免 CLI 选中 Claude 包。修改封装后运行 `pnpm agent-plugin:check-installer`,验证实际 CLI 的发现结果。 diff --git a/agent-plugin/targets/plugins-cli/assets/icon-padded.svg b/agent-plugin/targets/plugins-cli/assets/icon-padded.svg new file mode 100644 index 00000000..2e8c6946 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/assets/icon-padded.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/agent-plugin/targets/plugins-cli/assets/icon.png b/agent-plugin/targets/plugins-cli/assets/icon.png new file mode 100644 index 00000000..5d1f6bf2 Binary files /dev/null and b/agent-plugin/targets/plugins-cli/assets/icon.png differ diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/SKILL.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/SKILL.md new file mode 100644 index 00000000..7732c78f --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/SKILL.md @@ -0,0 +1,183 @@ +--- +name: figma-canvas-authoring +description: >- + Create or update native, editable Figma designs with TemPad Dev MCP: screens, + flows, components, and requested local design-system resources, including on + an empty canvas. Use for Design in Figma work, not Figma-to-code, critique + without edits, or raw Plugin API automation. +--- + +# Design in Figma + +Deliver the smallest complete native Figma result that serves the user's +situation. Keep the working experience in view as you research, compose, and +repair. A successful tool call establishes a document change; the rendered +result and its editable structure establish whether that change served the task. + +## Establish the task + +Use the user's exact target and constraints. For an existing design, inspect +`get_code` and its pixels before changing the composition; use `get_structure` +for hierarchy, geometry, stable keys, or selected native facts. Write to a known +page directly. Create or activate a page only when the task calls for it. +Infer low-consequence gaps; ask when a missing decision would materially change +the result. Keep unrelated account, filesystem, task, and page metadata out of +product identity and content. + +Require an editable Figma Design file and the intended tab's active MCP +connection. Use the host's TemPad MCP tools for all canvas reads and writes. +If unavailable, report the integration problem and stop. Do not launch the CLI, +recreate its transport, use browser automation to set up the canvas, or emit raw +Plugin API operations. Research and asset acquisition use the host's appropriate +tools; website research uses the in-app browser when available unless the user +selected another browser. + +For new design work, call `begin_design` before research or canvas work with a short task title +and a fresh UUID `requestId`; reuse that UUID only to retry the same begin. Carry +the returned `taskId` on related TemPad tool calls. The runtime handles status and +placement feedback: do not report progress, send heartbeats, or choose coordinates +for a placeholder. Use `list_design_sessions` when the intended Figma target is +unclear, then pass its exact `sessionId` to `begin_design`. Pausing a turn preserves +the design task. Follow-up comments continue the same task, including after a completed +pass while its review remains open. After completion, pause, or lease expiry, use `resume_design` with its latest +`epoch`, carry the returned epoch as `taskEpoch`, and reread the affected canvas +with `get_structure` or `get_code` before writing. Use `get_design_task` only when +recovery needs the current state or epoch. Never replay a stale write. Stop in TemPad Dev +permanently cancels the current task after any running operation settles. Never resume +that cancelled task or automatically replace it. If further design work is necessary or +the user requests it, explicitly call `begin_design` with a fresh requestId. No separate +Figma unlock or new user turn is required. Done closes the review; a closed or replaced +task cannot resume. Do not automatically begin a replacement for comments on such a task. +Element feedback arrives as a numbered batch. Each item retains its file, page, +and node identity from draft creation. Reread every target before applying the +batch; do not substitute the current selection. +Supported hosts receive submitted feedback through native conversation messages. Do not poll for it or +set up a helper process or host control endpoint. + +Begin without waiting to choose a canvas location. Once an existing design region is +known, use `set_design_anchor` with its exact Frame node ID and `taskId`. Otherwise +the first created top-level Frame anchors automatically. The region stays stable +across reads and writes; call this tool again only to explicitly change design regions. + +## Ground and compose + +For net-new or materially redesigned interfaces without an established system, +read [style-grounding.md](references/style-grounding.md) and inspect relevant +real product screens or a permitted implementation before the first Canvas +write. The evidence must expose the interface relationships informing the new +work. Search snippets, URLs, failed retrievals, and generated concepts do not +establish a precedent. Subject imagery establishes its depicted content, not +its surrounding application's design. Try another permitted source when +retrieval fails; if none is inspectable, disclose the gap and stop. Supplied +source pixels or implementation can satisfy this boundary; mechanical edits do +not require unrelated research. + +Resolve what the person needs to recognize or change, which content and states +carry that work, and how the interface makes their consequences perceptible. +Choose the screen or flow, visual language, density, and scrolling model from +that situation. Use [visual-composition.md](references/visual-composition.md) +when forming or reconsidering a composition. Familiar structures and distinctive +ones both need a reason in the task. Research informs an independent solution; +it does not authorize copying a composition or placing reference pixels on the +canvas unless the user requested that treatment. + +When selecting or changing fonts, or when script coverage is uncertain, read +[typefaces.md](references/typefaces.md) to resolve candidates and native identities. + +Choose representations by their role in the work. Once an image, icon, diagram, +or visualization matters to the direction, read +[visual-assets.md](references/visual-assets.md) and its selected branch. Do not +silently replace the chosen content or medium to simplify sourcing or markup. +For content-bearing graphics, preserve meaningful marks and editable +relationships with native shapes, vectors, text, and groups; styled FRAME +lookalikes do not acquire drawing semantics. Read +[document-geometry.md](references/document-geometry.md) for that construction. +Ordinary UI panels, controls, backgrounds, and separators remain Canvas HTML. + +Choose resources from the task, not repetition alone: + +- **Direct:** default for a first net-new composition. Use primitives, literals, + and assets. Do not discover or create a design system just because shapes or + values repeat. +- **Reuse:** use [design-system-reuse.md](references/design-system-reuse.md) when + the user, selected source, or project evidence establishes the applicable + system. Catalog names, domain similarity, or mere file presence do not prove + relevance. +- **Author:** use [design-system-authoring.md](references/design-system-authoring.md) + when reusable resources are requested or established as part of the + deliverable. Prove the composition and one real consumer before propagation. + +For selected variables and typography styles, read +[resource-mapping.md](references/resource-mapping.md): define or discover their +identities once, then use variable utilities and text-style classes throughout +the markup. + +## Build, inspect, and repair + +For markup create or structural update, read +[canvas-html.md](references/canvas-html.md) and check its preflight before the +call. Canvas HTML is a strict native-state dialect; browser CSS assumptions do +not apply. Page-only and native-only operations omit markup. Load native +mechanics only for the capabilities selected below. + +Build a materially complete representative screen, then open its PNG before +expanding the flow or extracting resources. Judge whether the whole supports +the intended work. When it does not, focus on the particular relationship or +execution defect that explains the mismatch and repair it. A skeleton, resource +board, or generated concept does not establish the real composition. + +For updates, read [editing.md](references/editing.md). Preserve the requested +source, unrelated fields, and stable identities while updating every dependent +representation of the changed state. For larger results, split at meaningful +screen or section boundaries and carry shared roles coherently across them. + +Inspect every `apply_canvas` result, including warnings. Repair each observed +unintended defect or disclose why it remains. A local validation failure calls +for a local payload correction; it does not justify discarding a working root +or simplifying away the intended content. Open pixels again after the final +material write, covering every materially distinct screen. Verify native facts +with `get_structure` when identity, placement, editability, or representation +matters. Opened pixels prove visual access, not good judgment; a structural pass +proves only the conditions checked. + +Finish when the requested experience is coherent and observed defects are +repaired, accepted with reason, or disclosed. Report the delivered result and +material limitations, with a Figma link to the delivered nodes. A verified Direct +result is complete without an unsolicited component pass. + +Call `end_design` after the design outcome and its final verification are complete. +An optional short `summary` records the applied result in task history. +Use `outcome: "cancelled"` only when abandoning the design. Waiting for user input +or stopping a turn is a pause, not completion or cancellation. Host lifecycle hooks +handle pauses when available; do not create progress or heartbeat calls. + +## Native mechanics — load when selected + +Read the selected reference completely; do not preload the capability catalog. +Examples demonstrate syntax, not a design template. + +| Capability | Reference | +| --------------------------------------------------------------------- | ----------------------------------------------------------- | +| Exact updates, removal, or editor context | [editing.md](references/editing.md) | +| Pages, sections, groups, Booleans, masks, transforms, shapes, vectors | [document-geometry.md](references/document-geometry.md) | +| Paints, media, effects, shaders, grids, guides | [paints-effects.md](references/paints-effects.md) | +| Exact fonts, rich text, range styles, lists, hyperlinks | [rich-text.md](references/rich-text.md) | +| Components, variants, properties, Slots | [component-authoring.md](references/component-authoring.md) | +| Variables, collections, modes, bindings | [variables.md](references/variables.md) | +| CSS variable utilities and named text-style classes | [resource-mapping.md](references/resource-mapping.md) | +| Paint, Text, Effect, Grid styles | [local-styles.md](references/local-styles.md) | +| Authorized independent research, assets, inventory, or QA delegation | [delegation.md](references/delegation.md) | + +## Mutation boundaries + +Use returned IDs and stable keys as identity, never names. Create describes a +new complete root or exact new page. Update targets an exact node or page; +omissions preserve live state. `activate` always requires `page.id` or +`page.pageKey`, even when only changing selection. + +Never mutate outside scope, remove manual or unkeyed content, or remove a +component with surviving instances. An instance's definition-derived sublayers +are not authoring targets. Do not mutate remote resources, publish, detach or +reset instances, execute arbitrary JavaScript, or imitate an unresolved +resource. Use `null` only for supported links or managed resources the requested +change actually removes. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/agents/openai.yaml b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/agents/openai.yaml new file mode 100644 index 00000000..25e5075e --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/agents/openai.yaml @@ -0,0 +1,7 @@ +interface: + display_name: 'Design in Figma' + short_description: 'Create user-directed native Figma designs' + icon_small: './assets/icon.svg' + icon_large: './assets/icon.svg' + brand_color: '#0098FF' + default_prompt: 'Use $figma-canvas-authoring to create a native Figma design while following my resource constraints.' diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/assets/icon.svg b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/assets/icon.svg new file mode 100644 index 00000000..2e8c6946 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/assets/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/canvas-html.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/canvas-html.md new file mode 100644 index 00000000..2cc27632 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/canvas-html.md @@ -0,0 +1,277 @@ +# Canvas HTML and Tailwind subset + +Canvas HTML describes desired state, not browser rendering. Use its elements for +interface structure and genuine simple UI geometry, not as a drawing medium. +Do not assemble `div` or `span` primitives to imitate a photograph, +illustration, icon, logo, texture, or other content-bearing visual; acquire the +appropriate routed raster or vector asset instead. Classes do not cover every +Figma result: use routed native bindings for gradients, media, non-shadow +effects, masks, transforms, exact fonts, and rich text. + +One `apply_canvas` markup tree may contain at most 160 elements and 12 levels. +This is a safety ceiling, not a target. Before calling, count the tree, include +only assets referenced by that call, and split larger work at meaningful screen +or section boundaries. + +Prefer supported Tailwind utilities; use arbitrary pixels only off the default +scale. Numeric spacing follows Tailwind v4's `4px` unit. Selected Figma resources +can use CSS variable utilities and `type-*` text-style classes through +[resource-mapping.md](resource-mapping.md). Arbitrary project theme extensions, +variants, plugins, viewport-dependent utilities, and CSS cascade are unsupported. + +## Contents + +- [Preflight each markup tree](#preflight-each-markup-tree) +- [Elements and identity](#elements-and-identity) +- [Layout](#layout) +- [Appearance and text](#appearance-and-text) + +## Preflight each markup tree + +Immediately before each create or structural update, scan the complete supplied +tree once: + +- require a fixed width and height on the markup root; +- give every `div` with children `flex` or `grid`, or make every child absolute + with one edge per axis and fixed parent and child dimensions; +- keep flex, grid, gap, padding, border, corner, and box-shadow classes off + `span`; +- resolve defaults and overrides before assembling each class list. Both + `text-[16px] text-[18px]` and `text-black text-white` are conflicts, not + overrides. A helper must choose the final font size, color, and line height + instead of appending them to hard-coded defaults; +- trace every `w-full`, `h-full`, and `grow` against its direct parent's axis and + the element's required dimensions; +- give a fixed-height grid explicit row tracks when its children should fill or + divide that height; omitted rows remain content-sized; +- count at most 160 elements and 12 levels, and include only assets referenced by + this call. + +Correct the complete set before calling instead of serializing until validation +reveals issues one at a time. + +## Elements and identity + +- Use `div`, `span`, or a component tag returned by the active catalog. +- Give every element one unique `data-key` of letters, numbers, `. / : _ -`. +- Use `data-node-id` only in update mode to adopt an exact live node; instance + sublayers are not authoring targets. +- When markup is supplied, every `native` key must occur as a `data-key` in that + supplied tree; existence elsewhere in the live target does not satisfy this. + For mixed structural/native edits, include each bound node under its actual + parent path, or send the omitted nodes' changes in a separate native-only update. + When only native state changes, omit markup, target the exact managed root, + and key `native` by existing stable keys in that scope. This preserves topology; + masks and node removal still require structural markup. +- Use no arbitrary attributes on `div` or `span`. Common catalog links use + `data-var-="vN"` and `data-style-="sN"`; `"none"` explicitly + unlinks that field. +- A `span` contains only text and `
` or `
` line breaks. Use + `whitespace-pre-wrap` for literal newlines or repeated spaces. A plain `&` is + literal unless it forms a semicolon-terminated entity; supported entities + decode. Canvas typography does not inherit from a parent `div`: put font and + other text utilities on each `span`/TEXT node. Put flex/grid, gaps, padding, + borders, corners, and box shadows on a parent `div`. +- A component tag is childless, includes its returned `data-ref`, and accepts + returned props plus the shared class, identity, variable, and style + attributes. + +Variable attributes use kebab-case native field names: fill, stroke, characters, +visible, dimensions/bounds, gaps, four paddings/corners/stroke sides, radius, +stroke weight, opacity, and whole-node font/line-height/letter-spacing/paragraph +fields. Style attributes are `data-style-fill`, `data-style-stroke`, +`data-style-text`, `data-style-effect`, and `data-style-grid`. Node-type and +fallback rules still apply. + +Every primitive needs one width and one height. Supported fixed forms are: + +- default spacing: `w-N`, `h-N`, `size-N` (`N * 4px`), plus `w-px`, `h-px`, `size-px` +- default width containers: `w-3xs|2xs|xs|sm|md|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl` +- exact: `w-[Npx]`, `h-[Npx]`, `size-[Npx]` +- hug: `w-fit`, `h-fit` +- hug both axes: `size-fit` +- fill: `w-full`, `h-full`, or `size-full` for both axes +- bounds: numeric, `px`, or arbitrary-pixel values with `min-w`, `max-w`, `min-h`, or `max-h`; + width bounds also accept the default container names; use `min-w-none`, `max-w-none`, + `min-h-none`, or `max-h-none` to clear a bound in an update + +Text using `w-fit` also needs `h-fit`; prefer `size-fit`. Fixed-width `h-fit` +remains valid for wrapping text. + +Create and update markup roots require fixed width and height; fill, hug, and +grow are invalid even when the live target has a sized parent. + +Use `w-full` only on a `flex-col` cross axis, `h-full` only on a `flex-row` +cross axis, and `grow` on the main axis; `grow-0` clears growth. `grow` does not +replace required dimensions—for a row track use `grow w-fit h-[3px]`. Give +growing text in constrained rows a positive `min-w-*` to prevent collapse. +Prefer a hug main axis for content stacks whose extent is not behaviorally +fixed. Otherwise budget the fixed axis as padding + gaps + fixed/minimum child +extents. A non-overflowing result is still wrong when resolved content consumes +the intended inset; compare rendered child edges with the layout's padding. +Grid children may fill cells. Direct dimension variables require fixed +fallbacks. Fixed sizes must be at least `0.01px`; native lines use `h-[0px]`. + +## Layout + +Use Auto Layout for ordinary product UI. `flex` follows CSS's horizontal default; +use `flex-row` when that direction should be explicit and `flex-col` for a +vertical stack: + +- `flex`, `flex flex-row`, or `flex flex-col` +- `items-start|center|end|baseline` +- `justify-start|center|end|between` +- `flex-wrap`, `flex-nowrap`, `content-between`, `content-normal` +- `gap-N`, `gap-x-N`, `gap-y-N`, or exact `[Npx]` +- `p`, `px`, `py`, `pt`, `pr`, `pb`, `pl` with `-N`, `-px`, or `-[Npx]` +- `box-border`, `box-content` + +New Auto Layout frames include inside strokes by default (`box-border`); +`box-content` excludes them. Center/outside strokes never affect layout, and +each nested frame owns its setting. Fixed create sizes must cover opposing +padding plus included inside strokes. Figma determines `FILL` geometry and +border-box distribution. Derive exact descendant or instance sizes from the +rendered inner box, not nominal parent size; prefer valid cross-axis fill and +exceed the box only for intentional bleed or overlap. + +`managed-content-overflow` means managed Text or INSTANCE exceeds its direct +managed Frame or Component, or a native INSTANCE contains descendant content +beyond its own fixed root. Inspect edges, clipping, rendering, and instance +bounds; resize or realign accidental overflow and retain only intentional bleed, +crop, or overlap. Property-driven content outside an INSTANCE root is a broken +component contract rather than intentional consumer overflow. + +`justify-between` uses nonnegative native Auto gap and keeps one child at the +start. Use negative `figma.autoLayout.itemSpacing` only for intentional overlap. +Omitting box-sizing on update preserves the live setting. + +`hidden` and BOOLEAN visibility remove in-flow children, changing gaps, +positions, and hug bounds. To preserve geometry, keep a fixed slot and toggle +its inner child. `absolute left-[Npx] top-[Npx]` maps to Ignore Auto Layout for +true overlays; it needs fixed offsets, cannot fill/grow, and leaves surrounding +flow unchanged. Its text and Auto Layout descendants may still hug. + +For grid use: + +- `grid grid-cols-N` +- optional `grid-rows-N` +- custom tracks: `grid-cols-[1fr_240px_fit-content(100%)]` +- optional `grid-flow-row` or `grid-flow-none` +- child placement: `col-start-N`, `row-start-N`, `col-span-N`, `row-span-N` +- child alignment: `justify-self-auto|start|center|end`, + `self-auto|start|center|end` + +Give manual grid children both row and column starts or neither. Auto-flow uses +source order without explicit starts. A height-hugging grid cannot use flexible +or automatic rows; fix either its height or row tracks. Omitting `grid-rows-*` +creates native automatic content-sized rows; increasing only the container +height does not enlarge them. + +For a coherent board larger than one call, first create one fixed parent: + +```json +{ + "mode": "create", + "markup": "
" +} +``` + +Then append one bounded screen per update. Keep the root key and classes stable, +target its returned ID, and omit previously added children so they remain in +place: + +```json +{ + "mode": "update", + "targetNodeId": "FrameID:app-board", + "markup": "
" +} +``` + +For freeform composition, omit layout classes and give each child `absolute` +with exactly one horizontal edge (`left-*` or `right-*`) and one vertical edge +(`top-*` or `bottom-*`), including negative or exact values, or use a native +relative transform. Edge placement needs fixed parent and child sizing modes; +right/bottom offsets are resolved from live bounds after each markup apply. They +are placements, not reactive CSS anchors: use Auto Layout for alignment that +must follow later mode changes without another markup apply. A plain +non-flex/grid `div` is freeform even with one child; opt into layout for every +in-flow child. Absolute children cannot grow or fill; use `static` to return one +to Auto Layout on update. + +## Appearance and text + +Frame appearance: + +- `bg-transparent|white|black`, or an exact CSS hex value +- Linear backgrounds use `bg-linear-to-t|tr|r|br|b|bl|l|tl` with exact + `from-white|black|[#hex]`, optional `via-white|black|[#hex]`, and required + `to-white|black|[#hex]` stops. Stops are fixed at 0, optional 0.5, and 1; + `bg-gradient-to-*` is accepted as a legacy alias. Do not combine a gradient + with a solid background, direct fill paints, or a fill style/variable. +- `border`, `border-N`, `border-[Npx]`; use `border-x|y|t|r|b|l` with the same widths +- `border-white|black`, or an exact CSS hex value +- `rounded`, `rounded-none|xs|sm|md|lg|xl|2xl|3xl|4xl|full`, or `rounded-[Npx]`; + prefix the value with `t`, `r`, `b`, `l`, `tl`, `tr`, `br`, or `bl` for individual sides/corners +- `overflow-hidden`, `overflow-visible` +- A clipped rounded frame does not paint its inside stroke above children. A + filled child that reaches a curved edge can therefore square off or hide the + boundary even with `overflow-hidden`; inset it, give the touching child + corners a corresponding inner radius, or add a dedicated foreground + boundary, then inspect the rendered pixels. +- Exact pixel shadow lists through `shadow-[...]` or `inset-shadow-[...]`. + Each layer needs an explicit hex, `rgb()`, or `rgba()` color and two to four + pixel lengths; use underscores for spaces, for example + `shadow-[0_8px_24px_rgba(0,0,0,0.16)]`. +- `shadow-none` and `inset-shadow-none` clear their class-owned effect stack. + Theme-dependent named scales such as `shadow-md` are unsupported: use an + explicit native style or typed effect/variable binding for a reusable token, + or resolve the governing theme before applying and provide the exact value. + +Figma accepts shadow spread only on rectangles and ellipses, or on frames, +components, and instances with a visible fill and clipping enabled. + +A new border needs weight and paint, literal or bound. Updates may change either +independently; omission preserves the other. + +New frames are transparent when background is omitted, including frames added +during update. On an existing frame, omission preserves its live background; +use `bg-transparent` to clear it. Set an explicit background when fill is +intended. + +Shared appearance: + +- `opacity-N` (`N%`) or `opacity-[0..1]`, `hidden`, `visible` +- `rotate-N`, `-rotate-N`, `rotate-none`, or `rotate-[Ndeg]` +- `mix-blend-` with `pass-through`, `normal`, `darken`, `multiply`, + `plus-darker`, `color-burn`, `lighten`, `screen`, `plus-lighter`, + `color-dodge`, `overlay`, `soft-light`, `hard-light`, `difference`, + `exclusion`, `hue`, `saturation`, `color`, or `luminosity` + +Text: + +- `font-sans|serif|mono` resolve to an editor-available family in that category, + preferring Inter, Noto Serif, and Noto Sans Mono +- `font-thin|extralight|light|normal|medium|semibold|bold|extrabold|black` +- `text-xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl` with their default line + heights, `text-SIZE/N`, or `text-[Npx]` +- `leading-none|tight|snug|normal|relaxed|loose`, `leading-N`, `leading-[Npx]`, + `leading-[N%]`, or a unitless arbitrary ratio +- `tracking-tighter|tight|normal|wide|wider|widest`, `tracking-[Npx]`, + `tracking-[N%]`, or `tracking-[Nem]` +- `text-left|center|right|justify` +- `normal-case`, `uppercase`, `lowercase`, `capitalize` +- `no-underline`, `underline`, `line-through` +- `truncate`, `line-clamp-N`, `line-clamp-none` +- `text-white|black`, an exact CSS hex value, `whitespace-pre-wrap` +- `text-shadow-[...]` for an exact pixel text-shadow list with a color and two + or three pixel lengths; `text-shadow-none` clears it + +A `span` is one TEXT node, so `bg-*` and `text-*` share its fill channel. Put +background on a parent `div` and color on its child `span`. + +Shadow classes compile to the native effect stack; never combine them with +`figma.effects` or an Effect style on that node. + +Unknown elements, attributes, classes, CSS, responsive/state prefixes, custom +themes, margins, percentages, and plugins fail closed. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/component-authoring.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/component-authoring.md new file mode 100644 index 00000000..99573887 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/component-authoring.md @@ -0,0 +1,294 @@ +# Author reusable components + +Use this reference after selecting a reusable local component. It explains +representation, not library strategy. New local components need no +`get_design_system`; use catalogs only for discovery or normalized library +props, and exact returned IDs for newly authored components. + +## Shared-responsibility decision + +New local components are opt-in for net-new authoring. Use Author when the user +requested reusable components before delivery, accepted a component pass after +seeing the completed design, or applicable project evidence makes a local +component deliverable part of the task. Existing components may still be Reuse +without authoring new ones. Repeated appearance, repeated data, screen count, +possible future reuse, or tool availability do not opt the user into Author. + +Make the decision from real usages after the representative composition is +visually sound: + +1. Name the shared job and compare the intended consumers. +2. Identify stable anatomy and meaningful content, media, state, availability, + label, swap, or slot differences. +3. Choose Author only when a truthful supported contract provides more + coordination value than it costs to create, migrate, and verify. Otherwise + keep the responsibility Direct; a brief reason is enough. +4. Bound Author at the smallest subtree that owns the complete shared job. Do + not infer that a parent must become reusable because a nested label, icon, + status, or button is reusable. + +Do not inventory or rank every recurring family, and do not turn repetition +into a quota. Record only selected Author responsibilities and their concrete +consumers. Before propagation, create the smallest real definition, instantiate +it once, and verify the exact reference. Then replace the selected consumers +with native instances; never leave literal lookalikes for a responsibility that +was deliberately selected as Author. Use the exact returned `rootNodeId` or +`nodeIdsByKey` entry for every usage. + +A keyed primitive cannot become an INSTANCE in place. Update its bounded +ancestor, add the instance under a new key, and remove the old key in the same +call. + +Stop component authoring if the ID is missing, the instance fails, or the +definition is empty, default-sized, or loses +properties. Do not substitute primitives or claim completion. Continue only +independent Direct work, report the degraded component result, and remove a +temporary definition only when unused and safe. Re-read a corrupt definition +and its intended usage; never rebuild it in place or remove one with instances. +Recreate only when unused. If a diagnostic would systematize primitives that +this definition replaces, reconcile the component first; independent token work +does not need to wait. + +Before handoff, reconcile only selected Author responsibilities with actual +consumers. Each selected consumer must be a native INSTANCE. Inspect the most +demanding instance through its descendants; root type and size do not prove +wrapping, slots, media, or state content fit. +Revise the contract or boundary when real content breaks it. + +Markup-only updates preserve keyed components, sets, instances, and shapes. +Restate native bindings only when changing native state; new native nodes still +need declarations or component references. + +Copy a complete recipe and change its design facts. Do not infer TemPad's +component shape from raw Plugin API calls. + +## Contents + +- [Define the contract from real usages](#define-the-contract-from-real-usages) +- [Keep source definitions discoverable](#keep-source-definitions-discoverable) +- [Component and properties](#component-and-properties) +- [Consume an authored component directly](#consume-an-authored-component-directly) +- [Variant set](#variant-set) +- [Slots and instances](#slots-and-instances) + +## Define the contract from real usages + +Compare every intended usage. Separate stable anatomy from varying content, +state, or nested substitution; map differences to the smallest supported Text, +Boolean, Instance Swap, variant, Slot, or nested-composition mechanism. Treat a +field as invariant only when real usages agree. + +Size the contract from real extremes: test the longest wrapping text, widest +label, largest nested swap, and materially different slots. Compare descendant +bounds with the INSTANCE root; screenshots can still paint invalid overflow. +If content exceeds the root, enlarge the definition, add a truthful size +variant, or move the varying region outside a smaller stable boundary. +If consumer-specific media cannot be expressed by the available instance +contract, keep that media direct and componentize the stable surrounding +responsibility; never freeze one image into every instance to retain a larger +component boundary. + +When stable anatomy should evolve together, expressible state differences +support a shared contract. Keep it local only when divergence or contract cost +outweighs coordinated change. + +If the contract cannot express a meaningful difference, revise it or keep the +responsibility local. Never force usages to share placeholder content or an +accidental default merely because outer geometry repeats. + +Model each mutually exclusive categorical concern as one variant axis; do not +replace it with Booleans that allow impossible combinations. Reserve Booleans +for independently optional content or behavior. + +Expose one choice through both a variant and independent property only when real +usages vary them independently. Keep each source variant's visible state +truthful; instance overrides do not repair accidental source defaults. + +## Keep source definitions discoverable + +Keep main components and sets visible at natural bounds in a clearly named +source area separate from screens. Never hide, clip, make transparent, or +invisibly nest them. For several families, use a top-level SECTION with +`contentsHidden: false`, discoverable definition children, and content-sized +bounds. + +Keep each real definition once, without redundant specimens. Before handoff, +use `get_structure` to verify every definition is visible and every intended +consumer is an INSTANCE. Inspect distinct source variants at readable scale; +names, content, and styling must encode the same state. + +Keep the source area operational and visually subordinate: use the smallest +content-sized container that exposes the definitions, outside the consumer +board or screen sequence. Do not turn it into a branded artboard, mood board, +visual-thesis panel, token showcase, or documentation page unless the user asks +for that deliverable. Product screenshots and presentation framing should stay +focused on the requested experience. + +## Component and properties + +This complete call creates a component with TEXT and BOOLEAN properties and +connects both properties to its label layer. + +```json +{ + "mode": "create", + "markup": "
Continue
", + "native": { + "button": { + "figma": { + "name": "Button", + "component": { + "type": "COMPONENT", + "properties": { + "label": { + "type": "TEXT", + "name": "Label", + "defaultValue": "Continue" + }, + "show-label": { + "type": "BOOLEAN", + "name": "Show label", + "defaultValue": true + } + } + } + } + }, + "button/label": { + "figma": { + "componentPropertyReferences": { + "characters": "label", + "visible": "show-label" + } + } + } + } +} +``` + +Stable keys such as `label` connect definitions and sublayer references within +one result; they are not generated Figma property names. Supported property +types are `BOOLEAN`, `TEXT`, and `INSTANCE_SWAP`, linked through `visible`, +`characters`, and `mainComponent` respectively. + +BOOLEAN properties control visibility, not styling. Hidden in-flow children +leave Auto Layout. Use this only for intentionally optional content. To preserve +geometry, toggle an inner layer inside a fixed slot, use `absolute` for a true +overlay, or use geometry-equivalent variants for whole-state changes. + +Treat `layout-affecting-visibility-property` as a contract warning. Fix it when +geometry must stay stable. Accept intentional reflow only after comparing true +and false instances for bounds, sibling positions, baselines, and clipping; one +default-state screenshot is insufficient. + +## Consume an authored component directly + +Use the exact ID returned by `apply_canvas`. For TemPad-authored components, +`componentProperties` accepts their stable definition keys. This follow-up +needs no catalog: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "screen/action": { + "component": { "id": "ComponentID:created-button" }, + "componentProperties": { "label": "Save", "show-label": true } + } + } +} +``` + +Replace the illustrative ID with the returned ID. Never invent IDs or use this +shortcut for unidentified library components. + +## Variant set + +This call creates two components in one variant set. Every direct child of a new +set must be an authored component; names encode axes as `Property=Value`. + +```json +{ + "mode": "create", + "markup": "
Continue
Continue
", + "native": { + "button-set": { + "figma": { + "name": "Button", + "component": { "type": "COMPONENT_SET" } + } + }, + "button/default": { + "figma": { + "name": "State=Default", + "component": { "type": "COMPONENT" } + } + }, + "button/hover": { + "figma": { + "name": "State=Hover", + "component": { "type": "COMPONENT" } + } + } + } +} +``` + +Consume the returned set ID and select siblings through variant properties. If +the call returns the set as `rootNodeId`, this creates Default and Hover: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "screen/default": { + "component": { "id": "ComponentSetID:created-button-set" } + }, + "screen/hover": { + "component": { "id": "ComponentSetID:created-button-set" }, + "componentProperties": { "State": "Hover" } + } + } +} +``` + +Replace the ID with returned `rootNodeId`. The set ID creates its default; +`componentProperties` selects another encoded variant. An exact child ID from +`nodeIdsByKey` may instantiate that variant directly. + +Use `descriptionMarkdown` and `documentationLink` only for real guidance, inside +`figma.component` beside `type` and `properties`: + +```json +{ + "figma": { + "name": "Button", + "component": { + "type": "COMPONENT", + "descriptionMarkdown": "Primary action" + } + } +} +``` + +Define shared properties on the component set rather than on one variant. + +## Slots and instances + +Use `figma.slot` only for an intentional flexible nested-content API. New slots +must be inside local authored components and include `property.name`; markup +children become defaults. Optional settings control stretching, empty display, +child limits, and preferred values. + +An `INSTANCE_SWAP` default uses exact live component/set ID `{ "id": "..." }` +or importable library key `{ "key": "..." }`. Preferred values require +`{ "type": "COMPONENT" | "COMPONENT_SET", "key": "..." }` and accept neither +live IDs nor catalog refs. Resolve catalog identity before authoring and never +invent it. Put advanced state under `figma.instance`; omission preserves normal +override behavior. + +Never edit a remote component, nest a main component inside another main +component, delete a component with surviving instances, or create properties +and variants that the requested component API does not need. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/delegation.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/delegation.md new file mode 100644 index 00000000..181b7cc9 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/delegation.md @@ -0,0 +1,82 @@ +# Delegate bounded evidence work + +Delegate evidence gathering or isolated production, never focal judgment. The +main agent synthesizes results and remains the only Canvas writer. + +## Pass the delegation gate + +Delegate only work that is: + +1. **Separable:** has a stable objective independent of evolving design choices. +2. **Compressible:** needs only a compact task-local brief. +3. **Isolated:** is read-only or produces an isolated artifact without mutating + Figma, design-system state, or another agent's files. +4. **Verifiable:** returns citations, importable asset references, exact facts, + or a bounded defect list the main agent can inspect. +5. **Worth coordinating:** gains enough from parallelism, specialist capability, + or independent review to justify handoff and synthesis. + +Keep work local if any condition fails. Do not delegate for ritual, convenience, +or another unsupported aesthetic opinion. + +## Write a complete handoff + +Give each worker one objective and its relevance, only required task evidence +and constraints, permitted tools and sources, explicit exclusions including no +Canvas writes, and an exact output contract and stop condition. The main agent +must read required Canvas references and set safety boundaries; never delegate +interpretation of this skill. Prefer fresh or minimum-context workers, pass +source evidence rather than conclusions, and avoid overlapping assignments. + +## Suitable tracks + +### Research scout + +After framing the design problem, delegate a bounded evidence question. Return: + +```txt +open decision; exact source; applicable finding; relevance; authority boundary +``` + +The scout does not choose direction. Combine questions only when their search +space is shared; use multiple scouts only for independent spaces. + +### Asset scout + +After fixing asset requirements and import contract, return one importable +`imageUrl` or `assetHash` per asset plus MIME type, dimensions, provenance, and +factual description. Return no bytes, rejected candidates, or transcript. The +main agent owns selection and integration. + +### Independent QA scout + +After a representative composition exists, provide a fresh worker its +screenshot and frozen brief without creator rationale or suspected defects. Ask +for at most eight observations: + +```txt +severity; screen/node or region; observed defect; visible evidence; violated constraint +``` + +The scout neither edits nor declares completion; the main agent checks findings +against the live canvas. + +### Inventory scout + +Use read-only inventory when independent volume warrants it, such as several +screens or icon candidates. Require exact findings and references, not a design +proposal. + +## Orchestrate conservatively + +- Default to one worker; use at most two concurrent non-overlapping workers. +- Keep a faster local critical path with the main agent. +- Only the main agent resolves intent and conflicts, chooses direction, calls + `apply_canvas`, and accepts the result. +- Resolve conflicts from evidence, not voting; discard unverifiable or + out-of-scope claims and stop when evidence is sufficient. + +Never delegate interdependent page or component construction, component +authoring plus instance placement, concurrent updates to one root, final +composition, or final acceptance. These require one ordered mutation stream and +continuous awareness of the whole. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/design-system-authoring.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/design-system-authoring.md new file mode 100644 index 00000000..45825de5 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/design-system-authoring.md @@ -0,0 +1,87 @@ +# Implement a selected local design system + +Use this reference only when the user or resolved plan requires new local +components, variables, or styles. It translates that plan into native resources +and verifies delivery; it does not choose component strategy, visual language, +resource inventory, or token taxonomy. + +## Establish the implementation contract + +Before writing, identify each selected resource, responsibility, concrete +consumer, meaningful variation, and exclusion. Resolve any open material +boundary first. For components, use the gate in +[component-authoring.md](component-authoring.md); screen count, one-screen scope, +and visual similarity alone neither establish nor exclude a component. + +Keep a private reconciliation map: + +```txt +selected resource -> native representation -> intended consumers +``` + +A resource is complete only when its native definition or binding exists and +every intended consumer uses it. Equivalent primitives or literals are not +coverage. + +## Translate the plan + +Use this loop: + +1. Stabilize one representative composition. +2. Author only selected resources with known consumers. +3. Exercise each contract in that composition. +4. Propagate native instances and bindings to all intended consumers. +5. Reconcile the final artifact with the map. + +Preserve the decided semantics: + +- A variable carries a semantic value consumers must bind and evolve together; + name it by role, not literal. +- A local style carries a reusable paint, text, effect, or grid definition. Do + not duplicate one decision across resource types unless required. +- A component carries a reusable responsibility. Define stable anatomy and + expose only variations required by real usages. + +Use [resource-mapping.md](resource-mapping.md) to map selected variable and text +style identities once per apply, then consume them through familiar variable +utilities and `type-*` classes. A new resource and its first consumer can share +one call. Query available fonts independently through `get_design_system` with +`scope: "fonts"`; selecting a family does not require discovering a file system. + +Consume a component through a childless instance placeholder without layout or +appearance classes. Do not make a repeated shell or wrapping top-level subtree +a component unless every consumer can use that placeholder through supported +properties. Slots do not permit markup children on instance placeholders; keep +incompatible wrappers as ordinary structure around a compatible inner boundary. + +Map each real component difference to the smallest supported mechanism: Text, +Boolean, Instance Swap, variant, Slot, or nested composition. Use one variant +axis per mutually exclusive categorical concern and Booleans only for +independently optional concerns. Do not encode arbitrary content as variants, +generate unused combinations, or freeze varying content as invariant. + +If supported native mechanisms cannot express a real usage, do not weaken or +redesign it silently. Choose another valid boundary or report the limitation. + +Read [variables.md](variables.md), [local-styles.md](local-styles.md), or +[component-authoring.md](component-authoring.md) only for selected resource +types. + +## Verify the native handoff + +Verify through representative consumers, not definitions alone: inspect native +bindings, Auto Layout, text resizing, property behavior, and every material +state. Raw literals and primitive lookalikes do not demonstrate system usage. + +For components, verify visible inspectable definitions and native INSTANCE +consumers using [component-authoring.md](component-authoring.md). For variables +and styles, inspect live bindings rather than apply input or equal values. + +Resolve warnings through real consumers, or remove a resource only when the +resolved plan no longer includes it. Tool friction, payload size, or an easy +resource type does not alter the plan. Do not create swatches, specimens, +definition panels, or redundant examples solely for verification; add +documentation only when requested. + +Finish when selected resources support all requested usages and the live Figma +structure reconciles with the map. Do not expand for imagined future needs. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/design-system-reuse.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/design-system-reuse.md new file mode 100644 index 00000000..11cf574f --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/design-system-reuse.md @@ -0,0 +1,59 @@ +# Reuse an existing design system + +Use this reference only when reuse is allowed and relevant. If the user rejects +a design system, use Direct. + +## Discover definitions + +Call `get_design_system` without arguments. Its immutable deterministic catalog +contains: + +- a `catalogId` scoping all short refs; +- component tags, props, source pages, and native sizes; +- variables, collections, modes, styles, and shaders as refs such as `v1`, + `k1`, `m1_2`, `s1`, and `h1`; +- `cssName` on variables and `className` on text styles for direct use in markup; +- `omitted` and `nextCursor` when more definitions remain. + +The catalog neither scans usage nor loads pages or ranks resources. Select from +returned names, pages, summaries, props, types, scopes, and defaults. Continue a +cursor or inspect an exact ref only until evidence is sufficient. + +Prefer, in order: catalog component, supported component prop, matching native +style, semantic variable, then primitive or literal for a real gap. + +When variants, anatomy, layout, or semantic meaning affect the result, inspect +the exact `ref` with the same `catalogId`. Use its `previewNodeId` with +`get_screenshot` only when appearance affects selection. Read an existing +composition with `get_code` or `get_screenshot`; catalogs do not reveal usage +conventions. Never invent refs, IDs, keys, props, or variant values. + +## Apply catalog resources + +Component tags are childless, include returned `data-ref`, and use exact props. +Omit size classes to preserve native size. Use returned CSS variable names and +text-style classes through [resource-mapping.md](resource-mapping.md). For other +native fields, bind `data-var-="vN"` or `data-style-="sN"`; put +collection modes or strict native links under `native[data-key]`. + +Replace every illustrative ref in this contract with one from the active +catalog: + +```json +{ + "mode": "create", + "catalogId": "ds_example", + "markup": "
Team settings
", + "theme": { "textStyles": { "type-body": { "ref": "s1" } } }, + "native": { + "settings": { + "variableModes": { "k1": "m1_1" } + } + } +} +``` + +If a mandatory component is absent, ask the user to open its definition page; +otherwise use the normal primitive fallback. An empty canvas does not block +catalog reuse. When reuse is unavailable, create a small coherent primitive +draft—never a token or component library solely for one screen. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/document-geometry.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/document-geometry.md new file mode 100644 index 00000000..1f24c0d6 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/document-geometry.md @@ -0,0 +1,124 @@ +# Document and native geometry + +Use `native[key].figma` only for state HTML and classes cannot express honestly; +it remains declarative desired state. + +## Contents + +- [Pages and containers](#pages-and-containers) +- [Shapes and vectors](#shapes-and-vectors) +- [Transforms, masks, and native state](#transforms-masks-and-native-state) + +## Pages and containers + +Top-level `page` can set a name, exact zero-based document index, solid RGBA +background, ordered guides, and explicit variable modes. Page-only create uses +a new `pageKey` plus name. Page-only update uses +an exact `id` or `pageKey` and omits markup. A create root may target an existing +or new page directly; creating pages and writing nodes preserve the user's current +page and viewport. Do not activate a page merely to write there. +Markup updates stay on the target node's page. + +Use top-level `mode: "activate"` with exact page identity when editor context or +selection matters; `selection: []` clears selection. Use top-level `mode: +"remove"` with an owned `pageKey` to delete a page. Page deletion rejects the +last page, manual or unowned content, and surviving external dependencies. + +Use: + +- `figma.section: { contentsHidden? }` for canvas organization; +- `figma.group: true` for an intrinsic group; +- `figma.booleanOperation: "UNION" | "SUBTRACT" | "INTERSECT" | "EXCLUDE"` + for non-destructive geometry. + +Sections can be canvas roots or direct children of sections; a frame cannot +contain a section. Sections require fixed pixel dimensions and freeform +children. Groups and Booleans use `w-fit h-fit` with freeform children. A new +group needs one child and a Boolean needs two. When updating an intrinsic +container's children, +describe every live direct child because order is semantic. + +Sections have no frame clipping, so omit `overflow-hidden` and +`overflow-visible`. When `targetNodeId` is an existing section, retain +`figma.section` on the root or the frame-typed markup root is rejected. + +## Shapes and vectors + +Use a childless `div` with `figma.shape`: + +- `{ "type": "RECTANGLE" }` +- `{ "type": "LINE" }` +- `{ "type": "ELLIPSE", "arc": { "startAngle", "endAngle", "innerRadius" } }` +- `{ "type": "POLYGON", "pointCount": 3 }` +- `{ "type": "STAR", "pointCount": 5, "innerRadius": 0.5 }` +- `{ "type": "VECTOR", "paths": [...] }` +- `{ "type": "VECTOR", "network": {...}, "handleMirroring": "..." }` + +Use exact uppercase `M L Q C Z` paths for already-decided custom vector +geometry. Selected icon roles use sourced SVG through [icons.md](icons.md), not +remembered paths. Use a vector network only for branching segments, per-vertex +state, or region-specific fills or styles. Never provide both. New vectors need +geometry; omission preserves it on update and an empty path or network clears +it. + +Each path item is an object. `windingRule` is `"NONE"`, `"NONZERO"`, or +`"EVENODD"`; use `"NONE"` for an open stroked path. Path data uses +whitespace-separated uppercase commands and numbers. + +Figma normalizes path geometry to tight bounds before applying markup size. The +childless `div` defines final bounds, not a preserved viewport. For alignment, +offset it by the path's minimum x/y and size it to the x/y spans; otherwise a +partial-range path stretches to the box. Verify rendered anchors because +`get_structure` returns node bounds, not path coordinates. + +This Direct recipe creates an editable branch curve: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "branch": { + "figma": { + "name": "Branch", + "shape": { + "type": "VECTOR", + "paths": [ + { + "windingRule": "NONE", + "data": "M 14 300 C 30 252 52 188 104 20" + } + ] + }, + "fills": [], + "strokes": [{ "type": "SOLID", "color": { "r": 0.447, "g": 0.314, "b": 0.231 } }], + "stroke": { "weight": 2, "cap": "ROUND", "join": "ROUND" } + } + } + } +} +``` + +## Transforms, masks, and native state + +- `figma.name` sets the display name; `data-key` remains identity. +- `locked` and `aspectRatioLocked` set interaction state. +- `relativeTransform` is a complete native 2×3 unit-axis transform; width and + height carry scale. Do not combine it with `rotate-*`. On create roots, TemPad + preserves rotation and skew but replaces translation with automatic placement. +- `stroke` carries weights, alignment, caps, joins, miter, and `dashPattern`. +- `corners` carries radii and smoothing. +- `mask` is `"ALPHA"`, `"VECTOR"`, `"LUMINANCE"`, or `null`. + +Place a mask before masked siblings inside one dedicated frame and describe all +direct siblings on update. A non-null mask needs a following sibling. Omission +preserves mask state; `null` disables it. + +After changing a mask, layout grid, or frame guide, call `get_structure` with +`options.native: true` on the smallest relevant root. Verify `native.mask` and +sibling order, or returned `native.layoutGrids` and `native.guides`; desired +bindings alone are insufficient. + +Use `{ "ref": "…" }` for catalog resources nested in native state and +`sourceCanvasKey` or `{ "canvasKey": "…" }` for same-result forward node +references. Never insert raw Plugin API calls. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/editing.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/editing.md new file mode 100644 index 00000000..f8653bd5 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/editing.md @@ -0,0 +1,44 @@ +# Edit an existing result + +Use this reference for an update, removal, or change of editor context. Read the +exact target and recover managed keys from structured tool results when prior +call context is unavailable. Names are labels, not identity. + +## Describe the desired change + +Trace the requested change through its visible dependents: a changed selection +may affect the working surface, label, enabled action, and summary. Preserve +unrelated content and relationships. Preserving the source does not mean +retaining stale representations of its previous state. + +Use the smallest owning target that can express the complete change: + +- For native state on existing keys, target the exact managed root and send only + `native`; omit markup to preserve topology. +- For structural changes, read `canvas-html.md`, keep `data-key` stable, and + include the affected structure. Omitted existing fields and keyed elements + retain their live state; omission is not deletion. +- `removeKeys` removes owned descendants. Top-level `mode: "remove"` removes an + exact managed root or page. Do not remove manual/unkeyed content, unmanaged + resources, or surviving external consumers. +- `mode: "activate"` requires `page.id` or `page.pageKey`, even for a + selection-only change. It changes editor context, not document state. An + exact off-current-page write does not require activation. + +Respect instance boundaries. Change an instance root or its authorized +component definition, never a definition-derived sublayer. Select only the +native references needed for the intended change. + +## Recover locally + +Read the entire mutation result. For a rejected payload, correct all reported +issues together without changing the design to fit the error. A verification +failure is rolled back by TemPad; do not assume a partial successful edit. +For an unknown transport outcome, read the exact target before retrying a create +or removal so an uncertain response does not become a duplicate mutation. + +Repair warnings where they occur. Replace a whole root only when an observed +structural defect requires it and the complete intended content can be +preserved. Reopen the affected composition after its last material write and +inspect its dependents; read back protected native facts when preservation +matters. Do not expand a local correction into an unrelated restyle. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/icons.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/icons.md new file mode 100644 index 00000000..b3457638 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/icons.md @@ -0,0 +1,65 @@ +# Deliver icons + +Use this reference only after the composition selects an icon role. It does not +require icons, set an icon count, or choose a family or visual style. + +Prefer permitted current-file, catalog, project, or user sources; otherwise use +a trustworthy brief-compatible source and record material license constraints. +When inspected evidence establishes a family or geometry, use that permitted +source or a compatible one. A general library is a fallback only when its +stroke or fill, optical weight, corners, negative space, and platform semantics +remain coherent. Do not diversify sources by quota. + +Import exact SVG geometry. Never redraw a known icon from memory or replace an +icon role with Unicode, emoji, TEXT, or assembled primitives. A character, +shape, or cluster that communicates an affordance, object, or semantic category +is an icon role even when beside a worded label. Before markup, scan literal +text for pictographic Unicode, emoji, and symbols and route each qualifying mark +to a permitted vector source. Simple geometry remains valid only when it is +itself the intended status or data mark, divider, decoration, or brand shape. + +Search results and snippets identify external candidates only; they establish +neither geometry nor license. Open the governing license once and fetch or open +every exact SVG used before markup. If either remains uninspected, omit an +optional icon or report a required gap instead of inventing one. + +For Direct delivery, give the icon a childless `div` whose classes supply the +decided wrapper bounds. Declare the inspected SVG document in +`assets[assetKey]` with `type: "SVG"`, then set +`native[nodeKey].figma.svg.assetKey` to that alias. An optional `color` resolves +`currentColor`; omit it for explicit-color SVGs. Figma may import a Frame with +Vector children; treat that subtree as one opaque asset and never flatten or +reconcile it. + +This complete Direct recipe demonstrates the required shape, not a design +default; its identifiers and values stand in for the already-decided role and +inspected source: + +```json +{ + "mode": "create", + "markup": "
", + "assets": { + "search": { + "type": "SVG", + "svg": "" + } + }, + "native": { + "search-icon": { + "figma": { "svg": { "assetKey": "search", "color": "#334155" } } + } + } +} +``` + +Omit `color` when it is not part of the selected source. A markup-only call +cannot deliver the SVG geometry. Once an icon source has been selected and +inspected, do not replace it with text or primitives merely to avoid the +`assets` and `native` mapping. + +For larger exact SVG, declare a Hub asset using a full lowercase SHA-256: + +```json +{ "type": "SVG", "assetHash": "" } +``` diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/images.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/images.md new file mode 100644 index 00000000..b019a960 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/images.md @@ -0,0 +1,120 @@ +# Deliver images and illustrations + +Use this reference only after the composition selects an image or illustration +role and the common boundaries in [visual-assets.md](visual-assets.md) establish +its subject and medium. + +Treat existing assets, rights-established remote sources, generation, and +purpose-built vectors as acquisition routes. Choose the nearest route that +satisfies content, fidelity, rights, quality, and import requirements; tools +have no global priority. Before importing a remote asset, establish its +applicable usage rights and a recoverable source. A search result, accessible +URL, CDN host, or lack of a watermark does not establish permission. Confirm +Canvas delivery before layout depends on the asset. + +When depiction is part of a record, keep it. Text, category icons, generic +placeholders, and numbered markers may index the record but cannot replace its +visual content. Source or generate an established raster role, preserve exact +vector art when vector is the real medium, or disclose the gap. + +Keep only enough trace to recover material choices, the remote source and its +applicable terms, or content distinctions. Combine role, evidence, medium, +source, rights, and import treatment in one short rationale when needed; do not +create a per-asset ceremony. Record exact creator, license, or attribution only +when the applicable terms, policy, or handoff requires it; assets sharing one +route and terms may share a trace. + +When medium is unspecified, use nearest visual evidence or ask if the choice is +material; otherwise state a low-consequence assumption. + +Use generation when the decided role needs a bespoke or fictional subject, +identity, composition, or treatment. In a prototype, a coherent generated set +may be the nearest truthful source for distinct fictional records; do not +require stock search merely because each subject is ordinary. For a real named +subject or supplied identity, use the supplied or rights-established source and +do not generate a substitute. Before generation, map each planned asset to the +subject and consumer it serves; skip ceremony that does not protect fidelity, +rights, or import. + +Compose generation and Hub import in one programmatic execution so image bytes +never enter prose or expire between calls: pass the generator's `data:` URL +directly to TemPad's `upload_asset`, read its returned `assetHash`, then declare +that hash as an IMAGE asset in `apply_canvas`. Do not regenerate an unchanged +prompt only to recover an importable URL. If generation or `upload_asset` is +unavailable, choose a rights-established public image source only when it +preserves the intended medium; otherwise disclose the required gap. Never +generate first and silently switch medium because import failed. + +Use `imageUrl` for a rights-established public IMAGE paint or same-file +`imageHash` for an existing image. For generated or other local Hub content, +declare the returned full lowercase SHA-256, then use its alias in a basic fill: + +```json +{ + "assets": { "image": { "type": "IMAGE", "assetHash": "" } }, + "native": { + "image-node": { + "figma": { + "fills": [{ "type": "IMAGE", "assetKey": "image", "scaleMode": "FILL" }] + } + } + } +} +``` + +Inline bytes and local paths are unsupported. Remote URLs must resolve directly +to accessible images, not pages or thumbnails. + +When a supplied canvas image is itself a permitted source artifact and an exact +visible subregion must carry into the result, reuse its same-file `imageHash` +instead of redrawing that content. For an axis-aligned source rectangle +`(x, y, width, height)` within an image of size `(imageWidth, imageHeight)`, and +a destination with the same aspect ratio, declare: + +```js +{ + type: "IMAGE", + imageHash: "", + scaleMode: "CROP", + imageTransform: [ + [width / imageWidth, 0, x / imageWidth], + [0, height / imageHeight, y / imageHeight] + ] +} +``` + +Supply the evaluated finite numbers, not expression strings. If the destination +aspect ratio differs, first choose an aspect-correct source rectangle rather +than stretching the subject. Open the rendered crop and verify its native IMAGE +fill; a valid transform does not prove that the intended subject was isolated. + +When the medium must remain a real image, verify with `get_structure` and +`options.native: true`; `native.imageFills` must contain the expected non-null +Figma hash. Input URLs, successful mutation, and visually similar screenshots +are not native read-back. + +The main agent owns placement, crop, and final verification. In a comparison, +make visual differences represent the subjects rather than their source files: +normalize incidental canvas padding, crop, background, viewpoint, and apparent +scale when they would bias the decision; preserve and explain differences that +are real or cannot be normalized faithfully. + +Before markup, map every content-bearing image consumer to the subject it +claims to depict. Reuse one asset and crop only when consumers represent that +same subject; distinct records require distinct assets or crops that visibly +isolate the correct subject. A composite scene may serve the composition it +depicts, but cannot stand in for several named records. Stop and source or +generate missing media instead of serializing a false mapping. + +When a gallery, carousel, or thumbnail set promises several views of one +subject, every retained view must add distinct, truthful information. Repeating +one unchanged source and crop does not satisfy that role; unrelated subjects +break identity. Use distinct sourced views, evidence-supported crops, or +generation/editing only for a named same-subject coverage need that sourcing +cannot satisfy. Otherwise reduce the views or disclose the gap. + +For repeated depictions of the same subject, keep asset identity and crop +stable unless evidence requires variation. If required media remains +unavailable, report it; omit optional media or use a neutral slot only when the +requested outcome is unchanged. A neutral slot is an explicit fallback, not +representative content or proof of reusable variation. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/local-styles.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/local-styles.md new file mode 100644 index 00000000..74aec685 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/local-styles.md @@ -0,0 +1,61 @@ +# Author local styles + +Use this reference only when the user or resolved system plan requires a local +style. Do not extract styles from an ordinary screen. New local resources need +no catalog; send `catalogId` only when a nested `{ "ref": "…" }` deliberately +reuses an existing resource. + +Copy this recipe and change its design facts. Style authoring keys persist +file-wide and are neither names nor IDs. Namespace keys by product and role. In +shared drafts, also prefix generic visible names that could collide; retain +established project naming when already clear. + +For whole-node typography, prefer a `theme.textStyles` alias and a `type-*` +class using [resource-mapping.md](resource-mapping.md). The recipe below shows +the explicit native binding form, also used for paint, effect, and grid styles. + +```json +{ + "mode": "create", + "markup": "
Account
", + "styles": { + "product/style/surface": { + "type": "PAINT", + "name": "Product/Color/Surface", + "paints": [{ "type": "SOLID", "color": { "r": 1, "g": 1, "b": 1 } }] + }, + "product/style/heading": { + "type": "TEXT", + "name": "Product/Typography/Heading", + "fontName": { "family": "Inter", "style": "Semi Bold" }, + "fontSize": 20, + "lineHeight": { "unit": "PIXELS", "value": 28 } + } + }, + "native": { + "card": { + "styles": { + "fill": { "styleKey": "product/style/surface" } + } + }, + "card/title": { + "styles": { + "text": { "styleKey": "product/style/heading" } + } + } + } +} +``` + +Types are `PAINT`, `TEXT`, `EFFECT`, and `GRID`, using `paints`, text fields, +`effects`, or `layoutGrids` respectively. For exact Paint, Effect, and Grid +shapes beyond this recipe, read [paints-effects.md](paints-effects.md). + +Omission preserves managed state. Top-level `null` removes a managed style only +when absence is required and all live consumers are cleared or removed in the +same result. Never mutate remote resources, invent library keys, or create a +broad style library for one screen. + +`unbound-created-style` means a same-call style lacks a `styleKey` consumer. +Bind it to a representative property performing its named role or remove it. A +swatch or unrelated binding is not coverage. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/paints-effects.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/paints-effects.md new file mode 100644 index 00000000..c32b82f2 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/paints-effects.md @@ -0,0 +1,111 @@ +# Paints, effects, grids, guides, and media + +Use this reference whenever the result uses a nontrivial shadow, blur, glass, +texture, noise, image paint, layered gradient material, or layout aid, including +effects expressed as Canvas HTML classes. Resolve an image or illustration's +role, subject, and medium through [visual-assets.md](visual-assets.md), then its +source and delivery through [images.md](images.md). Prefer a matching catalog +style; otherwise use direct native arrays. + +## Catalog links + +```html +
+``` + +A style owns its channel. Do not combine a non-null fill or stroke style with a +whole-node variable on the same paint. Styled strokes still need literal, +typed, or variable-bound geometry. `null` unlinks; omission preserves. + +## Resolve shadow references + +Named scales such as `shadow-md` are theme references, not portable geometry: + +- Reuse: bind the matching catalog Effect style. +- Author: create and bind a local Effect style only when the system plan requires + it. +- Direct: use an exact `shadow-[...]` class or typed `figma.effects` value. + +Never assume Tailwind defaults or create a token only to resolve a named class. +`shadow-none`, `inset-shadow-none`, and `text-shadow-none` explicitly clear. + +Treat an outer shadow's rendered halo as part of the composition. Inspect the +final PNG beyond the root edges; visible granular or noisy fringe, or a halo +that dominates the captured bounds, is a defect even when the frame itself is +intact. Preserve intended depth by tightening blur, spread, or opacity or using +smaller layered shadows, then recheck. Do not flatten established material +treatment merely to hide the defect. + +## Native paint and effect stacks + +`figma.fills` and `figma.strokes` support ordered solid, linear/radial/angular/ +diamond gradient, image/video, Pattern, and fill-shader paints. +`figma.effects` supports ordered shadows, normal/progressive blur, noise, +texture, glass, and effect shaders. + +A `SOLID` paint uses RGB `color` and optional paint-level `opacity`; only +gradient stops use RGBA colors. Keep stroke geometry, including `dashPattern`, +in `figma.stroke`, not the stroke paint. + +Use the exact gradient enum and normalized RGBA stop shape; do not translate +from CSS or Plugin API names: + +```json +{ + "figma": { + "fills": [ + { + "type": "GRADIENT_LINEAR", + "gradientTransform": [ + [1, 0, 0], + [0, 1, 0] + ], + "gradientStops": [ + { "position": 0, "color": { "r": 1, "g": 0.43, "b": 0.29, "a": 1 } }, + { "position": 1, "color": { "r": 0.16, "g": 0.09, "b": 0.24, "a": 1 } } + ] + } + ] + } +} +``` + +Other gradient enums are `GRADIENT_RADIAL`, `GRADIENT_ANGULAR`, and +`GRADIENT_DIAMOND`. + +Omission preserves a stack; `[]` clears it. Direct stacks cannot share their +channel with a literal class, whole-node variable, or style. Use variable refs +such as `{ "ref": "v1" }` and shader refs such as `{ "ref": "h1" }`; use only +returned shader property IDs and declared value shapes. + +For images, provide exactly one same-file `imageHash`, public HTTP(S) `imageUrl`, +or call-scoped `assetKey` for a full-SHA-256 Hub IMAGE asset. PNG, JPEG, and GIF +are limited to 4096×4096. For video, provide exactly one same-file `videoHash` or +public `videoUrl` for MP4, MOV, or WebM up to 100 MB. URLs must need no +credentials. Reuse `figmaImageHash`, `figmaImageHashes`, or `figmaVideoHashes` +from `get_code` only in the same file; they identify native media, not preview +bytes. + +A Pattern uses exactly one existing `sourceNodeId` or same-result +`sourceCanvasKey`. + +## Layout aids + +Prefer a matching Grid style. Otherwise `figma.layoutGrids` declares ordered +row, column, or square grids on frames, components, sets, and instances. Use +`"AUTO"` for automatic row or column count. Do not bind `sectionSize` with +`STRETCH` or `offset` with `CENTER`. + +`figma.guides` is the complete ordered X/Y guide list: omission preserves and +`[]` clears. Page guides live under `page.guides`. + +For wrapping linear Auto Layout, `figma.autoLayout` may set signed +`itemSpacing`, positive or synchronized-null `counterAxisSpacing`, and +`itemReverseZIndex`. Never declare one physical gap in both classes and native +state. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/resource-mapping.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/resource-mapping.md new file mode 100644 index 00000000..4d3f3db8 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/resource-mapping.md @@ -0,0 +1,138 @@ +# Use resources in Canvas classes + +Keep layout and visual composition in markup. Put a reusable value's native +identity in the catalog or a call-scoped `theme`, then reference it by class. +Variables remain bound Figma variables, including mode changes. A `type-*` +class binds an entire native TextStyle. Ordinary utilities such as `gap-4` and +`text-base` remain literals and do not create or discover resources. + +## Existing system + +When the applicable system permits reuse, discover it with `get_design_system`. +Use returned variable `cssName` and TEXT-style `className` with its `catalogId`: +`bg-(--surface)`, `gap-(--spacing-content)`, `type-body`. These are examples of +names, not assumed resources. Read a style's exact ref when its font, metrics, +or bindings affect the choice. + +The catalog uses valid WEB code syntax when available, otherwise derives a +name. It disambiguates collisions and keeps the resulting alias tied to one +exact identity for that catalog's lifetime. Use the returned name unchanged; +never derive identity from equal values, similar names, or another catalog. + +For task-specific names, add `theme.variables: { "--surface": { "ref": "v1" } }` +or `theme.textStyles: { "type-body": { "ref": "s1" } }`. Use returned refs. An +alias cannot replace another catalog alias with a different resource. A stable +authoring key and catalog ref for the same native identity may share an alias. + +## New system + +When the deliverable includes a design system, define the selected variables +and styles through `variableCollections` and `styles`. Map their stable keys in +`theme` and consume them in the same call. A primitive draft without a system +still uses ordinary classes; repetition alone does not require resource creation. + +This complete recipe illustrates the relationship. Change the design facts, +namespace resource keys for the product, and confirm the font family/style in +the environment before authoring it. + +```json +{ + "mode": "create", + "markup": "
Account settings
", + "theme": { + "variables": { + "--surface": { "variableKey": "product/color/surface" }, + "--content-gap": { "variableKey": "product/space/content" } + }, + "textStyles": { "type-body": { "styleKey": "product/type/body" } } + }, + "variableCollections": { + "product/theme": { + "name": "Product/Theme", + "modes": { "light": { "name": "Light" }, "dark": { "name": "Dark" } }, + "variables": { + "product/color/surface": { + "name": "Surface", + "type": "COLOR", + "codeSyntax": { "WEB": "var(--surface)" }, + "values": { + "light": { "r": 1, "g": 1, "b": 1 }, + "dark": { "r": 0.08, "g": 0.09, "b": 0.11 } + } + }, + "product/space/content": { + "name": "Space/Content", + "type": "FLOAT", + "values": { "light": 16, "dark": 16 } + } + } + } + }, + "styles": { + "product/type/body": { + "type": "TEXT", + "name": "Product/Typography/Body", + "fontName": { "family": "Inter", "style": "Regular" }, + "fontSize": 16, + "lineHeight": { "unit": "PIXELS", "value": 24 } + } + } +} +``` + +On later calls, retain the small `theme` mapping and omit resource definitions +unless changing them. The stable keys resolve the same native resources. The +mapping is local to the call, so different screens can use different aliases +without changing the file's naming. Authoring keys and native identities +persist; aliases do not create a second resource registry. + +Use [variables.md](variables.md) for modes, aliases, scopes, and resource updates; +use [local-styles.md](local-styles.md) for style definitions. A TextStyle may +bind selected typography primitives through its `variables` fields when those +values must change together. Do not create font-family, size, or weight tokens +solely to express a single named text role: the TextStyle can hold those facts. + +## Supported variable utilities + +Both `gap-(--space)` and `gap-[var(--space)]` work. Explicit type hints resolve +ambiguous Tailwind prefixes, for example `text-(length:--body-size)` versus +`text-(color:--foreground)`. + +| Utility | Native value | +| ---------------------------------------------------------------------- | ------------------------------------------------------- | +| `bg-(--surface)`, `text-(--foreground)`, `border-(--border)` | COLOR fill or stroke; border still needs a width | +| `w/h/size/min-w/max-w/min-h/max-h-(--value)` | FLOAT dimensions, in pixels | +| `gap/gap-x/gap-y-(--value)` | FLOAT layout gaps, in pixels; axes follow flex or grid | +| `p/px/py/pt/pr/pb/pl-(--value)` | FLOAT padding, in pixels | +| `rounded/rounded-tl/rounded-tr/rounded-br/rounded-bl-(--value)` | FLOAT corner radius, in pixels | +| `border-(length:--width)` | FLOAT stroke width, in pixels | +| `text-(length:--size)`, `leading-(--leading)`, `tracking-(--tracking)` | FLOAT font size, line height, letter spacing, in pixels | +| `font-(family-name:--family)` | STRING font family | +| `font-(--weight)` | FLOAT font weight, 1–1000 | +| `opacity-(--opacity)` | FLOAT opacity, 0–1 | + +The tool reads an initial native value itself and retains the variable binding; +do not add a second literal fallback class. Native node, layout, and scope rules +still apply. This is a bounded mapping to Figma fields, not a CSS engine: no +`calc()`, var fallbacks, arbitrary expressions, or cascade. FLOAT metrics use +the native units above, not unitless CSS line-height multipliers. + +## Typography ownership + +`type-body` consumes the whole TextStyle. Keep color, sizing, alignment, and +wrapping classes on the text node as needed; omit font, weight, size, leading, +tracking, case, and decoration overrides owned by that style. Choose another +style or explicitly unlink the style for a deliberate local treatment. Composite +typography has no single Figma variable type, so `type-*` is an explicit custom +utility convention rather than a Tailwind default or a fabricated CSS variable. + +Inline `data-var-*`, `data-style-*`, and `native` bindings remain available for +fields outside this subset, exact native fonts/styles, and explicit unlinking. +Use one mechanism per property. Unknown names, conflicting declarations, +incompatible types, and cyclic variable aliases require correction; the tool +does not guess a replacement. + +Updates preserve omitted native state. Removing a resource class or replacing +it with a literal does not unlink the existing binding: explicitly clear the +variable/style with its `data-var-*="none"`, `data-style-*="none"`, or supported +`native` null binding when that is the intended change. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/rich-text.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/rich-text.md new file mode 100644 index 00000000..3e26cc97 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/rich-text.md @@ -0,0 +1,52 @@ +# Rich text and hyperlinks + +Use this reference for native font application or Figma-only text behavior; +use [typefaces.md](typefaces.md) when font selection or availability needs resolving. +Use `span` for editable text. Put whole-node typography in classes, a catalog +Text style, or semantic variable bindings when possible. + +`native[key].figma.text` supports: + +- exact whole-node `fontName`, `autoRename`, vertical alignment, and leading + trim; +- paragraph indent/spacing, list spacing, hanging punctuation/list; +- whole-node hyperlink; +- ordered rich-text `ranges`. + +Do not combine `autoRename: true` with fixed `figma.name`. + +When no Text style or typography variable expresses the chosen family and +style, use the exact available Figma font: + +```json +{ + "fontName": { "family": "IBM Plex Sans", "style": "Medium" } +} +``` + +Do not combine it with `font-*` classes, linked Text styles, or font family/style +variables. Never guess family or style availability. + +Range `start` and `end` are UTF-16 offsets into final characters. Ranges must be +ordered, non-overlapping, and set at least one property; split overlapping +intentions into disjoint intervals. A range may set font name/size, case, +letter spacing, line height, complete underline state, native fills, Text/Paint +style, list options, indentation, paragraph spacing, hyperlink, and supported +text-range variables. + +Use `{ "ref": "s1" }` for a catalog range style and `{ "ref": "v1" }` for a +range variable. `null` unlinks supported styles or hyperlinks; omission +preserves. + +Hyperlinks support URLs and node targets. For a same-result target: + +```json +{ + "type": "NODE", + "value": { "canvasKey": "settings/help" } +} +``` + +The target may appear later in markup; never remove a live hyperlink target. If +a catalog component exposes text through a prop, set that prop instead of +editing internal layers. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/style-grounding.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/style-grounding.md new file mode 100644 index 00000000..2a83efca --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/style-grounding.md @@ -0,0 +1,80 @@ +# Ground design judgment + +Use this reference for a new direction, material redesign, or consequential +uncertainty not settled by the user or an established source. Exact reproduction +and mechanical edits use their supplied evidence directly. + +## Inspect what can change the decision + +Start with the nearest credible evidence: the supplied design or implementation, +real product states, primary platform requirements, or adjacent visual work. +Choose separate evidence for behavior and visual expression when needed. A +functional walkthrough can establish behavior without settling visual language; +a visually relevant product state or adjacent visual work can show how density, +controls, surfaces, icon/text economy, and states cohere without establishing +behavior it does not expose. One artifact may inform both only when the relevant +behavior and pixels are actually inspected. + +Open the relevant state at useful scale. A homepage or brand campaign may not +show the working interface. Search cards, prose, remembered products, generated +images, and failed retrievals are not inspected visual precedents. A content +photograph establishes what it depicts, not the surrounding application's +interaction or composition. Follow the main skill's first-write evidence +boundary when retrieval fails. + +An image-search result that exposes only a screenshot description or URL remains +a search card. Open the actual product-state pixels at useful scale before +treating them as visual grounding; otherwise use the result only as behavioral +description. + +Research is grounded when it changes, confirms, or reopens a material decision +in the new result. Retain enough source identity and context to support that +claim; do not invent a source-by-source decision report. If a source contributed +nothing consequential, do not cite it as a precedent. Generic expertise helps +interpret the evidence; its familiar defaults are not evidence about this +product. + +There is no source quota. Stop when further investigation is unlikely to change +a material choice. Do not research routine decisions for ceremony. Keep source +screens outside the authored result unless the user asked to place or reproduce +them, and preserve required source content and behavior when adapting a design. + +## Form a provisional direction + +Integrate the brief, evidence, and professional judgment into a relationship +among content, state, and action, with a visual language that makes it fitting +and perceptible. A new design needs its own solution; independence is not a +reason to discard an applicable interaction or representation because it is +harder to source or serialize. + +Before the first write, be able to state privately what the inspected pixels +changed or confirmed about the recurring visual language. A mood label or +task-themed palette is not that direction; if the same control and surface +grammar could survive a noun swap, inspect more relevant pixels or reconsider +the synthesis. + +Resolve recurring visual roles enough to try them in a real composition. The +foundation is provisional and may change after seeing pixels. It is not a +separate foundation board or permission to create components, variables, or +styles outside the task's resource scope. + +Reconsider choices whose only justification is habit or semantic association. +Ask what in the brief or inspected reality makes the proposed treatment fit. +Familiar solutions can be appropriate; choosing the opposite of a criticized +motif is no stronger evidence. Functional specificity alone does not settle +expression, and stylistic difference alone does not make the product useful. + +## Externalize unresolved visual choices + +If materially different visual hypotheses remain and a capable image-generation +tool is available, a bounded visual exploration can help you see their +consequences. Open those pixels and use them to reconsider the composition; +omit this step when the direction is already clear. + +Generated concepts are speculative sketches, not real-product evidence or +flattened Figma deliverables. Do not trust their text/data or trace them +literally. A generated subject chosen as actual product content is a separate +asset decision under `visual-assets.md`. + +Return to the representative native composition and inspect it. Let a mismatch +reopen the decision it actually challenges; otherwise complete the design. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/typefaces.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/typefaces.md new file mode 100644 index 00000000..185284bc --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/typefaces.md @@ -0,0 +1,48 @@ +# Choose and apply fonts + +Use this reference when selecting or changing fonts, delivering a required +family/style, or resolving uncertainty about the text's scripts. Availability +can change a provisional choice; query before committing when that matters. + +Start from applicable Text styles, typography variables, project fonts, or +supplied references. Preserve established font identities for ordinary edits. +For a new direction, form candidates from the language, text roles, density, +and visual intent. A portable `font-sans|serif|mono` category does not establish +an exact family or suitable coverage for the actual text. + +## Query what can change the choice + +`get_design_system` with `scope: "fonts"` reads the environment without scanning +file resources. It is valid for direct composition, reuse, and an independent +system, including a blank page. + +- With candidate family names, use `families: ["Noto Sans SC"]` to inspect + exact native style names and missing families in one call; batch candidates. +- Use `query: "Noto"` when the family name itself needs discovery. This searches + names, not language coverage or visual suitability. +- Continue `nextCursor` with the same filters only when more results could + affect the choice. Reuse current evidence rather than querying per text node. + +Use returned or source-established native names. For an unavailable provisional +candidate, reconsider the choice. For a required font, preserve the requirement +and disclose the delivery gap rather than silently substituting another family. + +## Apply the selected typography + +Reuse the applicable TextStyle or font variables. If a new design system is in +scope, define the selected text roles as TextStyles and consume their `type-*` +classes through [resource-mapping.md](resource-mapping.md). Font selection alone +does not require creating styles or tokens. + +For direct composition, `font-[family-name:Noto_Sans_SC] font-semibold` fixes +the family and chooses its closest available weight. Underscores encode spaces; +`\_` preserves an underscore. Use `native[key].figma.text.fontName` with exact +`{ family, style }` when the native style identity matters; see +[rich-text.md](rich-text.md). Weight matching is approximate. For variable-driven +typography, consider the family/weight/style combinations in the delivered modes. + +Inspect representative real content in the composition, including relevant +scripts, numbers, punctuation, and wrapping. Availability and successful loading +do not prove glyph coverage; a correct-looking screenshot alone does not prove +native font identity or current editability. Reopen the font choice when the +observed text challenges it, without requiring a separate specimen board. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/variables.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/variables.md new file mode 100644 index 00000000..692a8699 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/variables.md @@ -0,0 +1,154 @@ +# Author local variables + +Use this reference after the representative pixel check when repeated colors +may carry shared semantic roles, or when the user or resolved system plan +requires local variables. Do not extract tokens from an ordinary screen. New +resources need no catalog; send `catalogId` only for deliberate nested +`{ "ref": "…" }` reuse. + +## Contents + +- [Decide from real roles](#decide-from-real-roles) +- [Author variables](#author-variables) +- [Bind and verify](#bind-and-verify) +- [Update and remove](#update-and-remove) + +## Decide from real roles + +After any selected representative component reconciliation and before +propagation, call full `get_code` with unresolved tokens only when repeated +colors plausibly represent semantic roles whose coordinated maintenance matters. +Treat `literalClusters` as candidate locations, not a to-do list. Select a role +only when concrete consumers should evolve together; split mixed roles even +when their literal values match. Leave incidental, local, and ambiguous +repetition literal. If the diagnostic is unavailable, do not infer a system +from repetition. + +For each selected role, map concrete consumer and field to a semantic variable +key, bind every representative consumer, then re-run once to confirm the role is +exposed through `tokens` and no longer unresolved. A non-empty +`literalClusters` result is acceptable. + +Carry only selected mappings into propagation. A later apply that includes a +consumer of a selected role must bind that field in the same call; an inherited +instance binding does not cover sibling literals. Before finalization, scan each +materially distinct dependent root that uses a selected role once, fix missing +bindings for those roles, and recheck only changed roots. Do not create variables +to empty diagnostics, expand the map from literal equality, or repeat scans after +the selected roles are verified. + +## Author variables + +Copy this recipe and change its design facts. Collection and variable authoring +keys persist file-wide and are neither names nor IDs. Choose one +collision-resistant prefix for the independent system; recover existing exact +keys when intentionally updating it. Mode keys are collection-scoped. + +```json +{ + "mode": "create", + "markup": "
Account
", + "variableCollections": { + "product/theme": { + "name": "Theme", + "modes": { + "light": { "name": "Light" }, + "dark": { "name": "Dark" } + }, + "variables": { + "product/color/surface": { + "name": "Color/Surface", + "type": "COLOR", + "scopes": ["ALL_FILLS"], + "values": { + "light": { "r": 1, "g": 1, "b": 1 }, + "dark": { "r": 0.08, "g": 0.09, "b": 0.11 } + } + }, + "product/space/md": { + "name": "Spacing/Medium", + "type": "FLOAT", + "scopes": ["GAP"], + "values": { + "light": 16, + "dark": 16 + } + } + } + } + }, + "native": { + "card": { + "variables": { + "fill": { "variableKey": "product/color/surface" }, + "gap": { "variableKey": "product/space/md" } + }, + "variableModes": { + "product/theme": "dark" + } + } + } +} +``` + +A new collection needs `name` and at least one named mode. Each variable needs +`name`, `type`, and a value for every mode. Types are `BOOLEAN`, `COLOR`, +`FLOAT`, and `STRING`. Values may alias another variable: + +```json +{ "variable": { "variableKey": "…" } } +``` + +Valid scopes: + +- general: `ALL_SCOPES`, `TEXT_CONTENT`, `CORNER_RADIUS`, `WIDTH_HEIGHT`, `GAP`, + `OPACITY`; +- color: `ALL_FILLS`, `FRAME_FILL`, `SHAPE_FILL`, `TEXT_FILL`, `STROKE_COLOR`, + `EFFECT_COLOR`; +- numeric effect/stroke: `STROKE_FLOAT`, `EFFECT_FLOAT`; +- typography: `FONT_FAMILY`, `FONT_STYLE`, `FONT_WEIGHT`, `FONT_SIZE`, + `LINE_HEIGHT`, `LETTER_SPACING`, `PARAGRAPH_SPACING`, `PARAGRAPH_INDENT`. + +Use `STROKE_COLOR`, not `ALL_STROKES`. Combine neither `ALL_SCOPES` with other +scopes nor `ALL_FILLS` with `FRAME_FILL`, `SHAPE_FILL`, or `TEXT_FILL`; +`ALL_FILLS` may coexist with a non-fill scope such as `STROKE_COLOR`. + +## Bind and verify + +Bind through `native[key].variables` using the exact supported field, such as +`fill`, `stroke`, `gap`, `paddingTop`, `width`, `visible`, `fontSize`, or +`characters`. Retain a matching literal class when Figma needs an initial paint +or numeric fallback. + +Bind each variable to representative fields performing its semantic role. +Prefer `GAP` for shared gaps/padding, `WIDTH_HEIGHT` for semantic control/icon +sizes, and `CORNER_RADIUS` for shared radii. Do not tokenize viewport dimensions, +one-off crops, content-derived geometry, or optical corrections merely because +numbers repeat. + +A representative binding proves usability, not complete coverage. Bind every +consumer intended to evolve with the role; keep equal peer literals only when +incidental or independently owned. + +`apply_canvas` reports `unbound-created-variable` when a new variable lacks a +same-result consumer. Bind it to a real consumer or remove it. A staged warning +may be temporary, but final delivery must show a native binding; equal literals +do not count. + +`variable-fallback-mismatch` means a bound literal matches none of the +same-call variable's direct or aliased mode values. Align the fallback with a +real mode or bind the variable that owns the value, or the binding will silently +change the declared markup. + +## Update and remove + +After changing a variable value, update and verify every intended consumer that +cannot carry a native binding, such as `figma.svg.color`; omission leaves its +old literal in place. + +Omission preserves managed state. Top-level `null` removes a managed variable, +mode, or collection only when absence is required and all consumers are cleared +or removed in the same result. Never mutate remote resources, invent parent +collections or library keys, or build a broad token system for one screen. +Extended collections must inherit a real local or catalog collection and obey +plan limits. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/visual-assets.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/visual-assets.md new file mode 100644 index 00000000..eaa3d4c8 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/visual-assets.md @@ -0,0 +1,57 @@ +# Choose and preserve visual assets + +Use this reference after the design selects an icon, image, +illustration, diagram, or vector asset. It governs role, medium, source +integrity, editability, and delivery—not whether the design should contain that +asset or what the finished visual style should be. + +Research pixels and generated screen concepts remain evidence for judgment, +not canvas content. Import, reproduce, annotate, or compare them only when the +user explicitly requests that treatment. When evidence establishes that the +new product needs an asset role, acquire or author a truthful asset for the new +result instead of redrawing or embedding the reference. + +## Preserve the decided role + +Start from the composition, not an available tool or assumed asset slot. Once a +material role is selected, fulfill it faithfully; sourcing difficulty is not a +reason to replace an image, icon, visualization, or exact medium with easier +text or plausible geometry. + +Depiction is a role, not a medium. Choose raster, sourced vector, +agent-authored vector, diagram, or another medium only when the brief, inspected +evidence, or a low-consequence assumption supports it. Convenience never +changes the medium. + +Treat content-bearing visualization—such as a chart, map, waveform, notation, +document or media preview, or domain instrument—as a first-class +representation. Identify the user decision and the visual structures that make +it possible. Preserve enough context and density to act; a stylized trace or +labeled decoration is not the representation. When only topology or sequence +is intended, name and design it as a diagram. + +When recognition depends on a subject's real appearance—such as a person, +product, food, place, room, photograph, cover, or shared-media preview—preserve +that distinction with a real sourced or generated image unless the brief or +inspected evidence independently establishes an illustrated language. + +Preserve editability semantics. Build changing diagram labels, shapes, and +relationships as native structure; use an opaque SVG only when exact vector art +is the asset. An SVG wrapper with Vector descendants does not make a diagram +model editable. If editable primitives cannot carry a required representation, +use an evidence-supported native, vector, or raster base with changing overlays +editable, or disclose the gap. + +For material assets retain enough evidence for identity and content fidelity, +provenance and applicable rights, source quality, and Canvas-compatible form. +Never silently change subject, style, or medium. Crops, masks, overlays, and +retouching must preserve the depicted subject; do not hide distinctive branding +or features to make one subject represent another. + +## Load only the selected branch + +- For an icon role, read [icons.md](icons.md). +- For an image or illustration, read [images.md](images.md). + +For diagrams and other custom vector art, use the source and editability +boundaries above, then load only the required geometry or paint mechanics. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/visual-composition.md b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/visual-composition.md new file mode 100644 index 00000000..27993d33 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-canvas-authoring/references/visual-composition.md @@ -0,0 +1,64 @@ +# Compose a product interface + +Use this reference when forming or reconsidering a composition. Keep the +person's working experience in view; use the questions below only where they +help resolve a decision. They are not independent quality axes. + +## Find the working relationship + +What is the person attending to, and what can they do with it in the depicted +state? Does the chosen screen or flow expose the user's central work, or merely +promise it through a button whose destination is absent? What changes across +states, and what must remain perceptible while that happens? Arrange content, +controls, and context so their relationship is understandable in the rendered +whole. + +A familiar shell may be the right answer. Reconsider it when it hides the +working object, requires unnecessary reading or navigation, or survives only +because task-specific nouns make it look relevant. Novelty and decoration do +not repair that mismatch. + +As content grows, what extends: the document or an owned scrolling region? +Choose document flow, a fixed workspace, or a hybrid from product behavior; +check that making room has not silently redefined the device or window viewport. +Density and control scale follow platform, frequency, precision, and environment +of use. In frequent expert work, inspect the real product's interaction economy +before carrying over the spacing and repeated explanations of an occasional +consumer journey. Preserve legibility and suitable targets in either case. + +## Make meaning perceptible + +What should someone notice now, and what should stay available without +competing? Resolve type, position, scale, color, contrast, media, depth, and space +together. Repeated roles need recognizable treatment; differences need to carry +meaning in this task. An expressive role does not by itself justify the first +familiar palette, shape, or effect. + +Choose text, icons, images, and graphics by recognition, comparison, +manipulation, and expression. Familiar iconographic affordances can reduce the +reading and space required by repeated controls; words can be more precise. +Inspect that tradeoff at actual size, including when every action has become +text. Source selected icons through `visual-assets.md`; sourcing effort is not +a design reason to drop their role. + +A working graphic must carry the distinctions needed for the decision. Check +whether its marks, scale, context, and state make the relevant comparison or +manipulation possible. Changing a label does not change what the marks encode. This is a question +of represented meaning, not a quota for detail or a preferred graphic style. Use `visual-assets.md` for truthful +source and native representation. + +## Learn from the rendered result + +Open the representative composition at useful scale. Mentally follow the +central action through its visible consequences. Does the selected state agree +with the working surface, available action, and result? If the experience breaks, +inspect the particulars that explain where and why. + +Judge spacing from visible relationships: nested insets, seams, baselines, +grouping, and repeated rhythm. Nominal padding or a non-overflowing bounding box +does not prove that the intended space survived native layout. Repair the +owning relationship instead of decorating over it. + +Carry resolved shared roles into dependent screens while allowing their layouts +to differ with the work. Stop when the requested whole is coherent and the +observed defects are resolved; do not keep polishing to fill a checklist. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/SKILL.md b/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/SKILL.md new file mode 100644 index 00000000..a5bb5f20 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/SKILL.md @@ -0,0 +1,177 @@ +--- +name: figma-design-to-code +description: >- + Implement or update project-consistent UI code from a visible Figma selection + or nodeId using TemPad Dev MCP. Use when the user wants Figma UI recreated, + ported, or integrated into the target project's framework, styling system, + tokens, assets, and existing components. Do not use for design critique, + product invention, generic code review, or guessing states, responsiveness, + or behavior not evidenced by Figma, the project, or the user. +--- + +# Implement Figma design in code + +Turn visible Figma evidence into the smallest project-native implementation +that preserves the intended result. Keep that result focal: project files, +TemPad output, rules, and tool calls are evidence for the implementation, not +deliverables to reproduce mechanically. + +Require TemPad Dev MCP to provide trustworthy design evidence for the current +selection or an exact `nodeId` inside the user's established scope. Never +reconstruct the design from memory, screenshots alone, or `get_structure` +metadata. + +## Evidence and authority + +Use each source only for what it can establish: + +- **The user** sets scope, requirements, prohibitions, and missing product or + implementation decisions. +- **The project** sets framework, file placement, component boundaries, + styling, tokens, assets, dependencies, and verification conventions. +- **TemPad Dev** sets visible structure and rendered design facts. + +Follow project instruction files for concerns outside Figma-to-code +translation. Do not add policy for routing, analytics, i18n, CMS, or other +orthogonal systems. + +TemPad can establish visible hierarchy, layout, spacing, typography, color, +effects, token references, exported assets, and codegen unit context. It cannot +establish unevidenced states, responsive behavior, business logic, navigation, +validation, analytics, or project conventions. Treat `get_structure` as +hierarchy and geometry evidence only, never as missing style truth. + +## Workflow + +### 1. Establish the implementation envelope + +Read only local evidence that can change this implementation, in this order: + +1. applicable `AGENTS.md` or equivalent instructions; +2. relevant design-system, token, component, and asset guidance; +3. the nearest comparable implementation and reusable primitives; +4. framework, styling, and check configuration needed for this task. + +Determine the target file or component boundary, framework, styling method, +token and asset paths, reuse candidates, dependency constraints, and narrowest +relevant checks. Inspect Tailwind version and theme scales only when the +project actually uses Tailwind-compatible tooling. + +Do not inventory the repository broadly after the needed envelope is clear. If +a missing project decision would materially change the result, ask before +implementation. + +### 2. Read the design at the requested scope + +Call TemPad Dev's `get_code` before implementing: + +- use `resolveTokens: false` by default; +- omit `nodeId` for the current single selection; pass one only when the user + supplied it or TemPad returned the exact ID for a targeted read inside the + user's established scope; +- set `preferredLang` from the established project target; +- keep TemPad's default vector behavior unless the user explicitly requests + asset-preserving vector fidelity and the active MCP version supports it. + +Use `resolveTokens: true` only when the user explicitly does not want design +token references. Treat returned `lang` as authoritative because plugin +configuration may override `preferredLang`. + +Retain the returned `code`, `lang`, `warnings`, `assets`, `tokens`, and +`codegen` facts that bear on the implementation. Use +`codegen.config.{cssUnit,rootFontSize,scale}` for exact unit conversion. + +Prefer one top-level read that preserves the requested composition. If the +tool is unavailable, points at the wrong file, or returns incomplete evidence, +read [recovery.md](references/recovery.md) before doing anything else. + +### 3. Separate facts, adaptations, and gaps + +Before editing, distinguish: + +- **design facts** to preserve; +- **project-native adaptations** supported by existing components, tokens, + utilities, or asset conventions; +- **unevidenced product decisions** that must remain unimplemented or be asked. + +Map by rendered value and semantics, not by a convenient name. A familiar +component or token is a candidate, not proof of equivalence. If more than one +material implementation path remains equally plausible, ask the user. Infer +only low-consequence details and report any inference that affects the result. + +### 4. Implement the smallest coherent change + +- Keep the established framework, styling system, file placement, imports, and + abstraction level. Do not introduce a parallel system. +- Reuse an existing primitive only when its semantics and rendered behavior fit + without guessing. Do not force reuse that erases design facts. +- Preserve exact rendered values unless project evidence proves an equivalent + token, utility, or component. For `rem` output, convert with TemPad's actual + `cssUnit`, `rootFontSize`, and `scale`. +- Preserve intentional uncommon output, including pseudo-elements, filters, + masks, blend and backdrop effects, gradients, and non-default compositing, + unless a documented project constraint requires an adaptation. +- Implement only evidenced states and responsiveness. Do not invent hover, + loading, error, empty, disabled, or responsive behavior. +- Use native semantic elements and preserve keyboard access and accessible + names when an established primitive does not already provide them. +- Add no runtime or build dependency without user approval unless the user has + explicitly waived that constraint. +- Keep `data-hint-*` attributes out of shipped code. + +When TemPad returns relevant entries, load only the matching protocol: + +- assets: read [Assets](references/assets-and-tokens.md#assets) and follow the + project's asset delivery path; +- token references: read [Tokens](references/assets-and-tokens.md#tokens) and + follow the project's token workflow. + +Read both when both are present and skip both when neither is present. + +Do not enter a visual tuning loop. Change the implementation again only when +new project, design, tool, or verification evidence identifies a concrete +defect. + +### 5. Verify in the project's real workflow + +Run the narrowest relevant checks defined by project instructions and scripts. +Repair implementation failures and rerun the affected checks. Use an existing +preview, screenshot, or comparison workflow when available; do not invent a +universal verification matrix. + +If no runnable check exists, report the implementation as unverified. Do not +claim visual completion without a real project comparison path; ask the user +to confirm the rendered result against Figma. + +## Hard stops + +Stop instead of shipping when: + +- TemPad is unavailable, unauthorized, inactive on the intended file, or + cannot provide a trustworthy visible parent composition; +- the target is unreadable or not visible; +- project, design, and user evidence still conflict after targeted recovery; +- a missing decision would materially change behavior, structure, dependency, + asset delivery, or token mapping; +- required assets cannot be retrieved or stored under project policy. + +If blocked, give at most three concrete actions that would unblock the task. + +## Handoff + +Report: + +- what changed and where; +- only the relevant adaptation, inference, warning, asset/token handling, or + residual visual risk; +- checks run, their result, and what remains unverified. + +Keep absent concerns absent from the handoff. Do not produce a compliance +checklist for branches the task never used. + +## Decision example + +If TemPad emits `padding: 15px` and the project has a `space-4` token worth +`16px`, preserve `15px` unless project evidence explicitly makes the token the +intended mapping. Project consistency selects the representation; it does not +authorize changing the visible design. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/agents/openai.yaml b/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/agents/openai.yaml new file mode 100644 index 00000000..406fbf6e --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/agents/openai.yaml @@ -0,0 +1,7 @@ +interface: + display_name: 'Figma Design to Code' + short_description: 'Implement project-consistent UI code from Figma' + icon_small: './assets/icon.svg' + icon_large: './assets/icon.svg' + brand_color: '#0098FF' + default_prompt: 'Use $figma-design-to-code to implement the selected Figma design in the current project.' diff --git a/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/assets/icon.svg b/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/assets/icon.svg new file mode 100644 index 00000000..2e8c6946 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/assets/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/references/assets-and-tokens.md b/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/references/assets-and-tokens.md new file mode 100644 index 00000000..01dec4a6 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/references/assets-and-tokens.md @@ -0,0 +1,47 @@ +# Translate assets and tokens + +Read this reference only when `get_code` returns `assets` or `tokens`. + +## Assets + +Follow the project's established asset and icon policy before TemPad delivery +details. + +- Download bytes only from a TemPad-provided `asset.url`. Never substitute a + public internet asset. +- Treat assets as files to store or reference, not text evidence to parse. +- If project policy forbids storing them, reference TemPad URLs only when the + user accepts the local-server dependency, and report it. +- Treat emitted `` markup as design truth for structure, + size, and instance color. Refactor delivery only through an existing project + SVG path. +- If upload falls back to inline SVG, preserve that markup rather than + resynthesizing the vector. +- `themeable: true` permits one contextual color channel, usually + `currentColor`; drive it through the established wrapper or icon convention. + Preserve internal palettes when `themeable` is absent. +- Do not invent a new SVG pipeline, multi-color props, or custom variables. + +If a required asset cannot be retrieved or represented under project policy, +stop rather than draw or substitute it from memory. + +## Tokens + +Preserve token usage when the target project can carry or map it safely. +Token facts may be direct values or mode-specific values keyed by +`Collection:Mode`; preserve aliases between variables when present. + +- Map to an existing project token only when value, reference behavior, + semantics, and relevant mode agree. A similar name is insufficient. +- Preserve TemPad token references through the project's normal token workflow + when that workflow can accept them. +- Add a token only when the project already defines how and this task calls for + it. +- If landing location, mode, or mapping remains ambiguous, use the exact + rendered value and report the fallback. +- Use hint metadata only while reasoning about a mode; never ship hint + attributes. + +When tokens and explicit rendered values disagree, do not silently choose. +Narrow the design evidence or ask the user which source expresses the intended +state. diff --git a/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/references/recovery.md b/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/references/recovery.md new file mode 100644 index 00000000..88cf1e89 --- /dev/null +++ b/agent-plugin/targets/plugins-cli/skills/figma-design-to-code/references/recovery.md @@ -0,0 +1,54 @@ +# Recover trustworthy design evidence + +Read this reference only when TemPad is unavailable, a `get_code` call warns +or fails, or the requested selection cannot fit in one trustworthy response. + +## Connection and target failures + +For a transient transport failure, retry once. Do not blind-retry invalid +selection, hidden node, wrong file, deterministic budget, or depth errors. + +If TemPad is unavailable or active on the wrong file, stop and ask the user to: + +1. enable MCP access in TemPad Dev **Preferences > Agent integration**; +2. keep the intended TemPad Dev and Figma tab active; +3. use the MCP badge in the panel to activate the intended file when multiple + Figma tabs are open. + +Do not edit code while design evidence is untrustworthy. + +## Incomplete `get_code` results + +Preserve the largest trustworthy parent composition and narrow only the +missing evidence: + +- **`depth-cap`**: keep the returned top-level composition, then use returned + `data-hint-id` values for targeted child `get_code` calls. +- **budget overflow or shell response**: keep the returned parent shell, then + fetch omitted children separately. Use the smallest parent that still proves + their shared layout. Plain string truncation is not evidence. +- **hierarchy, geometry, or overlap uncertainty**: call TemPad Dev's + `get_structure` only to resolve that uncertainty or select a narrower retry + target. + +Never rebuild a missing parent from child metadata. If no trustworthy parent +shell can be recovered, stop the full implementation and ask the user to +narrow the selection or choose the highest-priority subtree. + +If a budget error requires user action, report its consumption, limit, and +overage from the tool response. + +## Resolve contradictions + +Prefer the evidence source with authority over the disputed fact: project +evidence for implementation conventions, `get_code` for visible design, and +the user for product intent. Narrow the read once when the conflict may be a +scope problem. If the sources still disagree, stop rather than choose silently. + +## Worked example + +When a large frame returns a usable header-and-grid shell but omits three cards, +keep the shell as the parent layout, fetch only those card subtrees, and insert +them into the known grid. If the response contains cards but no trustworthy +grid shell, do not infer columns or spacing from `get_structure`; request a +narrower parent selection. diff --git a/agent-plugin/targets/standard/CHANGELOG.md b/agent-plugin/targets/standard/CHANGELOG.md new file mode 100644 index 00000000..1e9275fc --- /dev/null +++ b/agent-plugin/targets/standard/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +## 0.2.0 + +- Routed the `plugins` CLI through its own hook-free compatibility package and marketplace, + with installer discovery checks for both skills and MCP configuration. +- Added design-task lifecycle guidance and Stop/Done controls. Codex App uses MCP metadata and + native IPC without hooks; Claude uses installed lifecycle and Stop hooks. +- Documented native Codex App comments, Queue/Steer timing, and element-editor Save & Queue + shortcuts. Other clients retain task controls without comment delivery. + +- Added `figma-canvas-authoring` for creating and editing native Figma designs, alongside the + existing `figma-design-to-code` skill. +- Added progressive references for native authoring, fonts, images, icons, resource bindings, + and scoped editing. Direct, Reuse, and Author workflows keep resource decisions tied to the task. +- Grounded new compositions in inspectable evidence and required inspection of the rendered result + plus relevant native facts, with focused repair of observed defects. +- Made the portable Agent Plugins 1.0 bundle the shared source for installation, with synchronized + Codex and Claude compatibility manifests and refreshed icons. +- Paired the plugin with extension 0.21.0 and MCP 0.8.0 through `@tempad-dev/mcp@latest`. + The MCP server requires Node.js 22.x, 24.x, or 26+. diff --git a/agent-plugin/targets/standard/README.md b/agent-plugin/targets/standard/README.md new file mode 100644 index 00000000..3e7d6d69 --- /dev/null +++ b/agent-plugin/targets/standard/README.md @@ -0,0 +1,173 @@ +# TemPad Dev Agent Plugin + +[Simplified Chinese](./README.zh-Hans.md) + +Read, edit, and implement Figma designs through your coding agent or IDE. This plugin includes: + +- `figma-canvas-authoring`: create and revise native Figma designs, reusing accessible components, variables, and styles as needed. +- `figma-design-to-code`: use Figma design context to implement UI with your project’s components and conventions. +- The TemPad Dev MCP server configuration: connect to the Figma file open in your browser. + +Requires the TemPad Dev browser extension. Canvas editing also requires edit access to the Figma Design file. For manual inspection and output plugins, see the full [user guide](https://github.com/ecomfe/tempad-dev/blob/main/README.md). + +This plugin follows [Agent Plugins 1.0](https://agent-plugins.org/) and is published from one +source as a standard package, a compatibility package for the `plugins` CLI, and a package per +native host. Prefer native installation on Codex and Claude. Codex App binds tasks over MCP +metadata and native IPC, so its plugin registers no lifecycle hooks. + +## Cursor and VS Code installation + +For Cursor and VS Code, select the corresponding target: + +```bash +npx plugins add ecomfe/tempad-dev --target cursor +npx plugins add ecomfe/tempad-dev --target vscode +``` + +The installer reads `.plugin/marketplace.json` and installs the generated `plugins-cli` +compatibility package, which contains both skills and MCP configuration without lifecycle hooks. +This path is verified with `plugins@1.3.4`. Agent Plugins 1.0 consumers can use the separate +`agent-plugin/targets/standard` package; the current `plugins` CLI does not read that format. + +## Codex and Claude installation + +Use these native marketplace flows for Codex and Claude. Claude's lifecycle hooks require +the host's normal trust review; Codex does not register hooks. +The `--sparse` paths limit checkout to the host's marketplace and generated package, including +its skills and any required hooks. Codex repeats `--sparse` for each path; Claude accepts multiple +paths after one `--sparse`. The `plugins` CLI used for Cursor and VS Code has no equivalent flag. + +### Codex + +```bash +codex plugin marketplace add ecomfe/tempad-dev --ref main --sparse .agents --sparse agent-plugin/targets/codex +codex plugin add tempad-dev@tempad-dev +``` + +You can also install **TemPad Dev** from the Codex app plugin directory after adding the +marketplace. + +### Claude Code and Claude Desktop + +```bash +claude plugin marketplace add ecomfe/tempad-dev --sparse .claude-plugin agent-plugin/targets/claude +claude plugin install tempad-dev@tempad-dev +``` + +The plugin appears in Claude Desktop after the marketplace is added. + +For clients without Agent Plugin support, follow the direct MCP and standalone skill setup in the +[complete setup guide](https://github.com/ecomfe/tempad-dev/blob/main/README.md#agent-integration). + +## Usage + +Before using the integration, open TemPad Dev in Figma, then open **Preferences → Agent +integration** and enable **MCP access**. Canvas authoring is available while the active Figma +Design file is editable. + +## Upgrading + +The canvas-authoring release pairs Agent Plugin **0.2.0**, TemPad Dev extension **0.21.0**, and +MCP server **0.8.0**. Node.js **22.x, 24.x, or 26+** is required for the MCP server. + +1. Update the browser extension and reload the Figma tab. +2. Update the installed plugin through the client or installer used originally. With standalone + setup, update both `figma-design-to-code` and `figma-canvas-authoring`. +3. Keep the release MCP configuration on `@tempad-dev/mcp@latest`; replace any previous + `@alpha` or fixed alpha version. Reconnect the MCP client and start a new task so it loads the + updated tools and skills. If a stale Hub is reported, close tasks using the old MCP server + before reconnecting. +4. Open TemPad Dev, enable **MCP access**, and click the MCP badge in the intended Figma tab when + a session choice is needed. The badge selects the file receiving tool calls. + +## Packaging source of truth + +Everything is authored once under `agent-plugin/src/` and published by +`pnpm agent-plugin:build`. Every target is generated; never edit one. + +| Path | Role | +| ---------------------------------- | ------------------------------------------------- | +| `agent-plugin/src/plugin.json` | Standard manifest; owns all shared metadata | +| `agent-plugin/src/mcp.json` | Standard MCP configuration | +| `agent-plugin/src/skills/` | Both skills | +| `agent-plugin/src/clients/claude/` | Claude lifecycle hooks | +| `agent-plugin/src/clients/codex/` | Codex directory presentation (`interface.json`) | +| `agent-plugin/src/clients/shared/` | Hook transport shared by hosts | +| `agent-plugin/targets/standard` | Generated; also the standalone skills URL | +| `agent-plugin/targets/plugins-cli` | Generated compatibility package for `plugins` CLI | +| `agent-plugin/targets/codex` | Generated Codex marketplace package | +| `agent-plugin/targets/claude` | Generated Claude marketplace package | + +Each target carries only what its own installer reads. A standard consumer projects `plugin.json` +onto the host itself, so shipping a host layout beside it would create a second source of truth for +the same package; each host target likewise omits the standard manifests and the other host's +directory. Only Claude loads lifecycle hooks, so only `targets/claude` carries `clients/`. +The `plugins-cli` package carries `.plugin/plugin.json` and `.mcp.json`; its marketplace is +generated separately so the CLI does not select the Claude package. Verify discovery through +the actual CLI with `pnpm agent-plugin:check-installer` after changing packaging. + +## Task controls and client enhancements + +Design tasks can pause and resume across turns. Figma's canvas status bar shows the +source client, a Stop control, and a counted comment entry. Stop permanently cancels +the current task; subsequent design work explicitly begins a fresh task. Lifecycle pauses can resume +with a new lease epoch and require a fresh canvas read before writing. See the +[task and client design](https://github.com/ecomfe/tempad-dev/blob/main/docs/extension/mcp-design-tasks.md). + +The normal setup is the TemPad Dev extension configuration followed by this plugin's +installation. There are no control +addresses, environment variables, or helper services for users to configure. + +Codex App binds tasks from host-supplied MCP metadata and follows native conversation +state through the existing IPC connection. Claude retains lifecycle and Stop hooks. +Comments are delivered only through native conversation messages on compatible Codex App +hosts. TemPad Dev discovers the original conversation through the App's existing local +connection. Where supported, Queue submits the batch to the host's native queue, where it waits until the +conversation is ready. As soon as the host confirms admission, TemPad Dev clears the submitted +comments and markers, stops the sending indicator, and allows another batch. This confirmation +means the host received the comments, not that the agent finished the requested changes. +When native queue admission is unavailable, Queue waits in the Hub for existing queued +messages to clear and the conversation to accept a new response. The sending indicator +remains until that admission is confirmed. If queue state cannot be checked, comments +remain saved and delivery reports an error. Compatible hosts also support native server-queue +admission; these messages may appear in Codex after its next queue refresh. +Steer adds comments to an active response or starts a response when the conversation is idle. +Failed or uncertain delivery retains drafts; uncertain delivery is not automatically resent. +Comments never fall back to hooks. + +| Editor | Enter or click the submit button | Command/Ctrl+Enter or Command/Ctrl+click | +| --------------------------------- | -------------------------------- | ---------------------------------------- | +| Element comment | Save the comment without sending | Save & Queue the whole batch | +| General comment in the status bar | Queue the whole batch | Steer the whole batch | + +A batch includes all saved element comments and the general comment. Shift+Enter inserts a +newline in either editor. Saving an element comment alone does not send it. + +Claude, Codex CLI, and other clients currently provide task status and Stop/Done without +comment controls. Previously saved drafts remain in extension-local storage. + +Stop immediately blocks further writes from the current task and permanently cancels it +once an executing operation drains. The cancelled task cannot resume. The agent respects +Stop without automatically replacing it; necessary or user-requested design work can +explicitly begin a fresh task. No separate Figma unlock is needed. Codex App Stop also +requests native interruption of the exact bound turn; a delayed Stop cannot interrupt a +newer turn. Stop and Done also remove this task's comments that are still in the native queue, +leaving unrelated messages intact. Failed cleanup is retried after reconnection; already consumed +input cannot be recalled. Local cancellation remains effective if the host is unavailable. Claude +conveys Stop at the next hooked tool boundary. Native Codex delivery is enabled +only after the exact conversation owner reports support; no manual connection setup +is required. See the task and client design for the current validation scope. + +The native adapter uses Unix sockets on macOS/Linux and Codex's local named pipe on Windows. +macOS Steer and paused native queue admission/removal have been exercised against Codex App +26.908.70816. Automatic queue execution and the complete installed-plugin/Figma UI flow still +require live verification. Windows and Linux coverage is limited to source inspection and +automated tests; it does not establish complete host support. + +With a supported connection, select an element, save its feedback draft, then send the +numbered batch from the canvas status bar. Drafts can be edited or deleted and survive +navigation and closed tabs in extension-local storage, isolated by file, agent conversation, and task. +Successful delivery clears the submitted markers together; restoring drafts never sends them. + +The agent reports the result and its Figma link in the conversation, where users can +continue with follow-up requests. Task tools return text and structured data. diff --git a/agent-plugin/targets/standard/README.zh-Hans.md b/agent-plugin/targets/standard/README.zh-Hans.md new file mode 100644 index 00000000..bc5feda9 --- /dev/null +++ b/agent-plugin/targets/standard/README.zh-Hans.md @@ -0,0 +1,130 @@ +# TemPad Dev Agent Plugin + +[English](./README.md) + +在你的 coding agent 或 IDE 中读取、编辑和实现 Figma 设计。这个插件包含: + +- `figma-canvas-authoring`:创建和修改原生 Figma 设计,按任务需要复用可访问的组件、变量和样式。 +- `figma-design-to-code`:读取 Figma 设计信息,结合项目已有组件和约定实现 UI。 +- TemPad Dev MCP server 配置:连接浏览器中打开的 Figma 文件。 + +需要安装 TemPad Dev 浏览器扩展。画布编辑还需要 Figma Design 文件的编辑权限。手动检查设计和输出插件的完整说明见 [使用指南](https://github.com/ecomfe/tempad-dev/blob/main/README.zh-Hans.md)。 + +本插件遵循 [Agent Plugins 1.0](https://agent-plugins.org/),并从同一份内容源发布一个标准包 +(供自行适配该标准的客户端使用)、一个 `plugins` CLI 兼容包,以及每个原生宿主各一个包。Codex 与 Claude 请优先使用原生安装。 +Codex App 通过 MCP 元数据和原生 IPC 绑定任务,其插件不注册生命周期 hooks。 + +## Cursor 和 VS Code 安装 + +Cursor 和 VS Code 请指定对应的 target: + +```bash +npx plugins add ecomfe/tempad-dev --target cursor +npx plugins add ecomfe/tempad-dev --target vscode +``` + +安装器读取 `.plugin/marketplace.json`,安装生成的 `plugins-cli` 兼容包,其中包含两个 skill +和 MCP 配置,不包含生命周期 hooks。此路径已通过 `plugins@1.3.4` 验证。支持 Agent Plugins 1.0 +的客户端可使用独立的 `agent-plugin/targets/standard` 标准包;当前 `plugins` CLI 不读取该格式。 + +## Codex 和 Claude 安装 + +使用以下原生 marketplace 流程。Claude 提示时,请检查并信任插件的生命周期 hooks;Codex 不注册 hooks。 +`--sparse` 将检出范围限制为对应宿主的 marketplace 和生成包,包含所需的 skill 及 hooks。 +Codex 为每个路径重复指定 `--sparse`;Claude 在一个 `--sparse` 后接受多个路径。 +Cursor 和 VS Code 使用的 `plugins` CLI 没有对应参数。 + +### Codex + +```bash +codex plugin marketplace add ecomfe/tempad-dev --ref main --sparse .agents --sparse agent-plugin/targets/codex +codex plugin add tempad-dev@tempad-dev +``` + +添加 marketplace 后,也可以从 Codex 应用的插件目录安装 **TemPad Dev**。 + +### Claude Code 和 Claude Desktop + +```bash +claude plugin marketplace add ecomfe/tempad-dev --sparse .claude-plugin agent-plugin/targets/claude +claude plugin install tempad-dev@tempad-dev +``` + +添加 marketplace 后,该插件也会出现在 Claude Desktop 中。 + +不支持 Agent Plugin 的客户端,请按照 +[完整配置指南](https://github.com/ecomfe/tempad-dev/blob/main/README.zh-Hans.md#agent-集成)直接配置 MCP 并安装独立 skill。 + +## 使用 + +使用前,请在 Figma 中打开 TemPad Dev,然后进入 **Preferences → Agent integration** +并启用 **MCP access**。启用后,只要当前 Figma Design 文件可编辑,即可进行画布创作。 + +设计任务的状态栏显示 agent 状态、Stop/Done 和评论入口。Stop 会立即阻止当前任务继续写入, +在执行中的操作结束后永久取消该任务;重新连接也不会恢复它。后续设计工作需要明确开始新任务。 + +评论目前仅支持通过兼容 Codex App 的原生会话通道发送。Queue 将整批评论交给宿主的原生队列, +等待会话可以执行时再处理。宿主确认接收后,TemPad Dev 会清空本批评论和标记、停止发送指示, +并允许继续输入下一批;这表示已接收,不表示 agent 已完成修改。如果原生入队不可用, +Queue 会在 Hub 中等待已有排队消息清空、会话能接收新回复,此时发送指示会保留到确认接收。 +如果无法确认队列状态,会保留评论并报告发送错误。兼容宿主也支持原生服务端队列入队, +这些消息可能会在 Codex 下一次刷新队列时才显示。 +Steer 会将评论追加到正在执行的回复,空闲时直接开始新回复。投递失败或结果不确定时保留草稿, +结果不确定的评论不会自动重发,也不会回退到 hooks。 + +| 编辑位置 | Enter 或点击提交按钮 | Command/Ctrl+Enter 或 Command/Ctrl+点击 | +| ------------------ | -------------------- | ---------------------------------------- | +| 元素评论 | 保存当前评论,不发送 | Save & Queue:保存当前评论并排队整批评论 | +| 状态栏中的总体评论 | 排队整批评论 | 使用 Steer 发送整批评论 | + +整批评论包含全部已保存的元素评论和总体评论;两个编辑器中都可以用 Shift+Enter 换行。 +草稿按文件、会话和任务隔离,关闭标签页后仍保留,恢复草稿不会自动发送。 + +Codex App 的任务绑定和状态同步使用 MCP 元数据及原生 IPC,不依赖 hooks。Stop 还会请求中断 +对应的 Codex 回合,迟到的 Stop 不会中断较新的回合。Stop 和 Done 会移除当前任务尚未执行的 +原生队列评论,保留其它消息;清理失败后会在重新连接时重试,已被宿主取走的输入无法撤回。 +宿主不可用时,本地取消仍然生效。Claude 保留生命周期和 Stop 通知 hooks;Claude、Codex CLI +等尚未接入原生投递的客户端提供任务状态和 Stop/Done,但不显示评论入口,已有草稿不会删除。 + +原生适配器在 macOS/Linux 上使用 Unix socket,在 Windows 上使用 Codex 的本机 Named Pipe。 +已在 macOS Codex App 26.908.70816 上实测 Steer,以及暂停状态下的原生队列入队和移除。 +自动执行和完整的已安装插件/Figma UI 流程仍待实测;Windows/Linux 的证据限于源码检查和 +自动化测试,尚不能据此宣称完整宿主支持。 + +## 升级 + +本次画布创作版本应配套使用 Agent Plugin **0.2.0**、TemPad Dev 扩展 **0.21.0** 和 MCP +server **0.8.0**。MCP server 要求 Node.js **22.x、24.x 或 26+**。 + +1. 更新浏览器扩展,并重新加载 Figma 标签页。 +2. 通过原先使用的客户端或安装器更新 plugin。独立配置时,请同时更新 + `figma-design-to-code` 和 `figma-canvas-authoring`。 +3. 正式版 MCP 配置使用 `@tempad-dev/mcp@latest`;请替换旧的 `@alpha` 或固定 alpha 版本。 + 重新连接 MCP client 并新建任务,以加载更新后的工具和 skill。若提示 Hub 过期,请先关闭 + 使用旧 MCP server 的任务,再重新连接。 +4. 打开 TemPad Dev 并启用 **MCP access**;需要选择会话时,点击目标 Figma 标签页内的 MCP + badge。实际接收工具调用的文件由该 badge 选择。 + +## 封装内容源 + +所有内容只在 `agent-plugin/src/` 下编写一次,由 `pnpm agent-plugin:build` 生成各个产物。 +所有产物都是生成的,请勿直接编辑。 + +| 路径 | 作用 | +| ---------------------------------- | -------------------------------------- | +| `agent-plugin/src/plugin.json` | 标准清单,拥有全部公共 metadata | +| `agent-plugin/src/mcp.json` | 标准 MCP 配置 | +| `agent-plugin/src/skills/` | 两个 skill | +| `agent-plugin/src/clients/claude/` | Claude 生命周期 hooks | +| `agent-plugin/src/clients/codex/` | Codex 目录展示信息(`interface.json`) | +| `agent-plugin/src/clients/shared/` | 宿主共用的 hook 传输脚本 | +| `agent-plugin/targets/standard` | 生成产物,同时是独立 skills 的安装地址 | +| `agent-plugin/targets/plugins-cli` | 为 `plugins` CLI 生成的兼容包 | +| `agent-plugin/targets/codex` | 生成的 Codex marketplace 包 | +| `agent-plugin/targets/claude` | 生成的 Claude marketplace 包 | + +每个产物只携带自己的安装方式会读取的内容。标准客户端会自行把 `plugin.json` 适配到宿主, +因此在它旁边放置宿主清单会让同一个包出现第二个事实来源;两个宿主产物同理省略标准清单 +以及对方宿主的目录。只有 Claude 会加载生命周期 hooks,因此只有 `targets/claude` 携带 `clients/`。 +`plugins-cli` 包使用 `.plugin/plugin.json` 和 `.mcp.json`,由独立生成的 marketplace 入口路由, +避免 CLI 选中 Claude 包。修改封装后运行 `pnpm agent-plugin:check-installer`,验证实际 CLI 的发现结果。 diff --git a/agent-plugin/targets/standard/assets/icon-padded.svg b/agent-plugin/targets/standard/assets/icon-padded.svg new file mode 100644 index 00000000..2e8c6946 --- /dev/null +++ b/agent-plugin/targets/standard/assets/icon-padded.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/agent-plugin/targets/standard/assets/icon.png b/agent-plugin/targets/standard/assets/icon.png new file mode 100644 index 00000000..5d1f6bf2 Binary files /dev/null and b/agent-plugin/targets/standard/assets/icon.png differ diff --git a/agent-plugin/targets/standard/mcp.json b/agent-plugin/targets/standard/mcp.json new file mode 100644 index 00000000..56c29e0f --- /dev/null +++ b/agent-plugin/targets/standard/mcp.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json", + "mcpServers": { + "tempad-dev": { + "type": "stdio", + "command": "npx", + "args": [ + "-y", + "@tempad-dev/mcp@latest" + ] + } + } +} diff --git a/agent-plugin/targets/standard/plugin.json b/agent-plugin/targets/standard/plugin.json new file mode 100644 index 00000000..78fa0ccc --- /dev/null +++ b/agent-plugin/targets/standard/plugin.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "tempad-dev", + "version": "0.2.0", + "description": "Connect your coding agent to Figma. Create and edit native designs, inspect existing designs, and implement UI in your codebase.", + "author": { + "name": "TemPad Dev" + }, + "homepage": "https://github.com/ecomfe/tempad-dev#agent-integration", + "repository": "https://github.com/ecomfe/tempad-dev", + "license": "MIT", + "keywords": [ + "figma", + "mcp", + "skill", + "agent-integration", + "design-to-code", + "canvas-authoring", + "design-system", + "frontend" + ] +} diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/SKILL.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/SKILL.md new file mode 100644 index 00000000..7732c78f --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/SKILL.md @@ -0,0 +1,183 @@ +--- +name: figma-canvas-authoring +description: >- + Create or update native, editable Figma designs with TemPad Dev MCP: screens, + flows, components, and requested local design-system resources, including on + an empty canvas. Use for Design in Figma work, not Figma-to-code, critique + without edits, or raw Plugin API automation. +--- + +# Design in Figma + +Deliver the smallest complete native Figma result that serves the user's +situation. Keep the working experience in view as you research, compose, and +repair. A successful tool call establishes a document change; the rendered +result and its editable structure establish whether that change served the task. + +## Establish the task + +Use the user's exact target and constraints. For an existing design, inspect +`get_code` and its pixels before changing the composition; use `get_structure` +for hierarchy, geometry, stable keys, or selected native facts. Write to a known +page directly. Create or activate a page only when the task calls for it. +Infer low-consequence gaps; ask when a missing decision would materially change +the result. Keep unrelated account, filesystem, task, and page metadata out of +product identity and content. + +Require an editable Figma Design file and the intended tab's active MCP +connection. Use the host's TemPad MCP tools for all canvas reads and writes. +If unavailable, report the integration problem and stop. Do not launch the CLI, +recreate its transport, use browser automation to set up the canvas, or emit raw +Plugin API operations. Research and asset acquisition use the host's appropriate +tools; website research uses the in-app browser when available unless the user +selected another browser. + +For new design work, call `begin_design` before research or canvas work with a short task title +and a fresh UUID `requestId`; reuse that UUID only to retry the same begin. Carry +the returned `taskId` on related TemPad tool calls. The runtime handles status and +placement feedback: do not report progress, send heartbeats, or choose coordinates +for a placeholder. Use `list_design_sessions` when the intended Figma target is +unclear, then pass its exact `sessionId` to `begin_design`. Pausing a turn preserves +the design task. Follow-up comments continue the same task, including after a completed +pass while its review remains open. After completion, pause, or lease expiry, use `resume_design` with its latest +`epoch`, carry the returned epoch as `taskEpoch`, and reread the affected canvas +with `get_structure` or `get_code` before writing. Use `get_design_task` only when +recovery needs the current state or epoch. Never replay a stale write. Stop in TemPad Dev +permanently cancels the current task after any running operation settles. Never resume +that cancelled task or automatically replace it. If further design work is necessary or +the user requests it, explicitly call `begin_design` with a fresh requestId. No separate +Figma unlock or new user turn is required. Done closes the review; a closed or replaced +task cannot resume. Do not automatically begin a replacement for comments on such a task. +Element feedback arrives as a numbered batch. Each item retains its file, page, +and node identity from draft creation. Reread every target before applying the +batch; do not substitute the current selection. +Supported hosts receive submitted feedback through native conversation messages. Do not poll for it or +set up a helper process or host control endpoint. + +Begin without waiting to choose a canvas location. Once an existing design region is +known, use `set_design_anchor` with its exact Frame node ID and `taskId`. Otherwise +the first created top-level Frame anchors automatically. The region stays stable +across reads and writes; call this tool again only to explicitly change design regions. + +## Ground and compose + +For net-new or materially redesigned interfaces without an established system, +read [style-grounding.md](references/style-grounding.md) and inspect relevant +real product screens or a permitted implementation before the first Canvas +write. The evidence must expose the interface relationships informing the new +work. Search snippets, URLs, failed retrievals, and generated concepts do not +establish a precedent. Subject imagery establishes its depicted content, not +its surrounding application's design. Try another permitted source when +retrieval fails; if none is inspectable, disclose the gap and stop. Supplied +source pixels or implementation can satisfy this boundary; mechanical edits do +not require unrelated research. + +Resolve what the person needs to recognize or change, which content and states +carry that work, and how the interface makes their consequences perceptible. +Choose the screen or flow, visual language, density, and scrolling model from +that situation. Use [visual-composition.md](references/visual-composition.md) +when forming or reconsidering a composition. Familiar structures and distinctive +ones both need a reason in the task. Research informs an independent solution; +it does not authorize copying a composition or placing reference pixels on the +canvas unless the user requested that treatment. + +When selecting or changing fonts, or when script coverage is uncertain, read +[typefaces.md](references/typefaces.md) to resolve candidates and native identities. + +Choose representations by their role in the work. Once an image, icon, diagram, +or visualization matters to the direction, read +[visual-assets.md](references/visual-assets.md) and its selected branch. Do not +silently replace the chosen content or medium to simplify sourcing or markup. +For content-bearing graphics, preserve meaningful marks and editable +relationships with native shapes, vectors, text, and groups; styled FRAME +lookalikes do not acquire drawing semantics. Read +[document-geometry.md](references/document-geometry.md) for that construction. +Ordinary UI panels, controls, backgrounds, and separators remain Canvas HTML. + +Choose resources from the task, not repetition alone: + +- **Direct:** default for a first net-new composition. Use primitives, literals, + and assets. Do not discover or create a design system just because shapes or + values repeat. +- **Reuse:** use [design-system-reuse.md](references/design-system-reuse.md) when + the user, selected source, or project evidence establishes the applicable + system. Catalog names, domain similarity, or mere file presence do not prove + relevance. +- **Author:** use [design-system-authoring.md](references/design-system-authoring.md) + when reusable resources are requested or established as part of the + deliverable. Prove the composition and one real consumer before propagation. + +For selected variables and typography styles, read +[resource-mapping.md](references/resource-mapping.md): define or discover their +identities once, then use variable utilities and text-style classes throughout +the markup. + +## Build, inspect, and repair + +For markup create or structural update, read +[canvas-html.md](references/canvas-html.md) and check its preflight before the +call. Canvas HTML is a strict native-state dialect; browser CSS assumptions do +not apply. Page-only and native-only operations omit markup. Load native +mechanics only for the capabilities selected below. + +Build a materially complete representative screen, then open its PNG before +expanding the flow or extracting resources. Judge whether the whole supports +the intended work. When it does not, focus on the particular relationship or +execution defect that explains the mismatch and repair it. A skeleton, resource +board, or generated concept does not establish the real composition. + +For updates, read [editing.md](references/editing.md). Preserve the requested +source, unrelated fields, and stable identities while updating every dependent +representation of the changed state. For larger results, split at meaningful +screen or section boundaries and carry shared roles coherently across them. + +Inspect every `apply_canvas` result, including warnings. Repair each observed +unintended defect or disclose why it remains. A local validation failure calls +for a local payload correction; it does not justify discarding a working root +or simplifying away the intended content. Open pixels again after the final +material write, covering every materially distinct screen. Verify native facts +with `get_structure` when identity, placement, editability, or representation +matters. Opened pixels prove visual access, not good judgment; a structural pass +proves only the conditions checked. + +Finish when the requested experience is coherent and observed defects are +repaired, accepted with reason, or disclosed. Report the delivered result and +material limitations, with a Figma link to the delivered nodes. A verified Direct +result is complete without an unsolicited component pass. + +Call `end_design` after the design outcome and its final verification are complete. +An optional short `summary` records the applied result in task history. +Use `outcome: "cancelled"` only when abandoning the design. Waiting for user input +or stopping a turn is a pause, not completion or cancellation. Host lifecycle hooks +handle pauses when available; do not create progress or heartbeat calls. + +## Native mechanics — load when selected + +Read the selected reference completely; do not preload the capability catalog. +Examples demonstrate syntax, not a design template. + +| Capability | Reference | +| --------------------------------------------------------------------- | ----------------------------------------------------------- | +| Exact updates, removal, or editor context | [editing.md](references/editing.md) | +| Pages, sections, groups, Booleans, masks, transforms, shapes, vectors | [document-geometry.md](references/document-geometry.md) | +| Paints, media, effects, shaders, grids, guides | [paints-effects.md](references/paints-effects.md) | +| Exact fonts, rich text, range styles, lists, hyperlinks | [rich-text.md](references/rich-text.md) | +| Components, variants, properties, Slots | [component-authoring.md](references/component-authoring.md) | +| Variables, collections, modes, bindings | [variables.md](references/variables.md) | +| CSS variable utilities and named text-style classes | [resource-mapping.md](references/resource-mapping.md) | +| Paint, Text, Effect, Grid styles | [local-styles.md](references/local-styles.md) | +| Authorized independent research, assets, inventory, or QA delegation | [delegation.md](references/delegation.md) | + +## Mutation boundaries + +Use returned IDs and stable keys as identity, never names. Create describes a +new complete root or exact new page. Update targets an exact node or page; +omissions preserve live state. `activate` always requires `page.id` or +`page.pageKey`, even when only changing selection. + +Never mutate outside scope, remove manual or unkeyed content, or remove a +component with surviving instances. An instance's definition-derived sublayers +are not authoring targets. Do not mutate remote resources, publish, detach or +reset instances, execute arbitrary JavaScript, or imitate an unresolved +resource. Use `null` only for supported links or managed resources the requested +change actually removes. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/agents/openai.yaml b/agent-plugin/targets/standard/skills/figma-canvas-authoring/agents/openai.yaml new file mode 100644 index 00000000..25e5075e --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/agents/openai.yaml @@ -0,0 +1,7 @@ +interface: + display_name: 'Design in Figma' + short_description: 'Create user-directed native Figma designs' + icon_small: './assets/icon.svg' + icon_large: './assets/icon.svg' + brand_color: '#0098FF' + default_prompt: 'Use $figma-canvas-authoring to create a native Figma design while following my resource constraints.' diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/assets/icon.svg b/agent-plugin/targets/standard/skills/figma-canvas-authoring/assets/icon.svg new file mode 100644 index 00000000..2e8c6946 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/assets/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/canvas-html.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/canvas-html.md new file mode 100644 index 00000000..2cc27632 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/canvas-html.md @@ -0,0 +1,277 @@ +# Canvas HTML and Tailwind subset + +Canvas HTML describes desired state, not browser rendering. Use its elements for +interface structure and genuine simple UI geometry, not as a drawing medium. +Do not assemble `div` or `span` primitives to imitate a photograph, +illustration, icon, logo, texture, or other content-bearing visual; acquire the +appropriate routed raster or vector asset instead. Classes do not cover every +Figma result: use routed native bindings for gradients, media, non-shadow +effects, masks, transforms, exact fonts, and rich text. + +One `apply_canvas` markup tree may contain at most 160 elements and 12 levels. +This is a safety ceiling, not a target. Before calling, count the tree, include +only assets referenced by that call, and split larger work at meaningful screen +or section boundaries. + +Prefer supported Tailwind utilities; use arbitrary pixels only off the default +scale. Numeric spacing follows Tailwind v4's `4px` unit. Selected Figma resources +can use CSS variable utilities and `type-*` text-style classes through +[resource-mapping.md](resource-mapping.md). Arbitrary project theme extensions, +variants, plugins, viewport-dependent utilities, and CSS cascade are unsupported. + +## Contents + +- [Preflight each markup tree](#preflight-each-markup-tree) +- [Elements and identity](#elements-and-identity) +- [Layout](#layout) +- [Appearance and text](#appearance-and-text) + +## Preflight each markup tree + +Immediately before each create or structural update, scan the complete supplied +tree once: + +- require a fixed width and height on the markup root; +- give every `div` with children `flex` or `grid`, or make every child absolute + with one edge per axis and fixed parent and child dimensions; +- keep flex, grid, gap, padding, border, corner, and box-shadow classes off + `span`; +- resolve defaults and overrides before assembling each class list. Both + `text-[16px] text-[18px]` and `text-black text-white` are conflicts, not + overrides. A helper must choose the final font size, color, and line height + instead of appending them to hard-coded defaults; +- trace every `w-full`, `h-full`, and `grow` against its direct parent's axis and + the element's required dimensions; +- give a fixed-height grid explicit row tracks when its children should fill or + divide that height; omitted rows remain content-sized; +- count at most 160 elements and 12 levels, and include only assets referenced by + this call. + +Correct the complete set before calling instead of serializing until validation +reveals issues one at a time. + +## Elements and identity + +- Use `div`, `span`, or a component tag returned by the active catalog. +- Give every element one unique `data-key` of letters, numbers, `. / : _ -`. +- Use `data-node-id` only in update mode to adopt an exact live node; instance + sublayers are not authoring targets. +- When markup is supplied, every `native` key must occur as a `data-key` in that + supplied tree; existence elsewhere in the live target does not satisfy this. + For mixed structural/native edits, include each bound node under its actual + parent path, or send the omitted nodes' changes in a separate native-only update. + When only native state changes, omit markup, target the exact managed root, + and key `native` by existing stable keys in that scope. This preserves topology; + masks and node removal still require structural markup. +- Use no arbitrary attributes on `div` or `span`. Common catalog links use + `data-var-="vN"` and `data-style-="sN"`; `"none"` explicitly + unlinks that field. +- A `span` contains only text and `
` or `
` line breaks. Use + `whitespace-pre-wrap` for literal newlines or repeated spaces. A plain `&` is + literal unless it forms a semicolon-terminated entity; supported entities + decode. Canvas typography does not inherit from a parent `div`: put font and + other text utilities on each `span`/TEXT node. Put flex/grid, gaps, padding, + borders, corners, and box shadows on a parent `div`. +- A component tag is childless, includes its returned `data-ref`, and accepts + returned props plus the shared class, identity, variable, and style + attributes. + +Variable attributes use kebab-case native field names: fill, stroke, characters, +visible, dimensions/bounds, gaps, four paddings/corners/stroke sides, radius, +stroke weight, opacity, and whole-node font/line-height/letter-spacing/paragraph +fields. Style attributes are `data-style-fill`, `data-style-stroke`, +`data-style-text`, `data-style-effect`, and `data-style-grid`. Node-type and +fallback rules still apply. + +Every primitive needs one width and one height. Supported fixed forms are: + +- default spacing: `w-N`, `h-N`, `size-N` (`N * 4px`), plus `w-px`, `h-px`, `size-px` +- default width containers: `w-3xs|2xs|xs|sm|md|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl` +- exact: `w-[Npx]`, `h-[Npx]`, `size-[Npx]` +- hug: `w-fit`, `h-fit` +- hug both axes: `size-fit` +- fill: `w-full`, `h-full`, or `size-full` for both axes +- bounds: numeric, `px`, or arbitrary-pixel values with `min-w`, `max-w`, `min-h`, or `max-h`; + width bounds also accept the default container names; use `min-w-none`, `max-w-none`, + `min-h-none`, or `max-h-none` to clear a bound in an update + +Text using `w-fit` also needs `h-fit`; prefer `size-fit`. Fixed-width `h-fit` +remains valid for wrapping text. + +Create and update markup roots require fixed width and height; fill, hug, and +grow are invalid even when the live target has a sized parent. + +Use `w-full` only on a `flex-col` cross axis, `h-full` only on a `flex-row` +cross axis, and `grow` on the main axis; `grow-0` clears growth. `grow` does not +replace required dimensions—for a row track use `grow w-fit h-[3px]`. Give +growing text in constrained rows a positive `min-w-*` to prevent collapse. +Prefer a hug main axis for content stacks whose extent is not behaviorally +fixed. Otherwise budget the fixed axis as padding + gaps + fixed/minimum child +extents. A non-overflowing result is still wrong when resolved content consumes +the intended inset; compare rendered child edges with the layout's padding. +Grid children may fill cells. Direct dimension variables require fixed +fallbacks. Fixed sizes must be at least `0.01px`; native lines use `h-[0px]`. + +## Layout + +Use Auto Layout for ordinary product UI. `flex` follows CSS's horizontal default; +use `flex-row` when that direction should be explicit and `flex-col` for a +vertical stack: + +- `flex`, `flex flex-row`, or `flex flex-col` +- `items-start|center|end|baseline` +- `justify-start|center|end|between` +- `flex-wrap`, `flex-nowrap`, `content-between`, `content-normal` +- `gap-N`, `gap-x-N`, `gap-y-N`, or exact `[Npx]` +- `p`, `px`, `py`, `pt`, `pr`, `pb`, `pl` with `-N`, `-px`, or `-[Npx]` +- `box-border`, `box-content` + +New Auto Layout frames include inside strokes by default (`box-border`); +`box-content` excludes them. Center/outside strokes never affect layout, and +each nested frame owns its setting. Fixed create sizes must cover opposing +padding plus included inside strokes. Figma determines `FILL` geometry and +border-box distribution. Derive exact descendant or instance sizes from the +rendered inner box, not nominal parent size; prefer valid cross-axis fill and +exceed the box only for intentional bleed or overlap. + +`managed-content-overflow` means managed Text or INSTANCE exceeds its direct +managed Frame or Component, or a native INSTANCE contains descendant content +beyond its own fixed root. Inspect edges, clipping, rendering, and instance +bounds; resize or realign accidental overflow and retain only intentional bleed, +crop, or overlap. Property-driven content outside an INSTANCE root is a broken +component contract rather than intentional consumer overflow. + +`justify-between` uses nonnegative native Auto gap and keeps one child at the +start. Use negative `figma.autoLayout.itemSpacing` only for intentional overlap. +Omitting box-sizing on update preserves the live setting. + +`hidden` and BOOLEAN visibility remove in-flow children, changing gaps, +positions, and hug bounds. To preserve geometry, keep a fixed slot and toggle +its inner child. `absolute left-[Npx] top-[Npx]` maps to Ignore Auto Layout for +true overlays; it needs fixed offsets, cannot fill/grow, and leaves surrounding +flow unchanged. Its text and Auto Layout descendants may still hug. + +For grid use: + +- `grid grid-cols-N` +- optional `grid-rows-N` +- custom tracks: `grid-cols-[1fr_240px_fit-content(100%)]` +- optional `grid-flow-row` or `grid-flow-none` +- child placement: `col-start-N`, `row-start-N`, `col-span-N`, `row-span-N` +- child alignment: `justify-self-auto|start|center|end`, + `self-auto|start|center|end` + +Give manual grid children both row and column starts or neither. Auto-flow uses +source order without explicit starts. A height-hugging grid cannot use flexible +or automatic rows; fix either its height or row tracks. Omitting `grid-rows-*` +creates native automatic content-sized rows; increasing only the container +height does not enlarge them. + +For a coherent board larger than one call, first create one fixed parent: + +```json +{ + "mode": "create", + "markup": "
" +} +``` + +Then append one bounded screen per update. Keep the root key and classes stable, +target its returned ID, and omit previously added children so they remain in +place: + +```json +{ + "mode": "update", + "targetNodeId": "FrameID:app-board", + "markup": "
" +} +``` + +For freeform composition, omit layout classes and give each child `absolute` +with exactly one horizontal edge (`left-*` or `right-*`) and one vertical edge +(`top-*` or `bottom-*`), including negative or exact values, or use a native +relative transform. Edge placement needs fixed parent and child sizing modes; +right/bottom offsets are resolved from live bounds after each markup apply. They +are placements, not reactive CSS anchors: use Auto Layout for alignment that +must follow later mode changes without another markup apply. A plain +non-flex/grid `div` is freeform even with one child; opt into layout for every +in-flow child. Absolute children cannot grow or fill; use `static` to return one +to Auto Layout on update. + +## Appearance and text + +Frame appearance: + +- `bg-transparent|white|black`, or an exact CSS hex value +- Linear backgrounds use `bg-linear-to-t|tr|r|br|b|bl|l|tl` with exact + `from-white|black|[#hex]`, optional `via-white|black|[#hex]`, and required + `to-white|black|[#hex]` stops. Stops are fixed at 0, optional 0.5, and 1; + `bg-gradient-to-*` is accepted as a legacy alias. Do not combine a gradient + with a solid background, direct fill paints, or a fill style/variable. +- `border`, `border-N`, `border-[Npx]`; use `border-x|y|t|r|b|l` with the same widths +- `border-white|black`, or an exact CSS hex value +- `rounded`, `rounded-none|xs|sm|md|lg|xl|2xl|3xl|4xl|full`, or `rounded-[Npx]`; + prefix the value with `t`, `r`, `b`, `l`, `tl`, `tr`, `br`, or `bl` for individual sides/corners +- `overflow-hidden`, `overflow-visible` +- A clipped rounded frame does not paint its inside stroke above children. A + filled child that reaches a curved edge can therefore square off or hide the + boundary even with `overflow-hidden`; inset it, give the touching child + corners a corresponding inner radius, or add a dedicated foreground + boundary, then inspect the rendered pixels. +- Exact pixel shadow lists through `shadow-[...]` or `inset-shadow-[...]`. + Each layer needs an explicit hex, `rgb()`, or `rgba()` color and two to four + pixel lengths; use underscores for spaces, for example + `shadow-[0_8px_24px_rgba(0,0,0,0.16)]`. +- `shadow-none` and `inset-shadow-none` clear their class-owned effect stack. + Theme-dependent named scales such as `shadow-md` are unsupported: use an + explicit native style or typed effect/variable binding for a reusable token, + or resolve the governing theme before applying and provide the exact value. + +Figma accepts shadow spread only on rectangles and ellipses, or on frames, +components, and instances with a visible fill and clipping enabled. + +A new border needs weight and paint, literal or bound. Updates may change either +independently; omission preserves the other. + +New frames are transparent when background is omitted, including frames added +during update. On an existing frame, omission preserves its live background; +use `bg-transparent` to clear it. Set an explicit background when fill is +intended. + +Shared appearance: + +- `opacity-N` (`N%`) or `opacity-[0..1]`, `hidden`, `visible` +- `rotate-N`, `-rotate-N`, `rotate-none`, or `rotate-[Ndeg]` +- `mix-blend-` with `pass-through`, `normal`, `darken`, `multiply`, + `plus-darker`, `color-burn`, `lighten`, `screen`, `plus-lighter`, + `color-dodge`, `overlay`, `soft-light`, `hard-light`, `difference`, + `exclusion`, `hue`, `saturation`, `color`, or `luminosity` + +Text: + +- `font-sans|serif|mono` resolve to an editor-available family in that category, + preferring Inter, Noto Serif, and Noto Sans Mono +- `font-thin|extralight|light|normal|medium|semibold|bold|extrabold|black` +- `text-xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl` with their default line + heights, `text-SIZE/N`, or `text-[Npx]` +- `leading-none|tight|snug|normal|relaxed|loose`, `leading-N`, `leading-[Npx]`, + `leading-[N%]`, or a unitless arbitrary ratio +- `tracking-tighter|tight|normal|wide|wider|widest`, `tracking-[Npx]`, + `tracking-[N%]`, or `tracking-[Nem]` +- `text-left|center|right|justify` +- `normal-case`, `uppercase`, `lowercase`, `capitalize` +- `no-underline`, `underline`, `line-through` +- `truncate`, `line-clamp-N`, `line-clamp-none` +- `text-white|black`, an exact CSS hex value, `whitespace-pre-wrap` +- `text-shadow-[...]` for an exact pixel text-shadow list with a color and two + or three pixel lengths; `text-shadow-none` clears it + +A `span` is one TEXT node, so `bg-*` and `text-*` share its fill channel. Put +background on a parent `div` and color on its child `span`. + +Shadow classes compile to the native effect stack; never combine them with +`figma.effects` or an Effect style on that node. + +Unknown elements, attributes, classes, CSS, responsive/state prefixes, custom +themes, margins, percentages, and plugins fail closed. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/component-authoring.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/component-authoring.md new file mode 100644 index 00000000..99573887 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/component-authoring.md @@ -0,0 +1,294 @@ +# Author reusable components + +Use this reference after selecting a reusable local component. It explains +representation, not library strategy. New local components need no +`get_design_system`; use catalogs only for discovery or normalized library +props, and exact returned IDs for newly authored components. + +## Shared-responsibility decision + +New local components are opt-in for net-new authoring. Use Author when the user +requested reusable components before delivery, accepted a component pass after +seeing the completed design, or applicable project evidence makes a local +component deliverable part of the task. Existing components may still be Reuse +without authoring new ones. Repeated appearance, repeated data, screen count, +possible future reuse, or tool availability do not opt the user into Author. + +Make the decision from real usages after the representative composition is +visually sound: + +1. Name the shared job and compare the intended consumers. +2. Identify stable anatomy and meaningful content, media, state, availability, + label, swap, or slot differences. +3. Choose Author only when a truthful supported contract provides more + coordination value than it costs to create, migrate, and verify. Otherwise + keep the responsibility Direct; a brief reason is enough. +4. Bound Author at the smallest subtree that owns the complete shared job. Do + not infer that a parent must become reusable because a nested label, icon, + status, or button is reusable. + +Do not inventory or rank every recurring family, and do not turn repetition +into a quota. Record only selected Author responsibilities and their concrete +consumers. Before propagation, create the smallest real definition, instantiate +it once, and verify the exact reference. Then replace the selected consumers +with native instances; never leave literal lookalikes for a responsibility that +was deliberately selected as Author. Use the exact returned `rootNodeId` or +`nodeIdsByKey` entry for every usage. + +A keyed primitive cannot become an INSTANCE in place. Update its bounded +ancestor, add the instance under a new key, and remove the old key in the same +call. + +Stop component authoring if the ID is missing, the instance fails, or the +definition is empty, default-sized, or loses +properties. Do not substitute primitives or claim completion. Continue only +independent Direct work, report the degraded component result, and remove a +temporary definition only when unused and safe. Re-read a corrupt definition +and its intended usage; never rebuild it in place or remove one with instances. +Recreate only when unused. If a diagnostic would systematize primitives that +this definition replaces, reconcile the component first; independent token work +does not need to wait. + +Before handoff, reconcile only selected Author responsibilities with actual +consumers. Each selected consumer must be a native INSTANCE. Inspect the most +demanding instance through its descendants; root type and size do not prove +wrapping, slots, media, or state content fit. +Revise the contract or boundary when real content breaks it. + +Markup-only updates preserve keyed components, sets, instances, and shapes. +Restate native bindings only when changing native state; new native nodes still +need declarations or component references. + +Copy a complete recipe and change its design facts. Do not infer TemPad's +component shape from raw Plugin API calls. + +## Contents + +- [Define the contract from real usages](#define-the-contract-from-real-usages) +- [Keep source definitions discoverable](#keep-source-definitions-discoverable) +- [Component and properties](#component-and-properties) +- [Consume an authored component directly](#consume-an-authored-component-directly) +- [Variant set](#variant-set) +- [Slots and instances](#slots-and-instances) + +## Define the contract from real usages + +Compare every intended usage. Separate stable anatomy from varying content, +state, or nested substitution; map differences to the smallest supported Text, +Boolean, Instance Swap, variant, Slot, or nested-composition mechanism. Treat a +field as invariant only when real usages agree. + +Size the contract from real extremes: test the longest wrapping text, widest +label, largest nested swap, and materially different slots. Compare descendant +bounds with the INSTANCE root; screenshots can still paint invalid overflow. +If content exceeds the root, enlarge the definition, add a truthful size +variant, or move the varying region outside a smaller stable boundary. +If consumer-specific media cannot be expressed by the available instance +contract, keep that media direct and componentize the stable surrounding +responsibility; never freeze one image into every instance to retain a larger +component boundary. + +When stable anatomy should evolve together, expressible state differences +support a shared contract. Keep it local only when divergence or contract cost +outweighs coordinated change. + +If the contract cannot express a meaningful difference, revise it or keep the +responsibility local. Never force usages to share placeholder content or an +accidental default merely because outer geometry repeats. + +Model each mutually exclusive categorical concern as one variant axis; do not +replace it with Booleans that allow impossible combinations. Reserve Booleans +for independently optional content or behavior. + +Expose one choice through both a variant and independent property only when real +usages vary them independently. Keep each source variant's visible state +truthful; instance overrides do not repair accidental source defaults. + +## Keep source definitions discoverable + +Keep main components and sets visible at natural bounds in a clearly named +source area separate from screens. Never hide, clip, make transparent, or +invisibly nest them. For several families, use a top-level SECTION with +`contentsHidden: false`, discoverable definition children, and content-sized +bounds. + +Keep each real definition once, without redundant specimens. Before handoff, +use `get_structure` to verify every definition is visible and every intended +consumer is an INSTANCE. Inspect distinct source variants at readable scale; +names, content, and styling must encode the same state. + +Keep the source area operational and visually subordinate: use the smallest +content-sized container that exposes the definitions, outside the consumer +board or screen sequence. Do not turn it into a branded artboard, mood board, +visual-thesis panel, token showcase, or documentation page unless the user asks +for that deliverable. Product screenshots and presentation framing should stay +focused on the requested experience. + +## Component and properties + +This complete call creates a component with TEXT and BOOLEAN properties and +connects both properties to its label layer. + +```json +{ + "mode": "create", + "markup": "
Continue
", + "native": { + "button": { + "figma": { + "name": "Button", + "component": { + "type": "COMPONENT", + "properties": { + "label": { + "type": "TEXT", + "name": "Label", + "defaultValue": "Continue" + }, + "show-label": { + "type": "BOOLEAN", + "name": "Show label", + "defaultValue": true + } + } + } + } + }, + "button/label": { + "figma": { + "componentPropertyReferences": { + "characters": "label", + "visible": "show-label" + } + } + } + } +} +``` + +Stable keys such as `label` connect definitions and sublayer references within +one result; they are not generated Figma property names. Supported property +types are `BOOLEAN`, `TEXT`, and `INSTANCE_SWAP`, linked through `visible`, +`characters`, and `mainComponent` respectively. + +BOOLEAN properties control visibility, not styling. Hidden in-flow children +leave Auto Layout. Use this only for intentionally optional content. To preserve +geometry, toggle an inner layer inside a fixed slot, use `absolute` for a true +overlay, or use geometry-equivalent variants for whole-state changes. + +Treat `layout-affecting-visibility-property` as a contract warning. Fix it when +geometry must stay stable. Accept intentional reflow only after comparing true +and false instances for bounds, sibling positions, baselines, and clipping; one +default-state screenshot is insufficient. + +## Consume an authored component directly + +Use the exact ID returned by `apply_canvas`. For TemPad-authored components, +`componentProperties` accepts their stable definition keys. This follow-up +needs no catalog: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "screen/action": { + "component": { "id": "ComponentID:created-button" }, + "componentProperties": { "label": "Save", "show-label": true } + } + } +} +``` + +Replace the illustrative ID with the returned ID. Never invent IDs or use this +shortcut for unidentified library components. + +## Variant set + +This call creates two components in one variant set. Every direct child of a new +set must be an authored component; names encode axes as `Property=Value`. + +```json +{ + "mode": "create", + "markup": "
Continue
Continue
", + "native": { + "button-set": { + "figma": { + "name": "Button", + "component": { "type": "COMPONENT_SET" } + } + }, + "button/default": { + "figma": { + "name": "State=Default", + "component": { "type": "COMPONENT" } + } + }, + "button/hover": { + "figma": { + "name": "State=Hover", + "component": { "type": "COMPONENT" } + } + } + } +} +``` + +Consume the returned set ID and select siblings through variant properties. If +the call returns the set as `rootNodeId`, this creates Default and Hover: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "screen/default": { + "component": { "id": "ComponentSetID:created-button-set" } + }, + "screen/hover": { + "component": { "id": "ComponentSetID:created-button-set" }, + "componentProperties": { "State": "Hover" } + } + } +} +``` + +Replace the ID with returned `rootNodeId`. The set ID creates its default; +`componentProperties` selects another encoded variant. An exact child ID from +`nodeIdsByKey` may instantiate that variant directly. + +Use `descriptionMarkdown` and `documentationLink` only for real guidance, inside +`figma.component` beside `type` and `properties`: + +```json +{ + "figma": { + "name": "Button", + "component": { + "type": "COMPONENT", + "descriptionMarkdown": "Primary action" + } + } +} +``` + +Define shared properties on the component set rather than on one variant. + +## Slots and instances + +Use `figma.slot` only for an intentional flexible nested-content API. New slots +must be inside local authored components and include `property.name`; markup +children become defaults. Optional settings control stretching, empty display, +child limits, and preferred values. + +An `INSTANCE_SWAP` default uses exact live component/set ID `{ "id": "..." }` +or importable library key `{ "key": "..." }`. Preferred values require +`{ "type": "COMPONENT" | "COMPONENT_SET", "key": "..." }` and accept neither +live IDs nor catalog refs. Resolve catalog identity before authoring and never +invent it. Put advanced state under `figma.instance`; omission preserves normal +override behavior. + +Never edit a remote component, nest a main component inside another main +component, delete a component with surviving instances, or create properties +and variants that the requested component API does not need. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/delegation.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/delegation.md new file mode 100644 index 00000000..181b7cc9 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/delegation.md @@ -0,0 +1,82 @@ +# Delegate bounded evidence work + +Delegate evidence gathering or isolated production, never focal judgment. The +main agent synthesizes results and remains the only Canvas writer. + +## Pass the delegation gate + +Delegate only work that is: + +1. **Separable:** has a stable objective independent of evolving design choices. +2. **Compressible:** needs only a compact task-local brief. +3. **Isolated:** is read-only or produces an isolated artifact without mutating + Figma, design-system state, or another agent's files. +4. **Verifiable:** returns citations, importable asset references, exact facts, + or a bounded defect list the main agent can inspect. +5. **Worth coordinating:** gains enough from parallelism, specialist capability, + or independent review to justify handoff and synthesis. + +Keep work local if any condition fails. Do not delegate for ritual, convenience, +or another unsupported aesthetic opinion. + +## Write a complete handoff + +Give each worker one objective and its relevance, only required task evidence +and constraints, permitted tools and sources, explicit exclusions including no +Canvas writes, and an exact output contract and stop condition. The main agent +must read required Canvas references and set safety boundaries; never delegate +interpretation of this skill. Prefer fresh or minimum-context workers, pass +source evidence rather than conclusions, and avoid overlapping assignments. + +## Suitable tracks + +### Research scout + +After framing the design problem, delegate a bounded evidence question. Return: + +```txt +open decision; exact source; applicable finding; relevance; authority boundary +``` + +The scout does not choose direction. Combine questions only when their search +space is shared; use multiple scouts only for independent spaces. + +### Asset scout + +After fixing asset requirements and import contract, return one importable +`imageUrl` or `assetHash` per asset plus MIME type, dimensions, provenance, and +factual description. Return no bytes, rejected candidates, or transcript. The +main agent owns selection and integration. + +### Independent QA scout + +After a representative composition exists, provide a fresh worker its +screenshot and frozen brief without creator rationale or suspected defects. Ask +for at most eight observations: + +```txt +severity; screen/node or region; observed defect; visible evidence; violated constraint +``` + +The scout neither edits nor declares completion; the main agent checks findings +against the live canvas. + +### Inventory scout + +Use read-only inventory when independent volume warrants it, such as several +screens or icon candidates. Require exact findings and references, not a design +proposal. + +## Orchestrate conservatively + +- Default to one worker; use at most two concurrent non-overlapping workers. +- Keep a faster local critical path with the main agent. +- Only the main agent resolves intent and conflicts, chooses direction, calls + `apply_canvas`, and accepts the result. +- Resolve conflicts from evidence, not voting; discard unverifiable or + out-of-scope claims and stop when evidence is sufficient. + +Never delegate interdependent page or component construction, component +authoring plus instance placement, concurrent updates to one root, final +composition, or final acceptance. These require one ordered mutation stream and +continuous awareness of the whole. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/design-system-authoring.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/design-system-authoring.md new file mode 100644 index 00000000..45825de5 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/design-system-authoring.md @@ -0,0 +1,87 @@ +# Implement a selected local design system + +Use this reference only when the user or resolved plan requires new local +components, variables, or styles. It translates that plan into native resources +and verifies delivery; it does not choose component strategy, visual language, +resource inventory, or token taxonomy. + +## Establish the implementation contract + +Before writing, identify each selected resource, responsibility, concrete +consumer, meaningful variation, and exclusion. Resolve any open material +boundary first. For components, use the gate in +[component-authoring.md](component-authoring.md); screen count, one-screen scope, +and visual similarity alone neither establish nor exclude a component. + +Keep a private reconciliation map: + +```txt +selected resource -> native representation -> intended consumers +``` + +A resource is complete only when its native definition or binding exists and +every intended consumer uses it. Equivalent primitives or literals are not +coverage. + +## Translate the plan + +Use this loop: + +1. Stabilize one representative composition. +2. Author only selected resources with known consumers. +3. Exercise each contract in that composition. +4. Propagate native instances and bindings to all intended consumers. +5. Reconcile the final artifact with the map. + +Preserve the decided semantics: + +- A variable carries a semantic value consumers must bind and evolve together; + name it by role, not literal. +- A local style carries a reusable paint, text, effect, or grid definition. Do + not duplicate one decision across resource types unless required. +- A component carries a reusable responsibility. Define stable anatomy and + expose only variations required by real usages. + +Use [resource-mapping.md](resource-mapping.md) to map selected variable and text +style identities once per apply, then consume them through familiar variable +utilities and `type-*` classes. A new resource and its first consumer can share +one call. Query available fonts independently through `get_design_system` with +`scope: "fonts"`; selecting a family does not require discovering a file system. + +Consume a component through a childless instance placeholder without layout or +appearance classes. Do not make a repeated shell or wrapping top-level subtree +a component unless every consumer can use that placeholder through supported +properties. Slots do not permit markup children on instance placeholders; keep +incompatible wrappers as ordinary structure around a compatible inner boundary. + +Map each real component difference to the smallest supported mechanism: Text, +Boolean, Instance Swap, variant, Slot, or nested composition. Use one variant +axis per mutually exclusive categorical concern and Booleans only for +independently optional concerns. Do not encode arbitrary content as variants, +generate unused combinations, or freeze varying content as invariant. + +If supported native mechanisms cannot express a real usage, do not weaken or +redesign it silently. Choose another valid boundary or report the limitation. + +Read [variables.md](variables.md), [local-styles.md](local-styles.md), or +[component-authoring.md](component-authoring.md) only for selected resource +types. + +## Verify the native handoff + +Verify through representative consumers, not definitions alone: inspect native +bindings, Auto Layout, text resizing, property behavior, and every material +state. Raw literals and primitive lookalikes do not demonstrate system usage. + +For components, verify visible inspectable definitions and native INSTANCE +consumers using [component-authoring.md](component-authoring.md). For variables +and styles, inspect live bindings rather than apply input or equal values. + +Resolve warnings through real consumers, or remove a resource only when the +resolved plan no longer includes it. Tool friction, payload size, or an easy +resource type does not alter the plan. Do not create swatches, specimens, +definition panels, or redundant examples solely for verification; add +documentation only when requested. + +Finish when selected resources support all requested usages and the live Figma +structure reconciles with the map. Do not expand for imagined future needs. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/design-system-reuse.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/design-system-reuse.md new file mode 100644 index 00000000..11cf574f --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/design-system-reuse.md @@ -0,0 +1,59 @@ +# Reuse an existing design system + +Use this reference only when reuse is allowed and relevant. If the user rejects +a design system, use Direct. + +## Discover definitions + +Call `get_design_system` without arguments. Its immutable deterministic catalog +contains: + +- a `catalogId` scoping all short refs; +- component tags, props, source pages, and native sizes; +- variables, collections, modes, styles, and shaders as refs such as `v1`, + `k1`, `m1_2`, `s1`, and `h1`; +- `cssName` on variables and `className` on text styles for direct use in markup; +- `omitted` and `nextCursor` when more definitions remain. + +The catalog neither scans usage nor loads pages or ranks resources. Select from +returned names, pages, summaries, props, types, scopes, and defaults. Continue a +cursor or inspect an exact ref only until evidence is sufficient. + +Prefer, in order: catalog component, supported component prop, matching native +style, semantic variable, then primitive or literal for a real gap. + +When variants, anatomy, layout, or semantic meaning affect the result, inspect +the exact `ref` with the same `catalogId`. Use its `previewNodeId` with +`get_screenshot` only when appearance affects selection. Read an existing +composition with `get_code` or `get_screenshot`; catalogs do not reveal usage +conventions. Never invent refs, IDs, keys, props, or variant values. + +## Apply catalog resources + +Component tags are childless, include returned `data-ref`, and use exact props. +Omit size classes to preserve native size. Use returned CSS variable names and +text-style classes through [resource-mapping.md](resource-mapping.md). For other +native fields, bind `data-var-="vN"` or `data-style-="sN"`; put +collection modes or strict native links under `native[data-key]`. + +Replace every illustrative ref in this contract with one from the active +catalog: + +```json +{ + "mode": "create", + "catalogId": "ds_example", + "markup": "
Team settings
", + "theme": { "textStyles": { "type-body": { "ref": "s1" } } }, + "native": { + "settings": { + "variableModes": { "k1": "m1_1" } + } + } +} +``` + +If a mandatory component is absent, ask the user to open its definition page; +otherwise use the normal primitive fallback. An empty canvas does not block +catalog reuse. When reuse is unavailable, create a small coherent primitive +draft—never a token or component library solely for one screen. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/document-geometry.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/document-geometry.md new file mode 100644 index 00000000..1f24c0d6 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/document-geometry.md @@ -0,0 +1,124 @@ +# Document and native geometry + +Use `native[key].figma` only for state HTML and classes cannot express honestly; +it remains declarative desired state. + +## Contents + +- [Pages and containers](#pages-and-containers) +- [Shapes and vectors](#shapes-and-vectors) +- [Transforms, masks, and native state](#transforms-masks-and-native-state) + +## Pages and containers + +Top-level `page` can set a name, exact zero-based document index, solid RGBA +background, ordered guides, and explicit variable modes. Page-only create uses +a new `pageKey` plus name. Page-only update uses +an exact `id` or `pageKey` and omits markup. A create root may target an existing +or new page directly; creating pages and writing nodes preserve the user's current +page and viewport. Do not activate a page merely to write there. +Markup updates stay on the target node's page. + +Use top-level `mode: "activate"` with exact page identity when editor context or +selection matters; `selection: []` clears selection. Use top-level `mode: +"remove"` with an owned `pageKey` to delete a page. Page deletion rejects the +last page, manual or unowned content, and surviving external dependencies. + +Use: + +- `figma.section: { contentsHidden? }` for canvas organization; +- `figma.group: true` for an intrinsic group; +- `figma.booleanOperation: "UNION" | "SUBTRACT" | "INTERSECT" | "EXCLUDE"` + for non-destructive geometry. + +Sections can be canvas roots or direct children of sections; a frame cannot +contain a section. Sections require fixed pixel dimensions and freeform +children. Groups and Booleans use `w-fit h-fit` with freeform children. A new +group needs one child and a Boolean needs two. When updating an intrinsic +container's children, +describe every live direct child because order is semantic. + +Sections have no frame clipping, so omit `overflow-hidden` and +`overflow-visible`. When `targetNodeId` is an existing section, retain +`figma.section` on the root or the frame-typed markup root is rejected. + +## Shapes and vectors + +Use a childless `div` with `figma.shape`: + +- `{ "type": "RECTANGLE" }` +- `{ "type": "LINE" }` +- `{ "type": "ELLIPSE", "arc": { "startAngle", "endAngle", "innerRadius" } }` +- `{ "type": "POLYGON", "pointCount": 3 }` +- `{ "type": "STAR", "pointCount": 5, "innerRadius": 0.5 }` +- `{ "type": "VECTOR", "paths": [...] }` +- `{ "type": "VECTOR", "network": {...}, "handleMirroring": "..." }` + +Use exact uppercase `M L Q C Z` paths for already-decided custom vector +geometry. Selected icon roles use sourced SVG through [icons.md](icons.md), not +remembered paths. Use a vector network only for branching segments, per-vertex +state, or region-specific fills or styles. Never provide both. New vectors need +geometry; omission preserves it on update and an empty path or network clears +it. + +Each path item is an object. `windingRule` is `"NONE"`, `"NONZERO"`, or +`"EVENODD"`; use `"NONE"` for an open stroked path. Path data uses +whitespace-separated uppercase commands and numbers. + +Figma normalizes path geometry to tight bounds before applying markup size. The +childless `div` defines final bounds, not a preserved viewport. For alignment, +offset it by the path's minimum x/y and size it to the x/y spans; otherwise a +partial-range path stretches to the box. Verify rendered anchors because +`get_structure` returns node bounds, not path coordinates. + +This Direct recipe creates an editable branch curve: + +```json +{ + "mode": "create", + "markup": "
", + "native": { + "branch": { + "figma": { + "name": "Branch", + "shape": { + "type": "VECTOR", + "paths": [ + { + "windingRule": "NONE", + "data": "M 14 300 C 30 252 52 188 104 20" + } + ] + }, + "fills": [], + "strokes": [{ "type": "SOLID", "color": { "r": 0.447, "g": 0.314, "b": 0.231 } }], + "stroke": { "weight": 2, "cap": "ROUND", "join": "ROUND" } + } + } + } +} +``` + +## Transforms, masks, and native state + +- `figma.name` sets the display name; `data-key` remains identity. +- `locked` and `aspectRatioLocked` set interaction state. +- `relativeTransform` is a complete native 2×3 unit-axis transform; width and + height carry scale. Do not combine it with `rotate-*`. On create roots, TemPad + preserves rotation and skew but replaces translation with automatic placement. +- `stroke` carries weights, alignment, caps, joins, miter, and `dashPattern`. +- `corners` carries radii and smoothing. +- `mask` is `"ALPHA"`, `"VECTOR"`, `"LUMINANCE"`, or `null`. + +Place a mask before masked siblings inside one dedicated frame and describe all +direct siblings on update. A non-null mask needs a following sibling. Omission +preserves mask state; `null` disables it. + +After changing a mask, layout grid, or frame guide, call `get_structure` with +`options.native: true` on the smallest relevant root. Verify `native.mask` and +sibling order, or returned `native.layoutGrids` and `native.guides`; desired +bindings alone are insufficient. + +Use `{ "ref": "…" }` for catalog resources nested in native state and +`sourceCanvasKey` or `{ "canvasKey": "…" }` for same-result forward node +references. Never insert raw Plugin API calls. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/editing.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/editing.md new file mode 100644 index 00000000..f8653bd5 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/editing.md @@ -0,0 +1,44 @@ +# Edit an existing result + +Use this reference for an update, removal, or change of editor context. Read the +exact target and recover managed keys from structured tool results when prior +call context is unavailable. Names are labels, not identity. + +## Describe the desired change + +Trace the requested change through its visible dependents: a changed selection +may affect the working surface, label, enabled action, and summary. Preserve +unrelated content and relationships. Preserving the source does not mean +retaining stale representations of its previous state. + +Use the smallest owning target that can express the complete change: + +- For native state on existing keys, target the exact managed root and send only + `native`; omit markup to preserve topology. +- For structural changes, read `canvas-html.md`, keep `data-key` stable, and + include the affected structure. Omitted existing fields and keyed elements + retain their live state; omission is not deletion. +- `removeKeys` removes owned descendants. Top-level `mode: "remove"` removes an + exact managed root or page. Do not remove manual/unkeyed content, unmanaged + resources, or surviving external consumers. +- `mode: "activate"` requires `page.id` or `page.pageKey`, even for a + selection-only change. It changes editor context, not document state. An + exact off-current-page write does not require activation. + +Respect instance boundaries. Change an instance root or its authorized +component definition, never a definition-derived sublayer. Select only the +native references needed for the intended change. + +## Recover locally + +Read the entire mutation result. For a rejected payload, correct all reported +issues together without changing the design to fit the error. A verification +failure is rolled back by TemPad; do not assume a partial successful edit. +For an unknown transport outcome, read the exact target before retrying a create +or removal so an uncertain response does not become a duplicate mutation. + +Repair warnings where they occur. Replace a whole root only when an observed +structural defect requires it and the complete intended content can be +preserved. Reopen the affected composition after its last material write and +inspect its dependents; read back protected native facts when preservation +matters. Do not expand a local correction into an unrelated restyle. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/icons.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/icons.md new file mode 100644 index 00000000..b3457638 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/icons.md @@ -0,0 +1,65 @@ +# Deliver icons + +Use this reference only after the composition selects an icon role. It does not +require icons, set an icon count, or choose a family or visual style. + +Prefer permitted current-file, catalog, project, or user sources; otherwise use +a trustworthy brief-compatible source and record material license constraints. +When inspected evidence establishes a family or geometry, use that permitted +source or a compatible one. A general library is a fallback only when its +stroke or fill, optical weight, corners, negative space, and platform semantics +remain coherent. Do not diversify sources by quota. + +Import exact SVG geometry. Never redraw a known icon from memory or replace an +icon role with Unicode, emoji, TEXT, or assembled primitives. A character, +shape, or cluster that communicates an affordance, object, or semantic category +is an icon role even when beside a worded label. Before markup, scan literal +text for pictographic Unicode, emoji, and symbols and route each qualifying mark +to a permitted vector source. Simple geometry remains valid only when it is +itself the intended status or data mark, divider, decoration, or brand shape. + +Search results and snippets identify external candidates only; they establish +neither geometry nor license. Open the governing license once and fetch or open +every exact SVG used before markup. If either remains uninspected, omit an +optional icon or report a required gap instead of inventing one. + +For Direct delivery, give the icon a childless `div` whose classes supply the +decided wrapper bounds. Declare the inspected SVG document in +`assets[assetKey]` with `type: "SVG"`, then set +`native[nodeKey].figma.svg.assetKey` to that alias. An optional `color` resolves +`currentColor`; omit it for explicit-color SVGs. Figma may import a Frame with +Vector children; treat that subtree as one opaque asset and never flatten or +reconcile it. + +This complete Direct recipe demonstrates the required shape, not a design +default; its identifiers and values stand in for the already-decided role and +inspected source: + +```json +{ + "mode": "create", + "markup": "
", + "assets": { + "search": { + "type": "SVG", + "svg": "" + } + }, + "native": { + "search-icon": { + "figma": { "svg": { "assetKey": "search", "color": "#334155" } } + } + } +} +``` + +Omit `color` when it is not part of the selected source. A markup-only call +cannot deliver the SVG geometry. Once an icon source has been selected and +inspected, do not replace it with text or primitives merely to avoid the +`assets` and `native` mapping. + +For larger exact SVG, declare a Hub asset using a full lowercase SHA-256: + +```json +{ "type": "SVG", "assetHash": "" } +``` diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/images.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/images.md new file mode 100644 index 00000000..b019a960 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/images.md @@ -0,0 +1,120 @@ +# Deliver images and illustrations + +Use this reference only after the composition selects an image or illustration +role and the common boundaries in [visual-assets.md](visual-assets.md) establish +its subject and medium. + +Treat existing assets, rights-established remote sources, generation, and +purpose-built vectors as acquisition routes. Choose the nearest route that +satisfies content, fidelity, rights, quality, and import requirements; tools +have no global priority. Before importing a remote asset, establish its +applicable usage rights and a recoverable source. A search result, accessible +URL, CDN host, or lack of a watermark does not establish permission. Confirm +Canvas delivery before layout depends on the asset. + +When depiction is part of a record, keep it. Text, category icons, generic +placeholders, and numbered markers may index the record but cannot replace its +visual content. Source or generate an established raster role, preserve exact +vector art when vector is the real medium, or disclose the gap. + +Keep only enough trace to recover material choices, the remote source and its +applicable terms, or content distinctions. Combine role, evidence, medium, +source, rights, and import treatment in one short rationale when needed; do not +create a per-asset ceremony. Record exact creator, license, or attribution only +when the applicable terms, policy, or handoff requires it; assets sharing one +route and terms may share a trace. + +When medium is unspecified, use nearest visual evidence or ask if the choice is +material; otherwise state a low-consequence assumption. + +Use generation when the decided role needs a bespoke or fictional subject, +identity, composition, or treatment. In a prototype, a coherent generated set +may be the nearest truthful source for distinct fictional records; do not +require stock search merely because each subject is ordinary. For a real named +subject or supplied identity, use the supplied or rights-established source and +do not generate a substitute. Before generation, map each planned asset to the +subject and consumer it serves; skip ceremony that does not protect fidelity, +rights, or import. + +Compose generation and Hub import in one programmatic execution so image bytes +never enter prose or expire between calls: pass the generator's `data:` URL +directly to TemPad's `upload_asset`, read its returned `assetHash`, then declare +that hash as an IMAGE asset in `apply_canvas`. Do not regenerate an unchanged +prompt only to recover an importable URL. If generation or `upload_asset` is +unavailable, choose a rights-established public image source only when it +preserves the intended medium; otherwise disclose the required gap. Never +generate first and silently switch medium because import failed. + +Use `imageUrl` for a rights-established public IMAGE paint or same-file +`imageHash` for an existing image. For generated or other local Hub content, +declare the returned full lowercase SHA-256, then use its alias in a basic fill: + +```json +{ + "assets": { "image": { "type": "IMAGE", "assetHash": "" } }, + "native": { + "image-node": { + "figma": { + "fills": [{ "type": "IMAGE", "assetKey": "image", "scaleMode": "FILL" }] + } + } + } +} +``` + +Inline bytes and local paths are unsupported. Remote URLs must resolve directly +to accessible images, not pages or thumbnails. + +When a supplied canvas image is itself a permitted source artifact and an exact +visible subregion must carry into the result, reuse its same-file `imageHash` +instead of redrawing that content. For an axis-aligned source rectangle +`(x, y, width, height)` within an image of size `(imageWidth, imageHeight)`, and +a destination with the same aspect ratio, declare: + +```js +{ + type: "IMAGE", + imageHash: "", + scaleMode: "CROP", + imageTransform: [ + [width / imageWidth, 0, x / imageWidth], + [0, height / imageHeight, y / imageHeight] + ] +} +``` + +Supply the evaluated finite numbers, not expression strings. If the destination +aspect ratio differs, first choose an aspect-correct source rectangle rather +than stretching the subject. Open the rendered crop and verify its native IMAGE +fill; a valid transform does not prove that the intended subject was isolated. + +When the medium must remain a real image, verify with `get_structure` and +`options.native: true`; `native.imageFills` must contain the expected non-null +Figma hash. Input URLs, successful mutation, and visually similar screenshots +are not native read-back. + +The main agent owns placement, crop, and final verification. In a comparison, +make visual differences represent the subjects rather than their source files: +normalize incidental canvas padding, crop, background, viewpoint, and apparent +scale when they would bias the decision; preserve and explain differences that +are real or cannot be normalized faithfully. + +Before markup, map every content-bearing image consumer to the subject it +claims to depict. Reuse one asset and crop only when consumers represent that +same subject; distinct records require distinct assets or crops that visibly +isolate the correct subject. A composite scene may serve the composition it +depicts, but cannot stand in for several named records. Stop and source or +generate missing media instead of serializing a false mapping. + +When a gallery, carousel, or thumbnail set promises several views of one +subject, every retained view must add distinct, truthful information. Repeating +one unchanged source and crop does not satisfy that role; unrelated subjects +break identity. Use distinct sourced views, evidence-supported crops, or +generation/editing only for a named same-subject coverage need that sourcing +cannot satisfy. Otherwise reduce the views or disclose the gap. + +For repeated depictions of the same subject, keep asset identity and crop +stable unless evidence requires variation. If required media remains +unavailable, report it; omit optional media or use a neutral slot only when the +requested outcome is unchanged. A neutral slot is an explicit fallback, not +representative content or proof of reusable variation. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/local-styles.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/local-styles.md new file mode 100644 index 00000000..74aec685 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/local-styles.md @@ -0,0 +1,61 @@ +# Author local styles + +Use this reference only when the user or resolved system plan requires a local +style. Do not extract styles from an ordinary screen. New local resources need +no catalog; send `catalogId` only when a nested `{ "ref": "…" }` deliberately +reuses an existing resource. + +Copy this recipe and change its design facts. Style authoring keys persist +file-wide and are neither names nor IDs. Namespace keys by product and role. In +shared drafts, also prefix generic visible names that could collide; retain +established project naming when already clear. + +For whole-node typography, prefer a `theme.textStyles` alias and a `type-*` +class using [resource-mapping.md](resource-mapping.md). The recipe below shows +the explicit native binding form, also used for paint, effect, and grid styles. + +```json +{ + "mode": "create", + "markup": "
Account
", + "styles": { + "product/style/surface": { + "type": "PAINT", + "name": "Product/Color/Surface", + "paints": [{ "type": "SOLID", "color": { "r": 1, "g": 1, "b": 1 } }] + }, + "product/style/heading": { + "type": "TEXT", + "name": "Product/Typography/Heading", + "fontName": { "family": "Inter", "style": "Semi Bold" }, + "fontSize": 20, + "lineHeight": { "unit": "PIXELS", "value": 28 } + } + }, + "native": { + "card": { + "styles": { + "fill": { "styleKey": "product/style/surface" } + } + }, + "card/title": { + "styles": { + "text": { "styleKey": "product/style/heading" } + } + } + } +} +``` + +Types are `PAINT`, `TEXT`, `EFFECT`, and `GRID`, using `paints`, text fields, +`effects`, or `layoutGrids` respectively. For exact Paint, Effect, and Grid +shapes beyond this recipe, read [paints-effects.md](paints-effects.md). + +Omission preserves managed state. Top-level `null` removes a managed style only +when absence is required and all live consumers are cleared or removed in the +same result. Never mutate remote resources, invent library keys, or create a +broad style library for one screen. + +`unbound-created-style` means a same-call style lacks a `styleKey` consumer. +Bind it to a representative property performing its named role or remove it. A +swatch or unrelated binding is not coverage. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/paints-effects.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/paints-effects.md new file mode 100644 index 00000000..c32b82f2 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/paints-effects.md @@ -0,0 +1,111 @@ +# Paints, effects, grids, guides, and media + +Use this reference whenever the result uses a nontrivial shadow, blur, glass, +texture, noise, image paint, layered gradient material, or layout aid, including +effects expressed as Canvas HTML classes. Resolve an image or illustration's +role, subject, and medium through [visual-assets.md](visual-assets.md), then its +source and delivery through [images.md](images.md). Prefer a matching catalog +style; otherwise use direct native arrays. + +## Catalog links + +```html +
+``` + +A style owns its channel. Do not combine a non-null fill or stroke style with a +whole-node variable on the same paint. Styled strokes still need literal, +typed, or variable-bound geometry. `null` unlinks; omission preserves. + +## Resolve shadow references + +Named scales such as `shadow-md` are theme references, not portable geometry: + +- Reuse: bind the matching catalog Effect style. +- Author: create and bind a local Effect style only when the system plan requires + it. +- Direct: use an exact `shadow-[...]` class or typed `figma.effects` value. + +Never assume Tailwind defaults or create a token only to resolve a named class. +`shadow-none`, `inset-shadow-none`, and `text-shadow-none` explicitly clear. + +Treat an outer shadow's rendered halo as part of the composition. Inspect the +final PNG beyond the root edges; visible granular or noisy fringe, or a halo +that dominates the captured bounds, is a defect even when the frame itself is +intact. Preserve intended depth by tightening blur, spread, or opacity or using +smaller layered shadows, then recheck. Do not flatten established material +treatment merely to hide the defect. + +## Native paint and effect stacks + +`figma.fills` and `figma.strokes` support ordered solid, linear/radial/angular/ +diamond gradient, image/video, Pattern, and fill-shader paints. +`figma.effects` supports ordered shadows, normal/progressive blur, noise, +texture, glass, and effect shaders. + +A `SOLID` paint uses RGB `color` and optional paint-level `opacity`; only +gradient stops use RGBA colors. Keep stroke geometry, including `dashPattern`, +in `figma.stroke`, not the stroke paint. + +Use the exact gradient enum and normalized RGBA stop shape; do not translate +from CSS or Plugin API names: + +```json +{ + "figma": { + "fills": [ + { + "type": "GRADIENT_LINEAR", + "gradientTransform": [ + [1, 0, 0], + [0, 1, 0] + ], + "gradientStops": [ + { "position": 0, "color": { "r": 1, "g": 0.43, "b": 0.29, "a": 1 } }, + { "position": 1, "color": { "r": 0.16, "g": 0.09, "b": 0.24, "a": 1 } } + ] + } + ] + } +} +``` + +Other gradient enums are `GRADIENT_RADIAL`, `GRADIENT_ANGULAR`, and +`GRADIENT_DIAMOND`. + +Omission preserves a stack; `[]` clears it. Direct stacks cannot share their +channel with a literal class, whole-node variable, or style. Use variable refs +such as `{ "ref": "v1" }` and shader refs such as `{ "ref": "h1" }`; use only +returned shader property IDs and declared value shapes. + +For images, provide exactly one same-file `imageHash`, public HTTP(S) `imageUrl`, +or call-scoped `assetKey` for a full-SHA-256 Hub IMAGE asset. PNG, JPEG, and GIF +are limited to 4096×4096. For video, provide exactly one same-file `videoHash` or +public `videoUrl` for MP4, MOV, or WebM up to 100 MB. URLs must need no +credentials. Reuse `figmaImageHash`, `figmaImageHashes`, or `figmaVideoHashes` +from `get_code` only in the same file; they identify native media, not preview +bytes. + +A Pattern uses exactly one existing `sourceNodeId` or same-result +`sourceCanvasKey`. + +## Layout aids + +Prefer a matching Grid style. Otherwise `figma.layoutGrids` declares ordered +row, column, or square grids on frames, components, sets, and instances. Use +`"AUTO"` for automatic row or column count. Do not bind `sectionSize` with +`STRETCH` or `offset` with `CENTER`. + +`figma.guides` is the complete ordered X/Y guide list: omission preserves and +`[]` clears. Page guides live under `page.guides`. + +For wrapping linear Auto Layout, `figma.autoLayout` may set signed +`itemSpacing`, positive or synchronized-null `counterAxisSpacing`, and +`itemReverseZIndex`. Never declare one physical gap in both classes and native +state. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/resource-mapping.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/resource-mapping.md new file mode 100644 index 00000000..4d3f3db8 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/resource-mapping.md @@ -0,0 +1,138 @@ +# Use resources in Canvas classes + +Keep layout and visual composition in markup. Put a reusable value's native +identity in the catalog or a call-scoped `theme`, then reference it by class. +Variables remain bound Figma variables, including mode changes. A `type-*` +class binds an entire native TextStyle. Ordinary utilities such as `gap-4` and +`text-base` remain literals and do not create or discover resources. + +## Existing system + +When the applicable system permits reuse, discover it with `get_design_system`. +Use returned variable `cssName` and TEXT-style `className` with its `catalogId`: +`bg-(--surface)`, `gap-(--spacing-content)`, `type-body`. These are examples of +names, not assumed resources. Read a style's exact ref when its font, metrics, +or bindings affect the choice. + +The catalog uses valid WEB code syntax when available, otherwise derives a +name. It disambiguates collisions and keeps the resulting alias tied to one +exact identity for that catalog's lifetime. Use the returned name unchanged; +never derive identity from equal values, similar names, or another catalog. + +For task-specific names, add `theme.variables: { "--surface": { "ref": "v1" } }` +or `theme.textStyles: { "type-body": { "ref": "s1" } }`. Use returned refs. An +alias cannot replace another catalog alias with a different resource. A stable +authoring key and catalog ref for the same native identity may share an alias. + +## New system + +When the deliverable includes a design system, define the selected variables +and styles through `variableCollections` and `styles`. Map their stable keys in +`theme` and consume them in the same call. A primitive draft without a system +still uses ordinary classes; repetition alone does not require resource creation. + +This complete recipe illustrates the relationship. Change the design facts, +namespace resource keys for the product, and confirm the font family/style in +the environment before authoring it. + +```json +{ + "mode": "create", + "markup": "
Account settings
", + "theme": { + "variables": { + "--surface": { "variableKey": "product/color/surface" }, + "--content-gap": { "variableKey": "product/space/content" } + }, + "textStyles": { "type-body": { "styleKey": "product/type/body" } } + }, + "variableCollections": { + "product/theme": { + "name": "Product/Theme", + "modes": { "light": { "name": "Light" }, "dark": { "name": "Dark" } }, + "variables": { + "product/color/surface": { + "name": "Surface", + "type": "COLOR", + "codeSyntax": { "WEB": "var(--surface)" }, + "values": { + "light": { "r": 1, "g": 1, "b": 1 }, + "dark": { "r": 0.08, "g": 0.09, "b": 0.11 } + } + }, + "product/space/content": { + "name": "Space/Content", + "type": "FLOAT", + "values": { "light": 16, "dark": 16 } + } + } + } + }, + "styles": { + "product/type/body": { + "type": "TEXT", + "name": "Product/Typography/Body", + "fontName": { "family": "Inter", "style": "Regular" }, + "fontSize": 16, + "lineHeight": { "unit": "PIXELS", "value": 24 } + } + } +} +``` + +On later calls, retain the small `theme` mapping and omit resource definitions +unless changing them. The stable keys resolve the same native resources. The +mapping is local to the call, so different screens can use different aliases +without changing the file's naming. Authoring keys and native identities +persist; aliases do not create a second resource registry. + +Use [variables.md](variables.md) for modes, aliases, scopes, and resource updates; +use [local-styles.md](local-styles.md) for style definitions. A TextStyle may +bind selected typography primitives through its `variables` fields when those +values must change together. Do not create font-family, size, or weight tokens +solely to express a single named text role: the TextStyle can hold those facts. + +## Supported variable utilities + +Both `gap-(--space)` and `gap-[var(--space)]` work. Explicit type hints resolve +ambiguous Tailwind prefixes, for example `text-(length:--body-size)` versus +`text-(color:--foreground)`. + +| Utility | Native value | +| ---------------------------------------------------------------------- | ------------------------------------------------------- | +| `bg-(--surface)`, `text-(--foreground)`, `border-(--border)` | COLOR fill or stroke; border still needs a width | +| `w/h/size/min-w/max-w/min-h/max-h-(--value)` | FLOAT dimensions, in pixels | +| `gap/gap-x/gap-y-(--value)` | FLOAT layout gaps, in pixels; axes follow flex or grid | +| `p/px/py/pt/pr/pb/pl-(--value)` | FLOAT padding, in pixels | +| `rounded/rounded-tl/rounded-tr/rounded-br/rounded-bl-(--value)` | FLOAT corner radius, in pixels | +| `border-(length:--width)` | FLOAT stroke width, in pixels | +| `text-(length:--size)`, `leading-(--leading)`, `tracking-(--tracking)` | FLOAT font size, line height, letter spacing, in pixels | +| `font-(family-name:--family)` | STRING font family | +| `font-(--weight)` | FLOAT font weight, 1–1000 | +| `opacity-(--opacity)` | FLOAT opacity, 0–1 | + +The tool reads an initial native value itself and retains the variable binding; +do not add a second literal fallback class. Native node, layout, and scope rules +still apply. This is a bounded mapping to Figma fields, not a CSS engine: no +`calc()`, var fallbacks, arbitrary expressions, or cascade. FLOAT metrics use +the native units above, not unitless CSS line-height multipliers. + +## Typography ownership + +`type-body` consumes the whole TextStyle. Keep color, sizing, alignment, and +wrapping classes on the text node as needed; omit font, weight, size, leading, +tracking, case, and decoration overrides owned by that style. Choose another +style or explicitly unlink the style for a deliberate local treatment. Composite +typography has no single Figma variable type, so `type-*` is an explicit custom +utility convention rather than a Tailwind default or a fabricated CSS variable. + +Inline `data-var-*`, `data-style-*`, and `native` bindings remain available for +fields outside this subset, exact native fonts/styles, and explicit unlinking. +Use one mechanism per property. Unknown names, conflicting declarations, +incompatible types, and cyclic variable aliases require correction; the tool +does not guess a replacement. + +Updates preserve omitted native state. Removing a resource class or replacing +it with a literal does not unlink the existing binding: explicitly clear the +variable/style with its `data-var-*="none"`, `data-style-*="none"`, or supported +`native` null binding when that is the intended change. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/rich-text.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/rich-text.md new file mode 100644 index 00000000..3e26cc97 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/rich-text.md @@ -0,0 +1,52 @@ +# Rich text and hyperlinks + +Use this reference for native font application or Figma-only text behavior; +use [typefaces.md](typefaces.md) when font selection or availability needs resolving. +Use `span` for editable text. Put whole-node typography in classes, a catalog +Text style, or semantic variable bindings when possible. + +`native[key].figma.text` supports: + +- exact whole-node `fontName`, `autoRename`, vertical alignment, and leading + trim; +- paragraph indent/spacing, list spacing, hanging punctuation/list; +- whole-node hyperlink; +- ordered rich-text `ranges`. + +Do not combine `autoRename: true` with fixed `figma.name`. + +When no Text style or typography variable expresses the chosen family and +style, use the exact available Figma font: + +```json +{ + "fontName": { "family": "IBM Plex Sans", "style": "Medium" } +} +``` + +Do not combine it with `font-*` classes, linked Text styles, or font family/style +variables. Never guess family or style availability. + +Range `start` and `end` are UTF-16 offsets into final characters. Ranges must be +ordered, non-overlapping, and set at least one property; split overlapping +intentions into disjoint intervals. A range may set font name/size, case, +letter spacing, line height, complete underline state, native fills, Text/Paint +style, list options, indentation, paragraph spacing, hyperlink, and supported +text-range variables. + +Use `{ "ref": "s1" }` for a catalog range style and `{ "ref": "v1" }` for a +range variable. `null` unlinks supported styles or hyperlinks; omission +preserves. + +Hyperlinks support URLs and node targets. For a same-result target: + +```json +{ + "type": "NODE", + "value": { "canvasKey": "settings/help" } +} +``` + +The target may appear later in markup; never remove a live hyperlink target. If +a catalog component exposes text through a prop, set that prop instead of +editing internal layers. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/style-grounding.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/style-grounding.md new file mode 100644 index 00000000..2a83efca --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/style-grounding.md @@ -0,0 +1,80 @@ +# Ground design judgment + +Use this reference for a new direction, material redesign, or consequential +uncertainty not settled by the user or an established source. Exact reproduction +and mechanical edits use their supplied evidence directly. + +## Inspect what can change the decision + +Start with the nearest credible evidence: the supplied design or implementation, +real product states, primary platform requirements, or adjacent visual work. +Choose separate evidence for behavior and visual expression when needed. A +functional walkthrough can establish behavior without settling visual language; +a visually relevant product state or adjacent visual work can show how density, +controls, surfaces, icon/text economy, and states cohere without establishing +behavior it does not expose. One artifact may inform both only when the relevant +behavior and pixels are actually inspected. + +Open the relevant state at useful scale. A homepage or brand campaign may not +show the working interface. Search cards, prose, remembered products, generated +images, and failed retrievals are not inspected visual precedents. A content +photograph establishes what it depicts, not the surrounding application's +interaction or composition. Follow the main skill's first-write evidence +boundary when retrieval fails. + +An image-search result that exposes only a screenshot description or URL remains +a search card. Open the actual product-state pixels at useful scale before +treating them as visual grounding; otherwise use the result only as behavioral +description. + +Research is grounded when it changes, confirms, or reopens a material decision +in the new result. Retain enough source identity and context to support that +claim; do not invent a source-by-source decision report. If a source contributed +nothing consequential, do not cite it as a precedent. Generic expertise helps +interpret the evidence; its familiar defaults are not evidence about this +product. + +There is no source quota. Stop when further investigation is unlikely to change +a material choice. Do not research routine decisions for ceremony. Keep source +screens outside the authored result unless the user asked to place or reproduce +them, and preserve required source content and behavior when adapting a design. + +## Form a provisional direction + +Integrate the brief, evidence, and professional judgment into a relationship +among content, state, and action, with a visual language that makes it fitting +and perceptible. A new design needs its own solution; independence is not a +reason to discard an applicable interaction or representation because it is +harder to source or serialize. + +Before the first write, be able to state privately what the inspected pixels +changed or confirmed about the recurring visual language. A mood label or +task-themed palette is not that direction; if the same control and surface +grammar could survive a noun swap, inspect more relevant pixels or reconsider +the synthesis. + +Resolve recurring visual roles enough to try them in a real composition. The +foundation is provisional and may change after seeing pixels. It is not a +separate foundation board or permission to create components, variables, or +styles outside the task's resource scope. + +Reconsider choices whose only justification is habit or semantic association. +Ask what in the brief or inspected reality makes the proposed treatment fit. +Familiar solutions can be appropriate; choosing the opposite of a criticized +motif is no stronger evidence. Functional specificity alone does not settle +expression, and stylistic difference alone does not make the product useful. + +## Externalize unresolved visual choices + +If materially different visual hypotheses remain and a capable image-generation +tool is available, a bounded visual exploration can help you see their +consequences. Open those pixels and use them to reconsider the composition; +omit this step when the direction is already clear. + +Generated concepts are speculative sketches, not real-product evidence or +flattened Figma deliverables. Do not trust their text/data or trace them +literally. A generated subject chosen as actual product content is a separate +asset decision under `visual-assets.md`. + +Return to the representative native composition and inspect it. Let a mismatch +reopen the decision it actually challenges; otherwise complete the design. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/typefaces.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/typefaces.md new file mode 100644 index 00000000..185284bc --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/typefaces.md @@ -0,0 +1,48 @@ +# Choose and apply fonts + +Use this reference when selecting or changing fonts, delivering a required +family/style, or resolving uncertainty about the text's scripts. Availability +can change a provisional choice; query before committing when that matters. + +Start from applicable Text styles, typography variables, project fonts, or +supplied references. Preserve established font identities for ordinary edits. +For a new direction, form candidates from the language, text roles, density, +and visual intent. A portable `font-sans|serif|mono` category does not establish +an exact family or suitable coverage for the actual text. + +## Query what can change the choice + +`get_design_system` with `scope: "fonts"` reads the environment without scanning +file resources. It is valid for direct composition, reuse, and an independent +system, including a blank page. + +- With candidate family names, use `families: ["Noto Sans SC"]` to inspect + exact native style names and missing families in one call; batch candidates. +- Use `query: "Noto"` when the family name itself needs discovery. This searches + names, not language coverage or visual suitability. +- Continue `nextCursor` with the same filters only when more results could + affect the choice. Reuse current evidence rather than querying per text node. + +Use returned or source-established native names. For an unavailable provisional +candidate, reconsider the choice. For a required font, preserve the requirement +and disclose the delivery gap rather than silently substituting another family. + +## Apply the selected typography + +Reuse the applicable TextStyle or font variables. If a new design system is in +scope, define the selected text roles as TextStyles and consume their `type-*` +classes through [resource-mapping.md](resource-mapping.md). Font selection alone +does not require creating styles or tokens. + +For direct composition, `font-[family-name:Noto_Sans_SC] font-semibold` fixes +the family and chooses its closest available weight. Underscores encode spaces; +`\_` preserves an underscore. Use `native[key].figma.text.fontName` with exact +`{ family, style }` when the native style identity matters; see +[rich-text.md](rich-text.md). Weight matching is approximate. For variable-driven +typography, consider the family/weight/style combinations in the delivered modes. + +Inspect representative real content in the composition, including relevant +scripts, numbers, punctuation, and wrapping. Availability and successful loading +do not prove glyph coverage; a correct-looking screenshot alone does not prove +native font identity or current editability. Reopen the font choice when the +observed text challenges it, without requiring a separate specimen board. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/variables.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/variables.md new file mode 100644 index 00000000..692a8699 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/variables.md @@ -0,0 +1,154 @@ +# Author local variables + +Use this reference after the representative pixel check when repeated colors +may carry shared semantic roles, or when the user or resolved system plan +requires local variables. Do not extract tokens from an ordinary screen. New +resources need no catalog; send `catalogId` only for deliberate nested +`{ "ref": "…" }` reuse. + +## Contents + +- [Decide from real roles](#decide-from-real-roles) +- [Author variables](#author-variables) +- [Bind and verify](#bind-and-verify) +- [Update and remove](#update-and-remove) + +## Decide from real roles + +After any selected representative component reconciliation and before +propagation, call full `get_code` with unresolved tokens only when repeated +colors plausibly represent semantic roles whose coordinated maintenance matters. +Treat `literalClusters` as candidate locations, not a to-do list. Select a role +only when concrete consumers should evolve together; split mixed roles even +when their literal values match. Leave incidental, local, and ambiguous +repetition literal. If the diagnostic is unavailable, do not infer a system +from repetition. + +For each selected role, map concrete consumer and field to a semantic variable +key, bind every representative consumer, then re-run once to confirm the role is +exposed through `tokens` and no longer unresolved. A non-empty +`literalClusters` result is acceptable. + +Carry only selected mappings into propagation. A later apply that includes a +consumer of a selected role must bind that field in the same call; an inherited +instance binding does not cover sibling literals. Before finalization, scan each +materially distinct dependent root that uses a selected role once, fix missing +bindings for those roles, and recheck only changed roots. Do not create variables +to empty diagnostics, expand the map from literal equality, or repeat scans after +the selected roles are verified. + +## Author variables + +Copy this recipe and change its design facts. Collection and variable authoring +keys persist file-wide and are neither names nor IDs. Choose one +collision-resistant prefix for the independent system; recover existing exact +keys when intentionally updating it. Mode keys are collection-scoped. + +```json +{ + "mode": "create", + "markup": "
Account
", + "variableCollections": { + "product/theme": { + "name": "Theme", + "modes": { + "light": { "name": "Light" }, + "dark": { "name": "Dark" } + }, + "variables": { + "product/color/surface": { + "name": "Color/Surface", + "type": "COLOR", + "scopes": ["ALL_FILLS"], + "values": { + "light": { "r": 1, "g": 1, "b": 1 }, + "dark": { "r": 0.08, "g": 0.09, "b": 0.11 } + } + }, + "product/space/md": { + "name": "Spacing/Medium", + "type": "FLOAT", + "scopes": ["GAP"], + "values": { + "light": 16, + "dark": 16 + } + } + } + } + }, + "native": { + "card": { + "variables": { + "fill": { "variableKey": "product/color/surface" }, + "gap": { "variableKey": "product/space/md" } + }, + "variableModes": { + "product/theme": "dark" + } + } + } +} +``` + +A new collection needs `name` and at least one named mode. Each variable needs +`name`, `type`, and a value for every mode. Types are `BOOLEAN`, `COLOR`, +`FLOAT`, and `STRING`. Values may alias another variable: + +```json +{ "variable": { "variableKey": "…" } } +``` + +Valid scopes: + +- general: `ALL_SCOPES`, `TEXT_CONTENT`, `CORNER_RADIUS`, `WIDTH_HEIGHT`, `GAP`, + `OPACITY`; +- color: `ALL_FILLS`, `FRAME_FILL`, `SHAPE_FILL`, `TEXT_FILL`, `STROKE_COLOR`, + `EFFECT_COLOR`; +- numeric effect/stroke: `STROKE_FLOAT`, `EFFECT_FLOAT`; +- typography: `FONT_FAMILY`, `FONT_STYLE`, `FONT_WEIGHT`, `FONT_SIZE`, + `LINE_HEIGHT`, `LETTER_SPACING`, `PARAGRAPH_SPACING`, `PARAGRAPH_INDENT`. + +Use `STROKE_COLOR`, not `ALL_STROKES`. Combine neither `ALL_SCOPES` with other +scopes nor `ALL_FILLS` with `FRAME_FILL`, `SHAPE_FILL`, or `TEXT_FILL`; +`ALL_FILLS` may coexist with a non-fill scope such as `STROKE_COLOR`. + +## Bind and verify + +Bind through `native[key].variables` using the exact supported field, such as +`fill`, `stroke`, `gap`, `paddingTop`, `width`, `visible`, `fontSize`, or +`characters`. Retain a matching literal class when Figma needs an initial paint +or numeric fallback. + +Bind each variable to representative fields performing its semantic role. +Prefer `GAP` for shared gaps/padding, `WIDTH_HEIGHT` for semantic control/icon +sizes, and `CORNER_RADIUS` for shared radii. Do not tokenize viewport dimensions, +one-off crops, content-derived geometry, or optical corrections merely because +numbers repeat. + +A representative binding proves usability, not complete coverage. Bind every +consumer intended to evolve with the role; keep equal peer literals only when +incidental or independently owned. + +`apply_canvas` reports `unbound-created-variable` when a new variable lacks a +same-result consumer. Bind it to a real consumer or remove it. A staged warning +may be temporary, but final delivery must show a native binding; equal literals +do not count. + +`variable-fallback-mismatch` means a bound literal matches none of the +same-call variable's direct or aliased mode values. Align the fallback with a +real mode or bind the variable that owns the value, or the binding will silently +change the declared markup. + +## Update and remove + +After changing a variable value, update and verify every intended consumer that +cannot carry a native binding, such as `figma.svg.color`; omission leaves its +old literal in place. + +Omission preserves managed state. Top-level `null` removes a managed variable, +mode, or collection only when absence is required and all consumers are cleared +or removed in the same result. Never mutate remote resources, invent parent +collections or library keys, or build a broad token system for one screen. +Extended collections must inherit a real local or catalog collection and obey +plan limits. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/visual-assets.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/visual-assets.md new file mode 100644 index 00000000..eaa3d4c8 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/visual-assets.md @@ -0,0 +1,57 @@ +# Choose and preserve visual assets + +Use this reference after the design selects an icon, image, +illustration, diagram, or vector asset. It governs role, medium, source +integrity, editability, and delivery—not whether the design should contain that +asset or what the finished visual style should be. + +Research pixels and generated screen concepts remain evidence for judgment, +not canvas content. Import, reproduce, annotate, or compare them only when the +user explicitly requests that treatment. When evidence establishes that the +new product needs an asset role, acquire or author a truthful asset for the new +result instead of redrawing or embedding the reference. + +## Preserve the decided role + +Start from the composition, not an available tool or assumed asset slot. Once a +material role is selected, fulfill it faithfully; sourcing difficulty is not a +reason to replace an image, icon, visualization, or exact medium with easier +text or plausible geometry. + +Depiction is a role, not a medium. Choose raster, sourced vector, +agent-authored vector, diagram, or another medium only when the brief, inspected +evidence, or a low-consequence assumption supports it. Convenience never +changes the medium. + +Treat content-bearing visualization—such as a chart, map, waveform, notation, +document or media preview, or domain instrument—as a first-class +representation. Identify the user decision and the visual structures that make +it possible. Preserve enough context and density to act; a stylized trace or +labeled decoration is not the representation. When only topology or sequence +is intended, name and design it as a diagram. + +When recognition depends on a subject's real appearance—such as a person, +product, food, place, room, photograph, cover, or shared-media preview—preserve +that distinction with a real sourced or generated image unless the brief or +inspected evidence independently establishes an illustrated language. + +Preserve editability semantics. Build changing diagram labels, shapes, and +relationships as native structure; use an opaque SVG only when exact vector art +is the asset. An SVG wrapper with Vector descendants does not make a diagram +model editable. If editable primitives cannot carry a required representation, +use an evidence-supported native, vector, or raster base with changing overlays +editable, or disclose the gap. + +For material assets retain enough evidence for identity and content fidelity, +provenance and applicable rights, source quality, and Canvas-compatible form. +Never silently change subject, style, or medium. Crops, masks, overlays, and +retouching must preserve the depicted subject; do not hide distinctive branding +or features to make one subject represent another. + +## Load only the selected branch + +- For an icon role, read [icons.md](icons.md). +- For an image or illustration, read [images.md](images.md). + +For diagrams and other custom vector art, use the source and editability +boundaries above, then load only the required geometry or paint mechanics. diff --git a/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/visual-composition.md b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/visual-composition.md new file mode 100644 index 00000000..27993d33 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-canvas-authoring/references/visual-composition.md @@ -0,0 +1,64 @@ +# Compose a product interface + +Use this reference when forming or reconsidering a composition. Keep the +person's working experience in view; use the questions below only where they +help resolve a decision. They are not independent quality axes. + +## Find the working relationship + +What is the person attending to, and what can they do with it in the depicted +state? Does the chosen screen or flow expose the user's central work, or merely +promise it through a button whose destination is absent? What changes across +states, and what must remain perceptible while that happens? Arrange content, +controls, and context so their relationship is understandable in the rendered +whole. + +A familiar shell may be the right answer. Reconsider it when it hides the +working object, requires unnecessary reading or navigation, or survives only +because task-specific nouns make it look relevant. Novelty and decoration do +not repair that mismatch. + +As content grows, what extends: the document or an owned scrolling region? +Choose document flow, a fixed workspace, or a hybrid from product behavior; +check that making room has not silently redefined the device or window viewport. +Density and control scale follow platform, frequency, precision, and environment +of use. In frequent expert work, inspect the real product's interaction economy +before carrying over the spacing and repeated explanations of an occasional +consumer journey. Preserve legibility and suitable targets in either case. + +## Make meaning perceptible + +What should someone notice now, and what should stay available without +competing? Resolve type, position, scale, color, contrast, media, depth, and space +together. Repeated roles need recognizable treatment; differences need to carry +meaning in this task. An expressive role does not by itself justify the first +familiar palette, shape, or effect. + +Choose text, icons, images, and graphics by recognition, comparison, +manipulation, and expression. Familiar iconographic affordances can reduce the +reading and space required by repeated controls; words can be more precise. +Inspect that tradeoff at actual size, including when every action has become +text. Source selected icons through `visual-assets.md`; sourcing effort is not +a design reason to drop their role. + +A working graphic must carry the distinctions needed for the decision. Check +whether its marks, scale, context, and state make the relevant comparison or +manipulation possible. Changing a label does not change what the marks encode. This is a question +of represented meaning, not a quota for detail or a preferred graphic style. Use `visual-assets.md` for truthful +source and native representation. + +## Learn from the rendered result + +Open the representative composition at useful scale. Mentally follow the +central action through its visible consequences. Does the selected state agree +with the working surface, available action, and result? If the experience breaks, +inspect the particulars that explain where and why. + +Judge spacing from visible relationships: nested insets, seams, baselines, +grouping, and repeated rhythm. Nominal padding or a non-overflowing bounding box +does not prove that the intended space survived native layout. Repair the +owning relationship instead of decorating over it. + +Carry resolved shared roles into dependent screens while allowing their layouts +to differ with the work. Stop when the requested whole is coherent and the +observed defects are resolved; do not keep polishing to fill a checklist. diff --git a/agent-plugin/targets/standard/skills/figma-design-to-code/SKILL.md b/agent-plugin/targets/standard/skills/figma-design-to-code/SKILL.md new file mode 100644 index 00000000..a5bb5f20 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-design-to-code/SKILL.md @@ -0,0 +1,177 @@ +--- +name: figma-design-to-code +description: >- + Implement or update project-consistent UI code from a visible Figma selection + or nodeId using TemPad Dev MCP. Use when the user wants Figma UI recreated, + ported, or integrated into the target project's framework, styling system, + tokens, assets, and existing components. Do not use for design critique, + product invention, generic code review, or guessing states, responsiveness, + or behavior not evidenced by Figma, the project, or the user. +--- + +# Implement Figma design in code + +Turn visible Figma evidence into the smallest project-native implementation +that preserves the intended result. Keep that result focal: project files, +TemPad output, rules, and tool calls are evidence for the implementation, not +deliverables to reproduce mechanically. + +Require TemPad Dev MCP to provide trustworthy design evidence for the current +selection or an exact `nodeId` inside the user's established scope. Never +reconstruct the design from memory, screenshots alone, or `get_structure` +metadata. + +## Evidence and authority + +Use each source only for what it can establish: + +- **The user** sets scope, requirements, prohibitions, and missing product or + implementation decisions. +- **The project** sets framework, file placement, component boundaries, + styling, tokens, assets, dependencies, and verification conventions. +- **TemPad Dev** sets visible structure and rendered design facts. + +Follow project instruction files for concerns outside Figma-to-code +translation. Do not add policy for routing, analytics, i18n, CMS, or other +orthogonal systems. + +TemPad can establish visible hierarchy, layout, spacing, typography, color, +effects, token references, exported assets, and codegen unit context. It cannot +establish unevidenced states, responsive behavior, business logic, navigation, +validation, analytics, or project conventions. Treat `get_structure` as +hierarchy and geometry evidence only, never as missing style truth. + +## Workflow + +### 1. Establish the implementation envelope + +Read only local evidence that can change this implementation, in this order: + +1. applicable `AGENTS.md` or equivalent instructions; +2. relevant design-system, token, component, and asset guidance; +3. the nearest comparable implementation and reusable primitives; +4. framework, styling, and check configuration needed for this task. + +Determine the target file or component boundary, framework, styling method, +token and asset paths, reuse candidates, dependency constraints, and narrowest +relevant checks. Inspect Tailwind version and theme scales only when the +project actually uses Tailwind-compatible tooling. + +Do not inventory the repository broadly after the needed envelope is clear. If +a missing project decision would materially change the result, ask before +implementation. + +### 2. Read the design at the requested scope + +Call TemPad Dev's `get_code` before implementing: + +- use `resolveTokens: false` by default; +- omit `nodeId` for the current single selection; pass one only when the user + supplied it or TemPad returned the exact ID for a targeted read inside the + user's established scope; +- set `preferredLang` from the established project target; +- keep TemPad's default vector behavior unless the user explicitly requests + asset-preserving vector fidelity and the active MCP version supports it. + +Use `resolveTokens: true` only when the user explicitly does not want design +token references. Treat returned `lang` as authoritative because plugin +configuration may override `preferredLang`. + +Retain the returned `code`, `lang`, `warnings`, `assets`, `tokens`, and +`codegen` facts that bear on the implementation. Use +`codegen.config.{cssUnit,rootFontSize,scale}` for exact unit conversion. + +Prefer one top-level read that preserves the requested composition. If the +tool is unavailable, points at the wrong file, or returns incomplete evidence, +read [recovery.md](references/recovery.md) before doing anything else. + +### 3. Separate facts, adaptations, and gaps + +Before editing, distinguish: + +- **design facts** to preserve; +- **project-native adaptations** supported by existing components, tokens, + utilities, or asset conventions; +- **unevidenced product decisions** that must remain unimplemented or be asked. + +Map by rendered value and semantics, not by a convenient name. A familiar +component or token is a candidate, not proof of equivalence. If more than one +material implementation path remains equally plausible, ask the user. Infer +only low-consequence details and report any inference that affects the result. + +### 4. Implement the smallest coherent change + +- Keep the established framework, styling system, file placement, imports, and + abstraction level. Do not introduce a parallel system. +- Reuse an existing primitive only when its semantics and rendered behavior fit + without guessing. Do not force reuse that erases design facts. +- Preserve exact rendered values unless project evidence proves an equivalent + token, utility, or component. For `rem` output, convert with TemPad's actual + `cssUnit`, `rootFontSize`, and `scale`. +- Preserve intentional uncommon output, including pseudo-elements, filters, + masks, blend and backdrop effects, gradients, and non-default compositing, + unless a documented project constraint requires an adaptation. +- Implement only evidenced states and responsiveness. Do not invent hover, + loading, error, empty, disabled, or responsive behavior. +- Use native semantic elements and preserve keyboard access and accessible + names when an established primitive does not already provide them. +- Add no runtime or build dependency without user approval unless the user has + explicitly waived that constraint. +- Keep `data-hint-*` attributes out of shipped code. + +When TemPad returns relevant entries, load only the matching protocol: + +- assets: read [Assets](references/assets-and-tokens.md#assets) and follow the + project's asset delivery path; +- token references: read [Tokens](references/assets-and-tokens.md#tokens) and + follow the project's token workflow. + +Read both when both are present and skip both when neither is present. + +Do not enter a visual tuning loop. Change the implementation again only when +new project, design, tool, or verification evidence identifies a concrete +defect. + +### 5. Verify in the project's real workflow + +Run the narrowest relevant checks defined by project instructions and scripts. +Repair implementation failures and rerun the affected checks. Use an existing +preview, screenshot, or comparison workflow when available; do not invent a +universal verification matrix. + +If no runnable check exists, report the implementation as unverified. Do not +claim visual completion without a real project comparison path; ask the user +to confirm the rendered result against Figma. + +## Hard stops + +Stop instead of shipping when: + +- TemPad is unavailable, unauthorized, inactive on the intended file, or + cannot provide a trustworthy visible parent composition; +- the target is unreadable or not visible; +- project, design, and user evidence still conflict after targeted recovery; +- a missing decision would materially change behavior, structure, dependency, + asset delivery, or token mapping; +- required assets cannot be retrieved or stored under project policy. + +If blocked, give at most three concrete actions that would unblock the task. + +## Handoff + +Report: + +- what changed and where; +- only the relevant adaptation, inference, warning, asset/token handling, or + residual visual risk; +- checks run, their result, and what remains unverified. + +Keep absent concerns absent from the handoff. Do not produce a compliance +checklist for branches the task never used. + +## Decision example + +If TemPad emits `padding: 15px` and the project has a `space-4` token worth +`16px`, preserve `15px` unless project evidence explicitly makes the token the +intended mapping. Project consistency selects the representation; it does not +authorize changing the visible design. diff --git a/agent-plugin/targets/standard/skills/figma-design-to-code/agents/openai.yaml b/agent-plugin/targets/standard/skills/figma-design-to-code/agents/openai.yaml new file mode 100644 index 00000000..406fbf6e --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-design-to-code/agents/openai.yaml @@ -0,0 +1,7 @@ +interface: + display_name: 'Figma Design to Code' + short_description: 'Implement project-consistent UI code from Figma' + icon_small: './assets/icon.svg' + icon_large: './assets/icon.svg' + brand_color: '#0098FF' + default_prompt: 'Use $figma-design-to-code to implement the selected Figma design in the current project.' diff --git a/agent-plugin/targets/standard/skills/figma-design-to-code/assets/icon.svg b/agent-plugin/targets/standard/skills/figma-design-to-code/assets/icon.svg new file mode 100644 index 00000000..2e8c6946 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-design-to-code/assets/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/agent-plugin/targets/standard/skills/figma-design-to-code/references/assets-and-tokens.md b/agent-plugin/targets/standard/skills/figma-design-to-code/references/assets-and-tokens.md new file mode 100644 index 00000000..01dec4a6 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-design-to-code/references/assets-and-tokens.md @@ -0,0 +1,47 @@ +# Translate assets and tokens + +Read this reference only when `get_code` returns `assets` or `tokens`. + +## Assets + +Follow the project's established asset and icon policy before TemPad delivery +details. + +- Download bytes only from a TemPad-provided `asset.url`. Never substitute a + public internet asset. +- Treat assets as files to store or reference, not text evidence to parse. +- If project policy forbids storing them, reference TemPad URLs only when the + user accepts the local-server dependency, and report it. +- Treat emitted `` markup as design truth for structure, + size, and instance color. Refactor delivery only through an existing project + SVG path. +- If upload falls back to inline SVG, preserve that markup rather than + resynthesizing the vector. +- `themeable: true` permits one contextual color channel, usually + `currentColor`; drive it through the established wrapper or icon convention. + Preserve internal palettes when `themeable` is absent. +- Do not invent a new SVG pipeline, multi-color props, or custom variables. + +If a required asset cannot be retrieved or represented under project policy, +stop rather than draw or substitute it from memory. + +## Tokens + +Preserve token usage when the target project can carry or map it safely. +Token facts may be direct values or mode-specific values keyed by +`Collection:Mode`; preserve aliases between variables when present. + +- Map to an existing project token only when value, reference behavior, + semantics, and relevant mode agree. A similar name is insufficient. +- Preserve TemPad token references through the project's normal token workflow + when that workflow can accept them. +- Add a token only when the project already defines how and this task calls for + it. +- If landing location, mode, or mapping remains ambiguous, use the exact + rendered value and report the fallback. +- Use hint metadata only while reasoning about a mode; never ship hint + attributes. + +When tokens and explicit rendered values disagree, do not silently choose. +Narrow the design evidence or ask the user which source expresses the intended +state. diff --git a/agent-plugin/targets/standard/skills/figma-design-to-code/references/recovery.md b/agent-plugin/targets/standard/skills/figma-design-to-code/references/recovery.md new file mode 100644 index 00000000..88cf1e89 --- /dev/null +++ b/agent-plugin/targets/standard/skills/figma-design-to-code/references/recovery.md @@ -0,0 +1,54 @@ +# Recover trustworthy design evidence + +Read this reference only when TemPad is unavailable, a `get_code` call warns +or fails, or the requested selection cannot fit in one trustworthy response. + +## Connection and target failures + +For a transient transport failure, retry once. Do not blind-retry invalid +selection, hidden node, wrong file, deterministic budget, or depth errors. + +If TemPad is unavailable or active on the wrong file, stop and ask the user to: + +1. enable MCP access in TemPad Dev **Preferences > Agent integration**; +2. keep the intended TemPad Dev and Figma tab active; +3. use the MCP badge in the panel to activate the intended file when multiple + Figma tabs are open. + +Do not edit code while design evidence is untrustworthy. + +## Incomplete `get_code` results + +Preserve the largest trustworthy parent composition and narrow only the +missing evidence: + +- **`depth-cap`**: keep the returned top-level composition, then use returned + `data-hint-id` values for targeted child `get_code` calls. +- **budget overflow or shell response**: keep the returned parent shell, then + fetch omitted children separately. Use the smallest parent that still proves + their shared layout. Plain string truncation is not evidence. +- **hierarchy, geometry, or overlap uncertainty**: call TemPad Dev's + `get_structure` only to resolve that uncertainty or select a narrower retry + target. + +Never rebuild a missing parent from child metadata. If no trustworthy parent +shell can be recovered, stop the full implementation and ask the user to +narrow the selection or choose the highest-priority subtree. + +If a budget error requires user action, report its consumption, limit, and +overage from the tool response. + +## Resolve contradictions + +Prefer the evidence source with authority over the disputed fact: project +evidence for implementation conventions, `get_code` for visible design, and +the user for product intent. Narrow the read once when the conflict may be a +scope problem. If the sources still disagree, stop rather than choose silently. + +## Worked example + +When a large frame returns a usable header-and-grid shell but omits three cards, +keep the shell as the parent layout, fetch only those card subtrees, and insert +them into the known grid. If the response contains cards but no trustworthy +grid shell, do not infer columns or spacing from `get_structure`; request a +narrower parent selection. diff --git a/agent-plugins/tempad-dev/.claude-plugin/plugin.json b/agent-plugins/tempad-dev/.claude-plugin/plugin.json deleted file mode 100644 index bde03b87..00000000 --- a/agent-plugins/tempad-dev/.claude-plugin/plugin.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "tempad-dev", - "version": "0.1.0", - "description": "Use selected Figma nodes as agent-ready evidence for project-consistent UI implementation.", - "author": { - "name": "TemPad Dev" - }, - "homepage": "https://github.com/ecomfe/tempad-dev#agent-integration", - "repository": "https://github.com/ecomfe/tempad-dev", - "license": "MIT", - "keywords": ["figma", "mcp", "skill", "agent-integration", "design-to-code", "frontend"], - "skills": "./skills/", - "mcpServers": "./.mcp.json" -} diff --git a/agent-plugins/tempad-dev/.codex-plugin/plugin.json b/agent-plugins/tempad-dev/.codex-plugin/plugin.json deleted file mode 100644 index a420ad27..00000000 --- a/agent-plugins/tempad-dev/.codex-plugin/plugin.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "tempad-dev", - "version": "0.1.1", - "description": "Use the TemPad Dev agent integration to turn selected Figma nodes into repo-ready UI code.", - "author": { - "name": "TemPad Dev" - }, - "homepage": "https://github.com/ecomfe/tempad-dev#agent-integration", - "repository": "https://github.com/ecomfe/tempad-dev", - "license": "MIT", - "keywords": ["figma", "mcp", "skill", "agent-integration", "design-to-code", "frontend"], - "skills": "./skills/", - "interface": { - "displayName": "TemPad Dev", - "shortDescription": "Use Figma selections as agent-ready design evidence.", - "longDescription": "TemPad Dev packages the figma-design-to-code agent skill with MCP server configuration so coding agents can inspect selected Figma nodes and implement project-consistent UI code.", - "developerName": "TemPad Dev", - "category": "Design", - "capabilities": ["Agent integration", "MCP", "Design-to-code", "Frontend"], - "websiteURL": "https://github.com/ecomfe/tempad-dev", - "defaultPrompt": [ - "Use TemPad Dev to implement the selected Figma node.", - "Convert this Figma selection into repo-ready UI code.", - "Inspect the selected Figma node with TemPad Dev." - ], - "brandColor": "#0098FF" - }, - "mcpServers": "./.mcp.json" -} diff --git a/agent-plugins/tempad-dev/README.md b/agent-plugins/tempad-dev/README.md deleted file mode 100644 index 3042a180..00000000 --- a/agent-plugins/tempad-dev/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# TemPad Dev Agent Plugin - -This plugin packages the TemPad Dev agent integration for Codex and Claude Code. It bundles: - -- the `figma-design-to-code` agent skill -- the TemPad Dev MCP server configuration for selected-node design evidence - -Install it for Codex: - -```bash -codex plugin marketplace add ecomfe/tempad-dev --ref main -codex plugin add tempad-dev@tempad-dev -``` - -You can also install **TemPad Dev** from the Codex app plugin directory after adding the marketplace. - -Install it for Claude Code CLI and Desktop: - -```bash -claude plugin marketplace add ecomfe/tempad-dev -claude plugin install tempad-dev@tempad-dev -``` - -The plugin appears in Claude Desktop after the marketplace is added. Both clients use the same -skill and MCP server configuration from this directory. - -Before using the integration, open TemPad Dev in Figma, then open **Preferences -> Agent integration** and enable **MCP access**. - -For app, CLI, direct MCP, and manual fallbacks, see the [complete setup guide](../../README.md#agent-integration). diff --git a/agent-plugins/tempad-dev/skills/figma-design-to-code/SKILL.md b/agent-plugins/tempad-dev/skills/figma-design-to-code/SKILL.md deleted file mode 100644 index a65e8e30..00000000 --- a/agent-plugins/tempad-dev/skills/figma-design-to-code/SKILL.md +++ /dev/null @@ -1,392 +0,0 @@ ---- -name: figma-design-to-code -description: >- - Implement or update project-consistent UI code from a Figma selection or - nodeId using TemPad Dev MCP. Use when the user wants visible Figma UI - recreated, ported, or integrated into the target project's framework, - styling system, tokens, and existing components when available. Do not use - for design critique, product invention, generic code review, or for guessing - hidden states, responsiveness, or behavior not shown in design or project - evidence. -metadata: - version: '4.3' ---- - -# TemPad Dev: Figma Design to Code - -Use this skill to turn TemPad Dev design evidence into project-consistent UI -code. - -TemPad Dev MCP must be available and able to provide trustworthy design -evidence for the current selection or provided `nodeId`. If not, stop and tell -the user to enable or reconnect TemPad Dev MCP. - -Within this skill, TemPad Dev MCP is the authoritative source of design -evidence. Treat: - -- project files and project instructions as implementation truth when available -- TemPad Dev output as design truth -- the user as the source of truth for missing product or implementation - decisions - -Do not infer project conventions before reading local evidence. - -For concerns orthogonal to Figma-to-code translation, follow project -instruction files such as `AGENTS.md` and other project instructions instead of -defining new policy in this skill. If such a concern is unspecified there and -would materially change the implementation, ask the user or stop. - -## Evidence model - -Use three evidence channels for different jobs: - -- **Project evidence**: `AGENTS.md` or equivalent project instruction files, - design-system docs, token/theme docs, component docs, existing primitives, - nearby implementations, framework/styling config, asset rules, and project - scripts -- **Design evidence**: `tempad-dev:get_code` first for markup, styles, tokens, - assets, warnings, and codegen facts; `tempad-dev:get_structure` only for - hierarchy, geometry, overlap, and retry targeting -- **User input**: missing behavioral intent, responsive intent, target file, - acceptable tradeoffs, asset or dependency decisions, or other product or - implementation decisions that cannot be recovered from project or design - evidence - -## What TemPad Dev can and cannot prove - -TemPad Dev can prove: - -- the visible structure of the current selection or a provided `nodeId` -- explicit layout, spacing, typography, color, radius, borders, shadows, - gradients, masks, filters, compositing, and other rendered visual details -- token references and values when present -- exported assets and whether an SVG may safely adopt one contextual color - channel via `themeable` -- codegen facts such as actual output language, `cssUnit`, `scale`, and - `rootFontSize` - -TemPad Dev cannot prove: - -- hidden, hover, active, loading, error, empty, disabled, or responsive states - unless separately evidenced -- non-visual product requirements such as behavior, business logic, validation, - navigation, or analytics -- project conventions, file placement, component boundaries, primitive-reuse - policy, token-mapping policy, or asset workflow beyond what the project - already establishes -- missing style truth from `get_structure`; it is only a structure aid - -## Default operating rules - -Do not output `data-hint-*` attributes. - -Never invent visual details or behavior not evidenced, including color, -typography, spacing, radius, borders, shadows, gradients, opacity, overlays, -blur, hidden states, responsive behavior, interactions, or asset semantics. - -Treat advanced or uncommon style output from TemPad Dev as intentional unless -project constraints force an adaptation. - -Only ask the user when the answer would materially change the implementation and -cannot be established from project or design evidence. Typical blockers: - -- more than one plausible target file or component boundary -- more than one plausible existing primitive or abstraction to reuse -- missing behavior, state, or responsive intent -- asset, dependency, or token workflow requiring a product decision - -If a gap is minor and non-blocking, proceed with a clearly stated inference. - -Prefer the **smallest safe change**. Do not perform unrelated refactors or add -new abstractions unless project patterns clearly call for them. - -Do not enter open-ended visual tuning loops without new evidence. If remaining -differences cannot be proved from project or design evidence, warn clearly and -stop or hand off for user validation. - -## Workflow - -### 1. Read local evidence first - -Read local evidence before implementing. Prioritize, in order: - -1. `AGENTS.md` or equivalent project instruction files -2. relevant design-system, token, and component docs -3. existing primitives/components and nearby implementations -4. config files and scripts that constrain output - -Establish at least: - -- framework/runtime and file conventions -- styling rules, including whether utilities are used and how classes are - ordered or formatted -- token/theme system and mode handling -- asset and icon pipeline -- reusable primitives/components, file placement, and import path conventions -- the narrowest established project checks for this change, if any - -Only if the project actually uses Tailwind or Tailwind-compatible tooling, -detect Tailwind version and config before changing class syntax or ordering. - -For Tailwind projects, also inspect the local theme scales relevant to exact- -value mapping, especially spacing, sizing, radius, and typography. - -If a material implementation constraint is still missing after local evidence, -ask the user instead of inferring it. - -### 2. Fetch the top-level design snapshot - -Call `tempad-dev:get_code` first. - -Use these defaults: - -- `resolveTokens: false` -- pass `nodeId` only when the user provided one; otherwise use the current - selection -- set `preferredLang` to match the project target, such as `jsx` or `vue` - -Use TemPad's default vector behavior unless the user explicitly asks for -asset-preserving vector fidelity and the current MCP version clearly supports -it. - -Use `resolveTokens: true` only when the user explicitly does not want -design-token usage. - -Treat returned `lang` as authoritative because TemPad Dev plugin or config may -override `preferredLang`. - -Record these as design facts: - -- `code` -- `lang` -- `warnings` -- `assets`, if present -- `tokens`, if present -- `codegen` - -Use `codegen.config.{cssUnit,rootFontSize,scale}` as the authoritative unit -context for exact-value mapping. - -Prefer fetching the full requested top-level selection first so parent -composition and containment are not lost. - -### 3. Resolve incomplete or conflicting evidence before implementing - -If `get_code` warns or fails, narrow uncertainty instead of guessing. - -- **`depth-cap`**: keep the returned top-level result as the source of parent - layout and composition, then use returned `data-hint-id` values to choose - narrower `get_code` follow-ups for the subtrees you still need. -- **budget overflow or shell response**: keep the returned parent shell as the - composition source of truth, then fetch omitted child subtrees separately and - fill them into that known shell. Prefer the smallest parent container that - still preserves the shared layout for the child subtrees you must assemble. - Do not treat plain string truncation as usable evidence. -- **layout, hierarchy, or overlap uncertainty**: call - `tempad-dev:get_structure`, but use it only to resolve hierarchy or geometry, - or to choose a narrower parent-shell retry target. Do not treat it as - missing style truth. -- **remaining contradiction**: if project evidence, design evidence, and - structure evidence still conflict after narrowing, stop. -- **untrustworthy parent recovery**: if you still cannot obtain a trustworthy - parent shell or parent composition via `get_code`, stop full implementation - and ask the user to narrow scope or choose the highest-priority subtree. - -Retry policy: - -- retry once only for transient transport or connectivity failures -- do not blind-retry deterministic issues such as invalid selection, hidden - node, wrong file, `depth-cap`, budget overflow, or unreadable target; change - scope or inputs first - -If TemPad MCP appears unavailable, inactive, or pointed at the wrong file, stop -and tell the user to: - -- enable MCP access in TemPad Dev Preferences > Agent integration -- keep the correct TemPad Dev / Figma tab active -- use the MCP badge in the TemPad Dev panel to activate the correct file if - multiple Figma tabs are open - -If asking the user to narrow scope because of budget overflow, report the -current consumption, limit, and overage from the error text. - -### 4. Implement code in the established project style - -Translate TemPad Dev output into the implementation's established patterns. - -- Reuse existing primitives and abstractions when they fit **without guessing**. -- Keep the established framework and styling system. Do not introduce a second - one. -- Follow established file placement and import conventions. -- If the implementation is utility-first, keep utilities and match existing - conventions. Otherwise translate generated utilities into the established - styling approach while preserving values. -- Preserve exact values. Do not coarsen arbitrary values such as `py-[4px]`, - `text-[12px]`, or `font-[600]` into named utilities unless local project - evidence proves the same rendered value; for `rem` output, use - `codegen.config.{cssUnit,rootFontSize,scale}` to convert exactly. Apply this - to spacing, sizing, - inset, gap, radius, `font-size`, `line-height`, `letter-spacing`, and - `font-weight`. -- Implement the base state only unless variants, interactions, or responsive - behavior are evidenced. -- Preserve emitted pseudo-elements. If TemPad output includes `before:`, - `after:`, `content-*`, or equivalent CSS, keep them or use an established - equivalent with the same rendered result. -- Preserve other high-fidelity details from `get_code`, including pseudo- - classes, filters, masks, blend or backdrop effects, and other non-default - visual properties, unless implementation constraints require adaptation. -- New runtime or build dependencies require user confirmation unless explicitly - waived. -- Extract new abstractions only when repetition plus established patterns - justify it. -- If multiple plausible primitives, layout abstractions, or delivery strategies - fit and evidence does not decide, ask the user instead of guessing. - -#### Assets - -Follow the established asset policy first. - -- Download bytes only from TemPad-provided `asset.url`. Never substitute public - internet assets. -- Treat assets as files to save or reference, not as text evidence to parse. -- If policy forbids storing assets, you may reference TemPad URLs, but you must - warn that the output depends on the local TemPad asset server. -- If a vector is emitted as `` in `code`, treat that - placeholder markup as the current design truth for structure, sizing, and - instance color evidence. `data-src` points at the uploaded SVG asset. Only - refactor delivery when the implementation already has another established SVG - policy. -- If TemPad falls back to inline SVG because asset upload failed, treat that - inline markup as the design truth for that vector instead of re-synthesizing - the shape from the asset metadata. -- Do not introduce a new SVG pipeline if one is already established. -- Preserve vector semantics: - - `themeable: true` means one context-driven color channel, typically via - `currentColor` - - drive that color from the established wrapper or component styling rather - than inventing a new icon API - - vectors without `themeable: true` keep their internal palette -- Use `asset.themeable` only after accounting for the project's existing SVG - delivery policy. -- Do not invent multi-color SVG props or custom CSS variables unless the - implementation already has an established icon API that requires them. - -#### Tokens - -Preserve design-token usage by default. - -Token evidence may be either direct values or mode-specific values keyed by -`Collection:Mode`. Preserve references between variables when present. - -- Prefer existing tokens only when equivalence is justified by value, - references, and semantics, not by name alone. -- If the implementation can safely carry design-token references for this - change, preserve TemPad token references until they are mapped through the - normal token workflow. -- Add new tokens only when there is already an established process for doing so - and this change is expected to use it. -- If token landing, mode selection, or mapping remains ambiguous or unsupported, - use explicit values and warn. -- Hints may be used only for reasoning about mode selection; never output hint - attributes. - -#### Semantics and accessibility - -When not already using an appropriate primitive or component: - -- use native elements where appropriate, such as `button`, `a`, `input`, and - `label` -- preserve keyboard interaction and focusability -- add accessible names when needed, such as `aria-label` or `alt` - -Assume the existing CSS reset or normalize strategy. Do not add new reset -libraries or global CSS unless there is already a defined pattern for it. - -### 5. Project checks and handoff - -Project checks are project-defined, not skill-defined. - -- Follow project instruction files such as `AGENTS.md`, local docs, and - existing project scripts for any lint, format, typecheck, build, test, - preview, screenshot, or design-comparison steps relevant to this change. -- Run the narrowest relevant checks that the project already defines and the - current host or client can actually execute. -- If those checks fail, repair obvious implementation issues when feasible and - re-run the relevant checks. -- Do not invent a default verification matrix just because this is a - Figma-to-code task. -- If no established or runnable check path exists for this change, say the - output is **unverified**. -- If shell recovery or subtree stitching was involved and no existing project - check can confirm the resulting layout, explicitly call out the remaining - visual risk. -- Do not claim visual or design-complete verification unless the project - already has a normal preview, screenshot, or design-comparison workflow. - Otherwise ask the user to visually validate the result against Figma. - -## Stop conditions - -Stop instead of shipping code when: - -- TemPad Dev MCP is unavailable, unauthorized, disconnected, inactive on the - correct file, or otherwise cannot provide trustworthy design evidence -- the target cannot be read or is not visible -- project, design, and user evidence still conflict after narrowing -- a missing user decision would materially change the implementation and cannot - be safely inferred -- required implementation constraints are missing and cannot be safely inferred - from project or design evidence -- a trustworthy parent composition cannot be recovered after `depth-cap`, shell - response, or budget overflow -- required assets cannot be retrieved or stored under the established policy -- new dependencies would be required and user confirmation has not been obtained - -## Output contract - -When shipping code, end with: - -- what was implemented and where -- evidence caveats, warnings, any stated inference, and whether shell recovery - or subtree stitching was used -- asset handling, including whether assets were stored locally or still depend - on TemPad URLs -- token handling, including mapped tokens, preserved references, or explicit - fallback values -- dependency notes, including whether any were added and whether approval was - obtained -- project-check status, including commands run if any, what passed or failed, - and what remains unverified -- any residual visual risk and the visual confirmation the user should still - perform - -If blocked, provide at most 3 concrete next items needed from the user. - -## Examples - -### Example: over-budget parent with recoverable shell - -- `get_code` returns a parent shell and a shell warning -- keep that shell as the composition source of truth -- fetch missing child subtrees with `get_code` -- insert them into the known parent structure -- do not rebuild sibling layout from guesswork -- if no trustworthy parent shell can be recovered, stop and ask for a narrower - scope instead of reconstructing parent layout from guesses -- report any remaining visual risk if project checks cannot confirm the layout - -### Example: SVG marked `themeable: true` - -- first check the established icon or SVG delivery policy -- if the implementation already uses contextual icon color, adapt the SVG to - one color channel, usually `currentColor` -- do not invent multi-color props or a custom icon API -- if more than one delivery strategy is plausible and evidence does not decide, - ask the user - -### Example: token mapping is ambiguous - -- preserve TemPad token references if the implementation can safely carry them -- map to existing tokens only when value plus semantic equivalence is justified -- if mode selection or landing zone is still unclear, use explicit values and - warn instead of inventing a mapping diff --git a/docs/engineering/codex-desktop-ipc.md b/docs/engineering/codex-desktop-ipc.md new file mode 100644 index 00000000..fc8ed685 --- /dev/null +++ b/docs/engineering/codex-desktop-ipc.md @@ -0,0 +1,949 @@ +# Codex desktop IPC: protocol and integration research + +Research date: **2026-09-15**. Inspected host: **Codex App 26.908.70816, build 9275, +macOS**. Native queue follow-ups: **2026-09-16 and 2026-09-17**. Bundled executable: +**codex-cli 0.154.0-alpha.6.2**. + +Read this report when changing TemPad's Codex conversation routing, lifecycle, +comments, Queue, Steer, or Stop. It describes the installed desktop application's +private protocol, not a stable public API. The implementation and product rules +remain in [Design tasks, client integration, and feedback](../extension/mcp-design-tasks.md). + +## Release-blocking installed-host findings + +### 2026-09-20 implementation follow-up + +Rechecked installed Codex App **26.915.31945, build 9922**, with bundled CLI +**0.155.0-alpha.9.2**. The current renderer still selects its server queue only when +enabled and the legacy queue is empty. Its `thread-follower-set-queued-follow-ups-state` +handler still calls the legacy replacement writer. A fresh targeted, read-only +`thread/queue/list` request found the conversation owner but returned `no-client-found`. +The input-box server requests use the internal renderer/app-server transport; the +native send-message tool exposes neither Queue mode nor targeted queue removal. + +The live app-server also opens `CODEX_HOME/queue_1.sqlite`. Read-only SQLite access +can observe committed `queued_items` rows by `thread_id`, including WAL changes. +This corrects the earlier implication that the server queue cannot be read at all: +its persisted local state is accessible, although the existing follower IPC does +not expose it. Both stores were empty for the inspected task, so that probe alone +does not validate nonempty payload decoding or establish its feature-gate value. + +The adapter now retains a populated legacy queue and uses native server admission +when a server database exists and the legacy queue is empty. It lazily discovers +the running desktop's unique bundled executable and manages a queue-only companion +process using the Hub's Codex home/configuration. Native list/add/delete operations +own all server writes; no queue items are copied between stores or written with SQL. +Unknown database/schema/read state fails with drafts retained. A missing database +retains the older-host path. The existing bounded Start fallback still checks both +stores before submitting. Stop follows each receipt's recorded backend, independently +of the current backend selection. + +The source adapter has passed the isolated native-owner experiment described below, +including duplicate-delivery suppression, cancellation, ordering, and idle execution. +That experiment did not establish the renderer feature gate or desktop presentation; +the installed-host observations below provide separate evidence. Single-user legacy +read/merge/set has a residual race; atomicity alone is not a release gate. + +The subsequent interactive check confirmed visible native A / Figma B / native C +coexistence, draft clearing, and execution in that order. Stop removed the Figma +submission and preserved the independent native submission, but did not interrupt +the running response. A broker regression reproduced cancellation snapshots being +sent before the explicit Stop action. The Hub consequently treats Stop as an +already-ended task and skips interruption. The broker now dispatches Stop before +publishing that snapshot, while retaining durable local cancellation. After the +extension refresh, Figma Stop interrupted the running Codex response, the user +confirmed the interruption, and the Hub logged `interrupted: true` for the exact +target turn at 2026-09-20 10:28:07 +08:00. The task remained cancelled on read-back. +A fresh task then delivered Figma Steer into the already-running response, which +acknowledged it without ending the turn first. Stopping that fresh task interrupted +the response again; after refreshing Figma, the user still saw cancellation and +native task read-back confirmed `status: cancelled`. This checks page-refresh +persistence, not every transport-failure or host-restart scenario. + +Current archive evidence: `webview/assets/app-initial-a498f911edeb.js`, SHA-256 +`34a75db63c7137eb4caecdba1f36d631c10c7912487e532fd5e9dafb175bb9be`; +`.vite/build/src-C3YaUE83.js`, SHA-256 +`14c8c23e8b8dfa874d3fb5a50d54fb28eccf55fb83232c3ab29cb7c0ef0a0472`. + +#### Read/append/set verification + +A further 2026-09-20 check regenerated the complete app-server JSON Schema with +`generate-json-schema --experimental` from the installed executable. Its +`ClientRequest` union contains exactly six `thread/queue/*` methods: `add`, `list`, +`update`, `delete`, `reorder`, and `start`. There is no server-queue `set` or +whole-list replacement request. `update` accepts a single `queuedSubmissionId` +and `input`; `reorder` accepts only submission IDs, not new message content. +Scanning all 11,164 packed JavaScript files found the same six request names and +the `changed` notification, with no additional `thread/queue/*` operation. + +The replacement call chain was traced again in the installed renderer and main +process: `thread-follower-set-queued-follow-ups-state` calls `acceptFromFollower`, +which applies a replacement through `storage.update`; `updateQueuedFollowUps` +commits `QUEUED_FOLLOW_UPS` through the global-state store. This path does not +forward a server-queue request. The complete follower handler registration also +contains no server-queue operation. A fresh connection discovered the current +conversation owner, but a targeted read-only `thread/queue/list` v0 request again +returned `no-client-found`. + +For this installed build, reading the database, appending locally, and calling +the existing follower `set` therefore cannot implement a server-queue addition: +it writes a second list to the legacy store while leaving the server submissions +intact. This limitation is independent of concurrent user input or atomicity. +The verification did not submit, replace, or delete any live queue entries. + +#### Queue-only companion process: verified feasibility + +The absence of a direct owner RPC route does not prevent every native queue +integration. A subsequent experiment used two instances of the installed bundled +CLI, a shared temporary `CODEX_HOME`, and a local mock Responses server. No real +account, desktop task, or Figma document was changed. The original process created +and executed the fixture task. The companion process only initialized and called +queue APIs plus `thread/loaded/list`; it never resumed or executed that task. + +Observed behavior in this build: + +- The companion can call `thread/queue/add` for a persisted task owned by the + original process. Its loaded-thread list remains empty. +- Both processes read the same native queue through `thread/queue/list`. +- Cross-process changes are not immediately pushed to the original process. + Observed periodic notifications were approximately ten seconds apart. An + eleven-second observation window caught both admission and deletion changes. + The renderer's existing `thread/queue/changed` handler refetches its queue. +- After an active turn completes, the original process consumes the companion's + queued message and emits the subsequent turn lifecycle. With the original + task already idle, it also discovers and executes companion admissions without + a new `thread/resume` or an externally requested `thread/queue/start`. +- A held-turn test enqueued native A, companion B, then native C. Deleting B by + its returned submission ID preserved A and C. Releasing the held turn caused + only the original process to execute A followed by C. The companion still had + no loaded threads. +- `clientUserMessageId` is not an idempotency key: adding twice with the same + value created two different submission IDs. Durable receipts and uncertain + delivery reconciliation remain necessary. +- A newly created task without a persisted rollout could not be addressed from + the companion. It became addressable after a fixture turn completed. This is + a pre-admission error, not permission to resume the task in the companion. + +This corrects the earlier blanket rejection of another app-server process. +A queue-only native writer is materially different from resuming or executing the +same task in a second process. The prototype establishes queue persistence, +cross-process observation, original-owner execution, and targeted cancellation. +It does not establish installed-desktop presentation or complete TemPad support. + +The adapter discovers the unique running bundled executable, automatically manages +one companion connection, and restricts it to queue list/add/delete operations. +The companion inherits Codex home/configuration from the Hub. It must never +resume a task, start a turn, or execute a queued item in the companion. Keep native +owner IPC for lifecycle, direct idle submissions, Steer, and guarded interruption. +Do not copy messages between stores or issue direct SQL writes. + +Receipts retain the stable TemPad feedback identity and an explicit backend +discriminator. Cancellation lists that backend, matches `clientUserMessageId`, +and deletes the matching native `queuedSubmission.id` values. Native IDs need not +be duplicated in the receipts, including when the admission response was lost. +Cancellation uses the admitting backend even after queue selection changes. Reserve before +dispatch and acknowledge native admission only after the RPC succeeds. On an +uncertain response, reconcile by client identity; absence alone does not prove +non-admission because the owner may already have consumed the item. Do not retry +an uncertain add automatically. Stop fences further admissions first, then deletes +only this task's admitted IDs and interrupts the captured owner turn independently. + +The interactive checks above establish queue visibility/coexistence, ordered +execution, targeted removal, and interruption for the tested desktop configuration. +They do not expose the renderer gate value or measure a refresh-delay bound. +Restart and uncertain-response behavior also have deterministic regression coverage. +Figma shows native admission without waiting for the desktop's periodic refresh. + +### Original installed-host findings + +The 2026-09-17 installed-plugin acceptance exposed a queue-backend conflict. After +the user queued an independent message in Codex, admitting a Figma comment through +the legacy follower endpoint made that independent message disappear from the +displayed queue. The user reported that it did not reappear after Figma Stop. +Source inspection explains the queue selection: `R1t` selects the server queue only +when enabled **and** the legacy queue is empty, while `acceptFromFollower` always +writes legacy storage. This establishes a visibility/coexistence failure, not proof +that TemPad deleted the server-side submission. The adapter does not call +`thread/queue/delete`. + +Basic Queue admission, consecutive submission, draft clearing, queued execution, +and Steer had passed immediately before this test. Those observations remain valid +for their exercised paths; they do not establish safe coexistence with independent +server-queue input. That finding blocked release until the later server-admission +implementation and interactive coexistence check described above. + +Further inspection of the same installed build found these transport boundaries: + +| Candidate access path | Evidence | Result | +| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| Existing desktop IPC owner | Complete follower handler registration in S1 `y9`; a targeted, read-only `thread/queue/list` v0 probe returned `no-client-found` | No server-queue route is exposed by the inspected follower registry. | +| Desktop's generic `mcp-request` bridge | S2 dispatches it through `handleClientRequest` from a registered Electron view; the outer IPC handler checks the trusted sender | This is an internal renderer bridge, not a generic method on the desktop coordination socket. | +| App tools native pipe | S2 `wse`, `Tse`, and `Dse` accept `tools/list`, `tools/call`, and `tools/cancel`; calls dispatch catalogued app tools | No generic app-server forwarding operation or queue tool was found. | +| Existing local app-server transport | The running bundled process uses stdio; inspection found no named Unix or TCP listener for that process | There is no discovered local endpoint for a second plugin client. | +| SSH app-server control transport | S2 `Tk` selects it only for SSH hosts; `Ck` owns the remote connection | It does not provide access to this existing local conversation. | + +No server-queue mutation was used for that investigation. These results apply to +the inspected build and running host; they do not prove that every future host will +lack an endpoint. A direct owner route would provide immediate native queue +notifications. The later isolated companion-process experiment above establishes +another route with periodic observation, without taking ownership of the task. +That process must be managed automatically by the plugin/runtime; a manually +launched helper or a changed host configuration is not the normal installation path. + +Figma Stop also failed to interrupt the active Codex response in this test, although +the design task became permanently cancelled. A deterministic regression showed +that conversation-only MCP metadata could overwrite a binding's lifecycle-derived +turn ID, leaving Stop without its interruption target. The working-tree fix retains +that identity and uses a single known active native turn when reconnecting without +turn metadata; absent or ambiguous state is not guessed. A refreshed-runtime test +still cancelled the design task without interrupting the host response. A further +deterministic gap was found: after MCP disconnection, the fallback binding retained +only the conversation, and Stop skipped IPC even when native state identified one +active turn. Capability reporting and Stop now share target resolution, capture the +target before cancellation callbacks, and record skipped, dispatched, acknowledged, +and failed interruptions. These are reproduced failure paths; the live request +metadata and interruption result were not retained, so neither is conclusive +attribution of the observed interruption failure. The subsequent broker-ordering +regression and successful refreshed-host acceptance are recorded above. + +## Findings + +1. **Desktop IPC has a native queue interface.** + `thread-follower-set-queued-follow-ups-state` persists a conversation's local + follow-up queue and acknowledges the write without waiting for execution. + TemPad now reads the committed local queue and submits a merged list through + this interface. An unavailable local store retains the bounded Hub waiting path. +2. **The native queue interface replaces a whole conversation queue.** It is not + an atomic append operation. Its request has no expected revision, and its + acknowledgement has no message ID or queue revision. Finding this method does + not establish that an independent producer can safely append alongside the + Codex composer. +3. **The host has two queue implementations.** The desktop coordinator maintains + a legacy local queue; a feature-gated app-server queue exposes separate + `thread/queue/*` operations. These are different protocols and stores. The + desktop socket does not expose arbitrary app-server methods. +4. **Native Steer is already integrated.** The owner resolves the active turn and + forwards user input through `turn/steer`. Native Queue admission, execution, + Steer acceptance, and task completion are distinct events. +5. **Targeted interruption is narrower than the complete Stop button behavior.** + `expectedTurnId` prevents interruption of a later turn. That guarded path does + not run every unguarded Stop side effect, including the goal-pause branch. + TemPad's permanent Figma write fence must remain independent. +6. **Response annotations are message context, not a general element-anchor API.** + The host serializes selected response text and comments into a user prompt. + The optional source is a message ID and text range; there is no Figma node + source in that contract. + +The working-tree integration uses best-effort read/merge/set, with conversation-level +serialization, stable message IDs, durable receipts, and targeted cancellation. +The endpoint still has no compare-and-swap protection against simultaneous composer edits. + +## Contents + +- [Evidence and limits](#evidence-and-limits) +- [Protocol boundaries](#protocol-boundaries) +- [Connection and wire protocol](#connection-and-wire-protocol) +- [Routing and versioning](#routing-and-versioning) +- [Desktop method inventory](#desktop-method-inventory) +- [Starting and steering turns](#starting-and-steering-turns) +- [Native queues](#native-queues) +- [Lifecycle subscriptions and interruption](#lifecycle-subscriptions-and-interruption) +- [Input context and annotations](#input-context-and-annotations) +- [TemPad integration assessment](#tempad-integration-assessment) +- [Reproducing and extending the research](#reproducing-and-extending-the-research) + +## Evidence and limits + +This report distinguishes four kinds of evidence: + +| Evidence | What it establishes | What it does not establish | +| ------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | +| Installed client code | Routes, payload consumers, storage operations, guards, and control flow in this build | Success against every owner, feature assignment, or operating system | +| Bundled executable schema | App-server request and response shapes generated by this binary | Exposure over the desktop IPC socket or current feature enablement | +| Live observation | Behavior exercised against the running macOS host | Unexercised mutations, Windows behavior, or a complete installed Figma workflow | +| TemPad implementation and tests | Current adapter behavior and deterministic regression coverage | Independent confirmation of private host behavior | + +The JavaScript below was read from `Contents/Resources/app.asar`. Previously +extracted files were compared byte-for-byte with the installed archive before use. +Minified function names are search aids for this build only. + +| Key | Archive entry or source | Relevant search anchors | +| --- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | +| S1 | `.vite/build/src-CCXHtyvY.js` | `IpcRouter`, `IpcClient`, `s9`, `thread-owner-discovery`, `request-version-mismatch`, `nv` | +| S2 | `.vite/build/main-DaMR-wdT.js` | `Host manager coordination`, `thread-follower-set-queued-follow-ups-state`, `acceptFromFollower` | +| S3 | `webview/assets/app-initial-4d7ea7f81c2d.js` | `wGt`, `R1t`, `F1t`, `H1t`, `Tvn`, `l4t`, `N$t`, `cKt`, `Kan`, `responseTextAnnotations` | +| S4 | `webview/assets/src-996ff3571e1f.js` | `lv`, `App input requires confirmation before legacy delivery`, `threadQueue`, `QUEUED_FOLLOW_UPS` | +| S5 | `codex_app_server_protocol.v2.schemas.json`, generated with `--experimental` from the bundled executable | `ThreadQueueAddParams`, `QueuedSubmission`, `TurnSteerParams`, `AdditionalContextKind` | + +Additional source S6: `.vite/build/window-all-closed-BxbCP6YG.js`, specifically +`JT.updateAndPersist`, `iE`, and `.codex-global-state.json`, establishes the local +commit-before-acknowledgement behavior used by the queue integration. + +SHA-256 fingerprints: + +```text +S1 a42da38cbb14b28399f1d54fcf453bffc5e9802663e7e098f187c8378f4c7a40 +S2 0765260be74e8843630d5a92e30bca574783892688e67180c119a5c58679bb61 +S3 5dcf4a29db25b086f9bd11d053eec60cf0c50bfd988494969cec452e03f19245 +S4 d85e9d112eebcc71ae35bc012bca39313111c438f360092b5375165239bbd02c +S5 7b9e7d385fffef8d428cc5490b56ce9c393bd3ed7bc7ccd730956387e723ec05 +S6 8939f42fd89899a649b8062699b386e9ff933c241155b611c3b5ec7a738673ed +``` + +### Live evidence + +A read-only probe on 2026-09-15 at 23:14 +08:00 connected to the existing Codex-home +socket using `clientType: "tempad-dev"`. It used this research conversation's +runtime thread identity, without creating a conversation or changing its queue. + +| Probe | Observed result | +| ------------------------------------------------ | ----------------------------------------------------------------- | +| `initialize`, version 0 | Success; host assigned a client ID | +| Exact `thread-owner-discovery`, version 1 | Success; returned an owner and `supportsUntrustedAppInput: true` | +| Targeted discovery with incompatible version 999 | `no-client-found`; discovery rejected the version before dispatch | + +A controlled macOS Steer probe on 2026-09-15 used TemPad's adapter: +the busy `start-turn` rejection was followed by `steer-turn`, the diagnostic user +message arrived, and the durable receipt recorded `delivered` with a turn ID. +That establishes direct macOS IPC delivery, not a new end-to-end Figma UI test. + +On 2026-09-16, the working-tree native queue adapter admitted a deliberately paused +diagnostic into this conversation, verified its committed composer context, and removed +only that message through IPC. The queue was empty before and after the probe. Admission, +including the original-conversation snapshot, took 782.96 ms in this single observation. +The probe did not execute the diagnostic or measure the read-to-write conflict window. +Unit tests cover preservation of existing messages, multiple batches, uncertain admission, +restart recovery, and targeted removal. Automatic queued execution, simultaneous native +composer edits, and the full installed-plugin/Figma UI flow still need live verification. +Windows and Linux observations remain limited to source and deterministic tests. + +## Protocol boundaries + +```mermaid +flowchart LR + F[Figma extension] --> H[TemPad Hub] + H -->|length-prefixed JSON| R[Desktop IPC router] + R -->|owner discovery and follower requests| O[Conversation owner] + O --> Q[Desktop turn coordinator] + O -->|app-server RPC| A[Codex app-server] + Q --> L[Local follow-up storage] + Q -->|when enabled| A +``` + +Three surfaces must not be conflated: + +| Surface | Wire/API shape | Role | +| --------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------- | +| Desktop coordination socket | Four-byte length prefix and JSON envelopes with `type`, `requestId`, `version` | Routes existing desktop clients and conversation owners | +| Codex app-server | JSON-RPC-shaped requests using `id`, `method`, and `params`; methods such as `turn/start` | Executes and stores Codex threads and turns | +| Desktop view/service bridge | Internal renderer service calls, including global-state and queue-send locks | Coordinates the app's own UI and native services | + +Official [Codex App Server documentation](https://learn.chatgpt.com/docs/app-server#protocol) +describes the second surface: bidirectional JSON-RPC without the `jsonrpc` field, +using JSONL over stdio or WebSocket transports. That documentation does +not define the desktop follower methods. Even an app-server Unix control socket +uses a different handshake from the desktop coordination socket. + +Names such as `get-global-state`, `queued-follow-up-send-lock-acquire`, and +`thread/queue/add` appearing in the desktop bundle do not make them callable as +desktop socket methods. Trace each call to its transport and registered handler. +An app tools pipe advertised by `CODEX_APP_TOOLS_PIPE_PATH` is also not the socket +described here. + +## Connection and wire protocol + +Evidence: S1; TemPad's [codex-ipc.ts](../../packages/mcp-server/src/agent-clients/codex-ipc.ts). + +### Endpoints and ownership + +| Platform | Host endpoint | Observed handling | +| -------------------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| macOS / Unix | `$CODEX_HOME/ipc/ipc.sock`, normally `~/.codex/ipc/ipc.sock` | Host creates/validates a current-user directory, sets directory mode `0700`, and secures its socket with mode `0600` | +| Legacy Unix fallback | `/codex-ipc/ipc-.sock`; UID 0 uses `ipc.sock` | Host considers an existing socket with matching UID and a suitably protected parent | +| Windows | `\\.\pipe\codex-ipc` | Fixed local named pipe; Unix inode/UID checks do not apply | + +The host can create the router when necessary. TemPad deliberately connects only +to an existing endpoint: starting a replacement router does not create a valid +conversation owner and would obscure a missing host. + +TemPad validates Unix socket and parent ownership and rejects a group/world-writable +parent. On Windows it accepts only the fixed local pipe, leaving connection access +to the OS. These controls establish the local OS-user boundary. `clientType` is a +registration label, not an authentication token or a grant of product-level authority. + +### Framing + +Each frame is: + +```text +uint32 little-endian UTF-8 byte length +JSON payload of exactly that byte length +``` + +The host rejects zero-length frames and payloads above **268,435,456 bytes +(256 MiB)**. Reads may split either header or payload; one socket read may contain +multiple frames. The bound is a transport maximum, not an appropriate comment-size +limit. TemPad applies much smaller feedback limits before encoding. + +### Envelopes + +The following illustrates the desktop wire format. IDs are examples, not reusable +identities: + +```json +{ + "type": "request", + "requestId": "request-uuid", + "sourceClientId": "initializing-client", + "version": 0, + "method": "initialize", + "params": { "clientType": "tempad-dev" }, + "timeoutMs": 2000 +} +``` + +A successful initialization returns `type: "response"`, the same `requestId`, +`resultType: "success"`, `method: "initialize"`, `handledByClientId`, and +`result: { clientId }`. Use the assigned ID on subsequent requests. Reconnection +creates a new client identity; an old owner ID is not a durable address. + +| Envelope | Important fields and behavior | +| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| `request` | `requestId`, `sourceClientId`, `method`, `version`, `params`; optional `targetClientId`, top-level `hostId`, `timeoutMs` | +| `response` | Correlates by `requestId`; success carries `method`, `handledByClientId`, `result`; failure carries `resultType: "error"` and `error` | +| `broadcast` | `sourceClientId`, `method`, `version`, `params`; optional `targetClientIds`; no acknowledgement | +| `client-discovery-request` | A separate `requestId` and the original `request`; asks a client whether it can handle that request | +| `client-discovery-response` | Discovery `requestId` and `response: { canHandle: boolean }` | + +TemPad answers discovery requests with `canHandle: false`: it is a consumer, not +a desktop conversation owner. Leaving these messages unanswered can delay other +clients' discovery. + +Broadcasts go to other connected clients, optionally restricted by recipient IDs. +The router sets their source to the registered sender. They are not replayable +event logs; a newly connected consumer cannot infer current state from silence. + +## Routing and versioning + +Evidence: S1's `findClientForRequest`, `handleClientDiscoveryRequest`, `nv`, `iv`, +and `av`; S2/S3's owner assertions and follower dispatcher. + +1. Register with `initialize`. +2. Discover the exact owner using `thread-owner-discovery` v1 and + `{ hostId: "local", conversationId }`. +3. Retain `handledByClientId`, and verify the capabilities required by the intended + operation. TemPad currently requires `supportsUntrustedAppInput: true`. +4. Target subsequent follower requests at that owner. The router still asks the + selected client whether it can handle each targeted request. +5. Validate the response method, owner, and operation-specific acknowledgement. + Rediscover after owner loss rather than selecting a focused or similarly named task. + +Without a target, the router asks other clients and selects a successful handler. +Its discovery timeout is **10 seconds**. Forwarded requests have a separate timeout, +using the supplied `timeoutMs` or the router's default. A caller's shorter timer +can expire while host discovery is still running. + +The version registry is per method, not a single negotiated protocol version. +Unlisted methods default to version 0; this does not mean they have a handler. +For `thread-follower-*` requests, a non-null **top-level** `hostId` adds one to the +base version. `params.hostId` used by discovery and broadcasts is a different field. +TemPad's local follower calls omit the top-level host ID and use base versions. + +The interrupt method also accepts a legacy local v3 path. The native client's +version selector uses v3 when `expectedTurnId` is absent and v4 for the guarded +shape. Do not infer that a lower version preserves the newer interruption guarantee. + +### Failure meanings + +| Failure | Interpretation | +| ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| `no-client-found` | No client accepted discovery; can mean missing owner, wrong host, incompatible version, or unavailable handler | +| `request-version-mismatch` | A dispatched request failed the receiving client's version check | +| `no-handler-for-request` | The receiving client has no handler for the dispatched method | +| `request-timeout`, disconnect, or caller timeout | A mutating request may already have run; absence of acknowledgement is not rollback | +| Wrong response method, wrong owner, or malformed result | Delivery is not confirmed; do not treat socket success as operation success | + +The read-only probe's deliberately wrong discovery version returned +`no-client-found`, not `request-version-mismatch`, because rejection happened +during discovery. TemPad's error handling and capability reporting should retain +that ambiguity rather than always presenting it as an unloaded conversation. + +## Desktop method inventory + +This is the complete **thread-follower handler set** registered in S1 and consumed +by S2/S3 for this build. Versions below are the base/local versions. Results are +the contents of the outer IPC response's `result`, after the service bridge has +removed its internal method wrapper. + +### Requests + +| Method | Version | Parameters / result | Meaning | +| -------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| `initialize` | 0 | `{ clientType }` → `{ clientId }` | Router registration, handled separately from thread requests | +| `thread-owner-discovery` | 1 | `{ hostId, conversationId }` → `{ supportsUntrustedAppInput: true }`; owner in envelope | Discover an existing owner | +| `thread-follower-start-turn` | 2 | `{ conversationId, turnStart: { request, context? } }` → `{ result: { turn } }` | Submit a turn through its owner | +| `thread-follower-steer-turn` | 1 | Conversation, `input`, `restoreMessage`, optional message ID, context, attachments, service tier, tool output → `{ result: { turnId } }` | Steer the active turn; tool-output behavior differs | +| `thread-follower-interrupt-turn` | 4 | Conversation, `mode`, `expectedTurnId` → `{ ok, interruptedTurnId, goalPauseError? }` | Targeted interruption | +| `thread-follower-set-queued-follow-ups-state` | 1 | `{ conversationId, state: { [conversationId]: messages } }` → `{ ok: true }` | Replace the local follow-up queue | +| `thread-follower-load-complete-history` | 1 | `{ conversationId }` → `{ revision }` | Hydrate history and establish a stream revision; bridge permits a longer timeout | +| `thread-follower-compact-thread` | 1 | `{ conversationId }` → `{ ok: true }` | Initiate owner-side compaction | +| `thread-follower-edit-last-user-turn` | 2 | Conversation plus edit parameters → `{ ok: true }` | Edit/revert through the owner; not ordinary feedback | +| `thread-follower-update-thread-settings` | 2 | Conversation, `threadSettings`, optional `activeTurnId`, `condition` → `{ applied }` | Update next-turn settings or active-turn permissions | +| `thread-follower-command-approval-decision` | 1 | Conversation, `requestId`, `decision` → `{ ok: true }` | Answer an existing command approval | +| `thread-follower-file-approval-decision` | 1 | Conversation, `requestId`, `decision` → `{ ok: true }` | Answer an existing file-change approval | +| `thread-follower-permissions-request-approval-response` | 1 | Conversation, `requestId`, `response` → `{ ok: true }` | Answer an existing permissions request | +| `thread-follower-submit-user-input` | 1 | Conversation, `requestId`, `response` → `{ ok: true }` | Answer an existing user-input request | +| `thread-follower-submit-mcp-server-elicitation-response` | 1 | Conversation, `requestId`, `response` → `{ ok: true }` | Answer an existing MCP elicitation | + +An `{ ok: true }` here has method-specific meaning. For example, accepting an +approval response or initiating compaction does not establish completion of the +underlying work. This inventory is not authorization for TemPad to answer host +approvals or change model, permission, or task settings. + +### Broadcasts + +| Method | Version | Meaning / payload highlights | +| ------------------------------------------ | ------- | ----------------------------------------------------------------------------------- | +| `thread-stream-following-changed` | 1 | `{ hostId, conversationId, following }`; subscribe/unsubscribe to an owner's stream | +| `thread-stream-following-status-requested` | 1 | Owner asks followers to announce whether they still follow | +| `thread-stream-state-changed` | 11 | `{ hostId, conversationId, change }`; full snapshot or revisioned patches | +| `thread-queued-followups-changed` | 2 | `{ hostId, conversationId, messages }`; local queue state changed | +| `thread-read-state-changed` | 3 | Synchronizes read state, with host context | +| `thread-archived` | 2 | Archive coordination | +| `thread-unarchived` | 1 | Unarchive coordination | +| `client-status-changed` | 0 | Client ID, client type, and connected/disconnected state | +| `ipc-connection-reset` | 1 | Invalidate connection-dependent state and re-establish coordination | + +S1 also exposes an `ide-context` request helper (v0, `{ workspaceRoot }` → +`{ ideContext }`) and forwarding for `query-cache-invalidate`, +`automation-capability-event`, `automation-run-triggered-event`, and +`app-connect-oauth-callback-received` broadcasts (v0). These are peripheral to +TemPad's design-task path; their full producer payloads and availability were not +validated. They are not a generic app command-execution interface. + +## Starting and steering turns + +Evidence: S3's start-turn handler, busy guard, `N$t`, `L$t`, and `I$t`; +[codex-feedback.ts](../../packages/mcp-server/src/agent-clients/codex-feedback.ts). + +### Start + +The desktop request wraps the app-server request in `turnStart`: + +```ts +{ + conversationId, + turnStart: { + request: { + threadId: conversationId, + clientUserMessageId, + input: [{ type: 'text', text, text_elements: [] }] + }, + context: { responseItems } + } +} +``` + +The owner prepares settings and context, requires an existing streaming +conversation, injects any response items, and submits the turn. If nonempty +`context.responseItems` are present while the conversation is active, it rejects +before creating the turn with: + +```text +App context must wait until the current turn finishes +``` + +This guard lets TemPad's Hub waiting fallback retry a known busy rejection. It is +not a native queue acknowledgement. Removing `responseItems` just to avoid the +guard does not establish Queue semantics. + +TemPad's body is user input. A separate paired `untrusted_input` call/output carries +the design task ID, so a conversation that has owned several Figma tasks can +identify the right one. Model, approval, and sandbox overrides are not supplied. +Successful delivery requires `response.result.result.turn.id` and the expected owner. + +### Steer + +The plain-user-input shape is: + +```ts +{ + conversationId, + clientUserMessageId, + input: [{ type: 'text', text, text_elements: [] }], + restoreMessage: { text, context: {} }, + additionalContext: { + 'tempad-design-task': { kind: 'untrusted', value: taskContext } + } +} +``` + +The owner checks for an active turn, adds a pending steering message to its view, +waits for an actual turn ID if necessary, and submits `turn/steer` with +`expectedTurnId`. Its implementation can reconcile a backend-reported active-turn +ID mismatch and retry against that ID. Therefore this follower method means +“steer the owner's active turn”; it does not expose TemPad's own expected-turn +precondition in its request shape. + +Successful desktop acknowledgement contains `response.result.result.turnId`. +The host distinguishes outcome-unknown errors from known rejection and tracks +unconfirmed submissions. TemPad retains its own receipt as well and does not +replay uncertain delivery automatically. + +Supplying `toolOutput` changes the owner helper's backend path to `turn/start` +with empty user input and standalone tool output. It is not interchangeable with +user-authored comments. `restoreMessage` is restoration/display context, not a +substitute for `input`. + +The official [Steer contract](https://learn.chatgpt.com/docs/app-server#steer-an-active-turn) +requires an active turn and its expected ID. The desktop owner performs that +translation; TemPad should not bypass it by opening a second app-server process. + +## Native queues + +### Local desktop queue admission + +Evidence: S1 registration; S2/S3 follower dispatcher; S3 `R1t.acceptFromFollower`, +its private storage writer, and `F1t`; S4 `lv`. + +The request is a state update, not a message append: + +```ts +{ + conversationId, + state: { + [conversationId]: completeReplacementMessageList + } +} +``` + +The dispatcher passes only `state[conversationId]`, defaulting a missing entry to +`[]`. **Omitting that entry requests an empty queue.** Other conversation keys in +the submitted object are not a multi-conversation update through this handler. + +The coordinator: + +1. Validates the proposed message list and updates its pending in-memory state. +2. Serializes storage writes and checks that it is still the conversation owner. +3. Replaces that conversation's entry in local follow-up storage; an empty list + removes the entry. +4. Initiates a queue-state broadcast and wakes the execution coordinator. +5. Resolves the request with `{ ok: true }` after the storage operation settles. + +It does not await message execution or acknowledgement by every broadcast +recipient. Broadcast failure is logged separately. There is no queue revision, +compare-and-swap token, or per-message admission result in this request/response. + +### Message representation and provenance + +The legacy queue stores composer-shaped objects. These are distinct from the +`UserInput[]` passed directly to `start-turn` and `steer-turn`. The following is +a structural example from native producers and consumers. The adapter's variant +omits `workspaceRoots` so the owner derives its existing roots and permissions, +and carries the task ID as untrusted `writingBlockAdditionalContext`: + +```ts +{ + id: messageId, + text: displayText, + context: { + prompt: userPrompt, + addedFiles: [], + fileAttachments: [], + imageAttachments: [], + commentAttachments: [], + ideContext: null, + workspaceRoots: [cwd] + }, + cwd, + createdAt, + // Optional native state includes submissionOptions, pausedReason, + // response annotations inside context, and writingBlockAdditionalContext. +} +``` + +The preparation code renders `context.prompt` and context attachments into model +input. Top-level `text` alone is insufficient. Several attachment collections are +read as arrays without defaults; `{ text, context: {} }`, used by the verified +Steer path, is not a complete legacy queued message. + +The legacy writer rejects a batch if any message has either: + +- `context.untrustedAppMessage != null`; or +- a `context.mcpAppModelContextAttachments` entry with `untrusted: true`. + +The error is `App input requires confirmation before legacy delivery`. Automatic +execution also checks this condition. Do not remove provenance flags simply to +make the old queue accept an App payload. User-authored design instructions and +captured Figma metadata have different roles; a native queue integration must +preserve that distinction through the host's supported preparation path. + +### Concurrent writes and recovery + +Owner-side serialization and the app's `codex-queued-follow-up-state` storage lock +do not turn an external replacement list into an atomic append. A stale list can +overwrite a composer edit even when both writes individually succeed. + +The registered follower API has no corresponding queue-list request or +revision-checked append request. `thread-queued-followups-changed` carries a list, +but no queue revision or initial-snapshot handshake. A conversation stream +snapshot should not be assumed to provide the coordinator's separate queue store. +Internal `readState` and global-state services exist, but are not thereby exposed +on this socket. + +TemPad reads `queued-follow-ups` from the host's `.codex-global-state.json` without +modifying that file. S2 uses `updateAndPersist`; S6 writes and commits the complete +file before updating the in-memory store and resolving the native write. Each +admission reads again after durable receipt preparation, immediately before dispatch. +A missing or unreadable store uses the existing Hub waiting path; incompatible queue +contents fail without replacement. This is a best-effort integration, not atomic append. +Even obtaining an initial list is insufficient to exclude intervening composer edits. Never submit only TemPad's new +batch as the replacement list when other queued messages may exist. Likewise, +retrying an acknowledged or uncertain replacement can restore messages that the +host has already consumed or that the user has removed. + +### Execution and interruption + +The local coordinator automatically processes the queue when client readiness, +ownership, resume state, and turn state allow it. Pending writes, local deferrals, +paused messages, and an active turn can delay execution. It acquires a native +per-message send lock, prepares the message, and removes it after a successful +send. A failure can retain the message with a `pausedReason`. + +An interrupted turn marks legacy queued messages as paused; the coordinator has +separate methods for resuming interrupted messages, removing, editing, reordering, +and sending a queued message immediately. Those internal methods do not each have +a dedicated follower IPC route in the inspected registry. Native composer UI +capability is therefore broader than the exposed socket method inventory. + +Keep these events separate: + +| Event | Meaning | +| ---------------------------------- | ------------------------------------------------------------------------------------------------ | +| TemPad accepts a batch | TemPad owns a pending delivery attempt | +| Native queue storage acknowledges | Host owns the stored queue state | +| Queue item disappears | Could have been sent, edited, deleted, or cleared; disappearance alone is not proof of execution | +| Start/Steer acknowledges a turn ID | Host accepted input into a turn | +| Turn completes | That turn ended; the design task or review may remain open | + +### App-server queue + +Evidence: S3 `Tvn` and the coordinator's server-queue selection; S4's `threadQueue` +compatibility entry; S5's generated schema. + +The desktop can use app-server queue storage for non-ephemeral conversations when +the `2120612410` feature gate and `threadQueue` version capability are satisfied. +The compatibility table starts that capability at `0.148.0-alpha.14`. A capable +binary version alone does not establish the feature gate's value. + +| App-server method | Required parameters | Response | +| ---------------------- | ------------------------------------------ | ----------------------- | +| `thread/queue/add` | `threadId`, `clientUserMessageId`, `input` | `{ queuedSubmission }` | +| `thread/queue/list` | `threadId`; optional `cursor`, `limit` | `{ data, nextCursor? }` | +| `thread/queue/update` | `threadId`, `queuedSubmissionId`, `input` | `{ queuedSubmission }` | +| `thread/queue/delete` | `threadId`, `queuedSubmissionId` | `{ deleted }` | +| `thread/queue/reorder` | `threadId`, `queuedSubmissionIds` | Empty result object | +| `thread/queue/start` | `threadId`; optional `queuedSubmissionId` | `{ turn }` | + +`QueuedSubmission` contains `id`, `clientUserMessageId`, and `input`. The +`thread/queue/changed` notification contains `threadId`; the desktop refetches +the list. These schemas were generated from the installed binary with experimental +fields enabled; no app-server queue mutations were performed. + +The local coordinator selects the server queue only when it is enabled **and the +legacy queue is empty**. Adding a legacy entry can change which queue is selected. +The follower state-replacement handler still writes the legacy store; it is not +a wrapper around `thread/queue/add`. Coexistence and ordering across the two +stores require explicit verification. + +The app-server API's atomic add and targeted delete are a better semantic fit for +multiple producers, but no generic app-server forwarding method was found in the +desktop follower registry. Whether TemPad can reach these operations through an +existing, supported owner connection remains unresolved. Starting another server +or editing Codex's global-state file would not satisfy the normal installation path. + +## Lifecycle subscriptions and interruption + +Evidence: S3 `Kan`, the stream coordinator, `interruptConversationSelf`, and +`cKt`; [codex-lifecycle.ts](../../packages/mcp-server/src/agent-clients/codex-lifecycle.ts) +and [codex-turn-state.ts](../../packages/mcp-server/src/agent-clients/codex-turn-state.ts). + +### Stream state + +Subscribe by broadcasting `thread-stream-following-changed` v1 to the exact owner +with `{ hostId: "local", conversationId, following: true }`. Install the receive +handler first. The owner responds with `thread-stream-state-changed` v11: + +```ts +// params.change +{ type: 'snapshot', revision, conversationState } +{ type: 'patches', baseRevision, revision, patches, acceptedTextChanges? } +``` + +The initial snapshot contains conversation state, potentially including transcript +content. Subsequent patches use native paths and values. TemPad projects only turn +IDs and statuses from legacy or canonical turn history; it does not persist the +transcript. Apply a patch batch atomically. A revision gap, unsupported lifecycle +path, changed owner, or reconnect requires a new snapshot before trusting controls. + +Respond to `thread-stream-following-status-requested` by re-announcing the +subscription. Unsubscribe on teardown. Queue broadcasts and stream revisions are +separate mechanisms; a valid turn-state revision does not validate a queue list. + +### Targeted Stop + +TemPad sends: + +```ts +{ + conversationId, + mode: 'user-stop', + expectedTurnId +} +``` + +The owner returns a successful no-op with `interruptedTurnId: null` when the +expected turn is no longer the active in-progress turn. It does not chase a new +turn. A matching interruption returns the interrupted ID. Validate the owner, +`ok`, and ID independently of the outer transport response. + +The native unguarded Stop path can pause a goal, update other state, clean up +background work, and interrupt descendants. With `expectedTurnId`, the owner +returns through its guarded interrupt helper before the goal-pause branch. +Matching targeted interruption can still trigger descendant cleanup. Do not +equate an IPC interrupt acknowledgement with stopping every future source of +work or clearing a native queue. + +TemPad cancels the design task and fences Figma writes before requesting host +interruption. An IPC failure cannot remove that fence. Cancelling a Hub promise +does not remove messages already owned by Codex. TemPad therefore removes this task's +native queue IDs and reconciles failed or late removals while preserving unrelated +user messages. The task fence remains necessary even if cancellation +races with execution. + +## Input context and annotations + +Evidence: S3 `g2t`, `Sv`, `i4t`, `l4t`, `responseTextAnnotations`, and the annotation +schema; S4's untrusted-input predicate; S5's context-kind enum. + +| Data | Current role | Integration consequence | +| ---------------------------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------- | +| User feedback text | `input` for direct Start/Steer; `context.prompt` for legacy queued messages | Preserve the user's wording and instruction role | +| Captured Figma names and IDs | Target context | Keep them distinguishable from user instructions | +| Design task ID | Separate untrusted context in TemPad's Start/Steer adapters | Native queue preparation must retain exact task binding too | +| `responseItems` | Raw paired model-context items on Start | Nonempty items trigger the busy-turn guard | +| `additionalContext` | Named values with a context kind; binary enum includes `untrusted` and `application` | Do not promote external context to application authority | +| `responseTextAnnotations` | Native response-selection context serialized into the prompt | Not an IPC method or Figma node attachment | + +Native annotation serialization has this shape: + +```text +# Response annotations: + + +[{"text":"Selected response text","annotation":"User comment","source":{"messageId":"message-id","startOffset":0,"endOffset":22}}] + +``` + +`text` is required; the comment and source are optional in the inspected native +schema. A source range requires a message ID, nonnegative integer offsets, and +`endOffset > startOffset`. The serialization also adds instructions to address +annotations and emit `:codex-annotation{index="N"}` in the response. + +An absent source permits text-only annotation context; it does not provide a +native Figma anchor. Reusing the envelope for element comments would also import +its reply protocol. This is a formatting decision separate from choosing Queue +or Steer transport. + +The design task already binds the Figma file. IPC itself does not require a Figma +URL in each comment. Node/page identity is needed for exact in-file targeting; +whether a clickable URL helps the user is a presentation choice, not a routing +requirement. + +## TemPad integration assessment + +The following describes the working-tree adapter inspected for this report. +It is not a claim about a published release. + +| Capability | Current TemPad behavior | Remaining distinction | +| ------------ | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| Identity | Host-supplied MCP metadata, then exact owner discovery | Focused windows never establish identity | +| Lifecycle | Follows v11 snapshots/patches with a minimal turn projection | Full initial snapshot still transfers | +| Queue | Native server add, or legacy snapshot/merge/replacement when selected | Tested desktop coexistence passes; legacy composer races remain possible | +| Steer | Idle Start path; busy owner uses native Steer | Promotion of an already admitted batch is unavailable | +| Stop | Permanent task fence, expected-turn interruption, targeted native queue removal | A consumed message cannot be recalled; failed removal retries after reconnection | +| Windows | Fixed local pipe, OS URL handler, deterministic tests | Native Windows host verification is outstanding | +| Reconnection | Durable identities and reconciliation; never restore absent uncertain messages | Absence is not evidence of execution | + +A final `delivered` receipt means native input admission, either into the local queue +or into a turn. It does not mean execution or completion. The UI clears only submitted +revisions and permits the next batch after native admission. A final receipt arriving +before the initial Hub response unlocks the editor immediately; the late response cannot +reset a newer batch's submission state. Initial Hub acceptance alone keeps the batch pending. + +Legacy admission keeps comments in `context.prompt` and the task ID in untrusted +`writingBlockAdditionalContext`. Server admission sends formatted feedback only and +retains task attribution in durable receipts. Neither path strips provenance flags +from existing messages or changes the owner's permission settings. + +Native admission, automatic execution, and removal have been exercised against the +inspected macOS host. Installed-plugin acceptance exposed server-queue coexistence +and interruption failures; the fixes and successful interactive rechecks are recorded +above. These observations do not make the legacy replacement endpoint atomic or +establish support for every host version and platform. + +## Reproducing and extending the research + +Start from the installed host, not from a guessed method name or an old cached +bundle. Record the app version/build and binary version separately. The app +archive, generated schemas, and active feature assignments can change independently. + +For a new build: + +1. Read its application metadata and archive index. Locate the actual main, + shared protocol, renderer, and renderer-shared chunks by following imports. + Extract only the relevant entries into temporary storage and record hashes. +2. Enumerate the socket method-version registry **and** handler registrations. + Follow the handler through the owner/coordinator to storage or app-server + calls. A method string found in a bundle is not proof of socket exposure. +3. Inspect payload producers as well as consumers, including optional context, + restoration data, feature/version gates, acknowledgements, and errors. +4. Generate the bundled app-server schema into a temporary directory when + checking backend contracts: + + ```sh + /path/to/Codex.app/Contents/Resources/codex --version + /path/to/Codex.app/Contents/Resources/codex app-server generate-json-schema \ + --experimental --out /tmp/codex-ipc-research-schema + ``` + + Schema generation does not launch a conversation or establish desktop IPC + access. Do not replace the running owner with a separately launched server. + +5. Use read-only handshake/discovery probes against the exact research task to + validate routing. Record method, version, outcome, and capabilities; omit + transcript bodies, unrelated conversation IDs, and local credentials. +6. For mutation verification, use an explicitly scoped test conversation and + inspect both host state and receipts. Queue research must include an existing + unrelated queued message, concurrent edits, reconnect after uncertain + admission, cancellation, and each supported queue backend. A happy-path + acknowledgement alone does not validate the integration. + +When the next question requires an actual Figma authoring run or an installed +plugin workflow, use the existing +[agent authoring evolution runbook](../testing/agent-authoring-evolution.md). +This report does not introduce a parallel runtime-refresh or candidate-promotion +process. + +### Source map in this repository + +- [IPC transport and discovery](../../packages/mcp-server/src/agent-clients/codex-ipc.ts) +- [Feedback delivery and receipts](../../packages/mcp-server/src/agent-clients/codex-feedback.ts) +- [Lifecycle subscription and interruption](../../packages/mcp-server/src/agent-clients/codex-lifecycle.ts) +- [Turn-state projection](../../packages/mcp-server/src/agent-clients/codex-turn-state.ts) +- [Per-request host identity](../../packages/mcp-server/src/agent-clients/identity.ts) +- [Client actions and task cancellation](../../packages/mcp-server/src/agent-clients/registry.ts) +- [Comment UI and pending-delivery state](../../packages/extension/components/DesignTaskFeedback.vue) +- [IPC/feedback tests](../../packages/mcp-server/tests/codex-feedback.test.ts), + [lifecycle tests](../../packages/mcp-server/tests/codex-lifecycle.test.ts), and + [platform tests](../../packages/mcp-server/tests/codex-platform.test.ts) diff --git a/docs/engineering/optimization-audit.md b/docs/engineering/optimization-audit.md index 714c7193..5bfdc66a 100644 --- a/docs/engineering/optimization-audit.md +++ b/docs/engineering/optimization-audit.md @@ -78,9 +78,11 @@ satisfy, so those package commands failed despite high aggregate coverage. active route exists. Mandatory pairing would add setup and recovery burden to every MCP client, so it is not part of the current hardening path. If a higher-threat deployment appears later, pairing must be opt-in and version-negotiated rather than changing the default flow. -- **Pending compatible migration: asset hash length.** The current 8-hex content identifier is useful - for lookup, not authorization. Negotiate longer new-write ids, dual-read during TTL cleanup, then - remove short writes. +- **Completed: full asset content identity.** Extension, Hub, store paths, browser bridge, and shared + contracts use one complete lowercase SHA-256 digest and verify it after upload and download. + Internal callers migrated together; the Hub retains download-only support for legacy 8-character + identifiers until cached assets expire. The random capability URL—not the digest—continues to + authorize loopback access. - **Completed: Hub admission and activation extraction.** Port selection and handshake admission now live in a testable WebSocket server module with real loopback integration tests for accepted and rejected Origins/paths, connection limits, occupied-port fallback, and exhaustion. Registration, diff --git a/docs/engineering/write-to-figma-optimization.md b/docs/engineering/write-to-figma-optimization.md new file mode 100644 index 00000000..713ecc15 --- /dev/null +++ b/docs/engineering/write-to-figma-optimization.md @@ -0,0 +1,392 @@ +# Write-to-Figma structural optimization + +Status: global-to-detail review and accepted behavior-preserving changes verified, 2026-09-17. + +## Scope and baseline + +This pass covers `feat/write-to-figma` against its merge base with `origin/main` +(`29f1789fe7ec57e4492395028447a743ca087d6f`), applied to the current checkout at +`a71381c3c3e44bc1c116053041d201c5bd4b2023`. The earlier branch pass reviewed the +complete changed-file inventory and made local simplifications in ten source files. +Those edits and the fifteen existing release/documentation changes are retained. +This report addresses responsibility boundaries and repeated execution policy beyond +that first pass; file counts alone do not establish optimization completeness. + +The task is behavior-preserving simplification. No public API, wire format, native +host protocol, connection setup, cancellation policy, resource deletion policy, or +visual authoring behavior is being redesigned. No dependency or commit is required. + +## Global-to-detail progression + +The review follows architecture and execution paths, then module internals and +implementation details. Finishing a selected batch is not the completion criterion; +each domain needs an implementation decision and evidence for retained boundaries. + +| Stage | Required analysis and output | Current status | +| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------- | +| 1. Global ownership and flows | Map entry points, source ownership, dependency direction, state lifetimes, and the complete request/feedback/asset paths. Identify authority duplicated across layers versus independent enforcement. | Complete; ownership map below | +| 2. Cross-module consolidation | Review task/operation lifecycle, request routing, resource discovery/resolution and Canvas normalization boundaries with all consumers. Record each supported consolidation and why retained boundaries differ. | Complete; consolidation decisions below | +| 3. Module internals | Walk the implementation of each affected domain: persistent state, transitions, async ordering, caches, error paths, tree traversal, normalization, mutation and verification. Remove redundant concepts and unnecessary work. | Complete; internal review below | +| 4. Implementation details | Review internal APIs and callers, duplicate expressions/tables, stale compatibility paths, naming and test organization. Migrate callers instead of retaining unnecessary internal shims. | Complete; callers and coverage inventories migrated | +| 5. Integrated verification | Review the complete accumulated change against the original branch objective, run required checks and account for every identified optimization or justified retention. | Complete | + +Each stage must produce evidence for the next. A list of filenames, a passing test +suite, or splitting a large file is not by itself evidence that a domain has been +fully simplified. Existing behavior remains the baseline; unresolved correctness +questions are recorded separately from behavior-preserving refactors. + +## Stage 1: authority and execution map + +### Tool execution + +`cli.ts` connects the MCP transport to `hub.ts`. `AgentClients.owner` derives the +conversation owner from request metadata; `resolveDesignTarget` selects the exact +extension/session; `DesignTasks` checks the epoch, file lease and operation slot. +The broker (`service-worker.ts`) verifies the gateway and registered page route; +`bridge/content.ts` carries the request into `composables/mcp.ts`; +`PageDesignTasks.enter` enforces the final local fence before `runtime.ts` invokes +the tool. The response traverses those same registered channels, and +`extension-socket.ts` settles the matching request and operation. + +These are three different responsibilities: Hub authority, registered transport +routing, and final execution authorization. They cannot be collapsed into one +shared mutable state machine. In particular, a missing socket does not establish +that the page finished its native transaction. + +### Canvas and read pipelines + +Canvas follows public-schema validation → catalog/native reference resolution → +local theme preparation → markup compilation or native-only input preparation → +scoped native preflight → mutation → structural verification within an undo +boundary. The two input forms ultimately produce `CanvasNodeSpec`, but currently +retain separate normalization paths in `markup.ts` and `reconcile.ts`: their +defaulting and preservation rules differ, as established in stage 2. + +Reading follows exact-node/page selection → visible-tree snapshot and budget +preflight → variables/plugin/asset planning → collection → style preparation → +rendering → token processing and optional resolved rerender → bounded result. +The read path permits factual fallback and partial output where authoring must +reject an unresolved reference. Shared value helpers are appropriate only where +both consumers have the same failure and mode-selection rules. + +### Feedback and persistence + +UI edits become broker drafts keyed by file, conversation and task. Submission +persists the delivery identity before the Hub adapter is invoked. `AgentClients` +checks task ownership/epoch; `CodexAppFeedback` serializes one conversation, records +a durable receipt, and delegates native queue or active-turn delivery. Broker +settlement clears only unchanged content from the matching draft round. Done +persists a closed-review fence with draft clearing; Stop independently fences +execution and removes pending delivery. + +Draft snapshots, Hub receipts and native composer entries are different records: +unsent editable intent, delivery uncertainty, and host-owned scheduled work. A +single generic persistence abstraction would erase meaningful boundaries. + +### State ownership and lifetime + +| State | Authority and lifetime | Decision | +| --------------------------------------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Active extension and browser session | Transport registry / broker; connection lifetime | Defaults for taskless selection, never replacements for a bound task target. | +| Current task ID per file | `DesignTasks.currentTaskIds`; persisted across restarts | Already identifies the only task allowed to acquire or recover an active lease; occupancy now uses this authority instead of searching all historical records. | +| Historical tasks and Stop fences | `DesignTasks.records`; durable review history | Keep history for recovery, idempotent begin and taskless-write cancellation fences; do not use it as a second current-owner index. | +| Pending native operations | `DesignTasks.operations`; live until definitive settlement or proven runtime replacement | Independent of task status and socket presence. Keep uncertainty tracking. | +| Page busy/revoked/stopped state | `PageDesignTasks`; local runtime plus Stop persistence | Final fence for a stale in-flight route; cannot be derived from the Hub snapshot. | +| Review snapshots and UI projection | Broker durable review + tab snapshot + displayed/dismissed controls | None grants a lease. Review persistence is separate from acknowledgement and anchor restoration. | +| Draft round and submission receipt | `FeedbackDraftStore`; durable across page and worker replacement | Clear/Done now share the same atomic round-advance write; Done retains its closed-review fence. | +| Native receipt / per-conversation queue | `CodexAppFeedback`; durable receipt, process-local serial tail | One scheduler owns serialization; durable receipt states and tombstones remain necessary for uncertain writes. | +| Canvas resources and fonts | One apply, with a separate bounded cross-call image cache | Keep strict resource identities; share node classification and preparation without changing mutation counting. | +| Code generation caches | One `handleGetCode` execution and its rerenders | Removed the forwarding cache and redundant pipeline fields; language detection and shell collection remain explicit. | + +## Stage 2: cross-module decisions + +| Domain and source evidence | Implemented consolidation | Boundary retained after comparison | +| -------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Task authority: `DesignTasks.begin`, `resume`, `recoverSessions`, `restore`, `restoreReview` and Hub binding callers | **G1:** occupancy derives from `currentTaskIds`; remove the redundant occupant check and repeated current-ID assignment after the resume guard. | History remains necessary for retry identity, reviews and cancelled taskless-write fences. `operations`, `ready` and `ending` represent dispatch uncertainty, page binding and deferred settlement, not duplicate task status. | +| Canvas model: `model.ts`, `markup.ts` node inference, `reconcile.ts` supported-node checks and update hints | **G2:** one node classification owns shape, preserved and supported types. Infer supported/preserved unions from the same lists; share frame/intrinsic predicates. | Keep wrappers that narrow a live Figma node object separately from predicates over a type string. Do not broaden the supported native-node set. | +| Canvas preparation: `prepareCanvasTheme`, `parseCanvasMarkup`, `applyResolvedCanvas` | **G3:** carry the already parsed HTML tree from asynchronous theme hydration into compilation. Attach theme-bound fields while compiling each node instead of walking the completed tree again. | Hydration precedes live update hints; class normalization remains after those hints, with the same diagnostic boundary. Catalog normalization, static legality and asset validation retain their own ordering. | +| Broker persistence: `FeedbackDraftStore.request/closeReview`, `DesignReviews.save/close` | **G4:** one draft-round advance commits the empty snapshot and receipt fence; one review commit persists before publishing memory. | Done supplies its additional closed-review state to the same atomic storage write. Restore retains its existing initialization/failure semantics. Draft and review stores remain separate owners. | +| Code pipeline: `handleGetCode`, `finalizeRenderedOutput`, `rerenderResolvedOutput`, render/plugin consumers | **G5:** remove duplicate node map/config/plugin fields from pipeline input; use the render context. Delete the context copier and explicitly reset language detection on a resolved rerender. | Root-only shell collection and full collection differ. Token resolution must use the selected collected subset; render context still carries SVG and plugin facts. Preserve the first render's output language. | +| Token cache: all imports under `code/tokens` and `token`, barrel tests and coverage inventory | **G6:** migrate to the existing shared token cache, remove the forwarding file/export and duplicate cache suite. | Keep cache miss, cached-null and API-call assertions in the owning `token/cache` suite. UI codegen output remains distinct from MCP token IR. | +| Evaluation: rollout, identity and skill-catalog inspectors | **G7:** one JSONL reader retains parsed values and malformed-line evidence; authoring inspection and identity checks reuse that parse. | Identity treats malformed rows as invalid evidence; catalog extraction skips them. Preserve line numbers and issue order. The strict durable run-log parser remains separate. | + +### What cannot be merged by shape alone + +Structural markup and native-only updates both produce `CanvasNodeSpec`, but their +omission rules differ. Structural stroke/corner normalization fills missing sides +from uniform values and class/variable fallbacks. Native-only normalization leaves +unspecified fields absent to preserve live state. A single helper with mode flags +would hide this distinction. Shared node classification and prepared-tree reuse +remove actual duplication without introducing that policy switch. + +Styles and variables also have distinct lifecycles. Style resolution caches direct +IDs/import keys and relies on native style-consumer queries for removal. Variable +resolution additionally owns collections, inherited modes, overrides and aliases; +removal must inspect pages, physical instance descendants, rich text, styles, +shaders, aliases and extended collections. Their similarly named local-index and +cache methods do not justify a generic resource store. Their common ordered phases +are shared at reconciliation's existing transaction boundary (initial item D). + +## Stage 3: internal review + +The internal review follows the same domains rather than treating large files as +opaque or exempt from simplification. + +| Implementation area | Reviewed mechanism and disposition | +| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Hub/CLI and request transport | Request IDs, extension ownership, mutation timeout, disconnect and shutdown are separate outcomes. Initial F shares response lookup/timer cleanup; definitive operation settlement remains explicit. Hub process locking/stdio shutdown is retained: moving module state into a class would require a new process lifecycle API without eliminating a duplicated policy. | +| Task state and page fence | Only guarded begin/resume/recovery paths activate a task. Restore deactivates leases; an uncertain operation outlives socket loss. G1 removes the competing historical scan while preserving restart, Stop, same-file and epoch guards. | +| Native host delivery | Per-conversation tails, admission caps, durable pending/delivered receipts, cancellation tombstones and owner reload were compared. Initial E shares scheduling. Receipt rereads after pending deliveries are necessary: taking one earlier snapshot would miss a delivery that commits while cancellation waits. Canonical and legacy native histories remain active compatibility inputs. | +| Browser routing and feedback UI | Registered page/document/session identities, broker serialization, draft rounds, review closure and UI projections have different lifetimes. G4 consolidates writes without moving authority into UI state. Failed persistence does not publish a successful save/Done fence. | +| Catalog and reference resolution | Catalog refs, component tags, CSS aliases and current-file native identities are separate namespaces. Existing bounded catalog LRU and conflict-safe alias generation remain. Deep native resolution preserves depth caps, own-property lookup and diagnostics; read fallback must not replace strict authoring resolution. | +| Markup compilation and native-only preparation | Compare node inference, size defaults, strokes/corners, grids, text and instance preservation. G2 removes duplicate type tables/casts. G3 removes a second HTML parse and a post-compilation annotation walk. Static legality and resource-reference validation remain separate because they inspect different representations. | +| Reconciliation mutation and verification | Inspect identity/adoption, protected nodes, preflight, creation, setters, deferred node-key references, manual/flow grid finalization, removal and undo. These passes run against different live states; combining them would change mutation and diagnostic order. Apply and verify intentionally share comparison helpers while retaining independent setter and assertion paths. | +| Fonts, media and resource removal | Initial B/C give caches narrow owners. Pending font promises, exact/portable face selection, bounded image reuse and ordered video imports remain. Collection removal orders descendants before parents and checks all retained consumers; repeated live checks cannot be replaced by the initial read snapshot. | +| Read/codegen and plugin sandbox | G5 removes redundant pipeline state and the field-copy adapter. Preserve early-shell budget preflight, per-request read caches, source-ordered bounded asset export, plugin batches and per-node token mode resolution. Worker isolation and timeout/recovery behavior remain unchanged. | +| Evaluation and plugin generation | G7 shares parsing while preserving evidence policy. Host message envelopes, timestamps and prompt validation remain distinct consumers. Release manifests and native packages continue to derive from their existing tracked source; no generator-input change is needed. | + +No universal tree walker, transition engine, property-setter registry or generic +persistence framework was introduced. These would require policy flags for actual +semantic differences and increase the number of concepts needed to reason about a +write. The accepted changes remove duplicated authority, state, parsing or commits. + +## Stage 4: details and caller migration + +- `CanvasNodeTypeHints` now benefits from actual type predicates, replacing casts + around repeated supported/preserved sets. The shape members remain identical. +- `PreparedCanvasTheme` carries the parsed tree and hydrated resources together. + Direct synchronous markup compilation remains available for local inputs; the + production asynchronous path reuses its preparation result. Theme normalization + does not mutate the prepared tree or caller's bindings. +- `CompileState` is constructed at the compile boundary. Theme field annotations + are attached after each node's children and validation, preserving the final + property representation while eliminating the annotation-only traversal. +- Pipeline configuration, plugin code and node lookups now have one source. The + resolved render explicitly clears `detectedLang`; it still uses the first render's + selected language for serialization and the result. +- All three cache consumers and their mocks import `token/cache` directly. Four + duplicate forwarding-cache cases are removed; the owner's three cases retain all + behaviors and additionally assert Figma call counts. The removed barrel assertion + only checked the deleted internal export. +- Rollout parsing preserves blank-line offsets, scalar/null rows and malformed-row + evidence. Identity consumes parsed entries; all internal callers and tests are + migrated without a second string/parsed compatibility path. +- Coverage inventories follow the code: remove the deleted forwarding cache and add + the extracted rollout parser. Canvas model helpers are covered by the existing + Canvas wildcard. Thresholds remain unchanged. + +## Initial structural review (completed batch only) + +| Layer | Existing responsibility | Finding and decision | +| ---------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Shared contracts | Tool inputs/results, native Canvas declarations, browser protocol | `mcp/tools.ts` contains 2,546 lines; the contiguous Canvas contract accounts for over 2,000. Separate that contract while preserving existing exports and schema objects (A). | +| Server routing and pending calls | Tool metadata, extension ownership, request settlement | Hub registration and extension dispatch have different consumers and must stay separate. Resolve/reject in `request.ts` repeat the same ownership/timer/map policy; consolidate that exact policy (F). | +| Host integration | Conversation binding, lifecycle projection, native feedback, durable receipts | Admission and cancellation independently maintain the same per-conversation promise chain in `codex-feedback.ts`. Centralize scheduling (E), while retaining receipt fencing and host-specific delivery. | +| Browser gateway and review UI | Session selection, permissions, feedback drafts and task controls | Existing bridge/broker separation and broker serial queue already provide appropriate boundaries. Do not unify them with Node host delivery: persistence, cancellation and concurrency limits differ. | +| Canvas resolution | Catalog aliases, local identities, type checks, preflight | Styles and variables look similar but differ in error categories, lazy initialization, imported-key caching, and extended collection semantics. Keep distinct resolvers; a generic registry would hide these contracts. | +| Canvas mutation | Reconciliation, loading, mutation bookkeeping, verification, undo | The 7,407-line reconciler owns unrelated font and media caches. Extract each with a narrow state contract (B/C), then consolidate exact common resource phases in structural and native-only writes (D). | +| Read/code generation | Semantic snapshots, token extraction/resolution, output budgets | Token value/mode utilities already share common rules. Read fallback semantics differ from strict authoring resolution. Retain separate read/write pipelines and UI/MCP codegen boundaries. | +| Skills, plugin generation and evaluation | Portable release source, derived native packages, runtime evidence | Preserve generator ownership, progressive skill references, and runtime identity checks. No generator input changes are justified by this refactor. | + +The main improvement is fewer places to understand and modify a policy. Extracting +files without narrowing dependencies would only move complexity. Conversely, +combining operations with different error, lifetime, or ordering semantics would +make the code shorter while weakening the design. + +## Completed initial work + +### A. Separate the Canvas contract from general tool contracts + +Current evidence: `packages/shared/src/mcp/tools.ts` places `CanvasDesignReference` +through `ApplyCanvasResult` between design-system and asset tools. Structure results +also refer to Canvas types, and structure parameters use `CanvasStableKeySchema`. +The Canvas block depends on shared constants and task schemas, not general tool +registration. + +Move the Canvas declarations and stable-key schema into `mcp/canvas.ts`. General +tools import their needed Canvas types/schema and re-export the module, preserving +both package exports and existing direct `tools` imports. Avoid a reverse import +from Canvas into tools. Do not rewrite refinements, defaults, limits, descriptions, +or validation order. Add the new module to package and root coverage inventories. + +Verification: shared contract tests and strict shared coverage, downstream typecheck, +server formatter tests, and extension parser/reconciler tests. This is structural +separation, not a schema migration. + +### B. Give font resolution and loading its own state + +Current evidence: `loadFont`, `loadFonts`, `resolveFamilyFont`, and +`resolvePortableFont` use only `fontLoads` and `availableFonts` from the broad +`ApplyState`. They serve resource preflight, text styles, whole-node text and ranges. + +Move these operations, face matching, and current-text font inspection to +`canvas/fonts.ts`. Give each apply one `CanvasFontState`; callers pass that state +rather than mutation/ownership state. Preserve pending-promise deduplication, +failed-load caching, font listing laziness, candidate order, tie-breaking, exact +family matching, and the single Figma readiness retry. Keep consumer-mode variable +resolution in reconciliation, where it depends on live nodes. + +Verification: existing portable/exact-font, text range, variable-font, missing-face, +and transient-readiness regressions through `applyCanvas`. + +### C. Give media import its own state and bounded cache + +Current evidence: image URL, asset and video loading use assets, URL inventories and +hash maps, but no node ownership or mutation bookkeeping. The cross-call image +cache validates a Figma hash before reuse and evicts at 256 entries. + +Move import policy to `canvas/media.ts` with one per-apply media state. Keep the +cross-call cache module-local. Expose one import operation with the current order: +URL images, supplied image bytes, then video URLs. Preserve fetch credentials, +timeout, bounded streaming, error codes/messages, first-usage reporting and cache +invalidation. SVG placement and ownership remain in the reconciler; source SVG +resolution remains in `assets.ts`. + +Verification: existing URL import deduplication, content-addressed image reuse, +first-usage error, streamed/declared video limits and import-failure rollback tests. + +### D. Share the resource phases of structural and native-only updates + +Current evidence: both final orchestration paths repeat variable reconciliation, +style preparation/preflight, media import, style application, resource removal, +and the same ordered layout-warning families. They differ in scope validation, +page modes, topology, removal, and verification traversal. + +Extract only identical ordered phases and layout-warning collection. Keep their +call positions and asynchronous boundaries explicit in both paths. Do not combine +the two operation handlers or introduce a configurable transaction framework. +Resource definition/preflight still precedes node changes; deferred node-key links +still follow node creation; removals still precede final verification. + +Verification: existing native-only and structural resource tests, idempotent updates, +warning assertions, resource-consumer removal rejection, and rollback tests. + +### E. Centralize native per-conversation scheduling + +Current evidence: `CodexAppFeedback.enqueue` and `cancelQueued` independently read a +promise tail, ignore an earlier rejection, append work, register the new tail, and +delete it only if it is still the latest. The conditional deletion prevents an old +operation from erasing newer pending work. + +Use one private scheduler for both callers. Keep enqueue admission limits and Steer +rejection at their current call site. Keep cancellation's immediate task fence and +its wait for current delivery before receipt discovery. Do not merge queue and steer +payloads, receipt states, uncertain-write handling, or lifecycle subscriptions. + +Verification: existing native feedback tests plus a focused ordering regression if +current tests do not cover removal followed by a later submission to that same +conversation. Test error recovery and independence across conversations through +public behavior, not private promise maps. + +### F. Unify pending-result ownership checks + +Current evidence: `request.resolve` and `request.reject` duplicate pending lookup, +wrong-extension rejection, timer cleanup and result-specific logging. Shutdown and +disconnect have different iteration and error creation behavior. + +Share response lookup/ownership validation and settlement cleanup without changing +public functions or warning text. Preserve timeout behavior, including the +warning-only timeout for mutations that require a definitive result. Keep shutdown +and disconnect loops explicit rather than folding every exit into a generic event +state machine. + +Verification: existing request tests for wrong sender, unknown/late response, +normal success/failure, warning-only timeout, disconnect, and shutdown. + +## Constraints to preserve during deeper review + +- `withUndoBoundary` remains the sole native transaction wrapper. It has already + consolidated rollback; page-removal context restoration is an additional duty, + not a duplicate generic transaction. +- Variable async preflight and synchronous application remain separate. Application + must use preflighted resources; an async resolver or generic recursive evaluator + would obscure when native reads/imports are allowed. +- Authored node keys, style keys and variable keys retain their current scope and + diagnostics. Similar map operations do not establish equivalent semantics. +- Canvas traversal distinguishes physical descendants, authoring boundaries and + instance protection. A universal walker would require hidden policy switches. +- Native canonical and legacy turn-history projections remain supported because + actual host snapshots/patches use both. Their names alone are not evidence of + obsolete migration code. +- Queue receipts and cancellation tombstones remain durable. In-memory deduplication + cannot prove whether an uncertain native write committed after disconnect. +- Component properties, layout/grid finalization, native setters and verification + stay together for this pass. They share live topology and mutation tracking; + splitting them requires a larger domain API, not merely moving functions. +- Existing large behavioral suites remain intact. Mechanical test splitting would + add fixture boundaries without removing duplicated assertions; no assertions are + weakened or removed to make refactoring pass. + +## Initial batch results + +The six initial items are implemented and verified. Their completion does not +establish completion of the requested global-to-detail review. The constraints +above preserve behavior; they do not exempt the surrounding modules from deeper +analysis or implementation-level simplification. + +| Item | Completed implementation | +| ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| A | [Canvas contracts](../../packages/shared/src/mcp/canvas.ts) now own the authoring dialect. General [tool contracts](../../packages/shared/src/mcp/tools.ts) shrink from 2,546 to 489 lines and retain all 122 named exports through re-export. Schema declarations and stable-key validation match the preserved baseline exactly. | +| B | [Canvas fonts](../../packages/extension/mcp/tools/canvas/fonts.ts) own font listing/loading state. Extracted function bodies are unchanged apart from exports and the narrowed state type. | +| C | [Canvas media](../../packages/extension/mcp/tools/canvas/media.ts) own image/video import state and the existing bounded image cache. Extracted import bodies retain their original logic. | +| D | [Reconciliation](../../packages/extension/mcp/tools/canvas/reconcile.ts) shares resource preparation, application, removal and ordered layout-warning collection across both write paths. Its top-level state now delegates fonts and media to their respective state objects. | +| E | [Native feedback](../../packages/mcp-server/src/agent-clients/codex-feedback.ts) uses one scheduler for delivery and removal. Two added cancellation-order regressions passed before and after refactoring. | +| F | [Pending requests](../../packages/mcp-server/src/request.ts) share response ownership checks, diagnostics and timer cleanup; success/error settlement and shutdown semantics remain explicit. | + +The incremental change touches 13 files, including this report, coverage configuration +and tests. The 23 previously modified files outside the two overlapping source +files remain byte-for-byte unchanged. The earlier edits in those two overlapping +files were retained in the extracted code or reconciliation logic. No commits were +created, and no generated plugin source was edited. + +Validation completed: + +- `pnpm typecheck` and `pnpm lint`: passed. +- `pnpm test:run`: 2,134 tests passed, including extension/site browser tests; + Worker and release-plugin Chromium sandbox probes passed. +- `pnpm test:coverage`: passed; statements 92.60%, branches 87.52%, functions + 95.52%, lines 94.04%. Coverage inventories include the moved Canvas contract. +- `pnpm -C packages/shared test:coverage`: 230 tests passed; all four coverage + dimensions are 100%. Thirty added cases protect operation-scope diagnostics, + resource bounds, result identities, grid bindings and vector-loop edge cases. +- `pnpm -C packages/shared build` and `pnpm build:ext`: passed. +- The 252-test Canvas suite passed after each Canvas batch. The focused server + batch passed all 74 tests. Formatting and `git diff --check` passed. + +Live Figma authoring was not run: these are deterministic refactors. This result +makes no new host-compatibility or visual-quality claim. + +## Stage 5: integrated result + +The original branch inventory review, the initial structural batch and this +follow-through cover the domain map above. All accepted items A–F and G1–G7 are +implemented. Retained implementations are accounted for by their ownership, +defaulting, error, lifetime or ordering semantics; they are not excluded solely +because a file is large or an existing test passes. + +The follow-through changes 26 paths: 18 implementation files (including one removed +forwarder and one new parser), six test files, the coverage inventory and this report. +Of the 36 paths modified before this follow-through, 33 remain byte-for-byte +unchanged. Only this report, the markup compiler and reconciler overlap; their earlier +changes remain present. Existing release documentation and generated plugin files +were preserved. No commits were created. + +Final verification: + +- `pnpm typecheck`: passed. +- `pnpm lint`: passed after correcting import order in the migrated cache consumers. +- `pnpm test:run`: 2,130 tests passed: extension 1,614, MCP server 272, shared 230, + plugins 6 and site 8. Browser tests and Worker/release-plugin sandbox checks passed. +- `pnpm test:coverage`: passed, with unchanged thresholds. Statements 92.61%, + branches 87.53%, functions 95.53%, lines 94.04%. +- `pnpm build:ext`: passed, including rewrite and README generation. +- Focused verification passed during the work: task authority/recovery/client tests + 67; Canvas parsing/theme/resolution/reconciliation tests 514; broker tests 76; + code/token tests 258; script/evaluation tests 84. +- Formatting, complete incremental-diff review, removed-API caller searches and + `git diff --check`: passed. + +The four-test difference from the initial batch is the removed forwarding-cache +suite. Its distinct behaviors remain covered in the owning cache suite; no expected +behavior or coverage threshold was relaxed. No live Figma run was required for these +deterministic refactors, so this report makes no new visual or host-support claim. diff --git a/docs/extension/mcp-browser-gateway-design.md b/docs/extension/mcp-browser-gateway-design.md index c4c651ee..3a59d5ca 100644 --- a/docs/extension/mcp-browser-gateway-design.md +++ b/docs/extension/mcp-browser-gateway-design.md @@ -14,37 +14,104 @@ in Figma's page world. Shared browser-gateway schemas validate page, session, tool, and asset traffic. Permission requests use a separate narrow runtime message validated by the background worker. +Explicit design tasks add file leases, fixed session routing, page-side fencing, +and DOM feedback. See [design tasks](mcp-design-tasks.md) for lifecycle, takeover, +expiry, and recovery semantics. Taskless reads still use the active route. + ## Connection lifecycle 1. Enabling Agent integration requests optional access to `http://127.0.0.1/*` from the initiating user action. 2. The content bridge opens a named runtime port and registers the page session with the broker. 3. The broker starts one WebSocket client for all Figma tabs in the extension context. -4. The client probes the known ports, then accepts a candidate only after receiving both - `registered` and `state` messages from the hub. The advertised asset URL must use an explicit - loopback IPv4 port and cannot contain credentials, a query, or a fragment. +4. The client probes the known ports and requests the `tempad-mcp` WebSocket subprotocol before + receiving any frames. It accepts a candidate only after receiving both `registered` and `state`. + Registration announces `protocolVersion` and the versions the Hub still serves. A Hub that does + not serve this extension is rejected with instructions to restart the agent's MCP connection + using `@tempad-dev/mcp@latest`, including other agents keeping an old Hub alive. Reloading Figma + alone does not update that Hub. The advertised asset URL must use + an explicit loopback IPv4 port and cannot contain credentials, a query, or a fragment. 5. Every later `state` message is validated by the same rule and must keep the handshake's exact asset endpoint. Malformed traffic, a second registration, or an endpoint change closes that socket and resumes the existing reconnect loop. 6. A 20-second ping keeps the Manifest V3 service worker alive. A disconnected content port or WebSocket reconnects while its session remains enabled. + Draft requests wait for the initial permission check and session registration. A request + that opens a replacement runtime port registers its session before forwarding the request. + A draft request that cannot be forwarded receives an error response instead of being + silently dropped. A waiting request never carries over into a replacement enable. + +The bridge protocol version covers the shared tool contract as well as transport messages. Bump it +whenever a Hub and extension built from different revisions must not exchange tool calls. + +Runtime identities record the observed builds; changed source fingerprints, versions, +executable hashes, or build timestamps do not determine compatibility. The modifying +agent decides whether to reuse or refresh the Hub under the +[evolution guide](../testing/agent-authoring-evolution.md#3-establish-a-trustworthy-runtime). +Compatible extension updates can reconnect to the same Hub. Runtime handshakes, +protocol validation, connection ownership, and stale-request checks remain enforced. +Exact checkout matching belongs to preflight and the frozen run record. + +### Released unversioned extensions + +Extension 0.20.0 sends no WebSocket subprotocol and strictly rejects extra registration fields. +For these connections the Hub sends only `{type: "registered", id}` and the old state/tool-call +envelopes. It accepts only activation, ping, and tool-result frames. Session inventories, runtime +identity, design actions, and design-task messages are unavailable on this path. Unknown +subprotocols are rejected during the HTTP upgrade. + +The active legacy connection can serve taskless `get_code`, `get_screenshot`, and node-based +`get_structure` with their released arguments and result shapes. The internal token tool contract +is retained without changing its public exposure. New arguments such as page identity or native +read-back, and canvas authoring operations, return `EXTENSION_UPGRADE_REQUIRED` before dispatch. +The Hub never fabricates a session or task lease for an old tab. Calls carrying a task id always +resolve their original bound session, even when a legacy connection becomes active or replaces +a disconnected current connection. Current peers still require their runtime identity handshake. + +Legacy connections receive a separate random asset capability from the same HTTP server. +That capability permits their 8-character SHA-256-prefix uploads; the current capability continues +to require full SHA-256 uploads. Both use the same Origin checks, quota, concurrent-upload limit, +and store. Legacy retries are fully hashed, and an existing short hash with different full content +returns a collision error without changing its bytes. Existing short-hash downloads remain valid. + +Keep this adapter for at least one store cycle. Its removal requires an explicit breaking migration; +see [release coordination](../releasing.md#bridge-protocol-and-release-order). The hub chooses the active browser connection. Inside that connection, the broker chooses the -active Figma session. A sole session is selected automatically; switching sessions is explicit. -Broker activation is sent to the hub only from that explicit user action. Pending tool results are +active Figma session. A sole session is selected automatically. More than one session requires an +explicit choice: registering another Figma tab clears the previous choice, and a newly connected +Hub clears an ambiguous choice inherited from its predecessor. Foregrounding a tab does not route +MCP calls; clicking its badge does. Broker activation is sent to the hub only from that explicit +user action. Pending tool results are bound to the extension connection that received the request, so a second connection cannot satisfy or reject another connection's request by guessing its id. While an extension connection is active, the hub accepts replacement activation only from the same extension Origin. Normal reconnects and all Figma-tab switching inside one extension context keep the current flow; a later connection from a differently identified extension cannot take over the established route. +Review recovery uses the same registered session inventory. An optional saved review in +`mcp.enable` identifies the task this page is restoring; the broker sends its durable latest +review as `sessions.reviews` only for the matching file and page claim. Hub task records, +not cached capabilities or transport IDs, remain authoritative for sending comments. +`reviewClosed` is a one-way Done fence. The broker persists it together with draft deletion +before acknowledging Done, then synchronizes it on reconnect. `mcp.designReviewClosed` +notifies other registered tabs locally; it never grants a canvas lease. Both browser and +Hub protocol versions advance for this contract. + +Stop persists cancellation locally before dispatch. On a connected socket, the broker sends +the explicit Stop action before publishing the cancelled review snapshot. Otherwise the Hub +restores cancellation first and treats Stop as an already-ended task, skipping native host +interruption. The cancelled snapshot still synchronizes when dispatch fails or on reconnect. + ## Assets -The page computes asset hashes and descriptors, then sends at most `MCP_MAX_ASSET_BYTES` through the -bridge. The service worker decodes the payload and uploads it to the hub's loopback asset server. -The page never fetches the loopback server directly. The asset URL contains a random capability -path generated for the hub process; the server also enforces per-asset, aggregate-store, concurrent -upload, header, and request-time limits. It does not emit wildcard CORS. +For outbound assets, the page computes hashes and descriptors and sends at most +`MCP_MAX_ASSET_BYTES` through the bridge; the service worker decodes and uploads the bytes to the +hub. For inbound canvas assets, the page sends only the hash; the service worker downloads a bounded +body, verifies its digest, and returns the bytes through the same validated bridge. The page never +fetches the loopback server directly. The asset URL contains a random capability path generated for +the hub process; the server also enforces per-asset, aggregate-store, concurrent upload, header, and +request-time limits. It does not emit wildcard CORS. ## Trust boundary diff --git a/docs/extension/mcp-canvas-assets-design.md b/docs/extension/mcp-canvas-assets-design.md new file mode 100644 index 00000000..0464ce6e --- /dev/null +++ b/docs/extension/mcp-canvas-assets-design.md @@ -0,0 +1,539 @@ +# MCP Canvas SVG and image assets + +Status: implemented, including programmatic generated-image upload +Date: 2026-07-31 + +## Decision + +Keep `apply_canvas` as the only canvas-mutating tool. Add a call-scoped asset manifest, one SVG placement +field, and one content-addressed image source: + +```txt +agent or host asset + -> small inline SVG or Hub asset hash + -> apply_canvas desired result + -> deterministic asset resolution + -> Figma-native SVG import or image fill + -> normal diff, Undo, rollback, and verification +``` + +Do not add icon-search, image-search, or SVG-operation tools to TemPad. Expose one narrow +`upload_asset` bridge for PNG, JPEG, or GIF `data:` URLs returned by an image-generation tool. The +agent must compose generation and upload inside one programmatic tool call so bytes do not enter +model-authored prose or later Canvas arguments. The dedicated upload argument carries the image +once; subsequent Canvas calls see only a content hash. Do not put raster bytes or large SVG +documents in `apply_canvas`. + +Image generation may run in an isolated subagent when the host supports it and the canvas-authoring +delegation gate passes. The main agent fixes the art brief, remains the only Canvas writer, and owns +placement and final judgment. This is an optional agent-orchestration optimization, not part of the +TemPad protocol. + +Asset-medium selection remains an evidence decision. Creative latitude, Canvas editability, and +delivery convenience do not establish a geometric or vector language. When several assets represent +distinct content, the chosen existing, licensed, generated, or vector route must preserve the +distinctions the composition depends on instead of substituting one reusable placeholder motif. + +This extends the existing declarative language rather than creating a second asset dialect. + +## Figma facts + +Figma provides two different vector paths: + +- [`figma.createNodeFromSvg(svg)`](https://developers.figma.com/docs/plugins/api/figma/) imports an + SVG string as editable Figma layers inside a `FrameNode`, equivalent to editor SVG import. +- [`VectorPath.data`](https://developers.figma.com/docs/plugins/api/properties/VectorPath-data/) + accepts only absolute `M`, `L`, `Q`, `C`, and `Z` commands. + +Direct SVG import is therefore the correct path for frontend icon-library SVG. Requiring the agent +to translate arbitrary SVG into `VectorPath` would spend context, invite geometry errors, and lose +supported SVG structure. + +The expected layer shape is a managed Frame containing one native imported SVG subtree. TemPad does +not flatten its Vector descendants because that can change strokes, holes, masks, multicolor art, +and exact source replacement. + +Figma has no image node. Images are content handles used by +[`ImagePaint`](https://developers.figma.com/docs/plugins/api/Paint/). The Plugin API accepts: + +- PNG, JPEG, or GIF bytes through + [`figma.createImage`](https://developers.figma.com/docs/plugins/api/properties/figma-createimage/); +- a public PNG, JPEG, or GIF URL through + [`figma.createImageAsync`](https://developers.figma.com/docs/plugins/api/properties/figma-createimageasync/); +- existing current-file image hashes through `figma.getImageByHash`. + +Both byte and URL imports are limited to 4096 pixels on each axis. SVG import produces editable +vector layers rather than an image fill. + +MCP resources and resource links let a server send large data to a client. The protocol does not +define a general client-to-server binary upload handle. TemPad therefore accepts one bounded image +data URL through a dedicated Hub-only call instead of widening `apply_canvas`, reading local files, +or adding an arbitrary URL fetcher. + +## Public desired-result contract + +Add one optional top-level field to the compact public schema: + +```ts +type ApplyCanvasInput = { + // existing fields + assets?: Record +} +``` + +As with `styles`, `variableCollections`, and advanced `native` state, the public schema exposes the +outer record while keeping each asset definition opaque. The resolver validates the complete +private shape: + +```ts +type CanvasAssets = Record< + CanvasStableKey, + | { + type: 'SVG' + svg: string + } + | { + type: 'SVG' + assetHash: string + } + | { + type: 'IMAGE' + assetHash: string + } +> +``` + +Asset keys are call-scoped aliases. They deduplicate one source used by several nodes, but do not +create a Figma design-system resource and do not need to remain stable across calls. + +The asset manifest is a delivery contract, not a medium selector. Before declaring a material +asset, the agent records which user requirement, inspected evidence, or explicit brief decision +establishes its subject and medium. A content-image role uses a sourced, generated, supplied, or +current-file asset; availability of inline SVG does not justify replacing it with primitives or +newly invented vector artwork. Agent-authored vectors require an independently established +illustration, diagram, pattern, or decorative-geometry role. + +Allow at most 32 declarations and 64 KiB of inline SVG across one call. Every declaration must be +referenced, every reference must exist and match the required type, and page-only or remove +operations cannot carry assets. These rules prevent an asset manifest from becoming hidden +general-purpose payload storage. + +### SVG placement + +A childless `div` may carry: + +```ts +type CanvasSvgPlacement = { + assetKey: string + color?: string // exactly #RRGGBB or #RRGGBBAA +} +``` + +under `native[key].figma.svg`. + +Example: + +```jsx +
+``` + +```json +{ + "assets": { + "search": { + "type": "SVG", + "svg": "..." + } + }, + "native": { + "search-icon": { + "figma": { + "svg": { + "assetKey": "search", + "color": "#334155" + } + } + } + } +} +``` + +`color` resolves CSS `currentColor` before import. It is a literal in the first version: + +- it makes common frontend icon SVG deterministic; +- it does not pretend a paint variable can be reliably propagated through importer-generated + descendants; +- catalog icon components remain the correct choice when native token linkage matters. + +Reject unresolved `currentColor`. Do not silently import it as black. Omit `color` for SVGs with +complete explicit colors. + +The SVG placement: + +- compiles to a managed `FRAME` wrapper; +- must be childless in Canvas HTML; +- cannot combine with a component binding, native shape, group, Boolean operation, section, + authored component, or Slot; +- may use normal layout, size, position, visibility, opacity, blend, and rotation on the wrapper; +- preserves the SVG aspect ratio, centers it, and contains it inside the declared width and height; +- does not reinterpret wrapper fills, strokes, or variables as descendant SVG colors. + +Only contain-and-center is supported initially. Cover, stretch, arbitrary SVG viewport alignment, +and descendant paint remapping need real use cases before becoming protocol concepts. + +### Image paint source + +Keep the existing `IMAGE` paint model and add `assetKey` as a third source: + +```ts +type CanvasImageSource = { imageHash: string | null } | { imageUrl: string } | { assetKey: string } +``` + +Exactly one source remains required. All existing `FILL`, `FIT`, `CROP`, and `TILE` placement, +transform, rotation, filter, visibility, opacity, and blend fields remain unchanged. + +```json +{ + "assets": { + "hero": { + "type": "IMAGE", + "assetHash": "full-sha256" + } + }, + "native": { + "hero-frame": { + "figma": { + "fills": [ + { + "type": "IMAGE", + "assetKey": "hero", + "scaleMode": "FILL" + } + ] + } + } + } +} +``` + +Use: + +- `imageHash` to reuse exact bytes already present in the current Figma file; +- `imageUrl` for a public HTTP(S) PNG, JPEG, or GIF; +- `assetKey` for content already stored in the local Hub, including host-uploaded generated images. + +Do not infer node geometry from image dimensions. Canvas HTML remains the source of layout size; +the paint scale mode controls placement within that geometry. + +## Asset transport + +### Existing paths + +The current pipeline already supports: + +- Figma-to-Hub asset upload for `get_code` and `get_screenshot`; +- content-addressed storage behind a random loopback capability URL; +- linked output instead of binary model context; +- public image URL import through Figma. + +Reuse that store for authoring assets. + +### Hub-to-Figma bytes + +Add a narrow reverse path: + +```txt +Figma page requests assetHash + -> content bridge + -> extension service worker + -> authenticated loopback GET + -> MIME, size, and SHA-256 verification + -> bounded internal base64 message + -> page Uint8Array + -> createImage(bytes) or createNodeFromSvg(text) +``` + +The page never uses the Hub capability URL for inbound fetches. The broker accepts only an exact +content hash, builds the URL from its validated Hub state, and cannot be used as an arbitrary URL +proxy. Binary encoding exists only inside the extension bridge; it never enters an MCP tool call or +result. The page still receives the existing capability URL solely to describe outbound assets +already uploaded by `get_code` and `get_screenshot`. + +Cache resolved bytes and imported Figma image hashes by content hash for the active session. + +### Agent-generated images + +When custom focal imagery is appropriate and a generation capability is +available, generation runs before layout instead of substituting hand-built +Canvas geometry. + +Support three factual routes: + +1. A rights-established public HTTPS PNG/JPEG/GIF URL: use `imageUrl`. +2. The generator returns a PNG/JPEG/GIF `data:` URL: compose its result directly into + `upload_asset`, then use the returned `assetHash`. +3. Neither path exists: omit optional imagery or disclose the required gap; never synthesize an + image-role illustration from Figma primitives. + +`upload_asset` is Hub-only, content-addressed, idempotent, and bounded by the existing per-asset and +aggregate quotas. It accepts no local path, remote URL, headers, credentials, SVG, or arbitrary MIME +type. It validates base64 canonically, recomputes SHA-256, and stores through the existing loopback +asset server. Its response contains only `assetHash`, MIME type, and size. + +When the host supports subagents and generation is separable, importable, verifiable, and worth its +coordination cost, delegate nontrivial image generation: + +1. The main design agent sends a compact brief: layout role, subject, aspect ratio, palette/style, + important empty space, and negative constraints. +2. The image subagent generates and iterates independently. The main agent programmatically uploads + its selected `data:` URL through `upload_asset`; a rights-established public result URL remains a + valid direct route. +3. It returns only an importable `assetHash` or `imageUrl` plus MIME type, dimensions, and a short + description. It does not return bytes, candidate history, or its generation transcript. +4. The main agent owns placement and crop, and verifies the final composition when pixels can + change the decision. It does not need to inspect intermediate candidates. + +Do not delegate exact project assets, icon-library SVGs, existing Figma images, direct URL imports, +crop/placement decisions, or final acceptance. Do not spawn an image subagent when it cannot return +an importable reference. Clients without subagents follow the same asset contract directly; TemPad +neither exposes a subagent tool nor assumes one exists. + +Do not accept: + +- base64 or data URLs in `apply_canvas`, prose, or a copied/manual tool argument; +- arbitrary local file paths; +- credentials, headers, cookies, or signed-request recipes; +- a server-side “fetch any URL” endpoint. + +These alternatives respectively consume model context, expose local files, leak secrets, or create +an SSRF surface. + +### Content identity + +New asset descriptors and store paths use the complete lowercase SHA-256 digest. The extension and +Hub validate the digest again after every upload and download. The current asset capability retains +download-only support for legacy 8-character identifiers. Unversioned extensions receive a separate +compatibility capability that also accepts their short-hash uploads, validates the SHA-256 prefix, +and compares complete contents before reusing an existing short hash. Collisions fail without +overwriting bytes. Both capabilities share quotas and concurrency limits. Modern exports and +`upload_asset` always return full digests; see the [legacy gateway](mcp-browser-gateway-design.md#released-unversioned-extensions). + +The additional characters are negligible beside the bytes they replace. + +## SVG validation + +SVG is code-like input even when Figma turns it into design layers. Validate before mutation: + +- UTF-8 only; +- `` document root; +- inline SVG at most 32 KiB; +- Hub-backed SVG at most 1 MiB; +- at most 500 XML elements and depth 32; +- a finite positive `viewBox`, or finite positive intrinsic width and height; +- no `DOCTYPE`, entity declarations, scripts, event-handler attributes, `foreignObject`, embedded + HTML, audio, video, or iframe content; +- no embedded raster ``; +- no external `href`, `src`, CSS import, font URL, or `url(...)`; local `#id` references remain + valid for gradients, masks, clipping, and ``; +- no `
` creates a line break; `whitespace-pre-wrap` preserves every decoded character, including repeated spaces and literal source line breaks | +| Text-content variable | STRING variable bound to `characters` | **Supported** on the whole text node | +| Font family and style | `fontName` | **Supported**: common Inter shorthand remains available through classes; any available exact family/style can be loaded and applied to a whole node or range; STRING variables and Text styles remain available | +| Font size | pixel font size of at least 1 | **Supported** on the whole node and ranges, including FLOAT variable binding | +| Font weight | selected font style and FLOAT `fontWeight` variable binding | **Supported** through exact whole-node/range `fontName` styles and whole-node/range FLOAT variable bindings; Figma exposes the resolved numeric weight itself read-only | +| Line height | auto, pixels, or percent | **Supported**: whole-node classes cover auto and positive values; typed ranges accept every finite API value; whole-node and range FLOAT bindings are supported | +| Letter spacing | pixels or percent | **Supported** for finite signed whole-node and range literals in both units and whole-node/range FLOAT variable binding | +| Horizontal alignment | left, center, right, justified | **Supported** | +| Vertical alignment | top, center, bottom | **Supported** through typed `figma.text.verticalAlign` | +| Auto resize | none, width-and-height, height, deprecated truncate | **Supported** for all current modes; the deprecated `TRUNCATE` value is deliberately not emitted | +| Truncation | disabled or ending ellipsis, with nullable `number` maximum lines | **Supported**: both modes and null are supported; non-null maximum lines use the native API's required integer range starting at one | +| Text case | original, upper, lower, title, small caps, forced small caps | **Supported** on the whole node and ranges | +| Paragraph formatting | paragraph indent, paragraph spacing, and list spacing | **Supported** on the whole node and ranges; indent and paragraph spacing accept whole-node and range FLOAT variables | +| Lists | ordered/unordered list options, indentation, list spacing, and hanging-list state | **Supported**: range patches carry every list type, indentation, and spacing; a full-range patch expresses whole-node list state | +| Hanging punctuation | `hangingPunctuation` | **Supported** on the whole node | +| Decoration | none/underline/strikethrough plus underline style, offset, thickness, color, and skip ink | **Supported**: basic values are available whole-node; ranges carry the complete writable decoration state, including variable-bound solid decoration color | +| Leading trim | cap-height or none | **Supported** on the whole node | +| Hyperlinks | URL or node target, or null | **Supported** on the whole node and ranges, including explicit removal; node targets accept an existing Figma ID or a stable canvas key from the desired result/current update scope, including forward references | +| Auto rename | derive the layer name from changed characters | **Supported** through `figma.text.autoRename`; fixed `figma.name` plus enabled auto-renaming is rejected as contradictory | +| Rich text ranges | per-range font, case, spacing, line height, fill, styles, lists, decoration, links, and variable bindings | **Supported** for every non-deprecated range setter for formatting, lists, links, styles, and variables in the pinned typings; declarative `characters` replaces procedural insertion/deletion; patches are ordered, non-overlapping UTF-16 intervals and omitted fields preserve live state | +| Text and fill styles | whole-node or range `textStyleId` and `fillStyleId` | **Supported** by local ID, published key, or stable local `styleKey`, including same-result authored styles and explicit `null` unlinking at whole-node or range scope | +| OpenType features | `openTypeFeatures` | Plugin API 1.130 exposes this state read-only; `apply_canvas` cannot author it without a Figma API addition | + +## Components and instances + +| Capability | Figma Design state | Current `apply_canvas` status | +| ------------------------------ | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Instantiate local component | component node ID | **Supported** | +| Instantiate library component | published component key | **Supported** through import | +| Variant property | string property value | **Supported** | +| Text property | string property value | **Supported** | +| Boolean property | boolean property value | **Supported** | +| Instance-swap property | component node ID encoded by Figma as a string value | **Supported** when the caller supplies a valid component ID | +| Component-property variable | `VariableAlias` value | **Supported** through typed `componentProperties` variable references on instances and typed BOOLEAN/TEXT/INSTANCE_SWAP defaults on authored definitions. Catalog component-tag attributes remain literal shorthands | +| Slot content | slot property and authored `SlotNode` children | **Supported** with native default-content children, the full frame surface, exact property metadata/settings, and update identity. The pinned API cannot attach a new Slot in another variant to an existing SLOT definition | +| Instance replacement | swap an existing instance's main component while preserving identity | **Supported** by using a different catalog component tag/ref for the same stable key. Omitted or true `figma.instance.preserveOverrides` uses Figma's normal override-preserving swap; false changes the main component without carrying old overrides, then applies the rest of the declared result | +| Exposed nested instance | `isExposedInstance` | **Supported** when updating an existing primary instance inside a component or component set | +| Instance scale factor | `scaleFactor` | **Supported** across the native range starting at `0.01`, independently from final instance size | +| Create component | new `ComponentNode` | **Supported** as a native frame-like authored component, including children, Auto Layout/Grid, appearance, styles, variables, guides, metadata, and exact update identity | +| Component variants | component sets, variant definitions, default variant | **Supported**: native non-empty component sets are created from ordered component children; exact variant names define property names/options and declared geometry determines Figma's top-left default. The dedicated property methods mutate that same derived state, so exposing them as a second path would create contradictory dual writes rather than add expression power | +| Component property definitions | create/edit/delete BOOLEAN, TEXT, INSTANCE_SWAP, VARIANT, SLOT definitions | **Partial**: BOOLEAN, TEXT, and INSTANCE_SWAP support stable-keyed create/edit/explicit delete, variable defaults, and preferred values; complete VARIANT state derives from exact variant names and geometry; SLOT definitions are created/edited through native Slot nodes and removed with the owned Slot node. The contract intentionally has no contradictory property-only SLOT deletion path; the pinned API cannot attach a new Slot in another variant to an existing definition | +| Component sublayer references | bind visibility, text, or nested-instance identity to a definition | **Supported** by stable or exact property name with type preflight, explicit null clearing, omit/preserve semantics, and deterministic precedence over conflicting literals | +| Publishable metadata | description Markdown and the single supported documentation link | **Supported** on authored components and component sets with omit/preserve, empty-description clear, and null-link clear semantics | + +Publish status is read-only in the pinned Plugin API, and publishing itself is not exposed by that +API; neither is counted as missing writable canvas state. + +The [Figma editor](https://help.figma.com/hc/en-us/articles/38231200344599) can use multi-edit to +apply one Slot property across variants. The pinned Plugin API exposes +[`ComponentNode.createSlot()`](https://developers.figma.com/docs/plugins/api/ComponentNode/), +which creates a new Slot and definition together, but no operation that attaches another variant's +Slot to that existing definition. The remaining cross-variant Slot limitation is therefore an API +boundary, not a deliberate reduction of the design model. + +## Variables and styles + +| Capability | Figma Design state | Current `apply_canvas` status | +| --------------------------------- | --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Discover components | identities, dimensions, variants, usage guidance, and property definitions | **Partial**: local component definitions on pages Figma already makes accessible are found with one optimized `COMPONENT` type query per page, grouped by family, and deterministically paged. Inaccessible pages are skipped because Figma exposes no direct file-local component listing API and loading every page can block large files. Normal discovery returns a generated tag, short ref, bounded summary, native size, literal prop types/defaults/options, and semantic labels when generated prop names lose meaning; an exact-ref lookup in the same immutable catalog returns bounded native definition, variant, layout, anatomy, and preview-node detail. Unused subscribed-library components cannot be enumerated by the Plugin API | +| Discover variables | variable identities, collection identities and modes, types, scopes, descriptions, and values | **Partial**: local variables, definition dependencies from native styles, component defaults, shader defaults, aliases, and extended collections, plus enabled-library variables, are deterministically paged. Normal discovery returns short variable, collection, and mode refs plus type, scopes, and the default-mode literal value when available; an exact-ref lookup returns the complete captured definition. The Team Library API does not expose file-local IDs, modes, scopes, descriptions, or values for an unimported variable | +| Discover styles | local Paint/Text/Effect/Grid styles plus relevant imported styles | **Partial**: local style definitions are deterministically paged. Normal discovery returns short refs, type, signature, and summary; an exact-ref lookup returns the complete native Paint, Text, Effect, or Grid definition. Subscribed-library styles cannot be enumerated by the Plugin API | +| Discover shaders | owned and subscribed effect/fill shaders, import state, property definitions | **Supported** through `listAvailableShaders`: normal discovery returns deterministic short refs, names, and types, while exact-ref lookup returns the captured definition and defaults Figma exposes without importing or mutating the file | +| COLOR variable binding | fill/stroke solid colors and gradient-stop colors | **Supported** on every direct solid paint and gradient stop on current nodes; a compact whole-node shortcut covers one solid fill/stroke where applicable | +| FLOAT size binding | width, height, four min/max fields | **Supported** for section width/height and for width, height, and applicable bounds on frames, authored components, component sets, slots, text, instances, and basic shapes; a line supports width and width bounds but not its invariant zero height. Groups and Boolean operations derive bounds from children and reject independent size bindings | +| FLOAT Auto Layout binding | linear main/counter gap, grid row/column gap, and four padding fields | **Supported** | +| FLOAT appearance binding | opacity, corner radii, and stroke weights | **Supported** for opacity on current nodes that expose it, including authored components, component sets, groups, and Boolean operations; uniform stroke weight on every current node with stroke geometry; side weights on frame containers/instances/rectangles; uniform radius on every current corner node; side radii on sections/frame containers/instances/rectangles | +| FLOAT typography binding | font size, font weight, line height, letter spacing, paragraph spacing/indent | **Supported** for every field in the pinned whole-node `VariableBindableTextField` union | +| STRING typography binding | font family and style | **Supported** | +| STRING text-content binding | characters | **Supported** | +| BOOLEAN visibility binding | visible | **Supported** on sections, frames, authored components, component sets, slots, groups, Boolean operations, text, instances, and every current basic shape node | +| Stroke and corner bindings | four independent corners, uniform stroke weight, and four side stroke weights | **Supported** on every current node type that exposes each field in the pinned API | +| Range text bindings | the eight text fields above on character ranges | **Supported** for exact references and `null` unbinding on every field in the pinned `VariableBindableTextField` union | +| Paint/effect/layout-grid bindings | paint colors/stops, effect fields, layout-grid fields | **Supported** for direct and authored-style solid colors, every gradient-stop color, every shadow/blur field, and every valid field on row, column, or square layout grids; linked styles preserve their bindings | +| Component-property bindings | instance values and component defaults | **Supported** through typed `componentProperties` variable references and authored BOOLEAN/TEXT/INSTANCE_SWAP defaults. Catalog component-tag attributes set validated literal BOOLEAN, TEXT, VARIANT, and INSTANCE_SWAP values | +| Explicit variable mode | collection mode override on a node/page | **Supported**: catalog collection/mode refs or same-result stable authoring keys set or clear an explicit override on every current scene-node kind and on the page containing the result | +| Variable unbinding | remove an existing binding | **Supported** for every binding exposed by the current surface: `null` clears whole-node and range bindings, while replacing direct Paint/Effect/Layout Grid arrays clears bindings inside those entries. A direct catalog component prop replaces its previous literal or alias value | +| Local variable resources | create/edit/delete variable and collection, modes, aliases, scopes, code syntax | **Supported** for every writable field: one result can create or adopt stable-keyed local collections and variables; create, adopt, add, rename, or explicitly delete modes; edit names, descriptions, publishing visibility, scopes, and WEB/ANDROID/iOS code syntax; set typed literal or variable-alias values; and explicitly delete managed variables or collections. New variables require a value for every mode, and adding a mode copies each undeclared existing variable's default value. Null deletion runs last, scans every readable node/page, rich-text range, vector region, component default, local style, surviving variable alias, extended override, and shader default, and rejects any remaining consumer. Dependent extensions must also be explicitly removed. A variable's type and collection are immutable in the pinned native API and are therefore selected at creation rather than counted as writable gaps | +| Extended collections | extend a collection, inherit modes/variables, and override inherited values | **Supported**: in Enterprise files, one result can extend a local parent by native ID or managed key, or a published parent by library key; same-result parent chains are ordered and cycles fail before creation. Existing extensions expose parent/root and parent-mode identities, support name/publishing-visibility edits, typed literal or alias overrides, null override removal, node/page mode selection, consumer-safe child-before-parent deletion, automatic override cleanup for deleted variables, and deterministic orphan-mode cleanup down retained extension chains | +| Paint style | apply/import/create/edit/delete `PaintStyle` | **Supported**: apply by local ID, imported key, or local authoring key at whole-node, text-range, or vector-region scope. One result can create/adopt and edit a local style's name, Markdown/link metadata, and complete Paint stack with variables, media, patterns, and shaders; Pattern stable keys must already exist in the update scope. `styles[key]: null` removes a managed local style only after every live consumer is explicitly unlinked or removed | +| Text style | apply/import/create/edit/delete `TextStyle` | **Supported**: apply by local ID, imported key, or local authoring key at whole-node or range scope. One result can create/adopt and edit every writable `TextStyle` field and all eight variable bindings, plus name and Markdown/link metadata. Explicit unlinking is supported; `styles[key]: null` uses the same consumer-safe removal rule | +| Effect style | apply/import/create/edit/delete `EffectStyle` | **Supported**: apply by local ID, imported key, or local authoring key on every current effect-style consumer. One result can create/adopt and edit name, Markdown/link metadata, and the complete ordered Effect stack with variables and shaders; unlinking and direct replacement are supported; `styles[key]: null` uses the same consumer-safe removal rule | +| Grid style | apply/import/create/edit/delete `GridStyle` | **Supported**: apply by local ID, imported key, or local authoring key to frames, authored components, component sets, slots, and instances. One result can create/adopt and edit name, Markdown/link metadata, and the complete ordered Grid stack with variables; unlinking and direct replacement are supported; `styles[key]: null` uses the same consumer-safe removal rule | + +`backgroundStyleId` is the deprecated frame-background alias of the fill-style link, not a separate +visual capability. Style bindings are preflighted by exact style type. Repeating a binding is a +no-op; omitting an existing style preserves the link. + +## Document organization + +| Capability | Figma Design state | Current `apply_canvas` status | +| ---------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| Page name | page `name` | **Supported** exactly on the page containing the result | +| Page canvas background | page `backgrounds` | **Supported** for Figma's single solid color, including alpha | +| Page variable modes | page explicit modes | **Supported** for set and null-clear | +| Page guides | page `guides` | **Supported** | +| Frame guides | frame-container/instance `guides` | **Supported** | +| Page identity | existing local `PageNode` | **Supported** by exact ID or a stable `pageKey`; an explicit ID can adopt a key and conflicting identities fail closed | +| Page creation | new `PageNode` | **Supported** for a missing named `pageKey` in create mode; the new page receives any declared root and becomes active with empty selection | +| Page order | position under `DocumentNode` | **Supported** through an exact zero-based `page.index`; omission preserves an existing position | + +## Consequence for the result language + +Restricted HTML and deterministic Tailwind utility classes cover the common linear UI composition path. They cannot +faithfully encode every row above without turning class syntax into a second Figma API. + +The result language keeps: + +- HTML for hierarchy, plain text, linear Auto Layout, basic sizing, and common literal appearance; +- design-system bindings for stable component, variable, and style identities; +- small typed Figma-native fields for state with no honest HTML/CSS equivalent, such as component + instances, authored reusable components and variant sets, variable modes, masks, intrinsic + groups, non-destructive Boolean operations, and vector geometry. + +Unknown fields must continue to fail closed until their mapping and reconciliation semantics are +implemented. diff --git a/docs/extension/mcp-canvas-authoring-design.md b/docs/extension/mcp-canvas-authoring-design.md new file mode 100644 index 00000000..79c4281b --- /dev/null +++ b/docs/extension/mcp-canvas-authoring-design.md @@ -0,0 +1,847 @@ +# MCP canvas authoring + +Status: implemented + +## Decision + +TemPad Dev gives an agent one declarative authoring language and keeps Figma operations inside the +extension: + +```txt +task intent + -> ground unresolved material design decisions in user / project / skill / research evidence + -> optional page-only apply_canvas create/activate when a fresh page is requested + -> optionally delegate isolated evidence, asset, inventory, or QA work + -> choose reuse or direct resources from the user's constraints + -> design-system authoring only when requested or established by the resolved plan + -> optional get_design_system() for permitted existing-resource reuse, or scope: fonts for environment availability + -> optional exact skill reference for authored Figma-only resources + -> optionally consume exact live component ids returned by earlier canvas work + -> apply_canvas(desired result) + -> resolve refs and resource classes + validate + -> diff latest canvas + -> one undoable native patch + -> structural verification + -> optional get_screenshot validation +``` + +The model never emits Plugin API calls or an operation sequence. It describes the result once. +TemPad Dev chooses the safe operations against the latest live document. + +User constraints govern routing. A request to avoid the file's design system skips +resource-catalog discovery, `catalogId`, catalog tags, and catalog refs. Environment-only +`get_design_system({ scope: 'fonts' })` remains available. Creating new local variables, +styles, or components also does not require a catalog. The agent creates them only when requested +or established as part of the resolved deliverable. A verified Direct result does not require an +unsolicited resource pass. Detailed modeling guidance and executable resource shapes remain in +progressive references rather than the core skill or server instructions. + +A current-page-only evidence constraint also keeps the agent from inspecting other pages or using +pre-existing file resources. It does not redefine Figma's file-wide variable, style, or authoring +identity scopes, and it does not prevent the extension from performing the file-wide identity +checks required for safe reconciliation. + +The model-visible surface includes these tools: + +- `set_design_anchor` binds an active task to an exact existing Frame without moving + the viewport; the first created top-level Frame otherwise anchors automatically. + The region stays stable until explicitly changed; beginning a task needs no anchor. +- `begin_design` binds one design task to the selected file/session with an idle lease; +- `end_design` releases the task after delivery or cancellation; + +- `get_code` reads visible design as implementation evidence; +- `get_structure` reads hierarchy and geometry when composition is ambiguous, exposes stable + authoring keys for managed nodes when an update resumes without prior call context, and can + optionally return compact live mask, IMAGE paint, layout-grid, and frame-guide state; +- `get_design_system` conditionally reads deterministic resource catalogs or bounded available-font queries; +- `apply_canvas` creates, updates, removes, or activates exact pages and managed roots and is the + only design-result/context mutating tool; +- `upload_asset` stores a programmatically composed generated PNG/JPEG/GIF data URL in the Hub and + returns only a content hash for a later Canvas IMAGE declaration; +- `get_screenshot` returns bounded visual evidence only when pixels affect the next decision. + +Related calls carry the returned task ID. The runtime owns status, expiry, safe +takeover, and optional DOM placement feedback; the agent does not report progress. +See [design tasks](mcp-design-tasks.md) for the lifecycle and execution boundaries. + +## Why this is the right level + +UI models have strong priors for HTML, common utility classes, and component props. They have much +weaker priors for large Figma node graphs and long imperative Plugin API traces. The public language +therefore uses: + +- `div` for frame-like composition; +- `span` for editable text; +- returned custom tags for real Figma component instances; +- a strict Tailwind utility subset for common layout and appearance, including native default + spacing, sizing, border, radius, opacity, rotation, and typography scales plus exact arbitrary + pixel/color values; +- CSS custom-property utility syntax mapped to exact variable identities, and `type-*` utility + classes mapped to native TextStyle identities; +- a typed `figma` extension for native state that HTML cannot represent honestly. + +This is one dialect, not parallel “simple” and “advanced” languages. The native extension is an +escape hatch inside the same desired-result document. The agent pays for advanced detail only when +the task needs it. + +Custom component tags are better than generic TemPad primitives because they are both familiar to +models and specific to the active design system. A returned `.

@@ -275,6 +289,7 @@ function getCopyTitle(action: AgentIntegrationAction): string { } .tp-agent-dialog-nav { + min-height: 0; padding: var(--spacer-1) 0; border-right: 1px solid var(--color-border); overflow-y: auto; @@ -306,6 +321,7 @@ function getCopyTitle(action: AgentIntegrationAction): string { .tp-agent-dialog-content { min-width: 0; + min-height: 0; padding: var(--spacer-3); overflow-y: auto; } diff --git a/packages/extension/components/Code.vue b/packages/extension/components/Code.vue index 42cbb976..b5408d19 100644 --- a/packages/extension/components/Code.vue +++ b/packages/extension/components/Code.vue @@ -36,16 +36,12 @@ const prismRevision = shallowRef(0) const code = computed(() => props.code.replace(STRIP_TRAILING_WS_RE, '')) -const lang = computed(() => { - if (prismAlias[props.lang]) { - return prismAlias[props.lang] - } - - return props.lang -}) +const lang = computed(() => prismAlias[props.lang] || props.lang) const highlighted = computed(() => { - const Prism = prismRevision.value >= 0 ? window.Prism : window.Prism + // Recompute after asynchronously loaded grammars become available. + void prismRevision.value + const Prism = window.Prism if (!Prism || !Prism.languages[lang.value]) { return escapeHTML(code.value) } diff --git a/packages/extension/components/DesignTaskFeedback.vue b/packages/extension/components/DesignTaskFeedback.vue new file mode 100644 index 00000000..04e774c8 --- /dev/null +++ b/packages/extension/components/DesignTaskFeedback.vue @@ -0,0 +1,1479 @@ + + +