Advanced styling
Generated MCP reference for advanced styling.
This page is generated from mcp-catalog.json. Do not edit it by hand.
Source: paper3 local extraction on 2026-05-29. Generated: 2026-05-29T11:34:45.044Z.
add_artboard_breakpoint
Add a breakpoint artboard to a page
Appends a tablet (834px) or mobile (390px) artboard alongside the existing desktop artboard so the user can design responsive variants. Each breakpoint is an independent artboard the AI can write_html into. Default widths follow Apple's iPad / iPhone Pro sizes; override via width if needed.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
pageId | string | Yes | |
breakpoint | string | Yes | |
width | number | No | |
height | union | No | |
_site | string | No | Optional target site formatted as <workspaceSlug>/<siteSlug>. Required when the workspace has multiple sites and no site header is set. |
Input schema
{
"type": "object",
"properties": {
"pageId": {
"type": "string"
},
"breakpoint": {
"type": "string",
"enum": [
"desktop",
"tablet",
"mobile"
]
},
"width": {
"type": "number"
},
"height": {
"anyOf": [
{
"type": "number"
},
{
"const": [
"fit-content"
]
}
]
},
"_site": {
"type": "string",
"description": "Optional target site formatted as <workspaceSlug>/<siteSlug>. Required when the workspace has multiple sites and no site header is set.",
"pattern": "^[^/]+/[^/]+$"
}
},
"required": [
"pageId",
"breakpoint"
],
"additionalProperties": false
}remove_artboard_breakpoint
Remove a breakpoint artboard
Removes an artboard from a page. The first artboard cannot be removed — every page must keep at least one surface.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
pageId | string | Yes | |
artboardId | string | Yes | |
_site | string | No | Optional target site formatted as <workspaceSlug>/<siteSlug>. Required when the workspace has multiple sites and no site header is set. |
Input schema
{
"type": "object",
"properties": {
"pageId": {
"type": "string"
},
"artboardId": {
"type": "string"
},
"_site": {
"type": "string",
"description": "Optional target site formatted as <workspaceSlug>/<siteSlug>. Required when the workspace has multiple sites and no site header is set.",
"pattern": "^[^/]+/[^/]+$"
}
},
"required": [
"pageId",
"artboardId"
],
"additionalProperties": false
}set_breakpoint_override
Set / clear per-breakpoint overrides (one or many)
Patches a node's properties for a specific breakpoint artboard (tablet or mobile) without touching the desktop master. The override is sparse — only carry the fields that should diverge at this breakpoint; everything else cascades from the wider breakpoint (mobile ← tablet ← desktop). Use cases: shrink fontSize on mobile (override: \{ styles: \{ fontSize: '24px' \} \}), hide a desktop-only sidebar (override: \{ styles: \{ display: 'none' \} \} — visibility ALWAYS goes through styles.display, never a structured hidden flag), swap an image for a portrait crop (override: \{ src: '...' \}). The artboardId MUST be a tablet or mobile artboard from the same page; the nodeId is the master id (the same id you used in update_styles). To CLEAR an existing override and let the cascade flow through again, pass override: null (this replaces the old clear_breakpoint_override tool).
INPUT SHAPES (pick whichever fits — the model-side framing overhead drops linearly with the number of tool calls):
• \{ nodeId, ...patch \} — one node, one patch.
• \{ nodeIds: [id1, id2, …], ...patch \} — same patch fanned out to many nodes (the 'multi-select' shape — use whenever 3+ nodes get the same change).
• \{ updates: [\{ nodeId, ...patch \}, …] \} — different patches per node, batched in one call (use whenever 3+ nodes get different changes; far cheaper than N separate calls).
Missing nodes are skipped silently. The result is \{ ok: true, applied, skipped \}.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
nodeId | string | No | |
nodeIds | array | No | |
updates | array | No | |
artboardId | string | No | |
override | unknown | No | |
replace | boolean | No | |
_site | string | No | Optional target site formatted as <workspaceSlug>/<siteSlug>. Required when the workspace has multiple sites and no site header is set. |
Input schema
{
"type": "object",
"properties": {
"nodeId": {
"type": "string"
},
"nodeIds": {
"type": "array",
"items": {
"type": "string"
}
},
"updates": {
"type": "array",
"items": {
"type": "object",
"properties": {
"nodeId": {
"type": "string"
},
"artboardId": {
"type": "string"
},
"override": {},
"replace": {
"type": "boolean"
}
},
"required": [
"nodeId",
"artboardId",
"override"
],
"additionalProperties": false
}
},
"artboardId": {
"type": "string"
},
"override": {},
"replace": {
"type": "boolean"
},
"_site": {
"type": "string",
"description": "Optional target site formatted as <workspaceSlug>/<siteSlug>. Required when the workspace has multiple sites and no site header is set.",
"pattern": "^[^/]+/[^/]+$"
}
},
"additionalProperties": false
}set_node_behaviors
Set declarative behaviors on a node (one or many)
Replaces the node's behavior list — interactive primitives the runtime shim wires up at boot (no JS authored by you). Variants: (1) toggleClass — click/hover the source toggles a class on a target node, used for accordions/tabs/menus; (2) scrollLink — smooth-scroll to a target node on click; (3) scrollReveal — IntersectionObserver adds a class when the node enters the viewport, pair with hoverStyles authored under that class; (4) openMenu — convenience wrapper for the canonical hamburger pattern (toggles is-open on both the trigger and the menu). Pass [] to clear. The runtime shim is automatically tree-shaken to only the kinds actually used on the page.
INPUT SHAPES (pick whichever fits — the model-side framing overhead drops linearly with the number of tool calls):
• \{ nodeId, ...patch \} — one node, one patch.
• \{ nodeIds: [id1, id2, …], ...patch \} — same patch fanned out to many nodes (the 'multi-select' shape — use whenever 3+ nodes get the same change).
• \{ updates: [\{ nodeId, ...patch \}, …] \} — different patches per node, batched in one call (use whenever 3+ nodes get different changes; far cheaper than N separate calls).
Missing nodes are skipped silently. The result is \{ ok: true, applied, skipped \}.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
nodeId | string | No | |
nodeIds | array | No | |
updates | array | No | |
behaviors | array | No | |
_site | string | No | Optional target site formatted as <workspaceSlug>/<siteSlug>. Required when the workspace has multiple sites and no site header is set. |
Input schema
{
"type": "object",
"properties": {
"nodeId": {
"type": "string"
},
"nodeIds": {
"type": "array",
"items": {
"type": "string"
}
},
"updates": {
"type": "array",
"items": {
"type": "object",
"properties": {
"nodeId": {
"type": "string"
},
"behaviors": {
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"properties": {
"kind": {
"const": [
"toggleClass"
]
},
"targetId": {
"type": "string"
},
"className": {
"type": "string"
},
"trigger": {
"type": "string",
"enum": [
"click",
"hover"
]
}
},
"required": [
"kind",
"targetId",
"className"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"kind": {
"const": [
"scrollLink"
]
},
"targetId": {
"type": "string"
},
"offsetPx": {
"type": "number"
}
},
"required": [
"kind",
"targetId"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"kind": {
"const": [
"scrollReveal"
]
},
"className": {
"type": "string"
},
"once": {
"type": "boolean"
},
"threshold": {
"type": "number"
}
},
"required": [
"kind"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"kind": {
"const": [
"openMenu"
]
},
"targetId": {
"type": "string"
}
},
"required": [
"kind",
"targetId"
],
"additionalProperties": false
}
]
}
}
},
"required": [
"nodeId",
"behaviors"
],
"additionalProperties": false
}
},
"behaviors": {
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"properties": {
"kind": {
"const": [
"toggleClass"
]
},
"targetId": {
"type": "string"
},
"className": {
"type": "string"
},
"trigger": {
"type": "string",
"enum": [
"click",
"hover"
]
}
},
"required": [
"kind",
"targetId",
"className"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"kind": {
"const": [
"scrollLink"
]
},
"targetId": {
"type": "string"
},
"offsetPx": {
"type": "number"
}
},
"required": [
"kind",
"targetId"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"kind": {
"const": [
"scrollReveal"
]
},
"className": {
"type": "string"
},
"once": {
"type": "boolean"
},
"threshold": {
"type": "number"
}
},
"required": [
"kind"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"kind": {
"const": [
"openMenu"
]
},
"targetId": {
"type": "string"
}
},
"required": [
"kind",
"targetId"
],
"additionalProperties": false
}
]
}
},
"_site": {
"type": "string",
"description": "Optional target site formatted as <workspaceSlug>/<siteSlug>. Required when the workspace has multiple sites and no site header is set.",
"pattern": "^[^/]+/[^/]+$"
}
},
"additionalProperties": false
}update_state_styles
Update state-specific styles (hover / focus / active, one or many)
Patches a node's interactive-state style overlay — the styles applied when the node is :hover, :focus-visible, or :active. Read first — read_styles(\{nodeId, states:['hover','focus','active']\}) returns exactly the overlays in play. Same shape and tokens as update_styles; the codegen emits a scoped [data-pid="..."]:hover \{ ... \} rule so inline styles can finally express interactivity. Pass state: "default" to write the resting state (alias for update_styles). Empty string clears a property. Common uses: hover-darken a button (state:'hover', styles:\{ background:'var(--color-accent)' \}), focus-ring on inputs, active-pressed on CTAs. Pair with the transition property on the resting state for a smooth animation.
INPUT SHAPES (pick whichever fits — the model-side framing overhead drops linearly with the number of tool calls):
• \{ nodeId, ...patch \} — one node, one patch.
• \{ nodeIds: [id1, id2, …], ...patch \} — same patch fanned out to many nodes (the 'multi-select' shape — use whenever 3+ nodes get the same change).
• \{ updates: [\{ nodeId, ...patch \}, …] \} — different patches per node, batched in one call (use whenever 3+ nodes get different changes; far cheaper than N separate calls).
Missing nodes are skipped silently. The result is \{ ok: true, applied, skipped \}.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
nodeId | string | No | |
nodeIds | array | No | |
updates | array | No | |
state | string | No | |
styles | object | No | |
replace | boolean | No | |
_site | string | No | Optional target site formatted as <workspaceSlug>/<siteSlug>. Required when the workspace has multiple sites and no site header is set. |
Input schema
{
"type": "object",
"properties": {
"nodeId": {
"type": "string"
},
"nodeIds": {
"type": "array",
"items": {
"type": "string"
}
},
"updates": {
"type": "array",
"items": {
"type": "object",
"properties": {
"nodeId": {
"type": "string"
},
"state": {
"type": "string",
"enum": [
"default",
"hover",
"focus",
"active"
]
},
"styles": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
}
},
"replace": {
"type": "boolean"
}
},
"required": [
"nodeId",
"state",
"styles"
],
"additionalProperties": false
}
},
"state": {
"type": "string",
"enum": [
"default",
"hover",
"focus",
"active"
]
},
"styles": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
}
},
"replace": {
"type": "boolean"
},
"_site": {
"type": "string",
"description": "Optional target site formatted as <workspaceSlug>/<siteSlug>. Required when the workspace has multiple sites and no site header is set.",
"pattern": "^[^/]+/[^/]+$"
}
},
"additionalProperties": false
}