Skip to main content
Glama

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework


Tools

Seven tools covering the full display pipeline — from quick styled text to full layered scene composition, device control, and initial setup:

Tool

Description

pixoo_display_text

Render styled text (theme, gradient, shadow, outline, auto-fit) onto the display and push it. Returns the rendered frame as an image.

pixoo_compose_scene

Compose a full scene: layered elements (text, icons, widgets, shapes, bitmaps, images, sprites) with per-element effects and keyframes, static or animated. Returns the rendered scene as an image.

pixoo_push_image

Load an image (absolute local path or https URL), resize it to the LED grid, and push it. Returns the downsampled result as an image.

pixoo_overlay_text

Set or clear a device-native scrolling text overlay. Uses device-rendered fonts; overlays persist across channel switches until cleared.

pixoo_control_device

Read or change device state: brightness, screen on/off, channel, or clock face. Call with no params for a status read.

pixoo_discover_devices

Find Pixoo devices on the local network via Divoom's cloud discovery endpoint. Run once during setup to find device IPs.

pixoo_design_brief

Return craft guidance and live device context for a design topic. Covers legibility rules, palette discipline, layout zones, animation budget, and pre-filled next-tool suggestions.

pixoo_display_text

The primary tool for text-only display. Covers the 80% case — styled text with quality defaults.

  • Named scene themes set background gradient and text palette in one parameter (midnight, ember, claude, ice, neon, forest, mono)

  • Style block: gradient palette ramps (ember, ice, neon, fire, lavender, claude, mono), drop shadow, 1px outline for legibility, integer scale multiplier for block-letter weight

  • Semantic positioning: x: "center", y: "bottom" — no manual pixel math

  • Auto-fit overflow: tries 5×7 → 3×5 → scroll; every fit decision reported in layout[]

  • Returns the rendered frame as an image content block so you see it immediately

  • Optional brightness convenience parameter applied before push


pixoo_compose_scene

Full scene composition with the complete element vocabulary.

  • Layered elements rendered back-to-front: text, icon, rect, circle, line, progress, sparkline, bitmap, pixels, image, sprite

  • Named icons from the built-in registry (weather, arrows, status, media) or custom SVG path

  • Dashboard widgets: progress bar with gradient fill and optional label; sparkline mini chart (line or bar, auto-scaled)

  • Animation: named effect presets (float, scroll-left, scroll-right, pulse, blink, twinkle, drift, fade-in, fade-out) or raw keyframe arrays — 1–40 frames, configurable speed

  • Per-element opacity and visible flag; images at https URLs fetched server-side to a temp file

  • Returns a preview image (static: PNG; animated: labeled contact-sheet PNG + GIF saved to disk)


pixoo_push_image

Push any image to the display with control over the downsampling.

  • Accepts absolute local paths and https URLs

  • Three fit modes: contain (letterbox), cover (crop to fill), fill (stretch)

  • Three resize kernels: nearest for pixel art, lanczos3 for photos, mitchell for a balance

  • Returns the exact 64×64 result as an image block — you see what the display received


pixoo_overlay_text

Device-native scrolling text overlay — persists across channel switches.

  • 115 device-rendered font IDs (0–114)

  • Up to 20 independent overlay slots (IDs 0–19)

  • Configurable scroll direction, speed, and alignment

  • Clears with mode: "clear" — overlays survive channel changes until explicitly removed

  • Not previewable (device-rendered); for styled previewable text use pixoo_display_text


pixoo_design_brief

The orientation tool. Run before authoring any scene to get grounded in 64px craft constraints.

  • Six topics: text, scene, dashboard, animation, pixel-art, troubleshooting

  • Returns legibility floors, palette discipline, layout zones, animation budgets, and common pitfalls

  • Merges live device state (reachable, channel, brightness, screen) into the response

  • Pre-filled nextToolSuggestions with ready-to-use arguments based on current device state


Related MCP server: mcp-divoom-lan

Resources

Type

Name

Description

Resource

pixoo://device/status

Live snapshot of the connected Pixoo display: reachable, channel, brightness, screen state, and display size

Resource

pixoo://reference/themes

Theme and palette registry with background gradients, default text palettes, accent colors, and swatch values

Resource

pixoo://reference/icons

Built-in icon names organized by category (weather, arrows, status, media)

Resource

pixoo://reference/design-guide

Long-form 64px craft guide: legibility floors, palette discipline, layout zones, animation budget, and known device behaviors

All resource data is also reachable via tools. pixoo_design_brief surfaces the design guide content per topic; pixoo_control_device returns live device state equivalent to pixoo://device/status.

Features

Built on @cyanheads/mcp-ts-core:

  • Declarative tool and resource definitions — single file per primitive, framework handles registration and validation

  • Unified error handling — handlers throw, framework catches, classifies, and formats

  • Pluggable auth: none, jwt, oauth

  • Swappable storage backends: in-memory, filesystem, Supabase, Cloudflare KV/R2/D1

  • Structured logging with optional OpenTelemetry tracing

  • STDIO and Streamable HTTP transports, serving MCP protocol revision 2026-07-28 alongside the 2025 revisions

Pixoo-specific:

  • Requires a Divoom Pixoo LED matrix display on the local network; primary target is the Pixoo-64 (16 and 32 also supported)

  • All composition happens in an RGBA canvas pipeline on the host (@cyanheads/pixoo-toolkit) — the device receives final RGB frames, never raw drawing commands

  • Styled text engine: gradient palette ramps, drop shadows, outlines, integer scale, semantic alignment — no manual pixel math or bitmap letterforms required

  • Push pacing: device commands serialized with a configurable minimum inter-push interval (default 1000ms) to prevent device freezes

  • Every PixooResult checked — pushed: true means the device acknowledged with error_code: 0, never "I tried"

  • Animation capped at 40 frames (device instability beyond this); contact-sheet PNG preview for animations (GIF inconsistent across MCP clients)

  • Local transports only — sharp image processing doesn't run on Cloudflare Workers

Agent-friendly output:

  • Preview-as-content: render tools return the upscaled (8×, 512px) output as an image content block — the calling model sees exactly what was drawn, before and after push

  • Layout transparency: every silent renderer decision (font fallback, truncation, scroll engaged, element clipped) reported in layout[] so agents can inspect and refine

  • Device truth: pushed reflects the device ACK; deviceState post-push flags visibility issues (screen off, brightness ≤ 10, wrong channel) as enrichment notices rather than failures

  • Graceful degradation: render succeeds and returns the preview even when the device is unreachable — the agent keeps its work

Getting started

Requirements: A Divoom Pixoo display (Pixoo-64, Pixoo-32, or Pixoo-16) on the same local network as the server. Run pixoo_discover_devices to find its IP, then set PIXOO_IP in your server configuration.

Add the following to your MCP client configuration file:

{
  "mcpServers": {
    "pixoo-mcp-server": {
      "type": "stdio",
      "command": "bunx",
      "args": ["@cyanheads/pixoo-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info",
        "PIXOO_IP": "192.168.1.50"
      }
    }
  }
}

Or with npx (no Bun required):

{
  "mcpServers": {
    "pixoo-mcp-server": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@cyanheads/pixoo-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info",
        "PIXOO_IP": "192.168.1.50"
      }
    }
  }
}

Or with Docker:

{
  "mcpServers": {
    "pixoo-mcp-server": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "MCP_TRANSPORT_TYPE=stdio",
        "-e", "PIXOO_IP=192.168.1.50",
        "ghcr.io/cyanheads/pixoo-mcp-server:latest"
      ]
    }
  }
}

For Streamable HTTP, set the transport and start the server:

MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 PIXOO_IP=192.168.1.50 bun run start:http
# Server listens at http://localhost:3010/mcp

Prerequisites

  • Bun v1.3.2 or higher (or Node.js v24+).

  • A Divoom Pixoo LED matrix display on the local network (Pixoo-64, Pixoo-32, or Pixoo-16). Discovery tools and pure-render tools (push: false) work without a configured device.

Installation

  1. Clone the repository:

git clone https://github.com/cyanheads/pixoo-mcp-server.git
  1. Navigate into the directory:

cd pixoo-mcp-server
  1. Install dependencies:

bun install
  1. Configure environment:

cp .env.example .env
# edit .env and set PIXOO_IP

Configuration

All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:

Variable

Description

Default

PIXOO_IP

Device IP address on the local network. Required for device tools (pixoo_display_text, pixoo_compose_scene, pixoo_push_image, pixoo_overlay_text, pixoo_control_device). Discovery and pure-render (push: false) work without it.

PIXOO_SIZE

Display size in pixels: 16, 32, or 64.

64

PIXOO_OUTPUT_DIR

Directory for auto-saving preview PNG and GIF files. When unset, previews are returned in-response only.

PIXOO_PUSH_MIN_INTERVAL_MS

Minimum interval between device pushes in milliseconds. Prevents device freeze from rapid-fire commands.

1000

MCP_TRANSPORT_TYPE

Transport: stdio or http.

stdio

MCP_HTTP_PORT

HTTP server port.

3010

MCP_SESSION_MODE

HTTP session handling: stateful, stateless, or auto. Shipped as stateless in .env.example and the Dockerfile — no tool requests input mid-call.

auto (resolves to stateful)

MCP_AUTH_MODE

Authentication: none, jwt, or oauth.

none

MCP_LOG_LEVEL

Log level (debug, info, warning, error, etc.).

info

LOGS_DIR

Directory for log files (Node.js only).

<project-root>/logs

STORAGE_PROVIDER_TYPE

Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1.

in-memory

OTEL_ENABLED

Enable OpenTelemetry instrumentation (spans, metrics, completion logs).

false

See .env.example for the full list of optional overrides.

Running the server

Local development

  • Build and run:

    # One-time build
    bun run rebuild
    
    # Run the built server
    bun run start:stdio
    # or
    bun run start:http
  • Run checks and tests:

    bun run devcheck   # Lint, format, typecheck, security
    bun run test       # Vitest test suite
    bun run lint:mcp   # Validate MCP definitions against spec

Docker

docker build -t pixoo-mcp-server .
docker run --rm -e PIXOO_IP=192.168.1.50 -p 3010:3010 pixoo-mcp-server

The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/pixoo-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.

Project structure

Path

Purpose

src/index.ts

createApp() entry point — registers tools/resources and initializes the Pixoo service.

src/config/

Server-specific environment variable parsing and validation with Zod.

src/mcp-server/tools/

Tool definitions (*.tool.ts).

src/mcp-server/resources/

Resource definitions (*.resource.ts).

src/services/pixoo/

PixooService — wraps @cyanheads/pixoo-toolkit, handles pacing, result mapping, and device state.

src/renderer/

Pure rendering pipeline: element renderers, styled-text engine, themes, icons, effect compiler, preview encoding. No device dependency.

tests/

Unit and integration tests mirroring src/.

Development guide

See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:

  • Handlers throw, framework catches — no try/catch in tool logic

  • Use ctx.log for request-scoped logging, ctx.state for tenant-scoped storage

  • The renderer (src/renderer/) is pure — no device dependency, testable without hardware

  • All device calls go through PixooService; every PixooResult is checked

Contributing

Issues and pull requests are welcome. Run checks and tests before submitting:

bun run devcheck
bun run test

License

Apache-2.0 — see LICENSE for details.

Available Tools

7 tools
pixoo_compose_scenepixoo_compose_sceneA
Idempotent

Compose a full scene: layered elements (text, icons, widgets, shapes, bitmaps, images, sprites) with per-element effects and keyframes, static or animated. Returns the rendered scene as an image content block for immediate inspection. Elements render back-to-front in array order. For text-only display use pixoo_display_text; run pixoo_design_brief with topic "scene" or "dashboard" for layout and palette guidance.

ParametersJSON Schema
NameRequiredDescriptionDefault
pushNoPush to device (default: true).
speedNoMilliseconds per frame for animations (default: 150ms).
framesNoNumber of animation frames (1–40, default: 1). 20 frames at 150ms ≈ 3s loop.
outputNoAbsolute, already-normalized path to save the first frame to, in addition to the PIXOO_OUTPUT_DIR auto-save when that is configured. Both paths are reported in outputFiles.
elementsYesScene elements rendered back-to-front. Up to 50 elements.
backgroundYesScene background: solid color, gradient, or named theme.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
framesNoNumber of frames in the rendered output (1 for static, 2–40 for animations).
layoutNoLayout report for each element.
noticeNoWarning or informational notice about the render or push.
pushedNoTrue when the device acknowledged the push. False when push: false or push failed.
deviceStateNoDevice state after the push. Absent when push: false.
outputFilesNoAbsolute paths to saved output files (PNG for static, GIF for animations). Present only when PIXOO_OUTPUT_DIR is configured or output is set.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotentHint=true and destructiveHint=false, covering the safety profile. The description adds genuine behavioral detail beyond that: it returns "the rendered scene as an image content block for immediate inspection" and discloses the z-order rule "Elements render back-to-front in array order." It does not mention the default push-to-device side effect, but this is not a contradiction and the safety info is already well covered by the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences of pure information: the core action with capability summary, the return behavior, and the explicit routing with a requirement. Every sentence earns its place and the most important decision-relevant facts are front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with a rich nested schema, output schema, and annotations, the description does its job: it establishes the composition model, states the z-order semantics, and gives an explicit decision path to sibling tools. The main minor gap is that it does not flag that the scene is, by default, pushed to the device via the 'push' parameter, but that behavior is already fully documented in the schema itself.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema covers 100% of parameters with meaningful descriptions, including the element oneOf discrimination, so the baseline is 3. The description's element type list is a useful summary but it simply reflects what the schema's oneOf already documents. It does not add meaning beyond the schema, which the rubric says the baseline already accounts for.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description starts with the specific verb-resource action "Compose a full scene" and enumerates the element families it covers (text, icons, widgets, shapes, bitmaps, images, sprites) plus the animation capabilities (effects, keyframes, static or animated). It also names the sibling tool pixoo_display_text to make the distinction explicit, so an agent can tell this tool apart without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit routing guidance: "For text-only display use pixoo_display_text" and "run pixoo_design_brief with topic 'scene' or 'dashboard' for layout and palette guidance." This clearly handles the most confusable sibling and the companion design tool, but does not mention exclusions for the other siblings (e.g., pixoo_push_image, among others), so the guidance is strong but not exhaustive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pixoo_control_devicepixoo_control_deviceA
Idempotent

Read or change device state: brightness (0–100), screen on/off, channel, or clock face. Call with no params to read current state only. Supply any params to apply changes before reading back state. Use pixoo_discover_devices first if PIXOO_IP is not yet configured.

ParametersJSON Schema
NameRequiredDescriptionDefault
screenNoTurn the display screen on or off.
channelNoSwitch to a channel: faces, cloud, visualizer, or custom.
brightnessNoSet display brightness (0–100).
clockFaceIdNoSelect a clock face by ID (channel must be faces).

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
appliedNoSettings successfully applied in this call (e.g. "brightness:80", "screen:on"). Empty when called with no params or all changes failed. A requested setting that failed is absent here and reported in a notice instead.
channelNoCurrent channel name (faces, cloud, visualizer, or custom). Absent when device is unreachable.
clockIdNoCurrent clock face ID (faces channel only). Absent on other channels or when device is unreachable.
screenOnNoTrue if the screen is on. Absent when device is unreachable.
reachableNoTrue if device responded to the status read.
brightnessNoCurrent brightness level (0–100). Absent when device is unreachable.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the call idempotent and non-destructive, so the description's main job is to disclose the threshold value of calling it with no params vs applying changes before reading back state. It also usefully notes that pixoo_discover_devices may be needed first. It does not provide deeper details like persistence or authentication, but none are essential here.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, no filler, operationally efficient. The first sentence defines the tool's scope, the second explains the two calling patterns, and the third handles the environment prerequisite.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an optional padded 4-param device-control tool with fully described input fields and an existing output schema, the description covers the main workflow and prerequisite. An agent has enough to invoke it correctly: choose only params if changing state, else omit them to read state.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents every parameter at 100% coverage, so a baseline of 3 applies. The description adds helpful usage semantics by making the interaction rule explicit: 'no params = read', 'any params = apply then read back'. That is valuable beyond the schema structure.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description states a specific operation ('Read or change device state') and enumerates the exact dimensions affected: brightness, screen on/off, channel, and clock face. This clearly separates it from the sibling content-related tools like pixoo_display_text and pixoo_push_image.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly explains when to call with no params (read only) versus with params (apply changes), and names pixoo_discover_devices as a prerequisite when PIXOO_IP is unknown. It could slightly strengthen by naming which siblings are NOT appropriate for device-state changes, but the guidance is otherwise clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pixoo_design_briefpixoo_design_briefA
Read-only

Return craft guidance and live device context for a design topic. Covers legibility rules, palette discipline, layout zones, animation budget, and pre-filled next-tool suggestions based on current device state. The orientation tool to run before authoring a scene, dashboard, or animation — or when troubleshooting display issues.

ParametersJSON Schema
NameRequiredDescriptionDefault
topicYesDesign topic: text (styled text guidance), scene (composition + layout zones), dashboard (widgets + metrics), animation (motion budget + effects), pixel-art (bitmap + sprite guidance), troubleshooting (device + display issues).

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
topicNoThe topic that was requested.
craftGuidanceNoMarkdown-formatted craft rules: legibility floors, palette discipline, layout zones, and technique guidance specific to the topic.
deviceContextNoLive device state snapshot at the time of the request.
iconCategoriesNoBuilt-in icon names grouped by category (weather, arrows, status, media). Use names in pixoo_compose_scene icon elements.
availableThemesNoAvailable named scene themes (e.g. "midnight", "ember"). Use in background.theme or pixoo_display_text theme param.
nextToolSuggestionsNoSuggested next steps based on topic and device state.

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The readOnlyHint annotation already tells agents this is a safe read-only operation, and the description adds useful context about what it returns: craft guidance, live device context, and next-tool suggestions. It does not disclose details about device unavailability or failure modes, but the annotation lowers the burden on the description.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loads the core purpose, and wastes no words. It covers scope, coverage areas, and a clear temporal use case without over-explaining.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with a full enum description, an output schema, and a readOnly annotation, the description is sufficiently complete. It tells agents what the tool does, what topics it covers, when to run it, and how it relates to downstream authoring tools.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema fully documents the only parameter, 'topic,' including an enum and per-value descriptions. The description's mention of topics like legibility rules, palette discipline, layout zones, and animation budget reinforces the enum but does not add essential meaning beyond the schema already covers.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb-resource pair ('Return craft guidance and live device context for a design topic') and clearly defines the tool's role as an orientation tool rather than an authoring tool. It distinguishes itself from sibling tools by framing it as the step to run before authoring or troubleshooting.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use the tool: before authoring a scene, dashboard, or animation, and when troubleshooting display issues. It does not explicitly name alternative tools or exclusion criteria, but the guidance is clear enough to route an agent correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pixoo_discover_devicespixoo_discover_devicesA
Read-only

Find Pixoo devices on the local network via Divoom's cloud discovery endpoint (requires internet — queries app.divoom-gz.com). Run once during initial setup to find device IPs; set PIXOO_IP in server configuration to enable all other tools. For ongoing device control use pixoo_control_device.

ParametersJSON Schema
NameRequiredDescriptionDefault
timeoutMsNoDiscovery timeout in milliseconds (default: 5000ms).

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
noticeNoRecovery hint when no devices found or IP mismatch.
devicesNoDiscovered Pixoo devices on the local network.
configuredIpNoCurrently configured PIXOO_IP value (absent if not set).
configuredIpFoundNoTrue if PIXOO_IP matches a discovered device; false signals an IP mismatch. Absent when PIXOO_IP is not set.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish readOnly and openWorld hints. The description adds value by disclosing the network dependency (requires internet) and the specific external endpoint (app.divoom-gz.com), which are important behavioral traits not captured by annotations. Does not contradict annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three concise sentences, front-loaded with the primary purpose, then the setup context and routing to an alternative. Every sentence earns its place; no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Moderate-low complexity tool with an output schema, so return values need not be described. The description covers purpose, network prerequisites, and post-condition (set PIXOO_IP). Slightly more could be said about what discovery returns, but the output schema already handles that.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with clear description, default, minimum, and maximum for timeoutMs. The narrative description adds nothing about the parameter, but with full schema coverage the baseline of 3 is appropriate since no extra meaning is needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource ('Find Pixoo devices on the local network') and identifies the method via Divoom's cloud discovery endpoint. It distinguishes itself from all sibling tools, which are for display, control, or composition, by being the discovery step.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

States explicitly when to use this tool ('Run once during initial setup'), what to do with the result (set PIXOO_IP in server configuration), and names the alternative for ongoing control (pixoo_control_device). This gives an agent complete routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pixoo_display_textpixoo_display_textA
Idempotent

Render styled text (theme, gradient, shadow, outline, auto-fit) onto the Pixoo display and push it. Returns the rendered frame as an image content block for immediate inspection. The primary tool for text-only display — for layers, icons, widgets, or animations use pixoo_compose_scene. Run pixoo_design_brief with topic "text" first for palette and legibility guidance.

ParametersJSON Schema
NameRequiredDescriptionDefault
fontNoFont variant: standard (5×7) or compact (3×5). Auto-fit will choose if omitted.
pushNoPush the rendered frame to the device (default: true).
textYesText to display. String or array of lines.
alignNoMulti-line text alignment (default: center).
styleNoText style: palette, shadow, outline, scale.
themeNoNamed scene theme — sets background gradient and default text palette.
effectNoAnimation effect. auto = scroll only when text overflows. Produces a multi-frame result.
positionNoText position on the display.
backgroundNoBackground color or gradient. Overrides theme background when set.
brightnessNoSet device brightness before push (0–100). Failure is a warning, not an error.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
layoutNoLayout report: every fit decision the renderer made.
noticeNoWarning or informational message about the render or push.
pushedNoTrue when the device acknowledged the push.
deviceStateNoDevice state after the push. Absent when push: false.
outputFilesNoAbsolute paths to saved PNG preview files. Present only when PIXOO_OUTPUT_DIR is configured.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes beyond the annotations (idempotentHint true, destructiveHint false) by exposing the push-to-device side effect and the fact that the tool returns the rendered frame as an image content block for inspection. This is valuable behavioral information about what physically happens to the display and what the agent should expect in the output.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise, front-loaded with the primary purpose, and every sentence earns its place. It covers the core action, the output behavior, the sibling distinction, and a design brief next step all without significantly bloating.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Combined with the thorough input schema, output schema, and annotations, the description is complete enough for an agent to decide when to call this tool, what parameters to consider, what to expect from the return, and what to do for richer scenes. The shape does not have an obvious missing aspect.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema is fully documented at 100% coverage with detailed descriptions for font, text, align, style, theme, effect, position, background, brightness, and push. The tool description adds no substantive param-level semantics beyond the schema already provides. It names a few style aspects, but the schema itself explains those concepts in detail.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Render'), a specific resource ('text onto the Pixoo display'), and a push-and-return behavior, ending with an image content block. It also fully differentiates itself from the available sibling ('ptixoo_compose_sceene') by declaring itself as the primary text-on-console display tool. This gives the agent enough high-level directional information before inspecting the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says this is the primary tool for text-only display and directs the agent to 'pixoo_compose_cene' for layers, icons, widgets, or animations. It also recommends running 'pixoo_design_brief' with topic 'text' first. That is a useful when-to-use vs. when-not-to-use instruction sequence.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pixoo_overlay_textpixoo_overlay_textA
Idempotent

Set or clear a device-native scrolling text overlay. Use mode "set" to add or update an overlay on a slot (0–19); use mode "clear" to remove it. Overlays use device-rendered fonts (115 font IDs, 0–114) and persist across channel switches until explicitly cleared with mode "clear". Not previewable — rendering happens on-device. Best for persistent tickers over pushed scenes; for styled, previewable text use pixoo_display_text instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
xNoX start position on display (default: 0).
yNoY start position on display (default: 0).
idYesOverlay slot ID (0–19). Each ID is an independent overlay layer.
fontNoDevice font ID (0–114). 0 = default, 18 = arrows, 20 = °C/°F. Device-rendered; no preview.
modeYesset = add/update overlay; clear = remove it.
textNoText to display (required for mode=set).
alignNoText alignment (default: left).left
colorNoText color as CSS hex color (default: white).#ffffff
speedNoScroll speed (0–100, device units; default: 50).
widthNoText region width in pixels (optional; defaults to display width).
directionNoScroll direction (default: left).left

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNoThe overlay slot ID (0–19) that was operated on.
modeNoOperation performed: "set" (overlay added/updated) or "clear" (overlay removed).
errorNoPresent when the call failed. Absent on success.
acknowledgedNoTrue when the device confirmed the overlay command (error_code: 0).

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover idempotency and non-destructiveness, so the description correctly adds behavioral context beyond them: overlays persist across channel switches, rendering happens on-device, and the feature is not previewable. This is genuinely useful invocation-relevant detail.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is brief, front-loaded with the core action, and every sentence contributes: action, mode usage, persistence detail, limitation, and sibling routing. No filler or tautology.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 11 parameters, 2 required, and a rich input schema, the description captures the behavioral context an agent needs: mode semantics, overlay slots, persistence, and when to choose this tool versus pixoo_display_text. No meaningful selection or invocation context is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3; the description reinforces slot/font semantics and mode behavior, but every parameter already has a descriptive schema helper. It does not need to repeat the full parameter list.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description uses specific verbs ('Set or clear') and a specific resource ('device-native scrolling text overlay'), immediately distinguishing its function. It also names the sibling it is not — pixoo_display_text — so an agent can tell them apart without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Describes exactly when to invoke 'set' versus 'clear', and explicitly recommends pixoo_display_text for styled, previewable text. This gives clear routing guidance for the main alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pixoo_push_imagepixoo_push_imageA
Idempotent

Load an image (absolute local path or https URL), resize it to fit the LED grid, and optionally push it to the display. Returns the downsampled result as an image content block so you see exactly what the display received. Nearest-neighbor kernel preserves pixel art; use lanczos3 or mitchell for photos.

ParametersJSON Schema
NameRequiredDescriptionDefault
fitNoResize fit mode: contain (letterbox), cover (crop to fill), fill (stretch).contain
pushNoPush the resized image to the device (default: true).
kernelNoResize kernel: nearest for pixel art, lanczos3 for photos, mitchell for a balance.nearest
sourceYesAbsolute local file path or https (not http) URL of the image to display.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
noticeNoWarning or informational message.
pushedNoTrue when the device acknowledged the push.
deviceStateNoDevice state after the push. Absent when push: false.
outputFilesNoAbsolute paths to saved PNG preview files. Present only when PIXOO_OUTPUT_DIR is configured.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover idempotency (indy), open-world behavior, and not destructive. The description adds valuable behavioral detail: it returns the exact downsampled result as an image content block, and it makes explicit the resize/display pipeline. It doesn' t contradict the annotations. Slight gaps such as failure modes, but for a non-destuctive image utility this is solid.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three compact sentences with no filler. It front-loads the main pipeline, then covers optional push behavior, return value, and kernel guidance. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given only 4 parameters, 1 required, and no output schema explain, the description is sufficient: covers input source, resizing modes, kernel choice, push default, and return-value semantics. The agent can select parameters from either schema or description, and know exactly what to expect back from the tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already defines fit, kernel, push, and source. The description adds real selection guidance on which kernel to choose (nearest for pixel art, lanczos3/mitchell for photos), which is above the baseline and helps the agent pick semantic effective values. Small extra value beyond schema, hence a 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states the operation clearly: load an image from a local path or HTTPS URL, resize it to fit the LED grid, optionally push to the display, and return the downsampled result. This is a specific verb-plus-resource description. It is functionally distinct from the text/device sibling tools, though it does not explicitly name them or contrast itself with a tool like pixoo_compose_scene.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description outlines the pipeline and the 'optionally push' behavior, which implies a preview-only use case when push=false. It does not explicitly state when to use this tool over siblings such as pixoo_compose_scene, pixoo_overlay_text, or pixoo_control_device. There is enough context for the agent to infer, but no direct that when-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 7 tool updatesv1.1.1
    • Changedpixoo_compose_scene10 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedInput schema / properties / elements / items / oneOf
        Previous value: -[
        -  {
        -    "description": "Styled text element rendered at a position.",
        -    "properties": {
        -      "animate": {
        -        "additionalProperties": {
        -          "description": "Keyframe entries: [[frame, value], ...].",
        -          "items": {
        -            "items": [
        -              {
        -                "description": "Frame index.",
        -                "type": "number"
        -              },
        -              {
        -                "anyOf": [
        -                  {
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "boolean"
        -                  }
        -                ],
        -                "description": "Value at this frame."
        -              }
        -            ],
        -            "type": "array"
        -          },
        -          "type": "array"
        -        },
        -        "description": "Raw keyframe animation map for this element.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "color": {
        -        "description": "Flat text color.",
        -        "type": "string"
        -      },
        -      "dx": {
        -        "description": "X offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "dy": {
        -        "description": "Y offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "effect": {
        -        "description": "Named animation preset for this element.",
        -        "properties": {
        -          "amplitude": {
        -            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        -            "type": "number"
        -          },
        -          "name": {
        -            "description": "Named animation preset.",
        -            "enum": [
        -              "float",
        -              "scroll-left",
        -              "scroll-right",
        -              "pulse",
        -              "blink",
        -              "twinkle",
        -              "drift",
        -              "fade-in",
        -              "fade-out"
        -            ],
        -            "type": "string"
        -          },
        -          "period": {
        -            "description": "Effect period in frames. Defaults to total scene frame count.",
        -            "type": "number"
        -          },
        -          "phase": {
        -            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "name"
        -        ],
        -        "type": "object"
        -      },
        -      "font": {
        -        "description": "Font variant.",
        -        "enum": [
        -          "standard",
        -          "compact"
        -        ],
        -        "type": "string"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0–100 (default: 100).",
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "style": {
        -        "description": "Text style options.",
        -        "properties": {
        -          "color": {
        -            "description": "Flat color override.",
        -            "type": "string"
        -          },
        -          "outline": {
        -            "description": "1px outline.",
        -            "type": "boolean"
        -          },
        -          "palette": {
        -            "anyOf": [
        -              {
        -                "description": "Named built-in color palette for the vertical ramp.",
        -                "enum": [
        -                  "ember",
        -                  "ice",
        -                  "neon",
        -                  "fire",
        -                  "lavender",
        -                  "claude",
        -                  "mono"
        -                ],
        -                "type": "string"
        -              },
        -              {
        -                "description": "Custom gradient stop: specify top and bottom colors directly.",
        -                "properties": {
        -                  "from": {
        -                    "description": "Top color.",
        -                    "type": "string"
        -                  },
        -                  "to": {
        -                    "description": "Bottom color.",
        -                    "type": "string"
        -                  }
        -                },
        -                "required": [
        -                  "from",
        -                  "to"
        -                ],
        -                "type": "object"
        -              }
        -            ],
        -            "description": "Palette name or custom gradient stop for vertical color ramp."
        -          },
        -          "scale": {
        -            "description": "Integer pixel scale multiplier.",
        -            "maximum": 8,
        -            "minimum": 1,
        -            "type": "integer"
        -          },
        -          "shadow": {
        -            "description": "Drop shadow.",
        -            "type": "boolean"
        -          }
        -        },
        -        "type": "object"
        -      },
        -      "text": {
        -        "description": "Text content to render.",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "text",
        -        "description": "Text element type.",
        -        "type": "string"
        -      },
        -      "visible": {
        -        "description": "Whether the element is visible (default: true).",
        -        "type": "boolean"
        -      },
        -      "x": {
        -        "anyOf": [
        -          {
        -            "description": "Absolute pixel X coordinate (0 = left edge).",
        -            "type": "number"
        -          },
        -          {
        -            "description": "Semantic horizontal alignment.",
        -            "enum": [
        -              "left",
        -              "center",
        -              "right"
        -            ],
        -            "type": "string"
        -          }
        -        ],
        -        "description": "X position (default: 0)."
        -      },
        -      "y": {
        -        "anyOf": [
        -          {
        -            "description": "Absolute pixel Y coordinate (0 = top edge).",
        -            "type": "number"
        -          },
        -          {
        -            "description": "Semantic vertical alignment.",
        -            "enum": [
        -              "top",
        -              "center",
        -              "bottom"
        -            ],
        -            "type": "string"
        -          }
        -        ],
        -        "description": "Y position (default: 0)."
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "text"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Built-in or custom SVG icon element.",
        -    "properties": {
        -      "animate": {
        -        "additionalProperties": {
        -          "description": "Keyframe entries: [[frame, value], ...].",
        -          "items": {
        -            "items": [
        -              {
        -                "description": "Frame index.",
        -                "type": "number"
        -              },
        -              {
        -                "anyOf": [
        -                  {
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "boolean"
        -                  }
        -                ],
        -                "description": "Value at this frame."
        -              }
        -            ],
        -            "type": "array"
        -          },
        -          "type": "array"
        -        },
        -        "description": "Raw keyframe animation map for this element.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "color": {
        -        "description": "Icon fill color.",
        -        "type": "string"
        -      },
        -      "d": {
        -        "description": "Custom SVG path d attribute.",
        -        "type": "string"
        -      },
        -      "dx": {
        -        "description": "X offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "dy": {
        -        "description": "Y offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "effect": {
        -        "description": "Named animation preset for this element.",
        -        "properties": {
        -          "amplitude": {
        -            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        -            "type": "number"
        -          },
        -          "name": {
        -            "description": "Named animation preset.",
        -            "enum": [
        -              "float",
        -              "scroll-left",
        -              "scroll-right",
        -              "pulse",
        -              "blink",
        -              "twinkle",
        -              "drift",
        -              "fade-in",
        -              "fade-out"
        -            ],
        -            "type": "string"
        -          },
        -          "period": {
        -            "description": "Effect period in frames. Defaults to total scene frame count.",
        -            "type": "number"
        -          },
        -          "phase": {
        -            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "name"
        -        ],
        -        "type": "object"
        -      },
        -      "h": {
        -        "description": "Render height in pixels (default: 12).",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "name": {
        -        "description": "Built-in icon name (see pixoo://reference/icons).",
        -        "type": "string"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0–100 (default: 100).",
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "palette": {
        -        "description": "Named palette for colored icon.",
        -        "enum": [
        -          "ember",
        -          "ice",
        -          "neon",
        -          "fire",
        -          "lavender",
        -          "claude",
        -          "mono"
        -        ],
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "icon",
        -        "description": "Icon element type.",
        -        "type": "string"
        -      },
        -      "viewBox": {
        -        "description": "SVG viewBox string (default: \"0 0 16 16\").",
        -        "type": "string"
        -      },
        -      "visible": {
        -        "description": "Whether the element is visible (default: true).",
        -        "type": "boolean"
        -      },
        -      "w": {
        -        "description": "Render width in pixels (default: 12).",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "x": {
        -        "anyOf": [
        -          {
        -            "description": "Absolute pixel X coordinate (0 = left edge).",
        -            "type": "number"
        -          },
        -          {
        -            "description": "Semantic horizontal alignment.",
        -            "enum": [
        -              "left",
        -              "center",
        -              "right"
        -            ],
        -            "type": "string"
        -          }
        -        ],
        -        "description": "X position."
        -      },
        -      "y": {
        -        "anyOf": [
        -          {
        -            "description": "Absolute pixel Y coordinate (0 = top edge).",
        -            "type": "number"
        -          },
        -          {
        -            "description": "Semantic vertical alignment.",
        -            "enum": [
        -              "top",
        -              "center",
        -              "bottom"
        -            ],
        -            "type": "string"
        -          }
        -        ],
        -        "description": "Y position."
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Filled or gradient rectangle element.",
        -    "properties": {
        -      "animate": {
        -        "additionalProperties": {
        -          "description": "Keyframe entries: [[frame, value], ...].",
        -          "items": {
        -            "items": [
        -              {
        -                "description": "Frame index.",
        -                "type": "number"
        -              },
        -              {
        -                "anyOf": [
        -                  {
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "boolean"
        -                  }
        -                ],
        -                "description": "Value at this frame."
        -              }
        -            ],
        -            "type": "array"
        -          },
        -          "type": "array"
        -        },
        -        "description": "Raw keyframe animation map for this element.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "borderColor": {
        -        "description": "1px border color.",
        -        "type": "string"
        -      },
        -      "color": {
        -        "description": "Fill color.",
        -        "type": "string"
        -      },
        -      "dx": {
        -        "description": "X offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "dy": {
        -        "description": "Y offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "effect": {
        -        "description": "Named animation preset for this element.",
        -        "properties": {
        -          "amplitude": {
        -            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        -            "type": "number"
        -          },
        -          "name": {
        -            "description": "Named animation preset.",
        -            "enum": [
        -              "float",
        -              "scroll-left",
        -              "scroll-right",
        -              "pulse",
        -              "blink",
        -              "twinkle",
        -              "drift",
        -              "fade-in",
        -              "fade-out"
        -            ],
        -            "type": "string"
        -          },
        -          "period": {
        -            "description": "Effect period in frames. Defaults to total scene frame count.",
        -            "type": "number"
        -          },
        -          "phase": {
        -            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "name"
        -        ],
        -        "type": "object"
        -      },
        -      "gradient": {
        -        "description": "Gradient fill.",
        -        "properties": {
        -          "from": {
        -            "description": "Start color.",
        -            "type": "string"
        -          },
        -          "to": {
        -            "description": "End color.",
        -            "type": "string"
        -          },
        -          "type": {
        -            "description": "v = vertical, h = horizontal.",
        -            "enum": [
        -              "v",
        -              "h"
        -            ],
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "type",
        -          "from",
        -          "to"
        -        ],
        -        "type": "object"
        -      },
        -      "h": {
        -        "description": "Height in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0–100 (default: 100).",
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "rect",
        -        "description": "Rectangle element type.",
        -        "type": "string"
        -      },
        -      "visible": {
        -        "description": "Whether the element is visible (default: true).",
        -        "type": "boolean"
        -      },
        -      "w": {
        -        "description": "Width in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "x": {
        -        "description": "X coordinate.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "y": {
        -        "description": "Y coordinate.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "x",
        -      "y",
        -      "w",
        -      "h"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Filled or outline circle element.",
        -    "properties": {
        -      "animate": {
        -        "additionalProperties": {
        -          "description": "Keyframe entries: [[frame, value], ...].",
        -          "items": {
        -            "items": [
        -              {
        -                "description": "Frame index.",
        -                "type": "number"
        -              },
        -              {
        -                "anyOf": [
        -                  {
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "boolean"
        -                  }
        -                ],
        -                "description": "Value at this frame."
        -              }
        -            ],
        -            "type": "array"
        -          },
        -          "type": "array"
        -        },
        -        "description": "Raw keyframe animation map for this element.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "color": {
        -        "description": "Circle color.",
        -        "type": "string"
        -      },
        -      "cx": {
        -        "description": "Center X coordinate.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "cy": {
        -        "description": "Center Y coordinate.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "dx": {
        -        "description": "X offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "dy": {
        -        "description": "Y offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "effect": {
        -        "description": "Named animation preset for this element.",
        -        "properties": {
        -          "amplitude": {
        -            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        -            "type": "number"
        -          },
        -          "name": {
        -            "description": "Named animation preset.",
        -            "enum": [
        -              "float",
        -              "scroll-left",
        -              "scroll-right",
        -              "pulse",
        -              "blink",
        -              "twinkle",
        -              "drift",
        -              "fade-in",
        -              "fade-out"
        -            ],
        -            "type": "string"
        -          },
        -          "period": {
        -            "description": "Effect period in frames. Defaults to total scene frame count.",
        -            "type": "number"
        -          },
        -          "phase": {
        -            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "name"
        -        ],
        -        "type": "object"
        -      },
        -      "fill": {
        -        "description": "Filled or outline only (default: true).",
        -        "type": "boolean"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0–100 (default: 100).",
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "radius": {
        -        "description": "Radius in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "circle",
        -        "description": "Circle element type.",
        -        "type": "string"
        -      },
        -      "visible": {
        -        "description": "Whether the element is visible (default: true).",
        -        "type": "boolean"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "cx",
        -      "cy",
        -      "radius"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Single-pixel line element.",
        -    "properties": {
        -      "animate": {
        -        "additionalProperties": {
        -          "description": "Keyframe entries: [[frame, value], ...].",
        -          "items": {
        -            "items": [
        -              {
        -                "description": "Frame index.",
        -                "type": "number"
        -              },
        -              {
        -                "anyOf": [
        -                  {
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "boolean"
        -                  }
        -                ],
        -                "description": "Value at this frame."
        -              }
        -            ],
        -            "type": "array"
        -          },
        -          "type": "array"
        -        },
        -        "description": "Raw keyframe animation map for this element.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "color": {
        -        "description": "Line color.",
        -        "type": "string"
        -      },
        -      "dx": {
        -        "description": "X offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "dy": {
        -        "description": "Y offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "effect": {
        -        "description": "Named animation preset for this element.",
        -        "properties": {
        -          "amplitude": {
        -            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        -            "type": "number"
        -          },
        -          "name": {
        -            "description": "Named animation preset.",
        -            "enum": [
        -              "float",
        -              "scroll-left",
        -              "scroll-right",
        -              "pulse",
        -              "blink",
        -              "twinkle",
        -              "drift",
        -              "fade-in",
        -              "fade-out"
        -            ],
        -            "type": "string"
        -          },
        -          "period": {
        -            "description": "Effect period in frames. Defaults to total scene frame count.",
        -            "type": "number"
        -          },
        -          "phase": {
        -            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "name"
        -        ],
        -        "type": "object"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0–100 (default: 100).",
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "line",
        -        "description": "Line element type.",
        -        "type": "string"
        -      },
        -      "visible": {
        -        "description": "Whether the element is visible (default: true).",
        -        "type": "boolean"
        -      },
        -      "x0": {
        -        "description": "Start X coordinate.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "x1": {
        -        "description": "End X coordinate.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "y0": {
        -        "description": "Start Y coordinate.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "y1": {
        -        "description": "End Y coordinate.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "x0",
        -      "y0",
        -      "x1",
        -      "y1"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Horizontal progress bar widget.",
        -    "properties": {
        -      "animate": {
        -        "additionalProperties": {
        -          "description": "Keyframe entries: [[frame, value], ...].",
        -          "items": {
        -            "items": [
        -              {
        -                "description": "Frame index.",
        -                "type": "number"
        -              },
        -              {
        -                "anyOf": [
        -                  {
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "boolean"
        -                  }
        -                ],
        -                "description": "Value at this frame."
        -              }
        -            ],
        -            "type": "array"
        -          },
        -          "type": "array"
        -        },
        -        "description": "Raw keyframe animation map for this element.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "dx": {
        -        "description": "X offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "dy": {
        -        "description": "Y offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "effect": {
        -        "description": "Named animation preset for this element.",
        -        "properties": {
        -          "amplitude": {
        -            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        -            "type": "number"
        -          },
        -          "name": {
        -            "description": "Named animation preset.",
        -            "enum": [
        -              "float",
        -              "scroll-left",
        -              "scroll-right",
        -              "pulse",
        -              "blink",
        -              "twinkle",
        -              "drift",
        -              "fade-in",
        -              "fade-out"
        -            ],
        -            "type": "string"
        -          },
        -          "period": {
        -            "description": "Effect period in frames. Defaults to total scene frame count.",
        -            "type": "number"
        -          },
        -          "phase": {
        -            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "name"
        -        ],
        -        "type": "object"
        -      },
        -      "h": {
        -        "description": "Height in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "label": {
        -        "description": "Optional label rendered on the bar.",
        -        "type": "string"
        -      },
        -      "max": {
        -        "description": "Maximum value.",
        -        "type": "number"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0–100 (default: 100).",
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "palette": {
        -        "description": "Named palette for gradient fill.",
        -        "enum": [
        -          "ember",
        -          "ice",
        -          "neon",
        -          "fire",
        -          "lavender",
        -          "claude",
        -          "mono"
        -        ],
        -        "type": "string"
        -      },
        -      "trackColor": {
        -        "description": "Background track color.",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "progress",
        -        "description": "Progress bar widget type.",
        -        "type": "string"
        -      },
        -      "value": {
        -        "description": "Current value.",
        -        "type": "number"
        -      },
        -      "visible": {
        -        "description": "Whether the element is visible (default: true).",
        -        "type": "boolean"
        -      },
        -      "w": {
        -        "description": "Width in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "x": {
        -        "description": "X coordinate.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "y": {
        -        "description": "Y coordinate.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "x",
        -      "y",
        -      "w",
        -      "h",
        -      "value",
        -      "max"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Sparkline chart widget (line or bar).",
        -    "properties": {
        -      "animate": {
        -        "additionalProperties": {
        -          "description": "Keyframe entries: [[frame, value], ...].",
        -          "items": {
        -            "items": [
        -              {
        -                "description": "Frame index.",
        -                "type": "number"
        -              },
        -              {
        -                "anyOf": [
        -                  {
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "boolean"
        -                  }
        -                ],
        -                "description": "Value at this frame."
        -              }
        -            ],
        -            "type": "array"
        -          },
        -          "type": "array"
        -        },
        -        "description": "Raw keyframe animation map for this element.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "color": {
        -        "description": "Line or bar color.",
        -        "type": "string"
        -      },
        -      "data": {
        -        "description": "Data points for the chart.",
        -        "items": {
        -          "type": "number"
        -        },
        -        "minItems": 2,
        -        "type": "array"
        -      },
        -      "dx": {
        -        "description": "X offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "dy": {
        -        "description": "Y offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "effect": {
        -        "description": "Named animation preset for this element.",
        -        "properties": {
        -          "amplitude": {
        -            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        -            "type": "number"
        -          },
        -          "name": {
        -            "description": "Named animation preset.",
        -            "enum": [
        -              "float",
        -              "scroll-left",
        -              "scroll-right",
        -              "pulse",
        -              "blink",
        -              "twinkle",
        -              "drift",
        -              "fade-in",
        -              "fade-out"
        -            ],
        -            "type": "string"
        -          },
        -          "period": {
        -            "description": "Effect period in frames. Defaults to total scene frame count.",
        -            "type": "number"
        -          },
        -          "phase": {
        -            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "name"
        -        ],
        -        "type": "object"
        -      },
        -      "h": {
        -        "description": "Height in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": 2,
        -        "type": "integer"
        -      },
        -      "kind": {
        -        "description": "Chart style (default: line).",
        -        "enum": [
        -          "line",
        -          "bar"
        -        ],
        -        "type": "string"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0–100 (default: 100).",
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "sparkline",
        -        "description": "Sparkline chart widget type.",
        -        "type": "string"
        -      },
        -      "visible": {
        -        "description": "Whether the element is visible (default: true).",
        -        "type": "boolean"
        -      },
        -      "w": {
        -        "description": "Width in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": 2,
        -        "type": "integer"
        -      },
        -      "x": {
        -        "description": "X coordinate.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "y": {
        -        "description": "Y coordinate.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "x",
        -      "y",
        -      "w",
        -      "h",
        -      "data"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Bitmap element using explicit palette indices.",
        -    "properties": {
        -      "animate": {
        -        "additionalProperties": {
        -          "description": "Keyframe entries: [[frame, value], ...].",
        -          "items": {
        -            "items": [
        -              {
        -                "description": "Frame index.",
        -                "type": "number"
        -              },
        -              {
        -                "anyOf": [
        -                  {
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "boolean"
        -                  }
        -                ],
        -                "description": "Value at this frame."
        -              }
        -            ],
        -            "type": "array"
        -          },
        -          "type": "array"
        -        },
        -        "description": "Raw keyframe animation map for this element.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "dx": {
        -        "description": "X offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "dy": {
        -        "description": "Y offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "effect": {
        -        "description": "Named animation preset for this element.",
        -        "properties": {
        -          "amplitude": {
        -            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        -            "type": "number"
        -          },
        -          "name": {
        -            "description": "Named animation preset.",
        -            "enum": [
        -              "float",
        -              "scroll-left",
        -              "scroll-right",
        -              "pulse",
        -              "blink",
        -              "twinkle",
        -              "drift",
        -              "fade-in",
        -              "fade-out"
        -            ],
        -            "type": "string"
        -          },
        -          "period": {
        -            "description": "Effect period in frames. Defaults to total scene frame count.",
        -            "type": "number"
        -          },
        -          "phase": {
        -            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "name"
        -        ],
        -        "type": "object"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0–100 (default: 100).",
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "palette": {
        -        "description": "Color palette: array of hex colors indexed 0-F.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "rows": {
        -        "description": "Row strings of hex palette indices (0-F, space = transparent).",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "bitmap",
        -        "description": "Bitmap element using palette indices.",
        -        "type": "string"
        -      },
        -      "visible": {
        -        "description": "Whether the element is visible (default: true).",
        -        "type": "boolean"
        -      },
        -      "x": {
        -        "description": "X coordinate.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "y": {
        -        "description": "Y coordinate.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "x",
        -      "y",
        -      "rows",
        -      "palette"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Sparse scatter of individually colored pixels.",
        -    "properties": {
        -      "animate": {
        -        "additionalProperties": {
        -          "description": "Keyframe entries: [[frame, value], ...].",
        -          "items": {
        -            "items": [
        -              {
        -                "description": "Frame index.",
        -                "type": "number"
        -              },
        -              {
        -                "anyOf": [
        -                  {
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "boolean"
        -                  }
        -                ],
        -                "description": "Value at this frame."
        -              }
        -            ],
        -            "type": "array"
        -          },
        -          "type": "array"
        -        },
        -        "description": "Raw keyframe animation map for this element.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "data": {
        -        "description": "Array of pixel positions and colors.",
        -        "items": {
        -          "description": "A single pixel: position and color.",
        -          "properties": {
        -            "color": {
        -              "description": "Pixel color.",
        -              "type": "string"
        -            },
        -            "x": {
        -              "description": "Pixel X coordinate.",
        -              "maximum": 9007199254740991,
        -              "minimum": -9007199254740991,
        -              "type": "integer"
        -            },
        -            "y": {
        -              "description": "Pixel Y coordinate.",
        -              "maximum": 9007199254740991,
        -              "minimum": -9007199254740991,
        -              "type": "integer"
        -            }
        -          },
        -          "required": [
        -            "x",
        -            "y",
        -            "color"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "dx": {
        -        "description": "X offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "dy": {
        -        "description": "Y offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "effect": {
        -        "description": "Named animation preset for this element.",
        -        "properties": {
        -          "amplitude": {
        -            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        -            "type": "number"
        -          },
        -          "name": {
        -            "description": "Named animation preset.",
        -            "enum": [
        -              "float",
        -              "scroll-left",
        -              "scroll-right",
        -              "pulse",
        -              "blink",
        -              "twinkle",
        -              "drift",
        -              "fade-in",
        -              "fade-out"
        -            ],
        -            "type": "string"
        -          },
        -          "period": {
        -            "description": "Effect period in frames. Defaults to total scene frame count.",
        -            "type": "number"
        -          },
        -          "phase": {
        -            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "name"
        -        ],
        -        "type": "object"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0–100 (default: 100).",
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "pixels",
        -        "description": "Sparse pixel dots element.",
        -        "type": "string"
        -      },
        -      "visible": {
        -        "description": "Whether the element is visible (default: true).",
        -        "type": "boolean"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "data"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "External image element (local path or https URL).",
        -    "properties": {
        -      "animate": {
        -        "additionalProperties": {
        -          "description": "Keyframe entries: [[frame, value], ...].",
        -          "items": {
        -            "items": [
        -              {
        -                "description": "Frame index.",
        -                "type": "number"
        -              },
        -              {
        -                "anyOf": [
        -                  {
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "boolean"
        -                  }
        -                ],
        -                "description": "Value at this frame."
        -              }
        -            ],
        -            "type": "array"
        -          },
        -          "type": "array"
        -        },
        -        "description": "Raw keyframe animation map for this element.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "dx": {
        -        "description": "X offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "dy": {
        -        "description": "Y offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "effect": {
        -        "description": "Named animation preset for this element.",
        -        "properties": {
        -          "amplitude": {
        -            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        -            "type": "number"
        -          },
        -          "name": {
        -            "description": "Named animation preset.",
        -            "enum": [
        -              "float",
        -              "scroll-left",
        -              "scroll-right",
        -              "pulse",
        -              "blink",
        -              "twinkle",
        -              "drift",
        -              "fade-in",
        -              "fade-out"
        -            ],
        -            "type": "string"
        -          },
        -          "period": {
        -            "description": "Effect period in frames. Defaults to total scene frame count.",
        -            "type": "number"
        -          },
        -          "phase": {
        -            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "name"
        -        ],
        -        "type": "object"
        -      },
        -      "fit": {
        -        "description": "Resize fit mode (default: contain).",
        -        "enum": [
        -          "contain",
        -          "cover",
        -          "fill"
        -        ],
        -        "type": "string"
        -      },
        -      "h": {
        -        "description": "Target height (default: canvas height).",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "kernel": {
        -        "description": "Resize kernel: nearest for pixel art, lanczos3 for photos (default: nearest).",
        -        "enum": [
        -          "nearest",
        -          "lanczos3",
        -          "mitchell"
        -        ],
        -        "type": "string"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0–100 (default: 100).",
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "source": {
        -        "description": "Absolute local file path or https (not http) URL.",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "image",
        -        "description": "Image element (local path or https URL).",
        -        "type": "string"
        -      },
        -      "visible": {
        -        "description": "Whether the element is visible (default: true).",
        -        "type": "boolean"
        -      },
        -      "w": {
        -        "description": "Target width (default: canvas width).",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "x": {
        -        "description": "X offset on canvas (default: 0).",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "y": {
        -        "description": "Y offset on canvas (default: 0).",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "source"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Sprite sheet element for character or tile art.",
        -    "properties": {
        -      "animate": {
        -        "additionalProperties": {
        -          "description": "Keyframe entries: [[frame, value], ...].",
        -          "items": {
        -            "items": [
        -              {
        -                "description": "Frame index.",
        -                "type": "number"
        -              },
        -              {
        -                "anyOf": [
        -                  {
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "boolean"
        -                  }
        -                ],
        -                "description": "Value at this frame."
        -              }
        -            ],
        -            "type": "array"
        -          },
        -          "type": "array"
        -        },
        -        "description": "Raw keyframe animation map for this element.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "bodyColor": {
        -        "description": "Override body color.",
        -        "type": "string"
        -      },
        -      "cols": {
        -        "description": "Number of columns in the sprite grid.",
        -        "maximum": 9007199254740991,
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "darkColor": {
        -        "description": "Override dark/eye color.",
        -        "type": "string"
        -      },
        -      "dx": {
        -        "description": "X offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "dy": {
        -        "description": "Y offset nudge in pixels.",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "effect": {
        -        "description": "Named animation preset for this element.",
        -        "properties": {
        -          "amplitude": {
        -            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        -            "type": "number"
        -          },
        -          "name": {
        -            "description": "Named animation preset.",
        -            "enum": [
        -              "float",
        -              "scroll-left",
        -              "scroll-right",
        -              "pulse",
        -              "blink",
        -              "twinkle",
        -              "drift",
        -              "fade-in",
        -              "fade-out"
        -            ],
        -            "type": "string"
        -          },
        -          "period": {
        -            "description": "Effect period in frames. Defaults to total scene frame count.",
        -            "type": "number"
        -          },
        -          "phase": {
        -            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "name"
        -        ],
        -        "type": "object"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0–100 (default: 100).",
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "path": {
        -        "description": "Absolute local path to the sprite sheet image.",
        -        "type": "string"
        -      },
        -      "rows": {
        -        "description": "Number of rows in the sprite grid.",
        -        "maximum": 9007199254740991,
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "scale": {
        -        "description": "Pixel scale factor.",
        -        "maximum": 9007199254740991,
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "sprite",
        -        "description": "Sprite sheet element.",
        -        "type": "string"
        -      },
        -      "visible": {
        -        "description": "Whether the element is visible (default: true).",
        -        "type": "boolean"
        -      },
        -      "x": {
        -        "anyOf": [
        -          {
        -            "description": "Absolute pixel X coordinate (0 = left edge).",
        -            "type": "number"
        -          },
        -          {
        -            "description": "Semantic horizontal alignment.",
        -            "enum": [
        -              "left",
        -              "center",
        -              "right"
        -            ],
        -            "type": "string"
        -          }
        -        ],
        -        "description": "X position (default: center)."
        -      },
        -      "y": {
        -        "description": "Y position (default: 0).",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "path",
        -      "cols",
        -      "rows"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "description": "Styled text element rendered at a position.",
        +    "properties": {
        +      "animate": {
        +        "additionalProperties": {
        +          "description": "Keyframe entries: [[frame, value], ...].",
        +          "items": {
        +            "prefixItems": [
        +              {
        +                "description": "Frame index.",
        +                "type": "number"
        +              },
        +              {
        +                "anyOf": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "boolean"
        +                  }
        +                ],
        +                "description": "Value at this frame."
        +              }
        +            ],
        +            "type": "array"
        +          },
        +          "type": "array"
        +        },
        +        "description": "Raw keyframe animation map for this element.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "color": {
        +        "description": "Flat text color.",
        +        "type": "string"
        +      },
        +      "dx": {
        +        "description": "X offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "dy": {
        +        "description": "Y offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "effect": {
        +        "description": "Named animation preset for this element.",
        +        "properties": {
        +          "amplitude": {
        +            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        +            "type": "number"
        +          },
        +          "name": {
        +            "description": "Named animation preset.",
        +            "enum": [
        +              "float",
        +              "scroll-left",
        +              "scroll-right",
        +              "pulse",
        +              "blink",
        +              "twinkle",
        +              "drift",
        +              "fade-in",
        +              "fade-out"
        +            ],
        +            "type": "string"
        +          },
        +          "period": {
        +            "description": "Effect period in frames. Defaults to total scene frame count.",
        +            "type": "number"
        +          },
        +          "phase": {
        +            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "name"
        +        ],
        +        "type": "object"
        +      },
        +      "font": {
        +        "description": "Font variant.",
        +        "enum": [
        +          "standard",
        +          "compact"
        +        ],
        +        "type": "string"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0–100 (default: 100).",
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "style": {
        +        "description": "Text style options.",
        +        "properties": {
        +          "color": {
        +            "description": "Flat color override.",
        +            "type": "string"
        +          },
        +          "outline": {
        +            "description": "1px outline.",
        +            "type": "boolean"
        +          },
        +          "palette": {
        +            "anyOf": [
        +              {
        +                "description": "Named built-in color palette for the vertical ramp.",
        +                "enum": [
        +                  "ember",
        +                  "ice",
        +                  "neon",
        +                  "fire",
        +                  "lavender",
        +                  "claude",
        +                  "mono"
        +                ],
        +                "type": "string"
        +              },
        +              {
        +                "description": "Custom gradient stop: specify top and bottom colors directly.",
        +                "properties": {
        +                  "from": {
        +                    "description": "Top color.",
        +                    "type": "string"
        +                  },
        +                  "to": {
        +                    "description": "Bottom color.",
        +                    "type": "string"
        +                  }
        +                },
        +                "required": [
        +                  "from",
        +                  "to"
        +                ],
        +                "type": "object"
        +              }
        +            ],
        +            "description": "Palette name or custom gradient stop for vertical color ramp."
        +          },
        +          "scale": {
        +            "description": "Integer pixel scale multiplier.",
        +            "maximum": 8,
        +            "minimum": 1,
        +            "type": "integer"
        +          },
        +          "shadow": {
        +            "description": "Drop shadow.",
        +            "type": "boolean"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "text": {
        +        "description": "Text content to render.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "text",
        +        "description": "Text element type.",
        +        "type": "string"
        +      },
        +      "visible": {
        +        "description": "Whether the element is visible (default: true).",
        +        "type": "boolean"
        +      },
        +      "x": {
        +        "anyOf": [
        +          {
        +            "description": "Absolute pixel X coordinate (0 = left edge).",
        +            "type": "number"
        +          },
        +          {
        +            "description": "Semantic horizontal alignment.",
        +            "enum": [
        +              "left",
        +              "center",
        +              "right"
        +            ],
        +            "type": "string"
        +          }
        +        ],
        +        "description": "X position (default: 0)."
        +      },
        +      "y": {
        +        "anyOf": [
        +          {
        +            "description": "Absolute pixel Y coordinate (0 = top edge).",
        +            "type": "number"
        +          },
        +          {
        +            "description": "Semantic vertical alignment.",
        +            "enum": [
        +              "top",
        +              "center",
        +              "bottom"
        +            ],
        +            "type": "string"
        +          }
        +        ],
        +        "description": "Y position (default: 0)."
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "text"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Built-in or custom SVG icon element.",
        +    "properties": {
        +      "animate": {
        +        "additionalProperties": {
        +          "description": "Keyframe entries: [[frame, value], ...].",
        +          "items": {
        +            "prefixItems": [
        +              {
        +                "description": "Frame index.",
        +                "type": "number"
        +              },
        +              {
        +                "anyOf": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "boolean"
        +                  }
        +                ],
        +                "description": "Value at this frame."
        +              }
        +            ],
        +            "type": "array"
        +          },
        +          "type": "array"
        +        },
        +        "description": "Raw keyframe animation map for this element.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "color": {
        +        "description": "Icon fill color.",
        +        "type": "string"
        +      },
        +      "d": {
        +        "description": "Custom SVG path d attribute.",
        +        "type": "string"
        +      },
        +      "dx": {
        +        "description": "X offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "dy": {
        +        "description": "Y offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "effect": {
        +        "description": "Named animation preset for this element.",
        +        "properties": {
        +          "amplitude": {
        +            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        +            "type": "number"
        +          },
        +          "name": {
        +            "description": "Named animation preset.",
        +            "enum": [
        +              "float",
        +              "scroll-left",
        +              "scroll-right",
        +              "pulse",
        +              "blink",
        +              "twinkle",
        +              "drift",
        +              "fade-in",
        +              "fade-out"
        +            ],
        +            "type": "string"
        +          },
        +          "period": {
        +            "description": "Effect period in frames. Defaults to total scene frame count.",
        +            "type": "number"
        +          },
        +          "phase": {
        +            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "name"
        +        ],
        +        "type": "object"
        +      },
        +      "h": {
        +        "description": "Render height in pixels (default: 12).",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "name": {
        +        "description": "Built-in icon name (see pixoo://reference/icons).",
        +        "type": "string"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0–100 (default: 100).",
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "palette": {
        +        "description": "Named palette for colored icon.",
        +        "enum": [
        +          "ember",
        +          "ice",
        +          "neon",
        +          "fire",
        +          "lavender",
        +          "claude",
        +          "mono"
        +        ],
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "icon",
        +        "description": "Icon element type.",
        +        "type": "string"
        +      },
        +      "viewBox": {
        +        "description": "SVG viewBox string (default: \"0 0 16 16\").",
        +        "type": "string"
        +      },
        +      "visible": {
        +        "description": "Whether the element is visible (default: true).",
        +        "type": "boolean"
        +      },
        +      "w": {
        +        "description": "Render width in pixels (default: 12).",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "x": {
        +        "anyOf": [
        +          {
        +            "description": "Absolute pixel X coordinate (0 = left edge).",
        +            "type": "number"
        +          },
        +          {
        +            "description": "Semantic horizontal alignment.",
        +            "enum": [
        +              "left",
        +              "center",
        +              "right"
        +            ],
        +            "type": "string"
        +          }
        +        ],
        +        "description": "X position."
        +      },
        +      "y": {
        +        "anyOf": [
        +          {
        +            "description": "Absolute pixel Y coordinate (0 = top edge).",
        +            "type": "number"
        +          },
        +          {
        +            "description": "Semantic vertical alignment.",
        +            "enum": [
        +              "top",
        +              "center",
        +              "bottom"
        +            ],
        +            "type": "string"
        +          }
        +        ],
        +        "description": "Y position."
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Filled or gradient rectangle element.",
        +    "properties": {
        +      "animate": {
        +        "additionalProperties": {
        +          "description": "Keyframe entries: [[frame, value], ...].",
        +          "items": {
        +            "prefixItems": [
        +              {
        +                "description": "Frame index.",
        +                "type": "number"
        +              },
        +              {
        +                "anyOf": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "boolean"
        +                  }
        +                ],
        +                "description": "Value at this frame."
        +              }
        +            ],
        +            "type": "array"
        +          },
        +          "type": "array"
        +        },
        +        "description": "Raw keyframe animation map for this element.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "borderColor": {
        +        "description": "1px border color.",
        +        "type": "string"
        +      },
        +      "color": {
        +        "description": "Fill color.",
        +        "type": "string"
        +      },
        +      "dx": {
        +        "description": "X offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "dy": {
        +        "description": "Y offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "effect": {
        +        "description": "Named animation preset for this element.",
        +        "properties": {
        +          "amplitude": {
        +            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        +            "type": "number"
        +          },
        +          "name": {
        +            "description": "Named animation preset.",
        +            "enum": [
        +              "float",
        +              "scroll-left",
        +              "scroll-right",
        +              "pulse",
        +              "blink",
        +              "twinkle",
        +              "drift",
        +              "fade-in",
        +              "fade-out"
        +            ],
        +            "type": "string"
        +          },
        +          "period": {
        +            "description": "Effect period in frames. Defaults to total scene frame count.",
        +            "type": "number"
        +          },
        +          "phase": {
        +            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "name"
        +        ],
        +        "type": "object"
        +      },
        +      "gradient": {
        +        "description": "Gradient fill.",
        +        "properties": {
        +          "from": {
        +            "description": "Start color.",
        +            "type": "string"
        +          },
        +          "to": {
        +            "description": "End color.",
        +            "type": "string"
        +          },
        +          "type": {
        +            "description": "v = vertical, h = horizontal.",
        +            "enum": [
        +              "v",
        +              "h"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "type",
        +          "from",
        +          "to"
        +        ],
        +        "type": "object"
        +      },
        +      "h": {
        +        "description": "Height in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0–100 (default: 100).",
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "rect",
        +        "description": "Rectangle element type.",
        +        "type": "string"
        +      },
        +      "visible": {
        +        "description": "Whether the element is visible (default: true).",
        +        "type": "boolean"
        +      },
        +      "w": {
        +        "description": "Width in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "X coordinate.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "y": {
        +        "description": "Y coordinate.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "x",
        +      "y",
        +      "w",
        +      "h"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Filled or outline circle element.",
        +    "properties": {
        +      "animate": {
        +        "additionalProperties": {
        +          "description": "Keyframe entries: [[frame, value], ...].",
        +          "items": {
        +            "prefixItems": [
        +              {
        +                "description": "Frame index.",
        +                "type": "number"
        +              },
        +              {
        +                "anyOf": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "boolean"
        +                  }
        +                ],
        +                "description": "Value at this frame."
        +              }
        +            ],
        +            "type": "array"
        +          },
        +          "type": "array"
        +        },
        +        "description": "Raw keyframe animation map for this element.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "color": {
        +        "description": "Circle color.",
        +        "type": "string"
        +      },
        +      "cx": {
        +        "description": "Center X coordinate.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "cy": {
        +        "description": "Center Y coordinate.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "dx": {
        +        "description": "X offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "dy": {
        +        "description": "Y offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "effect": {
        +        "description": "Named animation preset for this element.",
        +        "properties": {
        +          "amplitude": {
        +            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        +            "type": "number"
        +          },
        +          "name": {
        +            "description": "Named animation preset.",
        +            "enum": [
        +              "float",
        +              "scroll-left",
        +              "scroll-right",
        +              "pulse",
        +              "blink",
        +              "twinkle",
        +              "drift",
        +              "fade-in",
        +              "fade-out"
        +            ],
        +            "type": "string"
        +          },
        +          "period": {
        +            "description": "Effect period in frames. Defaults to total scene frame count.",
        +            "type": "number"
        +          },
        +          "phase": {
        +            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "name"
        +        ],
        +        "type": "object"
        +      },
        +      "fill": {
        +        "description": "Filled or outline only (default: true).",
        +        "type": "boolean"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0–100 (default: 100).",
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "radius": {
        +        "description": "Radius in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "circle",
        +        "description": "Circle element type.",
        +        "type": "string"
        +      },
        +      "visible": {
        +        "description": "Whether the element is visible (default: true).",
        +        "type": "boolean"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "cx",
        +      "cy",
        +      "radius"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Single-pixel line element.",
        +    "properties": {
        +      "animate": {
        +        "additionalProperties": {
        +          "description": "Keyframe entries: [[frame, value], ...].",
        +          "items": {
        +            "prefixItems": [
        +              {
        +                "description": "Frame index.",
        +                "type": "number"
        +              },
        +              {
        +                "anyOf": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "boolean"
        +                  }
        +                ],
        +                "description": "Value at this frame."
        +              }
        +            ],
        +            "type": "array"
        +          },
        +          "type": "array"
        +        },
        +        "description": "Raw keyframe animation map for this element.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "color": {
        +        "description": "Line color.",
        +        "type": "string"
        +      },
        +      "dx": {
        +        "description": "X offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "dy": {
        +        "description": "Y offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "effect": {
        +        "description": "Named animation preset for this element.",
        +        "properties": {
        +          "amplitude": {
        +            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        +            "type": "number"
        +          },
        +          "name": {
        +            "description": "Named animation preset.",
        +            "enum": [
        +              "float",
        +              "scroll-left",
        +              "scroll-right",
        +              "pulse",
        +              "blink",
        +              "twinkle",
        +              "drift",
        +              "fade-in",
        +              "fade-out"
        +            ],
        +            "type": "string"
        +          },
        +          "period": {
        +            "description": "Effect period in frames. Defaults to total scene frame count.",
        +            "type": "number"
        +          },
        +          "phase": {
        +            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "name"
        +        ],
        +        "type": "object"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0–100 (default: 100).",
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "line",
        +        "description": "Line element type.",
        +        "type": "string"
        +      },
        +      "visible": {
        +        "description": "Whether the element is visible (default: true).",
        +        "type": "boolean"
        +      },
        +      "x0": {
        +        "description": "Start X coordinate.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "x1": {
        +        "description": "End X coordinate.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "y0": {
        +        "description": "Start Y coordinate.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "y1": {
        +        "description": "End Y coordinate.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "x0",
        +      "y0",
        +      "x1",
        +      "y1"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Horizontal progress bar widget.",
        +    "properties": {
        +      "animate": {
        +        "additionalProperties": {
        +          "description": "Keyframe entries: [[frame, value], ...].",
        +          "items": {
        +            "prefixItems": [
        +              {
        +                "description": "Frame index.",
        +                "type": "number"
        +              },
        +              {
        +                "anyOf": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "boolean"
        +                  }
        +                ],
        +                "description": "Value at this frame."
        +              }
        +            ],
        +            "type": "array"
        +          },
        +          "type": "array"
        +        },
        +        "description": "Raw keyframe animation map for this element.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "dx": {
        +        "description": "X offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "dy": {
        +        "description": "Y offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "effect": {
        +        "description": "Named animation preset for this element.",
        +        "properties": {
        +          "amplitude": {
        +            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        +            "type": "number"
        +          },
        +          "name": {
        +            "description": "Named animation preset.",
        +            "enum": [
        +              "float",
        +              "scroll-left",
        +              "scroll-right",
        +              "pulse",
        +              "blink",
        +              "twinkle",
        +              "drift",
        +              "fade-in",
        +              "fade-out"
        +            ],
        +            "type": "string"
        +          },
        +          "period": {
        +            "description": "Effect period in frames. Defaults to total scene frame count.",
        +            "type": "number"
        +          },
        +          "phase": {
        +            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "name"
        +        ],
        +        "type": "object"
        +      },
        +      "h": {
        +        "description": "Height in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "label": {
        +        "description": "Optional label rendered on the bar.",
        +        "type": "string"
        +      },
        +      "max": {
        +        "description": "Maximum value.",
        +        "type": "number"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0–100 (default: 100).",
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "palette": {
        +        "description": "Named palette for gradient fill.",
        +        "enum": [
        +          "ember",
        +          "ice",
        +          "neon",
        +          "fire",
        +          "lavender",
        +          "claude",
        +          "mono"
        +        ],
        +        "type": "string"
        +      },
        +      "trackColor": {
        +        "description": "Background track color.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "progress",
        +        "description": "Progress bar widget type.",
        +        "type": "string"
        +      },
        +      "value": {
        +        "description": "Current value.",
        +        "type": "number"
        +      },
        +      "visible": {
        +        "description": "Whether the element is visible (default: true).",
        +        "type": "boolean"
        +      },
        +      "w": {
        +        "description": "Width in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "X coordinate.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "y": {
        +        "description": "Y coordinate.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "x",
        +      "y",
        +      "w",
        +      "h",
        +      "value",
        +      "max"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Sparkline chart widget (line or bar).",
        +    "properties": {
        +      "animate": {
        +        "additionalProperties": {
        +          "description": "Keyframe entries: [[frame, value], ...].",
        +          "items": {
        +            "prefixItems": [
        +              {
        +                "description": "Frame index.",
        +                "type": "number"
        +              },
        +              {
        +                "anyOf": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "boolean"
        +                  }
        +                ],
        +                "description": "Value at this frame."
        +              }
        +            ],
        +            "type": "array"
        +          },
        +          "type": "array"
        +        },
        +        "description": "Raw keyframe animation map for this element.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "color": {
        +        "description": "Line or bar color.",
        +        "type": "string"
        +      },
        +      "data": {
        +        "description": "Data points for the chart.",
        +        "items": {
        +          "type": "number"
        +        },
        +        "minItems": 2,
        +        "type": "array"
        +      },
        +      "dx": {
        +        "description": "X offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "dy": {
        +        "description": "Y offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "effect": {
        +        "description": "Named animation preset for this element.",
        +        "properties": {
        +          "amplitude": {
        +            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        +            "type": "number"
        +          },
        +          "name": {
        +            "description": "Named animation preset.",
        +            "enum": [
        +              "float",
        +              "scroll-left",
        +              "scroll-right",
        +              "pulse",
        +              "blink",
        +              "twinkle",
        +              "drift",
        +              "fade-in",
        +              "fade-out"
        +            ],
        +            "type": "string"
        +          },
        +          "period": {
        +            "description": "Effect period in frames. Defaults to total scene frame count.",
        +            "type": "number"
        +          },
        +          "phase": {
        +            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "name"
        +        ],
        +        "type": "object"
        +      },
        +      "h": {
        +        "description": "Height in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": 2,
        +        "type": "integer"
        +      },
        +      "kind": {
        +        "description": "Chart style (default: line).",
        +        "enum": [
        +          "line",
        +          "bar"
        +        ],
        +        "type": "string"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0–100 (default: 100).",
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "sparkline",
        +        "description": "Sparkline chart widget type.",
        +        "type": "string"
        +      },
        +      "visible": {
        +        "description": "Whether the element is visible (default: true).",
        +        "type": "boolean"
        +      },
        +      "w": {
        +        "description": "Width in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": 2,
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "X coordinate.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "y": {
        +        "description": "Y coordinate.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "x",
        +      "y",
        +      "w",
        +      "h",
        +      "data"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Bitmap element using explicit palette indices.",
        +    "properties": {
        +      "animate": {
        +        "additionalProperties": {
        +          "description": "Keyframe entries: [[frame, value], ...].",
        +          "items": {
        +            "prefixItems": [
        +              {
        +                "description": "Frame index.",
        +                "type": "number"
        +              },
        +              {
        +                "anyOf": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "boolean"
        +                  }
        +                ],
        +                "description": "Value at this frame."
        +              }
        +            ],
        +            "type": "array"
        +          },
        +          "type": "array"
        +        },
        +        "description": "Raw keyframe animation map for this element.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "dx": {
        +        "description": "X offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "dy": {
        +        "description": "Y offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "effect": {
        +        "description": "Named animation preset for this element.",
        +        "properties": {
        +          "amplitude": {
        +            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        +            "type": "number"
        +          },
        +          "name": {
        +            "description": "Named animation preset.",
        +            "enum": [
        +              "float",
        +              "scroll-left",
        +              "scroll-right",
        +              "pulse",
        +              "blink",
        +              "twinkle",
        +              "drift",
        +              "fade-in",
        +              "fade-out"
        +            ],
        +            "type": "string"
        +          },
        +          "period": {
        +            "description": "Effect period in frames. Defaults to total scene frame count.",
        +            "type": "number"
        +          },
        +          "phase": {
        +            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "name"
        +        ],
        +        "type": "object"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0–100 (default: 100).",
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "palette": {
        +        "description": "Color palette: array of hex colors indexed 0-F.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "rows": {
        +        "description": "Row strings of hex palette indices (0-F, space = transparent).",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "bitmap",
        +        "description": "Bitmap element using palette indices.",
        +        "type": "string"
        +      },
        +      "visible": {
        +        "description": "Whether the element is visible (default: true).",
        +        "type": "boolean"
        +      },
        +      "x": {
        +        "description": "X coordinate.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "y": {
        +        "description": "Y coordinate.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "x",
        +      "y",
        +      "rows",
        +      "palette"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Sparse scatter of individually colored pixels.",
        +    "properties": {
        +      "animate": {
        +        "additionalProperties": {
        +          "description": "Keyframe entries: [[frame, value], ...].",
        +          "items": {
        +            "prefixItems": [
        +              {
        +                "description": "Frame index.",
        +                "type": "number"
        +              },
        +              {
        +                "anyOf": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "boolean"
        +                  }
        +                ],
        +                "description": "Value at this frame."
        +              }
        +            ],
        +            "type": "array"
        +          },
        +          "type": "array"
        +        },
        +        "description": "Raw keyframe animation map for this element.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "data": {
        +        "description": "Array of pixel positions and colors.",
        +        "items": {
        +          "description": "A single pixel: position and color.",
        +          "properties": {
        +            "color": {
        +              "description": "Pixel color.",
        +              "type": "string"
        +            },
        +            "x": {
        +              "description": "Pixel X coordinate.",
        +              "maximum": 9007199254740991,
        +              "minimum": -9007199254740991,
        +              "type": "integer"
        +            },
        +            "y": {
        +              "description": "Pixel Y coordinate.",
        +              "maximum": 9007199254740991,
        +              "minimum": -9007199254740991,
        +              "type": "integer"
        +            }
        +          },
        +          "required": [
        +            "x",
        +            "y",
        +            "color"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "dx": {
        +        "description": "X offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "dy": {
        +        "description": "Y offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "effect": {
        +        "description": "Named animation preset for this element.",
        +        "properties": {
        +          "amplitude": {
        +            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        +            "type": "number"
        +          },
        +          "name": {
        +            "description": "Named animation preset.",
        +            "enum": [
        +              "float",
        +              "scroll-left",
        +              "scroll-right",
        +              "pulse",
        +              "blink",
        +              "twinkle",
        +              "drift",
        +              "fade-in",
        +              "fade-out"
        +            ],
        +            "type": "string"
        +          },
        +          "period": {
        +            "description": "Effect period in frames. Defaults to total scene frame count.",
        +            "type": "number"
        +          },
        +          "phase": {
        +            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "name"
        +        ],
        +        "type": "object"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0–100 (default: 100).",
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "pixels",
        +        "description": "Sparse pixel dots element.",
        +        "type": "string"
        +      },
        +      "visible": {
        +        "description": "Whether the element is visible (default: true).",
        +        "type": "boolean"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "data"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "External image element (local path or https URL).",
        +    "properties": {
        +      "animate": {
        +        "additionalProperties": {
        +          "description": "Keyframe entries: [[frame, value], ...].",
        +          "items": {
        +            "prefixItems": [
        +              {
        +                "description": "Frame index.",
        +                "type": "number"
        +              },
        +              {
        +                "anyOf": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "boolean"
        +                  }
        +                ],
        +                "description": "Value at this frame."
        +              }
        +            ],
        +            "type": "array"
        +          },
        +          "type": "array"
        +        },
        +        "description": "Raw keyframe animation map for this element.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "dx": {
        +        "description": "X offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "dy": {
        +        "description": "Y offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "effect": {
        +        "description": "Named animation preset for this element.",
        +        "properties": {
        +          "amplitude": {
        +            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        +            "type": "number"
        +          },
        +          "name": {
        +            "description": "Named animation preset.",
        +            "enum": [
        +              "float",
        +              "scroll-left",
        +              "scroll-right",
        +              "pulse",
        +              "blink",
        +              "twinkle",
        +              "drift",
        +              "fade-in",
        +              "fade-out"
        +            ],
        +            "type": "string"
        +          },
        +          "period": {
        +            "description": "Effect period in frames. Defaults to total scene frame count.",
        +            "type": "number"
        +          },
        +          "phase": {
        +            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "name"
        +        ],
        +        "type": "object"
        +      },
        +      "fit": {
        +        "description": "Resize fit mode (default: contain).",
        +        "enum": [
        +          "contain",
        +          "cover",
        +          "fill"
        +        ],
        +        "type": "string"
        +      },
        +      "h": {
        +        "description": "Target height (default: canvas height).",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "kernel": {
        +        "description": "Resize kernel: nearest for pixel art, lanczos3 for photos (default: nearest).",
        +        "enum": [
        +          "nearest",
        +          "lanczos3",
        +          "mitchell"
        +        ],
        +        "type": "string"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0–100 (default: 100).",
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "source": {
        +        "description": "Absolute local file path or https (not http) URL.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "image",
        +        "description": "Image element (local path or https URL).",
        +        "type": "string"
        +      },
        +      "visible": {
        +        "description": "Whether the element is visible (default: true).",
        +        "type": "boolean"
        +      },
        +      "w": {
        +        "description": "Target width (default: canvas width).",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "X offset on canvas (default: 0).",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "y": {
        +        "description": "Y offset on canvas (default: 0).",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "source"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Sprite sheet element for character or tile art.",
        +    "properties": {
        +      "animate": {
        +        "additionalProperties": {
        +          "description": "Keyframe entries: [[frame, value], ...].",
        +          "items": {
        +            "prefixItems": [
        +              {
        +                "description": "Frame index.",
        +                "type": "number"
        +              },
        +              {
        +                "anyOf": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "boolean"
        +                  }
        +                ],
        +                "description": "Value at this frame."
        +              }
        +            ],
        +            "type": "array"
        +          },
        +          "type": "array"
        +        },
        +        "description": "Raw keyframe animation map for this element.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "bodyColor": {
        +        "description": "Override body color.",
        +        "type": "string"
        +      },
        +      "cols": {
        +        "description": "Number of columns in the sprite grid.",
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "darkColor": {
        +        "description": "Override dark/eye color.",
        +        "type": "string"
        +      },
        +      "dx": {
        +        "description": "X offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "dy": {
        +        "description": "Y offset nudge in pixels.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "effect": {
        +        "description": "Named animation preset for this element.",
        +        "properties": {
        +          "amplitude": {
        +            "description": "Effect intensity: pixels of movement for float/scroll/drift, 0–1 scale for fade/pulse. Default varies by effect (float: 2px).",
        +            "type": "number"
        +          },
        +          "name": {
        +            "description": "Named animation preset.",
        +            "enum": [
        +              "float",
        +              "scroll-left",
        +              "scroll-right",
        +              "pulse",
        +              "blink",
        +              "twinkle",
        +              "drift",
        +              "fade-in",
        +              "fade-out"
        +            ],
        +            "type": "string"
        +          },
        +          "period": {
        +            "description": "Effect period in frames. Defaults to total scene frame count.",
        +            "type": "number"
        +          },
        +          "phase": {
        +            "description": "Phase offset 0–1 to stagger this element relative to others (0.5 = half-cycle offset).",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "name"
        +        ],
        +        "type": "object"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0–100 (default: 100).",
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "path": {
        +        "description": "Absolute local path to the sprite sheet image.",
        +        "type": "string"
        +      },
        +      "rows": {
        +        "description": "Number of rows in the sprite grid.",
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "scale": {
        +        "description": "Pixel scale factor.",
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "sprite",
        +        "description": "Sprite sheet element.",
        +        "type": "string"
        +      },
        +      "visible": {
        +        "description": "Whether the element is visible (default: true).",
        +        "type": "boolean"
        +      },
        +      "x": {
        +        "anyOf": [
        +          {
        +            "description": "Absolute pixel X coordinate (0 = left edge).",
        +            "type": "number"
        +          },
        +          {
        +            "description": "Semantic horizontal alignment.",
        +            "enum": [
        +              "left",
        +              "center",
        +              "right"
        +            ],
        +            "type": "string"
        +          }
        +        ],
        +        "description": "X position (default: center)."
        +      },
        +      "y": {
        +        "description": "Y position (default: 0).",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "path",
        +      "cols",
        +      "rows"
        +    ],
        +    "type": "object"
        +  }
        +]
      • changedInput schema / properties / output / description
        Previous value: -"Explicit output file path for saving (overrides PIXOO_OUTPUT_DIR)."New value: +"Absolute, already-normalized path to save the first frame to, in addition to the PIXOO_OUTPUT_DIR auto-save when that is configured. Both paths are reported in outputFiles."
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "pushed",
        +      "frames",
        +      "layout"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable over the network. `device_rejected`: Device firmware returned a non-zero error code. `no_device_configured`: PIXOO_IP is not set and push was requested. `asset_not_found`: An image or sprite path could not be read. `invalid_color`: A color value could not be resolved. `unknown_icon`: Icon name not found in the registry. `invalid_output_path`: The output path is relative or contains traversal segments. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "device_unreachable",
        +            "device_rejected",
        +            "no_device_configured",
        +            "asset_not_found",
        +            "invalid_color",
        +            "unknown_icon",
        +            "invalid_output_path"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / properties / previewData
        Removed value: -{
        -  "description": "Base64-encoded PNG preview of the rendered scene (8× upscaled, 512px). For animations: the middle frame.",
        -  "type": "string"
        -}
      • removedOutput schema / properties / previewMimeType
        Removed value: -{
        -  "description": "MIME type of the preview image.",
        -  "enum": [
        -    "image/png"
        -  ],
        -  "type": "string"
        -}
      • removedOutput schema / required
        Removed value: -[
        -  "pushed",
        -  "frames",
        -  "layout"
        -]
    • Changedpixoo_control_device6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "reachable",
        +      "applied"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable. `device_rejected`: Device rejected the command. `no_device_configured`: PIXOO_IP is not set. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "device_unreachable",
        +            "device_rejected",
        +            "no_device_configured"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "reachable",
        -  "applied"
        -]
    • Changedpixoo_design_brief6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "topic",
        +      "craftGuidance",
        +      "deviceContext",
        +      "nextToolSuggestions",
        +      "availableThemes",
        +      "iconCategories"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode.",
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "topic",
        -  "craftGuidance",
        -  "deviceContext",
        -  "nextToolSuggestions",
        -  "availableThemes",
        -  "iconCategories"
        -]
    • Changedpixoo_discover_devices6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "devices"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `discovery_failed`: Divoom cloud discovery endpoint is unreachable. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "discovery_failed"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "devices"
        -]
    • Changedpixoo_display_text8 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "pushed",
        +      "layout"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable over the network. `device_rejected`: Device firmware returned a non-zero error code. `no_device_configured`: PIXOO_IP is not set. `invalid_color`: A color value could not be resolved. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "device_unreachable",
        +            "device_rejected",
        +            "no_device_configured",
        +            "invalid_color"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / properties / previewData
        Removed value: -{
        -  "description": "Base64-encoded PNG preview of the rendered frame (8× upscaled, 512px).",
        -  "type": "string"
        -}
      • removedOutput schema / properties / previewMimeType
        Removed value: -{
        -  "description": "MIME type of the preview image.",
        -  "enum": [
        -    "image/png"
        -  ],
        -  "type": "string"
        -}
      • removedOutput schema / required
        Removed value: -[
        -  "pushed",
        -  "layout"
        -]
    • Changedpixoo_overlay_text6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "acknowledged",
        +      "mode",
        +      "id"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable. `device_rejected`: Device firmware rejected the command. `no_device_configured`: PIXOO_IP is not set. `invalid_color`: The color value could not be resolved. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "device_unreachable",
        +            "device_rejected",
        +            "no_device_configured",
        +            "invalid_color"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "acknowledged",
        -  "mode",
        -  "id"
        -]
    • Changedpixoo_push_image8 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "pushed"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable. `device_rejected`: Device firmware returned a non-zero error code. `no_device_configured`: PIXOO_IP is not set. `asset_not_found`: Image path or URL could not be read. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "device_unreachable",
        +            "device_rejected",
        +            "no_device_configured",
        +            "asset_not_found"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / properties / previewData
        Removed value: -{
        -  "description": "Base64-encoded PNG preview of the downsampled 64×64 result (8× upscaled, 512px).",
        -  "type": "string"
        -}
      • removedOutput schema / properties / previewMimeType
        Removed value: -{
        -  "description": "MIME type of the preview image.",
        -  "enum": [
        -    "image/png"
        -  ],
        -  "type": "string"
        -}
      • removedOutput schema / required
        Removed value: -[
        -  "pushed"
        -]
  2. 7 tool updatesv1.0.0
    • First observedpixoo_compose_scene
    • First observedpixoo_control_device
    • First observedpixoo_design_brief
    • First observedpixoo_discover_devices
    • First observedpixoo_display_text
    • First observedpixoo_overlay_text
    • First observedpixoo_push_image

TDQS

A4.4/5.0
Disambiguation5/5

Each tool has a clearly distinct purpose: text rendering, scene composition, image pushing, device control, persistent overlays, discovery, and design guidance. Cross-references explicitly explain when to use display_text versus compose_scene versus overlay_text, eliminating ambiguity.

Naming Consistency5/5

All tools follow the same pixoo_ prefix and a verb_noun pattern, such as display_text, compose_scene, push_image, control_device, and discover_devices. Naming is uniform, predictable, and readable with no mixed conventions.

Tool Count5/5

Seven tools is a well-scoped size for a Pixoo LED display server, covering setup, content authoring, display operations, and device management without unnecessary duplication. Each tool earns its place and contributes a meaningful capability.

Completeness4/5

The server covers the main workflows well: discovery, device state, text, images, scenes, overlays, and design guidance. Minor missing operations like a simple clear/reset display method would make coverage more complete, but most users can work around it or use screen-off/push-blank behavior.

Maintenance

ActivityMaintained
ResponsivenessSlow

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    C
    maintenance
    Enables AI clients to control Divoom LAN devices, including watchface management, brightness adjustment, and screen control through natural language.
    18
    63
    2
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Enables LLMs to create and edit pixel art reliably with support for layers, frames, symmetry, and various drawing tools.
    70
    MIT No Attribution
  • F
    license
    A
    quality
    D
    maintenance
    Enables Claude to create, update, and manage LED patterns on a PixelBlaze controller, including setting brightness and reading device info, through a set of tools that interact with the device's API.
    14
    -

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/cyanheads/pixoo-mcp-server'

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