an.adapters.cutout#
The cut-out backend’s old package: the stage moved to an.stage (an#247).
The render path is an.stage.compile -> an.stage.serialize ->
an.stage.render (the stage engine, driven by the core frame stage) ->
runtime.js. Every module that moved keeps a LIVE alias here
(an.adapters.cutout.render is an.stage.render for reading and for
rebinding, an._shims.alias_module()). coarticulate and gaze moved to cutan (an#225; live aliases with a
warning). What stays here is the
timing re-exports (channel, clip, timeline).
The names this package used to export are resolved LAZILY, on first access:
importing an.adapters.cutout.coarticulate from the stage’s compiler must not
load the stage back through this __init__.
>>> from an.adapters.cutout import CutoutRenderer, compile_shot
>>> CutoutRenderer().name
'cutout'
Functions
|
Compile a single cutout-style |
Classes
|
The stage renderer: the stage engine through the core frame stage. |
|
Top-level cutout scene JSON — the JS runtime's input contract. |
|
One node in the scene tree. |
|
Drawable content attached to a node. |
|
A named, reusable animation clip. |
|
One animated property of one target. |
|
Single keyframe in an animation channel. |
|
Top-level timeline: total duration + tracks. |
|
A sequence of placed clips with optional target-prefix metadata. |
|
An animation placed on a track at a specific time. |
|
Map of asset id → AssetJSON, split by kind. |
|
A single asset (texture / audio file). |
|
How one scene entity's store reference actually resolved at compile time. |
Exceptions
Raised when a cutout render fails. |
- class an.adapters.cutout.AnimationClipJSON(**data)[source]#
Bases:
_JSONModelA named, reusable animation clip.
- class an.adapters.cutout.AssetJSON(**data)[source]#
Bases:
_JSONModelA single asset (texture / audio file).
- class an.adapters.cutout.AssetResolutionJSON(**data)[source]#
Bases:
_JSONModelHow one scene entity’s store reference actually resolved at compile time.
The IR declares every drawable entity as
store+ref. What the compiler builds from that pair is not recoverable from the scene tree afterwards: a character whose descriptor is missing and a character that never had one produce byte-identical procedural rigs. That ambiguity is an#33 — three CI runners once agreed perfectly about a picture that was not the picture, and the agreement read as a clean positive result.So the compiler records what it did, per entity, in the artifact the browser actually loads.
fallbackis the load-bearing bit: True means the declared ref supplied nothing and a stand-in was drawn in its place.>>> AssetResolutionJSON( ... id="maya", kind="character", store="characters", ref="maya-v1", ... resolved="descriptor", fallback=False, ... ).fallback False
- class an.adapters.cutout.AssetsJSON(**data)[source]#
Bases:
_JSONModelMap of asset id → AssetJSON, split by kind.
- class an.adapters.cutout.ChannelJSON(**data)[source]#
Bases:
_JSONModelOne animated property of one target.
- exception an.adapters.cutout.CutoutRenderError[source]#
Bases:
RuntimeErrorRaised when a cutout render fails. Carries actionable detail.
- class an.adapters.cutout.CutoutRenderer(engine=<factory>, name='cutout', supported_renderers=('cutout', 'stage'), error=<class 'an.stage.render.CutoutRenderError'>, capture_options=<factory>, paint_orders=('container', 'global'))[source]#
Bases:
FrameStageRendererThe stage renderer: the stage engine through the core frame stage.
It claims both renderer names (ADR 0001 decision 9):
stage, the engine’s own, andcutout, the persisted name every existing scene carries. Its registry name stayscutout– persisted too (the shot cache keys on it) – andStageRendereris the same class.>>> r = CutoutRenderer() >>> r.name 'cutout' >>> r.supported_renderers ('cutout', 'stage')
- error#
alias of
CutoutRenderError
- class an.adapters.cutout.CutoutSceneJSON(**data)[source]#
Bases:
_JSONModelTop-level cutout scene JSON — the JS runtime’s input contract.
Versioned so the runtime can refuse incompatible inputs.
- asset_resolution: list[AssetResolutionJSON]#
One entry per drawable entity, in scene order — see
AssetResolutionJSON. Inert to the runtime; read by the bench harness and the golden-corpus bless to assert WHICH render path ran.
- model_config: ClassVar[ConfigDict] = {'extra': 'allow', 'populate_by_name': True}#
Configuration for the model, should be a dictionary conforming to [
ConfigDict][pydantic.config.ConfigDict].
- overlay: NodeJSON | None#
a second top-level container the runtime centres on the canvas and never indexes, so no channel — the camera’s
root.pivot/root.scaleincluded — can reach it. Its children are indexed by their own paths exactly likescene’s, so an overlay title’s words tween like anything else.Nonewhen the shot has no overlay, and then omitted from the serialized document.- Type:
The camera-immune layer (an#155)
- class an.adapters.cutout.KeyframeJSON(**data)[source]#
Bases:
_JSONModelSingle keyframe in an animation channel.
- class an.adapters.cutout.NodeJSON(**data)[source]#
Bases:
_JSONModelOne node in the scene tree.
- model_config: ClassVar[ConfigDict] = {'extra': 'allow', 'populate_by_name': True}#
Configuration for the model, should be a dictionary conforming to [
ConfigDict][pydantic.config.ConfigDict].
- paint_order: list[str] | None#
The order its descendants’ visuals are PAINTED in, when it is not the tree’s (an#430): node paths relative to this node, back to front. Set on a rig’s entity node whose nested chain interleaves with an unrelated part (an upper arm 1, a cord 2, a forearm 3); the runtime keeps each visual in its transform tree and paints it from this list.
- scope: str | None#
as the children of the node named
scopein the same parent ("": as the parent’s own children).None= under this node’s own path, the rule before an#343. An environment’s foreground container carriesscope=<env>, so every plane is<env>/<plane>wherever the environment is cut.an.stage.treeis the Python statement of the rule.- Type:
Where this node’s CHILDREN are indexed (an#343)
- class an.adapters.cutout.PlacedClipJSON(**data)[source]#
Bases:
_JSONModelAn animation placed on a track at a specific time.
- class an.adapters.cutout.TimelineJSON(**data)[source]#
Bases:
_JSONModelTop-level timeline: total duration + tracks.
- class an.adapters.cutout.TrackJSON(**data)[source]#
Bases:
_JSONModelA sequence of placed clips with optional target-prefix metadata.
- class an.adapters.cutout.VisualJSON(**data)[source]#
Bases:
_JSONModelDrawable content attached to a node.
kind="svg_sprite"is the Phase 11b path: the runtime instantiates aPIXI.Spritefrom a pre-loaded SVG texture identified byasset_id.asset_setscarries this node’s swap vocabulary —{set_name: {KEY: asset_id}}, the compiler’s per-slot projection of the descriptor’sasset_setsonto the slot this visual draws (an#87). A channel whose property names one of these sets swaps the sprite’s texture by key;visemeis just the conventional set name lip-sync uses. Same field name asCharacterDescriptor.asset_setson purpose: one vocabulary, two layers (descriptor = declared, wire = resolved to texture aliases). Replaces the mouth-onlyviseme_assets.width/heightare the box the art is fitted into, not the size it is forced to. Underfit="contain"the art keeps its own aspect ratio and may leave slack on one axis; that slack is the correct rendering, not a bug.- asset_geometry: dict[str, dict[str, float]] | None#
Per-texture geometry for a swap key drawn differently from the built one (an#211):
{asset_id: {"width", "height", "anchor_x", "anchor_y", "x", "y"}}— the box the key is fitted into, its anchor, and its offset from the node (scene pixels). A swap used to carry the texture only, so every key drew in the DEFAULT attachment’s box: a closed mouth on a thin canvas squashed every open mouth to a fraction of a pixel. Only keys whose geometry differs are listed;None= every key shares it.
- blend: Literal['add', 'multiply'] | None#
"add"for a glow,"multiply"for the paper grain. PixiJS 7 does both in the blend equation — no filter, no render texture.None= normal.- Type:
The engine’s native blend mode for this visual (an#163)
- fit: Literal['stretch', 'contain']#
How the art is fitted to
width/height."contain"scales uniformly so the art keeps the shape it was drawn with — the invariant of an#74."stretch"sizes each axis independently, which is what every sprite did before that issue and what distortedarm_lby 3.929x on the repo’s own art.Additive with a
"stretch"default so no stored scene changes meaning; the compiler emits"contain"for every sprite it builds.
- kind: str#
One of
BUILTIN_VISUAL_KINDS, or a kind a genre’s runtime script registers (window.anRegisterVisual, an#247). A string on the wire, as it always was; the open set is what letscutanship the mouth and eye.
- model_config: ClassVar[ConfigDict] = {'extra': 'allow', 'populate_by_name': True}#
Configuration for the model, should be a dictionary conforming to [
ConfigDict][pydantic.config.ConfigDict].
- underlays: list[UnderlayJSON] | None#
Copies drawn behind this visual, back to front (an#163) — the outline and the paper-gap shadow. Only
rect,ellipseandsvg_spritetake them; the runtime refuses any other kind.
- an.adapters.cutout.compile_shot(shot, mall=None, *, fps=30, width=1920, height=1080, background='#ffffff', strict_assets=False, step_hz=None, expression_provider=None, style_pack=None, default_easing=None)[source]#
Compile a single cutout-style
Shotto its JS-runtime JSON form.default_easing(an#166) is the scene’smeta.default_easing: the curve of every authored tween that names none (tween > this > the built-in"ease_in_out",resolved_easing()).Noneleaves the document byte-identical to before the knob existed.expression_provider(an#98) is the seam that turns authoredexpressionleaves and dialogue[emotion]sugar into per-axis curves for the face solver;Noneis the genre’s default provider.step_hz(an#89) resamples every authored tween onto a SHOT-wide pose grid of that many updates per second (multiples of1/step_hzon this shot’s clock, shared by every tween in the shot; the grid restarts at a cut), each keyframe step-eased, so the character holds each pose for the frames between grid points — “on twos” at half the frame rate, “on threes” at a third. It is sample-and-hold of the eased curve at the grid instants, not a retiming into holds and fast transitions.None(default) leaves tweens smooth and the compiled document byte-identical to before the knob existed; anything else must satisfy0 < step_hz <= fps— checked HERE as well as byan validate, because a render never runs validate and a non-positive rate used to spinstep_timesforever (an#89 review). Exempt by construction, because they are separate emission sites rather than string-sniffed: the camera (_add_camera_clips— a stepped character under a translating camera slides in screen space, which is why the practice keeps cameras on ones), compiled blinks,playclips, and swap channels (already stepped by format). The value is stamped intometa.step_hz— only when set — so a serialized scene declares its timing policy without moving the contract hash of one that has none.strict_assetsturns a stand-in asset — the placeholder rig drawn for a character whose descriptor is missing, or the default backdrop drawn for an unknown environment ref — from a warning into aCutoutCompileError. Off by default so an asset-less project still renders; on for anything that measures pixels, where a stand-in is a wrong answer wearing a right one’s clothes (an#33).- Return type:
Modules
Moved to |
|
Moved to |
|
Channel evaluation — moved to |
|
Clips, loop modes and poses — moved to |
|
Moved to |
|
Moved to |
|
Moved to |
|
Moved to |
|
Moved to |
|
Moved to |
|
Moved to |
|
Moved to |
|
Moved to |
|
Moved to |
|
Moved to |
|
Moved to |