shadertoy-cli 2.5.1

Agent-friendly ShaderToy project, rendering, debugging, and live-preview CLI
shadertoy-cli-2.5.1 is not a library.

shadertoy-cli

Agent-friendly ShaderToy project, rendering, debugging, and live-preview CLI.

The installed binary is named shadertoy.

cargo binstall shadertoy-cli
shadertoy new demo --template multipass
cd demo
shadertoy check
shadertoy check --pedantic
shadertoy graph --dot target/graph.dot
shadertoy render -o target/frame.png
shadertoy render-frames --range 0:180:60 --contact-sheet target/contact.png
shadertoy render-video --frames 180 -o target/clip.mp4
shadertoy sweep --frame 120 --set foam_gain=0.8,1.0,1.2
shadertoy sweep --blind --frame 120 --set foam_gain=0.8,1.0,1.2
shadertoy blind create target/old-renders target/new-renders --output-dir target/old-vs-new
shadertoy blind create 'project:.@preset=high' 'project:.@preset=medium' 'project:.@preset=low' --frames 60,180,300 --set u_storm=1
shadertoy blind judge target/old-vs-new/blind-session.json --pick B --reason "preferred breakup"
shadertoy blind reveal target/old-vs-new/blind-session.json
shadertoy experiment --baseline git:main --candidate git:HEAD --frames 0,60,120 --set u_storm=1 --blind
shadertoy inspect buffer buffer-a --frame 120 --pixel 8,8 --set foam_gain=1.0
shadertoy inspect storage particle-state --frame 120 --type f32 --count 16
shadertoy profile --preset medium --frame 120 --samples 30
shadertoy profile --preset medium --frame 120 --samples 30 --sync-per-pass
shadertoy test --ci
shadertoy trace capture --frame 120 --include-intermediates -o target/bug.sttrace
shadertoy trace inspect target/bug.sttrace
shadertoy trace replay target/bug.sttrace
shadertoy preview --record target/session.strec
shadertoy replay target/session.strec -o target/replay.png

The CLI embeds its project templates, JSON Schema, agent documentation, preview web UI, and Camoufox import helper, so the installed executable does not need adjacent data files. Built-in topics are available through shadertoy docs for agent, project, import, manifest, passes, glsl, assets, buffers, channels, state, sweep, blind, experiment, profile, test, trace, graph, and preview guidance. Use shadertoy docs glsl for the generated prelude/entry-point contract and shadertoy docs assets for cubemap and volume file layouts.

Import a public ShaderToy into a fully local editable project:

shadertoy import https://www.shadertoy.com/view/lsX3W4 -o mandelbrot
cd mandelbrot
shadertoy check

Import uses a Camoufox browser session to handle ShaderToy's browser/Cloudflare path. On first use it creates a private cached Python environment, installs the pinned Camoufox adapter, and fetches its browser. Python 3.10+ is required. On Linux, the Camoufox browser also needs the usual Firefox GTK runtime (for Debian/Ubuntu, libgtk-3-0 or its distro equivalent). Supported textures, cubemaps, volumes, file-backed video inputs, and Sound passes are materialized into the local project; the original ShaderToy response is retained under .shadertoy/import-response.json. Webcam inputs remain live-preview-only.

See the repository README for project format, state/debugging workflows, and the underlying C++/Rust library architecture.

The underlying C++ renderer was originally written by Yingwei Zheng (dtcxzyw/shadertoy), whose groundwork this CLI builds on.

On Linux, GL-backed CLI operations including check, render, render-frames, render-video, render-audio, inspect buffer, inspect storage, state capture, profile, test, replay, and native preview use a surfaceless EGL context and do not need DISPLAY or WAYLAND_DISPLAY. render-frames and render-video reuse one deterministic runtime across their requested timeline. Encoded video and file-backed video channels require ffmpeg/ffprobe.

Additional development tooling

GLSL sources support project-local quoted #include directives. Configure shared include roots with [shader] include_dirs = ["shaders/lib"]; live preview tracks the include dependency graph and recompiles only affected passes, preserving feedback buffers when possible.

Projects can declare typed custom uniforms with [[uniform]]; defaults are applied everywhere, deterministic rendering/state-capture/runtime-inspection commands accept --set name=value, preview exposes matching controls, and [[test]] cases can override them independently. Named [preset.NAME] sections keep quality tiers in the same project root; render_scale adjusts default output size while [preset.NAME.pass.PASS] can override fixed pass dimensions and compute iterations/local size. check, build, preview, render, render-frames, render-video, sweep, and profile accept --preset NAME.

Preview and profile deliberately do not count a preset's smaller final output as an optimization. Preview holds the final Image at the base project output size across preset switches (or at a human-selected review size), and profile --preset NAME benchmarks at base project output size by default while reporting the preset-requested scale separately. Internal pass reductions still apply and remain measurable.

shadertoy sweep --set gain=0.8,1.0,1.2 renders parameter variants and a contact sheet without temporary project copies. profile separates per-pass raw GPU execution timestamps from CPU completion waits and the legacy post-completion attributed interval. It marks timer samples invalid when asynchronous work clearly outruns the timer, retains raw per-sample diagnostics, reports MAD outliers, and exposes an independent non-intrusive frame GPU timestamp interval for cross-run comparisons. --discard-outliers removes flagged samples from aggregates while keeping them in JSON; --sync-per-pass retires each attribution boundary before the next pass for maximum-isolation diagnostics. Blind sweeps anonymize parameter variants, while blind create accepts existing images/render directories, project directories, STTF builds, Git revisions, and project:PATH@preset=NAME sources. blind judge records the preference and rationale before blind reveal exposes the sealed mapping and writes a combined report. experiment turns the same source forms into a reproducible baseline/candidate or N-way run with deterministic frame sets, normalized RMSE, windowed SSIM, contact sheets, provenance, project/git GPU profiles, and optional sealed blind labels.

graph renders the resolved pass/resource graph as text/JSON or Graphviz DOT. check --pedantic additionally treats advisory graph/resource diagnostics as failures, including unreachable passes, unused assets/uniforms, viewport-sized feedback, and unordered shared SSBO users.

Buffer passes can opt into fixed width/height render targets for stable simulation grids, while each iChannel can independently choose filter = "nearest" | "linear" | "mipmap" and wrap = "clamp" | "repeat".

For heavier pipelines, kind = "compute" adds fixed-size OpenGL 4.3 compute dispatch, typed r32f/rg32f/rgba16f/rgba32f outputs, repeated dispatch iterations via iIteration, writable iOutput image load/store, and persistent named SSBOs shared across passes. Buffer/compute passes can also expose up to eight render targets with extra_outputs, and consumers select an attachment with output = N. inspect buffer --output-index N --raw ... reads any MRT attachment, while inspect storage can decode/dump a named SSBO. .ststate format 4 can optionally include SSBO bytes with state capture --include-storage. See shadertoy docs passes and shadertoy docs channels for the exact semantics.

For automated visual/numeric validation, add [[test]] cases to ShaderToy.toml and run shadertoy test. Visual cases compare deterministic PNGs with an RMSE tolerance and emit actual/expected/diff artifacts on failure; buffer cases can also assert no NaN/Inf values and finite-value mean ranges. Tests can also expand across frames = [...] and resolutions = [[w,h], ...], repeat each variant with assert_deterministic = true, and prove fixed GPU simulation grids are independent of output size with assert_resolution_independent = true. Tests can also compare uniforms against reference_uniforms with minimum/maximum RMSE bounds, enforce total/per-pass GPU budgets, compare exact SSBO binary fixtures, and set assert_state_roundtrip = true to verify persistent pass/SSBO state survives serialization into a fresh runtime. Use shadertoy test --ci for a non-mutating automation path.

ShaderToy Sound passes (kind = "sound") are compiled by check and render to deterministic stereo PCM WAV with shadertoy render-audio. File-backed video assets update at deterministic iTime and expose iChannelTime; webcam channels are available only in live preview and are intentionally rejected by headless render/replay/recording.

Trace bundles

shadertoy trace capture -o target/bug.sttrace freezes a deterministic render into a self-contained directory containing the STTF, final PNG, persistent .ststate, resolved configuration, source/asset hashes, graph/synchronization metadata, GPU pass timings, and optional per-pass PNG/RGBA32F readbacks. trace inspect verifies artifact SHA-256 values, while trace replay renders only from the bundled STTF and requires a bit-exact RGB match.