@px-petals/roku.motion-web 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/bands/bands.js +3 -1
  2. package/bundle/bundle.js +56 -0
  3. package/list/list.js +12 -1
  4. package/lottie/lottie.layers.js +64 -11
  5. package/lottie/lottie.paint.js +30 -0
  6. package/lottie/lottie.paths.js +19 -4
  7. package/lottie/lottie.props.js +18 -8
  8. package/lottie/lottie.shapes.js +2 -1
  9. package/mixer/mixer.js +31 -8
  10. package/mixer/mixer.mix.js +17 -0
  11. package/motion/motion.convert.js +32 -1
  12. package/motion/motion.flow.js +20 -2
  13. package/motion/motion.machine.js +28 -13
  14. package/motion/motion.values.js +13 -9
  15. package/motion.js +196 -20
  16. package/package.json +10 -16
  17. package/player/player.js +25 -5
  18. package/readme.md +78 -3
  19. package/script/luau/lib/base/base.js +202 -0
  20. package/script/luau/lib/base/base.table.js +189 -0
  21. package/script/luau/lib/lib.args.js +152 -0
  22. package/script/luau/lib/lib.js +23 -0
  23. package/script/luau/lib/math/math.bit32.js +144 -0
  24. package/script/luau/lib/math/math.js +288 -0
  25. package/script/luau/lib/math/math.vector.js +125 -0
  26. package/script/luau/lib/string/string.format.js +143 -0
  27. package/script/luau/lib/string/string.js +160 -0
  28. package/script/luau/lib/string/string.pattern.js +505 -0
  29. package/script/luau/load/load.js +362 -0
  30. package/script/luau/load/load.ops.js +79 -0
  31. package/script/luau/luau.convert.js +259 -0
  32. package/script/luau/luau.js +132 -0
  33. package/script/luau/luau.md +111 -0
  34. package/script/luau/vm/vm.js +167 -0
  35. package/script/luau/vm/vm.meta.js +401 -0
  36. package/script/luau/vm/vm.num.js +236 -0
  37. package/script/luau/vm/vm.run.js +842 -0
  38. package/script/luau/vm/vm.value.js +406 -0
  39. package/script/play/play.js +199 -0
  40. package/script/play/play.objects.js +295 -0
  41. package/script/play/play.scope.js +91 -0
  42. package/script/rive/api/api.statics.js +31 -0
  43. package/script/rive/api/api.type.js +188 -0
  44. package/script/rive/api/artboard/artboard.js +89 -0
  45. package/script/rive/api/assets/assets.js +72 -0
  46. package/script/rive/api/data/data.value.js +99 -0
  47. package/script/rive/api/draw/draw.contours.js +163 -0
  48. package/script/rive/api/draw/draw.measure.js +196 -0
  49. package/script/rive/api/draw/draw.paint.js +235 -0
  50. package/script/rive/api/draw/draw.path.js +153 -0
  51. package/script/rive/api/draw/draw.renderer.js +117 -0
  52. package/script/rive/api/math/math.color.js +96 -0
  53. package/script/rive/api/math/math.mat2d.js +180 -0
  54. package/script/rive/api/math/math.vector.js +121 -0
  55. package/script/rive/api/media/media.audio.js +113 -0
  56. package/script/rive/api/media/media.draw.js +73 -0
  57. package/script/rive/api/media/media.image.js +61 -0
  58. package/script/rive/api/media/media.mesh.js +50 -0
  59. package/script/rive/api/pointer/pointer.event.js +64 -0
  60. package/script/rive/api/pointer/pointer.route.js +69 -0
  61. package/script/rive/api/text/text.font.js +129 -0
  62. package/script/rive/api/text/text.js +278 -0
  63. package/script/rive/api/text/text.layout.js +259 -0
  64. package/script/rive/context/context.js +76 -0
  65. package/script/rive/context/context.memory.js +196 -0
  66. package/script/rive/context/context.viewmodel.js +302 -0
  67. package/script/rive/context/lists/lists.js +160 -0
  68. package/script/rive/context/lists/lists.values.js +281 -0
  69. package/script/rive/host/host.globals.js +44 -0
  70. package/script/rive/host/host.js +533 -0
  71. package/script/rive/host/host.node.js +45 -0
  72. package/script/rive/rive.js +23 -0
  73. package/script/rive/rive.md +180 -0
  74. package/script/script.js +11 -0
  75. package/skin/skin.deform.js +514 -0
  76. package/skin/skin.ik.js +260 -0
  77. package/skin/skin.js +297 -0
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Inverse kinematics for a skin's bone chain, from rive-runtime's
3
+ * `IKConstraint` (src/constraints/ik_constraint.cpp): one bone points at the
4
+ * target, two are solved by the law of cosines, a longer chain solves each
5
+ * bone against the tip in turn, and strength blends the solved angles with
6
+ * the angles the chain had. The converter solves the same way
7
+ * (rive/transformer/constraint/constraint.ik.js).
8
+ *
9
+ * It runs whenever a bound value moves a skin, so it allocates nothing: the
10
+ * caller fills `LOCALS` and `PARENT`, `solve` works in preallocated buffers,
11
+ * and the solved worlds are in `WORLDS`.
12
+ */
13
+
14
+ /** The most bones in a chain; a longer one is left as the bones' own values pose it */
15
+ export const MAX_CHAIN = 32
16
+
17
+ /** The chain's local matrices before the solve, six numbers a bone */
18
+ export const LOCALS = new Float64Array(MAX_CHAIN * 6)
19
+ /** The world matrix of the top bone's parent */
20
+ export const PARENT = new Float64Array(6)
21
+ /** The solved world matrices, six numbers a bone; the first six are the parent's, so a bone's parent is the slot before it */
22
+ export const WORLDS = new Float64Array((MAX_CHAIN + 1) * 6)
23
+
24
+ // what the solve starts from: each bone's own x, y, scale, skew and rotation, and its parent's world, inverted
25
+ const COMPONENTS = new Float64Array(MAX_CHAIN * 6)
26
+ const INVERSES = new Float64Array(MAX_CHAIN * 6)
27
+ const ANGLES = new Float64Array(MAX_CHAIN)
28
+
29
+ const TAU = Math.PI * 2
30
+
31
+ /**
32
+ * `world[slot] = world[parent] × local`, the matrices six numbers each.
33
+ *
34
+ * @param {number} bone the bone's place in the chain
35
+ */
36
+ function compose(bone) {
37
+ const p = bone * 6
38
+ const q = bone * 6
39
+ const o = (bone + 1) * 6
40
+ const a0 = WORLDS[p], a1 = WORLDS[p + 1], a2 = WORLDS[p + 2], a3 = WORLDS[p + 3], a4 = WORLDS[p + 4], a5 = WORLDS[p + 5]
41
+ const b0 = LOCALS[q], b1 = LOCALS[q + 1], b2 = LOCALS[q + 2], b3 = LOCALS[q + 3], b4 = LOCALS[q + 4], b5 = LOCALS[q + 5]
42
+ WORLDS[o] = a0 * b0 + a2 * b1
43
+ WORLDS[o + 1] = a1 * b0 + a3 * b1
44
+ WORLDS[o + 2] = a0 * b2 + a2 * b3
45
+ WORLDS[o + 3] = a1 * b2 + a3 * b3
46
+ WORLDS[o + 4] = a0 * b4 + a2 * b5 + a4
47
+ WORLDS[o + 5] = a1 * b4 + a3 * b5 + a5
48
+ }
49
+
50
+ /**
51
+ * The bone's parent's world, inverted (the identity where it has no inverse).
52
+ *
53
+ * @param {number} bone
54
+ */
55
+ function invertParent(bone) {
56
+ const p = bone * 6
57
+ const o = bone * 6
58
+ const a = WORLDS[p], b = WORLDS[p + 1], c = WORLDS[p + 2], d = WORLDS[p + 3], tx = WORLDS[p + 4], ty = WORLDS[p + 5]
59
+ let det = a * d - b * c
60
+ if (det === 0) {
61
+ INVERSES[o] = 1
62
+ INVERSES[o + 1] = 0
63
+ INVERSES[o + 2] = 0
64
+ INVERSES[o + 3] = 1
65
+ INVERSES[o + 4] = 0
66
+ INVERSES[o + 5] = 0
67
+ return
68
+ }
69
+ det = 1 / det
70
+ INVERSES[o] = d * det
71
+ INVERSES[o + 1] = -b * det
72
+ INVERSES[o + 2] = -c * det
73
+ INVERSES[o + 3] = a * det
74
+ INVERSES[o + 4] = (c * ty - d * tx) * det
75
+ INVERSES[o + 5] = (b * tx - a * ty) * det
76
+ }
77
+
78
+ /**
79
+ * The bone's local matrix at a rotation, its position, scale and skew as it began.
80
+ *
81
+ * @param {number} bone
82
+ * @param {number} rotation
83
+ */
84
+ function turn(bone, rotation) {
85
+ const c = bone * 6
86
+ const cos = rotation === 0 ? 1 : Math.cos(rotation)
87
+ const sin = rotation === 0 ? 0 : Math.sin(rotation)
88
+ const a = cos * COMPONENTS[c + 2]
89
+ const b = sin * COMPONENTS[c + 2]
90
+ let m2 = -sin * COMPONENTS[c + 3]
91
+ let m3 = cos * COMPONENTS[c + 3]
92
+ const skew = COMPONENTS[c + 4]
93
+ if (skew !== 0) {
94
+ m2 = a * skew + m2
95
+ m3 = b * skew + m3
96
+ }
97
+ LOCALS[c] = a
98
+ LOCALS[c + 1] = b
99
+ LOCALS[c + 2] = m2
100
+ LOCALS[c + 3] = m3
101
+ LOCALS[c + 4] = COMPONENTS[c]
102
+ LOCALS[c + 5] = COMPONENTS[c + 1]
103
+ compose(bone)
104
+ }
105
+
106
+ /**
107
+ * `std::max(-1, std::min(1, x))`, which sends NaN to 1 as the C++ library does.
108
+ *
109
+ * @param {number} x
110
+ */
111
+ function clamp(x) {
112
+ const low = x < 1 ? x : 1
113
+ return -1 < low ? low : -1
114
+ }
115
+
116
+ /**
117
+ * The shorter turn from one angle to another, each first taken modulo a full turn.
118
+ *
119
+ * @param {number} from
120
+ * @param {number} to
121
+ */
122
+ function difference(from, to) {
123
+ let diff = (to % TAU) - (from % TAU)
124
+ if (diff > Math.PI) diff -= TAU
125
+ else if (diff < -Math.PI) diff += TAU
126
+ return diff
127
+ }
128
+
129
+ /**
130
+ * @param {number} bone
131
+ * @returns {number} the x of the bone's world translation
132
+ */
133
+ const worldX = (bone) => WORLDS[(bone + 1) * 6 + 4]
134
+ /** @param {number} bone */
135
+ const worldY = (bone) => WORLDS[(bone + 1) * 6 + 5]
136
+
137
+ /**
138
+ * A point through the matrix of a bone's parent's inverse, as x or y.
139
+ *
140
+ * @param {number} bone
141
+ * @param {number} x
142
+ * @param {number} y
143
+ * @param {boolean} wantY
144
+ */
145
+ function parentSpace(bone, x, y, wantY) {
146
+ const i = bone * 6
147
+ return wantY ? INVERSES[i + 1] * x + INVERSES[i + 3] * y + INVERSES[i + 5] : INVERSES[i] * x + INVERSES[i + 2] * y + INVERSES[i + 4]
148
+ }
149
+
150
+ /**
151
+ * Solves the chain in `LOCALS` against a target, leaving the worlds in `WORLDS`.
152
+ *
153
+ * @param {number} count bones in the chain, the top one first
154
+ * @param {number} tipLength the last bone's length
155
+ * @param {number} tx the target's world x
156
+ * @param {number} ty the target's world y
157
+ * @param {boolean} invert
158
+ * @param {number} strength 0..1
159
+ */
160
+ export function solve(count, tipLength, tx, ty, invert, strength) {
161
+ for (let k = 0; k < 6; k++) WORLDS[k] = PARENT[k]
162
+ for (let n = 0; n < count; n++) {
163
+ const c = n * 6
164
+ // Mat2D::decompose of the bone's own matrix
165
+ const m0 = LOCALS[c], m1 = LOCALS[c + 1], m2 = LOCALS[c + 2], m3 = LOCALS[c + 3]
166
+ const denom = m0 * m0 + m1 * m1
167
+ const scaleX = Math.sqrt(denom)
168
+ COMPONENTS[c] = LOCALS[c + 4]
169
+ COMPONENTS[c + 1] = LOCALS[c + 5]
170
+ COMPONENTS[c + 2] = scaleX
171
+ COMPONENTS[c + 3] = scaleX === 0 ? 0 : (m0 * m3 - m2 * m1) / scaleX
172
+ COMPONENTS[c + 4] = Math.atan2(m0 * m2 + m1 * m3, denom)
173
+ COMPONENTS[c + 5] = Math.atan2(m1, m0)
174
+ ANGLES[n] = COMPONENTS[c + 5]
175
+ compose(n)
176
+ }
177
+ for (let n = 0; n < count; n++) invertParent(n)
178
+
179
+ if (count === 1) {
180
+ solveOne(tx, ty)
181
+ } else if (count === 2) {
182
+ solveTwo(0, 1, tipLength, tx, ty, invert)
183
+ } else {
184
+ const last = count - 1
185
+ for (let n = 0; n < last; n++) {
186
+ solveTwo(n, last, tipLength, tx, ty, invert)
187
+ for (let j = n + 1; j < last; j++) invertParent(j)
188
+ }
189
+ }
190
+
191
+ if (strength !== 1) {
192
+ for (let n = 0; n < count; n++) {
193
+ const from = COMPONENTS[n * 6 + 5] % TAU
194
+ turn(n, from + difference(from, ANGLES[n]) * strength)
195
+ }
196
+ }
197
+ }
198
+
199
+ /**
200
+ * @param {number} tx
201
+ * @param {number} ty
202
+ */
203
+ function solveOne(tx, ty) {
204
+ const x = INVERSES[0] * (tx - worldX(0)) + INVERSES[2] * (ty - worldY(0))
205
+ const y = INVERSES[1] * (tx - worldX(0)) + INVERSES[3] * (ty - worldY(0))
206
+ const r = Math.atan2(y, x)
207
+ turn(0, r)
208
+ ANGLES[0] = r
209
+ }
210
+
211
+ /**
212
+ * @param {number} first the bone solved against the target
213
+ * @param {number} last the tip, which the solve brings to the target
214
+ * @param {number} tipLength
215
+ * @param {number} tx
216
+ * @param {number} ty
217
+ * @param {boolean} invert
218
+ */
219
+ function solveTwo(first, last, tipLength, tx, ty, invert) {
220
+ const child = first + 1
221
+ const aX = parentSpace(first, worldX(first), worldY(first), false)
222
+ const aY = parentSpace(first, worldX(first), worldY(first), true)
223
+ const cX = parentSpace(first, worldX(child), worldY(child), false)
224
+ const cY = parentSpace(first, worldX(child), worldY(child), true)
225
+ const lw = (last + 1) * 6
226
+ const tipX = WORLDS[lw] * tipLength + WORLDS[lw + 4]
227
+ const tipY = WORLDS[lw + 1] * tipLength + WORLDS[lw + 5]
228
+ const bX = parentSpace(first, tipX, tipY, false)
229
+ const bY = parentSpace(first, tipX, tipY, true)
230
+ const tX = parentSpace(first, tx, ty, false)
231
+ const tY = parentSpace(first, tx, ty, true)
232
+
233
+ const a = Math.sqrt((bX - cX) * (bX - cX) + (bY - cY) * (bY - cY))
234
+ const b = Math.sqrt((cX - aX) * (cX - aX) + (cY - aY) * (cY - aY))
235
+ const cvX = tX - aX
236
+ const cvY = tY - aY
237
+ const c = Math.sqrt(cvX * cvX + cvY * cvY)
238
+
239
+ const A = Math.acos(clamp((-a * a + b * b + c * c) / (2 * b * c)))
240
+ const C = Math.acos(clamp((a * a + b * b - c * c) / (2 * a * b)))
241
+
242
+ let correction = 0
243
+ if (last !== child) {
244
+ // the tip is further down: the bone after the child turns the correction
245
+ const dx = tipX - worldX(child)
246
+ const dy = tipY - worldY(child)
247
+ const lx = INVERSES[(first + 2) * 6] * dx + INVERSES[(first + 2) * 6 + 2] * dy
248
+ const ly = INVERSES[(first + 2) * 6 + 1] * dx + INVERSES[(first + 2) * 6 + 3] * dy
249
+ correction = -Math.atan2(ly, lx)
250
+ }
251
+ const toTarget = Math.atan2(cvY, cvX)
252
+ const r1 = invert ? toTarget - A : A + toTarget
253
+ const r2 = (invert ? -C + Math.PI : C - Math.PI) + correction
254
+
255
+ turn(first, r1)
256
+ turn(child, r2)
257
+ if (child !== last) compose(last)
258
+ ANGLES[first] = r1
259
+ ANGLES[child] = r2
260
+ }
package/skin/skin.js ADDED
@@ -0,0 +1,297 @@
1
+ /**
2
+ * Skins: the paths a bundle's `skins` deform from the values data binds set.
3
+ * A bind's source is a slot's source (a view-model path and a converter),
4
+ * read by the caller's `read`; each time one of a skin's bound values changes
5
+ * the skin's path is recomputed, to be written into the slot `sid` as any slot
6
+ * value.
7
+ *
8
+ * A skin may also hold IK constraints over its bones (`ik`), whose strength
9
+ * and target position data can bind as well: they are solved, one chain each,
10
+ * before the bones deform the path.
11
+ *
12
+ * Under the bound values play what an animation keys in the rig (`keys`),
13
+ * as Rive applies animations first and binds after: a bound channel overrides
14
+ * the keyed one, and the rest keep following the animation. A skin an
15
+ * animation keys is written as a function of the frame, for the player to ask
16
+ * as it draws; any other as the path itself. In a nested machine that plays
17
+ * several animations at once, each channel is mixed toward each pose that
18
+ * keys it by the pose's weight, as Rive applies them, before the bones deform
19
+ * the path; the player passes the poses of the machine the path is drawn in.
20
+ *
21
+ * Nothing is allocated once a skin is made: its values, the scratch it
22
+ * deforms in and the paths it writes are made up front and reused.
23
+ */
24
+
25
+ import { BONE_CHANNELS, createPath, createRig, deformRig, IK_CHANNELS, NODE_CHANNELS, VERTEX_CHANNELS } from './skin.deform.js'
26
+ import { settledWeight } from '../mixer/mixer.mix.js'
27
+
28
+ /**
29
+ * @typedef {import('./skin.deform.js').Skin} Skin
30
+ * @typedef {import('./skin.deform.js').LottiePath} LottiePath
31
+ * @typedef {import('./skin.deform.js').Rig} Rig
32
+ *
33
+ * @typedef {object} State
34
+ * @property {Skin} skin
35
+ * @property {Rig} rig
36
+ * @property {number[]} at where in `rig.now` each bind's value goes
37
+ * @property {any[]} sources each bind's source
38
+ * @property {Float64Array} values each bind's value
39
+ * @property {Uint8Array} has whether each bind has one
40
+ * @property {number} version counts the changes of the bound values
41
+ * @property {number} done the version the static path was made for
42
+ * @property {LottiePath} path the path while no animation keys the skin
43
+ * @property {Record<string, Played | null>} played what an animation keys, by animation id
44
+ *
45
+ * @typedef {object} Played
46
+ * @property {number[]} at where in `rig.now` each track's value goes
47
+ * @property {number[][]} keys each track's `[frame, value, ...]`
48
+ * @property {Array<number[] | null>} segments each track's keying segments on a nested machine's stitched timeline, null outside one
49
+ * @property {LottiePath} path
50
+ * @property {number} frame the frame the path was made for
51
+ * @property {number} done the version of the bound values it was made for
52
+ * @property {any} poses the poses it was made for
53
+ * @property {(frame: number, poses?: Pose[] | null) => LottiePath} fn
54
+ *
55
+ * @typedef {{ start: number, frame: number, weight: number }} Pose a nested machine's animation playing: its segment's first frame, how far in it is, and its weight
56
+ *
57
+ * @typedef {object} Skins
58
+ * @property {number} count skins held
59
+ * @property {(read: (source: any) => any) => void} update reads every bound value; a skin whose values have not changed keeps its path
60
+ * @property {(animation?: string) => Record<string, any>} table by slot id, the value of each skin with a bound value, for the animation with that id
61
+ * @property {(read: (source: any) => any, animation?: string) => Record<string, any>} evaluate `update`, then `table`
62
+ * @property {(sid: string, animation: string) => any} keyedBy the skin's value in an animation that keys it, else undefined: a pose that does not key a skin leaves it alone
63
+ */
64
+
65
+ /**
66
+ * @param {Skin[] | undefined} list a bundle's `skins`
67
+ * @returns {Skins}
68
+ */
69
+ export function createSkins(list) {
70
+ /** @type {State[]} */
71
+ const states = []
72
+ for (let n = 0; n < (list || []).length; n++) states.push(makeState(/** @type {Skin[]} */ (list)[n]))
73
+ /** @type {Record<string, Record<string, any>>} */
74
+ const tables = {}
75
+
76
+ /** @param {string} [animation] */
77
+ function table(animation) {
78
+ const key = animation || ''
79
+ const found = tables[key] || (tables[key] = {})
80
+ for (let n = 0; n < states.length; n++) {
81
+ const state = states[n]
82
+ if (isBound(state)) found[state.skin.sid] = valueOf(state, key)
83
+ else delete found[state.skin.sid]
84
+ }
85
+ return found
86
+ }
87
+
88
+ /** @param {(source: any) => any} read */
89
+ function update(read) {
90
+ for (let n = 0; n < states.length; n++) read1(states[n], read)
91
+ }
92
+
93
+ /** @param {string} sid @param {string} animation */
94
+ function keyedBy(sid, animation) {
95
+ for (let n = 0; n < states.length; n++) {
96
+ const state = states[n]
97
+ const keys = state.skin.keys
98
+ if (state.skin.sid !== sid || !keys || !keys[animation] || !isBound(state)) continue
99
+ return valueOf(state, animation)
100
+ }
101
+ return undefined
102
+ }
103
+
104
+ return {
105
+ count: states.length,
106
+ update,
107
+ table,
108
+ keyedBy,
109
+ evaluate(read, animation) {
110
+ update(read)
111
+ return table(animation)
112
+ },
113
+ }
114
+ }
115
+
116
+ /**
117
+ * @param {Skin} skin
118
+ * @returns {State}
119
+ */
120
+ function makeState(skin) {
121
+ const rig = createRig(skin)
122
+ /** @type {number[]} */
123
+ const at = []
124
+ /** @type {any[]} */
125
+ const sources = []
126
+ /** @param {any[]} list @param {Record<string, number>} channels @param {number} first @param {number} width */
127
+ const collect = (list, channels, first, width) => {
128
+ for (let n = 0; n < list.length; n++) {
129
+ const binds = list[n].binds || {}
130
+ for (const name in binds) {
131
+ if (channels[name] === undefined || !binds[name] || !binds[name].source) continue
132
+ at.push(first + n * width + channels[name])
133
+ sources.push(binds[name].source)
134
+ }
135
+ }
136
+ }
137
+ collect(skin.bones, BONE_CHANNELS, 0, 6)
138
+ collect(skin.nodes || [], NODE_CHANNELS, rig.nodeAt, 5)
139
+ collect(skin.ik || [], IK_CHANNELS, rig.ikAt, 3)
140
+ return { skin, rig, at, sources, values: new Float64Array(at.length), has: new Uint8Array(at.length), version: 0, done: -1, path: createPath(skin), played: {} }
141
+ }
142
+
143
+ /**
144
+ * Reads what each bind holds now: a number, else nothing.
145
+ *
146
+ * @param {State} state
147
+ * @param {(source: any) => any} read
148
+ */
149
+ function read1(state, read) {
150
+ let changed = false
151
+ for (let n = 0; n < state.sources.length; n++) {
152
+ const value = read(state.sources[n])
153
+ const number = typeof value === 'number' ? value : parseFloat(value)
154
+ const has = isFinite(number) ? 1 : 0
155
+ if (has !== state.has[n] || (has && number !== state.values[n])) changed = true
156
+ state.has[n] = has
157
+ state.values[n] = has ? number : 0
158
+ }
159
+ if (changed) state.version++
160
+ }
161
+
162
+ /**
163
+ * Whether any of a skin's binds has a value: until one does the slot keeps the setup deform the bundle carries.
164
+ *
165
+ * @param {State} state
166
+ * @returns {boolean}
167
+ */
168
+ function isBound(state) {
169
+ for (let n = 0; n < state.has.length; n++) if (state.has[n]) return true
170
+ return false
171
+ }
172
+
173
+ /**
174
+ * The value of a bound skin's slot in an animation.
175
+ *
176
+ * @param {State} state
177
+ * @param {string} animation
178
+ * @returns {LottiePath | ((frame: number) => LottiePath)}
179
+ */
180
+ function valueOf(state, animation) {
181
+ let played = state.played[animation]
182
+ if (played === undefined) {
183
+ const all = state.skin.keys
184
+ const keys = (all && (all[animation] || all['*'])) || []
185
+ if (keys.length) {
186
+ const at = []
187
+ const k = []
188
+ const segments = []
189
+ for (let n = 0; n < keys.length; n++) {
190
+ at.push(channelAt(state.rig, keys[n]))
191
+ k.push(keys[n].k)
192
+ segments.push(keys[n].s || null)
193
+ }
194
+ /** @type {Played} */
195
+ const own = { at, keys: k, segments, path: createPath(state.skin), frame: NaN, done: -1, poses: null, fn: /** @type {any} */ (null) }
196
+ own.fn = (frame, given) => {
197
+ // a machine writes its poses as a new list each time they change
198
+ const poses = given || null
199
+ if (own.frame !== frame || own.done !== state.version || own.poses !== poses) {
200
+ own.frame = frame
201
+ own.done = state.version
202
+ own.poses = poses
203
+ setValues(state, own, frame, poses)
204
+ deformRig(state.rig, own.path)
205
+ }
206
+ return own.path
207
+ }
208
+ played = own
209
+ } else {
210
+ played = null
211
+ }
212
+ state.played[animation] = played
213
+ }
214
+ if (played) return played.fn
215
+
216
+ if (state.done !== state.version) {
217
+ state.done = state.version
218
+ setValues(state, null, 0, null)
219
+ deformRig(state.rig, state.path)
220
+ }
221
+ return state.path
222
+ }
223
+
224
+ /**
225
+ * The value a track moves, as an index into `rig.now`.
226
+ *
227
+ * @param {Rig} rig
228
+ * @param {{ o: string, i: number, c: string }} track
229
+ * @returns {number}
230
+ */
231
+ function channelAt(rig, track) {
232
+ if (track.o === 'n') return rig.nodeAt + track.i * 5 + NODE_CHANNELS[/** @type {keyof typeof NODE_CHANNELS} */ (track.c)]
233
+ if (track.o === 'v') return rig.vertexAt + track.i * 7 + VERTEX_CHANNELS[/** @type {keyof typeof VERTEX_CHANNELS} */ (track.c)]
234
+ return track.i * 6 + BONE_CHANNELS[/** @type {keyof typeof BONE_CHANNELS} */ (track.c)]
235
+ }
236
+
237
+ /**
238
+ * Puts the values a deform uses in `rig.now`: the setup, what the animation
239
+ * keys at the frame, mixed toward each pose that keys a track, then what
240
+ * binds hold.
241
+ *
242
+ * @param {State} state
243
+ * @param {Played | null} played
244
+ * @param {number} frame
245
+ * @param {Pose[] | null} poses
246
+ */
247
+ function setValues(state, played, frame, poses) {
248
+ const now = state.rig.now
249
+ now.set(state.rig.base)
250
+ if (played) {
251
+ for (let n = 0; n < played.at.length; n++) now[played.at[n]] = posedValue(played.keys[n], played.segments[n], frame, poses)
252
+ }
253
+ for (let n = 0; n < state.at.length; n++) if (state.has[n]) now[state.at[n]] = state.values[n]
254
+ }
255
+
256
+ /**
257
+ * A track's value in the poses whose segments key it, each counting as much
258
+ * as it does in the value Rive settles on (`settledWeight`); with none keying
259
+ * it, its value at the frame.
260
+ *
261
+ * @param {number[]} k
262
+ * @param {number[] | null} segments
263
+ * @param {number} frame
264
+ * @param {Pose[] | null} poses
265
+ * @returns {number}
266
+ */
267
+ function posedValue(k, segments, frame, poses) {
268
+ let value = valueAt(k, frame)
269
+ if (!poses || !segments) return value
270
+
271
+ let total = 0
272
+ for (let n = 0; n < poses.length; n++) {
273
+ const pose = poses[n]
274
+ const weight = segments.indexOf(pose.start) < 0 ? 0 : settledWeight(poses, n, segments)
275
+ if (weight <= 0) continue
276
+ total += weight
277
+ value += (valueAt(k, pose.start + pose.frame) - value) * (weight / total)
278
+ }
279
+ return value
280
+ }
281
+
282
+ /**
283
+ * A track's value at a frame: `[frame, value, ...]` blended linearly, held
284
+ * before the first and after the last.
285
+ *
286
+ * @param {number[]} k
287
+ * @param {number} frame
288
+ * @returns {number}
289
+ */
290
+ function valueAt(k, frame) {
291
+ if (frame <= k[0]) return k[1]
292
+ for (let n = 2; n < k.length; n += 2) {
293
+ if (frame > k[n]) continue
294
+ return k[n - 1] + (k[n + 1] - k[n - 1]) * ((frame - k[n - 2]) / (k[n] - k[n - 2]))
295
+ }
296
+ return k[k.length - 1]
297
+ }