animatableProps function
Imposed plus the target kind's intrinsic properties, in canonical emit order.
Implementation
List<ScenePropSpec> animatableProps(SceneNode node) => [
...imposedProps,
...switch (node) {
TextNode() => const [
ScenePropSpec(
'fontSize',
TrackKind.number,
unit: 'px',
softMin: 8,
softMax: 96,
),
// Tracking is the one a display size wants animated, and it wants it
// negative: a title that tightens as it lands.
ScenePropSpec(
'letterSpacing',
TrackKind.number,
identity: 0,
unit: 'px',
softMin: -8,
softMax: 24,
entrance: 12,
),
ScenePropSpec(
'wordSpacing',
TrackKind.number,
identity: 0,
unit: 'px',
softMin: -8,
softMax: 24,
),
ScenePropSpec(
'lineHeight',
TrackKind.number,
identity: 1.15,
softMin: 0.8,
softMax: 2,
),
ScenePropSpec(
'decorationThickness',
TrackKind.number,
identity: 1,
softMin: 0,
softMax: 6,
),
ScenePropSpec('color', TrackKind.color),
],
FrameNode() => const [
ScenePropSpec(
'gap',
TrackKind.number,
unit: 'px',
softMin: 0,
softMax: 64,
),
ScenePropSpec('fill', TrackKind.color),
],
ShapeNode() => const [ScenePropSpec('fill', TrackKind.color)],
// A registered kind's rows, with the hints the row carries.
KindNode k => [
for (var p in k.kind.props)
if (p.animatable)
ScenePropSpec(
p.name,
p.kind == ScenePropKind.color ? TrackKind.color : TrackKind.number,
identity: p.identity,
unit: p.unit,
softMin: p.softMin,
softMax: p.softMax,
angular: p.angular,
),
],
ExternalNode() => const <ScenePropSpec>[],
// The child's declared parameters, once somebody resolved it — a string
// parameter has no in-between values and does not animate.
SceneRefNode r => [
for (var p in r.instance?.params ?? const <SceneParamDecl>[])
if (p.kind == SceneParamKind.number)
ScenePropSpec('args.${p.name}', TrackKind.number)
else if (p.kind == SceneParamKind.color)
ScenePropSpec('args.${p.name}', TrackKind.color),
],
},
];