an.engines.protocol#
The Engine protocol: a seekable thing that turns a time, or a state, into a frame.
The second of the three renderer tiers (ADR 0001 decision 12; core study §2.7):
Renderer(an.adapters._base) – shot in, media file out. Every back-end is reachable through it; Manim lives there, whole-shot.``Engine`` (this module) –
previz’s meaning of the word: something that can show the scene at any instant and hand over the pixels. The core turns any engine into aRendererwithan.engines.frame_stage_renderer(), which owns the clock, the capture loop, supersampling, the shutter and the sinks, so an engine implements none of them.LiveEngine– apply, settle, capture in real time (walkthru’s recorder). Declared, not built.
Capabilities are read from which members exist, never from a flag
(previz’s rule, ADR 0002 applied to engines), so a flag can never disagree
with the code. describe() is the one place that reads them.
An Engine is a stateless factory, safe to share across the threads of a
parallel render. Engine.open() loads one shot and yields a session:
the loaded, seekable view, whose members say what it can do.
And on the Engine itself: check(ctx) validates the engine’s own knobs
before anything launches (a typo must fail in microseconds, not after a browser
started).
>>> class _Still:
... def frame(self, t): return b"png"
... def state(self, t): return {}
>>> describe(_Still())
EngineProfile(tier='seekable', drive='time', features=frozenset({'readback'}))
>>> class _Crop:
... timeline = None
... def render(self, state): return b"png"
>>> describe(_Crop()).drive
'state'
Module Attributes
who evaluates the timeline. |
|
Tiers an engine can be on (the |
|
Optional session member -> the feature it unlocks. |
Functions
|
The tier, drive mode and features a session (or a session class) offers. |
|
|
|
The session's drive mode, or a refusal that says what to add. |
|
Requests as plain dicts, the shape a page or a subprocess takes. |
Classes
|
A stateless factory of loaded, seekable sessions -- one per shot render. |
|
What a session can do, read off its members. |
|
What the frame stage asks of an engine for one shot. |
|
One output frame's instants, in the order they must be captured. |
|
The live tier: apply, settle, capture in real time. |
|
A session the core hands states to. |
|
A session that evaluates the compiled channels itself. |
Exceptions
A session that the frame stage cannot drive; the message says what to add. |
- an.engines.protocol.DRIVE_TIME: str = 'time'#
who evaluates the timeline.
- Type:
Drive modes (core study §2.7)
- class an.engines.protocol.Engine(*args, **kwargs)[source]#
Bases:
ProtocolA stateless factory of loaded, seekable sessions – one per shot render.
- class an.engines.protocol.EngineProfile(tier, drive, features)[source]#
Bases:
objectWhat a session can do, read off its members.
- an.engines.protocol.FEATURE_MEMBERS: dict[str, str] = {'bounds': 'bounds', 'frame_with_alpha': 'alpha', 'frames': 'batch', 'project': 'project', 'provenance': 'provenance', 'render_states': 'batch', 'resolve': 'resolve', 'state': 'readback'}#
Optional session member -> the feature it unlocks. The SSOT
describe()reads; a new feature is a new row, never a flag on an engine.
- class an.engines.protocol.FrameJob(shot, ctx, workspace, frames_dir, total_frames, supersample, frame_samples=None)[source]#
Bases:
objectWhat the frame stage asks of an engine for one shot.
Built by the core, before
Engine.open(): every knob here is already validated, so an engine never re-derives the frame count or the factor.- frame_samples: tuple[tuple[float, ...], ...] | None#
Per frame, the instants to capture and average, or
Nonefor one instant ati / fps.
- requests()[source]#
Every frame’s request, frame
iati / fpsunless a clock says otherwise.- Return type:
>>> from types import SimpleNamespace >>> job = FrameJob(None, SimpleNamespace(fps=4, resolution=(2, 2)), Path("."), ... Path("."), total_frames=3, supersample=1) >>> [r.times for r in job.requests()] [(0.0,), (0.25,), (0.5,)]
- property size: tuple[int, int]#
what every resolved frame must be.
- Type:
The DECLARED (width, height)
- class an.engines.protocol.FrameRequest(frame, times)[source]#
Bases:
objectOne output frame’s instants, in the order they must be captured.
One instant unless a frame clock opened the shutter (
RenderContext.frame_samples).
- class an.engines.protocol.LiveEngine(*args, **kwargs)[source]#
Bases:
ProtocolThe live tier: apply, settle, capture in real time. Declared, not built.
Its recorder resamples to a constant rate (
walkthru’s worked example);frame_stage_rendererdoes not drive it, and never falls back to it.
- class an.engines.protocol.StateDriven(*args, **kwargs)[source]#
Bases:
ProtocolA session the core hands states to.
- an.engines.protocol.TIER_SEEKABLE: str = 'seekable'#
Tiers an engine can be on (the
Renderertier is not an engine).
- class an.engines.protocol.TimeDriven(*args, **kwargs)[source]#
Bases:
ProtocolA session that evaluates the compiled channels itself.
- exception an.engines.protocol.UnseekableEngineError[source]#
Bases:
TypeErrorA session that the frame stage cannot drive; the message says what to add.
- an.engines.protocol.describe(session)[source]#
The tier, drive mode and features a session (or a session class) offers.
- Return type:
- an.engines.protocol.drive_mode(session)[source]#
"time","state", orNonefor a session the frame stage cannot drive.A session with both
frameandrenderis time-driven: it evaluates its own document, and the core does not second-guess it.
- an.engines.protocol.requests_as_dicts(requests)[source]#
Requests as plain dicts, the shape a page or a subprocess takes.
- an.engines.protocol.require_seekable(session)[source]#
The session’s drive mode, or a refusal that says what to add.
- Return type:
>>> require_seekable(object()) Traceback (most recent call last): ... an.engines.protocol.UnseekableEngineError: this engine session cannot be captured: it has no frame(t) (time-driven), and no render(state) with a timeline (state-driven). Add frame(t) and state(t) if the engine evaluates the timeline itself, or timeline and render(state) if the core should evaluate it.