@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,474 @@
1
+ /**
2
+ * Geometry: Lottie's shapes as cubic bezier paths, the affine maths that
3
+ * moves them between spaces, and trimming by length.
4
+ *
5
+ * A path keeps absolute control points, so a transform maps it exactly:
6
+ * `cOut[k]` follows point k, `cIn[k]` leads into it. Rectangles, ellipses and
7
+ * stars start and wind as lottie-web builds them, since a trim depends on both.
8
+ */
9
+
10
+ /** Bezier control distance for a quarter circle */
11
+ const KAPPA = 0.5519
12
+
13
+ /**
14
+ * @typedef {{ x: number, y: number }} Point
15
+ * @typedef {{ closed: boolean, points: Point[], cIn: Point[], cOut: Point[] }} Path
16
+ * @typedef {number[]} Matrix `[a, b, c, d, e, f]`, as canvas setTransform takes it
17
+ */
18
+
19
+ export const IDENTITY = [ 1, 0, 0, 1, 0, 0 ]
20
+
21
+ /**
22
+ * `left × right`: right applies first.
23
+ *
24
+ * @param {Matrix} left
25
+ * @param {Matrix} right
26
+ * @returns {Matrix}
27
+ */
28
+ export function multiply(left, right) {
29
+ return [
30
+ left[0] * right[0] + left[2] * right[1],
31
+ left[1] * right[0] + left[3] * right[1],
32
+ left[0] * right[2] + left[2] * right[3],
33
+ left[1] * right[2] + left[3] * right[3],
34
+ left[0] * right[4] + left[2] * right[5] + left[4],
35
+ left[1] * right[4] + left[3] * right[5] + left[5],
36
+ ]
37
+ }
38
+
39
+ /**
40
+ * @param {Matrix} m
41
+ * @param {number} x
42
+ * @param {number} y
43
+ * @returns {Point}
44
+ */
45
+ export function apply(m, x, y) {
46
+ return { x: m[0] * x + m[2] * y + m[4], y: m[1] * x + m[3] * y + m[5] }
47
+ }
48
+
49
+ /**
50
+ * A Lottie transform's matrix: anchor, scale, skew, rotation, then position,
51
+ * in lottie-web's order.
52
+ *
53
+ * @param {number[]} anchor
54
+ * @param {number[]} position
55
+ * @param {number[]} scale percent
56
+ * @param {number} rotation degrees, clockwise
57
+ * @param {number} skew degrees
58
+ * @param {number} skewAxis degrees
59
+ * @returns {Matrix}
60
+ */
61
+ export function transformMatrix(anchor, position, scale, rotation, skew, skewAxis) {
62
+ let m = [ 1, 0, 0, 1, -anchor[0], -anchor[1] ]
63
+ m = multiply([ scale[0] / 100, 0, 0, scale[1] / 100, 0, 0 ], m)
64
+ if (skew) {
65
+ const axis = (skewAxis * Math.PI) / 180
66
+ const shear = Math.tan((-skew * Math.PI) / 180)
67
+ const cos = Math.cos(axis)
68
+ const sin = Math.sin(axis)
69
+ m = multiply([ cos, -sin, sin, cos, 0, 0 ], m)
70
+ m = multiply([ 1, 0, shear, 1, 0, 0 ], m)
71
+ m = multiply([ cos, sin, -sin, cos, 0, 0 ], m)
72
+ }
73
+ if (rotation) {
74
+ const angle = (rotation * Math.PI) / 180
75
+ m = multiply([ Math.cos(angle), Math.sin(angle), -Math.sin(angle), Math.cos(angle), 0, 0 ], m)
76
+ }
77
+ return multiply([ 1, 0, 0, 1, position[0], position[1] ], m)
78
+ }
79
+
80
+ /**
81
+ * @param {Path} path
82
+ * @param {Matrix} m
83
+ * @returns {Path}
84
+ */
85
+ export function transformPath(path, m) {
86
+ const map = (/** @type {Point[]} */ list) => list.map((p) => apply(m, p.x, p.y))
87
+ return { closed: path.closed, points: map(path.points), cIn: map(path.cIn), cOut: map(path.cOut) }
88
+ }
89
+
90
+ /**
91
+ * Traces a path onto the context's current path.
92
+ *
93
+ * @param {CanvasRenderingContext2D} ctx
94
+ * @param {Path} path
95
+ */
96
+ export function trace(ctx, path) {
97
+ const { points, cIn, cOut } = path
98
+ if (!points.length) return
99
+
100
+ ctx.moveTo(points[0].x, points[0].y)
101
+ for (let k = 1; k < points.length; k++) segment(ctx, points[k - 1], cOut[k - 1], cIn[k], points[k])
102
+ if (path.closed) {
103
+ const last = points.length - 1
104
+ segment(ctx, points[last], cOut[last], cIn[0], points[0])
105
+ ctx.closePath()
106
+ }
107
+ }
108
+
109
+ /**
110
+ * One segment: a line where both handles sit on their points, as most of a
111
+ * Lottie's do, else the cubic. A line is far cheaper for the canvas to fill
112
+ * and stroke than a curve, and draws the same.
113
+ *
114
+ * @param {CanvasRenderingContext2D} ctx
115
+ * @param {Point} from
116
+ * @param {Point} out from's out handle
117
+ * @param {Point} into to's in handle
118
+ * @param {Point} to
119
+ */
120
+ function segment(ctx, from, out, into, to) {
121
+ const isStraight = out.x === from.x && out.y === from.y && into.x === to.x && into.y === to.y
122
+ if (isStraight) ctx.lineTo(to.x, to.y)
123
+ else ctx.bezierCurveTo(out.x, out.y, into.x, into.y, to.x, to.y)
124
+ }
125
+
126
+ // Shapes
127
+ // ■■■■■■
128
+
129
+ /**
130
+ * Lottie's own `{ v, i, o, c }`, tangents relative to their vertex.
131
+ *
132
+ * @param {any} shape
133
+ * @returns {Path}
134
+ */
135
+ export function fromLottie(shape) {
136
+ const points = []
137
+ const cIn = []
138
+ const cOut = []
139
+ const vertices = shape.v || []
140
+ for (let k = 0; k < vertices.length; k++) {
141
+ const v = vertices[k]
142
+ const i = (shape.i && shape.i[k]) || [ 0, 0 ]
143
+ const o = (shape.o && shape.o[k]) || [ 0, 0 ]
144
+ points.push({ x: v[0], y: v[1] })
145
+ cIn.push({ x: v[0] + i[0], y: v[1] + i[1] })
146
+ cOut.push({ x: v[0] + o[0], y: v[1] + o[1] })
147
+ }
148
+ return { closed: !!shape.c, points, cIn, cOut }
149
+ }
150
+
151
+ /**
152
+ * A rectangle centred on `position`, its corners rounded by `roundness`.
153
+ * Winds clockwise from the top right, or the other way when `reversed`.
154
+ *
155
+ * @param {number[]} position
156
+ * @param {number[]} size
157
+ * @param {number} roundness
158
+ * @param {boolean} reversed
159
+ * @returns {Path}
160
+ */
161
+ export function rectangle(position, size, roundness, reversed) {
162
+ const w = size[0] / 2
163
+ const h = size[1] / 2
164
+ const r = Math.min(roundness || 0, w, h)
165
+ const [ x, y ] = position
166
+ const c = r * (1 - KAPPA)
167
+
168
+ /** @type {[number, number, number, number, number, number][]} point, then in and out control offsets */
169
+ const corners = r
170
+ ? [
171
+ [ x + w, y - h + r, 0, -r + c, 0, 0 ],
172
+ [ x + w, y + h - r, 0, 0, 0, r - c ],
173
+ [ x + w - r, y + h, r - c, 0, 0, 0 ],
174
+ [ x - w + r, y + h, 0, 0, -(r - c), 0 ],
175
+ [ x - w, y + h - r, 0, r - c, 0, 0 ],
176
+ [ x - w, y - h + r, 0, 0, 0, -(r - c) ],
177
+ [ x - w + r, y - h, -(r - c), 0, 0, 0 ],
178
+ [ x + w - r, y - h, 0, 0, r - c, 0 ],
179
+ ]
180
+ : [ [ x + w, y - h, 0, 0, 0, 0 ], [ x + w, y + h, 0, 0, 0, 0 ], [ x - w, y + h, 0, 0, 0, 0 ], [ x - w, y - h, 0, 0, 0, 0 ] ]
181
+
182
+ const ordered = reversed ? reverseCorners(corners) : corners
183
+ return {
184
+ closed: true,
185
+ points: ordered.map((p) => ({ x: p[0], y: p[1] })),
186
+ cIn: ordered.map((p) => ({ x: p[0] + p[2], y: p[1] + p[3] })),
187
+ cOut: ordered.map((p) => ({ x: p[0] + p[4], y: p[1] + p[5] })),
188
+ }
189
+ }
190
+
191
+ /**
192
+ * The same corners the other way round: each point's in and out swap.
193
+ *
194
+ * @param {[number, number, number, number, number, number][]} corners
195
+ */
196
+ function reverseCorners(corners) {
197
+ const reversed = []
198
+ for (let k = corners.length - 1; k >= 0; k--) {
199
+ const p = corners[k]
200
+ reversed.push(/** @type {[number, number, number, number, number, number]} */ ([ p[0], p[1], p[4], p[5], p[2], p[3] ]))
201
+ }
202
+ return reversed
203
+ }
204
+
205
+ /**
206
+ * An ellipse centred on `position`, from its top, clockwise unless `reversed`.
207
+ *
208
+ * @param {number[]} position
209
+ * @param {number[]} size
210
+ * @param {boolean} reversed
211
+ * @returns {Path}
212
+ */
213
+ export function ellipse(position, size, reversed) {
214
+ const [ x, y ] = position
215
+ const rx = size[0] / 2
216
+ const ry = size[1] / 2
217
+ const kx = rx * KAPPA
218
+ const ky = ry * KAPPA
219
+ const direction = reversed ? -1 : 1
220
+
221
+ const points = [ { x, y: y - ry }, { x: x + direction * rx, y }, { x, y: y + ry }, { x: x - direction * rx, y } ]
222
+ const cIn = [ { x: x - direction * kx, y: y - ry }, { x: x + direction * rx, y: y - ky }, { x: x + direction * kx, y: y + ry }, { x: x - direction * rx, y: y + ky } ]
223
+ const cOut = [ { x: x + direction * kx, y: y - ry }, { x: x + direction * rx, y: y + ky }, { x: x - direction * kx, y: y + ry }, { x: x - direction * rx, y: y - ky } ]
224
+ return { closed: true, points, cIn, cOut }
225
+ }
226
+
227
+ /**
228
+ * A star (`sy` 1) or polygon (`sy` 2), as lottie-web builds them.
229
+ *
230
+ * @param {{ type: number, points: number, position: number[], rotation: number, outer: number, inner: number, outerRound: number, innerRound: number, reversed: boolean }} star
231
+ * @returns {Path}
232
+ */
233
+ export function star(star) {
234
+ const isStar = star.type === 1
235
+ const count = Math.floor(star.points) * (isStar ? 2 : 1)
236
+ const angleStep = (2 * Math.PI) / count
237
+ const direction = star.reversed ? -1 : 1
238
+ let angle = (star.rotation * Math.PI) / 180 - Math.PI / 2
239
+
240
+ const points = []
241
+ const cIn = []
242
+ const cOut = []
243
+ for (let k = 0; k < count; k++) {
244
+ const isOuter = !isStar || k % 2 === 0
245
+ const radius = isOuter ? star.outer : star.inner
246
+ const round = (isOuter ? star.outerRound : star.innerRound) / 100
247
+ const perimeter = (2 * Math.PI * radius) / (count * 2)
248
+ const x = star.position[0] + radius * Math.cos(angle)
249
+ const y = star.position[1] + radius * Math.sin(angle)
250
+ const tx = -Math.sin(angle) * perimeter * round * direction
251
+ const ty = Math.cos(angle) * perimeter * round * direction
252
+ points.push({ x, y })
253
+ cIn.push({ x: x - tx, y: y - ty })
254
+ cOut.push({ x: x + tx, y: y + ty })
255
+ angle += angleStep * direction
256
+ }
257
+ return { closed: true, points, cIn, cOut }
258
+ }
259
+
260
+ // Trimming
261
+ // ■■■■■■■■
262
+
263
+ /**
264
+ * The segments of a path, each as its four bezier points.
265
+ *
266
+ * @param {Path} path
267
+ * @returns {Point[][]}
268
+ */
269
+ function segments(path) {
270
+ const list = []
271
+ const { points, cIn, cOut } = path
272
+ for (let k = 1; k < points.length; k++) list.push([ points[k - 1], cOut[k - 1], cIn[k], points[k] ])
273
+ if (path.closed && points.length > 1) {
274
+ const last = points.length - 1
275
+ list.push([ points[last], cOut[last], cIn[0], points[0] ])
276
+ }
277
+ return list
278
+ }
279
+
280
+ /**
281
+ * @param {Point[]} s four bezier points
282
+ * @param {number} t
283
+ */
284
+ function pointAt(s, t) {
285
+ const u = 1 - t
286
+ return {
287
+ x: u * u * u * s[0].x + 3 * u * u * t * s[1].x + 3 * u * t * t * s[2].x + t * t * t * s[3].x,
288
+ y: u * u * u * s[0].y + 3 * u * u * t * s[1].y + 3 * u * t * t * s[2].y + t * t * t * s[3].y,
289
+ }
290
+ }
291
+
292
+ /** Samples per segment when measuring length */
293
+ const STEPS = 24
294
+
295
+ /**
296
+ * @param {Point[]} s
297
+ * @returns {number[]} cumulative length at each of STEPS + 1 samples
298
+ */
299
+ function lengths(s) {
300
+ const table = [ 0 ]
301
+ let previous = s[0]
302
+ for (let n = 1; n <= STEPS; n++) {
303
+ const point = pointAt(s, n / STEPS)
304
+ const dx = point.x - previous.x
305
+ const dy = point.y - previous.y
306
+ table.push(table[n - 1] + Math.sqrt(dx * dx + dy * dy))
307
+ previous = point
308
+ }
309
+ return table
310
+ }
311
+
312
+ /**
313
+ * The bezier parameter at a distance along a segment.
314
+ *
315
+ * @param {number[]} table from lengths()
316
+ * @param {number} distance
317
+ */
318
+ function parameterAt(table, distance) {
319
+ const total = table[table.length - 1]
320
+ if (distance <= 0 || total === 0) return 0
321
+ if (distance >= total) return 1
322
+
323
+ for (let n = 1; n < table.length; n++) {
324
+ if (table[n] >= distance) {
325
+ const span = table[n] - table[n - 1]
326
+ const within = span > 0 ? (distance - table[n - 1]) / span : 0
327
+ return (n - 1 + within) / STEPS
328
+ }
329
+ }
330
+ return 1
331
+ }
332
+
333
+ /**
334
+ * The part of a segment between two parameters, by de Casteljau.
335
+ *
336
+ * @param {Point[]} s
337
+ * @param {number} t0
338
+ * @param {number} t1
339
+ * @returns {Point[]}
340
+ */
341
+ function subSegment(s, t0, t1) {
342
+ const split = (/** @type {Point[]} */ q, /** @type {number} */ t) => {
343
+ const mix = (/** @type {Point} */ a, /** @type {Point} */ b) => ({ x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t })
344
+ const ab = mix(q[0], q[1])
345
+ const bc = mix(q[1], q[2])
346
+ const cd = mix(q[2], q[3])
347
+ const abc = mix(ab, bc)
348
+ const bcd = mix(bc, cd)
349
+ const mid = mix(abc, bcd)
350
+ return { before: [ q[0], ab, abc, mid ], after: [ mid, bcd, cd, q[3] ] }
351
+ }
352
+ const tail = split(s, t0).after
353
+ const span = t0 < 1 ? (t1 - t0) / (1 - t0) : 0
354
+ return split(tail, Math.min(1, Math.max(0, span))).before
355
+ }
356
+
357
+ /**
358
+ * The stretch of a path between two distances along it, as an open path.
359
+ *
360
+ * @param {Point[][]} list the path's segments
361
+ * @param {number[][]} tables each segment's lengths()
362
+ * @param {number} from
363
+ * @param {number} to
364
+ * @returns {Path | null}
365
+ */
366
+ function between(list, tables, from, to) {
367
+ /** @type {Path} */
368
+ const path = { closed: false, points: [], cIn: [], cOut: [] }
369
+ let offset = 0
370
+ for (let n = 0; n < list.length; n++) {
371
+ const length = tables[n][tables[n].length - 1]
372
+ const start = Math.max(from, offset)
373
+ const end = Math.min(to, offset + length)
374
+ if (end > start || (length === 0 && start === offset && start <= to && start >= from)) {
375
+ const piece = subSegment(list[n], parameterAt(tables[n], start - offset), parameterAt(tables[n], end - offset))
376
+ if (!path.points.length) {
377
+ path.points.push(piece[0])
378
+ path.cIn.push(piece[0])
379
+ }
380
+ path.cOut[path.points.length - 1] = piece[1]
381
+ path.points.push(piece[3])
382
+ path.cIn.push(piece[2])
383
+ path.cOut.push(piece[3])
384
+ }
385
+ offset += length
386
+ }
387
+ return path.points.length > 1 ? path : null
388
+ }
389
+
390
+ /**
391
+ * Trim Paths: the part of each path between `start` and `end`, percent of its
392
+ * length, shifted by `offset` degrees (360 is the whole length). `together`
393
+ * (`m` 2) treats every path as one, in order; otherwise each is trimmed alone.
394
+ *
395
+ * @param {Path[]} paths
396
+ * @param {number} start
397
+ * @param {number} end
398
+ * @param {number} offset
399
+ * @param {boolean} together
400
+ * @returns {Path[][]} what each path keeps, in the same order
401
+ */
402
+ export function trimEach(paths, start, end, offset, together) {
403
+ let s = Math.min(start, end) / 100
404
+ let e = Math.max(start, end) / 100
405
+ if (e - s >= 1) return paths.map((path) => [ path ])
406
+ if (e === s) return paths.map(() => [])
407
+
408
+ const shift = (offset % 360) / 360
409
+ s += shift
410
+ e += shift
411
+ // the range may run past the end and wrap round to the start
412
+ const ranges = s >= 1 || s < 0 ? wrapRanges(s, e) : e > 1 ? [ [ s, 1 ], [ 0, e - 1 ] ] : [ [ s, e ] ]
413
+
414
+ const measured = paths.map((path) => {
415
+ const list = segments(path)
416
+ const tables = list.map(lengths)
417
+ let total = 0
418
+ for (let n = 0; n < tables.length; n++) total += tables[n][tables[n].length - 1]
419
+ return { list, tables, total }
420
+ })
421
+
422
+ let combined = 0
423
+ for (let n = 0; n < measured.length; n++) combined += measured[n].total
424
+
425
+ const kept = []
426
+ let before = 0
427
+ for (let n = 0; n < measured.length; n++) {
428
+ const m = measured[n]
429
+ // alone, a path's range is its own length; together, a share of the combined one
430
+ const scale = together ? combined : m.total
431
+ const origin = together ? before : 0
432
+ const pieces = []
433
+ for (let r = 0; r < ranges.length; r++) {
434
+ const from = ranges[r][0] * scale - origin
435
+ const to = ranges[r][1] * scale - origin
436
+ if (to <= 0 || from >= m.total) continue
437
+ const piece = between(m.list, m.tables, Math.max(0, from), Math.min(m.total, to))
438
+ if (piece) pieces.push(piece)
439
+ }
440
+ kept.push(pieces)
441
+ before += m.total
442
+ }
443
+ return kept
444
+ }
445
+
446
+ /**
447
+ * The same trim, every path's pieces in one list.
448
+ *
449
+ * @param {Path[]} paths
450
+ * @param {number} start
451
+ * @param {number} end
452
+ * @param {number} offset
453
+ * @param {boolean} together
454
+ * @returns {Path[]}
455
+ */
456
+ export function trim(paths, start, end, offset, together) {
457
+ const kept = trimEach(paths, start, end, offset, together)
458
+ const flat = []
459
+ for (let n = 0; n < kept.length; n++) for (let k = 0; k < kept[n].length; k++) flat.push(kept[n][k])
460
+ return flat
461
+ }
462
+
463
+ /**
464
+ * A range shifted wholly outside 0-1, folded back into it.
465
+ *
466
+ * @param {number} s
467
+ * @param {number} e
468
+ */
469
+ function wrapRanges(s, e) {
470
+ const shift = Math.floor(s)
471
+ const a = s - shift
472
+ const b = e - shift
473
+ return b > 1 ? [ [ a, 1 ], [ 0, b - 1 ] ] : [ [ a, b ] ]
474
+ }