cutan.characters.registration

The character side of the cut-out genre, as declarations: play and character.

What the cut-out genre (cutan.genre) registers from here (ADR 0001 §First slice):

  • the ``play`` action kind — PlayAction, how long a duration-less play occupies a sequence (its natural length, through the caller’s extent resolver), and its scene.md spelling;

  • the ``character`` entity kind — a rigged character, whose nodes are nodes of the 2D stage engine (the stage.node property space).

Plain declarations: importing this module registers nothing.

>>> PLAY.name, CHARACTER.space
('play', 'stage.node')

Functions

character_specimen(ref)

The shot that shows one character on its own (an#347's EntityKind.specimen, cutan#40): the character at rest, facing the camera (its rest view, untouched), alone, so the rig builder places its root at the stage centre.

default_play_extent(action)

A duration-less play's extent when no descriptor is known: a motion preset's natural length over speed, else 0.0.

play(target, animation, *[, duration, ...])

Play a named animation of the target entity's descriptor (an#7).

play_duration(action, extent)

The span a play occupies: its duration, else its natural extent.

read_play_md(item, *, index)

{kind: play, target, animation, [duration], [speed], [loop], [args]}.

write_play_md(leaf)

The scene.md entry for leaf (read_play_md's inverse).

Classes

PlayAction(*[, name, kind, duration, speed, ...])

Play a named animation of the target entity's descriptor (an#7).

class cutan.characters.registration.PlayAction(*, name=None, kind='play', target, animation, duration=None, speed=1.0, loop=None, args=None, **extra_data)[source]

Bases: ExtensionAction

Play a named animation of the target entity’s descriptor (an#7).

animation names an entry of CharacterDescriptor.animations (the seeded idle_breath and blink, or anything an author adds); the compiler resolves its tracks into channels on the entity’s nodes. A name the descriptor does NOT declare — or any name on an entity with no descriptor (a procedural rig, a prop) — falls back to the motion presets of cutan.motion.PRESETS (hop, nod, …), which expand to ordinary tweens at the target’s built rest pose; a descriptor animation of the same name wins (an#166). Both halves are decided by cutan.characters.play.play_problems(), the one resolver an validate and the compiler share. For a preset, args are its parameters, duration stretches the whole move to that length, speed divides it, and loop: true is refused (a preset is a one-shot). duration widens/narrows the placement window; None means the animation’s own duration — or, when the resolved loop is true, the rest of the shot, because a loop bounded by its own natural duration never loops. loop overrides the animation’s declared loop (None = use the descriptor’s). Inside a sequence a play with duration=None occupies its NATURAL length — a motion preset’s own length, a non-looping descriptor animation’s duration, both over speed — so the next sibling starts when it ends; a looping one runs to the shot end and occupies ZERO (an.characters.play.play_extent()).

args: dict[str, Any] | None

Parameters of a MOTION PRESET (an#166) — {"height": 30} for a hop — passed to its cutan.motion.PRESETS function as keyword arguments. None (the default, omitted from JSON) means the preset’s own defaults. A descriptor animation takes none, and one given to it is refused; rest is never one — it is read off the built scene.

model_config: ClassVar[ConfigDict] = {'extra': 'allow', 'populate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

cutan.characters.registration.character_specimen(ref)[source]

The shot that shows one character on its own (an#347’s EntityKind.specimen, cutan#40): the character at rest, facing the camera (its rest view, untouched), alone, so the rig builder places its root at the stage centre. an library sheet draws its first frame on a canvas sized from the descriptor’s view_box and trims it to what it shows.

>>> from an.ir.schema import AssetRef
>>> shot = character_specimen(AssetRef(kind="character", id="ned", store="characters", ref="ned"))
>>> shot.renderer, [e.id for e in shot.entities], shot.actions
('cutout', ['ned'], [])
Return type:

Any

cutan.characters.registration.default_play_extent(action)[source]

A duration-less play’s extent when no descriptor is known: a motion preset’s natural length over speed, else 0.0.

The one resolver is cutan.characters.play.play_extent(); this is it with desc=None.

>>> default_play_extent(PlayAction(target="a", animation="hop"))
0.5
>>> default_play_extent(PlayAction(target="a", animation="not_a_preset"))
0.0
Return type:

float

cutan.characters.registration.play(target, animation, *, duration=None, speed=1.0, loop=None, args=None)[source]

Play a named animation of the target entity’s descriptor (an#7).

duration=None fills the animation’s natural length — or the shot’s remainder for a looping one. In a sequence a play with no duration occupies its natural length (a motion preset’s own length divided by speed; a non-looping descriptor animation’s likewise), so the sibling after it starts when it ends; a looping one runs to the shot end and occupies zero:

>>> [f.start for f in flatten(sequence(play("a", "idle_breath"), delay(1.0), play("a", "blink")))]
[0.0, 1.0]
>>> [f.start for f in flatten(sequence(play("a", "idle_breath", duration=2.0), play("a", "blink")))]
[0.0, 2.0]
>>> [f.start for f in flatten(sequence(play("a", "hop"), play("a", "nod")))]
[0.0, 0.5]
>>> [f.start for f in flatten(sequence(play("a", "hop", speed=2.0), play("a", "nod")))]
[0.0, 0.25]

(Bare flatten knows only the presets, by name; an validate and the compiler pass the entity’s descriptor too — cutan.characters.play.play_extent() — so a descriptor animation that shares a preset’s name is measured as the descriptor’s.)

A name the descriptor does not declare falls back to a motion preset of cutan.motion.PRESETS, with args as its parameters (an#166):

>>> play("charlie", "hop", args={"height": 30}).args
{'height': 30}
Return type:

PlayAction

cutan.characters.registration.play_duration(action, extent)[source]

The span a play occupies: its duration, else its natural extent.

extent is the caller’s resolver (the compiler and an validate pass one bound to the entity’s descriptor); without one, a motion preset’s own length (default_play_extent()).

>>> play_duration(PlayAction(target="a", animation="hop", duration=2.0), None)
2.0
>>> play_duration(PlayAction(target="a", animation="hop"), None)
0.5
Return type:

float

cutan.characters.registration.read_play_md(item, *, index)[source]

{kind: play, target, animation, [duration], [speed], [loop], [args]}.

Resolved at compile against the target entity’s descriptor animations (an#7), falling back to the motion presets of cutan.motion.PRESETS for a name the descriptor does not declare, with args as the preset’s parameters (an#166). loop omitted means the animation’s own. This reader accepted the shape from the start, then #24 made it refuse (nothing resolved a play) while the writer kept emitting it — three days of a project’s own scene.md failing to parse.

Return type:

PlayAction

cutan.characters.registration.write_play_md(leaf)[source]

The scene.md entry for leaf (read_play_md’s inverse).

Return type:

dict[str, Any]