pixoo-mcp-server
Push styled text, composed scenes, images, and HTML-rendered pages to Divoom Pixoo LED displays on the local network via MCP (stdio or Streamable HTTP), plus read/control device state.
Text rendering —
pixoo_display_text: styled text with themes, gradient palettes, shadow, outline, scale 1–8, three fonts (standard 5×7, compact 3×5, numerals 11×18), auto-fit with layout reporting, and scroll/auto/float/pulse effects; returns a preview PNG.Layered scenes —
pixoo_compose_scene: up to 50 back-to-front elements (text, icon, rect, circle, line, progress, sparkline, bitmap, pixels, image, sprite) with opacity, blend modes, gradients/solid/theme backgrounds, 9 effect presets, or raw keyframe animation over dx/dy/opacity/visible/color; 1–800 frames.Image pushing —
pixoo_push_image: resize a local path or https image to the LED grid (contain/cover/fill, nearest/lanczos3/mitchell kernels); animated GIF/WebP pushes as an animation with even frame sampling and optional palette reduction (colors/palette+ dither).HTML rendering —
pixoo_render_html: render an HTML document/fragment (CSS, Canvas, SVG, WebGL) in headless chrome at panel size on a virtual clock for deterministic frame-by-frame animation; exposes apixooglobal for crisp bitmap text, palettes, and icons; returns page errors and blocked URLs.Device-native overlay —
pixoo_overlay_text: set or clear a scrolling text overlay on one of 20 slots with device font IDs 0–114; persists across channel switches, not previewable.Device control —
pixoo_control_device: read state or set brightness 0–100, screen on/off, channel (faces/cloud/visualizer/custom), clock face ID.Discovery —
pixoo_discover_devices: find Pixoo devices and LAN IPs via Divoom's cloud endpoint; reports whetherPIXOO_IPmatches.Design guidance —
pixoo_design_brief: craft guidance per topic (text, scene, dashboard, animation, pixel-art, html, troubleshooting) with live device context, pre-filled next-tool suggestions, themes, and icon categories.Resources —
pixoo://device/status(live device snapshot),pixoo://reference/themes,pixoo://reference/icons,pixoo://reference/design-guide.Agent-friendly output — 8× upscaled PNG preview on every render (works with
push: false, no device needed), animation frame grids,layout[]transparency, device ACK plus post-push state read-back, and saved previews viaPIXOO_OUTPUT_DIReven when pushes fail.
Allows using Cloudflare R2, KV, or D1 as swappable storage backends for managing server data and display assets.
Enables loading, resizing, and pushing JPEG images directly to Divoom Pixoo LED matrices.
Includes support for OpenTelemetry instrumentation to provide observability and monitoring of server operations.
Provides support for using Supabase as a storage backend provider for server data and configurations.
Supports loading and pushing SVG vector graphics to Divoom Pixoo devices with automatic resizing to the display grid.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@pixoo-mcp-serverdisplay 'Meeting in Progress' in red scrolling text and set brightness to 50"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Overview
Divoom Pixoo LED matrix displays on the local network, with the Pixoo-64 as the primary target and the 16 and 32 also supported. Render and push styled text, layered scenes, dashboards, animations, and HTML pages, or read and change device state. Runs as a stdio process or a local Streamable HTTP server.
Tools
Tool | Description |
| Render styled text with themes, gradients, shadows, and auto-fit, static or animated, and push it |
| Compose layered scenes of text, icons, widgets, shapes, bitmaps, images, and sprites, static or animated |
| Resize a local or https image to the LED grid and push it, an animated GIF or WebP as an animation |
| Render an HTML page (CSS, SVG, Canvas, WebGL) in a headless browser at the panel size, still or animated frame by frame on a virtual clock, and push it |
| Set or clear a device-rendered scrolling text overlay |
| Read or change brightness, screen state, channel, or clock face |
| Find Pixoo devices and their LAN IPs through Divoom's cloud discovery |
| Craft guidance for a design topic, with live device state and pre-filled next calls |
Resources
Resource | Description |
| Live device snapshot: reachability, channel, brightness, screen state, display size |
| Theme and palette registry |
| Built-in icon names by category |
| Long-form craft guide for the 64px display |
Tools cover the same ground for tool-only clients: pixoo_control_device reads the live device state, and pixoo_design_brief returns craft guidance, theme names, and icon names.
Related MCP server: mcp-divoom-lan
Capability reference
pixoo_display_text tool
textas a string or an array of lines;theme(midnight,ember,claude,ice,neon,forest,mono) sets the background and default palette.styletakes apaletteramp (ember,ice,neon,fire,lavender,claude,mono) or a custom{ from, to }, plusshadow,outline, andscale1–8;positionis semantic or in pixels, andalignlines up multi-line textfont:standard(5×7) andcompact(3×5) draw printable ASCII plus° ← ↑ → ↓ ▲ ▼ ♥ · …, and any other character (€,’, a newline inside one string) as?, named with its code point and line index in the responsenotice;numeralsis an 11×18 digit face for clocks and readouts that draws 0–9, space, and: . - + / % ° ?, and text holding any other character fails validation, naming those characterslayout[]reports every fit decision as anaction(shrunk-to-compactwhen the text fits only in the compact font,scrollingwhen the returned frames scroll,noneotherwise), thefontused, and whether each line's boxfitson the panel; a single line too wide for the panel starts at x 0, cut at the right edge when it does not scroll. Single-line text falls back from the standard to the compact font unlessfontis set — never tonumerals— and text still too wide only scrolls undereffect: "auto"or"scroll"effect:scrollmakes one pass in up to 40 frames,autoscrolls only on overflow, andfloatandpulseloop over 20 frames;framesreports the count, and the animation pushes as one device animation
pixoo_compose_scene tool
Up to 50
elementsdrawn back-to-front:text(in the same three fonts aspixoo_display_text),icon,rect,circle,line,progress,sparkline,bitmap,pixels,image(absolute path or https URL, with the samefinishaspixoo_push_image),sprite(absolute path). Thebackgroundis a solid color, av/h/rgradient, or athemeEvery element takes
opacity(each pixel lands at its own alpha ×opacity, so soft edges fade evenly) andblend:normal,add(glows and light beams),screen, ormultiply.lineand outlinecircletakestrokeWidthandantialias, and arectborder takesstrokeWidth, growing inward; either field on a shape that draws no stroke fails validation, naming itReturns
layout[]: each element's placed box — for a wide or anti-aliased stroke, every pixel it draws — and whether itfitson the panel. Elements are placed as given and never refit, soactionis alwaysnone. An absoluteoutputpath saves the first frame as a PNG in place of thePIXOO_OUTPUT_DIRauto-save. Typed failures:asset_not_found,invalid_image(an image or sprite that was read but does not decode),invalid_color,unknown_icon,invalid_output_pathAnimation through per-element
effectpresets (float,scroll-left,scroll-right,pulse,blink,twinkle,drift,fade-in,fade-out) or rawanimatekeyframes overdx,dy,opacity(numbers or numeric strings),visible(true/false), andcolor(interpolated through RGB on any element with acolor), each track holding at least one keyframe;frames1–800,speed10–2000 ms per frame (default 150). Past 40 frames the scene plays as one GIF the device downloads from this host, withspeedrounded to 10 ms. An element takeseffectoranimate, not both. An effect'samplitudesets the movement offloat,scroll-*, anddrift, and the 0–1 depth of thepulseandtwinkleopacity dip
pixoo_push_image tool
sourceis an absolute local path or an https URL, with downloads capped at 10 MB;fitiscontain(default),cover, orfill, andkernelisnearest(default, for pixel art),lanczos3(photos), ormitchellA source that decodes as an animated GIF or WebP, whatever its file name, pushes as an animation of up to
maxFramesframes (1–800, default 40), sampled evenly from a longer source; past 40 frames it plays as one GIF the device downloads from this host. It plays at the source's total duration over the pushed frame count (150 ms when the source records no delays), or atspeed(10–2000 ms per frame);frames,sourceFrames, andspeedreport what was pushedfinishreduces the image to a palette before the push: exactly one ofcolors(2–256, built from the image) orpalette(1–256 hex or named colors), plusdither(none,bayer4,floyd-steinberg). Transparent pixels stay unlit, and an animation'scolorspalette is shared by every frameAn unreadable path or URL fails as
asset_not_found, a source that is read but does not decode (a text file, an HTML page, a truncated download) fails asinvalid_image, and an unresolvablefinishpalette entry fails asinvalid_color; the preview is the exact frame the device receives, or a grid of an animation's frames
pixoo_render_html tool
htmlis a full document or a body fragment, up to 500,000 characters, laid out in a square viewport one CSS pixel per LED. The page is the panel:bodyhas no margin, scrollbars are hidden, and a page that paints no background renders on black (unlit). Its own CSS overrides eachframes1–800 (default 1),speed10–2000 ms per frame (default 150). Each frame advances a virtual clock byspeed:window.render(t, frame), when the page defines it, runs before each capture witht = frame / frames, so periodic motion loops seamlessly;requestAnimationFrame,setTimeout/setInterval(4 ms floor for nested and repeating timers),Date(starting at the real time), andperformance.now()(0 at load) follow the same clock, and CSS animations are paused and seeked to it, so every frame is deterministic.requestIdleCallbackand iframes keep real time. Past 40 frames the page plays as one GIF the device downloads from this host, as onpixoo_compose_scenesampling:native(default) orsupersample, which renders at 8× and area-averages into each LED, smoothing transforms, text, SVG, and canvas. Chromium snaps a plain box's edges to whole CSS pixels before scaling, so a box atleft: 0.5pxstill lands on one LED; move it withtransformfor sub-pixel motion.finishtakes the same palette reduction aspixoo_push_image, applied before the previewNothing loads from the network and workers are blocked.
pageErrorsreturns the page's uncaught errors,console.erroroutput, and blocked URLs (a blocked navigation asBlocked navigation: <url>): the first 20, each cut to 500 characters. Awindow.renderthat throws or rejects fails aspage_error, naming the frame; with no browser found, the call fails asbrowser_unavailablewith install steps (see Prerequisites);render_timeoutandrender_crashedcover a render past 30 s and a crashed browser or page.PIXOO_HTML_ENABLED=falseremoves the toolEvery page gets a
pixooglobal before its own scripts run, for the crisp bitmap text, palettes, and icons that browser anti-aliasing would smear across LEDs:pixoo.context()is the 2D context of a transparent panel-size canvas fixed over the page.pixoo.text(ctx, text, x, y, { font, color, palette, scale, shadow, outline })drawspixoo_display_text's fonts.pixoo.icon(ctx, name, x, y, { w, h, color, palette })draws a registry icon.pixoo.palettesholds the 7 palettes, andpixoo.sizeis the panel size.
Text and icons drawn this way match
pixoo_compose_scenepixel for pixel in both sampling modes. An unknown palette, icon, or color throws naming it:<script> const ctx = pixoo.context(); pixoo.text(ctx, 'HELLO', 'center', 4, { palette: 'ember', scale: 2, shadow: true }); pixoo.icon(ctx, 'check-circle', 50, 50, { color: 'green' }); </script>pixoo_design_briefwith topichtmlcovers loops, the clock, sampling, thepixooruntime, and legibility at 64 px. A dot orbiting the panel once per loop:
{
"html": "<svg viewBox=\"0 0 64 64\" style=\"display:block;width:100vw;height:100vh\"><circle id=\"dot\" r=\"6\" fill=\"#ffb000\"/></svg><script>const dot = document.getElementById('dot'); window.render = (t) => { const a = 2 * Math.PI * t; dot.setAttribute('cx', 32 + 20 * Math.cos(a)); dot.setAttribute('cy', 32 + 20 * Math.sin(a)); };</script>",
"frames": 20,
"speed": 100,
"sampling": "supersample"
}pixoo_overlay_text tool
mode: "set"or"clear"on one of 20 slots (id0–19).setrequirestextand takes a devicefontID (0–114),x/ywithinPIXOO_SIZE,color,speed(0–100),direction,align, andwidthReturns
acknowledged,mode, andid. The device renders the overlay, so there is no preview, and it persists across channel switches until cleared
pixoo_control_device tool
No params reads state; any of
brightness(0–100),screen(on/off),channel(faces/cloud/visualizer/custom), orclockFaceIdis applied before the read-backReturns
reachable,channel,brightness,screenOn, andclockId(absent when unreachable) plusapplied; a failed setting is left out ofappliedand named in the notice instead of failing the call
pixoo_discover_devices tool
Queries Divoom's cloud endpoint (
app.divoom-gz.com), so it needs internet access;timeoutMs1000–30000 (default 5000)Returns each device's
name,id, andip; withPIXOO_IPset,configuredIpFoundsays whether it matched. An unreachable endpoint fails asdiscovery_failed
pixoo_design_brief tool
topic:text,scene,dashboard,animation,pixel-art,html, ortroubleshooting; works without a reachable deviceReturns markdown
craftGuidance, a livedeviceContext,htmlRenderer(available,disabledwhenPIXOO_HTML_ENABLED=false, orno_browser, found without launching a browser),nextToolSuggestionsas{ toolName, reason, args }with arguments pre-filled for the topic and device state, plusavailableThemesandiconCategories
pixoo://device/status resource
Uncached live read:
reachable,channel,brightness,screenOn,clockId,displaySize,configuredIpReturns
reachable: falserather than an error when the device can't be reached orPIXOO_IPis unset
pixoo://reference/themes resource
Every theme (background,
textPalette,accent,shadow) and palette (from/tostops), plusthemeNamesandpaletteNamesfor thethemeandpaletteparametersStatic registry, cached for 24h
pixoo://reference/icons resource
Each icon's
name,category, andviewBox, plus abyCategorygrouping (weather, arrows, status, media); anamegoes in apixoo_compose_sceneicon elementStatic registry, cached for 24h
pixoo://reference/design-guide resource
text/markdown: legibility floors, palette discipline, layout zones, animation budget, effect presets, pixel art rules, push pacing, and known device behaviorsThe whole guide in one document, where
pixoo_design_briefreturns guidance per topic; cached for 24h
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
Pixoo-specific:
All composition happens on the host in an RGBA canvas pipeline (
@cyanheads/pixoo-toolkit); the device receives finished RGB framesPushes switch the device to the custom channel and run one at a time, spaced by
PIXOO_PUSH_MIN_INTERVAL_MS(default 1000) so rapid pushes don't freeze the deviceUp to 40 animation frames push one request each; more frame pushes make the device unstable. Past 40,
pixoo_compose_scene,pixoo_push_image, andpixoo_render_html(up to 800 frames) serve one GIF from a one-shot listener on this host, which the device downloads and loops, so the device must be able to reach this host.pixoo_display_textstays within 40
Agent-friendly output:
Preview on every render:
pixoo_display_text,pixoo_compose_scene,pixoo_push_image, andpixoo_render_htmlreturn the frame as an 8× upscaled PNG image block, pushed or not, sopush: falsechecks a design with no device attached. Animations preview as a grid of their frames (every frame while 1× tiles fit the 512 px sheet, an even sample past that), since GIF display varies across MCP clients; the GIF itself is saved toPIXOO_OUTPUT_DIRwhen set — an 8× preview GIF, or past 40 frames the panel-size GIF the device downloadsLayout transparency:
layout[]reports every renderer decision (font fallback, scrolling, and whether each box fits on the panel) so agents can refine a designDevice truth:
pushedreflects the device ACK (past 40 frames, the ACK of the play plus the device's request for the GIF, with the whole file handed to the OS to send; the device does not confirm receipt), and thedeviceStateread back after a push comes with a notice naming the fix when the render won't be visible (screen off, brightness ≤ 10, off the custom channel)Renders survive failed pushes: on all four render tools, the typed error (
device_unreachable,device_http_error,device_rejected,gif_serve_failed,no_device_configured) carriesoutputFilespointing at the saved preview (thePIXOO_OUTPUT_DIRcopy, or a temp file when that is unset)
Getting started
Add the following to your MCP client configuration file, with PIXOO_IP set to your Pixoo's LAN address. pixoo_discover_devices finds it if you don't know it.
{
"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",
"-e", "PIXOO_SERVE_HOST=192.168.1.20",
"-e", "PIXOO_SERVE_PORT=8765",
"-p", "8765:8765",
"ghcr.io/cyanheads/pixoo-mcp-server:latest"
]
}
}
}The device downloads an animation of more than 40 frames from this host, and on Docker's default bridge network the address routed to the device is the container's own, which the device can't reach. Set PIXOO_SERVE_HOST to the Docker host's LAN address and publish a fixed PIXOO_SERVE_PORT, as above; 40 frames or fewer need neither.
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/mcpPrerequisites
Bun v1.4.0 or higher (or Node.js v24+).
A Divoom Pixoo on the local network (Pixoo-64, Pixoo-32, or Pixoo-16).
Optional, for the HTML renderer: chrome-headless-shell.
npx @puppeteer/browsers install chrome-headless-shell@stable --path ~/.cache/puppeteerinstalls it where the server looks by default. Installed anywhere else with--path <dir>, setPIXOO_BROWSER_PATHto the executable path the install prints. The server launches it headless, with no DevTools port, only when a render needs it.
Installation
Clone the repository:
git clone https://github.com/cyanheads/pixoo-mcp-server.gitNavigate into the directory:
cd pixoo-mcp-serverInstall dependencies:
bun installConfigure environment:
cp .env.example .env
# edit .env and set PIXOO_IPConfiguration
Variable | Description | Default |
| Device IP on the local network. Required for pushes, overlays, and device control; discovery, design briefs, and | — |
| Display size in pixels: |
|
| Directory where render tools save preview PNG and GIF files. A relative path resolves against the directory the server was launched from, so the saved paths it reports are absolute. Unset, previews are returned only in the response. | — |
| Minimum gap between device pushes, in ms. |
|
| Host advertised in the URL the device downloads an animation of more than 40 frames from, in place of the local address the OS routes to | — |
| Fixed port for that download's one-shot listener, for firewall rules and container port publishing. Unset, a free port per play. | — |
| Browser executable for HTML rendering. When set, the only browser tried: a path that is not an executable file fails rather than falling back. A relative path resolves against the launch directory. Unset, the newest chrome-headless-shell in Puppeteer's cache ( | — |
| Offer |
|
| Transport: |
|
| HTTP server port. |
|
| HTTP session mode: |
|
| Authentication: |
|
| Log level ( |
|
| Directory for log files (Node.js only). |
|
| Log each failed tool call's arguments and result, redacted by key name and capped at |
|
| Enable OpenTelemetry. |
|
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:httpRun 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 # Real-browser suite for the HTML renderer (opt-in; launches the named browser) PIXOO_TEST_BROWSER_PATH=/path/to/chrome-headless-shell bun run test:browser
Docker
docker build -t pixoo-mcp-server .
docker run --rm -e PIXOO_IP=192.168.1.50 -p 3010:3010 \
-e PIXOO_SERVE_HOST=192.168.1.20 -e PIXOO_SERVE_PORT=8765 -p 8765:8765 \
pixoo-mcp-serverPIXOO_SERVE_HOST (the Docker host's LAN address) and the published PIXOO_SERVE_PORT let the device download animations of more than 40 frames from inside the container, as in the stdio configuration above.
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
Directory | Purpose |
|
|
| Server-specific environment variable parsing and validation with Zod. |
| Tool definitions ( |
| Resource definitions ( |
|
|
|
|
| Pure rendering pipeline with no device dependency: element renderers, styled-text engine, themes, icons, effect compiler, palette finishing, preview encoding, remote image fetch, and the virtual clock injected into HTML pages. |
| Unit and integration tests mirroring |
Development guide
See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storageThe renderer (
src/renderer/) is pure — no device dependency, testable without hardwareAll device calls go through
PixooService; everyPixooResultis checked — never assume a push succeeded
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testLicense
Apache-2.0 — see LICENSE for details.
Available Tools
8 toolspixoo_compose_scenepixoo_compose_sceneAIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| push | No | Push to device (default: true). | |
| speed | No | Milliseconds per frame for animations (default: 150ms). | |
| frames | No | Number of animation frames (1–800, default: 1). 20 frames at 150ms ≈ 3s loop. Up to 40 push frame by frame; more play as one GIF the device downloads from this host, so the device must reach it (behind NAT or a firewall, set PIXOO_SERVE_HOST and PIXOO_SERVE_PORT), and speed rounds to the nearest 10 ms. | |
| output | No | Absolute, already-normalized path to save the first frame to as a PNG. Replaces the PIXOO_OUTPUT_DIR auto-save for this call, so outputFiles holds only this path. | |
| elements | Yes | Scene elements rendered back-to-front. Up to 50 elements. Each element takes either effect or animate, not both. An element's animate keyframes can drive dx, dy, and opacity (numbers or numeric strings, interpolated), visible (true or false, switching at the midpoint between keyframes), and color on any element with a color field (interpolated through RGB). | |
| background | Yes | Scene background: a solid color string, or an object holding exactly one of gradient or theme. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| frames | No | Number of frames in the rendered output (1 for static, 2–800 for animations). |
| layout | No | Layout report for each element. |
| notice | No | Warning or informational notice about the render or push. |
| pushed | No | True when the device acknowledged the push; past 40 frames, once it accepted the GIF play, requested the file, and the whole file was handed to the OS to send (the device does not confirm receipt). False when push: false. |
| deviceState | No | Device state after the push. Absent when push: false. |
| outputFiles | No | Absolute paths to saved output files: the output path when set, otherwise the PIXOO_OUTPUT_DIR auto-save (PNG for static; for animations an 8× GIF, or past 40 frames the panel-size GIF the device downloads). Absent when neither applies. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare idempotentHint=true and destructiveHint=false; the description adds real value by disclosing the return shape (image content block) and the render-order semantics (back-to-front in array order), which annotations do not cover. However, it omits the consequential default that push=true writes to the device, so 'compose' can be mistaken for a local preview; that side effect is left to the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four compact sentences, front-loaded with the core action followed by return behavior, ordering semantics, and alternatives. No sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-format detail is not required, and the description covers layering and alternative routing for a very complex tool. The main residual gap is not flagging that push defaults to true (device write) or the 50-element cap, both of which materially affect how the call is made.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents push, speed, frames, output, background, and the element union in depth. The description adds nothing parameter-specific (no mention of frames/speed/push/output), so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Compose a full scene') and enumerates the layer types (text, icons, widgets, shapes, bitmaps, images, sprites), which maps to the 8 schema element variants. It explicitly distinguishes itself from pixoo_display_text, so an agent can separate it from siblings 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names both alternatives with conditions: pixoo_display_text for text-only output and pixoo_design_brief with topic 'scene'/'dashboard' for layout and palette guidance. That is explicit when-to-use routing rather than inferred usage.
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_deviceAIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| screen | No | Turn the display screen on or off. | |
| channel | No | Switch to a channel: faces, cloud, visualizer, or custom. | |
| brightness | No | Set display brightness (0–100). | |
| clockFaceId | No | Select a clock face by ID (channel must be faces). |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| notice | No | Requested settings that failed, each with its failure kind and message (e.g. "brightness:80 failed (network): …"), joined by "; ". Absent when every requested setting applied. |
| applied | No | Settings 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. |
| channel | No | Current channel name (faces, cloud, visualizer, or custom). Absent when device is unreachable. |
| clockId | No | Current clock face ID (faces channel only). Absent on other channels or when device is unreachable. |
| screenOn | No | True if the screen is on. Absent when device is unreachable. |
| reachable | No | True if device responded to the status read. |
| brightness | No | Current brightness level (0–100). Absent when device is unreachable. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish idempotent and non-destructive behavior, so the description only needs to add extra context. It does so by explaining the read-only vs. apply-then-read behavior, which is not visible in the schema or annotations. It stops short of describing edge cases like invalid parameter combinations, but the output schema and annotations cover the core safety profile.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each earning its place: the first states scope, the second defines read vs. change behavior, the third gives the prerequisite. Information is front-loaded and there is no filler or repetition of schema content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the output schema, annotations, and full schema parameter descriptions, the description covers everything an agent needs to invoke this tool correctly: what it operates on, how to read vs. change, and when to call the discovery tool first. No critical operational gap remains.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds value beyond the schema by defining the no-params read mode and the supply-params-to-apply mode, which is essential for using the parameters correctly. It also reinforces the brightness range and channel/clock face relationship without merely repeating schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description states a specific verb ('Read or change') and resource ('device state') and enumerates the exact aspects affected: brightness, screen on/off, channel, clock face. This clearly differentiates it from sibling tools like pixoo_display_text or pixoo_push_image, which handle content rather than device state.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit usage modes: call with no params to read state, supply params to apply changes and read back. It also names the prerequisite alternative, pixoo_discover_devices, for when PIXOO_IP is not configured, giving clear routing guidance.
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_briefARead-only
Return craft guidance and live device context for a design topic. Covers legibility rules, palette discipline, layout zones, animation budget, HTML page authoring, and pre-filled next-tool suggestions based on current device state. The orientation tool to run before authoring a scene, dashboard, animation, or HTML page — or when troubleshooting display issues.
| Name | Required | Description | Default |
|---|---|---|---|
| topic | Yes | Design topic: text (styled text guidance), scene (composition + layout zones), dashboard (widgets + metrics), animation (motion budget + effects), pixel-art (bitmap + sprite guidance), html (pixoo_render_html pages: loops, clock, sampling), troubleshooting (device + display issues). |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| topic | No | The topic that was requested. |
| htmlRenderer | No | Whether pixoo_render_html can render: available; disabled (PIXOO_HTML_ENABLED=false, so the tool is not listed); or no_browser (no browser found, so the tool fails browser_unavailable until one is installed). |
| craftGuidance | No | Markdown-formatted craft rules: legibility floors, palette discipline, layout zones, and technique guidance specific to the topic. |
| deviceContext | No | Live device state snapshot at the time of the request. |
| iconCategories | No | Built-in icon names grouped by category (weather, arrows, status, media). Use names in pixoo_compose_scene icon elements. |
| availableThemes | No | Available named scene themes (e.g. "midnight", "ember"). Use in background.theme or pixoo_display_text theme param. |
| nextToolSuggestions | No | Suggested next steps based on topic and device state. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is covered. The description adds genuinely useful behavioral context beyond that: it returns live device state and pre-filled next-tool suggestions that vary with current device condition, making clear the output is dynamic rather than static documentation. It does not cover auth requirements or whether device discovery must precede it.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences: capability first, coverage second, usage routing third. Every clause earns its place with no redundancy, and the most actionable routing advice is placed last as a clear call to action.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation here. Combined with a fully documented enum parameter and readOnlyHint annotations, the description supplies everything an agent needs to decide when to call it and what topic values map to which authoring task.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single enum parameter is fully documented with per-value explanations in the schema. The description only restates the coverage areas (legibility, palette, layout zones, animation budget, HTML authoring) without adding format or interpretation guidance beyond the schema, so baseline 3 is correct.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('return craft guidance and live device context') and scopes it to a design topic. It also positions itself against siblings by declaring that it is the orientation tool to run before authoring scenes, dashboards, animations, or HTML pages, so an agent can distinguish it from pixoo_compose_scene and pixoo_render_html without opening their schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear usage context: run it before authoring a scene, dashboard, animation, or HTML page, or when troubleshooting display issues. This effectively routes the agent ahead of the sibling authoring tools. It lacks an explicit when-not condition or a named alternative for cases where it shouldn't be called, so it falls short of a 5.
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_devicesARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| timeoutMs | No | Discovery timeout in milliseconds (default: 5000ms). |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| notice | No | Recovery hint when no devices found or IP mismatch. |
| devices | No | Discovered Pixoo devices on the local network. |
| configuredIp | No | Currently configured PIXOO_IP value (absent if not set). |
| configuredIpFound | No | True if PIXOO_IP matches a discovered device; false signals an IP mismatch. Absent when PIXOO_IP is not set. |
TDQS
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.
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.
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.
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.
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.
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_textAIdempotent
Render styled text (theme, gradient, shadow, outline, auto-fit) onto the Pixoo display and push it, static or animated with a scroll, float, or pulse effect. Returns the render as an image content block for immediate inspection. The primary tool for text-only display — for layers, icons, widgets, or per-element motion use pixoo_compose_scene. Run pixoo_design_brief with topic "text" first for palette and legibility guidance.
| Name | Required | Description | Default |
|---|---|---|---|
| font | No | Font variant, used as given — text too wide for it overflows rather than switching font: standard (5×7) or compact (3×5), each printable ASCII plus ° ← ↑ → ↓ ▲ ▼ ♥ · …; or numerals (11×18 digits for clocks and readouts), which draws only 0–9, space, and : . - + / % ° ?, so text holding any other character is rejected. Omitted, single-line text tries standard and falls back to compact when standard overflows; multi-line text uses standard. | |
| push | No | Push the rendered frame to the device (default: true). | |
| text | Yes | Text to display. String or array of lines. | |
| align | No | Multi-line text: align every line within the widest line, then place that block with position.x. Omit to place each line by position.x on its own. | |
| style | No | Text style: palette, shadow, outline, scale. | |
| theme | No | Named scene theme — sets background gradient and default text palette. | |
| effect | No | Animation effect. scroll runs the text across the display once, in up to 40 frames; auto scrolls only when the text is too wide to fit; float (gentle bob) and pulse (breathing brightness) loop over 20 frames. An animated result is pushed as an animation and previewed as a grid of its frames. none or omitted renders one static frame. | |
| position | No | Text position on the display. | |
| background | No | Background color or gradient. Overrides theme background when set. | |
| brightness | No | Set device brightness before push (0–100). Failure is a warning, not an error. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| frames | No | Number of frames rendered: 1 for static text, 2–40 when an effect animates it. |
| layout | No | Layout report: every fit decision the renderer made. |
| notice | No | Warning or informational message about the render or push. |
| pushed | No | True when the device acknowledged the push. |
| deviceState | No | Device state after the push. Absent when push: false. |
| outputFiles | No | Absolute paths to saved preview files (PNG, or GIF when an effect animates the text). Present only when PIXOO_OUTPUT_DIR is configured. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotentHint and destructiveHint=false, so safety is covered. The description adds genuinely useful behavior beyond that: the return is an image content block for inspection, and an animated result is pushed as an animation and previewed as a grid of frames. It does not discuss failure modes or device-auth requirements, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tightly packed sentences, each earning its place: capability, return/push behavior, sibling routing plus prerequisite. Front-loaded with the core action and no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't explain return values, yet it still notes the image-block preview. Annotations, a 100%-covered schema, and sibling routing together leave nothing an agent needs to call this correctly missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the parameters are richly documented in the schema (font fallback rules, effect frame counts, palette stops, position semantics). The description only gestures at the feature set ('theme, gradient, shadow, outline, auto-fit') without adding syntax or defaults beyond the schema, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource ('Render styled text ... onto the Pixoo display and push it') and enumerates the styling and motion capabilities, so an agent immediately knows this is the text-rendering tool rather than a scene composer or overlay tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly routes away from siblings ('for layers, icons, widgets, or per-element motion use pixoo_compose_scene') and gives a prerequisite ('Run pixoo_design_brief with topic "text" first for palette and legibility guidance'). The only minor omission is distinguishing from pixoo_overlay_text, but the primary routing is explicit.
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_textAIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| x | No | X start position, 0 to display size − 1 (63 on a 64px display; default: 0). | |
| y | No | Y start position, 0 to display size − 1 (63 on a 64px display; default: 0). | |
| id | Yes | Overlay slot ID (0–19). Each ID is an independent overlay layer. | |
| font | No | Device font ID (0–114). 0 = default, 18 = arrows, 20 = °C/°F. Device-rendered; no preview. | |
| mode | Yes | set = add/update overlay; clear = remove it. | |
| text | No | Text to display (required for mode=set). | |
| align | No | Text alignment (default: left). | left |
| color | No | Text color: hex (#RRGGBB or #RGB) or a named color such as orange (default: white). | #ffffff |
| speed | No | Scroll speed (0–100, device units; default: 50). | |
| width | No | Text region width in pixels, 0 to display size (64 on a 64px display; defaults to display width). | |
| direction | No | Scroll direction (default: left). | left |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | The overlay slot ID (0–19) that was operated on. |
| mode | No | Operation performed: "set" (overlay added/updated) or "clear" (overlay removed). |
| error | No | Present when the call failed. Absent on success. |
| acknowledged | No | True when the device confirmed the overlay command (error_code: 0). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds valuable behavioral context beyond the annotations: overlays persist across channel switches, are device-rendered, and are not previewable. The description also makes clear that removal happens via mode 'clear'. No contradiction with the idempotentHint or destructiveHint annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three focused sentences front-load the core operation, then add persistence and preview constraints, and close with a routing pointer. Every sentence earns its place without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex 11-parameter tool with a full output schema and complete property descriptions, the description covers the essential behavioral and routing information. The combination of description, schema, and annotations leaves no critical gap for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning by explaining the mode enum ('set' = add/update, 'clear' = remove) and the slot persistence semantics. It doesn't elaborate on x/y/speed/etc., but the schema already covers those with defaults and ranges.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Set or clear') and a specific resource ('device-native scrolling text overlay'), plus the slot range. It clearly distinguishes itself from pixoo_display_text, so an agent can tell them 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says this is 'best for persistent tickers over pushed scenes' and names the alternative for styled/previewable text ('use pixoo_display_text instead'). It also explains when to use mode 'set' vs 'clear', giving the agent clear routing guidance.
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_imageAIdempotent
Load an image (absolute local path or https URL), resize it to fit the LED grid, and optionally push it to the display. An animated GIF or WebP pushes as an animation of up to maxFrames frames (default 40), sampled evenly from a longer source and played at the speed that keeps its loop length; past 40 frames it plays as one GIF the device downloads from this host. Returns the downsampled result as an image content block so you see exactly what the display received — for an animation, a grid of its frames, evenly sampled once they outnumber what fits the sheet. Nearest-neighbor kernel preserves pixel art; use lanczos3 or mitchell for photos. finish reduces the result to a small or fixed palette, optionally dithered.
| Name | Required | Description | Default |
|---|---|---|---|
| fit | No | Resize fit mode: contain (letterbox), cover (crop to fill), fill (stretch). | contain |
| push | No | Push the resized image to the device (default: true). | |
| speed | No | Milliseconds per frame for an animated source (10–2000). Default: the source's total duration over the pushed frame count, or 150 when it records no delays. A still ignores it. | |
| finish | No | Reduce the image to a palette before it reaches the panel: exactly one of colors (2–256, built from the image) or palette (1–256 hex or named colors), plus dither. Transparent pixels stay unlit and are not counted. The preview shows the finished frame. | |
| kernel | No | Resize kernel: nearest for pixel art, lanczos3 for photos, mitchell for a balance. | nearest |
| source | Yes | Absolute local file path or https (not http) URL of the image to display; a relative path is rejected. An animated GIF or WebP, whatever its file name, pushes as an animation. | |
| maxFrames | No | Most frames an animated source pushes (1–800, default 40); a longer source is sampled evenly down to it. Up to 40 push frame by frame; more play as one GIF the device downloads from this host, so the device must reach it (behind NAT or a firewall, set PIXOO_SERVE_HOST and PIXOO_SERVE_PORT), and speed rounds to the nearest 10 ms. A still ignores it. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| speed | No | Milliseconds per frame the animation plays at. Absent for a still. |
| frames | No | Frames rendered and pushed: 1 for a still, 2 to maxFrames for an animation. |
| notice | No | Warning or informational message. |
| pushed | No | True when the device acknowledged the push; past 40 frames, once it accepted the GIF play, requested the file, and the whole file was handed to the OS to send (the device does not confirm receipt). |
| deviceState | No | Device state after the push. Absent when push: false. |
| outputFiles | No | Absolute paths to saved preview files: a PNG for a still, an 8× GIF at the pushed speed for an animation, or past 40 frames the panel-size GIF the device downloads. Present only when PIXOO_OUTPUT_DIR is configured. |
| sourceFrames | No | Frames in the source before sampling down to maxFrames: 1 for a still. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the annotations (openWorld/idempotent/non-destructive) by disclosing non-obvious behavior: sources over 40 frames become a device-downloaded GIF, so the device must be able to reach this host and PIXOO_SERVE_HOST/PIXOO_SERVE_PORT may be required behind NAT; speed rounds to the nearest 10 ms above that threshold. It also explains the interleaved preview return and how transparent pixels are treated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first clause and almost every sentence carries load-bearing detail (frame limits, kernel choice, preview, dithering). The sentences are dense and run long, which slightly hurts scanability, but there is little outright filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter tool with an output schema, the description covers the remaining unknowns an agent needs: source format constraints, animation vs still behavior, frame-cap network implications, and kernel/palette choices. Nothing required to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds cross-parameter meaning the schema states only piecewise: frames are sampled evenly and played at a speed that preserves loop length, and finish optionally dithers the palette. It does not materially extend source/fit/push beyond their schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with full scope: load an image from a path or https URL, resize it to the LED grid, and optionally push it. It is clearly distinguishable from text-oriented siblings like pixoo_display_text or pixoo_overlay_text without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives real selection guidance at the parameter level (nearest for pixel art, lanczos3/mitchell for photos; finish for palette reduction) but never states when to choose this tool over siblings such as pixoo_compose_scene or pixoo_display_text, nor when to set push=false. Usage is implied rather than routed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pixoo_render_htmlpixoo_render_htmlAIdempotent
Render an HTML page — a full document or a body fragment, with inline CSS, Canvas, SVG, or WebGL — in a headless browser at the panel size, and optionally push it to the display. Animate it by capturing up to 800 frames on a virtual clock that advances speed ms per frame: window.render(t, frame), when the page defines it, runs before each capture with t = frame / frames, so periodic motion loops seamlessly; CSS animations, requestAnimationFrame, timers, Date, and performance.now follow the same clock, so every frame is deterministic. The page loads nothing from the network and starts no workers; a page with no background renders on black, which the panel shows as unlit. Every page gets a pixoo global before its own scripts run: pixoo.text, pixoo.icon, and pixoo.palettes draw crisp bitmap text, gradient palettes, and icons exactly as pixoo_compose_scene does. Returns the captured result as an image content block — for an animation, a grid of its frames — and the page's uncaught and console errors as pageErrors. Run pixoo_design_brief with topic "html" first for loop, clock, sampling, legibility, and pixoo runtime guidance.
| Name | Required | Description | Default |
|---|---|---|---|
| html | Yes | The page to render: a full HTML document or a body fragment, up to 500,000 characters, served with <!doctype html> prepended. It lays out in a square viewport one CSS pixel per LED (64×64 on a Pixoo-64). Inline scripts and styles run and data: and blob: URLs load; a network URL is blocked and listed in pageErrors. | |
| push | No | Push to device (default: true). | |
| speed | No | Milliseconds per frame (10–2000, default: 150): how far the virtual clock advances between captures, and how fast the animation plays. | |
| finish | No | Reduce the image to a palette before it reaches the panel: exactly one of colors (2–256, built from the image) or palette (1–256 hex or named colors), plus dither. Transparent pixels stay unlit and are not counted. The preview shows the finished frame. | |
| frames | No | Number of frames to capture (1–800, default: 1). At frame i, window.render gets t = i / frames and performance.now() reads i × speed. Up to 40 push frame by frame; more play as one GIF the device downloads from this host, so the device must reach it (behind NAT or a firewall, set PIXOO_SERVE_HOST and PIXOO_SERVE_PORT), and speed rounds to the nearest 10 ms. | |
| output | No | Absolute, already-normalized path to save the first frame to as a PNG. Replaces the PIXOO_OUTPUT_DIR auto-save for this call, so outputFiles holds only this path. | |
| sampling | No | native (default) captures one CSS pixel per LED. supersample renders at 8× and averages each 8×8 block into one LED, so transforms, text, SVG, and canvas shade smoothly; a plain box still snaps to whole CSS pixels (left: 0.5px lands on one LED), so move it with transform for sub-pixel motion. | native |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| frames | No | Number of frames captured (1 for a still, 2–800 for an animation). |
| notice | No | Warning or informational notice about the render or push. |
| pushed | No | True when the device acknowledged the push; past 40 frames, once it accepted the GIF play, requested the file, and the whole file was handed to the OS to send (the device does not confirm receipt). False when push: false. |
| pageErrors | No | The page's uncaught errors, console.error output, and blocked request URLs, in the order they arrived: the first 20, each cut to 500 characters. Empty when the page reported none. |
| deviceState | No | Device state after the push. Absent when push: false. |
| outputFiles | No | Absolute paths to saved output files: the output path when set, otherwise the PIXOO_OUTPUT_DIR auto-save (PNG for a still; for an animation an 8× GIF, or past 40 frames the panel-size GIF the device downloads). Absent when neither applies. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Far exceeds the (already low) bar set by idempotentHint/destructiveHint: it discloses the network-free sandbox, no workers, black-background default, deterministic virtual clock semantics, the 800-frame cap, the >40-frame GIF-requires-host-reachable behavior with PIXOO_SERVE_HOST, speed rounding, and that uncaught/console errors come back as pageErrors. That is rich operational context an agent could not infer from annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose is front-loaded in the first clause and every sentence carries substance. It is dense and lengthy, with a few clauses (e.g. the full re-derivation of the clock rules) that partly restate what parameters later say, keeping it just shy of a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter, side-effecting renderer this is complete: it explains the execution sandbox, the animation model, the push/GIF delivery constraint, and the return shape (image content block, frame grid, pageErrors) — and an output schema exists, so return values needn't be spelled out further.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 100% schema coverage the baseline is 3, but the description adds cross-parameter meaning the schema lacks: how window.render(t, frame) is invoked, that t = frame/frames produces seamless looping, and how the same clock drives CSS/rAF/timers. The pixoo global injection and network-block behavior also deepen parameters beyond their literal schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
It uses a precise verb+resource ('Render an HTML page ... in a headless browser at the panel size') and enumerates the supported content types (inline CSS, Canvas, SVG, WebGL, animation). It also differentiates itself from siblings by name, calling out that the pixoo global draws 'exactly as pixoo_compose_scene does' and routing to pixoo_design_brief. An agent can select it without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context for the animation path (capture frames for a loop, run pixoo_design_brief first) and the push toggle, but it never states an explicit when-not or a direct either/or against a sibling such as pixoo_push_image. Usage is strongly implied rather than laid out as alternatives.
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.
4 tool updates
v1.4.0- Changed
pixoo_compose_scene7 fields changed- changed
Input schema / properties / frames / descriptionPrevious value: -"Number of animation frames (1–40, default: 1). 20 frames at 150ms ≈ 3s loop."New value: +"Number of animation frames (1–800, default: 1). 20 frames at 150ms ≈ 3s loop. Up to 40 push frame by frame; more play as one GIF the device downloads from this host, so the device must reach it (behind NAT or a firewall, set PIXOO_SERVE_HOST and PIXOO_SERVE_PORT), and speed rounds to the nearest 10 ms." - changed
Input schema / properties / frames / maximumPrevious value: -40New value: +800 - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable over the network. `device_http_error`: The device answered with a non-2xx HTTP status (retryable for 408, 429, 500, and 502–504). `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 source or sprite path could not be read, a sprite path was a URL, or an image URL could not be fetched. `invalid_image`: An image source or sprite path was read but did not decode as an image. `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."New value: +"Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable over the network. `device_http_error`: The device answered with a non-2xx HTTP status (retryable for 408, 429, 500, and 502–504). `device_rejected`: Device firmware returned a non-zero error code. `gif_serve_failed`: An animation of more than 40 frames could not be served to the device: its listener failed to open, its URL ran past 255 bytes, or the device did not request the GIF within 10 s of the play, stalled its transfer for 10 s, or dropped it. `no_device_configured`: PIXOO_IP is not set and push was requested. `asset_not_found`: An image source or sprite path could not be read, a sprite path was a URL, or an image URL could not be fetched. `invalid_image`: An image source or sprite path was read but did not decode as an image. `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." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "device_unreachable", - "device_http_error", - "device_rejected", - "no_device_configured", - "asset_not_found", - "invalid_image", - "invalid_color", - "unknown_icon", - "invalid_output_path" -]New value: +[ + "device_unreachable", + "device_http_error", + "device_rejected", + "gif_serve_failed", + "no_device_configured", + "asset_not_found", + "invalid_image", + "invalid_color", + "unknown_icon", + "invalid_output_path" +] - changed
Output schema / properties / frames / descriptionPrevious value: -"Number of frames in the rendered output (1 for static, 2–40 for animations)."New value: +"Number of frames in the rendered output (1 for static, 2–800 for animations)." - changed
Output schema / properties / outputFiles / descriptionPrevious value: -"Absolute paths to saved output files: the output path when set, otherwise the PIXOO_OUTPUT_DIR auto-save (PNG for static, GIF for animations). Absent when neither applies."New value: +"Absolute paths to saved output files: the output path when set, otherwise the PIXOO_OUTPUT_DIR auto-save (PNG for static; for animations an 8× GIF, or past 40 frames the panel-size GIF the device downloads). Absent when neither applies." - changed
Output schema / properties / pushed / descriptionPrevious value: -"True when the device acknowledged the push. False when push: false or push failed."New value: +"True when the device acknowledged the push; past 40 frames, once it accepted the GIF play, requested the file, and the whole file was handed to the OS to send (the device does not confirm receipt). False when push: false."
- Changed
pixoo_design_brief4 fields changed- changed
Input schema / properties / topic / descriptionPrevious value: -"Design 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)."New value: +"Design topic: text (styled text guidance), scene (composition + layout zones), dashboard (widgets + metrics), animation (motion budget + effects), pixel-art (bitmap + sprite guidance), html (pixoo_render_html pages: loops, clock, sampling), troubleshooting (device + display issues)." - changed
Input schema / properties / topic / enumPrevious value: -[ - "text", - "scene", - "dashboard", - "animation", - "pixel-art", - "troubleshooting" -]New value: +[ + "text", + "scene", + "dashboard", + "animation", + "pixel-art", + "html", + "troubleshooting" +] - changed
Output schema / anyOfPrevious value: -[ - { - "not": { - "required": [ - "error" - ] - }, - "required": [ - "topic", - "craftGuidance", - "deviceContext", - "nextToolSuggestions", - "availableThemes", - "iconCategories" - ] - }, - { - "required": [ - "error" - ] - } -]New value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "topic", + "craftGuidance", + "deviceContext", + "htmlRenderer", + "nextToolSuggestions", + "availableThemes", + "iconCategories" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / htmlRendererAdded value: +{ + "description": "Whether pixoo_render_html can render: available; disabled (PIXOO_HTML_ENABLED=false, so the tool is not listed); or no_browser (no browser found, so the tool fails browser_unavailable until one is installed).", + "enum": [ + "available", + "disabled", + "no_browser" + ], + "type": "string" +}
- Changed
pixoo_push_image7 fields changed- added
Input schema / properties / maxFramesAdded value: +{ + "default": 40, + "description": "Most frames an animated source pushes (1–800, default 40); a longer source is sampled evenly down to it. Up to 40 push frame by frame; more play as one GIF the device downloads from this host, so the device must reach it (behind NAT or a firewall, set PIXOO_SERVE_HOST and PIXOO_SERVE_PORT), and speed rounds to the nearest 10 ms. A still ignores it.", + "maximum": 800, + "minimum": 1, + "type": "integer" +} - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable. `device_http_error`: The device answered with a non-2xx HTTP status (retryable for 408, 429, 500, and 502–504). `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. `invalid_image`: The source was read but did not decode as an image. `invalid_color`: A finish palette entry could not be resolved to a color. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable. `device_http_error`: The device answered with a non-2xx HTTP status (retryable for 408, 429, 500, and 502–504). `device_rejected`: Device firmware returned a non-zero error code. `gif_serve_failed`: An animation of more than 40 frames could not be served to the device: its listener failed to open, its URL ran past 255 bytes, or the device did not request the GIF within 10 s of the play, stalled its transfer for 10 s, or dropped it. `no_device_configured`: PIXOO_IP is not set. `asset_not_found`: Image path or URL could not be read. `invalid_image`: The source was read but did not decode as an image. `invalid_color`: A finish palette entry could not be resolved to a color. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "device_unreachable", - "device_http_error", - "device_rejected", - "no_device_configured", - "asset_not_found", - "invalid_image", - "invalid_color" -]New value: +[ + "device_unreachable", + "device_http_error", + "device_rejected", + "gif_serve_failed", + "no_device_configured", + "asset_not_found", + "invalid_image", + "invalid_color" +] - changed
Output schema / properties / frames / descriptionPrevious value: -"Frames rendered and pushed: 1 for a still, 2–40 for an animation."New value: +"Frames rendered and pushed: 1 for a still, 2 to maxFrames for an animation." - changed
Output schema / properties / outputFiles / descriptionPrevious value: -"Absolute paths to saved preview files: a PNG for a still, a GIF at the pushed speed for an animation. Present only when PIXOO_OUTPUT_DIR is configured."New value: +"Absolute paths to saved preview files: a PNG for a still, an 8× GIF at the pushed speed for an animation, or past 40 frames the panel-size GIF the device downloads. Present only when PIXOO_OUTPUT_DIR is configured." - changed
Output schema / properties / pushed / descriptionPrevious value: -"True when the device acknowledged the push."New value: +"True when the device acknowledged the push; past 40 frames, once it accepted the GIF play, requested the file, and the whole file was handed to the OS to send (the device does not confirm receipt)." - changed
Output schema / properties / sourceFrames / descriptionPrevious value: -"Frames in the source before sampling down to 40: 1 for a still."New value: +"Frames in the source before sampling down to maxFrames: 1 for a still."
- Added
pixoo_render_html
3 tool updates
v1.3.0- Changed
pixoo_compose_scene12 fields changed- changed
Input schema / properties / background / anyOfPrevious value: -[ - { - "description": "Solid CSS hex color.", - "type": "string" - }, - { - "description": "Gradient background: specify type and two colors.", - "properties": { - "gradient": { - "description": "Gradient background.", - "properties": { - "from": { - "description": "Gradient start color.", - "type": "string" - }, - "to": { - "description": "Gradient end color.", - "type": "string" - }, - "type": { - "description": "v = vertical, h = horizontal, r = radial.", - "enum": [ - "v", - "h", - "r" - ], - "type": "string" - } - }, - "required": [ - "type", - "from", - "to" - ], - "type": "object" - } - }, - "required": [ - "gradient" - ], - "type": "object" - }, - { - "description": "Named theme background: uses the theme's preset gradient.", - "properties": { - "theme": { - "description": "Named theme.", - "enum": [ - "midnight", - "ember", - "claude", - "ice", - "neon", - "forest", - "mono" - ], - "type": "string" - } - }, - "required": [ - "theme" - ], - "type": "object" - } -]New value: +[ + { + "description": "Solid CSS hex color.", + "type": "string" + }, + { + "additionalProperties": false, + "description": "Gradient or named-theme background: set exactly one of gradient or theme.", + "properties": { + "gradient": { + "additionalProperties": false, + "description": "Gradient background: type and two colors.", + "properties": { + "from": { + "description": "Gradient start color.", + "type": "string" + }, + "to": { + "description": "Gradient end color.", + "type": "string" + }, + "type": { + "description": "v = vertical, h = horizontal, r = radial.", + "enum": [ + "v", + "h", + "r" + ], + "type": "string" + } + }, + "required": [ + "type", + "from", + "to" + ], + "type": "object" + }, + "theme": { + "description": "Named theme: uses the theme's preset background.", + "enum": [ + "midnight", + "ember", + "claude", + "ice", + "neon", + "forest", + "mono" + ], + "type": "string" + } + }, + "type": "object" + } +] - changed
Input schema / properties / background / descriptionPrevious value: -"Scene background: solid color, gradient, or named theme."New value: +"Scene background: a solid color string, or an object holding exactly one of gradient or theme." - changed
Input schema / properties / elements / descriptionPrevious value: -"Scene elements rendered back-to-front. Up to 50 elements."New value: +"Scene elements rendered back-to-front. Up to 50 elements. Each element takes either effect or animate, not both. An element's animate keyframes can drive dx, dy, and opacity (numbers or numeric strings, interpolated), visible (true or false, switching at the midpoint between keyframes), and color on any element with a color field (interpolated through RGB)." - changed
Input schema / properties / elements / items / oneOfPrevious value: -[ - { - "description": "Styled text element rendered at a position.", - "properties": { - "animate": { - "additionalProperties": { - "description": "Keyframe entries: [[frame, value], ...].", - "items": { - "items": false, - "maxItems": 2, - "minItems": 2, - "prefixItems": [ - { - "description": "Frame index.", - "type": "number" - }, - { - "description": "Value at this frame.", - "type": [ - "number", - "string", - "boolean" - ] - } - ], - "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": false, - "maxItems": 2, - "minItems": 2, - "prefixItems": [ - { - "description": "Frame index.", - "type": "number" - }, - { - "description": "Value at this frame.", - "type": [ - "number", - "string", - "boolean" - ] - } - ], - "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": false, - "maxItems": 2, - "minItems": 2, - "prefixItems": [ - { - "description": "Frame index.", - "type": "number" - }, - { - "description": "Value at this frame.", - "type": [ - "number", - "string", - "boolean" - ] - } - ], - "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": false, - "maxItems": 2, - "minItems": 2, - "prefixItems": [ - { - "description": "Frame index.", - "type": "number" - }, - { - "description": "Value at this frame.", - "type": [ - "number", - "string", - "boolean" - ] - } - ], - "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": false, - "maxItems": 2, - "minItems": 2, - "prefixItems": [ - { - "description": "Frame index.", - "type": "number" - }, - { - "description": "Value at this frame.", - "type": [ - "number", - "string", - "boolean" - ] - } - ], - "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": false, - "maxItems": 2, - "minItems": 2, - "prefixItems": [ - { - "description": "Frame index.", - "type": "number" - }, - { - "description": "Value at this frame.", - "type": [ - "number", - "string", - "boolean" - ] - } - ], - "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": false, - "maxItems": 2, - "minItems": 2, - "prefixItems": [ - { - "description": "Frame index.", - "type": "number" - }, - { - "description": "Value at this frame.", - "type": [ - "number", - "string", - "boolean" - ] - } - ], - "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": false, - "maxItems": 2, - "minItems": 2, - "prefixItems": [ - { - "description": "Frame index.", - "type": "number" - }, - { - "description": "Value at this frame.", - "type": [ - "number", - "string", - "boolean" - ] - } - ], - "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": false, - "maxItems": 2, - "minItems": 2, - "prefixItems": [ - { - "description": "Frame index.", - "type": "number" - }, - { - "description": "Value at this frame.", - "type": [ - "number", - "string", - "boolean" - ] - } - ], - "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": false, - "maxItems": 2, - "minItems": 2, - "prefixItems": [ - { - "description": "Frame index.", - "type": "number" - }, - { - "description": "Value at this frame.", - "type": [ - "number", - "string", - "boolean" - ] - } - ], - "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": false, - "maxItems": 2, - "minItems": 2, - "prefixItems": [ - { - "description": "Frame index.", - "type": "number" - }, - { - "description": "Value at this frame.", - "type": [ - "number", - "string", - "boolean" - ] - } - ], - "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: +[ + { + "additionalProperties": false, + "description": "Styled text element rendered at a position.", + "properties": { + "animate": { + "additionalProperties": false, + "description": "Raw keyframe animation map for this element. Set either effect or animate, not both.", + "properties": { + "color": { + "description": "Color keyframes (hex or named), interpolated through RGB; each frame's value stands in for the element's color (on pixels, every point's color).", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Color at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dx": { + "description": "X offset keyframes in pixels, added to dx and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dy": { + "description": "Y offset keyframes in pixels, added to dy and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "opacity": { + "description": "Opacity keyframes 0–100, interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "visible": { + "description": "Visibility keyframes: true or false, switching at the midpoint between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Whether the element shows at this frame.", + "type": "boolean" + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + } + }, + "type": "object" + }, + "blend": { + "description": "How the element combines with what lies beneath it (default: normal, drawn over it). add sums the light of both, clamped at full brightness — for glows and light beams; screen brightens more gently; multiply darkens.", + "enum": [ + "normal", + "add", + "screen", + "multiply" + ], + "type": "string" + }, + "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": { + "additionalProperties": false, + "description": "Named animation preset for this element. Set either effect or animate, not both.", + "properties": { + "amplitude": { + "description": "Effect intensity. float, scroll-left, scroll-right, drift: movement in pixels (default 2). pulse, twinkle: 0–1 depth of the opacity dip below 100 (default 0.5 and 0.6). Other effects ignore it.", + "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 (default: standard): standard (5×7) or compact (3×5), each printable ASCII plus ° ← ↑ → ↓ ▲ ▼ ♥ · …; or numerals (11×18 digits for clocks and readouts), which draws only 0–9, space, and : . - + / % ° ?, so text holding any other character is rejected — put units and labels in a separate standard or compact text element.", + "enum": [ + "standard", + "compact", + "numerals" + ], + "type": "string" + }, + "opacity": { + "description": "Opacity 0–100 (default: 100).", + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "style": { + "additionalProperties": false, + "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" + }, + { + "additionalProperties": false, + "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" + }, + { + "additionalProperties": false, + "description": "Built-in or custom SVG icon element.", + "properties": { + "animate": { + "additionalProperties": false, + "description": "Raw keyframe animation map for this element. Set either effect or animate, not both.", + "properties": { + "color": { + "description": "Color keyframes (hex or named), interpolated through RGB; each frame's value stands in for the element's color (on pixels, every point's color).", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Color at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dx": { + "description": "X offset keyframes in pixels, added to dx and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dy": { + "description": "Y offset keyframes in pixels, added to dy and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "opacity": { + "description": "Opacity keyframes 0–100, interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "visible": { + "description": "Visibility keyframes: true or false, switching at the midpoint between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Whether the element shows at this frame.", + "type": "boolean" + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + } + }, + "type": "object" + }, + "blend": { + "description": "How the element combines with what lies beneath it (default: normal, drawn over it). add sums the light of both, clamped at full brightness — for glows and light beams; screen brightens more gently; multiply darkens.", + "enum": [ + "normal", + "add", + "screen", + "multiply" + ], + "type": "string" + }, + "color": { + "description": "Icon color (default: white).", + "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": { + "additionalProperties": false, + "description": "Named animation preset for this element. Set either effect or animate, not both.", + "properties": { + "amplitude": { + "description": "Effect intensity. float, scroll-left, scroll-right, drift: movement in pixels (default 2). pulse, twinkle: 0–1 depth of the opacity dip below 100 (default 0.5 and 0.6). Other effects ignore it.", + "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": 256, + "minimum": 1, + "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 painted as a top-to-bottom color ramp from the icon's top row to its bottom row. Takes precedence over color.", + "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": 256, + "minimum": 1, + "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" + }, + { + "additionalProperties": false, + "description": "Filled, gradient, or bordered rectangle element.", + "properties": { + "animate": { + "additionalProperties": false, + "description": "Raw keyframe animation map for this element. Set either effect or animate, not both.", + "properties": { + "color": { + "description": "Color keyframes (hex or named), interpolated through RGB; each frame's value stands in for the element's color (on pixels, every point's color).", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Color at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dx": { + "description": "X offset keyframes in pixels, added to dx and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dy": { + "description": "Y offset keyframes in pixels, added to dy and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "opacity": { + "description": "Opacity keyframes 0–100, interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "visible": { + "description": "Visibility keyframes: true or false, switching at the midpoint between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Whether the element shows at this frame.", + "type": "boolean" + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + } + }, + "type": "object" + }, + "blend": { + "description": "How the element combines with what lies beneath it (default: normal, drawn over it). add sums the light of both, clamped at full brightness — for glows and light beams; screen brightens more gently; multiply darkens.", + "enum": [ + "normal", + "add", + "screen", + "multiply" + ], + "type": "string" + }, + "borderColor": { + "description": "Border color. The border is drawn inside the rect, strokeWidth pixels thick.", + "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": { + "additionalProperties": false, + "description": "Named animation preset for this element. Set either effect or animate, not both.", + "properties": { + "amplitude": { + "description": "Effect intensity. float, scroll-left, scroll-right, drift: movement in pixels (default 2). pulse, twinkle: 0–1 depth of the opacity dip below 100 (default 0.5 and 0.6). Other effects ignore it.", + "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": { + "additionalProperties": false, + "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" + }, + "strokeWidth": { + "description": "Border thickness in whole pixels, growing inward from the rect edge (default: 1). Requires borderColor.", + "maximum": 9007199254740991, + "minimum": 1, + "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" + }, + { + "additionalProperties": false, + "description": "Filled or outline circle element.", + "properties": { + "animate": { + "additionalProperties": false, + "description": "Raw keyframe animation map for this element. Set either effect or animate, not both.", + "properties": { + "color": { + "description": "Color keyframes (hex or named), interpolated through RGB; each frame's value stands in for the element's color (on pixels, every point's color).", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Color at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dx": { + "description": "X offset keyframes in pixels, added to dx and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dy": { + "description": "Y offset keyframes in pixels, added to dy and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "opacity": { + "description": "Opacity keyframes 0–100, interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "visible": { + "description": "Visibility keyframes: true or false, switching at the midpoint between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Whether the element shows at this frame.", + "type": "boolean" + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + } + }, + "type": "object" + }, + "antialias": { + "description": "Shade each outline pixel by how much of it the ring covers, for a smooth curve (default: false, hard pixel edges). Outline circles only (fill: false).", + "type": "boolean" + }, + "blend": { + "description": "How the element combines with what lies beneath it (default: normal, drawn over it). add sums the light of both, clamped at full brightness — for glows and light beams; screen brightens more gently; multiply darkens.", + "enum": [ + "normal", + "add", + "screen", + "multiply" + ], + "type": "string" + }, + "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": { + "additionalProperties": false, + "description": "Named animation preset for this element. Set either effect or animate, not both.", + "properties": { + "amplitude": { + "description": "Effect intensity. float, scroll-left, scroll-right, drift: movement in pixels (default 2). pulse, twinkle: 0–1 depth of the opacity dip below 100 (default 0.5 and 0.6). Other effects ignore it.", + "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" + }, + "strokeWidth": { + "description": "Outline thickness in whole pixels, centered on the circle (default: 1). Outline circles only (fill: false).", + "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" + }, + { + "additionalProperties": false, + "description": "Straight line element, 1px wide unless strokeWidth is set.", + "properties": { + "animate": { + "additionalProperties": false, + "description": "Raw keyframe animation map for this element. Set either effect or animate, not both.", + "properties": { + "color": { + "description": "Color keyframes (hex or named), interpolated through RGB; each frame's value stands in for the element's color (on pixels, every point's color).", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Color at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dx": { + "description": "X offset keyframes in pixels, added to dx and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dy": { + "description": "Y offset keyframes in pixels, added to dy and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "opacity": { + "description": "Opacity keyframes 0–100, interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "visible": { + "description": "Visibility keyframes: true or false, switching at the midpoint between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Whether the element shows at this frame.", + "type": "boolean" + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + } + }, + "type": "object" + }, + "antialias": { + "description": "Shade each pixel by how much of it the line covers, for smooth diagonals (default: false, hard pixel edges).", + "type": "boolean" + }, + "blend": { + "description": "How the element combines with what lies beneath it (default: normal, drawn over it). add sums the light of both, clamped at full brightness — for glows and light beams; screen brightens more gently; multiply darkens.", + "enum": [ + "normal", + "add", + "screen", + "multiply" + ], + "type": "string" + }, + "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": { + "additionalProperties": false, + "description": "Named animation preset for this element. Set either effect or animate, not both.", + "properties": { + "amplitude": { + "description": "Effect intensity. float, scroll-left, scroll-right, drift: movement in pixels (default 2). pulse, twinkle: 0–1 depth of the opacity dip below 100 (default 0.5 and 0.6). Other effects ignore it.", + "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" + }, + "strokeWidth": { + "description": "Line thickness in whole pixels, centered on the line (default: 1).", + "maximum": 9007199254740991, + "minimum": 1, + "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" + }, + { + "additionalProperties": false, + "description": "Horizontal progress bar widget.", + "properties": { + "animate": { + "additionalProperties": false, + "description": "Raw keyframe animation map for this element (no color track). Set either effect or animate, not both.", + "properties": { + "dx": { + "description": "X offset keyframes in pixels, added to dx and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dy": { + "description": "Y offset keyframes in pixels, added to dy and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "opacity": { + "description": "Opacity keyframes 0–100, interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "visible": { + "description": "Visibility keyframes: true or false, switching at the midpoint between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Whether the element shows at this frame.", + "type": "boolean" + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + } + }, + "type": "object" + }, + "blend": { + "description": "How the element combines with what lies beneath it (default: normal, drawn over it). add sums the light of both, clamped at full brightness — for glows and light beams; screen brightens more gently; multiply darkens.", + "enum": [ + "normal", + "add", + "screen", + "multiply" + ], + "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": { + "additionalProperties": false, + "description": "Named animation preset for this element. Set either effect or animate, not both.", + "properties": { + "amplitude": { + "description": "Effect intensity. float, scroll-left, scroll-right, drift: movement in pixels (default 2). pulse, twinkle: 0–1 depth of the opacity dip below 100 (default 0.5 and 0.6). Other effects ignore it.", + "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" + }, + { + "additionalProperties": false, + "description": "Sparkline chart widget (line or bar).", + "properties": { + "animate": { + "additionalProperties": false, + "description": "Raw keyframe animation map for this element. Set either effect or animate, not both.", + "properties": { + "color": { + "description": "Color keyframes (hex or named), interpolated through RGB; each frame's value stands in for the element's color (on pixels, every point's color).", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Color at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dx": { + "description": "X offset keyframes in pixels, added to dx and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dy": { + "description": "Y offset keyframes in pixels, added to dy and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "opacity": { + "description": "Opacity keyframes 0–100, interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "visible": { + "description": "Visibility keyframes: true or false, switching at the midpoint between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Whether the element shows at this frame.", + "type": "boolean" + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + } + }, + "type": "object" + }, + "blend": { + "description": "How the element combines with what lies beneath it (default: normal, drawn over it). add sums the light of both, clamped at full brightness — for glows and light beams; screen brightens more gently; multiply darkens.", + "enum": [ + "normal", + "add", + "screen", + "multiply" + ], + "type": "string" + }, + "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": { + "additionalProperties": false, + "description": "Named animation preset for this element. Set either effect or animate, not both.", + "properties": { + "amplitude": { + "description": "Effect intensity. float, scroll-left, scroll-right, drift: movement in pixels (default 2). pulse, twinkle: 0–1 depth of the opacity dip below 100 (default 0.5 and 0.6). Other effects ignore it.", + "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" + }, + { + "additionalProperties": false, + "description": "Bitmap element using explicit palette indices.", + "properties": { + "animate": { + "additionalProperties": false, + "description": "Raw keyframe animation map for this element (no color track). Set either effect or animate, not both.", + "properties": { + "dx": { + "description": "X offset keyframes in pixels, added to dx and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dy": { + "description": "Y offset keyframes in pixels, added to dy and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "opacity": { + "description": "Opacity keyframes 0–100, interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "visible": { + "description": "Visibility keyframes: true or false, switching at the midpoint between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Whether the element shows at this frame.", + "type": "boolean" + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + } + }, + "type": "object" + }, + "blend": { + "description": "How the element combines with what lies beneath it (default: normal, drawn over it). add sums the light of both, clamped at full brightness — for glows and light beams; screen brightens more gently; multiply darkens.", + "enum": [ + "normal", + "add", + "screen", + "multiply" + ], + "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": { + "additionalProperties": false, + "description": "Named animation preset for this element. Set either effect or animate, not both.", + "properties": { + "amplitude": { + "description": "Effect intensity. float, scroll-left, scroll-right, drift: movement in pixels (default 2). pulse, twinkle: 0–1 depth of the opacity dip below 100 (default 0.5 and 0.6). Other effects ignore it.", + "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" + }, + { + "additionalProperties": false, + "description": "Sparse scatter of individually colored pixels.", + "properties": { + "animate": { + "additionalProperties": false, + "description": "Raw keyframe animation map for this element. Set either effect or animate, not both.", + "properties": { + "color": { + "description": "Color keyframes (hex or named), interpolated through RGB; each frame's value stands in for the element's color (on pixels, every point's color).", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Color at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dx": { + "description": "X offset keyframes in pixels, added to dx and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dy": { + "description": "Y offset keyframes in pixels, added to dy and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "opacity": { + "description": "Opacity keyframes 0–100, interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "visible": { + "description": "Visibility keyframes: true or false, switching at the midpoint between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Whether the element shows at this frame.", + "type": "boolean" + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + } + }, + "type": "object" + }, + "blend": { + "description": "How the element combines with what lies beneath it (default: normal, drawn over it). add sums the light of both, clamped at full brightness — for glows and light beams; screen brightens more gently; multiply darkens.", + "enum": [ + "normal", + "add", + "screen", + "multiply" + ], + "type": "string" + }, + "data": { + "description": "Array of pixel positions and colors.", + "items": { + "additionalProperties": false, + "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": { + "additionalProperties": false, + "description": "Named animation preset for this element. Set either effect or animate, not both.", + "properties": { + "amplitude": { + "description": "Effect intensity. float, scroll-left, scroll-right, drift: movement in pixels (default 2). pulse, twinkle: 0–1 depth of the opacity dip below 100 (default 0.5 and 0.6). Other effects ignore it.", + "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" + }, + { + "additionalProperties": false, + "description": "External image element (absolute local path or https URL).", + "properties": { + "animate": { + "additionalProperties": false, + "description": "Raw keyframe animation map for this element (no color track). Set either effect or animate, not both.", + "properties": { + "dx": { + "description": "X offset keyframes in pixels, added to dx and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dy": { + "description": "Y offset keyframes in pixels, added to dy and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "opacity": { + "description": "Opacity keyframes 0–100, interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "visible": { + "description": "Visibility keyframes: true or false, switching at the midpoint between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Whether the element shows at this frame.", + "type": "boolean" + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + } + }, + "type": "object" + }, + "blend": { + "description": "How the element combines with what lies beneath it (default: normal, drawn over it). add sums the light of both, clamped at full brightness — for glows and light beams; screen brightens more gently; multiply darkens.", + "enum": [ + "normal", + "add", + "screen", + "multiply" + ], + "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": { + "additionalProperties": false, + "description": "Named animation preset for this element. Set either effect or animate, not both.", + "properties": { + "amplitude": { + "description": "Effect intensity. float, scroll-left, scroll-right, drift: movement in pixels (default 2). pulse, twinkle: 0–1 depth of the opacity dip below 100 (default 0.5 and 0.6). Other effects ignore it.", + "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" + }, + "finish": { + "anyOf": [ + { + "additionalProperties": false, + "description": "Reduce to a palette built from the image.", + "properties": { + "colors": { + "description": "Build a palette of at most this many colors (2–256) from the image itself.", + "maximum": 256, + "minimum": 2, + "type": "integer" + }, + "dither": { + "default": "none", + "description": "How palette colors are placed: none maps each pixel to its nearest color; bayer4 mixes the two nearest in an ordered 4×4 pattern; floyd-steinberg diffuses the difference to neighboring pixels, smoothest on photos.", + "enum": [ + "none", + "bayer4", + "floyd-steinberg" + ], + "type": "string" + } + }, + "required": [ + "colors" + ], + "type": "object" + }, + { + "additionalProperties": false, + "description": "Reduce to a fixed palette.", + "properties": { + "dither": { + "default": "none", + "description": "How palette colors are placed: none maps each pixel to its nearest color; bayer4 mixes the two nearest in an ordered 4×4 pattern; floyd-steinberg diffuses the difference to neighboring pixels, smoothest on photos.", + "enum": [ + "none", + "bayer4", + "floyd-steinberg" + ], + "type": "string" + }, + "palette": { + "description": "Map every pixel to these colors (1–256 entries).", + "items": { + "description": "Hex color (#RRGGBB or #RGB) or a named color.", + "type": "string" + }, + "maxItems": 256, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "palette" + ], + "type": "object" + } + ], + "description": "Reduce the image to a palette before it reaches the panel: exactly one of colors (2–256, built from the image) or palette (1–256 hex or named colors), plus dither. Transparent pixels stay unlit and are not counted. The preview shows the finished frame." + }, + "fit": { + "description": "Resize fit mode (default: contain).", + "enum": [ + "contain", + "cover", + "fill" + ], + "type": "string" + }, + "h": { + "description": "Target height (default: canvas height).", + "maximum": 256, + "minimum": 1, + "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; a relative path is rejected.", + "type": "string" + }, + "type": { + "const": "image", + "description": "Image element (absolute 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": 256, + "minimum": 1, + "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" + }, + { + "additionalProperties": false, + "description": "Sprite sheet element for character or tile art.", + "properties": { + "animate": { + "additionalProperties": false, + "description": "Raw keyframe animation map for this element (no color track). Set either effect or animate, not both.", + "properties": { + "dx": { + "description": "X offset keyframes in pixels, added to dx and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "dy": { + "description": "Y offset keyframes in pixels, added to dy and interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "opacity": { + "description": "Opacity keyframes 0–100, interpolated between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame: a number, or a numeric string such as \"40\" read as that number.", + "type": [ + "number", + "string" + ] + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + }, + "visible": { + "description": "Visibility keyframes: true or false, switching at the midpoint between keyframes.", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Whether the element shows at this frame.", + "type": "boolean" + } + ], + "type": "array" + }, + "minItems": 1, + "type": "array" + } + }, + "type": "object" + }, + "blend": { + "description": "How the element combines with what lies beneath it (default: normal, drawn over it). add sums the light of both, clamped at full brightness — for glows and light beams; screen brightens more gently; multiply darkens.", + "enum": [ + "normal", + "add", + "screen", + "multiply" + ], + "type": "string" + }, + "bodyColor": { + "description": "Override body color.", + "type": "string" + }, + "cols": { + "description": "Number of columns in the sprite grid.", + "maximum": 64, + "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": { + "additionalProperties": false, + "description": "Named animation preset for this element. Set either effect or animate, not both.", + "properties": { + "amplitude": { + "description": "Effect intensity. float, scroll-left, scroll-right, drift: movement in pixels (default 2). pulse, twinkle: 0–1 depth of the opacity dip below 100 (default 0.5 and 0.6). Other effects ignore it.", + "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; a relative path is rejected.", + "type": "string" + }, + "rows": { + "description": "Number of rows in the sprite grid.", + "maximum": 64, + "minimum": 1, + "type": "integer" + }, + "scale": { + "description": "Pixel scale factor: each sprite cell renders as a scale × scale block.", + "maximum": 64, + "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" + } +] - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable over the network. `device_http_error`: The device answered with a non-2xx HTTP status (retryable for 408, 429, 500, and 502–504). `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."New value: +"Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable over the network. `device_http_error`: The device answered with a non-2xx HTTP status (retryable for 408, 429, 500, and 502–504). `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 source or sprite path could not be read, a sprite path was a URL, or an image URL could not be fetched. `invalid_image`: An image source or sprite path was read but did not decode as an image. `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." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "device_unreachable", - "device_http_error", - "device_rejected", - "no_device_configured", - "asset_not_found", - "invalid_color", - "unknown_icon", - "invalid_output_path" -]New value: +[ + "device_unreachable", + "device_http_error", + "device_rejected", + "no_device_configured", + "asset_not_found", + "invalid_image", + "invalid_color", + "unknown_icon", + "invalid_output_path" +] - changed
Output schema / properties / layout / items / properties / action / descriptionPrevious value: -"Overflow action taken by the renderer."New value: +"Always none: scene elements are placed as given and never refit, shrunk, or scrolled. Read fits to learn whether an element runs off the panel." - changed
Output schema / properties / layout / items / properties / action / enumPrevious value: -[ - "none", - "shrunk-to-compact", - "scrolling", - "wrapped", - "truncated", - "clipped" -]New value: +[ + "none" +] - removed
Output schema / properties / layout / items / properties / element / anyOfRemoved value: -[ - { - "description": "Zero-based index of the element in the input array.", - "type": "number" - }, - { - "const": "background", - "type": "string" - } -] - changed
Output schema / properties / layout / items / properties / element / descriptionPrevious value: -"Element index or \"background\" for the background layer."New value: +"Zero-based index of the element in the input array." - added
Output schema / properties / layout / items / properties / element / typeAdded value: +"number" - changed
Output schema / properties / layout / items / properties / font / enumPrevious value: -[ - "standard", - "compact" -]New value: +[ + "standard", + "compact", + "numerals" +]
- Changed
pixoo_display_text12 fields changed- changed
Input schema / properties / background / anyOfPrevious value: -[ - { - "description": "Solid CSS hex color.", - "type": "string" - }, - { - "description": "Gradient background object.", - "properties": { - "gradient": { - "description": "Gradient background specification.", - "properties": { - "from": { - "description": "Gradient start color.", - "type": "string" - }, - "to": { - "description": "Gradient end color.", - "type": "string" - }, - "type": { - "description": "v = vertical, h = horizontal.", - "enum": [ - "v", - "h" - ], - "type": "string" - } - }, - "required": [ - "type", - "from", - "to" - ], - "type": "object" - } - }, - "required": [ - "gradient" - ], - "type": "object" - } -]New value: +[ + { + "description": "Solid CSS hex color.", + "type": "string" + }, + { + "additionalProperties": false, + "description": "Gradient background object.", + "properties": { + "gradient": { + "additionalProperties": false, + "description": "Gradient background specification.", + "properties": { + "from": { + "description": "Gradient start color.", + "type": "string" + }, + "to": { + "description": "Gradient end color.", + "type": "string" + }, + "type": { + "description": "v = vertical, h = horizontal.", + "enum": [ + "v", + "h" + ], + "type": "string" + } + }, + "required": [ + "type", + "from", + "to" + ], + "type": "object" + } + }, + "required": [ + "gradient" + ], + "type": "object" + } +] - changed
Input schema / properties / font / descriptionPrevious value: -"Font variant: standard (5×7) or compact (3×5), used as given — text too wide for it overflows rather than switching font. Omitted, single-line text tries standard and falls back to compact when standard overflows; multi-line text uses standard."New value: +"Font variant, used as given — text too wide for it overflows rather than switching font: standard (5×7) or compact (3×5), each printable ASCII plus ° ← ↑ → ↓ ▲ ▼ ♥ · …; or numerals (11×18 digits for clocks and readouts), which draws only 0–9, space, and : . - + / % ° ?, so text holding any other character is rejected. Omitted, single-line text tries standard and falls back to compact when standard overflows; multi-line text uses standard." - changed
Input schema / properties / font / enumPrevious value: -[ - "standard", - "compact" -]New value: +[ + "standard", + "compact", + "numerals" +] - added
Input schema / properties / position / additionalPropertiesAdded value: +false - added
Input schema / properties / style / additionalPropertiesAdded value: +false - changed
Input schema / properties / style / properties / palette / anyOfPrevious value: -[ - { - "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": "Gradient start color (top).", - "type": "string" - }, - "to": { - "description": "Gradient end color (bottom).", - "type": "string" - } - }, - "required": [ - "from", - "to" - ], - "type": "object" - } -]New value: +[ + { + "description": "Named built-in color palette for the vertical ramp.", + "enum": [ + "ember", + "ice", + "neon", + "fire", + "lavender", + "claude", + "mono" + ], + "type": "string" + }, + { + "additionalProperties": false, + "description": "Custom gradient stop: specify top and bottom colors directly.", + "properties": { + "from": { + "description": "Gradient start color (top).", + "type": "string" + }, + "to": { + "description": "Gradient end color (bottom).", + "type": "string" + } + }, + "required": [ + "from", + "to" + ], + "type": "object" + } +] - changed
Output schema / properties / layout / items / properties / action / descriptionPrevious value: -"Overflow action taken by the renderer."New value: +"What the renderer did about the width: shrunk-to-compact when single-line text fits only in the compact font; scrolling when the returned frames scroll (effect scroll, or auto on text too wide to fit); none otherwise. A line too wide for the panel that does not scroll reports none with fits false, drawn from x 0 and cut at the right edge." - changed
Output schema / properties / layout / items / properties / action / enumPrevious value: -[ - "none", - "shrunk-to-compact", - "scrolling", - "wrapped", - "truncated", - "clipped" -]New value: +[ + "none", + "shrunk-to-compact", + "scrolling" +] - removed
Output schema / properties / layout / items / properties / element / anyOfRemoved value: -[ - { - "description": "Zero-based index of the element in the input array.", - "type": "number" - }, - { - "const": "background", - "type": "string" - } -] - changed
Output schema / properties / layout / items / properties / element / descriptionPrevious value: -"Element index or \"background\" for the background layer."New value: +"Zero-based line index: 0 for single-line text, the line position for an array." - added
Output schema / properties / layout / items / properties / element / typeAdded value: +"number" - changed
Output schema / properties / layout / items / properties / font / enumPrevious value: -[ - "standard", - "compact" -]New value: +[ + "standard", + "compact", + "numerals" +]
- Changed
pixoo_push_image10 fields changed- added
Input schema / properties / finishAdded value: +{ + "anyOf": [ + { + "additionalProperties": false, + "description": "Reduce to a palette built from the image.", + "properties": { + "colors": { + "description": "Build a palette of at most this many colors (2–256) from the image itself.", + "maximum": 256, + "minimum": 2, + "type": "integer" + }, + "dither": { + "default": "none", + "description": "How palette colors are placed: none maps each pixel to its nearest color; bayer4 mixes the two nearest in an ordered 4×4 pattern; floyd-steinberg diffuses the difference to neighboring pixels, smoothest on photos.", + "enum": [ + "none", + "bayer4", + "floyd-steinberg" + ], + "type": "string" + } + }, + "required": [ + "colors" + ], + "type": "object" + }, + { + "additionalProperties": false, + "description": "Reduce to a fixed palette.", + "properties": { + "dither": { + "default": "none", + "description": "How palette colors are placed: none maps each pixel to its nearest color; bayer4 mixes the two nearest in an ordered 4×4 pattern; floyd-steinberg diffuses the difference to neighboring pixels, smoothest on photos.", + "enum": [ + "none", + "bayer4", + "floyd-steinberg" + ], + "type": "string" + }, + "palette": { + "description": "Map every pixel to these colors (1–256 entries).", + "items": { + "description": "Hex color (#RRGGBB or #RGB) or a named color.", + "type": "string" + }, + "maxItems": 256, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "palette" + ], + "type": "object" + } + ], + "description": "Reduce the image to a palette before it reaches the panel: exactly one of colors (2–256, built from the image) or palette (1–256 hex or named colors), plus dither. Transparent pixels stay unlit and are not counted. The preview shows the finished frame." +} - changed
Input schema / properties / source / descriptionPrevious value: -"Absolute local file path or https (not http) URL of the image to display."New value: +"Absolute local file path or https (not http) URL of the image to display; a relative path is rejected. An animated GIF or WebP, whatever its file name, pushes as an animation." - added
Input schema / properties / speedAdded value: +{ + "description": "Milliseconds per frame for an animated source (10–2000). Default: the source's total duration over the pushed frame count, or 150 when it records no delays. A still ignores it.", + "maximum": 2000, + "minimum": 10, + "type": "integer" +} - changed
Output schema / anyOfPrevious value: -[ - { - "not": { - "required": [ - "error" - ] - }, - "required": [ - "pushed" - ] - }, - { - "required": [ - "error" - ] - } -]New value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "pushed", + "frames", + "sourceFrames" + ] + }, + { + "required": [ + "error" + ] + } +] - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable. `device_http_error`: The device answered with a non-2xx HTTP status (retryable for 408, 429, 500, and 502–504). `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."New value: +"Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable. `device_http_error`: The device answered with a non-2xx HTTP status (retryable for 408, 429, 500, and 502–504). `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. `invalid_image`: The source was read but did not decode as an image. `invalid_color`: A finish palette entry could not be resolved to a color. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "device_unreachable", - "device_http_error", - "device_rejected", - "no_device_configured", - "asset_not_found" -]New value: +[ + "device_unreachable", + "device_http_error", + "device_rejected", + "no_device_configured", + "asset_not_found", + "invalid_image", + "invalid_color" +] - added
Output schema / properties / framesAdded value: +{ + "description": "Frames rendered and pushed: 1 for a still, 2–40 for an animation.", + "type": "number" +} - changed
Output schema / properties / outputFiles / descriptionPrevious value: -"Absolute paths to saved PNG preview files. Present only when PIXOO_OUTPUT_DIR is configured."New value: +"Absolute paths to saved preview files: a PNG for a still, a GIF at the pushed speed for an animation. Present only when PIXOO_OUTPUT_DIR is configured." - added
Output schema / properties / sourceFramesAdded value: +{ + "description": "Frames in the source before sampling down to 40: 1 for a still.", + "type": "number" +} - added
Output schema / properties / speedAdded value: +{ + "description": "Milliseconds per frame the animation plays at. Absent for a still.", + "type": "number" +}
6 tool updates
v1.2.0- Changed
pixoo_compose_scene4 fields changed- changed
Input schema / properties / output / descriptionPrevious 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."New value: +"Absolute, already-normalized path to save the first frame to as a PNG. Replaces the PIXOO_OUTPUT_DIR auto-save for this call, so outputFiles holds only this path." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"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."New value: +"Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable over the network. `device_http_error`: The device answered with a non-2xx HTTP status (retryable for 408, 429, 500, and 502–504). `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." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "device_unreachable", - "device_rejected", - "no_device_configured", - "asset_not_found", - "invalid_color", - "unknown_icon", - "invalid_output_path" -]New value: +[ + "device_unreachable", + "device_http_error", + "device_rejected", + "no_device_configured", + "asset_not_found", + "invalid_color", + "unknown_icon", + "invalid_output_path" +] - changed
Output schema / properties / outputFiles / descriptionPrevious value: -"Absolute paths to saved output files (PNG for static, GIF for animations). Present only when PIXOO_OUTPUT_DIR is configured or output is set."New value: +"Absolute paths to saved output files: the output path when set, otherwise the PIXOO_OUTPUT_DIR auto-save (PNG for static, GIF for animations). Absent when neither applies."
- Changed
pixoo_control_device1 field changed- added
Output schema / properties / noticeAdded value: +{ + "description": "Requested settings that failed, each with its failure kind and message (e.g. \"brightness:80 failed (network): …\"), joined by \"; \". Absent when every requested setting applied.", + "type": "string" +}
- Changed
pixoo_design_brief8 fields changed- changed
Output schema / properties / nextToolSuggestions / items / descriptionPrevious value: -"A suggested next-step tool with rationale and optional pre-filled args."New value: +"A recommended follow-up call with its arguments pre-filled." - added
Output schema / properties / nextToolSuggestions / items / properties / argsAdded value: +{ + "additionalProperties": {}, + "description": "Pre-filled arguments for the call; {} when the tool needs none.", + "properties": {}, + "type": "object" +} - removed
Output schema / properties / nextToolSuggestions / items / properties / rationaleRemoved value: -{ - "description": "Why this tool is relevant given current state.", - "type": "string" -} - added
Output schema / properties / nextToolSuggestions / items / properties / reasonAdded value: +{ + "description": "Why this step is recommended given the current device state.", + "type": "string" +} - removed
Output schema / properties / nextToolSuggestions / items / properties / suggestedArgsRemoved value: -{ - "additionalProperties": {}, - "description": "Pre-filled argument suggestions as a key-value object.", - "properties": {}, - "type": "object" -} - removed
Output schema / properties / nextToolSuggestions / items / properties / toolRemoved value: -{ - "description": "Tool name to try next.", - "type": "string" -} - added
Output schema / properties / nextToolSuggestions / items / properties / toolNameAdded value: +{ + "description": "Tool to call next.", + "type": "string" +} - changed
Output schema / properties / nextToolSuggestions / items / requiredPrevious value: -[ - "tool", - "rationale" -]New value: +[ + "toolName", + "reason", + "args" +]
- Changed
pixoo_display_text8 fields changed- changed
Input schema / properties / align / descriptionPrevious value: -"Multi-line text alignment (default: center)."New value: +"Multi-line text: align every line within the widest line, then place that block with position.x. Omit to place each line by position.x on its own." - changed
Input schema / properties / effect / descriptionPrevious value: -"Animation effect. auto = scroll only when text overflows. Produces a multi-frame result."New value: +"Animation effect. scroll runs the text across the display once, in up to 40 frames; auto scrolls only when the text is too wide to fit; float (gentle bob) and pulse (breathing brightness) loop over 20 frames. An animated result is pushed as an animation and previewed as a grid of its frames. none or omitted renders one static frame." - changed
Input schema / properties / font / descriptionPrevious value: -"Font variant: standard (5×7) or compact (3×5). Auto-fit will choose if omitted."New value: +"Font variant: standard (5×7) or compact (3×5), used as given — text too wide for it overflows rather than switching font. Omitted, single-line text tries standard and falls back to compact when standard overflows; multi-line text uses standard." - changed
Output schema / anyOfPrevious value: -[ - { - "not": { - "required": [ - "error" - ] - }, - "required": [ - "pushed", - "layout" - ] - }, - { - "required": [ - "error" - ] - } -]New value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "pushed", + "frames", + "layout" + ] + }, + { + "required": [ + "error" + ] + } +] - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"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."New value: +"Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable over the network. `device_http_error`: The device answered with a non-2xx HTTP status (retryable for 408, 429, 500, and 502–504). `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." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "device_unreachable", - "device_rejected", - "no_device_configured", - "invalid_color" -]New value: +[ + "device_unreachable", + "device_http_error", + "device_rejected", + "no_device_configured", + "invalid_color" +] - added
Output schema / properties / framesAdded value: +{ + "description": "Number of frames rendered: 1 for static text, 2–40 when an effect animates it.", + "type": "number" +} - changed
Output schema / properties / outputFiles / descriptionPrevious value: -"Absolute paths to saved PNG preview files. Present only when PIXOO_OUTPUT_DIR is configured."New value: +"Absolute paths to saved preview files (PNG, or GIF when an effect animates the text). Present only when PIXOO_OUTPUT_DIR is configured."
- Changed
pixoo_overlay_text6 fields changed- changed
Input schema / properties / color / descriptionPrevious value: -"Text color as CSS hex color (default: white)."New value: +"Text color: hex (#RRGGBB or #RGB) or a named color such as orange (default: white)." - changed
Input schema / properties / width / descriptionPrevious value: -"Text region width in pixels (optional; defaults to display width)."New value: +"Text region width in pixels, 0 to display size (64 on a 64px display; defaults to display width)." - changed
Input schema / properties / x / descriptionPrevious value: -"X start position on display (default: 0)."New value: +"X start position, 0 to display size − 1 (63 on a 64px display; default: 0)." - changed
Input schema / properties / y / descriptionPrevious value: -"Y start position on display (default: 0)."New value: +"Y start position, 0 to display size − 1 (63 on a 64px display; default: 0)." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"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."New value: +"Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable. `device_http_error`: The device answered with a non-2xx HTTP status (retryable for 408, 429, 500, and 502–504). `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." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "device_unreachable", - "device_rejected", - "no_device_configured", - "invalid_color" -]New value: +[ + "device_unreachable", + "device_http_error", + "device_rejected", + "no_device_configured", + "invalid_color" +]
- Changed
pixoo_push_image2 fields changed- changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"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."New value: +"Machine-readable failure mode. Declared by this tool: `device_unreachable`: Device is not reachable. `device_http_error`: The device answered with a non-2xx HTTP status (retryable for 408, 429, 500, and 502–504). `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." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "device_unreachable", - "device_rejected", - "no_device_configured", - "asset_not_found" -]New value: +[ + "device_unreachable", + "device_http_error", + "device_rejected", + "no_device_configured", + "asset_not_found" +]
1 tool update
v1.1.3- Changed
pixoo_control_device2 fields changed- changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"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."New value: +"Machine-readable failure mode. Declared by this tool: `no_device_configured`: PIXOO_IP is not set. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "device_unreachable", - "device_rejected", - "no_device_configured" -]New value: +[ + "no_device_configured" +]
1 tool update
v1.1.2- Changed
pixoo_compose_scene1 field changed- changed
Input schema / properties / elements / items / oneOfPrevious 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" - } -]New value: +[ + { + "description": "Styled text element rendered at a position.", + "properties": { + "animate": { + "additionalProperties": { + "description": "Keyframe entries: [[frame, value], ...].", + "items": { + "items": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "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": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "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": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "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": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "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": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "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": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "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": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "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": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "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": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "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": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "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": false, + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "description": "Frame index.", + "type": "number" + }, + { + "description": "Value at this frame.", + "type": [ + "number", + "string", + "boolean" + ] + } + ], + "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" + } +]
7 tool updates
v1.1.1- Changed
pixoo_compose_scene10 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / elements / items / oneOfPrevious 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" + } +] - changed
Input schema / properties / output / descriptionPrevious 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." - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "pushed", + "frames", + "layout" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded 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" +} - removed
Output schema / properties / previewDataRemoved value: -{ - "description": "Base64-encoded PNG preview of the rendered scene (8× upscaled, 512px). For animations: the middle frame.", - "type": "string" -} - removed
Output schema / properties / previewMimeTypeRemoved value: -{ - "description": "MIME type of the preview image.", - "enum": [ - "image/png" - ], - "type": "string" -} - removed
Output schema / requiredRemoved value: -[ - "pushed", - "frames", - "layout" -]
- Changed
pixoo_control_device6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "reachable", + "applied" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded 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" +} - removed
Output schema / requiredRemoved value: -[ - "reachable", - "applied" -]
- Changed
pixoo_design_brief6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "topic", + "craftGuidance", + "deviceContext", + "nextToolSuggestions", + "availableThemes", + "iconCategories" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded 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" +} - removed
Output schema / requiredRemoved value: -[ - "topic", - "craftGuidance", - "deviceContext", - "nextToolSuggestions", - "availableThemes", - "iconCategories" -]
- Changed
pixoo_discover_devices6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "devices" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded 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" +} - removed
Output schema / requiredRemoved value: -[ - "devices" -]
- Changed
pixoo_display_text8 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "pushed", + "layout" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded 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" +} - removed
Output schema / properties / previewDataRemoved value: -{ - "description": "Base64-encoded PNG preview of the rendered frame (8× upscaled, 512px).", - "type": "string" -} - removed
Output schema / properties / previewMimeTypeRemoved value: -{ - "description": "MIME type of the preview image.", - "enum": [ - "image/png" - ], - "type": "string" -} - removed
Output schema / requiredRemoved value: -[ - "pushed", - "layout" -]
- Changed
pixoo_overlay_text6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "acknowledged", + "mode", + "id" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded 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" +} - removed
Output schema / requiredRemoved value: -[ - "acknowledged", - "mode", - "id" -]
- Changed
pixoo_push_image8 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "pushed" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded 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" +} - removed
Output schema / properties / previewDataRemoved value: -{ - "description": "Base64-encoded PNG preview of the downsampled 64×64 result (8× upscaled, 512px).", - "type": "string" -} - removed
Output schema / properties / previewMimeTypeRemoved value: -{ - "description": "MIME type of the preview image.", - "enum": [ - "image/png" - ], - "type": "string" -} - removed
Output schema / requiredRemoved value: -[ - "pushed" -]
7 tool updates
v1.0.0- First observed
pixoo_compose_scene - First observed
pixoo_control_device - First observed
pixoo_design_brief - First observed
pixoo_discover_devices - First observed
pixoo_display_text - First observed
pixoo_overlay_text - First observed
pixoo_push_image
TDQS
Scored across 8 tools
Each tool targets a distinct content type or device operation: scene composition, text rendering, image pushing, HTML rendering, overlay management, device control, discovery, and design guidance. Descriptions explicitly cross-reference (e.g., 'For text-only display use pixoo_display_text'), leaving little room for misselection.
All tools share the pixoo_ prefix and use snake_case with a predictable verb_noun structure (compose_scene, push_image, control_device, etc.), with only design_brief being a minor noun-phrase variant. The pattern is consistent throughout.
Eight tools is well-suited to the domain, covering setup, control, multiple rendering paths, and guidance without bloat. Each tool appears to earn its place, and the set is neither too thin nor too heavy.
The surface covers discovery, device state control, text, overlay, image, HTML, and scene composition, plus a design brief. A minor gap is the lack of an explicit way to push a composed scene to the display (compose_scene only mentions returning an image), though other tools may cover workarounds.
Maintenance
Related MCP Connectors
Manage digital signage screens, playlists and media from your AI assistant.
Generate pixel art sprites, animations, 8-direction rotations and palettes for games.
Run your TRMNL ePaper (e-ink) displays from any AI agent: devices, playlists and new screens.
Display delivery platform for AI agents. Push HTML, dashboards and live data to screens.
Related MCP Servers
- AlicenseBqualityCmaintenanceEnables AI assistants to create and manipulate pixel art by providing tools for drawing, layer management, and animation frame control. It supports exporting projects to PNG, GIF, and sprite sheet formats via the Model Context Protocol.2219Apache 2.0

mcp-divoom-lanofficial
AlicenseBqualityBmaintenanceEnables AI clients to control Divoom LAN devices, including watchface management, brightness adjustment, and screen control through natural language.1865 npm5MIT- AlicenseBqualityDmaintenanceEnables LLMs to create and edit pixel art reliably with support for layers, frames, symmetry, and various drawing tools.70MIT No Attribution
- FlicenseAqualityDmaintenanceEnables 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-