{"id":81836,"plugin_id":"plugin_asdk_app_6ad7a6e23400819198e9cc963ee1da61","kind":"skill","collection_source":"plugin_package","comparison_source":null,"observed_at":"2026-11-05T01:19:12.670Z","digest":"865f301d43095584e60a1753155e67984525c54b91670d219610978ccde97b36","against":null,"payload":{"description":"Make designs on the Visual Sandbox canvas with `vsb design` (or the `create_design` MCP tool): web pages, app screens, cards, posters and vector drawings, organized in named layers like a Figma file, and exported as HTML, React, SVG or PNG. Trigger when the user wants to \"design a page\", \"mock up a screen\", \"make a landing page / hero / card\", \"make this UI\" or \"rebuild this page\" from a screenshot, \"draw a picture or an illustration in code\", \"make an SVG by drawing it\", \"put a design on the canvas\", \"export it to React\", or points at a layer they picked on the canvas (\"change this button\"). Free: nothing is generated and nothing is billed.\n","included_files":[{"relative_path":"agents/openai.yaml","size_in_bytes":280},{"relative_path":"references/drawing.md","size_in_bytes":4054}],"name":"vsb-design","skill_md_contents":"---\nname: vsb-design\ndescription: >\n  Make designs on the Visual Sandbox canvas with `vsb design` (or the\n  `create_design` MCP tool): web pages, app screens, cards, posters and vector\n  drawings, organized in named layers like a Figma file, and exported as HTML,\n  React, SVG or PNG. Trigger when the user wants to \"design a page\", \"mock up\n  a screen\", \"make a landing page / hero / card\", \"make this UI\" or\n  \"rebuild this page\" from a screenshot, \"draw a picture or an\n  illustration in code\", \"make an SVG by drawing it\", \"put a design on the\n  canvas\", \"export it to React\", or points at a layer they picked on the\n  canvas (\"change this button\"). Free: nothing is generated and nothing is\n  billed.\nlicense: Proprietary. See LICENSE for the terms.\n---\n\n# Design on the canvas\n\nA design is **one HTML document on the canvas**, drawn at 1:1 like a frame in\nFigma. A page, a screen and a card are HTML and CSS. A drawing is one `<svg>`.\n**A layer is an element with a `data-name` attribute**, and the layer tree is\nhow those elements nest. The person sees the tree beside the canvas, hovers a\nlayer to outline it, and picks one to point at it.\n\nThe canvas, the HTML export and the React export are drawn by the same\nbrowser engine from the same document, so they match pixel for pixel.\n\n```bash\nvsb design new hero.html --name \"Landing hero\" --width 1440 --height 900\nvsb design export \"Landing hero\" -f png -o hero.png   # look at it, then fix it\nvsb design update \"Landing hero\" hero.html --version 1\nvsb design export \"Landing hero\" -f react             # landing-hero.jsx\n```\n\n## The loop\n\n1. Write the file: `page.html`, or `drawing.js` for a drawing. Build a page\n   with more than one section in sections (see below).\n2. `vsb design new <file> --name \"<what it is>\" --width <px> --height <px>`.\n3. `vsb design export <design> -f png -o check.png`, and **look at the PNG**.\n   Read it with your image tool. Never report a design you have not looked at.\n   Read the `warnings` the write printed too.\n4. Fix what is wrong, then `vsb design update <design> <file> --version <n>`.\n5. Give the person the canvas link the command printed.\n\n`<design>` is the node uuid or the design's name. `--version` is the version\nyou last read. When the person changed the design since, the write is refused\nwith a 409: read it again (`vsb design get`) and apply your change to that.\n\n**The person edits by hand too.** On the canvas they reorder layers inside\nauto layout and by dragging rows in the layer tree, move and resize layers\n(with snapping), type into text, rename and delete layers, set auto layout\nand Fixed / Hug / Fill in a panel, align layers in their frame, resize the\nartboard, and undo with Cmd+Z. A hand move is a `translate`, and a resize is\n`width` and `height`, in the layer's `style`. Keep what they did: read the\ndesign before you change it, and always pass `--version`.\n\n## Build a page in sections\n\nThe canvas shows each write in less than two seconds. Put a page on it one\nsection at a time, so the person sees it grow and can stop you early.\n\n1. Write the outline: the whole `<style>` block, the root, and one empty\n   frame for each section, each with its `data-name`.\n2. `vsb design new outline.html`, then give the person the canvas link.\n3. Write the sections from top to bottom, one file each. The root element\n   of the file carries the `data-name` of its section.\n4. `vsb design update Home hero.html --layer Hero --version <n>` for each\n   section. Each write adds one to the version.\n5. Export the PNG after the last section, and look at it.\n\n```html\n<style>\n  /* Every class of every section. A layer write replaces only its element,\n     so this block stays as the outline wrote it. */\n</style>\n<div class=\"page\" data-name=\"Home\">\n  <nav class=\"nav\" data-name=\"Nav\"></nav>\n  <section class=\"hero\" data-name=\"Hero\"></section>\n  <section class=\"features\" data-name=\"Features\"></section>\n  <footer class=\"footer\" data-name=\"Footer\"></footer>\n</div>\n```\n\nA card, a screen or a drawing is one write. Over MCP, the order is the same:\n`create_design`, then `update_design` with `layer`.\n\n## Commands\n\n| Command | Does |\n|---|---|\n| `vsb design` | List the designs on this canvas |\n| `vsb design new <file>` | Put a design on the canvas. `.html`, `.svg`, a `.js` drawing, or `-` for stdin |\n| `vsb design layers [design]` | Print the layer tree, with each layer's index and kind. The picked layer is marked |\n| `vsb design get [design]` | Print the HTML. `--layer <path>` prints one layer, `--layer picked` the one the person picked. `-o file` writes it |\n| `vsb design update <design> <file>` | Replace the design. `--layer <path>` replaces one layer only |\n| `vsb design move <design> --layer <path> --before\\|--after\\|--into <path>` | Rearrange: move one layer to another place. Nothing else is rewritten |\n| `vsb design export [design] -f html\\|react\\|svg\\|png` | Save a file. `--scale 2` for a retina PNG. PNG needs Chrome. `--layer <path>` saves one frame alone as html |\n| `vsb design delete <design>` | Delete the design and its node. No undo, so name the design; it never means the picked one |\n\n`[design]` may be left out on the commands that read: it is then the design\nthe person picked or selected on the canvas.\n\nA layer is found by its index (`12`), its path (`Hero/Body/CTAs`), the end of\nits path (`Body/CTAs`), or its name (`CTAs`). Two layers with the same name is\nan error that lists both: pass the index or a longer path.\n\n## Layers: every part a person can see\n\nThe layer tree is how the person reads your design and how they tell you what\nto change, so name it the way a designer names a Figma file.\n\n- **Every part a person can see is its own layer:** each shape, each line,\n  each dot, each icon, each piece of text. Three tick marks are three layers,\n  not one layer that holds three unnamed `<i>` elements.\n- **A shape with words in it is two layers:** the shape, and a text layer\n  inside it. Write `<a data-name=\"Primary\"><span data-name=\"Text\">Buy</span></a>`,\n  not `<a data-name=\"Primary\">Buy</a>`. The same goes for a key and its\n  legend, a pill and its label, a keycap and its letter.\n- **Never draw with `::before` or `::after`.** A pseudo-element is not a\n  layer, so the person cannot pick it. Draw the part as an element.\n- Leave a name off only a wrapper that does layout and draws nothing, and a\n  run of words inside one line (an `<em>` in a headline).\n- **Nest the names the way the design is built:** `Hero` holds `Nav` and\n  `Body`, `Body` holds `Copy` and `IDE`, `Copy` holds `Headline` and `CTAs`.\n- **Use short nouns in title case:** `Headline`, `Primary`, `Logos`, `Price`.\n  Name by role, not by look: `Primary`, not `Orange button`.\n- A landing page has 100 layers or more. That is correct.\n\n**Every write answers with `warnings`:** each part that is drawn but is not a\nlayer. Name each one and update the design before you report it.\n\nThe kind comes from the element: an element with its own words is `text`, an\n`<img>` is `image`, an SVG shape is `vector`, an SVG `<g>` is `group`, and\nanything else that holds layers is `frame`.\n\n## Auto layout: build every frame with flexbox\n\nThe canvas reads flexbox and grid as auto layout, the way Figma does. The\nperson resizes a button and expects its label to stay in the middle, so lay\nthe design out with flexbox, not with coordinates.\n\n- **The page is a column, and each row is a row.** The root is\n  `display: flex; flex-direction: column`. A nav with centred links is a\n  three-column grid: `grid-template-columns: 1fr auto 1fr`.\n- **A button centres what is in it:** `display: flex; align-items: center;\n  justify-content: center`. The same goes for a badge, a key and a tag.\n- **A box with words in it hugs them:** size a button, a badge, a tag or a\n  card with `padding`, never a px `width`. The layout panel shows it as Hug,\n  and it grows and shrinks with its text. Give a px size only to a part\n  whose size is fixed by what it shows: a keycap, an icon, an artboard.\n- **A part with a face inside it pads the face.** For a keycap, write\n  `display: flex; padding: 3px 26px 40px 11px` on the cap and `flex: 1` on\n  the face, not `position: absolute` on the face.\n- **Space siblings with `gap`.** Use a margin only where one distance is\n  different from the others.\n- **Use `position: absolute` only for a part that floats free:** a sticker, a\n  tilted illustration, a decoration that overlaps other parts. To nudge a\n  part in a row, use `translate`, the same as a hand move on the canvas.\n\n## Write the HTML so it draws the same everywhere\n\n- **Send the body, not a page:** a `<style>` block, then one root element the\n  size of the artboard. `vsb` wraps it in the page. A full page also works.\n- **Style the root element, not `body`.** The React export has no `<body>`,\n  so a `body { }` rule does not reach it.\n- **Set `font-family` on the root.** Load web fonts with an `@import` from\n  Google Fonts as the first line of the `<style>` block.\n- **Use `px` at the artboard size.** Set `box-sizing: border-box` on the root\n  and its descendants.\n- **Classes in the `<style>` block, not Tailwind.** Nothing runs in a design,\n  so Tailwind classes resolve to nothing.\n- **No scripts, no forms, no event handlers.** Nothing runs; the export drops them.\n- **Images by `https` URL.** Generate a picture with `vsb run` first, then put\n  its URL in an `<img>` layer. A logo or an icon can be an inline `<svg>`: name each shape in it.\n\nCommon artboards: 1440 × 900 (desktop hero), 1440 × 3200 (desktop page),\n390 × 844 (phone screen), 1080 × 1080 (square post), 1080 × 1350 (portrait post).\n\n## Auto layout: Figma's words in CSS\n\nAuto layout is flexbox. The person's layout panel writes exactly this, so\nwrite the same when they ask in Figma's words:\n\n| They say | Write |\n|---|---|\n| Auto layout, horizontal / vertical | `display: flex; flex-direction: row` / `column` |\n| Wrap | `flex-wrap: wrap` |\n| Spacing between items | `gap: 16px` |\n| Padding | `padding: 24px 32px` |\n| Align (the 3 × 3 grid) | `justify-content` along the flow, `align-items` across it |\n| Space between | `justify-content: space-between` |\n| Hug contents | `width: fit-content`, and `flex: none` along a flex parent's flow |\n| Fill container | along the parent's flow `flex: 1 1 0; min-width: 0`; across it `align-self: stretch`; with no auto layout `width: 100%` |\n| Fixed width | `width: 240px`, and `flex: none` along the flow |\n| Align left / centre / right in the frame | the frame's alignment; or `align-self` across the flow, `margin: auto` along it |\n| Absolute position | avoid it: it is a `translate` in code. Change the layout instead |\n\nBuild every page from auto layout frames, not from offsets: then the\nperson's drags reorder the layers, the export reads like hand-written CSS,\nand nothing breaks when a text grows. A `translate` on a layer is a hand\nmove the person made; keep it unless they ask.\n\n## Change one layer\n\nRead the layer, change it, and write back only it. The rest of the document\nstays byte for byte, and a big design does not travel twice.\n\n```bash\nvsb design get \"Landing hero\" --layer CTAs -o ctas.html\n# edit ctas.html — keep data-name=\"CTAs\" on its root element\nvsb design update \"Landing hero\" ctas.html --layer CTAs --version 4\n```\n\nThe file replaces the whole layer element, the tag with its `data-name`\nincluded. To add a layer, replace its parent. To delete one, replace it with\nan empty file.\n\n## What the person picked\n\nThe person picks a frame on the canvas: a double-click on it, or a click on\nits row in the layer tree. \"Make this bigger\", \"change this\", \"move this\nunder the headline\" mean that frame.\n\n```bash\nvsb design get --layer picked -o part.html   # the picked frame, from the selected design\n# prints: Wrote part.html  layer Hero/Body/CTAs, v7\nvsb design update <design> part.html --layer Hero/Body/CTAs --version 7\n```\n\nRead with `picked`, then **write to the path the read printed, never to\n`picked`**: the person may pick another frame while you work, and a write to\n`picked` would land on it. The server refuses `picked` in a write.\n`vsb sandbox selection --json` shows the same pick as `layer`.\n\n## Rearrange\n\nMove a layer to another place without rewriting its parent:\n\n```bash\nvsb design move Home --layer Hero/Logos --before Hero/CTAs --version 7\nvsb design move Home --layer Footer/Links --into Hero/Nav --version 8\n```\n\n`--before` and `--after` put it beside another layer; `--into` puts it last\ninside one. Only the layer's place in the HTML changes, so in a flex or grid\nbox the layout reflows around it. A layer cannot move into itself.\n\n## Drawings\n\nA `.js` file is a drawing. Its default export gets a Canvas 2D context, and\n`vsb` records every call as SVG, so the result is a vector file that you can\nalso draw on a `<canvas>`. The file runs on your machine; nothing runs on the\nserver.\n\n```js\nexport const width = 1080, height = 1080, name = \"Cat plate\";\nexport default function draw(g, { layer }) {\n  layer(\"Background\", () => { g.fillStyle = \"#e7c9a2\"; g.fillRect(0, 0, width, height); });\n  layer(\"Cat\", () => { layer(\"Head\", drawHead); layer(\"Body\", drawBody); });\n}\n```\n\n`layer(name, fn)` wraps what `fn` draws in `<g data-name>`: a layer on the\ncanvas. Read [references/drawing.md](references/drawing.md) before the first\ndrawing. It has the calls that work, the ones that are refused, and the craft\nthat makes a code drawing look drawn by hand.\n\n**Pick the tool by the job.** A page or a screen is HTML: the browser lays it\nout. An illustration with many organic shapes is a `.js` drawing: math makes\nthe geometry. An icon or a logo is a hand-written `<svg>`, or a vector model\n(see `vsb-vector`). Never type long SVG path data by hand for organic shapes;\ncompute it.\n\n## Exports\n\n| Format | What it is |\n|---|---|\n| `html` | The page exactly as the canvas draws it. Open it in a browser |\n| `react` | One component in a `.jsx` file. The same pixels at the same size |\n| `svg` | The drawing, when the design is one `<svg>` element |\n| `png` | A screenshot through the local Chrome. `--scale 2` doubles the pixels |\n\n`--layer <path>` (or `--layer picked`) saves one frame alone as an html\npage: the hero, the nav, one card. The frame keeps the styles, fonts and\nCSS variables it gets from the frames above it, and its place in its\nparent (margin, translate, offsets) goes. Take a frame this way when the\nperson wants one part of a design as code.\n\nOver MCP, the tools are `create_design`, `get_design` (`layer: \"picked\"`\nreads the pick), `update_design`, `move_layer`, `export_design` and\n`delete_design`;\n`export_design` has no `png`, and takes `layer` for one frame.\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}