Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault

No arguments

Capabilities

Features and capabilities supported by this server

CapabilityDetails
tools
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
jsxA

Create design trees with nested JSX markup. One jsx call builds a complete subtree atomically — nesting is the hierarchy. Keep a single logical unit inside one call; the returned root's children are already built, not stubs to be filled in later.

Examples: jsx({markup: ""}) jsx({markup: "Account"})

Elements: frame, text, rect, ellipse, line, icon, image, instance, component, group, section, vector Attributes (frame): layout, justify, items, wrap, w, h, minW, maxW, p, gap, bg, fill, rounded, stroke, shadow, blur, bgblur, opacity, layoutPositioning Attributes (text): size, weight, lineHeight, font, fill, w (w="fill" for wrap), maxLines, textTruncation Effects: shadow="0,8,32,0,#0006" or shadow={shadow(0,8,32,0,'#0006')}; blur={10} for layer blur; bgblur={20} for frosted-glass/glassmorphism background blur. Multiple effects merge automatically. Decoration in auto-layout: floating orbs/blobs/decorative shapes inside a row/column parent need layoutPositioning="absolute" so they don't get stacked into the main-axis flow. Full-frame backgrounds: set the parent frame's bg directly. Don't add a separate backdrop. Supported gradient strings (CSS-like subset, not full CSS):

  • linear-gradient(deg, <#hex> %, ...) e.g. "linear-gradient(135deg, #A 0%, #B 100%)"

  • linear-gradient(to , ) directions: top/right/bottom/left and corners (e.g. "to bottom right")

  • radial-gradient() centered, ellipse-fill — no position/shape modifiers

  • radial-gradient(circle, ) centered, circle shape only

  • conic-gradient(from deg, ) Unsupported (will be rejected): "circle at X% Y%", "ellipse at ...", "X% Y%" position syntax, named colors (red/blue/...), hsl(), and numeric stops without a percent sign. Text: content here Instance: Self-closing: (use line for dividers/separators; rect/ellipse for SMALL pure decoration with no children — page-level backgrounds belong on the parent frame's bg) Arc/Ring: (arc="start end innerRadius?" — innerRadius 0-1 makes a donut/ring) Grid layout: call help({ name: "grid-layout" }) for tracks, gaps, and when row/column is a better fit Variable binding: fill/bg/stroke accept qualified bare-name token strings (e.g. bg="$Theme/Bg/Surface"). Object literals (fill={{variable_id:...}}) drop the binding silently — always use the string form.

Swap an existing subtree: jsx({replaceId: "", markup: "..."}) replaces the old node at the same parent and sibling index atomically, preserving position in one call. Markup must have a single root. Use jsx for tree creation; edit for property updates on known nodes.

inspectA

Read design node(s) — choose what to surface with facets.

Default (no facets) returns a skeleton: id, name, type, role, children. For anything else, list the facets you need — nothing else is included.

Facets: structure name, type, size, layout shorthand — cheap overview layout layoutMode/gap/padding/align/sizing (row/column, fill/hug, etc.) paint|fill fills + Paint.boundVariables.color (see bound tokens) stroke strokes, strokeWeight, strokeAlign, dashPattern effects shadows, blurs typography|text fontFamily, fontSize, fontWeight, lineHeight, letterSpacing appearance opacity, visible, blendMode, cornerRadius, clipsContent variables node-level boundVariables + explicitVariableModes (token bindings) all everything

Parameters: node "/" for page root, or node ID from jsx/inspect results (e.g. "100:5"). facets array of facet names listed above. depth Max tree depth (default: 5, max: 10).

Examples: inspect({node: "/"}) → page skeleton inspect({node: "100:5"}) → one-node skeleton inspect({node: "100:5", facets: ["variables"]}) → token bindings only inspect({node: "100:5", facets: ["layout", "paint"]}) → layout + fills inspect({node: "100:5", facets: ["all"]}) → full properties

Use get_screenshot for visual verification. Use describe for lint/validation.

describeA

Validate a design subtree — semantic description, role detection, and lint rules. Checks for layout conflicts, overflow, missing properties, and structural issues.

Parameters: node: Node ID to describe (e.g. "100:5"). Required. depth: How deep to check children (default: 3, max: 8).

Returns per-node: role, visual summary, layout summary, and issues (severity: error/warning/info).

Examples: describe({node: "100:5"}) → validate subtree, depth 3 describe({node: "100:5", depth: 1}) → shallow check (root + direct children only)

editA

Batch update properties on multiple nodes.

For single-property changes, prefer focused setters: set_text — text content set_fill — fill/background color set_stroke — border set_layout — padding, gap, direction

Use edit for batch fixes or properties not covered by setters (sizing, radius, opacity, effects, component props): edit({nodes: [ {node: "1:1", props: {w: "fill", corner: 8}}, // Figma native props {node: "1:2", props: {opacity: 0.6}}, {node: "1:3", props: {Label: "Sign In"}}, // instance TEXT prop (by display name) ]})

For instances, use component property DISPLAY NAMES (e.g. "Label") — edit resolves them to Figma's internal keys automatically. Component props can be mixed with Figma props in the same call.

find_nodesA

Search nodes by name or type. Scoped to the current page — call switch_page first if your target lives on a different page.

Examples: find_nodes({query: "Button"}) find_nodes({query: "frame", scope: "1:2"})

discover_propsA

Discover unique property values in a subtree.

Examples: discover_props({node: "1:2", props: ["fillColor", "fontSize"]})

Searchable properties: fillColor, textColor, strokeColor, strokeWeight, opacity, cornerRadius, gap, fontSize, fontFamily, fontWeight.

replace_propsA

Bulk find-and-replace property values across a subtree (target node + all descendants). Destructive batch mutation — no preview, no undo across many nodes. Returns per-rule match counts.

Use when:

  • Theming pass: change every #FFF fill to #000 across a screen

  • Token migration: bump every fontSize from 14 to 16

  • Normalizing values left inconsistent by earlier passes

  • The alternative is N targeted single-node calls (set_text / set_fill / edit)

Returns: { data: { replacements: [{ rule: 0, matched: 12 }, { rule: 1, matched: 0 }] } }

Parameters beyond schema:

  • node is the subtree root; search recurses into all descendants (depth-first).

  • Each rule's from is an EXACT-match string (no substring, no regex). For typed props (fontSize, opacity), pass values as strings — the executor coerces.

  • Zero matches do NOT error — they return matched: 0. Sanity-check with discover_props first if you're unsure values exist.

Skip when:

  • Updating a single known node — use set_text / set_fill / set_stroke / set_layout for type-aware single-intent edits, or edit for generic.

  • Values are variable-bound (tokens) — replace_props bypasses bindings; use bind_variable to swap the token instead.

  • You need partial / fuzzy match — replace_props is exact-only; you'll need find_nodes + a loop.

Examples: // single rule, white -> black replace_props({node: "1:2", rules: [{prop: "fillColor", from: "#FFF", to: "#000"}]})

// batch theme update — both rules applied in one pass replace_props({node: "1:2", rules: [ {prop: "fillColor", from: "#FFF", to: "#000"}, {prop: "fontSize", from: "14", to: "16"} ]})

find_referencesA

Find every node on the current page that references a given variable.

This is the REVERSE of inspect: inspect asks "what does this node bind?", find_references asks "who uses this variable?". Use it when renaming, auditing, or swapping tokens — you need to know all the binding sites before you touch the variable.

Scan scope: currentPage only. Invisible nodes are skipped by default. Node-level bindings (e.g. boundVariables.paddingLeft) and per-paint color bindings (fills[i].boundVariables.color, strokes[i].boundVariables.color) are both returned.

Parameters: variable — VariableID (e.g. "VariableID:1:5"). Required.

Returns: {variable, variableName, variableType, referenceCount, references: [{nodeId, nodeName, nodeType, path}, ...]}

path values look like: "boundVariables.paddingLeft" "fills[0].boundVariables.color" "strokes[2].boundVariables.color"

Examples: find_references({variable: "VariableID:1:5"})

delete_nodeB

Delete a node and its children.

Examples: delete_node({node: "1:2"})

move_nodeA

Relocate a node without recreating it. Preserves IDs, bound variables, and component instances across the move, so callers tracking the node by ID never need to re-discover it. Use for: (a) changing child order within a container, (b) moving a subtree into a different parent, (c) fixing a placement mistake after jsx.

Examples: move_node({node: "1:3", name: "NewTitle"}) — rename in place move_node({node: "1:3", parent: "1:4"}) — move into parent 1:4 move_node({node: "1:5", index: 0}) — reorder within current parent

clone_nodeA

Deep-copy a node with optional property overrides.

Examples: clone_node({node: "1:2"}) — clone to page root, same name clone_node({node: "1:2", parent: "/"}) — clone to page root explicitly clone_node({node: "1:2", parent: "/", name: "Hero Copy"}) — clone to root with custom name clone_node({node: "1:2", parent: "1:4"}) — clone into parent node 1:4 clone_node({node: "1:2", parent: "1:4", overrides: {"bg": "#D9D9D9"}})

skillA

Load a procedural skill — workflow + tool sequence + anti-patterns. Use FIRST when the user is changing/adjusting existing canvas, OR before creating a new design if a matching skill exists.

Example: skill({ name: "restyle" })

styleA

Load a visual style preset as INSPIRATION — color tokens, typography, shape, depth. Treat as a reference library, not a cage: pick one wholesale, mix elements, or invent your own. You are not restricted to the menu.

Example: style({ name: "neon-cyber" })

guidelineA

Load a page-type design guideline — layout patterns for landing pages, dashboards, login flows, forms, etc.

Example: guideline({ name: "form" })

helpB

Load narrow how-to / process help — tool usage rules, edge cases, naming conventions.

Example: help({ name: "interaction-model" })

list_variablesA

List variables as a flat array with referenced collections.

Returns {data: {variables[], collections[], nextCursor?}}. Each variable carries its full Figma shape: id, name, variableCollectionId, resolvedType, valuesByMode. collections[] only includes collections referenced by the returned variables (use for mode-name resolution).

Parameters: collection — VariableCollectionId to filter by filter — substring match on variable name (case-insensitive) cursor — opaque pagination cursor from a previous call limit — max variables per page (default 100)

Examples: list_variables() list_variables({collection: "VariableCollectionId:1:2"}) list_variables({filter: "bg"}) list_variables({cursor: "100"})

create_collectionA

Create a VariableCollection with named modes.

The first mode in the array becomes the default mode. Returns {data: {id, modes: [{modeId, name}]}} — use those modeIds with set_variable_value and set_variable_mode.

Examples: create_collection({name: "Theme", modes: ["Light", "Dark"]}) create_collection({name: "Device", modes: ["Desktop", "Tablet", "Mobile"]})

create_variableA

Create a variable in an existing collection.

No value is set here — use set_variable_value after. Returns {data: {id}}.

Examples: create_variable({collection: "VariableCollectionId:1:2", name: "Theme/bg", type: "COLOR"}) create_variable({collection: "VariableCollectionId:1:2", name: "spacing/md", type: "FLOAT"})

ensure_collectionA

Idempotent VariableCollection creation — safe to retry.

Returns existing collection if one with the same name + identical mode list already exists, otherwise creates a new one. Spec §3.1.

Prefer this over create_collection — re-running with the same name + modes returns the existing collection instead of creating a duplicate.

Omit idempotency_key — the handler computes it canonically from (name, modes). Pass it only if you need strict concurrency-safety validation (LLMs should not try to compute SHA-256 inline; placeholder strings are rejected).

Returns {data: {collection_id, modes: [{modeId, name}], reused?: true}}.

Examples: ensure_collection({name: "Theme", modes: ["Light", "Dark"]})

ensure_variableA

Idempotent variable creation — populates values_by_mode in one shot.

Prefer this over create_variable — re-running with the same args returns the existing variable instead of creating a duplicate.

Behavior (spec §3.1):

  • Exactly 1 variable with (collection_id, name, type) in target collection → idempotent reuse.

  • 0 in target, matches in OTHER collections → create new in target + warning NAME_EXISTS_OUTSIDE_TARGET_COLLECTION.

  • 0 anywhere → create new.

  • 2+ in target collection (Figma allows duplicates) → fail SAME_COLLECTION_NAME_DUPLICATE.

values_by_mode keys can be either mode NAMES (e.g. "Light") or modeIds (e.g. "1:0"). Each value must match the variable type (hex/RGBA for COLOR, number for FLOAT, string for STRING, boolean for BOOLEAN).

Omit idempotency_key — the handler computes it canonically from (collection_id, name, type, values_by_mode). Pass it only if you need strict concurrency-safety validation (LLMs should not try to compute SHA-256 inline; placeholder strings are rejected).

Mode coverage policy (spec §6.2):

  • mode_coverage_required: 'all' (default) — every mode in the collection must have an explicit value. set_fill / bind_variable will REJECT bindings that fall through to a missing mode (MISSING_MODE_VALUES).

  • mode_coverage_required: 'opt-in-fallback' — fallback to default mode is intended. Bindings emit FALLBACK_BINDING warning instead of failing. Caller MUST provide fallback_reason containing the structured phrase "fallback to <mode_name>" (machine-greppable).

Returns {data: {variable_id, name, type, collection_id, mode_coverage[], mode_coverage_required, reused?: true}, warnings?: [...]}.

Examples: ensure_variable({collection_id: "VariableCollectionId:1:2", name: "Text/Primary", type: "COLOR", values_by_mode: {Light: "#111", Dark: "#EEE"}}) ensure_variable({collection_id: "VariableCollectionId:1:2", name: "Spacing/desktop", type: "FLOAT", values_by_mode: {Desktop: 24}, mode_coverage_required: "opt-in-fallback", fallback_reason: "Desktop-only metric; fallback to Desktop in Mobile mode."})

set_variable_valueA

Set a variable's value for a specific mode.

Thin wrapper over Figma's variable.setValueForMode(modeId, value). Call once per mode. Value is a raw value (COLOR/FLOAT/STRING/BOOLEAN) OR an alias object {type: "VARIABLE_ALIAS", id: "VariableID:x:y"}. Hex strings are accepted for COLOR and normalized to {r,g,b,a} in 0-1 range.

Examples: set_variable_value({variable: "VariableID:1:5", mode: "1:0", value: "#FFFFFF"}) set_variable_value({variable: "VariableID:1:5", mode: "1:1", value: {r: 0.1, g: 0.1, b: 0.1, a: 1}}) set_variable_value({variable: "VariableID:1:6", mode: "1:0", value: 16}) set_variable_value({variable: "VariableID:1:7", mode: "1:0", value: {type: "VARIABLE_ALIAS", id: "VariableID:1:9"}})

bind_variableA

Bind a FLOAT, BOOLEAN, or STRING variable to a node property.

prop is a flat Figma bindable field (e.g. fontSize, itemSpacing, paddingTop, cornerRadius, opacity, visible, width, height, characters). Shorthands: gap → itemSpacing, padding → paddingTop, corner → cornerRadius, font-size → fontSize.

COLOR variables are NOT bound here — they live inside Paint objects. To apply a color token, specify it at the source instead: • At creation: jsx <frame bg="$TokenName" ...> or fill="$TokenName" • Post-hoc: set_fill({node, bg: "$TokenName"}) or set_stroke

When selecting which variable to bind: if the node is a Tablet or Mobile variant (name or variant property contains "Tablet"/"Mobile"), match the node's property value against the Tablet/Mobile mode column from list_variables — not Desktop.

Examples: bind_variable({node: "1:2", prop: "fontSize", variable: "VariableID:1:6"}) bind_variable({node: "1:3", prop: "paddingTop", variable: "VariableID:1:7"}) bind_variable({node: "1:4", prop: "visible", variable: "VariableID:1:8"}) bind_variable({node: "1:5", prop: "characters", variable: "VariableID:1:9"})

set_variable_modeA

Set a node to use a specific mode of a variable collection.

This controls which variable values the node displays. For example, set a frame to use "Dark" mode of the "Theme" collection so all bound variables show dark values.

Examples: set_variable_mode({node: "1:2", collection: "VariableCollectionId:1:2", mode: "1:1"}) set_variable_mode({node: "1:5", collection: "VariableCollectionId:1:3", mode: "1:2"})

create_componentC

Convert a frame or group to a Figma component.

Examples: create_component({node: "1:2"})

combine_componentsB

Combine multiple components into a variant set (ComponentSet).

Examples: combine_components({nodes: ["1:2", "1:3", "1:4"], name: "Button"})

add_component_propA

Add a component property and bind it to a child node.

For TEXT properties: binds to the target text node's characters, so instances can override the text content. For BOOLEAN properties: binds to the target node's visibility.

Parameters: node: The component node ID (must be COMPONENT or COMPONENT_SET). name: Property display name. type: TEXT, BOOLEAN, or INSTANCE_SWAP. default: Default value. bind: Child node ID to bind this property to. For TEXT, binds to text content. For BOOLEAN, binds to visibility.

Examples: add_component_prop({node: "1:2", name: "Label", type: "TEXT", default: "Click me", bind: "1:5"}) add_component_prop({node: "1:2", name: "Show Icon", type: "BOOLEAN", default: "true", bind: "1:6"})

list_component_propsA

List properties and variants of a component, component set, or instance.

Examples: list_component_props({node: "1:2"})

create_instanceA

Create an instance of an existing component. Mutates the canvas — appends a new InstanceNode as the last child of parent (or the active page root if omitted). The instance is LINKED to the component master, so future component edits propagate. Returns the new instance's nodeId.

Use when:

  • Spawning runtime copies of a Component master (buttons, list items, cards)

  • Reusing a design-system component in a fresh layout

  • Programmatic instantiation outside a jsx() tree-build

Returns: { data: { id: "5:42", name: "Button", componentId: "1:2" } }

Parameters beyond schema:

  • node must be a Component node (not Frame, Text, or another Instance). Discover IDs with find_nodes({ type: "COMPONENT" }).

  • parent optional. If parent is auto-layout, the instance enters the flow and inherits sizing rules. If omitted, the instance is placed at the active page root with detached position — may overlap existing content; set explicit position with edit afterwards.

Skip when:

  • Duplicating a non-component node — instance creation will fail; use clone_node instead.

  • Building a subtree from scratch — use jsx with for atomic single-call construction.

Examples: create_instance({node: "1:2"}) // at page root create_instance({node: "1:2", parent: "1:4"}) // inside frame 1:4

set_textA

Set text content on one or more nodes.

set_text({node: "1:2", text: "Hello World"}) set_text({nodes: [{node: "1:2", text: "Title"}, {node: "1:3", text: "Subtitle"}]})

Use this when changing what text says. For text styling (font, size, weight), use edit.

set_fillA

Set fill or background color on a node.

set_fill({node: "1:2", bg: "#F5F5F5"}) set_fill({node: "1:2", fill: "#333333"}) set_fill({node: "1:2", bg: "linear-gradient(135deg, #8B5CF6 0%, #F97316 100%)"})

// Batch — bulk paint update in one call: set_fill({nodes: [{node: "1:2", bg: "#FFF"}, {node: "1:3", bg: "#F5F5F5"}]})

fill = text color or shape fill. bg = frame background. For stroke color, use set_stroke.

Accepted color formats (for fill or bg): hex "#FFF", "#F5F5F5" gradient string CSS-like subset, not full CSS: "linear-gradient(deg, <#hex> %, ...)" "linear-gradient(to , ...)" directions: top/right/bottom/left + corners "radial-gradient()" centered, no position/shape modifiers "radial-gradient(circle, )" circle shape only "conic-gradient(from deg, ...)" Rejected: "circle at X% Y%", "ellipse at ...", named colors, hsl(). variable token qualified bare name "$Surface/Card" transparent "transparent" (bg only)

set_strokeA

Set stroke (border) on a node.

set_stroke({node: "1:2", stroke: "1 #E0E0E0"}) set_stroke({node: "1:2", stroke: "2 #333 inside"}) set_stroke({node: "1:2", color: "#E0E0E0", weight: 1, align: "inside"}) set_stroke({node: "1:2", color: "linear-gradient(90deg, #8B5CF6 0%, #F97316 100%)", weight: 1.5, align: "inside"})

// Batch — bulk stroke update in one call: set_stroke({nodes: [{node: "1:2", color: "#E0E0E0", weight: 1}, {node: "1:3", color: "#333", weight: 2}]})

Shorthand: "weight color align" (e.g. "1 #E0E0E0 inside"). Hex only in shorthand.

Accepted color formats (for the explicit color field, not the shorthand): hex "#E0E0E0" gradient string CSS-like subset (see set_fill description for full grammar — same rules). Common: "linear-gradient(deg, <#hex> %, ...)", "radial-gradient()". Rejected: "circle at X% Y%", named colors, hsl(). variable token qualified bare name "$Border/Default"

To bind a variable to the stroke color, use the explicit color field — the shorthand parser silently drops bare-name tokens.

set_layoutB

Set auto-layout properties on a container.

set_layout({node: "1:2", gap: 16, p: 24}) set_layout({node: "1:2", layout: "row", justify: "space-between"}) set_layout({node: "1:2", layout: "column", gap: 8, p: "16 24", align: "center"}) set_layout({node: "1:2", layout: "grid", cols: 3, rows: 2, gap: 16})

// Batch — bulk update in one call: set_layout({nodes: [{node: "1:2", gap: 16, p: 24}, {node: "1:3", gap: 8, p: 12}]})

Controls spacing, padding, direction, and alignment of a container's children. Grid: use layout:"grid" with cols/rows + gap (or rowGap/colGap for asymmetric). Children fill the grid in insertion order.

get_selectionA

Get the user's currently selected nodes in Figma.

Returns node names, types, and IDs of selected elements. Call this when the user's intent involves modifying existing elements:

  • "change this button", "update the card", "fix the spacing"

  • References to "this", "the selected", "it"

Skip for fresh design requests ("design a login page", "create a dashboard") — a new canvas has no selection to read, so the call returns nothing and burns an iteration.

Examples: get_selection()

switch_pageA

Navigate between pages in the Figma file. ID-driven — names are not addressable (they can collide and change).

Two modes:

  • switch_page({}) → return the page roster only, no switch (use to discover IDs on first call)

  • switch_page({pageId: "1:23"}) → switch and return the updated state + roster

Pages are top-level containers under the file root. Most read/write operations default to figma.currentPage. Call this when you need to operate on nodes that live on a different page than the current one.

Returns:

  • currentPageId, currentPageName — the now-current page (always present)

  • pages — full roster [{id, name}] of every page in the file (always present)

  • previousPageId, previousPageName — what you switched from (only when an actual switch happened)

  • unchanged — true if target was already current

Typical flow:

  1. switch_page({}) // get IDs

  2. switch_page({pageId: ""}) // switch

When to call:

  • User mentions content on a different page than the current one

  • A previous tool reported a node ID is on a non-current page

  • You need to inspect/modify nodes outside the active page

Don't call:

  • For nodes already on the current page — figma.currentPage is the default scope, this would just waste an iteration

  • Repeatedly to "explore" — every call returns the full pages roster, cache it

read_plugin_dataA

Read plugin data (private or shared) from a Figma node.

Use for: i18n metadata, design-system tags, custom plugin annotations, anything stored via setPluginData / setSharedPluginData.

If namespace is omitted, reads private pluginData (node.getPluginData(key)). If namespace is provided, reads sharedPluginData (node.getSharedPluginData(namespace, key)).

Returns {value: ""} (empty string) when the key does not exist — Figma's API never throws here.

Examples: read_plugin_data({node_id: "1:5", key: "ref"}) read_plugin_data({node_id: "1:5", namespace: "i18n", key: "ref"})

write_plugin_dataA

Write plugin data (private or shared) to a Figma node.

If namespace is omitted, writes private pluginData (node.setPluginData(key, value)). If namespace is provided, writes sharedPluginData (node.setSharedPluginData(namespace, key, value)).

Pass an empty string as value to delete a key.

Examples: write_plugin_data({node_id: "1:5", key: "ref", value: "home_title"}) write_plugin_data({node_id: "1:5", namespace: "i18n", key: "ref", value: "home.welcome_title"})

create_vectorA

Create a vector node from SVG path data or a list of points. Use for chart lines, custom icon paths, freeform curves, or any shape that needs path data.

Examples: // Polyline (chart trend line) create_vector({ parent: "1:23", name: "TrendLine", x: 40, y: 20, width: 550, height: 240, points: [[0,144],[90,96],[180,120],[270,64],[360,80],[450,40],[540,72]], stroke: "#6366F1", strokeWeight: 2 })

// Raw SVG path (custom shape) create_vector({ parent: "1:23", name: "Wave", width: 200, height: 60, data: "M 0 30 Q 50 0 100 30 T 200 30", stroke: "linear-gradient(90deg, #8B5CF6 0%, #F97316 100%)", strokeWeight: 1.5 })

Path input — provide ONE of: points: [[x,y], ...] compiled to "M x0 y0 L x1 y1 ..." (polyline shortcut) data: "M ... L ..." raw SVG path (LLM-native; supports M, L, C, Q, A, Z)

Stroke / fill (same formats as set_stroke / set_fill): hex "#6366F1" gradient "linear-gradient(angle, #color stop%, ...)" variable qualified bare name "$Brand/Primary"

Default fill is "transparent" so the vector shows only its stroke. Pass an explicit fill if you want it filled.

When NOT to use:

  • Standard rectangles / ellipses / lines — use jsx , , elements (simpler, batch-friendly)

  • Existing vector edits — use edit / set_stroke instead

get_screenshotA

Capture a PNG screenshot of a node.

Use after style changes to visually verify the result instead of reading properties back. Returns base64 PNG data embedded in the response.

Parameters: node: Node ID from jsx/inspect results (e.g. "100:5"). Page root ("/") is not supported. scale: Export scale 0.5–2 (default 1). Higher = larger file. padding: Reserved for future use — currently ignored.

Examples: get_screenshot({node: "100:5"}) → PNG at 1x get_screenshot({node: "100:5", scale: 2}) → PNG at 2x (sharper)

ask_userA

Ask the user 1-3 questions in a single form. Each question has its own options and can be single- or multi-select. Bundle related decisions in ONE call instead of multiple turns.

Use when:

  • The prompt is ambiguous on multiple dimensions (audience + aesthetic + length) — bundle them into one form

  • You need a decision before proceeding (delete existing? which section first?)

  • Multiple valid approaches exist and user preference matters

Returns one of:

  • { answers: [...] } — array indexed to questions order. string for single-select, string[] for multi-select. The string MAY be one of the option labels OR custom text the user typed via the auto-injected "Other..." option.

  • { freeText: "..." } — when the user typed a free-form answer in the chat input instead of submitting the form. Treat as authoritative — user is overriding the structured options.

Each question:

  • question: required prompt string. Self-contained — no separate header/label, the question text IS the heading.

  • options: 2-3 options, each { label, description? }. The form auto-injects an "Other..." row, so the user always sees options.length + 1 rows total — keep options ≤ 3 to stay within the 4-row visual cap.

  • multiSelect: optional boolean (default false). Use only when the answer is genuinely a list (e.g. "which features?"). For mutually exclusive choices keep false.

Conventions:

  • First option = recommended. If you have a strong default for the user, put it FIRST and add "(Recommended)" at the end of the label. The form auto-focuses the first option and the dev/auto-pick fallback selects it — both work better with a deliberate recommendation.

  • Do NOT include an "Other" option yourself — the form auto-injects an "Other..." row per question with an inline text input. Don't add a redundant one.

  • Bundle aggressively. 2 related dimensions in ONE call beats 2 sequential turns.

Example: ask_user({ questions: [ { question: "Who is this for?", options: [{label:"B2B SaaS"},{label:"Consumer"},{label:"Developer tool"}] }, { question: "What visual direction?", options: [{label:"Minimal"},{label:"Bold/Brutalist"},{label:"Neon/Cyber"}] } ]})

Skip when the prompt is already actionable — asking adds a turn and costs momentum.

subtaskA

Delegate a focused sub-task to a typed child agent. Each type has its own tools, iteration budget, and behavioral constraints.

Available agent types:

  • create: Build an independent UI section (header, sidebar, form, card). Default.

  • audit: Read-only design review — find layout issues, property omissions, report PASS/FAIL.

  • token: Variable system operations — create collections, bind tokens, set up aliases.

Use when the prompt names 3+ distinct regions (e.g. header, sidebar, main) that share no nodes, or when specialized behavior is needed (audit, token ops). For 1-2 tool-call operations, inline calls finish faster than the subtask spin-up cost.

session_noteA

Read / write your own session scratchpad. Persists across turns within one design session ("New Design" resets it). Notes are how state carries from this turn into the next — the next session loads them as context.

Actions: action: "read" → read({key}) returns the current value (empty string if unset) action: "write" → write({key, value}) replaces or deletes (pass value:"" to delete) action: "list" → list({}) returns [{key, chars}] for all existing notes

Slots — FORWARD-LOOKING (what we plan / commit to):

  • plan — this turn's intent + step outline (write at turn start)

  • decisions — locked choices: style picked + reason, accent token, font scale, hero treatment, etc. (write BEFORE jsx)

  • brand — durable brand notes pulled from a project design.md (if user supplied one)

  • todo — TRULY unfinished work for the next turn (omit if everything shipped)

Slots — BACKWARD-LOOKING (what happened, write AT TURN END — AUTO-MERGE on write):

  • failures — tool calls that failed this turn + how you worked around them. Example: "jsx items='stretch' rejected (DSL valid: center|start|end|space-between|baseline); retried with 'center'." If a failure repeats a class you've seen before, name the class.

  • gotchas — validator warnings you noticed but chose not to fix + why. Example: "4 LOW_CONTRAST on nav links (2.5:1) — deliberate for ambient-grey style; revisit if user complains." Also: magic numbers / hand-tuned positions and what motivated them. Example: "Glow ellipses at (-180, 220) / (1060, 70) — placed half outside frame to bleed in."

  • learnings — surprises about this codebase / DSL / Figma API. Example: "radial-gradient(circle at X% Y%) rejected — DSL only takes the simple form. Same trap as CSS-prior bleed elsewhere."

BACKWARD-LOOKING slots auto-merge: writing to failures / gotchas / learnings appends to prior content after a "---" divider — your new value never silently overwrites accumulated retrospective notes. To replace fresh, first write({value: ""}) to clear, then write again. The result data.merged=true flag confirms when merge happened.

REQUIRED behavior:

  • First turn: write at least decisions BEFORE any jsx (commit-before-act).

  • Subsequent turns: read decisions and learnings BEFORE any jsx — those slots survive across turns and your conversationHistory won't carry the full content reliably. Your turn's adjacent snapshot also surfaces current notes, but explicit read proves you considered them.

  • Every turn end: write at least ONE of failures / gotchas / learnings if ANY of these happened this turn: • a tool call returned an error • a tool call returned warnings you chose not to fix • you hand-tuned a coordinate / size / color away from a value the model would have picked • you found a DSL behavior that surprised you "All clean, no carry-over" is almost never accurate — at least one backward slot belongs.

  • jsx that uses a color / font / size should round-trip through decisions (token traceability).

Examples: session_note({action: "write", key: "decisions", value: "Style: fintech-dark.\nAccent: #3B82F6 (style.accent — NOT indigo).\nFont: Space Grotesk display / Inter body.\nHero treatment: split (overrides anatomy VERTICAL — desktop convention).\nH1 size: 32 (style.display)."}) session_note({action: "write", key: "failures", value: "jsx #6 align='stretch' rejected (DSL valid: center|start|end|space-between|baseline) — retried with 'center'. Same CSS-prior class as gradient: model has CSS values that DSL doesn't accept."}) session_note({action: "write", key: "gotchas", value: "8 LOW_CONTRAST warnings on nav links + secondary CTA (2.5:1 against dark bg). Left as-is — user prompt didn't require WCAG pass; flagging in case next iteration tightens contrast."}) session_note({action: "write", key: "learnings", value: "layoutPositioning='absolute' children render correctly inside auto-layout frame, but parent needs clipsContent=true to suppress overflow on big glow ellipses."}) session_note({action: "read", key: "decisions"}) session_note({action: "list"})

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/musepy/genable'

If you have feedback or need assistance with the MCP directory API, please join our Discord server