an.timing.kinds#
Field kinds: the declared interpolator of each animatable property.
The declared kind picks the interpolator; a runtime value never does. A field
kind is what lets a number be an angle (shortest arc), a log-space zoom, or a
colour mixed in OKLab — none of which a value’s type can say. Kinds are declared
per property by a property space (an.timing.spaces); a property no space
declares is DiscreteKind.
Seven kinds are seeded, each parametrised (the TypeScript kernel’s seven):
Discrete is defined on TIME, never on a ratio or an eased value (an#86). A
segment from key a to key b shows b iff t >= a.time + switch_at *
(b.time - a.time), and switch_at == 1 is evaluated as t >= b.time with
no arithmetic at all: (t - a.time) / span can round up to 1.0 while
t < b.time, and an overshooting easing would flip an eased comparison twice.
Genres add kinds with register_kind() (a Manim genre’s points, say)
without editing this module.
>>> NumberKind().interpolate(0.0, 10.0, 0.25, Segment(0.25, 0.0, 1.0))
2.5
>>> NumberKind(space="log").interpolate(1.0, 4.0, 0.5, Segment(0.5, 0.0, 1.0))
2.0
>>> AngleKind().interpolate(350, 10, 0.5, Segment(0.5, 0.0, 1.0)) # not re-normalised
360.0
>>> b = 9.767899248713501
>>> DiscreteKind(switch_at=1).interpolate("A", "B", 1.0, Segment(math.nextafter(b, 0), 0.15, b))
'A'
>>> kind_from_spec({"kind": "number", "space": "log"})
NumberKind(space='log')
Module Attributes
Where an undeclared discrete value switches, in normalised segment time. |
|
How far a quaternion's norm may be from 1 and still count as unit length. |
|
Above this |dot|, slerp falls back to normalised lerp (the arc is too short). |
|
its parameters as keyword arguments -> an instance. |
|
Who registered the seeded kinds (only these reach the contract files). |
Functions
|
A kind instance from its contract spec ( |
|
The registered kind names in registration order; only |
|
Register a field kind under |
|
The signed shortest turn from |
|
Spherical interpolation of unit quaternions |
Classes
|
An angle: the shortest arc when |
|
A colour (hex or |
|
Holds |
Base of every field kind: a frozen, hashable, JSON-describable interpolator. |
|
|
A continuous scalar. |
|
A camera orbiting a target: |
A unit quaternion |
|
|
Where an evaluation sits: time |
A fixed-length list of numbers, interpolated componentwise. |
Exceptions
A kind spec is malformed, or names no registered kind. |
- class an.timing.kinds.AngleKind(unit='deg', wrap=True)[source]#
Bases:
FieldKindAn angle: the shortest arc when
wrap, else the raw numbers. Interpolated angles are not re-normalised (350 -> 10 passes through 360).
- an.timing.kinds.CORE_OWNER: str = 'an'#
Who registered the seeded kinds (only these reach the contract files).
- class an.timing.kinds.ColorKind(space='oklab')[source]#
Bases:
FieldKindA colour (hex or
[r, g, b, a?]in 0..1), written back in the form of the start value.oklabmixes perceptually with premultiplied alpha;srgblerps the encoded channels (Manim’s and the stage tint’s rule).
- an.timing.kinds.DEFAULT_SWITCH_AT: float = 0.5#
Where an undeclared discrete value switches, in normalised segment time.
- class an.timing.kinds.DiscreteKind(switch_at=0.5)[source]#
Bases:
FieldKindHolds
aand switches tobon TIME (see the module docstring).switch_atlies in(0, 1]. The default, 0.5, is the switch point of an undeclared property; a replacement drawing (a swap set) declares 1, so it never appears before its own key.
- class an.timing.kinds.FieldKind[source]#
Bases:
objectBase of every field kind: a frozen, hashable, JSON-describable interpolator.
Subclasses set
nameand implementinterpolate(); the dataclass fields are the kind’s parameters, andto_spec()writes them as the contract does ({"kind": name, **non-default params}).
- exception an.timing.kinds.FieldKindError[source]#
Bases:
ValueErrorA kind spec is malformed, or names no registered kind.
- an.timing.kinds.KindFactory#
its parameters as keyword arguments -> an instance.
- Type:
A kind’s factory
alias of
Callable[[…],FieldKind]
- class an.timing.kinds.NumberKind(space='linear')[source]#
Bases:
FieldKindA continuous scalar.
space="log"interpolates the logarithm (zoom, scale).Linear interpolation is
a + (b - a) * uwith no special case at the ends, which is the stage runtime’s arithmetic: a declarednumberchannel is bit-identical to whatruntime.jsdraws.
- class an.timing.kinds.OrbitKind(unit='deg')[source]#
Bases:
FieldKindA camera orbiting a target:
{azimuth, elevation, distance, target?}.Azimuth takes the shortest arc, elevation is lerped and clamped to the poles, distance is lerped in log, target componentwise. Any other member is discrete and switches at
DEFAULT_SWITCH_AT(on time). One value: a dotted address never reaches inside it.
- an.timing.kinds.QUATERNION_UNIT_TOLERANCE: float = 0.001#
How far a quaternion’s norm may be from 1 and still count as unit length.
- class an.timing.kinds.QuaternionKind[source]#
Bases:
FieldKindA unit quaternion
[x, y, z, w], interpolated by slerp after a sign fix.
- an.timing.kinds.SLERP_LINEAR_THRESHOLD: float = 0.9995#
Above this |dot|, slerp falls back to normalised lerp (the arc is too short).
- class an.timing.kinds.Segment(t, start, end)[source]#
Bases:
objectWhere an evaluation sits: time
tinside the segment[start, end).
- class an.timing.kinds.VectorKind[source]#
Bases:
FieldKindA fixed-length list of numbers, interpolated componentwise.
- an.timing.kinds.kind_from_spec(spec)[source]#
A kind instance from its contract spec (
{"kind": name, **params}), a bare kind name, or an instance (returned as is).- Return type:
>>> kind_from_spec("discrete") DiscreteKind(switch_at=0.5) >>> kind_from_spec({"kind": "points"}) Traceback (most recent call last): ... an.timing.kinds.FieldKindError: unknown field kind 'points'; known: ['number', 'angle', 'vector', 'quaternion', 'color', 'orbit', 'discrete']
- an.timing.kinds.kind_names(*, owner=None)[source]#
The registered kind names in registration order; only
owner’s when given.
- an.timing.kinds.register_kind(name, factory, *, replace=False, owner=None)[source]#
Register a field kind under
name(how a genre adds one).ownernames who registered it; onlyCORE_OWNER’s kinds reachan’s contract files.>>> sorted(kind_names())[:3] ['angle', 'color', 'discrete']
- an.timing.kinds.shortest_delta(a, b, period=360.0)[source]#
The signed shortest turn from
atob, in[-period/2, period/2].An exact half turn goes in the direction of
b - a, so a return trip retraces its path (0 -> 180 -> 0 goes there and back, not round).- Return type:
>>> shortest_delta(350, 10), shortest_delta(10, 350), shortest_delta(0, 180) (20.0, -20.0, 180.0)