Skip to main content

handbook

The CoDesign design loop, tool contract, workspace cheatsheet, typeface schema, common operations cheatsheet, and the full design-quality rubric. **Read this skill before any edit call** — it contains the 5-step Loop (decide parent → read API → exec → preview → judge), the tool roster and cross-tool rules, the workspace revision model (list / history / rename), rewind-recovery procedure, the typeface shape text.font declarations need, and §6: the design-rules index — the full enforceable rubric (typography, hierarchy, composition, craft) ships as this skill's design-rules.md, the runtime-quirk reference as its quirks.md, and the input-resolution contract every skill follows as its intake.md, all read on demand. Triggered for any task using this server's `edit` or `preview` tools.

Informações da origem

Repositório
imgly/codesign
Última atividade na origem
2 de outubro de 2026 às 13:32
Idioma detectado do SKILL.md
inglês
Estrelas
42
Forks
0

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
7 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
handbook
description
The CoDesign design loop, tool contract, workspace cheatsheet, typeface schema, common operations cheatsheet, and the full design-quality rubric. **Read this skill before any edit call** — it contains the 5-step Loop (decide parent → read API → exec → preview → judge), the tool roster and cross-tool rules, the workspace revision model (list / history / rename), rewind-recovery procedure, the typeface shape text.font declarations need, and §6: the design-rules index — the full enforceable rubric (typography, hierarchy, composition, craft) ships as this skill's design-rules.md, the runtime-quirk reference as its quirks.md, and the input-resolution contract every skill follows as its intake.md, all read on demand. Triggered for any task using this server's `edit` or `preview` tools.
## 1. Loop You MUST follow these steps in order for ANY canvas change: 1. **Decide where you're editing from — based on what the user asked for, not what's in the workspace.** Either: - **New design requested** (the default in a fresh conversation) → pass `parent: null` and supply a `title` (the design name). The workspace persists across all past conversations — designs in it are not yours to continue unless the user points at them. For a new design, run the `create` skill's intake first to assemble the brief — and when two or more of the five design-defining parameters (topic, audience, visual direction, brand, format) are neither stated nor safely inferable, that intake **asks** before this edit rather than defaulting them. - **Continuing this conversation's design** → use the `revision` id from your last `edit` response as `parent`. - **User explicitly asked to resume earlier work** ("keep working on yesterday's flyer") → call `list` to see designs newest-first, then `history({ revision })` on the design they meant; pass the leaf as `parent`. Never do this unprompted. 2. **Read the API docs** for every engine method you plan to use. `../api/SKILL.md` for signatures, `../guide/SKILL.md` for prose and recipes. NEVER guess parameters. **Read ALL remaining references in ONE message**, in parallel: the `api` and `judge` skills and `design-rules.md` (+ `quirks.md`/`fonts.md` if needed, the `models` skill before any `asset_generate`). 3. **Register the brief's acceptance checklist** (first edit only). Extract the machine-checkable claims from the brief and record them: `checklist({ revision, items })` — `{ kind: 'output', path }` for every file the brief orders delivered, `{ kind: 'copy', text }` for every string of approved copy that must land verbatim (translations, offers, legal lines), `{ kind: 'note', text }` for constraints only you can check. Every `export` verifies the list and reports unmet items — treat one like a failing test. Skip this step only when the brief fixes no outputs or copy. 4. **Run `edit({ parent, code, note? })`** — execute the JS body. The response's first text part is JSON `{ revision, parent }` — save `revision`; it's your `parent` for the next edit. 5. **Visually verify.** A mutating `edit`'s result already shows the changed page — read that render. Call `preview({ blockIds, revision })` only for full-size judging or multi-page looks; never re-preview a rendered revision. Never tell the user something "looks good" without seeing it yourself. 6. **Judge & remediate before reporting done.** When the design is a candidate for "done", run the `judge` loop: score the 8 axes against your actual `preview` renders, dry-run the §6.1.11 + §6.5.2 checklists (design-rules.md), remediate any applicable axis below 8 via further `edit`s, re-preview, re-judge. On pass, record `scorecard({ revision, verdict: 'pass' })`; later content `edit`s re-arm this step. Never report an unjudged design as done. Steps 1, 2, 5, and 6 are NOT optional. Step 4's `note` is encouraged: a one-liner describing what you accomplished, so you can re-ground later. **Resolve your inputs before step 3, whichever skill you are in.** Derive what the request already answers, ask **once** for what is genuinely missing, echo what you resolved, never invent a value that belongs to the user — a brand colour, a licensed font, a locale's wording. Ask through your environment's own question UI when it has one; a design's visual direction and brand are never silently defaulted on a first build. The contract is this skill's `intake.md` (`intake.md`); `create`, `brand`, `resize` and `localize` each carry the parameter table it applies to. `judge` alone asks nothing — it is the gate on every build. ### Speak the user's language **Reply in whatever language the user writes to you in.** From their first message, and in everything they read: prose, questions, option labels and subtext, the resolved-input echo, preview remarks, error explanations, the close. Switch if they switch. Not a translation step at the end — the language you work in. **Two languages, not one.** The language you _speak_ and the language the design _contains_ are different axes, and conflating them is the failure mode here: - **Conversation language** — always mirrors the user. No exceptions. - **Design copy** — follows the brief. When the user has stated or implied a language for the content, that wins outright: someone writing to you in German may well want an English poster, and an English speaker may ask for an Arabic edition. Only when nothing implies otherwise does design copy **default** to the conversation's language — and when it does, say so in the echo ("Textsprache: Deutsch"), so a wrong guess costs one word to correct. - Changing an existing design's content language is never a side effect of the conversation — that is the `localize` skill, on request. **Never translate these**, in any language, because they are values rather than copy: skill and tool names (`judge`, `asset_generate`); typed argument values; format ids and sizes (`ig-story`, `A4`, `1080×1350`); colour values; URLs, handles and channel names (`#showcase`); and revision ids. Translate a chip's **label**, never its **value** — a translated value breaks the call it feeds. **These documents stay English.** Every skill, handbook section and reference file is agent-facing instruction, not user-facing copy. Read them in English; speak to the user in theirs. The copy grammar in `../create/choice-copy.md` — system-POV headers, verb-led titles, no pronouns in titles, lists parallel within themselves — applies in whatever language you are writing. ### Re-grounding after a rewind / restart If your conversation was rewound (double-ESC in Claude Code), or your process restarted mid-conversation, your in-memory "current revision" is wrong. The engine's state is the truth, but the server can't tell you've been rewound. Recovery: 1. Call `list` — see the workspace's designs and their `latestLeaf` revisions. 2. Call `history({ revision: latestLeaf })` — read the notes to find where the user wanted to be. 3. Pass that revision id as `parent` on your next `edit`. The server reloads the engine to that scene before running your code — your edits land on top of the right state. Re-grounding recovers the design this conversation was already working on. It is not for starting a new conversation — a fresh session with a new request starts at `parent: null`. Editing on top of an OLDER revision (not the latest leaf) is fine: it creates a **non-destructive fork**. The previous leaves stay in storage; you can switch back any time by passing one of their ids as `parent`. ## 2. Tools Each tool's full contract lives on the tool itself — its description in tools/list is authoritative and always in front of you. This section is only the roster plus the rules that span tools. - `edit({ parent, code, title?, note? })` — THE mutating tool: runs async JS (`engine` in scope, plus `engine.design` — the preferred facade: awaited `create` for a block or subtree, `setProps`/`getProps`, `measure`, `align`/`distribute`; full contract in the api skill) and commits a revision. The response's first text part is JSON `{ revision, parent }` — save `revision`; it is your `parent` for the next edit. - `preview({ blockIds, revision })` — render blocks to inline PNGs; omit `blockIds` for every page (max 10). - `export({ format, revision, blockId?, outPath? })` — write a deliverable (`pdf`/`png`/`jpeg`/`webp`/`svg`/`pdfx`/`html`, or `imgly` to stay editable); omit `blockId` for the whole document; returns `{ uri, httpUrl, bytes, format, revision }` (+ `path` with `outPath`). `uri` is the durable handle; `httpUrl` is process-scoped — never persist it. Pass `outPath` (absolute) when your environment cannot fetch localhost URLs. Full contract on the tool itself. - `export` also accepts `format: "mp4"` — renders the block's authored timeline (recipe: `video.md`); needs the native engine (the default). - `import({ source, title? })` — ingest a design FILE as a NEW root (was `load`): native `.imgly` (also legacy `.scene` / `.zip`), foreign Photoshop `.psd` / InDesign `.idml` / PowerPoint `.pptx` / PDF (translated in; `warnings` are your touch-up list — preview, then repair with `edit`), or a plain image/SVG (one page sized to it). Continue with `edit({ parent: revision })`. - `asset_add({ source: { path } })` — bring a local file (image or font) into the workspace for use in a design (was `import`); embed the returned `workspace://` uri in `edit` code — never a fetch/file URL, and never the original local path or a `file://` URI (renders server-side but breaks portability). - `asset_search({ sourceId?, query?, page?, perPage? })` — discover and search the engine's asset sources; apply results inside `edit` (the exact patterns are in the tool's description). The `ly.img.workspace.images` source also lists images the human uploaded — searchable by their original filename, newest first. - `list()` / `history({ revision })` / `changes({ revision })` / `inspect({ revision })` / `rename({ revision, title })` — the workspace tools; usage in §3. - `view({ revision, pin? })` — human-facing viewer URL. Print it once; the viewer keeps it live. Cross-tool rules: - **Revision ids are durable, block ids are not.** Everything flows through revisions: `edit` produces one, `preview`/`export` consume one, `history`/`inspect` walk them. Block ids are session-scoped — re-discover blocks in the current engine; never persist or replay literal block ids (see `inspect`'s description). - **The single mutating tool is `edit`.** `asset_add`, `asset_search`, and `view` never change the scene; placement and application always happen inside `edit` code. (`import` is the exception: it creates a new root to `edit` from.) ## 3. Workspace cheatsheet The workspace is your durable memory: every revision you commit via `edit` is there, addressable by id, walkable via `history`. It survives a process restart and a Claude rewind. ``` list() → [{ rootRevision, title, latestLeaf, updatedAt, headOrigin?, headNote? }, …] history({ revision: leaf }) → [{ revision, parent, note?, origin?, createdAt }, …] (root first) changes({ revision }) → { head, state, design, since?, wouldOrphanEditorWork, guidance } (what landed AFTER it) inspect({ revision }) → { revision, parent, note?, origin?, createdAt, title?, code? } edit({ parent: leaf, code }) → linear edit, no engine reload edit({ parent: olderRev, code }) → fork; engine reloads to olderRev first edit({ parent: null, title }) → new design rename({ revision: any, title }) → updates the root title ``` A revision id is a 12-hex-char string. You never construct it; the server hands it back from `edit`. Treat it as opaque. ### Human edits from the browser editor The `view` URL is a full editor. When the human clicks **Save**, their edits land as a normal child revision with `origin: "editor"`, no code, and a note that starts `Edited in the browser editor. Engine-computed diff vs parent:` followed by block-level changes. - **Finding their revision**: `changes({ revision })`, passing the revision you hold — normally the one your last `edit` returned. It tells you whether that revision is still the design head, lists what was written since it (oldest first, each with its `note` and `origin`), and names the revision to build on. Do NOT use `history` for this: it walks _ancestors_, so called with your own last revision it will never show their newer save — and previewing your own last revision renders the pre-edit scene, which looks exactly like "nothing changed". In a fresh conversation you hold no revision to pass; there `list` is the signal — it reports `headOrigin: "editor"` and the `headNote` for a design whose newest revision came from the editor. - **Call `changes` before your first `edit`** of a design the user may have had open in the browser. `edit` REFUSES a parent whose path to the head contains one of their editor saves — building from it would orphan their work on a sibling branch — and the refusal names the revision to pass instead. Pass `fork: true` only when the user explicitly asked you to discard their own browser changes and branch from the older revision. - **That note is authoritative.** It is computed by the engine, not free-typed. Do NOT re-derive it with preview loops or read-only `edit` dumps — that burns your edit budget and mints junk revisions. - **Continue from the human revision**: `edit(parent=<their revision>)`. Their changes are already in that scene. - A `Note: this design has newer revision(s)…` line on an `edit`/`preview`/ `inspect`/`export` result means someone committed after the revision you passed. When that someone is you (your own earlier branch), the note is advisory and the fork is legal; the human's saves come back as the refusal above instead. Unless you are deliberately rewinding, rerun with the newer revision. ## 4. Engine recipes **Dialect rule (enforced): mutations go through `engine.design`** — `create`/`setProps`/`group`/`appendChild`, plus `measure` and `getProps` (incl. `['text.ranges']`). `edit` REJECTS code that mutates via `engine.block.*` (the error lists the equivalents); for a call the facade genuinely lacks, keep it with a `// engine.block: <reason>` comment. Print scenes: `await engine.design.setProps(scene, { scene: { designUnit: 'Millimeter', dpi: 300 } })` once. ### Build ONE complete page per `edit` The unit of work is the **page**: each `edit` emits one complete page — one `engine.design.create` with every block, font and size (it awaits resource loads itself), then positioning. Do **not** split one page's build across calls. Each tool call costs 20–200s of streaming wall time; one ~10000-char call beats three ~3000-char ones. For a **single-page design** that means the entire scene in one `edit` — scene, page, all blocks: ```js // 1. Structure + every block of the page — ONE awaited create call const scene = engine.scene.create('VerticalStack'); const stack = (await engine.design.findByType('stack'))[0]; const page = await engine.design.create( { type: 'page', props: { width: 720, height: 1008 }, children: [ { type: 'text', name: 'title', props: { text: { // A FAMILY name makes create do the Google-Fonts lookup and pick // that weight's file — no findAssets/fonts[0] hairline trap. font: { family: 'Playfair Display', weight: 'bold' }, string: 'Alex & Jordan', fontSize: '48px' }, widthMode: 'Auto', heightMode: 'Auto' } } // ... every other block — all of it in props: ranges via // text: { string, ranges: [{ from, to, color }] } (reshape-safe), // solid panels via fill: { type: 'color', color: { value } } ] }, { parent: stack } ); // create() awaited the subtree's font/image loads — measurements are live. // 2. Position with measured frame dims const [title] = await engine.design.findByName('title'); const { width: w } = await engine.design.measure(title); await engine.design.setProps(title, { position: { x: (720 - w) / 2, y: 250 } }); // ... position everything ... return { type: 'text', text: `page=${page} ready` }; ``` The edit result already carries a render of the changed page — that IS your capture. **One `edit` per page; `preview` only for full-size judging or multi-page review. Then STOP.** **Name every block you may touch again — that is how you find it.** `create` returns only the root id; `create` writes each `name` onto its block and `findByName` resolves it here and in every later edit — re-grounding in one line instead of walking the tree matching strings (which breaks on an NBSP, a line break, or shared copy): ```js const [headline] = await engine.design.findByName('headline'); // [] when nothing matches await engine.design.setProps(headline, { text: { fontSize: '52px' } }); ``` `findText(copy)` / `findAllText(copy)` are in scope too — they fold NBSP/space variants, which a hand-rolled `===` does not. **Unnamed blocks: address by uuid** — every id member also takes a block's `uuid` string, valid across edits and revisions. `getProps(root, { children: true, props: [...] })` reads the subtree as a uuid-keyed node tree; filter it in JS, and `setProps(root, { children: [{ uuid, props }...] })` patches by identity (absent props untouched). ### Multi-page designs: page by page, page 1 first Never emit a multi-page design (carousel, slide deck, brochure) in one giant `edit`. Build it **page by page**, one `edit` per page: 1. **Page 1 is the design-language gate.** The first `edit` builds the scene and page 1 only — it establishes fonts, palette, margins, grid. Check its render before touching page 2: a wrong aesthetic choice caught here costs one page, not N. 2. **Pages 2..N each get their own `edit`.** Each call builds one complete page reusing the design language page 1 proved out. Check each page's render right after building it — the bugs on later pages are content-dependent (a headline that overflows, an image that crops badly), so batching pages just delays discovery. Feed findings forward: if body text at 28px overflowed on page 3, use 26px from page 4 on. 3. **Batching is allowed only for near-identical clones** — templated pages differing by a short label or image swap. Even then, a thrown error mid-call loses every page in the batch; when in doubt, one page per call. Multi-block `preview` follows the same rule: batch renders are for review and final capture, never the build. The objective-bug bar below applies per page: fix an overflow on page 3 with a targeted `edit` to page 3, then re-capture page 3 only.
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub