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.

Quellinformationen

Repository
imgly/codesign
Letzte Quellaktivität
2. Oktober 2026 um 13:32
Erkannte Sprache von SKILL.md
Englisch
Sterne
42
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
7 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
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.
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen