← vDesignCONTENT HISTORY

Update to vDesign

Snapshot Nov 10, 2026 · 07:22 UTC · version 1.1.0

Collection source: downloaded plugin package.

WHAT CHANGED

Payment or plan references changed

Full description — Now says: (posters, diagrams, slides, illustrations, social posts, web pages, any visual document)

Observed in published text. Live prices and checkout terms have not been verified by this change.

Save vDesign and check future changes in Following.

Up to 3 plugins free · no card required.

All fields and original values.

Full description

Before

Nov 6, 2026 · 00:16 UTC

— posters, slides, hero sections, card grids, any laid-out visual document —

After

Nov 10, 2026 · 07:22 UTC

(posters, diagrams, slides, illustrations, social posts, web pages, any visual document)

Skill instructions

Before

Nov 6, 2026 · 00:16 UTC

— posters, slides, hero sections, card grids, any laid-out visual document — in the .vd DSL. Use when asked to create, change, or read a vDesign document, a .vd file, or when a task involves designing a layout that should stay editable a...

After

Nov 10, 2026 · 07:22 UTC

(posters, diagrams, slides, illustrations, social posts, web pages, any visual document) in the .vd DSL. Use when asked to create, change, or read a vDesign document, a .vd file, or when a task involves designing a layout that should sta...

Supporting files

Before

Nov 6, 2026 · 00:16 UTC

[{"relative_path":"examples/cards.vd","size_in_bytes":1008},{"relative_path":"examples/deck.vd","size_in_bytes":1710},{"relative_path":"examples/hero.vd","size_in_bytes":1020},{"relative_path":"examples/slide.vd","size_in_bytes":577},{"r...

After

Nov 10, 2026 · 07:22 UTC

[{"relative_path":"examples/deck.vd","size_in_bytes":1653},{"relative_path":"examples/diagram.vd","size_in_bytes":1263},{"relative_path":"examples/hero.vd","size_in_bytes":1029},{"relative_path":"examples/promo.vd","size_in_bytes":2120},...

Compare saved observations

Download comparison JSON

SKILL.md text changes

− removed · + added

--- before
+++ after
@@ -1,6 +1,7 @@
 ---
 name: vdesign
-description: Author and edit vDesign documents — posters, slides, hero sections, card grids, any laid-out visual document — in the .vd DSL. Use when asked to create, change, or read a vDesign document, a .vd file, or when a task involves designing a layout that should stay editable and relational rather than being flattened to fixed coordinates.
+description: Author and edit vDesign documents (posters, diagrams, slides, illustrations, social posts, web pages, any visual document) in the .vd DSL. Use when asked to create, change, or read a vDesign document, a .vd file, or when a task involves designing a layout that should stay editable and relational rather than being flattened to fixed coordinates.
+license: CC-BY-4.0 (https://creativecommons.org/licenses/by/4.0/). Credit vDesign.
 ---
 
 # Authoring vDesign documents
@@ -14,6 +15,11 @@
 full of literal coordinates is a worse version of a Figma file. A document of expressions
 and tokens can be edited by changing one number.
 
+## No house style
+
+vDesign draws anything. Design for the medium asked for: a poster is not a web page, so no
+cards, nav bars, buttons or rounded panels unless the person asks.
+
 ## The output contract
 
 Emit **only DSL lines**. No prose before or after, no explanation, no JSON. A fenced block
@@ -21,32 +27,36 @@
 
 ## The grammar in one screen
 
-```
+```vd
 version 4
 kind design
-title "Launch hero"
-$gap = 24
-$accent = #5b5bd6
-$paper = #ffffff
-$highlight = #ffd166
-
-font display = Inter
-  fallback "system-ui, sans-serif"
-
-frame page w=1280 h=720 background=paper
-  rect hero.bg x=$gap y=24 w=(100% - $gap * 2) h=260 fill=accent radius=16
-  text hero.title x=(@hero.bg.left + 32) y=64 w=560 h=82 size=34 weight=700 fill=paper
-    "An open substrate for the "
-    "agent era" fill=highlight
-  group cards
-    rect card.1 x=$gap y=(@hero.bg.bottom + $gap) w=((100% - $gap * 4) / 3) h=200
+title "Jazz night poster"
+$m = 72
+$paper = #f2e8d5
+$accent = #d2462f
+$ink = #1d1a16
+
+font display = Georgia
+  fallback "serif"
+
+frame poster w=1080 h=1350 background=paper
+  ellipse sun x=(parent.cx - self.w / 2) y=150 w=560 h=560 fill=accent
+  text poster.title x=$m y=(@sun.bottom + 56) w=(100% - $m * 2) h=210 font=display size=168 fill=ink
+    "Blue "
+    "Room" italic fill=accent
+  group stars
+    ellipse star.1 x=$m y=$m w=24 h=24 fill=ink
 ```
 
 - **The first lines are the header.** `version 4` and `kind design`. Write both. `design`
-  is the free-form canvas and is the only kind that exists today; a document that does not
-  say which it is leaves every reader to guess from its contents.
+  is the free-form canvas; a document that does not say which it is leaves every reader to
+  guess from its contents. The one other kind is a brand, `version 5` and `kind brand`, which
+  `reference/brand.md` covers — make one only when asked for a brand.
+- **A design in a brand** has a `brand ember@3` line under its title. Read the brand's brief
+  first (`vd_read_brand`), name its roles in paint (`fill=primary`, `background=background`)
+  and never write a colour out, and never write the brand line yourself: `vd_apply_brand` does.
 - **Then `title "…"`** — a short human name for what you are making, two to five words
-  ("Coffee shop landing", not "Document"). It is what the tab shows, so write it before the
+  ("Jazz night poster", not "Document"). It is what the tab shows, so write it before the
   first page: the name should appear while the design is still arriving.
 - **Two spaces of indent is one level.** Indentation is the only nesting.
 - A line is `<type> <id> key=value key=value …`.
@@ -69,9 +79,9 @@
 **1. Write relationships, not coordinates.** This is the difference between a vDesign
 document and a screenshot. Before writing a number, ask what it is derived from.
 
-```
-✗ rect card.2 x=148 y=308 w=395 h=200
-✓ rect card.2 x=(@card.1.right + $gap) y=(prev.y) w=@card.1.w h=200
+```text
+✗ rect step.2 x=416 y=180 w=220 h=88
+✓ rect step.2 x=(@step.1.right + $gap) y=(prev.y) w=@step.1.w h=88
 ```
 
 **2. Put every repeated value in a token first.** A colour used twice, a spacing used
@@ -82,13 +92,13 @@
 document, and a consumer may be rendering your output as it streams. Write `logo` before
 the headline that sits beside it.
 
-**4. Give ids a role, not a number.** `hero.title`, `card.1`, `nav.logo` — an id should be
+**4. Give ids a role, not a number.** `poster.title`, `step.1`, `legend.key`: an id should be
 guessable by someone who has not read the file. Never `node1`, `rect5`.
 
 **5. Text height is authored — estimate it.** Nothing measures glyphs for you. For a box
 of width `w` at font size `size`:
 
-```
+```text
 characters per line ≈ w / (size * 0.5)
 lines               = ceil(length of the text / characters per line)
 h                   = ceil(lines * size * 1.2)
@@ -108,34 +118,59 @@
 coordinate space, so `x=$gap` means `$gap` from _that page's_ left edge and `100%` means
 that page's width. `parent.cx` is that page's centre too, and `parent.left` is `0`, so the
 same line centres something on every page. Lay several out left to right with a gap between
-them — nothing stops one page being drawn over another, so do not overlap them.
+them: nothing stops one page being drawn over another.
+
+**9. Centre a label by giving it the box it sits in, never an offset.** A diagram step's
+name, a badge's number, a stamp's text: same `x y w h` as the shape behind it, then
+`align=center valign=middle`. The renderer centres the line inside the box, so it stays
+centred at any size or font. A guessed `y=(@step.1.top + 14)` is off by a few pixels and
+drifts the moment the shape or the type changes.
 
+```vd
+ellipse step.1 x=$gap y=400 w=200 h=104 fill=accent
+text step.1.label x=@step.1.x y=@step.1.y w=@step.1.w h=@step.1.h align=center valign=middle
+  "Placed"
 ```
-$gap = 24
 
-frame page w=1280 h=720 background=paper
-  rect hero.bg x=$gap y=$gap w=(100% - $gap * 2) h=320 fill=accent
+**10. Draw a repeated part once, as a component.** A footer, frame border or legend that
+appears on several pages is a frame marked `component`, in a row below the pages, and each
+page places an `instance` of it. What one page shows differently is an `override` line under
+that instance, never a copy of the parts:
+
+```vd
+frame foot x=0 y=1000 w=1600 h=64 component
+  text foot.title x=$gap y=0 w=400 h=64 valign=middle
+    "Q3 review"
 
-frame pricing x=1380 w=1280 h=720 background=paper
-  text pricing.title x=$gap y=$gap w=600 h=48 size=34 weight=700
-    "Pricing"
+frame intro x=0 y=0 w=1600 h=900
+  instance intro.foot component=foot x=0 y=(100% - 64)
+
+frame plan x=1700 y=0 w=1600 h=900
+  instance plan.foot component=foot x=0 y=(100% - 64)
+    override foot.title
+      "Plan"
 ```
 
+`reference/nodes.md` has the rest: a part's page id is the instance's id and its own
+(`plan.foot.foot.title`), and references inside a component are written unprefixed.
+
 ## Editing an existing document
 
 When given a document and asked to change it, reply with **statements**, not a new
-document. Five verbs, plus `title` to rename the document:
+document. Five verbs, plus `title` to rename the document and `merge` to make one shape of
+several:
 
-```
-title "Pricing page"
+```vd-patch
+title "Jazz night poster"
 set $gap = 40
-set hero.title size=($display * 1.2) weight=800
-set hero.sub content="A shorter subhead."
-unset hero.sub opacity
-insert rect card.4 after card.3 x=(@card.3.right + $gap) y=(prev.y) w=@card.1.w h=200
-insert frame pricing x=(@page.right + 100) w=@page.w h=@page.h background=paper
-move logo before hero.bg
-delete hero.tagline
+set poster.title size=($display * 1.2) weight=800
+set poster.when content="SATURDAY · 9PM"
+unset poster.where opacity
+insert rect step.4 after step.3 x=(@step.3.right + $gap) y=(prev.y) w=@step.1.w h=88
+insert frame back x=(@poster.right + 100) w=@poster.w h=@poster.h background=paper
+move logo before sun
+delete poster.tagline
+merge union badge.ring badge.dot as badge.mark
 ```
 
 An `insert` with no placement lands on the canvas, which in a multi-page document is
@@ -155,35 +190,58 @@
 
 Two flags come from the person more often than from you: `hidden` (not drawn, export
 included) and `locked` (their pointer passes over it). Keep them as you find them. Hide with
-`set card.2 hidden` only when asked to hide — when asked to remove something, `delete` it,
+`set step.2 hidden` only when asked to hide — when asked to remove something, `delete` it,
 because a hidden node is still in the file for the next reader to wade through. `unset
-card.2 hidden` shows it again.
+step.2 hidden` shows it again.
 
 A top-level frame is a slide when the document is played. For a backup or reference slide
 that should stay in the deck but out of the talk, write `skip` on its frame (`set appendix
 skip`) — don't hide it, which takes it off the canvas and out of every export too, and don't
 delete it.
 
-## Motion
+## Motion and video
 
-Transitions between slides, parts of a slide appearing in order, and buttons that go to
-another slide are a `motion` section after the last page. Only Play reads it: the canvas and
-every export show each page as written, so write the page as it looks when finished and let
-motion say how the presenter gets there.
+How a page moves in time is a `motion` section after the last page: transitions between
+slides, parts of a page appearing in order, links to another page and, for a
+video, words entering one by one, numbers counting up, strokes drawing on and a camera moving
+across the page. The canvas at rest and every still export show each page as written, so write
+the page as it looks when finished and let motion say how it gets there.
 
-```
+```vd
 motion intro enter=fade
-  intro.title enter=rise
+  intro.title enter=rise by=word
   intro.chart enter=fade step
-  intro.cta enter=pop go=#pricing
+  intro.next enter=pop go=#plan
 ```
 
-Add it when the person is making something to present or click through, and keep it light.
-Never copy a page to animate between the copies. `reference/motion.md` has the rest.
+Add it when the person is making something to present, click through or post as a video, and
+keep a deck light. Never copy a page to animate between the copies. A web page taller than a
+screen gets `motion <page> scroll`. A video can have one music track, `music <name>` under its
+header, and `bpm=` to time lines in beats — from the person or the file, never a guess.
+`reference/motion.md` has the rest; read `reference/video.md` before making a video (an ad, a
+promo, a social clip), and check one with `vd_frames`.
+
+## Icons
+
+Never write an icon's path from memory: it is slow, and it comes out roughly right at best.
+Icons come from the Lucide set, about 1,900 line icons, by name.
+
+- **Over MCP**, find one with `vd_search_icon` (`"settings"`, `"notification"`) and place it
+  with `vd_add_icon`, which writes the `vector` for you — the icon's path, Lucide's stroke,
+  round caps. Its `x`, `y` and `size` take expressions, so place an icon by relationship like
+  anything else: `x="(@step.1.right - 32)"`.
+- **In the app**, find one with `search_icons` and get its line with `use_icon`, before you
+  write any DSL; copy that `vector` line into your reply as it comes back.
+- **Where no icon tool is offered**, draw it as a `vector` (`reference/nodes.md`).
+- **Lucide has no brand logos** — GitHub, X, YouTube. A logo is an image the person supplies:
+  leave it as a slot (see Images).
+
+A placed icon is an ordinary vector named `lucide:<name>`. Recolour it with
+`set <id> stroke=…`; resize it with `w` and `h`, and scale `strokeWidth` with them — 2 at 24.
 
 ## Images
 
-A picture is an `image` node that names an asset: `image hero.logo x=40 y=32 w=160 h=48
+A picture is an `image` node that names an asset: `image poster.logo x=40 y=32 w=160 h=48
 src=logo fit=contain`. The asset's registry line (`asset logo = image/png hash=…`) and its
 bytes are **never yours to write** — hashes come from the app. You only ever write `src=`.
 
@@ -198,8 +256,8 @@
   so do not try: write the image anyway, with a `src` nothing supplies yet and a `name`
   saying what goes there:
 
-  ```
-  image nav.logo x=40 y=24 w=120 h=40 src=logo fit=contain name="Your logo"
+  ```vd
+  image poster.logo x=40 y=24 w=120 h=40 src=logo fit=contain name="Your logo"
   ```
 
   The canvas shows it as a labelled box the person drops the file into, whenever they like.
@@ -212,27 +270,43 @@
 
 ## Looking at your work, and exporting
 
-**Over MCP, `vd_export` is how you see what you made.** `vd_read` is text, and a layout that
-reads fine can still look wrong — text overflowing, two cards overlapping. After a build or
+**Over MCP (desktop and CLI), `vd_export` is how you see what you made.** `vd_read` is text, and a layout that
+reads fine can still look wrong: text overflowing, two shapes overlapping. After a build or
 a large edit, export the frame as `png` with `save: false` and look at the picture that comes
 back; fix what you see, then look again.
 
 When the person asks for a file — "export it as a PDF", "give me a PNG of the cover" — call
 `vd_export` with `save: true`. Formats: `png`, `jpg`, `webp`, `svg`, `pdf`, `ai` (Illustrator:
-one artboard of the whole canvas, or `artboards: "frames"` for a file per frame) and `html`.
-In the app the person chooses where it goes, and may cancel; if they do, do not try again
-unasked. Only save when asked — a look is `save: false`.
+one artboard of the whole canvas, or `artboards: "frames"` for a file per frame), `html` and
+`pptx` (PowerPoint: a slide per frame, with shapes and text still editable). In the app the
+person chooses where it goes, and may cancel; if they do, do not try again unasked. Only
+save when asked — a look is `save: false`.
+
+**With no vDesign tools at all** — this skill loaded on its own, by an agent that can write
+files — the design is a file. Write the document to `<title>.vd`, holding exactly the lines
+the output contract describes, and give the person that file. It opens in the vDesign app,
+at getv.design/app, and in the VS Code extension, where they can see it, keep editing it and
+export it to any format above. You cannot look at it first, which is one more reason to
+place everything by relationship and leave text room to breathe. Do not draw it some other
+way to show them: a picture from anything but vDesign is not what the design looks like.
 
 ## Reference
 
-Below, if you are reading this as a flattened system prompt; otherwise alongside this file.
+Each file is named by its path in this skill. Installed as a folder, read them from beside
+this file, never through `vd_skill`; in the flattened system prompt they follow below.
 
 - `reference/grammar.md` — the expression language in full: edges, percentages, relative
-  references, precedence; plus tokens, paint (colours and gradients), fonts and the asset
+  references, precedence; plus tokens, paint (colours, gradients, layers), fonts and the asset
   registry.
 - `reference/nodes.md` — every node type and every property it accepts: `frame`,
-  `canvas`, `rect`, `ellipse`, `vector`, `image`, `text`, `group`.
+  `canvas`, `rect`, `ellipse`, `vector`, `image`, `video`, `text`, `instance`, `connector`,
+  `group`.
 - `reference/edits.md` — the mutation dialect in full.
-- `reference/motion.md` — motion for Play: page transitions, reveals and buttons.
-- `examples/` — complete documents: `hero.vd`, `cards.vd`, `slide.vd`, and `deck.vd`, three
-  pages with motion.
+- `reference/motion.md` — motion: page transitions, reveals, buttons, timing, the camera, beats
+  and music.
+- `reference/video.md` — videos for social media and websites: sizes, storyboards, recipes,
+  cutting to the beat.
+- `reference/brand.md` — brands: a `kind brand` document's roles, logos, rules and guides, how
+  a patch changes one, how one is made, and how a design uses one.
+- `examples/`: complete documents. `diagram.vd`, `slide.vd`, `hero.vd` (a web page),
+  `deck.vd` (three pages with motion), and `promo.vd`, a 9-second video storyboard.
Full technical diff · 3 changed fields

changed /description

BEFORE
"Author and edit vDesign documents — posters, slides, hero sections, card grids, any laid-out visual document — in the .vd DSL. Use when asked to create, change, or read a vDesign document, a .vd file, or when a task involves designing a layout that should stay editable and relational rather than being flattened to fixed coordinates."
AFTER
"Author and edit vDesign documents (posters, diagrams, slides, illustrations, social posts, web pages, any visual document) in the .vd DSL. Use when asked to create, change, or read a vDesign document, a .vd file, or when a task involves designing a layout that should stay editable and relational rather than being flattened to fixed coordinates."

changed /included_files

BEFORE
[
  {
    "relative_path": "examples/cards.vd",
    "size_in_bytes": 1008
  },
  {
    "relative_path": "examples/deck.vd",
    "size_in_bytes": 1710
  },
  {
    "relative_path": "examples/hero.vd",
    "size_in_bytes": 1020
  },
  {
    "relative_path": "examples/slide.vd",
    "size_in_bytes": 577
  },
  {
    "relative_path": "reference/edits.md",
    "size_in_bytes": 4600
  },
  {
    "relative_path": "reference/grammar.md",
    "size_in_bytes": 8090
  },
  {
    "relative_path": "reference/motion.md",
    "size_in_bytes": 4362
  },
  {
    "relative_path": "reference/nodes.md",
    "size_in_bytes": 13100
  }
]
AFTER
[
  {
    "relative_path": "examples/deck.vd",
    "size_in_bytes": 1653
  },
  {
    "relative_path": "examples/diagram.vd",
    "size_in_bytes": 1263
  },
  {
    "relative_path": "examples/hero.vd",
    "size_in_bytes": 1029
  },
  {
    "relative_path": "examples/promo.vd",
    "size_in_bytes": 2120
  },
  {
    "relative_path": "examples/slide.vd",
    "size_in_bytes": 577
  },
  {
    "relative_path": "reference/brand.md",
    "size_in_bytes": 7493
  },
  {
    "relative_path": "reference/edits.md",
    "size_in_bytes": 11182
  },
  {
    "relative_path": "reference/grammar.md",
    "size_in_bytes": 8651
  },
  {
    "relative_path": "reference/motion.md",
    "size_in_bytes": 11592
  },
  {
    "relative_path": "reference/nodes.md",
    "size_in_bytes": 21159
  },
  {
    "relative_path": "reference/video.md",
    "size_in_bytes": 4672
  }
]

changed /skill_md_contents

BEFORE
"---\nname: vdesign\ndescription: Author and edit vDesign documents — posters, slides, hero sections, card grids, any laid-out visual document — in the .vd DSL. Use when asked to create, change, or read a vDesign document, a .vd file, or when a task involves designing a layout that should stay editable and relational rather than being flattened to fixed coordinates.\n---\n\n# Authoring vDesign documents\n\nA vDesign document is a tree of boxes whose geometry is **declarative**. A property holds\neither a number or an expression, and expressions are stored as written and resolved on\nread. `w=(100% - $gap * 2)` stays that formula in the file forever; change `$gap` and\neverything bound to it moves.\n\nThat is the entire point of the format, and it is what you are being asked for. A document\nfull of literal coordinates is a worse version of a Figma file. A document of expressions\nand tokens can be edited by changing one number.\n\n## The output contract\n\nEmit **only DSL lines**. No prose before or after, no explanation, no JSON. A fenced block\nis tolerated but unnecessary.\n\n## The grammar in one screen\n\n```\nversion 4\nkind design\ntitle \"Launch hero\"\n$gap = 24\n$accent = #5b5bd6\n$paper = #ffffff\n$highlight = #ffd166\n\nfont display = Inter\n  fallback \"system-ui, sans-serif\"\n\nframe page w=1280 h=720 background=paper\n  rect hero.bg x=$gap y=24 w=(100% - $gap * 2) h=260 fill=accent radius=16\n  text hero.title x=(@hero.bg.left + 32) y=64 w=560 h=82 size=34 weight=700 fill=paper\n    \"An open substrate for the \"\n    \"agent era\" fill=highlight\n  group cards\n    rect card.1 x=$gap y=(@hero.bg.bottom + $gap) w=((100% - $gap * 4) / 3) h=200\n```\n\n- **The first lines are the header.** `version 4` and `kind design`. Write both. `design`\n  is the free-form canvas and is the only kind that exists today; a document that does not\n  say which it is leaves every reader to guess from its contents.\n- **Then `title \"…\"`** — a short human name for what you are making, two to five words\n  (\"Coffee shop landing\", not \"Document\"). It is what the tab shows, so write it before the\n  first page: the name should appear while the design is still arriving.\n- **Two spaces of indent is one level.** Indentation is the only nesting.\n- A line is `<type> <id> key=value key=value …`.\n- A **quoted line** under a `text` node is one run of its content.\n- A **boolean is a bare flag**: `italic`, never `italic=true`.\n- **There are no comments.** `#` already starts a colour. Anything trailing a value is an\n  error rather than something to ignore, so do not annotate the document.\n\n### The one rule worth memorising\n\n> A value is an **expression** if it starts with `$`, `@`, or `(`. Everything else is a\n> literal.\n\nSo `x=$gap` and `x=@logo.right` need no parentheses, and everything else that is an\nexpression does: `y=(prev.bottom + 12)`, `w=(50%)`, `y=(parent.h / 2)`. A quoted value is\nalways a literal, which is how you write a string that starts with a sigil: `fill=\"$brand\"`.\n\n## Rules that decide whether the output is any good\n\n**1. Write relationships, not coordinates.** This is the difference between a vDesign\ndocument and a screenshot. Before writing a number, ask what it is derived from.\n\n```\n✗ rect card.2 x=148 y=308 w=395 h=200\n✓ rect card.2 x=(@card.1.right + $gap) y=(prev.y) w=@card.1.w h=200\n```\n\n**2. Put every repeated value in a token first.** A colour used twice, a spacing used\nthree times, a type scale — all tokens. `$gap` used eleven times is the compression, and it\nis also the edit surface: \"make it roomier\" becomes one line.\n\n**3. Only reference ids you have already written.** References resolve against the\ndocument, and a consumer may be rendering your output as it streams. Write `logo` before\nthe headline that sits beside it.\n\n**4. Give ids a role, not a number.** `hero.title`, `card.1`, `nav.logo` — an id should be\nguessable by someone who has not read the file. Never `node1`, `rect5`.\n\n**5. Text height is authored — estimate it.** Nothing measures glyphs for you. For a box\nof width `w` at font size `size`:\n\n```\ncharacters per line ≈ w / (size * 0.5)\nlines               = ceil(length of the text / characters per line)\nh                   = ceil(lines * size * 1.2)\n```\n\nRound up. Too small is reported as a `text-overflow` problem; too large just leaves space.\n\n**6. `fill` takes a token name or a CSS colour, never an expression.** `fill=accent`,\n`fill=#5b5bd6`. Sizes and positions bind; colours do not.\n\n**7. A group has no geometry.** It holds children and nothing else — no `x`, `y`, `w`, `h`.\nIts children keep the coordinate space of whatever contains the group, and `parent`, `prev`\nand `next` see straight through it.\n\n**8. A page is a `frame`, and more than one page is more than one frame.** Start the\ndocument with a frame; you do not write a `canvas` line at all. Each frame is its own\ncoordinate space, so `x=$gap` means `$gap` from _that page's_ left edge and `100%` means\nthat page's width. `parent.cx` is that page's centre too, and `parent.left` is `0`, so the\nsame line centres something on every page. Lay several out left to right with a gap between\nthem — nothing stops one page being drawn over another, so do not overlap them.\n\n```\n$gap = 24\n\nframe page w=1280 h=720 background=paper\n  rect hero.bg x=$gap y=$gap w=(100% - $gap * 2) h=320 fill=accent\n\nframe pricing x=1380 w=1280 h=720 background=paper\n  text pricing.title x=$gap y=$gap w=600 h=48 size=34 weight=700\n    \"Pricing\"\n```\n\n## Editing an existing document\n\nWhen given a document and asked to change it, reply with **statements**, not a new\ndocument. Five verbs, plus `title` to rename the document:\n\n```\ntitle \"Pricing page\"\nset $gap = 40\nset hero.title size=($display * 1.2) weight=800\nset hero.sub content=\"A shorter subhead.\"\nunset hero.sub opacity\ninsert rect card.4 after card.3 x=(@card.3.right + $gap) y=(prev.y) w=@card.1.w h=200\ninsert frame pricing x=(@page.right + 100) w=@page.w h=@page.h background=paper\nmove logo before hero.bg\ndelete hero.tagline\n```\n\nAn `insert` with no placement lands on the canvas, which in a multi-page document is\n_beside_ the pages rather than on one. Say `after <id>` or `in <frame>` whenever the new\nnode belongs to a page.\n\nCopy is changed with `set … content=`, or with an indented body when the marks matter.\nNever `delete` and `insert` a text node to reword it — it loses its place and every `@`\nreference to it.\n\nPrefer changing a **token** over changing the nodes that use it — that is usually what the\nrequest actually means. \"More breathing room\" is `set $gap = 40`, not eleven `set`\nstatements.\n\nSee `reference/edits.md` for placement, and for what happens when you delete something\nanother node references.\n\nTwo flags come from the person more often than from you: `hidden` (not drawn, export\nincluded) and `locked` (their pointer passes over it). Keep them as you find them. Hide with\n`set card.2 hidden` only when asked to hide — when asked to remove something, `delete` it,\nbecause a hidden node is still in the file for the next reader to wade through. `unset\ncard.2 hidden` shows it again.\n\nA top-level frame is a slide when the document is played. For a backup or reference slide\nthat should stay in the deck but out of the talk, write `skip` on its frame (`set appendix\nskip`) — don't hide it, which takes it off the canvas and out of every export too, and don't\ndelete it.\n\n## Motion\n\nTransitions between slides, parts of a slide appearing in order, and buttons that go to\nanother slide are a `motion` section after the last page. Only Play reads it: the canvas and\nevery export show each page as written, so write the page as it looks when finished and let\nmotion say how the presenter gets there.\n\n```\nmotion intro enter=fade\n  intro.title enter=rise\n  intro.chart enter=fade step\n  intro.cta enter=pop go=#pricing\n```\n\nAdd it when the person is making something to present or click through, and keep it light.\nNever copy a page to animate between the copies. `reference/motion.md` has the rest.\n\n## Images\n\nA picture is an `image` node that names an asset: `image hero.logo x=40 y=32 w=160 h=48\nsrc=logo fit=contain`. The asset's registry line (`asset logo = image/png hash=…`) and its\nbytes are **never yours to write** — hashes come from the app. You only ever write `src=`.\n\n- **In the app**, images the person attached are offered by name at the top of the request\n  (\"Images you can put in the design\"). Place one with `src=<that name>`; an edit uses\n  `insert image <id> in <frame> …`. Size it to the image's aspect ratio, and prefer\n  `fit=contain` for a logo.\n- **Over MCP**, a picture at a public URL goes in with `vd_add_asset` first, then you place\n  it. `vd_assets` lists what a document already has.\n- **A picture you cannot send** — one the person gave you in chat, or has on their machine —\n  becomes a **slot**. You cannot pass on an image you can see, and no tool reads file paths,\n  so do not try: write the image anyway, with a `src` nothing supplies yet and a `name`\n  saying what goes there:\n\n  ```\n  image nav.logo x=40 y=24 w=120 h=40 src=logo fit=contain name=\"Your logo\"\n  ```\n\n  The canvas shows it as a labelled box the person drops the file into, whenever they like.\n  Size and place it as if the picture were there, carry on with the design, and tell them\n  where it is (\"drop your logo onto the box in the top-left\"). Every image with the same\n  `src` fills together. `vd_assets` lists the slots still waiting.\n\nA `src` naming nothing reports `missing-asset`. That is what a slot is, so do not \"fix\" it by\ndeleting the image; do fix a `src` you simply misspelled.\n\n## Looking at your work, and exporting\n\n**Over MCP, `vd_export` is how you see what you made.** `vd_read` is text, and a layout that\nreads fine can still look wrong — text overflowing, two cards overlapping. After a build or\na large edit, export the frame as `png` with `save: false` and look at the picture that comes\nback; fix what you see, then look again.\n\nWhen the person asks for a file — \"export it as a PDF\", \"give me a PNG of the cover\" — call\n`vd_export` with `save: true`. Formats: `png`, `jpg`, `webp`, `svg`, `pdf`, `ai` (Illustrator:\none artboard of the whole canvas, or `artboards: \"frames\"` for a file per frame) and `html`.\nIn the app the person chooses where it goes, and may cancel; if they do, do not try again\nunasked. Only save when asked — a look is `save: false`.\n\n## Reference\n\nBelow, if you are reading this as a flattened system prompt; otherwise alongside this file.\n\n- `reference/grammar.md` — the expression language in full: edges, percentages, relative\n  references, precedence; plus tokens, paint (colours and gradients), fonts and the asset\n  registry.\n- `reference/nodes.md` — every node type and every property it accepts: `frame`,\n  `canvas`, `rect`, `ellipse`, `vector`, `image`, `text`, `group`.\n- `reference/edits.md` — the mutation dialect in full.\n- `reference/motion.md` — motion for Play: page transitions, reveals and buttons.\n- `examples/` — complete documents: `hero.vd`, `cards.vd`, `slide.vd`, and `deck.vd`, three\n  pages with motion.\n"
AFTER
"---\nname: vdesign\ndescription: Author and edit vDesign documents (posters, diagrams, slides, illustrations, social posts, web pages, any visual document) in the .vd DSL. Use when asked to create, change, or read a vDesign document, a .vd file, or when a task involves designing a layout that should stay editable and relational rather than being flattened to fixed coordinates.\nlicense: CC-BY-4.0 (https://creativecommons.org/licenses/by/4.0/). Credit vDesign.\n---\n\n# Authoring vDesign documents\n\nA vDesign document is a tree of boxes whose geometry is **declarative**. A property holds\neither a number or an expression, and expressions are stored as written and resolved on\nread. `w=(100% - $gap * 2)` stays that formula in the file forever; change `$gap` and\neverything bound to it moves.\n\nThat is the entire point of the format, and it is what you are being asked for. A document\nfull of literal coordinates is a worse version of a Figma file. A document of expressions\nand tokens can be edited by changing one number.\n\n## No house style\n\nvDesign draws anything. Design for the medium asked for: a poster is not a web page, so no\ncards, nav bars, buttons or rounded panels unless the person asks.\n\n## The output contract\n\nEmit **only DSL lines**. No prose before or after, no explanation, no JSON. A fenced block\nis tolerated but unnecessary.\n\n## The grammar in one screen\n\n```vd\nversion 4\nkind design\ntitle \"Jazz night poster\"\n$m = 72\n$paper = #f2e8d5\n$accent = #d2462f\n$ink = #1d1a16\n\nfont display = Georgia\n  fallback \"serif\"\n\nframe poster w=1080 h=1350 background=paper\n  ellipse sun x=(parent.cx - self.w / 2) y=150 w=560 h=560 fill=accent\n  text poster.title x=$m y=(@sun.bottom + 56) w=(100% - $m * 2) h=210 font=display size=168 fill=ink\n    \"Blue \"\n    \"Room\" italic fill=accent\n  group stars\n    ellipse star.1 x=$m y=$m w=24 h=24 fill=ink\n```\n\n- **The first lines are the header.** `version 4` and `kind design`. Write both. `design`\n  is the free-form canvas; a document that does not say which it is leaves every reader to\n  guess from its contents. The one other kind is a brand, `version 5` and `kind brand`, which\n  `reference/brand.md` covers — make one only when asked for a brand.\n- **A design in a brand** has a `brand ember@3` line under its title. Read the brand's brief\n  first (`vd_read_brand`), name its roles in paint (`fill=primary`, `background=background`)\n  and never write a colour out, and never write the brand line yourself: `vd_apply_brand` does.\n- **Then `title \"…\"`** — a short human name for what you are making, two to five words\n  (\"Jazz night poster\", not \"Document\"). It is what the tab shows, so write it before the\n  first page: the name should appear while the design is still arriving.\n- **Two spaces of indent is one level.** Indentation is the only nesting.\n- A line is `<type> <id> key=value key=value …`.\n- A **quoted line** under a `text` node is one run of its content.\n- A **boolean is a bare flag**: `italic`, never `italic=true`.\n- **There are no comments.** `#` already starts a colour. Anything trailing a value is an\n  error rather than something to ignore, so do not annotate the document.\n\n### The one rule worth memorising\n\n> A value is an **expression** if it starts with `$`, `@`, or `(`. Everything else is a\n> literal.\n\nSo `x=$gap` and `x=@logo.right` need no parentheses, and everything else that is an\nexpression does: `y=(prev.bottom + 12)`, `w=(50%)`, `y=(parent.h / 2)`. A quoted value is\nalways a literal, which is how you write a string that starts with a sigil: `fill=\"$brand\"`.\n\n## Rules that decide whether the output is any good\n\n**1. Write relationships, not coordinates.** This is the difference between a vDesign\ndocument and a screenshot. Before writing a number, ask what it is derived from.\n\n```text\n✗ rect step.2 x=416 y=180 w=220 h=88\n✓ rect step.2 x=(@step.1.right + $gap) y=(prev.y) w=@step.1.w h=88\n```\n\n**2. Put every repeated value in a token first.** A colour used twice, a spacing used\nthree times, a type scale — all tokens. `$gap` used eleven times is the compression, and it\nis also the edit surface: \"make it roomier\" becomes one line.\n\n**3. Only reference ids you have already written.** References resolve against the\ndocument, and a consumer may be rendering your output as it streams. Write `logo` before\nthe headline that sits beside it.\n\n**4. Give ids a role, not a number.** `poster.title`, `step.1`, `legend.key`: an id should be\nguessable by someone who has not read the file. Never `node1`, `rect5`.\n\n**5. Text height is authored — estimate it.** Nothing measures glyphs for you. For a box\nof width `w` at font size `size`:\n\n```text\ncharacters per line ≈ w / (size * 0.5)\nlines               = ceil(length of the text / characters per line)\nh                   = ceil(lines * size * 1.2)\n```\n\nRound up. Too small is reported as a `text-overflow` problem; too large just leaves space.\n\n**6. `fill` takes a token name or a CSS colour, never an expression.** `fill=accent`,\n`fill=#5b5bd6`. Sizes and positions bind; colours do not.\n\n**7. A group has no geometry.** It holds children and nothing else — no `x`, `y`, `w`, `h`.\nIts children keep the coordinate space of whatever contains the group, and `parent`, `prev`\nand `next` see straight through it.\n\n**8. A page is a `frame`, and more than one page is more than one frame.** Start the\ndocument with a frame; you do not write a `canvas` line at all. Each frame is its own\ncoordinate space, so `x=$gap` means `$gap` from _that page's_ left edge and `100%` means\nthat page's width. `parent.cx` is that page's centre too, and `parent.left` is `0`, so the\nsame line centres something on every page. Lay several out left to right with a gap between\nthem: nothing stops one page being drawn over another.\n\n**9. Centre a label by giving it the box it sits in, never an offset.** A diagram step's\nname, a badge's number, a stamp's text: same `x y w h` as the shape behind it, then\n`align=center valign=middle`. The renderer centres the line inside the box, so it stays\ncentred at any size or font. A guessed `y=(@step.1.top + 14)` is off by a few pixels and\ndrifts the moment the shape or the type changes.\n\n```vd\nellipse step.1 x=$gap y=400 w=200 h=104 fill=accent\ntext step.1.label x=@step.1.x y=@step.1.y w=@step.1.w h=@step.1.h align=center valign=middle\n  \"Placed\"\n```\n\n**10. Draw a repeated part once, as a component.** A footer, frame border or legend that\nappears on several pages is a frame marked `component`, in a row below the pages, and each\npage places an `instance` of it. What one page shows differently is an `override` line under\nthat instance, never a copy of the parts:\n\n```vd\nframe foot x=0 y=1000 w=1600 h=64 component\n  text foot.title x=$gap y=0 w=400 h=64 valign=middle\n    \"Q3 review\"\n\nframe intro x=0 y=0 w=1600 h=900\n  instance intro.foot component=foot x=0 y=(100% - 64)\n\nframe plan x=1700 y=0 w=1600 h=900\n  instance plan.foot component=foot x=0 y=(100% - 64)\n    override foot.title\n      \"Plan\"\n```\n\n`reference/nodes.md` has the rest: a part's page id is the instance's id and its own\n(`plan.foot.foot.title`), and references inside a component are written unprefixed.\n\n## Editing an existing document\n\nWhen given a document and asked to change it, reply with **statements**, not a new\ndocument. Five verbs, plus `title` to rename the document and `merge` to make one shape of\nseveral:\n\n```vd-patch\ntitle \"Jazz night poster\"\nset $gap = 40\nset poster.title size=($display * 1.2) weight=800\nset poster.when content=\"SATURDAY · 9PM\"\nunset poster.where opacity\ninsert rect step.4 after step.3 x=(@step.3.right + $gap) y=(prev.y) w=@step.1.w h=88\ninsert frame back x=(@poster.right + 100) w=@poster.w h=@poster.h background=paper\nmove logo before sun\ndelete poster.tagline\nmerge union badge.ring badge.dot as badge.mark\n```\n\nAn `insert` with no placement lands on the canvas, which in a multi-page document is\n_beside_ the pages rather than on one. Say `after <id>` or `in <frame>` whenever the new\nnode belongs to a page.\n\nCopy is changed with `set … content=`, or with an indented body when the marks matter.\nNever `delete` and `insert` a text node to reword it — it loses its place and every `@`\nreference to it.\n\nPrefer changing a **token** over changing the nodes that use it — that is usually what the\nrequest actually means. \"More breathing room\" is `set $gap = 40`, not eleven `set`\nstatements.\n\nSee `reference/edits.md` for placement, and for what happens when you delete something\nanother node references.\n\nTwo flags come from the person more often than from you: `hidden` (not drawn, export\nincluded) and `locked` (their pointer passes over it). Keep them as you find them. Hide with\n`set step.2 hidden` only when asked to hide — when asked to remove something, `delete` it,\nbecause a hidden node is still in the file for the next reader to wade through. `unset\nstep.2 hidden` shows it again.\n\nA top-level frame is a slide when the document is played. For a backup or reference slide\nthat should stay in the deck but out of the talk, write `skip` on its frame (`set appendix\nskip`) — don't hide it, which takes it off the canvas and out of every export too, and don't\ndelete it.\n\n## Motion and video\n\nHow a page moves in time is a `motion` section after the last page: transitions between\nslides, parts of a page appearing in order, links to another page and, for a\nvideo, words entering one by one, numbers counting up, strokes drawing on and a camera moving\nacross the page. The canvas at rest and every still export show each page as written, so write\nthe page as it looks when finished and let motion say how it gets there.\n\n```vd\nmotion intro enter=fade\n  intro.title enter=rise by=word\n  intro.chart enter=fade step\n  intro.next enter=pop go=#plan\n```\n\nAdd it when the person is making something to present, click through or post as a video, and\nkeep a deck light. Never copy a page to animate between the copies. A web page taller than a\nscreen gets `motion <page> scroll`. A video can have one music track, `music <name>` under its\nheader, and `bpm=` to time lines in beats — from the person or the file, never a guess.\n`reference/motion.md` has the rest; read `reference/video.md` before making a video (an ad, a\npromo, a social clip), and check one with `vd_frames`.\n\n## Icons\n\nNever write an icon's path from memory: it is slow, and it comes out roughly right at best.\nIcons come from the Lucide set, about 1,900 line icons, by name.\n\n- **Over MCP**, find one with `vd_search_icon` (`\"settings\"`, `\"notification\"`) and place it\n  with `vd_add_icon`, which writes the `vector` for you — the icon's path, Lucide's stroke,\n  round caps. Its `x`, `y` and `size` take expressions, so place an icon by relationship like\n  anything else: `x=\"(@step.1.right - 32)\"`.\n- **In the app**, find one with `search_icons` and get its line with `use_icon`, before you\n  write any DSL; copy that `vector` line into your reply as it comes back.\n- **Where no icon tool is offered**, draw it as a `vector` (`reference/nodes.md`).\n- **Lucide has no brand logos** — GitHub, X, YouTube. A logo is an image the person supplies:\n  leave it as a slot (see Images).\n\nA placed icon is an ordinary vector named `lucide:<name>`. Recolour it with\n`set <id> stroke=…`; resize it with `w` and `h`, and scale `strokeWidth` with them — 2 at 24.\n\n## Images\n\nA picture is an `image` node that names an asset: `image poster.logo x=40 y=32 w=160 h=48\nsrc=logo fit=contain`. The asset's registry line (`asset logo = image/png hash=…`) and its\nbytes are **never yours to write** — hashes come from the app. You only ever write `src=`.\n\n- **In the app**, images the person attached are offered by name at the top of the request\n  (\"Images you can put in the design\"). Place one with `src=<that name>`; an edit uses\n  `insert image <id> in <frame> …`. Size it to the image's aspect ratio, and prefer\n  `fit=contain` for a logo.\n- **Over MCP**, a picture at a public URL goes in with `vd_add_asset` first, then you place\n  it. `vd_assets` lists what a document already has.\n- **A picture you cannot send** — one the person gave you in chat, or has on their machine —\n  becomes a **slot**. You cannot pass on an image you can see, and no tool reads file paths,\n  so do not try: write the image anyway, with a `src` nothing supplies yet and a `name`\n  saying what goes there:\n\n  ```vd\n  image poster.logo x=40 y=24 w=120 h=40 src=logo fit=contain name=\"Your logo\"\n  ```\n\n  The canvas shows it as a labelled box the person drops the file into, whenever they like.\n  Size and place it as if the picture were there, carry on with the design, and tell them\n  where it is (\"drop your logo onto the box in the top-left\"). Every image with the same\n  `src` fills together. `vd_assets` lists the slots still waiting.\n\nA `src` naming nothing reports `missing-asset`. That is what a slot is, so do not \"fix\" it by\ndeleting the image; do fix a `src` you simply misspelled.\n\n## Looking at your work, and exporting\n\n**Over MCP (desktop and CLI), `vd_export` is how you see what you made.** `vd_read` is text, and a layout that\nreads fine can still look wrong: text overflowing, two shapes overlapping. After a build or\na large edit, export the frame as `png` with `save: false` and look at the picture that comes\nback; fix what you see, then look again.\n\nWhen the person asks for a file — \"export it as a PDF\", \"give me a PNG of the cover\" — call\n`vd_export` with `save: true`. Formats: `png`, `jpg`, `webp`, `svg`, `pdf`, `ai` (Illustrator:\none artboard of the whole canvas, or `artboards: \"frames\"` for a file per frame), `html` and\n`pptx` (PowerPoint: a slide per frame, with shapes and text still editable). In the app the\nperson chooses where it goes, and may cancel; if they do, do not try again unasked. Only\nsave when asked — a look is `save: false`.\n\n**With no vDesign tools at all** — this skill loaded on its own, by an agent that can write\nfiles — the design is a file. Write the document to `<title>.vd`, holding exactly the lines\nthe output contract describes, and give the person that file. It opens in the vDesign app,\nat getv.design/app, and in the VS Code extension, where they can see it, keep editing it and\nexport it to any format above. You cannot look at it first, which is one more reason to\nplace everything by relationship and leave text room to breathe. Do not draw it some other\nway to show them: a picture from anything but vDesign is not what the design looks like.\n\n## Reference\n\nEach file is named by its path in this skill. Installed as a folder, read them from beside\nthis file, never through `vd_skill`; in the flattened system prompt they follow below.\n\n- `reference/grammar.md` — the expression language in full: edges, percentages, relative\n  references, precedence; plus tokens, paint (colours, gradients, layers), fonts and the asset\n  registry.\n- `reference/nodes.md` — every node type and every property it accepts: `frame`,\n  `canvas`, `rect`, `ellipse`, `vector`, `image`, `video`, `text`, `instance`, `connector`,\n  `group`.\n- `reference/edits.md` — the mutation dialect in full.\n- `reference/motion.md` — motion: page transitions, reveals, buttons, timing, the camera, beats\n  and music.\n- `reference/video.md` — videos for social media and websites: sizes, storyboards, recipes,\n  cutting to the beat.\n- `reference/brand.md` — brands: a `kind brand` document's roles, logos, rules and guides, how\n  a patch changes one, how one is made, and how a design uses one.\n- `examples/`: complete documents. `diagram.vd`, `slide.vd`, `hero.vd` (a web page),\n  `deck.vd` (three pages with motion), and `promo.vd`, a 9-second video storyboard.\n"
Full snapshot data
{
  "description": "Author and edit vDesign documents (posters, diagrams, slides, illustrations, social posts, web pages, any visual document) in the .vd DSL. Use when asked to create, change, or read a vDesign document, a .vd file, or when a task involves designing a layout that should stay editable and relational rather than being flattened to fixed coordinates.",
  "included_files": [
    {
      "relative_path": "examples/deck.vd",
      "size_in_bytes": 1653
    },
    {
      "relative_path": "examples/diagram.vd",
      "size_in_bytes": 1263
    },
    {
      "relative_path": "examples/hero.vd",
      "size_in_bytes": 1029
    },
    {
      "relative_path": "examples/promo.vd",
      "size_in_bytes": 2120
    },
    {
      "relative_path": "examples/slide.vd",
      "size_in_bytes": 577
    },
    {
      "relative_path": "reference/brand.md",
      "size_in_bytes": 7493
    },
    {
      "relative_path": "reference/edits.md",
      "size_in_bytes": 11182
    },
    {
      "relative_path": "reference/grammar.md",
      "size_in_bytes": 8651
    },
    {
      "relative_path": "reference/motion.md",
      "size_in_bytes": 11592
    },
    {
      "relative_path": "reference/nodes.md",
      "size_in_bytes": 21159
    },
    {
      "relative_path": "reference/video.md",
      "size_in_bytes": 4672
    }
  ],
  "name": "vdesign",
  "skill_md_contents": "---\nname: vdesign\ndescription: Author and edit vDesign documents (posters, diagrams, slides, illustrations, social posts, web pages, any visual document) in the .vd DSL. Use when asked to create, change, or read a vDesign document, a .vd file, or when a task involves designing a layout that should stay editable and relational rather than being flattened to fixed coordinates.\nlicense: CC-BY-4.0 (https://creativecommons.org/licenses/by/4.0/). Credit vDesign.\n---\n\n# Authoring vDesign documents\n\nA vDesign document is a tree of boxes whose geometry is **declarative**. A property holds\neither a number or an expression, and expressions are stored as written and resolved on\nread. `w=(100% - $gap * 2)` stays that formula in the file forever; change `$gap` and\neverything bound to it moves.\n\nThat is the entire point of the format, and it is what you are being asked for. A document\nfull of literal coordinates is a worse version of a Figma file. A document of expressions\nand tokens can be edited by changing one number.\n\n## No house style\n\nvDesign draws anything. Design for the medium asked for: a poster is not a web page, so no\ncards, nav bars, buttons or rounded panels unless the person asks.\n\n## The output contract\n\nEmit **only DSL lines**. No prose before or after, no explanation, no JSON. A fenced block\nis tolerated but unnecessary.\n\n## The grammar in one screen\n\n```vd\nversion 4\nkind design\ntitle \"Jazz night poster\"\n$m = 72\n$paper = #f2e8d5\n$accent = #d2462f\n$ink = #1d1a16\n\nfont display = Georgia\n  fallback \"serif\"\n\nframe poster w=1080 h=1350 background=paper\n  ellipse sun x=(parent.cx - self.w / 2) y=150 w=560 h=560 fill=accent\n  text poster.title x=$m y=(@sun.bottom + 56) w=(100% - $m * 2) h=210 font=display size=168 fill=ink\n    \"Blue \"\n    \"Room\" italic fill=accent\n  group stars\n    ellipse star.1 x=$m y=$m w=24 h=24 fill=ink\n```\n\n- **The first lines are the header.** `version 4` and `kind design`. Write both. `design`\n  is the free-form canvas; a document that does not say which it is leaves every reader to\n  guess from its contents. The one other kind is a brand, `version 5` and `kind brand`, which\n  `reference/brand.md` covers — make one only when asked for a brand.\n- **A design in a brand** has a `brand ember@3` line under its title. Read the brand's brief\n  first (`vd_read_brand`), name its roles in paint (`fill=primary`, `background=background`)\n  and never write a colour out, and never write the brand line yourself: `vd_apply_brand` does.\n- **Then `title \"…\"`** — a short human name for what you are making, two to five words\n  (\"Jazz night poster\", not \"Document\"). It is what the tab shows, so write it before the\n  first page: the name should appear while the design is still arriving.\n- **Two spaces of indent is one level.** Indentation is the only nesting.\n- A line is `<type> <id> key=value key=value …`.\n- A **quoted line** under a `text` node is one run of its content.\n- A **boolean is a bare flag**: `italic`, never `italic=true`.\n- **There are no comments.** `#` already starts a colour. Anything trailing a value is an\n  error rather than something to ignore, so do not annotate the document.\n\n### The one rule worth memorising\n\n> A value is an **expression** if it starts with `$`, `@`, or `(`. Everything else is a\n> literal.\n\nSo `x=$gap` and `x=@logo.right` need no parentheses, and everything else that is an\nexpression does: `y=(prev.bottom + 12)`, `w=(50%)`, `y=(parent.h / 2)`. A quoted value is\nalways a literal, which is how you write a string that starts with a sigil: `fill=\"$brand\"`.\n\n## Rules that decide whether the output is any good\n\n**1. Write relationships, not coordinates.** This is the difference between a vDesign\ndocument and a screenshot. Before writing a number, ask what it is derived from.\n\n```text\n✗ rect step.2 x=416 y=180 w=220 h=88\n✓ rect step.2 x=(@step.1.right + $gap) y=(prev.y) w=@step.1.w h=88\n```\n\n**2. Put every repeated value in a token first.** A colour used twice, a spacing used\nthree times, a type scale — all tokens. `$gap` used eleven times is the compression, and it\nis also the edit surface: \"make it roomier\" becomes one line.\n\n**3. Only reference ids you have already written.** References resolve against the\ndocument, and a consumer may be rendering your output as it streams. Write `logo` before\nthe headline that sits beside it.\n\n**4. Give ids a role, not a number.** `poster.title`, `step.1`, `legend.key`: an id should be\nguessable by someone who has not read the file. Never `node1`, `rect5`.\n\n**5. Text height is authored — estimate it.** Nothing measures glyphs for you. For a box\nof width `w` at font size `size`:\n\n```text\ncharacters per line ≈ w / (size * 0.5)\nlines               = ceil(length of the text / characters per line)\nh                   = ceil(lines * size * 1.2)\n```\n\nRound up. Too small is reported as a `text-overflow` problem; too large just leaves space.\n\n**6. `fill` takes a token name or a CSS colour, never an expression.** `fill=accent`,\n`fill=#5b5bd6`. Sizes and positions bind; colours do not.\n\n**7. A group has no geometry.** It holds children and nothing else — no `x`, `y`, `w`, `h`.\nIts children keep the coordinate space of whatever contains the group, and `parent`, `prev`\nand `next` see straight through it.\n\n**8. A page is a `frame`, and more than one page is more than one frame.** Start the\ndocument with a frame; you do not write a `canvas` line at all. Each frame is its own\ncoordinate space, so `x=$gap` means `$gap` from _that page's_ left edge and `100%` means\nthat page's width. `parent.cx` is that page's centre too, and `parent.left` is `0`, so the\nsame line centres something on every page. Lay several out left to right with a gap between\nthem: nothing stops one page being drawn over another.\n\n**9. Centre a label by giving it the box it sits in, never an offset.** A diagram step's\nname, a badge's number, a stamp's text: same `x y w h` as the shape behind it, then\n`align=center valign=middle`. The renderer centres the line inside the box, so it stays\ncentred at any size or font. A guessed `y=(@step.1.top + 14)` is off by a few pixels and\ndrifts the moment the shape or the type changes.\n\n```vd\nellipse step.1 x=$gap y=400 w=200 h=104 fill=accent\ntext step.1.label x=@step.1.x y=@step.1.y w=@step.1.w h=@step.1.h align=center valign=middle\n  \"Placed\"\n```\n\n**10. Draw a repeated part once, as a component.** A footer, frame border or legend that\nappears on several pages is a frame marked `component`, in a row below the pages, and each\npage places an `instance` of it. What one page shows differently is an `override` line under\nthat instance, never a copy of the parts:\n\n```vd\nframe foot x=0 y=1000 w=1600 h=64 component\n  text foot.title x=$gap y=0 w=400 h=64 valign=middle\n    \"Q3 review\"\n\nframe intro x=0 y=0 w=1600 h=900\n  instance intro.foot component=foot x=0 y=(100% - 64)\n\nframe plan x=1700 y=0 w=1600 h=900\n  instance plan.foot component=foot x=0 y=(100% - 64)\n    override foot.title\n      \"Plan\"\n```\n\n`reference/nodes.md` has the rest: a part's page id is the instance's id and its own\n(`plan.foot.foot.title`), and references inside a component are written unprefixed.\n\n## Editing an existing document\n\nWhen given a document and asked to change it, reply with **statements**, not a new\ndocument. Five verbs, plus `title` to rename the document and `merge` to make one shape of\nseveral:\n\n```vd-patch\ntitle \"Jazz night poster\"\nset $gap = 40\nset poster.title size=($display * 1.2) weight=800\nset poster.when content=\"SATURDAY · 9PM\"\nunset poster.where opacity\ninsert rect step.4 after step.3 x=(@step.3.right + $gap) y=(prev.y) w=@step.1.w h=88\ninsert frame back x=(@poster.right + 100) w=@poster.w h=@poster.h background=paper\nmove logo before sun\ndelete poster.tagline\nmerge union badge.ring badge.dot as badge.mark\n```\n\nAn `insert` with no placement lands on the canvas, which in a multi-page document is\n_beside_ the pages rather than on one. Say `after <id>` or `in <frame>` whenever the new\nnode belongs to a page.\n\nCopy is changed with `set … content=`, or with an indented body when the marks matter.\nNever `delete` and `insert` a text node to reword it — it loses its place and every `@`\nreference to it.\n\nPrefer changing a **token** over changing the nodes that use it — that is usually what the\nrequest actually means. \"More breathing room\" is `set $gap = 40`, not eleven `set`\nstatements.\n\nSee `reference/edits.md` for placement, and for what happens when you delete something\nanother node references.\n\nTwo flags come from the person more often than from you: `hidden` (not drawn, export\nincluded) and `locked` (their pointer passes over it). Keep them as you find them. Hide with\n`set step.2 hidden` only when asked to hide — when asked to remove something, `delete` it,\nbecause a hidden node is still in the file for the next reader to wade through. `unset\nstep.2 hidden` shows it again.\n\nA top-level frame is a slide when the document is played. For a backup or reference slide\nthat should stay in the deck but out of the talk, write `skip` on its frame (`set appendix\nskip`) — don't hide it, which takes it off the canvas and out of every export too, and don't\ndelete it.\n\n## Motion and video\n\nHow a page moves in time is a `motion` section after the last page: transitions between\nslides, parts of a page appearing in order, links to another page and, for a\nvideo, words entering one by one, numbers counting up, strokes drawing on and a camera moving\nacross the page. The canvas at rest and every still export show each page as written, so write\nthe page as it looks when finished and let motion say how it gets there.\n\n```vd\nmotion intro enter=fade\n  intro.title enter=rise by=word\n  intro.chart enter=fade step\n  intro.next enter=pop go=#plan\n```\n\nAdd it when the person is making something to present, click through or post as a video, and\nkeep a deck light. Never copy a page to animate between the copies. A web page taller than a\nscreen gets `motion <page> scroll`. A video can have one music track, `music <name>` under its\nheader, and `bpm=` to time lines in beats — from the person or the file, never a guess.\n`reference/motion.md` has the rest; read `reference/video.md` before making a video (an ad, a\npromo, a social clip), and check one with `vd_frames`.\n\n## Icons\n\nNever write an icon's path from memory: it is slow, and it comes out roughly right at best.\nIcons come from the Lucide set, about 1,900 line icons, by name.\n\n- **Over MCP**, find one with `vd_search_icon` (`\"settings\"`, `\"notification\"`) and place it\n  with `vd_add_icon`, which writes the `vector` for you — the icon's path, Lucide's stroke,\n  round caps. Its `x`, `y` and `size` take expressions, so place an icon by relationship like\n  anything else: `x=\"(@step.1.right - 32)\"`.\n- **In the app**, find one with `search_icons` and get its line with `use_icon`, before you\n  write any DSL; copy that `vector` line into your reply as it comes back.\n- **Where no icon tool is offered**, draw it as a `vector` (`reference/nodes.md`).\n- **Lucide has no brand logos** — GitHub, X, YouTube. A logo is an image the person supplies:\n  leave it as a slot (see Images).\n\nA placed icon is an ordinary vector named `lucide:<name>`. Recolour it with\n`set <id> stroke=…`; resize it with `w` and `h`, and scale `strokeWidth` with them — 2 at 24.\n\n## Images\n\nA picture is an `image` node that names an asset: `image poster.logo x=40 y=32 w=160 h=48\nsrc=logo fit=contain`. The asset's registry line (`asset logo = image/png hash=…`) and its\nbytes are **never yours to write** — hashes come from the app. You only ever write `src=`.\n\n- **In the app**, images the person attached are offered by name at the top of the request\n  (\"Images you can put in the design\"). Place one with `src=<that name>`; an edit uses\n  `insert image <id> in <frame> …`. Size it to the image's aspect ratio, and prefer\n  `fit=contain` for a logo.\n- **Over MCP**, a picture at a public URL goes in with `vd_add_asset` first, then you place\n  it. `vd_assets` lists what a document already has.\n- **A picture you cannot send** — one the person gave you in chat, or has on their machine —\n  becomes a **slot**. You cannot pass on an image you can see, and no tool reads file paths,\n  so do not try: write the image anyway, with a `src` nothing supplies yet and a `name`\n  saying what goes there:\n\n  ```vd\n  image poster.logo x=40 y=24 w=120 h=40 src=logo fit=contain name=\"Your logo\"\n  ```\n\n  The canvas shows it as a labelled box the person drops the file into, whenever they like.\n  Size and place it as if the picture were there, carry on with the design, and tell them\n  where it is (\"drop your logo onto the box in the top-left\"). Every image with the same\n  `src` fills together. `vd_assets` lists the slots still waiting.\n\nA `src` naming nothing reports `missing-asset`. That is what a slot is, so do not \"fix\" it by\ndeleting the image; do fix a `src` you simply misspelled.\n\n## Looking at your work, and exporting\n\n**Over MCP (desktop and CLI), `vd_export` is how you see what you made.** `vd_read` is text, and a layout that\nreads fine can still look wrong: text overflowing, two shapes overlapping. After a build or\na large edit, export the frame as `png` with `save: false` and look at the picture that comes\nback; fix what you see, then look again.\n\nWhen the person asks for a file — \"export it as a PDF\", \"give me a PNG of the cover\" — call\n`vd_export` with `save: true`. Formats: `png`, `jpg`, `webp`, `svg`, `pdf`, `ai` (Illustrator:\none artboard of the whole canvas, or `artboards: \"frames\"` for a file per frame), `html` and\n`pptx` (PowerPoint: a slide per frame, with shapes and text still editable). In the app the\nperson chooses where it goes, and may cancel; if they do, do not try again unasked. Only\nsave when asked — a look is `save: false`.\n\n**With no vDesign tools at all** — this skill loaded on its own, by an agent that can write\nfiles — the design is a file. Write the document to `<title>.vd`, holding exactly the lines\nthe output contract describes, and give the person that file. It opens in the vDesign app,\nat getv.design/app, and in the VS Code extension, where they can see it, keep editing it and\nexport it to any format above. You cannot look at it first, which is one more reason to\nplace everything by relationship and leave text room to breathe. Do not draw it some other\nway to show them: a picture from anything but vDesign is not what the design looks like.\n\n## Reference\n\nEach file is named by its path in this skill. Installed as a folder, read them from beside\nthis file, never through `vd_skill`; in the flattened system prompt they follow below.\n\n- `reference/grammar.md` — the expression language in full: edges, percentages, relative\n  references, precedence; plus tokens, paint (colours, gradients, layers), fonts and the asset\n  registry.\n- `reference/nodes.md` — every node type and every property it accepts: `frame`,\n  `canvas`, `rect`, `ellipse`, `vector`, `image`, `video`, `text`, `instance`, `connector`,\n  `group`.\n- `reference/edits.md` — the mutation dialect in full.\n- `reference/motion.md` — motion: page transitions, reveals, buttons, timing, the camera, beats\n  and music.\n- `reference/video.md` — videos for social media and websites: sizes, storyboards, recipes,\n  cutting to the beat.\n- `reference/brand.md` — brands: a `kind brand` document's roles, logos, rules and guides, how\n  a patch changes one, how one is made, and how a design uses one.\n- `examples/`: complete documents. `diagram.vd`, `slide.vd`, `hero.vd` (a web page),\n  `deck.vd` (three pages with motion), and `promo.vd`, a 9-second video storyboard.\n"
}

SHA-256 of public snapshot: df1bbecd50724802baeb5b5b286ed480866eb685161221ab6a1a0108e4bff984