(tweens: SurfacedTween[])
| 527 | // (not drawn). Only targets with ≥2 strokes become a composited trace; a single |
| 528 | // stroke stays on the normal per-tween path so existing output is unchanged. |
| 529 | function groupTraces(tweens: SurfacedTween[]): SurfacedTrace[] { |
| 530 | const byTarget = new Map<string, SurfacedTween[]>(); |
| 531 | for (const t of tweens) { |
| 532 | if (t.method === "set") continue; |
| 533 | if (!t.path || t.path.length < 2) continue; |
| 534 | if (!pathTravels(t.path)) continue; // in-place tween (e.g. opacity carrying a static y) is not a drawn stroke |
| 535 | const list = byTarget.get(t.target); |
| 536 | if (list) list.push(t); |
| 537 | else byTarget.set(t.target, [t]); |
| 538 | } |
| 539 | const traces: SurfacedTrace[] = []; |
| 540 | for (const [target, list] of byTarget) { |
| 541 | if (list.length < 2) continue; |
| 542 | const strokes = [...list] |
| 543 | .sort((a, b) => a.start - b.start) |
| 544 | .map((t) => ({ |
| 545 | id: t.id, |
| 546 | start: t.start, |
| 547 | end: t.end, |
| 548 | keyframes: t.keyframes, |
| 549 | points: t.path!, |
| 550 | })); |
| 551 | traces.push({ target, strokes }); |
| 552 | } |
| 553 | return traces; |
| 554 | } |
| 555 | |
| 556 | function collectCompositions(indexPath: string): SurfacedComposition[] { |
| 557 | const html = readFileSync(indexPath, "utf-8"); |
no test coverage detected