cutan¶
Cut-out animation for an: rigged characters, faces and expressions, lip-sync, swap sets and views, impacts, and cut-out styles, as a genre package on the an core.
pip install "an[cutout]" # an + the stage + cutan
an character new maya --offline
an finds cutan through the an.genres entry point and loads it with an.genres.load() (the CLI and an.load(project) do). The scene format, rendering and the asset library are an’s; see its README.
What is here¶
cutan registers with the core:
the
characterentity kind and theplayandexpressionactions, the[emotion]dialogue sugar and the semantic checks that go with them (cutan.genre,cutan.characters,cutan.expression);the rig, face, viseme, blink, gaze and swap-pose compile passes over the
an.stagecompiler (cutan.compile), and the mouth and eye visuals of the stage runtime (cutan/runtime/visuals.js);the lip-sync providers
offline,rhubarbandwhisper(cutan.audio);locomotion, speech, blink and turn methods with their requirements and defaults, and the cut-out vocabulary;
the
an character …andan impacts …command namespaces;carving parts out of photos and frames (
cutan.carve, below);the style lint (
python -m cutan.verify.style VIDEO <style>) and the named style specs it measures against, shipped as package data:cutan.style_spec("south_park"),python -m cutan.stylesto list them (thecutan-styleskill applies one).
Carving parts from a photo or a frame¶
cutan.carve turns a photo or a video frame into a matted, cleaned, provenance-carrying cut-out part, and writes it as a library-ready prop folder. It needs OpenCV: pip install "cutan[carve]" (it installs opencv-python-headless; an environment that already has opencv-python or opencv-contrib-python works as it is, since all three provide the same cv2). Add cutan[rembg] for the neural matte and cutan[faces] for the face locator; cutan.carve.check_requirements() lists what is installed.
from cutan.carve import carve, carve_head, frame_source, write_prop, grab_frame, Polygon, FlatColour
src = frame_source("https://www.youtube.com/watch?v=VIDEO_ID", t=34.5, license="all-rights-reserved")
frame = grab_frame("clip.mp4", 34.5)
lamp = carve(frame, point=(1060, 130), source=src) # flat_colour: the cartoon-frame default
print(lamp.quality.warnings()) # backdrop left on the rim, glyphs attached, ...
write_prop(lamp, "assets/props/lamp") # prop.json + parts/body.png, source included
head = carve_head(frame, face=(830, 170, 930, 305), matte="rembg") # neck cut, 512² canvas, face centre as origin
The matte is a strategy: flat_colour (the default), chroma, grabcut, polygon, focus, rembg, or any (rgb, hint) -> alpha callable. Two combine with & and |: Polygon(outline) & FlatColour() is a hand outline cleaned by a colour key. split_parts lifts moving parts off a carving, each with a pivot (clock hands off the face), and write_prop gives each part its own bone. Publishing the folder (an library publish <folder> prop.<name> --package cutan --origin carved) records the rights from the descriptor’s own source; write_prop refuses a carving with no provenance (unless the pixels are yours: ours=True) and a source= that would loosen its licence without relicense=. Every coordinate is in the source’s pixels, and a carving’s recipe is its arguments by name, so carve(frame, **part.recipe) replays it: a batch of carves is a list of recipes.
The cut-out bench corpus (misc/bench/), examples/ and the demo gallery (misc/demos/) live here too; cutan.bench.run_bench() runs the corpus through an’s bench runner.
Production packs from writers¶
skills/cutan-production-pack/ is an agent skill for people who write and direct but do not run cutan: uploaded to Claude.ai (zip the folder, or package it with the skill-creator skill), it has their Claude write a production pack: scene.md, a cast.sh of an character new commands, environments, props and their SVG drawings, and a PRODUCTION.md brief, in the formats this package reads. Its example pack (examples/the-umbrella/) is validated by tests/test_production_pack_skill.py, which also regenerates the skill’s vocabulary, preset, rig-path and style tables from the code.
Receiving a pack:
python skills/cutan-production-pack/scripts/validate_pack.py <pack> # cutan's own checks on a scratch project
an init <id> --id --genre cutout_animation # then copy the pack in, run cast.sh's lines
an validate <project> --strict-assets && an render <project> # from the project root, and render
validate_pack.py runs only an character ... lines from cast.sh (no shell). Set the licence of the pack’s own drawings (their source) before publishing a render.
Names that never change¶
Moving the code renamed nothing that is stored. Scenes keep renderer: cutout, the genre keeps its slug cutout_animation, character descriptors keep their document kind and version, and asset ids keep their character. prefix. These names are in cutan/__init__.py. The old an.characters, an.expression, an.impacts, an.audio.offline_lipsync-style import paths still work in an, with a MovedModuleWarning.
Where data lives¶
The genre’s asset library and agent-made projects live under ~/.local/share/cutan by default. Set CUTAN_HOME to move them. The core’s own library (voices, sounds, fonts) stays under an’s root, and a project reads both as one search path.
Working on cutan¶
Read CLAUDE.md. In short: pip install -e . --no-deps next to an editable an, then pytest. The tests that render need a headless browser (playwright install chromium) and ffmpeg.
This documentation as a single file: cutan.md (Markdown, for agents).
built 2026-10-19 07:51 UTC from 0a76f38 (main) · cutan 0.0.54 · about this build