muvid.choreo.spec¶
The choreo treatment spec — what a director decides, as data; stdlib-only.
The same two-layer split as muvid.lyricvid.spec, for the same reason:
directionWHAT and WHY — palette, background, density, mood, a rationale. The half a model (or a person in a hurry) is genuinely good at.
scenesHOW — an archetype from a closed set, which sections it applies to, and a small bag of archetype parameters. Never geometry, never timings: every coordinate and every time is computed in Python from the event list.
Closed vocabularies everywhere (archetypes, backgrounds, densities), and a
repair that projects a nearly-right spec onto the valid space rather than
handing it back — a mechanical substitution renders something good now.
Module Attributes
How events become objects. |
|
What is behind the objects. |
|
How many events become objects, and how many objects an event makes. |
|
an event below it makes no object. |
|
Count multiplier per density, for the archetypes that spawn several per event. |
|
Archetype parameters, documented once for the schema and the prompt. |
Functions
|
Whatever a caller produced -> a renderable spec plus the repair notes. |
|
A one-scene treatment for |
The JSON Schema for a |
|
|
Project |
|
Human-readable problems; empty means renderable. |
Every closed vocabulary, for prompts and UI. |
Classes
|
The song-level creative decision. |
|
Colours as |
|
One archetype applied to part of the song. |
|
A complete, renderable treatment. |
- muvid.choreo.spec.ARCHETYPES: dict[str, str] = {'fischinger': 'Geometric shapes ignite per onset on a grid — band picks the shape class (low: discs, mid: squares, high: triangles), strength the size, and each section a different arrangement. The Study No. 7 look.', 'mclaren': 'White scratches and marks on black, one per onset, jittered, gone within a fraction of a beat. Hand-scratched film.', 'star_guitar': 'A side-scrolling landscape: bass onsets are poles, mids are buildings, highs are wires. Everything scrolls left at one constant speed, so the spacing of the objects IS the rhythm. Sections change the sky.', 'swarm': 'Particles whose count and speed follow band energy, thrown from a band-specific origin and persisting as they slow. Continuous, organic.'}¶
How events become objects. Each is a function in
muvid.choreo.scene.
- muvid.choreo.spec.ARCHETYPE_PARAMS: dict[str, dict[str, tuple[float, float, float, str]]] = {'fischinger': {'columns': (6, 2, 24, 'grid columns'), 'hold_beats': (1.0, 0.1, 8.0, 'how long a shape lives, in beats'), 'rows': (3, 1, 12, 'grid rows')}, 'mclaren': {'life_beats': (0.25, 0.05, 2.0, 'how long a scratch lives, in beats')}, 'star_guitar': {'horizon': (0.72, 0.3, 0.95, 'ground line, fraction of height from the top'), 'speed': (0.35, 0.05, 2.0, 'scroll speed, canvas widths per second')}, 'swarm': {'life_s': (1.5, 0.2, 6.0, 'particle lifetime, seconds'), 'particles': (6, 1, 40, 'particles per event at normal density')}}¶
Archetype parameters, documented once for the schema and the prompt. Each is read by its archetype with the default given here and clamped to the range.
- muvid.choreo.spec.BACKGROUNDS: dict[str, str] = {'gradient': 'Vertical gradient from palette.bg (top) to palette.bg2 (bottom).', 'solid': 'One flat colour (palette.bg).', 'vignette': 'palette.bg, darkened toward the corners.'}¶
What is behind the objects.
- muvid.choreo.spec.DENSITIES: dict[str, str] = {'dense': 'Every onset marks, and each makes more.', 'normal': 'Most onsets mark.', 'sparse': 'Only strong onsets mark; few objects at a time.'}¶
How many events become objects, and how many objects an event makes.
- muvid.choreo.spec.DENSITY_FACTOR: dict[str, float] = {'dense': 2.0, 'normal': 1.0, 'sparse': 0.5}¶
Count multiplier per density, for the archetypes that spawn several per event.
- muvid.choreo.spec.DENSITY_GATE: dict[str, float] = {'dense': 0.0, 'normal': 0.15, 'sparse': 0.45}¶
an event below it makes no object.
- Type:
Strength gate per density
- class muvid.choreo.spec.Direction(*, mood='', palette=<factory>, background='solid', density='normal', rationale='')[source]¶
Bases:
objectThe song-level creative decision.
- class muvid.choreo.spec.Palette(*, bg='#0b0b12', bg2='#1b1b2e', fg='#f4f1e8', low='#e4572e', mid='#f3c623', high='#4cc9f0')[source]¶
Bases:
objectColours as
#rrggbb.low/mid/highare the band colours.
- class muvid.choreo.spec.Scene(*, applies_to=('*', ), archetype='fischinger', params=<factory>)[source]¶
Bases:
objectOne archetype applied to part of the song.
applies_tonames section tiers (low/mid/high), section indices as strings ("2"), or"*"for everything. A named scene wins its sections over a"*"one; sections nobody names fall back to the first"*"scene, and to the first scene if there is none.
- class muvid.choreo.spec.TreatmentSpec(*, spec_version='1.0', title='', direction=<factory>, scenes=<factory>)[source]¶
Bases:
objectA complete, renderable treatment.
>>> s = TreatmentSpec() >>> validate(s) [] >>> TreatmentSpec.from_dict(s.to_dict()) == s True- classmethod from_dict(d)[source]¶
Build from a plain mapping — TOTAL over what a model or caller sends.
- Return type:
>>> s = TreatmentSpec.from_dict({'scenes': [None, {'applies_to': 'high', ... 'archetype': 'swarm', 'params': 'nope'}], ... 'direction': {'palette': {'foo': 1, 'bg': '#000000'}, 'density': None}}) >>> s.scenes[1].applies_to, s.scenes[1].params, s.direction.palette.bg (('high',), {}, '#000000')
- muvid.choreo.spec.coerce(obj)[source]¶
Whatever a caller produced -> a renderable spec plus the repair notes.
- Return type:
- muvid.choreo.spec.default_treatment(archetype='fischinger', **direction)[source]¶
A one-scene treatment for
archetype; the CLI’s--archetypeshortcut.- Return type:
>>> default_treatment('mclaren').scenes[0].archetype 'mclaren'
- muvid.choreo.spec.json_schema()[source]¶
The JSON Schema for a
TreatmentSpec.>>> json_schema()['properties']['scenes']['items']['properties']['archetype']['enum'] ['fischinger', 'star_guitar', 'mclaren', 'swarm']
- muvid.choreo.spec.repair(spec)[source]¶
Project
speconto the valid space; return(spec, notes).- Return type:
>>> fixed, notes = repair(TreatmentSpec(scenes=(Scene(archetype='swirl', ... params={'columns': 99, 'bogus': 1}),))) >>> fixed.scenes[0].archetype, dict(fixed.scenes[0].params) ('fischinger', {'columns': 24}) >>> notes ["scenes[0].archetype 'swirl' -> 'fischinger'", 'scenes[0].params.columns 99 -> 24', "scenes[0].params dropped unknown ['bogus']"]