muriel
A next-gen visual-production skill for LLMs.
Built for the agentic era, grounded in the full design-history lineage.
What it is
A dozen channels of tool-use recipes — ten output channels (raster, SVG, web, interactive, video, terminal, density viz, gaze, science, infographics) plus two cross-channel references (dimensions, style-guides) — each with rules, patterns, and anti-patterns. A two-tier brand-token schema with motion. A multi-constraint solver that enforces 8:1 contrast and the OLED palette at render time. A vision-model critique agent grounded in Tufte / Bertin / Gestalt / Reichle / scanpath research.
Next-gen means the tools — LLM-native skill format, vision-model critique, brand tokens alive at render time, motion as a first-class schema field, engine adapters for Pillow / Flux / pretext / ffmpeg / Playwright. Grounded means the principles — Cooper's Visible Language Workshop, Tufte's data-ink discipline, Bertin's retinal variables, Gestalt grouping, CRAP, Reichle's E-Z Reader, scanpath patterns. New tools serve the old principles.
Featured work
One shipped example per channel, organized by the surface it produces. Each card links to source or live post; the repo gallery has the full set, and per-channel deep dives live under channels/.
Spatial channel — depth scaffolding
Perspective grids — 1pt / 2pt / 3pt / iso.
Tools: muriel.spatial.grid() emitting deterministic SVG · pure Python, zero deps · Liang-Barsky line clipping · fade-to-horizon depth weighting on transversals · OLED palette throughout. The static side of the spatial channel — pairs with five Three.js + CSS3DRenderer exemplars — Cooper VLW · Data Mountain · Perspective Wall — now live and interactive in the demo gallery, sharing the same coordinate space by design. Channel doc names the full lineage: Alberti 1435 → Dürer 1525 → Cooper VLW 1980s → Mackinlay-Robertson-Card 1991 → Dumais Data Mountain 2001 → Tron.
▸ Live demo gallery → Channel doc →
Typography — type as structure
Drop cap H × log-polar cortical grid.
Tools: muriel.typeset drop-cap generator emitting deterministic SVG · log-polar grid backdrop (Schwartz 1977 cortical-magnification mapping — concentric rings + radial spokes traced outward from a foveal singularity) · serif glyph rendered as a filled vector path so it scales to any column width · OLED palette with the anatomical-pink (#c07fa0) accent muriel uses for cortical / retinal annotations. Pairs with the spatial channel — type rendered on the substrate it'll be read with, not floating in an abstract layout box.
Drop-caps gallery →
Raster / SVG channels — generative backgrounds
Patterns — dots, flow, grain.
Tools: muriel.patterns · pure Python, zero deps · Bridson (2007) fast Poisson-disk sampling for dots · value-noise vector field traced as polyline streamlines (LIC-style after Cabral & Leedom 1993) for flow · value-noise raster sampled into a small SVG <pattern> tile for grain (file size stays O(tile_cells²) regardless of canvas). All randomness routes through hashlib.blake2b — same seed produces byte-identical SVG across platforms. The workhorse-background layer the screenshot-designer P0 plugs into.
Source →
Diagrams channel — rhetorical primitives
N-step cycle — Evolver's improvement loop.
Tools: muriel.tools.diagrams.cycle() emitting deterministic SVG · five nodes evenly spaced on a circle, curved cyan arrows with auto-derived endpoint tangents · auto-placed labels (margin-aware, never overlapping the nodes — uses the same bbox-aware placement as muriel.layout.place_label) · OLED palette · 8:1 on every text node. One of the shipped rhetorical primitives (alongside 2×2 matrix and Venn). Each preset carries an epistemic precondition + anti-prescription — don't use a cycle when your process has an exit.
Channel doc →
v0.8.0 headline — brand-token round-trip
design.md ↔ brand.toml ↔ W3C DTCG.
Tools: muriel import (Google Stitch design.md → brand.toml) · muriel export-dtcg (brand.toml → W3C Design Tokens Community Group JSON) · pure Python, no DTCG-validator dependency. All 61 import-parseable brands in VoltAgent/awesome-design-md round-trip cleanly through both halves with zero failures. The exported JSON drops straight into style-dictionary, theo, Figma tokens-studio, or token-css — and from there into iOS / Android / Tailwind / CSS-vars pipelines. With v0.8.0 muriel is the rigorous offline cousin of DESIGN.md: imports the corpus, exports out to the W3C standard, holds the 8:1 floor honestly through all of it.
Release notes →
Infographics channel — three-panel single-page
Foveation explainer — Scrutinizer brand asset.
Tools: hand-rolled build_foveation.py emitting deterministic SVG (no D3, no template engine) · OLED palette (cream-on-near-black) for portfolio coherence · 8:1 contrast on every text node verified at build time · rsvg-convert for PNG raster. Single-page LinkedIn-shareable infographic stacking anatomical / statistical / "what users see" panels — the channel that turns a research thesis into one shareable artifact. Lives on the Scrutinizer brand page.
Live page →
SVG / Science channels — deterministic illustration
V1 orientation columns — pinwheel topology.
Tools: hand-rolled v1-orientation-columns-demo.py emitting deterministic SVG (no D3, no template engine) · multi-pinwheel orientation field (vector averaging on doubled angles to preserve V1's 180° periodicity) over a hex grid · muriel OLED palette · 8:1 contrast on every text node. Replaces an AI-generated illustration of the same concept — muriel's whole point: generated, not guessed. Topology after Bonhoeffer & Grinvald, Nature 1991.
Source →
Gaze channel — small multiples
Cursor + gaze trajectories by outcome class.
Tools: matplotlib subplot grid (3×3) · muriel.gaze primitives (numbered fixations sized by duration, start-square / end-diamond cursor markers, AOI rectangles) · muriel.matplotlibrc_light palette · class-coded color (green clicked / orange deferred / red eval-rejected). The small-multiples principle made literal: identical axes and encoding, only the outcome class varies row-by-row. Reading the rows reveals the behavioral signature (tight tracking → late return → never return).
Live post →
Density viz channel
Pooled gaze density around the parked cursor — three coupling regimes.
Tools: numpy 2D histogram for the density estimation · matplotlib imshow with the inferno-family fire colormap · per-panel peak normalization · muriel.heatmaps conventions (Tobii-style Gaussian-pooled overlay, scale-bar annotation, normalized luminance against ground-truth landmarks). Pools every fixation in each outcome class, recentered on its episode's cursor median: tight coupling (eval-rejected, ~220 px) → cursor parked at offset while gaze revisits (deferred, ~300 px) → cursor held far from gaze throughout approach (clicked, ~390 px). The figure that makes a population statistic visible as a shape.
Live post →
Interactive channel — interactive → captured
Cortical grid comparison — orientation energy revealed by foveation.
Tools: a WebGL grid-comparison demo (external — Scrutinizer's reference-pages/grid-comparison.html, four orientation tiles + foveated spotlight, isotropic-cortical sampling) for the rendering · muriel.capture.capture_responsive() for the retina screenshot · the OLED palette (cream-on-near-black) preserved through capture. Pairs the live interactive substrate with muriel's static-capture pipeline — a demonstration that "the figure" and "the demo" can share a source.
Live post →
Motion tuner
muriel's brand.toml ships a [motion] block with duration tokens (instant / fast / normal / slow / reveal, in ms) and easing tokens (default / emphasis / snappy / linear). Move the sliders; the animated bars below re-play at every change. Copy the resulting TOML snippet back into any project's brand.toml to apply.
Install
As a Claude Code plugin (recommended — no clone, no symlinks):
/plugin marketplace add andyed/muriel
/plugin install muriel@andyed-muriel
Invoke with /muriel:compose. The muriel-critique subagent loads alongside the skill automatically.
As a Python package (current release: v0.8.0 wheel attached to the GitHub Release — not on PyPI yet):
pip install https://github.com/andyed/muriel/releases/download/v0.8.0/muriel-0.8.0-py3-none-any.whl
As a developer install from a clone (edits go live):
git clone https://github.com/andyed/muriel ~/Documents/dev/muriel
cd ~/Documents/dev/muriel && ./install.sh
See the Install section in the README for full options and cross-harness (Cursor, Codex, Windsurf, Gemini CLI) instructions.
The critique agent
muriel ships a vision-model critique agent with read-only tools, hardened against prompt-injection, authority-laundering, and contrast-claim spoofing embedded in the artifact itself. It names what's wrong — with evidence — and cites the specific framework (Tufte / Bertin / Gestalt / CRAP / Reichle / scanpath) when surfacing issues. Fix is a human call; the agent doesn't try.
muriel-critique subagent on a rendered artifact. It returns a structured verdict — PASS / NEEDS REVISION / FAIL — with a numbered issue list (rule · evidence · fix · severity). Any CRITICAL → FAIL; any HIGH → NEEDS REVISION; otherwise PASS.