@px-petals/roku.motion-web 0.0.0-stage → 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 (99) hide show
  1. package/LICENSE +201 -0
  2. package/audio/audio.cues.js +27 -0
  3. package/audio/audio.js +259 -0
  4. package/bands/bands.js +392 -0
  5. package/bundle/bundle.fonts.js +55 -0
  6. package/bundle/bundle.js +131 -0
  7. package/focus/focus.direction.js +46 -0
  8. package/focus/focus.dom.js +158 -0
  9. package/focus/focus.js +277 -0
  10. package/focus/focus.tree.js +146 -0
  11. package/hit/hit.geometry.js +113 -0
  12. package/hit/hit.js +129 -0
  13. package/list/list.flex.js +181 -0
  14. package/list/list.items.js +80 -0
  15. package/list/list.js +518 -0
  16. package/lottie/lottie.js +124 -0
  17. package/lottie/lottie.layers.js +416 -0
  18. package/lottie/lottie.paint.js +238 -0
  19. package/lottie/lottie.paths.js +474 -0
  20. package/lottie/lottie.props.js +265 -0
  21. package/lottie/lottie.shapes.js +259 -0
  22. package/mixer/mixer.js +307 -0
  23. package/mixer/mixer.mix.js +107 -0
  24. package/mixer/mixer.stage.js +431 -0
  25. package/motion/motion.convert.js +404 -0
  26. package/motion/motion.flow.js +421 -0
  27. package/motion/motion.keys.js +150 -0
  28. package/motion/motion.machine.js +382 -0
  29. package/motion/motion.nested.js +345 -0
  30. package/motion/motion.values.js +368 -0
  31. package/motion.js +1155 -0
  32. package/package.json +47 -4
  33. package/player/overlay/overlay.js +325 -0
  34. package/player/overlay/overlay.layout.js +208 -0
  35. package/player/player.fit.js +101 -0
  36. package/player/player.js +421 -0
  37. package/player/player.raster.js +127 -0
  38. package/pointer/pointer.js +292 -0
  39. package/readme.md +345 -0
  40. package/script/luau/lib/base/base.js +202 -0
  41. package/script/luau/lib/base/base.table.js +189 -0
  42. package/script/luau/lib/lib.args.js +152 -0
  43. package/script/luau/lib/lib.js +23 -0
  44. package/script/luau/lib/math/math.bit32.js +144 -0
  45. package/script/luau/lib/math/math.js +288 -0
  46. package/script/luau/lib/math/math.vector.js +125 -0
  47. package/script/luau/lib/string/string.format.js +143 -0
  48. package/script/luau/lib/string/string.js +160 -0
  49. package/script/luau/lib/string/string.pattern.js +505 -0
  50. package/script/luau/load/load.js +362 -0
  51. package/script/luau/load/load.ops.js +79 -0
  52. package/script/luau/luau.convert.js +259 -0
  53. package/script/luau/luau.js +132 -0
  54. package/script/luau/luau.md +111 -0
  55. package/script/luau/vm/vm.js +167 -0
  56. package/script/luau/vm/vm.meta.js +401 -0
  57. package/script/luau/vm/vm.num.js +236 -0
  58. package/script/luau/vm/vm.run.js +842 -0
  59. package/script/luau/vm/vm.value.js +406 -0
  60. package/script/play/play.js +199 -0
  61. package/script/play/play.objects.js +295 -0
  62. package/script/play/play.scope.js +91 -0
  63. package/script/rive/api/api.statics.js +31 -0
  64. package/script/rive/api/api.type.js +188 -0
  65. package/script/rive/api/artboard/artboard.js +89 -0
  66. package/script/rive/api/assets/assets.js +72 -0
  67. package/script/rive/api/data/data.value.js +99 -0
  68. package/script/rive/api/draw/draw.contours.js +163 -0
  69. package/script/rive/api/draw/draw.measure.js +196 -0
  70. package/script/rive/api/draw/draw.paint.js +235 -0
  71. package/script/rive/api/draw/draw.path.js +153 -0
  72. package/script/rive/api/draw/draw.renderer.js +117 -0
  73. package/script/rive/api/math/math.color.js +96 -0
  74. package/script/rive/api/math/math.mat2d.js +180 -0
  75. package/script/rive/api/math/math.vector.js +121 -0
  76. package/script/rive/api/media/media.audio.js +113 -0
  77. package/script/rive/api/media/media.draw.js +73 -0
  78. package/script/rive/api/media/media.image.js +61 -0
  79. package/script/rive/api/media/media.mesh.js +50 -0
  80. package/script/rive/api/pointer/pointer.event.js +64 -0
  81. package/script/rive/api/pointer/pointer.route.js +69 -0
  82. package/script/rive/api/text/text.font.js +129 -0
  83. package/script/rive/api/text/text.js +278 -0
  84. package/script/rive/api/text/text.layout.js +259 -0
  85. package/script/rive/context/context.js +76 -0
  86. package/script/rive/context/context.memory.js +196 -0
  87. package/script/rive/context/context.viewmodel.js +302 -0
  88. package/script/rive/context/lists/lists.js +160 -0
  89. package/script/rive/context/lists/lists.values.js +281 -0
  90. package/script/rive/host/host.globals.js +44 -0
  91. package/script/rive/host/host.js +533 -0
  92. package/script/rive/host/host.node.js +45 -0
  93. package/script/rive/rive.js +23 -0
  94. package/script/rive/rive.md +180 -0
  95. package/script/script.js +11 -0
  96. package/skin/skin.deform.js +514 -0
  97. package/skin/skin.ik.js +260 -0
  98. package/skin/skin.js +297 -0
  99. package/README.md +0 -3
@@ -0,0 +1,404 @@
1
+ /**
2
+ * Data converters: the declarative descriptors a bundle's `data.slots` carry
3
+ * on a source (rive2lottie writes them, dotlottie.converters.js lists them),
4
+ * applied to a view-model value on its way to a slot, and reversed for a bind
5
+ * that writes back. A descriptor type this code does not know warns once and
6
+ * passes the value through.
7
+ *
8
+ * The same arithmetic runs at build time for the default instance
9
+ * (dotlottie.convert.js in the converter) and on Roku (bundle.convert.bs).
10
+ */
11
+
12
+ /**
13
+ * @typedef {object} ConvertContext
14
+ * @property {(path: string) => any} [read] a view-model property's value, by dotted path
15
+ * @property {string[]} [names] the names of an enum the value indexes
16
+ * @property {(message: string) => void} [warn]
17
+ * @property {import('../script/play/play.js').Scripts} [scripts] runs the bundle's script converters
18
+ * @property {string} [type] the bound property's type, so a script is given a colour as one
19
+ * @property {Record<string, any>} [values] every live value, which a script can read
20
+ */
21
+
22
+ /**
23
+ * Operations of an `operation` descriptor and a formula, by name.
24
+ * @type {Record<string, (a: number, b: number) => number>}
25
+ */
26
+ const OPERATIONS = {
27
+ add: (a, b) => a + b,
28
+ sub: (a, b) => a - b,
29
+ mul: (a, b) => a * b,
30
+ div: (a, b) => (b === 0 ? 0 : a / b),
31
+ mod: (a, b) => (b === 0 ? 0 : a % b),
32
+ sqrt: (a) => Math.sqrt(a),
33
+ pow: (a, b) => Math.pow(a, b),
34
+ exp: (a) => Math.exp(a),
35
+ log: (a) => Math.log(a),
36
+ cos: (a) => Math.cos(a),
37
+ sin: (a) => Math.sin(a),
38
+ tan: (a) => Math.tan(a),
39
+ acos: (a) => Math.acos(a),
40
+ asin: (a) => Math.asin(a),
41
+ atan: (a) => Math.atan(a),
42
+ atan2: (a, b) => Math.atan2(a, b),
43
+ round: (a) => Math.round(a),
44
+ floor: (a) => Math.floor(a),
45
+ ceil: (a) => Math.ceil(a),
46
+ }
47
+
48
+ /**
49
+ * Formula functions: the arguments are a list.
50
+ * @type {Record<string, (args: number[]) => number>}
51
+ */
52
+ const FUNCTIONS = {
53
+ min: (args) => Math.min.apply(Math, args),
54
+ max: (args) => Math.max.apply(Math, args),
55
+ round: (args) => Math.round(args[0]),
56
+ ceil: (args) => Math.ceil(args[0]),
57
+ floor: (args) => Math.floor(args[0]),
58
+ sqrt: (args) => Math.sqrt(args[0]),
59
+ pow: (args) => Math.pow(args[0], args[1]),
60
+ exp: (args) => Math.exp(args[0]),
61
+ log: (args) => Math.log(args[0]),
62
+ cos: (args) => Math.cos(args[0]),
63
+ sin: (args) => Math.sin(args[0]),
64
+ tan: (args) => Math.tan(args[0]),
65
+ acos: (args) => Math.acos(args[0]),
66
+ asin: (args) => Math.asin(args[0]),
67
+ atan: (args) => Math.atan(args[0]),
68
+ atan2: (args) => Math.atan2(args[0], args[1]),
69
+ random: () => Math.random(),
70
+ }
71
+
72
+ /**
73
+ * Binding strength of a formula's operation tokens: the rest bind tightest.
74
+ * @type {Record<string, number>}
75
+ */
76
+ const PRECEDENCE = { add: 1, sub: 1, mul: 2, div: 2, mod: 2 }
77
+
78
+ /**
79
+ * Unknown descriptor types already warned about
80
+ * @type {Record<string, boolean>}
81
+ */
82
+ const warned = {}
83
+
84
+ /**
85
+ * Whether a value is a number the converters can work on.
86
+ * @param {any} value
87
+ */
88
+ function numeric(value) {
89
+ const n = typeof value === 'number' ? value : parseFloat(value)
90
+ return isFinite(n) ? n : 0
91
+ }
92
+
93
+ /**
94
+ * Applies a descriptor to a view-model value.
95
+ *
96
+ * @param {any} descriptor
97
+ * @param {any} value
98
+ * @param {ConvertContext} [context]
99
+ * @returns {any}
100
+ */
101
+ export function applyConverter(descriptor, value, context) {
102
+ const ctx = context || {}
103
+ switch (descriptor && descriptor.type) {
104
+ case 'negate':
105
+ return !value
106
+ case 'range':
107
+ return range(descriptor, numeric(value))
108
+ case 'round':
109
+ return roundTo(numeric(value), descriptor.decimals)
110
+ case 'operation':
111
+ return operate(descriptor.op, numeric(value), operand(descriptor, ctx))
112
+ case 'formula':
113
+ return formula(descriptor.tokens || [], numeric(value), ctx)
114
+ case 'toString':
115
+ return toText(descriptor, value, ctx)
116
+ case 'toNumber':
117
+ return numeric(value)
118
+ case 'pad':
119
+ return pad(descriptor, String(value === undefined || value === null ? '' : value))
120
+ case 'trim': {
121
+ let text = String(value === undefined || value === null ? '' : value)
122
+ if (descriptor.trimStart) text = text.replace(/^\s+/, '')
123
+ if (descriptor.trimEnd) text = text.replace(/\s+$/, '')
124
+ return text
125
+ }
126
+ case 'removeZeros':
127
+ return trimZeros(String(value === undefined || value === null ? '' : value))
128
+ case 'enumToUint':
129
+ return enumIndex(value, ctx.names)
130
+ case 'listLength':
131
+ return Array.isArray(value) ? value.length : 0
132
+ case 'solo':
133
+ return soloVisibility(descriptor, value)
134
+ case 'group': {
135
+ let result = value
136
+ const items = descriptor.items || []
137
+ // only the first link sees the enum names
138
+ for (let n = 0; n < items.length; n++) result = applyConverter(items[n], result, n === 0 ? ctx : { read: ctx.read, warn: ctx.warn, scripts: ctx.scripts, values: ctx.values })
139
+ return result
140
+ }
141
+ case 'script':
142
+ // run by the bundle's script host; without one the value passes through
143
+ if (ctx.scripts) return ctx.scripts.convert(descriptor, value, false, ctx.type === 'color' ? 'color' : undefined, ctx.values)
144
+ warnUnknown(descriptor, ctx)
145
+ return value
146
+ default:
147
+ warnUnknown(descriptor, ctx)
148
+ return value
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Undoes a descriptor for a bind that writes a property back into the view
154
+ * model. What cannot be undone (a formula, a rounding) passes the value on.
155
+ *
156
+ * @param {any} descriptor
157
+ * @param {any} value the target property's value
158
+ * @param {ConvertContext} [context]
159
+ * @returns {any}
160
+ */
161
+ export function reverseConverter(descriptor, value, context) {
162
+ const ctx = context || {}
163
+ switch (descriptor && descriptor.type) {
164
+ case 'negate':
165
+ return !value
166
+ case 'range':
167
+ return unrange(descriptor, numeric(value))
168
+ case 'operation': {
169
+ /** @type {Record<string, string>} */
170
+ const inverses = { add: 'sub', sub: 'add', mul: 'div', div: 'mul' }
171
+ const inverse = inverses[descriptor.op]
172
+ return inverse ? operate(inverse, numeric(value), operand(descriptor, ctx)) : value
173
+ }
174
+ case 'toString':
175
+ return numeric(value)
176
+ case 'toNumber':
177
+ return String(value)
178
+ case 'group': {
179
+ let result = value
180
+ const items = descriptor.items || []
181
+ for (let n = items.length - 1; n >= 0; n--) result = reverseConverter(items[n], result, ctx)
182
+ return result
183
+ }
184
+ case 'script':
185
+ return ctx.scripts ? ctx.scripts.convert(descriptor, value, true) : value
186
+ default:
187
+ return value
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Applies descriptors in order.
193
+ *
194
+ * @param {any} descriptor a descriptor, or null for none
195
+ * @param {any} value
196
+ * @param {ConvertContext} [context]
197
+ */
198
+ export function convertValue(descriptor, value, context) {
199
+ return descriptor ? applyConverter(descriptor, value, context) : value
200
+ }
201
+
202
+ /**
203
+ * @param {any} descriptor
204
+ * @param {ConvertContext} ctx
205
+ */
206
+ function warnUnknown(descriptor, ctx) {
207
+ const type = descriptor && descriptor.type
208
+ if (warned[type] || !ctx.warn) return
209
+ warned[type] = true
210
+ ctx.warn("data converter '" + type + "' is not known to this player; its value passes through")
211
+ }
212
+
213
+ /**
214
+ * The right-hand side of an operation: a literal, or another property's value.
215
+ *
216
+ * @param {any} descriptor
217
+ * @param {ConvertContext} ctx
218
+ */
219
+ function operand(descriptor, ctx) {
220
+ if (typeof descriptor.path === 'string') return numeric(ctx.read ? ctx.read(descriptor.path) : 0)
221
+ return numeric(descriptor.value)
222
+ }
223
+
224
+ /**
225
+ * @param {string} op
226
+ * @param {number} a
227
+ * @param {number} b
228
+ */
229
+ function operate(op, a, b) {
230
+ const fn = OPERATIONS[op]
231
+ return fn ? fn(a, b) : a
232
+ }
233
+
234
+ /**
235
+ * @param {number} value
236
+ * @param {number} decimals
237
+ */
238
+ function roundTo(value, decimals) {
239
+ const scale = Math.pow(10, decimals || 0)
240
+ return Math.round(value * scale) / scale
241
+ }
242
+
243
+ /**
244
+ * A range mapper: the input's position in its range, placed in the output's.
245
+ *
246
+ * @param {any} d
247
+ * @param {number} input
248
+ */
249
+ function range(d, input) {
250
+ const low = Math.min(d.minInput, d.maxInput)
251
+ const high = Math.max(d.minInput, d.maxInput)
252
+ let x = input
253
+ if (d.modulo && high > low) x = low + ((((x - low) % (high - low)) + (high - low)) % (high - low))
254
+ if (d.clampLower && x < low) x = low
255
+ if (d.clampUpper && x > high) x = high
256
+
257
+ const span = d.maxInput - d.minInput
258
+ let t = span === 0 ? 0 : (x - d.minInput) / span
259
+ if (d.hold) t = t >= 1 ? 1 : 0
260
+ if (d.reverse) t = 1 - t
261
+ return d.minOutput + t * (d.maxOutput - d.minOutput)
262
+ }
263
+
264
+ /**
265
+ * @param {any} d
266
+ * @param {number} output
267
+ */
268
+ function unrange(d, output) {
269
+ const span = d.maxOutput - d.minOutput
270
+ let t = span === 0 ? 0 : (output - d.minOutput) / span
271
+ if (d.reverse) t = 1 - t
272
+ let x = d.minInput + t * (d.maxInput - d.minInput)
273
+ const low = Math.min(d.minInput, d.maxInput)
274
+ const high = Math.max(d.minInput, d.maxInput)
275
+ if (d.clampLower && x < low) x = low
276
+ if (d.clampUpper && x > high) x = high
277
+ return x
278
+ }
279
+
280
+ /**
281
+ * A formula's tokens read as an infix expression.
282
+ *
283
+ * @param {any[]} tokens
284
+ * @param {number} input
285
+ * @param {ConvertContext} ctx
286
+ */
287
+ function formula(tokens, input, ctx) {
288
+ let at = 0
289
+
290
+ /** @param {number} minimum */
291
+ function expression(minimum) {
292
+ /** @type {number} */
293
+ let left = operandOf()
294
+ while (at < tokens.length && tokens[at].token === 'op') {
295
+ const op = tokens[at].op
296
+ const strength = PRECEDENCE[op] || 3
297
+ if (strength < minimum) break
298
+ at++
299
+ left = operate(op, left, expression(strength + 1))
300
+ }
301
+ return left
302
+ }
303
+
304
+ /** @returns {number} */
305
+ function operandOf() {
306
+ const token = tokens[at++]
307
+ if (!token) return 0
308
+ if (token.token === 'input') return input
309
+ if (token.token === 'value') return typeof token.path === 'string' ? numeric(ctx.read ? ctx.read(token.path) : 0) : numeric(token.value)
310
+ if (token.token === 'open') {
311
+ /** @type {number} */
312
+ const inner = expression(0)
313
+ if (at < tokens.length && tokens[at].token === 'close') at++
314
+ return inner
315
+ }
316
+ if (token.token === 'op' && token.op === 'sub') return -operandOf()
317
+ if (token.token === 'fn') {
318
+ const args = []
319
+ while (at < tokens.length && tokens[at].token !== 'close') {
320
+ args.push(expression(0))
321
+ if (at < tokens.length && tokens[at].token === 'sep') at++
322
+ }
323
+ at++
324
+ const fn = FUNCTIONS[token.fn]
325
+ return fn ? fn(args) : 0
326
+ }
327
+ return 0
328
+ }
329
+
330
+ const result = expression(0)
331
+ return isFinite(result) ? result : 0
332
+ }
333
+
334
+ /**
335
+ * ToString: a number to text at the converter's precision, a colour to hex,
336
+ * an enum index to its name.
337
+ *
338
+ * @param {any} d
339
+ * @param {any} value
340
+ * @param {ConvertContext} ctx
341
+ */
342
+ function toText(d, value, ctx) {
343
+ if (typeof value === 'boolean') return value ? 'true' : 'false'
344
+ if (typeof value === 'string') return value
345
+ if (ctx.names && typeof value === 'number' && ctx.names[value] !== undefined) return ctx.names[value]
346
+ if (typeof value !== 'number') return value === undefined || value === null ? '' : String(value)
347
+
348
+ // Rive holds numbers as 32-bit floats, which rounds 25.55 to 25.5499992
349
+ const single = Math.fround ? Math.fround(value) : value
350
+ let text = d.round ? single.toFixed(d.decimals || 0) : single.toFixed(6)
351
+ if (d.trimZeros) text = trimZeros(text)
352
+ return text
353
+ }
354
+
355
+ /** @param {string} text */
356
+ function trimZeros(text) {
357
+ return text.indexOf('.') < 0 ? text : text.replace(/0+$/, '').replace(/\.$/, '')
358
+ }
359
+
360
+ /**
361
+ * @param {any} d
362
+ * @param {string} text
363
+ */
364
+ function pad(d, text) {
365
+ const filler = String(d.text || '')
366
+ if (!filler) return text
367
+ const wanted = Math.max(d.length, text.length)
368
+ let result = text
369
+ while (result.length < wanted) result = d.atEnd ? result + filler : filler + result
370
+ return d.atEnd ? result.slice(0, wanted) : result.slice(result.length - wanted)
371
+ }
372
+
373
+ /**
374
+ * A Solo option's visibility, in percent: 100 when the bound value names it,
375
+ * 0 otherwise. A number names an option by its place among the Solo's options
376
+ * (`index`), an enum or a string by name (`names`, the ones that pick the
377
+ * option; an enum's value is its index, which `ids` lists). A descriptor with
378
+ * neither is an option no value reaches.
379
+ *
380
+ * @param {any} d
381
+ * @param {any} value
382
+ */
383
+ function soloVisibility(d, value) {
384
+ if (Array.isArray(d.names)) {
385
+ if (typeof value === 'string') return d.names.indexOf(value) >= 0 ? 100 : 0
386
+ return Array.isArray(d.ids) && typeof value === 'number' && d.ids.indexOf(value) >= 0 ? 100 : 0
387
+ }
388
+ if (typeof d.index === 'number') return Math.round(numeric(value)) === d.index ? 100 : 0
389
+ return 0
390
+ }
391
+
392
+ /**
393
+ * An enum value as its index, from an index or a name.
394
+ *
395
+ * @param {any} value
396
+ * @param {string[]} [names]
397
+ */
398
+ function enumIndex(value, names) {
399
+ if (typeof value === 'string' && names) {
400
+ const at = names.indexOf(value)
401
+ if (at >= 0) return at
402
+ }
403
+ return numeric(value)
404
+ }