@clipkit/runtime 1.0.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 (219) hide show
  1. package/LICENSE +54 -0
  2. package/README.md +98 -0
  3. package/dist/animation/easings.d.ts +9 -0
  4. package/dist/animation/easings.d.ts.map +1 -0
  5. package/dist/animation/easings.js +230 -0
  6. package/dist/animation/easings.js.map +1 -0
  7. package/dist/animation/expr.d.ts +44 -0
  8. package/dist/animation/expr.d.ts.map +1 -0
  9. package/dist/animation/expr.js +236 -0
  10. package/dist/animation/expr.js.map +1 -0
  11. package/dist/animation/keyframes.d.ts +23 -0
  12. package/dist/animation/keyframes.d.ts.map +1 -0
  13. package/dist/animation/keyframes.js +117 -0
  14. package/dist/animation/keyframes.js.map +1 -0
  15. package/dist/animation/motion-path.d.ts +18 -0
  16. package/dist/animation/motion-path.d.ts.map +1 -0
  17. package/dist/animation/motion-path.js +269 -0
  18. package/dist/animation/motion-path.js.map +1 -0
  19. package/dist/animation/noise1d.d.ts +5 -0
  20. package/dist/animation/noise1d.d.ts.map +1 -0
  21. package/dist/animation/noise1d.js +27 -0
  22. package/dist/animation/noise1d.js.map +1 -0
  23. package/dist/animation/presets.d.ts +60 -0
  24. package/dist/animation/presets.d.ts.map +1 -0
  25. package/dist/animation/presets.js +221 -0
  26. package/dist/animation/presets.js.map +1 -0
  27. package/dist/assets/cache.d.ts +18 -0
  28. package/dist/assets/cache.d.ts.map +1 -0
  29. package/dist/assets/cache.js +56 -0
  30. package/dist/assets/cache.js.map +1 -0
  31. package/dist/assets/fonts.d.ts +20 -0
  32. package/dist/assets/fonts.d.ts.map +1 -0
  33. package/dist/assets/fonts.js +127 -0
  34. package/dist/assets/fonts.js.map +1 -0
  35. package/dist/assets/loader.d.ts +18 -0
  36. package/dist/assets/loader.d.ts.map +1 -0
  37. package/dist/assets/loader.js +87 -0
  38. package/dist/assets/loader.js.map +1 -0
  39. package/dist/assets/lut.d.ts +5 -0
  40. package/dist/assets/lut.d.ts.map +1 -0
  41. package/dist/assets/lut.js +77 -0
  42. package/dist/assets/lut.js.map +1 -0
  43. package/dist/assets/media-time.d.ts +31 -0
  44. package/dist/assets/media-time.d.ts.map +1 -0
  45. package/dist/assets/media-time.js +65 -0
  46. package/dist/assets/media-time.js.map +1 -0
  47. package/dist/assets/mp4-frame-source.d.ts +44 -0
  48. package/dist/assets/mp4-frame-source.d.ts.map +1 -0
  49. package/dist/assets/mp4-frame-source.js +387 -0
  50. package/dist/assets/mp4-frame-source.js.map +1 -0
  51. package/dist/audio/encoder.d.ts +31 -0
  52. package/dist/audio/encoder.d.ts.map +1 -0
  53. package/dist/audio/encoder.js +96 -0
  54. package/dist/audio/encoder.js.map +1 -0
  55. package/dist/audio/fades.d.ts +16 -0
  56. package/dist/audio/fades.d.ts.map +1 -0
  57. package/dist/audio/fades.js +43 -0
  58. package/dist/audio/fades.js.map +1 -0
  59. package/dist/audio/limiter.d.ts +8 -0
  60. package/dist/audio/limiter.d.ts.map +1 -0
  61. package/dist/audio/limiter.js +39 -0
  62. package/dist/audio/limiter.js.map +1 -0
  63. package/dist/audio/loader.d.ts +6 -0
  64. package/dist/audio/loader.d.ts.map +1 -0
  65. package/dist/audio/loader.js +42 -0
  66. package/dist/audio/loader.js.map +1 -0
  67. package/dist/audio/mixer.d.ts +17 -0
  68. package/dist/audio/mixer.d.ts.map +1 -0
  69. package/dist/audio/mixer.js +204 -0
  70. package/dist/audio/mixer.js.map +1 -0
  71. package/dist/audio/varispeed.d.ts +24 -0
  72. package/dist/audio/varispeed.d.ts.map +1 -0
  73. package/dist/audio/varispeed.js +114 -0
  74. package/dist/audio/varispeed.js.map +1 -0
  75. package/dist/audio/wav.d.ts +6 -0
  76. package/dist/audio/wav.d.ts.map +1 -0
  77. package/dist/audio/wav.js +62 -0
  78. package/dist/audio/wav.js.map +1 -0
  79. package/dist/backend/backend.d.ts +579 -0
  80. package/dist/backend/backend.d.ts.map +1 -0
  81. package/dist/backend/backend.js +17 -0
  82. package/dist/backend/backend.js.map +1 -0
  83. package/dist/backend/webgl-backend.d.ts +97 -0
  84. package/dist/backend/webgl-backend.d.ts.map +1 -0
  85. package/dist/backend/webgl-backend.js +2142 -0
  86. package/dist/backend/webgl-backend.js.map +1 -0
  87. package/dist/backend/webgpu-backend.d.ts +121 -0
  88. package/dist/backend/webgpu-backend.d.ts.map +1 -0
  89. package/dist/backend/webgpu-backend.js +2481 -0
  90. package/dist/backend/webgpu-backend.js.map +1 -0
  91. package/dist/compositor/bitfont.d.ts +8 -0
  92. package/dist/compositor/bitfont.d.ts.map +1 -0
  93. package/dist/compositor/bitfont.js +52 -0
  94. package/dist/compositor/bitfont.js.map +1 -0
  95. package/dist/compositor/camera.d.ts +5 -0
  96. package/dist/compositor/camera.d.ts.map +1 -0
  97. package/dist/compositor/camera.js +114 -0
  98. package/dist/compositor/camera.js.map +1 -0
  99. package/dist/compositor/color.d.ts +26 -0
  100. package/dist/compositor/color.d.ts.map +1 -0
  101. package/dist/compositor/color.js +189 -0
  102. package/dist/compositor/color.js.map +1 -0
  103. package/dist/compositor/element-renderers/caption.d.ts +4 -0
  104. package/dist/compositor/element-renderers/caption.d.ts.map +1 -0
  105. package/dist/compositor/element-renderers/caption.js +376 -0
  106. package/dist/compositor/element-renderers/caption.js.map +1 -0
  107. package/dist/compositor/element-renderers/group.d.ts +12 -0
  108. package/dist/compositor/element-renderers/group.d.ts.map +1 -0
  109. package/dist/compositor/element-renderers/group.js +259 -0
  110. package/dist/compositor/element-renderers/group.js.map +1 -0
  111. package/dist/compositor/element-renderers/image.d.ts +4 -0
  112. package/dist/compositor/element-renderers/image.d.ts.map +1 -0
  113. package/dist/compositor/element-renderers/image.js +97 -0
  114. package/dist/compositor/element-renderers/image.js.map +1 -0
  115. package/dist/compositor/element-renderers/lit.d.ts +6 -0
  116. package/dist/compositor/element-renderers/lit.d.ts.map +1 -0
  117. package/dist/compositor/element-renderers/lit.js +82 -0
  118. package/dist/compositor/element-renderers/lit.js.map +1 -0
  119. package/dist/compositor/element-renderers/particles.d.ts +4 -0
  120. package/dist/compositor/element-renderers/particles.d.ts.map +1 -0
  121. package/dist/compositor/element-renderers/particles.js +212 -0
  122. package/dist/compositor/element-renderers/particles.js.map +1 -0
  123. package/dist/compositor/element-renderers/shape.d.ts +4 -0
  124. package/dist/compositor/element-renderers/shape.d.ts.map +1 -0
  125. package/dist/compositor/element-renderers/shape.js +171 -0
  126. package/dist/compositor/element-renderers/shape.js.map +1 -0
  127. package/dist/compositor/element-renderers/svg.d.ts +4 -0
  128. package/dist/compositor/element-renderers/svg.d.ts.map +1 -0
  129. package/dist/compositor/element-renderers/svg.js +210 -0
  130. package/dist/compositor/element-renderers/svg.js.map +1 -0
  131. package/dist/compositor/element-renderers/text.d.ts +25 -0
  132. package/dist/compositor/element-renderers/text.d.ts.map +1 -0
  133. package/dist/compositor/element-renderers/text.js +1358 -0
  134. package/dist/compositor/element-renderers/text.js.map +1 -0
  135. package/dist/compositor/element-renderers/video.d.ts +12 -0
  136. package/dist/compositor/element-renderers/video.d.ts.map +1 -0
  137. package/dist/compositor/element-renderers/video.js +109 -0
  138. package/dist/compositor/element-renderers/video.js.map +1 -0
  139. package/dist/compositor/fit.d.ts +18 -0
  140. package/dist/compositor/fit.d.ts.map +1 -0
  141. package/dist/compositor/fit.js +106 -0
  142. package/dist/compositor/fit.js.map +1 -0
  143. package/dist/compositor/lighting.d.ts +63 -0
  144. package/dist/compositor/lighting.d.ts.map +1 -0
  145. package/dist/compositor/lighting.js +141 -0
  146. package/dist/compositor/lighting.js.map +1 -0
  147. package/dist/compositor/mat4.d.ts +88 -0
  148. package/dist/compositor/mat4.d.ts.map +1 -0
  149. package/dist/compositor/mat4.js +245 -0
  150. package/dist/compositor/mat4.js.map +1 -0
  151. package/dist/compositor/project.d.ts +24 -0
  152. package/dist/compositor/project.d.ts.map +1 -0
  153. package/dist/compositor/project.js +105 -0
  154. package/dist/compositor/project.js.map +1 -0
  155. package/dist/compositor/render-context.d.ts +194 -0
  156. package/dist/compositor/render-context.d.ts.map +1 -0
  157. package/dist/compositor/render-context.js +10 -0
  158. package/dist/compositor/render-context.js.map +1 -0
  159. package/dist/compositor/resolve.d.ts +80 -0
  160. package/dist/compositor/resolve.d.ts.map +1 -0
  161. package/dist/compositor/resolve.js +276 -0
  162. package/dist/compositor/resolve.js.map +1 -0
  163. package/dist/compositor/scene.d.ts +10 -0
  164. package/dist/compositor/scene.d.ts.map +1 -0
  165. package/dist/compositor/scene.js +658 -0
  166. package/dist/compositor/scene.js.map +1 -0
  167. package/dist/compositor/transform.d.ts +73 -0
  168. package/dist/compositor/transform.d.ts.map +1 -0
  169. package/dist/compositor/transform.js +229 -0
  170. package/dist/compositor/transform.js.map +1 -0
  171. package/dist/compositor/unit.d.ts +27 -0
  172. package/dist/compositor/unit.d.ts.map +1 -0
  173. package/dist/compositor/unit.js +74 -0
  174. package/dist/compositor/unit.js.map +1 -0
  175. package/dist/encoder/exporter.d.ts +95 -0
  176. package/dist/encoder/exporter.d.ts.map +1 -0
  177. package/dist/encoder/exporter.js +341 -0
  178. package/dist/encoder/exporter.js.map +1 -0
  179. package/dist/encoder/index.d.ts +3 -0
  180. package/dist/encoder/index.d.ts.map +1 -0
  181. package/dist/encoder/index.js +2 -0
  182. package/dist/encoder/index.js.map +1 -0
  183. package/dist/index.d.ts +12 -0
  184. package/dist/index.d.ts.map +1 -0
  185. package/dist/index.js +27 -0
  186. package/dist/index.js.map +1 -0
  187. package/dist/logger.d.ts +13 -0
  188. package/dist/logger.d.ts.map +1 -0
  189. package/dist/logger.js +32 -0
  190. package/dist/logger.js.map +1 -0
  191. package/dist/runtime.d.ts +216 -0
  192. package/dist/runtime.d.ts.map +1 -0
  193. package/dist/runtime.js +1012 -0
  194. package/dist/runtime.js.map +1 -0
  195. package/dist/svg/morph.d.ts +6 -0
  196. package/dist/svg/morph.d.ts.map +1 -0
  197. package/dist/svg/morph.js +62 -0
  198. package/dist/svg/morph.js.map +1 -0
  199. package/dist/svg/svg-renderer.d.ts +18 -0
  200. package/dist/svg/svg-renderer.d.ts.map +1 -0
  201. package/dist/svg/svg-renderer.js +142 -0
  202. package/dist/svg/svg-renderer.js.map +1 -0
  203. package/dist/text/caption-chunk.d.ts +17 -0
  204. package/dist/text/caption-chunk.d.ts.map +1 -0
  205. package/dist/text/caption-chunk.js +76 -0
  206. package/dist/text/caption-chunk.js.map +1 -0
  207. package/dist/text/font-atlas.d.ts +63 -0
  208. package/dist/text/font-atlas.d.ts.map +1 -0
  209. package/dist/text/font-atlas.js +225 -0
  210. package/dist/text/font-atlas.js.map +1 -0
  211. package/dist/text/measure.d.ts +38 -0
  212. package/dist/text/measure.d.ts.map +1 -0
  213. package/dist/text/measure.js +164 -0
  214. package/dist/text/measure.js.map +1 -0
  215. package/dist/text/text-animation.d.ts +52 -0
  216. package/dist/text/text-animation.d.ts.map +1 -0
  217. package/dist/text/text-animation.js +133 -0
  218. package/dist/text/text-animation.js.map +1 -0
  219. package/package.json +47 -0
@@ -0,0 +1,212 @@
1
+ // Particles renderer — Clipkit extension.
2
+ //
3
+ // Pure-function-of-time simulation: every particle's position, rotation,
4
+ // size, and color is deterministically derived from (element id, particle
5
+ // index, age). No state carried frame-to-frame, so seeking backward and
6
+ // rendering arbitrary frames works without resimulation.
7
+ //
8
+ // Each frame:
9
+ // 1. Enumerate which particle indices are currently alive.
10
+ // 2. For each, run simulateParticle(n, age) → {x, y, rotation, size, color, alpha}.
11
+ // 3. Emit one backend.drawShape per particle.
12
+ //
13
+ // Active-window enumeration is O(maxAlive) per frame regardless of total
14
+ // emission count — for continuous mode the alive window slides forward in
15
+ // time, so we only iterate ceil(lifetime × rate) indices.
16
+ import { parseColor } from '../color.js';
17
+ import { mat4ApplyToPoint, mat4Multiply, mat4PlaneAt, mat4Rotation, quadWorldTransform } from '../mat4.js';
18
+ import { resolveLength } from '../unit.js';
19
+ import { applyAnimation, resolve3D } from '../resolve.js';
20
+ import { applyEasing } from '../../animation/easings.js';
21
+ export function renderParticlesElement(element, ctx) {
22
+ const { canvas, backend } = ctx;
23
+ const elementStart = ctx.timeOffset + numberOr(element.time, 0);
24
+ const localTime = ctx.time - elementStart;
25
+ if (localTime < 0)
26
+ return;
27
+ // Emitter position (animatable like any other element).
28
+ const emitterX = applyAnimation(element, 'x', resolveLength(element.x, canvas.width, canvas), ctx);
29
+ const emitterY = applyAnimation(element, 'y', resolveLength(element.y, canvas.height, canvas), ctx);
30
+ // Per-particle depth (CKP/1.0, §5.7.3): vz along the emitter plane's
31
+ // normal. Authoring either field puts the element on the matrix path
32
+ // (like element `z`, depth is invisible without perspective).
33
+ const zVelocity = numberOr(element.z_velocity, 0);
34
+ const zSpread = numberOr(element.z_spread, 0);
35
+ const hasZDynamics = zVelocity !== 0 || zSpread !== 0;
36
+ // CKP/1.0 3D (§4.4): the whole particle field tilts as one plane
37
+ // anchored at the emitter.
38
+ const t3d = resolve3D(element, ctx);
39
+ const planeChain = t3d !== null || !ctx.modelMatrix.aff || hasZDynamics
40
+ ? mat4Multiply(ctx.modelMatrix, mat4PlaneAt(emitterX, emitterY, t3d?.z ?? 0, 0, t3d?.yRot ?? 0, t3d?.xRot ?? 0))
41
+ : null;
42
+ // Config with defaults.
43
+ const rate = Math.max(1, numberOr(element.rate, 60));
44
+ const lifetime = Math.max(0.01, numberOr(element.lifetime, 1.5));
45
+ const velocity = numberOr(element.velocity, 300);
46
+ const spread = numberOr(element.spread, 360);
47
+ const direction = numberOr(element.direction, -90);
48
+ const gravity = numberOr(element.gravity, 600);
49
+ const size = Math.max(1, numberOr(element.size, 12));
50
+ const sizeVariation = clamp01(numberOr(element.size_variation, 0.4));
51
+ const rotSpeed = numberOr(element.rotation_speed, 360);
52
+ const burst = element.burst === true;
53
+ const burstCount = Math.max(1, Math.floor(numberOr(element.burst_count, 80)));
54
+ const fadeAt = clamp01(numberOr(element.fade_at, 0.7));
55
+ const isCircle = element.particle_shape === 'circle';
56
+ // Convergence mode setup.
57
+ const targetPoints = Array.isArray(element.target_points) ? element.target_points : null;
58
+ const convergenceEasing = element.convergence_easing ?? 'ease-out-quart';
59
+ const scatterRadius = numberOr(element.scatter_radius, Math.max(canvas.width, canvas.height));
60
+ const colors = normalizeColors(element.color);
61
+ const elementOpacity = clamp01(applyAnimation(element, 'opacity', numberOr(element.opacity, 1), ctx) * ctx.opacityFactor);
62
+ if (elementOpacity <= 0)
63
+ return;
64
+ // Stable seed per element so the particle field is deterministic across frames.
65
+ const seedBase = hashString(typeof element.id === 'string' ? element.id : 'particles');
66
+ // Enumerate active particle indices.
67
+ // Burst mode: all particles share spawnTime=0, age=localTime.
68
+ // Continuous mode: particle n spawns at n/rate; alive when 0 ≤ age < lifetime.
69
+ let firstN;
70
+ let lastN;
71
+ if (burst) {
72
+ if (localTime >= lifetime)
73
+ return;
74
+ firstN = 0;
75
+ lastN = burstCount - 1;
76
+ }
77
+ else {
78
+ firstN = Math.max(0, Math.ceil((localTime - lifetime) * rate));
79
+ lastN = Math.floor(localTime * rate);
80
+ }
81
+ for (let n = firstN; n <= lastN; n++) {
82
+ const spawnTime = burst ? 0 : n / rate;
83
+ const age = localTime - spawnTime;
84
+ if (age < 0 || age >= lifetime)
85
+ continue;
86
+ // 6 independent random values per particle.
87
+ const rng = mulberry32(seedBase + n * 0x9e3779b9);
88
+ const r1 = rng(); // angle within spread / scatter x
89
+ const r2 = rng(); // speed jitter / scatter y
90
+ const r3 = rng(); // rotation direction
91
+ const r4 = rng(); // size
92
+ const r5 = rng(); // color index
93
+ const r6 = rng(); // z-velocity spread (§5.7.3)
94
+ let px;
95
+ let py;
96
+ if (targetPoints && targetPoints.length > 0) {
97
+ // ── Convergence mode ────────────────────────────────────────────
98
+ // Random scattered start position (in a disk of radius scatterRadius
99
+ // centered on the emitter), animating to its assigned target point.
100
+ const startAngle = r1 * Math.PI * 2;
101
+ const startDist = scatterRadius * (0.5 + 0.5 * r2); // 50%..100% radius
102
+ const startX = emitterX + Math.cos(startAngle) * startDist;
103
+ const startY = emitterY + Math.sin(startAngle) * startDist;
104
+ const target = targetPoints[n % targetPoints.length];
105
+ const progress = clamp01(age / lifetime);
106
+ const eased = applyEasing(convergenceEasing, progress);
107
+ px = startX + (target[0] - startX) * eased;
108
+ py = startY + (target[1] - startY) * eased;
109
+ }
110
+ else {
111
+ // ── Ballistic emission (default) ────────────────────────────────
112
+ const angleDeg = direction + (r1 - 0.5) * spread;
113
+ const angleRad = (angleDeg * Math.PI) / 180;
114
+ const speed = velocity * (0.7 + 0.6 * r2); // 70%..130%
115
+ const vx = Math.cos(angleRad) * speed;
116
+ const vy = Math.sin(angleRad) * speed;
117
+ px = emitterX + vx * age;
118
+ py = emitterY + vy * age + 0.5 * gravity * age * age;
119
+ }
120
+ // Depth along the plane normal: vz = z_velocity + (r6 − 0.5) ×
121
+ // z_spread, pz = vz · age. No z gravity (gravity stays in-plane y).
122
+ // Applies in convergence mode too (orthogonal, no special case).
123
+ const pz = hasZDynamics ? (zVelocity + (r6 - 0.5) * zSpread) * age : 0;
124
+ // Rotation accumulates linearly; sign randomized per particle.
125
+ const rot = rotSpeed * age * (r3 < 0.5 ? -1 : 1);
126
+ // Size — anchored at `size`, scaled down by up to sizeVariation.
127
+ const partSize = size * (1 - sizeVariation + sizeVariation * r4);
128
+ // Color — pick from the palette.
129
+ const color = colors[Math.floor(r5 * colors.length) % colors.length];
130
+ // Fade — full alpha until fade_at, then linear ramp to 0.
131
+ const lifeProg = age / lifetime;
132
+ let alpha = elementOpacity;
133
+ if (lifeProg > fadeAt) {
134
+ alpha *= (1 - lifeProg) / (1 - fadeAt);
135
+ }
136
+ if (alpha <= 0)
137
+ continue;
138
+ // Apply group transform stack: each particle's center is translated
139
+ // through the model matrix, rotation is summed, opacity multiplied.
140
+ // Under 3D the particle field lives in the emitter's plane: local
141
+ // coords stay local and each quad projects through planeChain.
142
+ const [worldX, worldY] = planeChain ? [px, py] : mat4ApplyToPoint(ctx.modelMatrix, px, py);
143
+ const totalRot = planeChain ? rot : rot + mat4Rotation(ctx.modelMatrix);
144
+ // Premultiplied RGBA. Group's opacity factor was already folded
145
+ // into elementOpacity at the top of this loop's caller.
146
+ const c = parseColor(color);
147
+ const ca = c[3] * alpha;
148
+ const premul = [
149
+ c[0] * ca,
150
+ c[1] * ca,
151
+ c[2] * ca,
152
+ ca,
153
+ ];
154
+ backend.drawShape({
155
+ cx: worldX,
156
+ cy: worldY,
157
+ width: partSize,
158
+ height: partSize,
159
+ rotation: totalRot,
160
+ transform: planeChain
161
+ ? quadWorldTransform(planeChain, px, py, partSize, partSize, rot, 0, 0, pz !== 0 ? { xRot: 0, yRot: 0, z: pz } : null)
162
+ : undefined,
163
+ color: premul,
164
+ shape: isCircle ? 'ellipse' : 'rectangle',
165
+ cornerRadius: isCircle ? 0 : 0,
166
+ blend: element.blend_mode,
167
+ });
168
+ }
169
+ }
170
+ // ── helpers ────────────────────────────────────────────────────────────────
171
+ function numberOr(value, fallback) {
172
+ if (typeof value === 'number' && Number.isFinite(value))
173
+ return value;
174
+ if (typeof value === 'string') {
175
+ const n = parseFloat(value);
176
+ if (Number.isFinite(n))
177
+ return n;
178
+ }
179
+ return fallback;
180
+ }
181
+ function clamp01(n) {
182
+ return n < 0 ? 0 : n > 1 ? 1 : n;
183
+ }
184
+ function normalizeColors(c) {
185
+ if (!c)
186
+ return ['#ffffff'];
187
+ if (Array.isArray(c))
188
+ return c.length > 0 ? c : ['#ffffff'];
189
+ return [c];
190
+ }
191
+ // FNV-1a string hash — fast, decent dispersion, no allocations.
192
+ function hashString(s) {
193
+ let h = 0x811c9dc5;
194
+ for (let i = 0; i < s.length; i++) {
195
+ h ^= s.charCodeAt(i);
196
+ h = Math.imul(h, 0x01000193);
197
+ }
198
+ return h >>> 0;
199
+ }
200
+ // Mulberry32 — small, fast, good-enough PRNG. Returns a thunk that yields
201
+ // successive [0, 1) values from a single seed.
202
+ function mulberry32(seed) {
203
+ let a = seed >>> 0;
204
+ return () => {
205
+ a = (a + 0x6d2b79f5) | 0;
206
+ let t = a;
207
+ t = Math.imul(t ^ (t >>> 15), t | 1);
208
+ t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
209
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
210
+ };
211
+ }
212
+ //# sourceMappingURL=particles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"particles.js","sourceRoot":"","sources":["../../../src/compositor/element-renderers/particles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ShapeElement } from '@clipkit/protocol';
2
+ import type { RenderContext } from '../render-context.js';
3
+ export declare function renderShapeElement(element: ShapeElement, ctx: RenderContext): void;
4
+ //# sourceMappingURL=shape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shape.d.ts","sourceRoot":"","sources":["../../../src/compositor/element-renderers/shape.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkC,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAStF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAuJlF"}
@@ -0,0 +1,171 @@
1
+ import { parseColor, parseColorPremultiplied } from '../color.js';
2
+ import { applyModelTransform, quadWorldTransform } from '../mat4.js';
3
+ import { resolveAnchor, resolveLength } from '../unit.js';
4
+ import { anchorToCenter } from '../transform.js';
5
+ import { applyAnimation, applyAspectRatio, resolve3D, resolveColorProperty, resolveScalePair, resolveSkewPair } from '../resolve.js';
6
+ import { resolveMaterial } from '../lighting.js';
7
+ import { buildLitParams } from './lit.js';
8
+ export function renderShapeElement(element, ctx) {
9
+ const { canvas, backend } = ctx;
10
+ const x = applyAnimation(element, 'x', resolveLength(element.x, canvas.width, canvas), ctx);
11
+ const y = applyAnimation(element, 'y', resolveLength(element.y, canvas.height, canvas), ctx);
12
+ const { sx, sy } = resolveScalePair(element, ctx);
13
+ const box = applyAspectRatio(element, applyAnimation(element, 'width', resolveLength(element.width, canvas.width, canvas, 100), ctx), applyAnimation(element, 'height', resolveLength(element.height, canvas.height, canvas, 100), ctx));
14
+ const width = sx * box.width;
15
+ const height = sy * box.height;
16
+ const rotation = applyAnimation(element, 'rotation', numberOr((element.rotation ?? element.z_rotation), 0), ctx);
17
+ const { skewX, skewY } = resolveSkewPair(element, ctx);
18
+ const opacity01 = applyAnimation(element, 'opacity', numberOr(element.opacity, 1), ctx);
19
+ const xAnchor = resolveAnchor(element.x_anchor);
20
+ const yAnchor = resolveAnchor(element.y_anchor);
21
+ const { cx, cy } = anchorToCenter(x, y, width, height, xAnchor, yAnchor);
22
+ // CKP/1.0 3D (§4.4): own 3D fields, or an un-flattened 3D ancestor,
23
+ // route through the full-matrix hand-off. Everything else stays on
24
+ // the byte-stable 2D decomposition.
25
+ const t3d = resolve3D(element, ctx);
26
+ const matrixPath = t3d !== null || !ctx.modelMatrix.aff;
27
+ // Apply the group transform stack (no-op when not nested in a group).
28
+ // Under the matrix path only opacity01 is meaningful (it is matrix-
29
+ // independent); the spatial fields are superseded by `transform`.
30
+ const w = applyModelTransform(ctx.modelMatrix, ctx.opacityFactor, cx, cy, rotation, opacity01, width, height);
31
+ const transform = matrixPath
32
+ ? quadWorldTransform(ctx.modelMatrix, cx, cy, width, height, rotation, skewX, skewY, t3d)
33
+ : undefined;
34
+ // Color: parse hex → straight RGBA, multiply alpha by opacity, premultiply.
35
+ // (parseColorPremultiplied premultiplies by the parsed alpha — we apply
36
+ // element-level opacity by multiplying the alpha channel before that.)
37
+ // fill_color is animatable via color-valued keyframe_animations.
38
+ const fillColor = resolveColorProperty(element, 'fill_color', typeof element.fill_color === 'string' ? element.fill_color : undefined, ctx);
39
+ const straight = parseColorPremultipliedWithOpacity(fillColor, w.opacity01);
40
+ // Border radius is in PIXELS — the backend now does corner SDF in pixel
41
+ // space (so corners stay circular on non-square rects) and clamps to a
42
+ // safe maximum internally. Animatable via keyframe_animations (no keyframes
43
+ // ⇒ applyAnimation returns the static value, so static shapes are unchanged).
44
+ const cornerRadius = applyAnimation(element, 'border_radius', numberOr(element.border_radius, 0), ctx);
45
+ // Primitive kind: rectangle (default) or ellipse. Arbitrary geometry takes
46
+ // the `paths` form and never reaches this SDF renderer.
47
+ const shapeName = (typeof element.shape === 'string' && element.shape) || 'rectangle';
48
+ const isEllipse = shapeName.toLowerCase() === 'ellipse';
49
+ // Parse gradient if present. Hex stops → premultiplied RGBA; angle deg → rad.
50
+ const gradient = element.gradient
51
+ ? compileGradient(element.gradient, w.opacity01)
52
+ : undefined;
53
+ // Stroke (border) — the SDF in SHAPE_FS paints the stroke band
54
+ // directly, so semi-transparent fills no longer let the stroke color
55
+ // bleed through the interior. We just pass through to the backend.
56
+ const strokeColorStr = resolveColorProperty(element, 'stroke_color', typeof element.stroke_color === 'string' ? element.stroke_color : undefined, ctx) ?? null;
57
+ const strokeWidth = applyAnimation(element, 'stroke_width', numberOr(element.stroke_width, 0), ctx);
58
+ const strokePremul = strokeColorStr && strokeWidth > 0
59
+ ? parseColorPremultipliedWithOpacity(strokeColorStr, w.opacity01)
60
+ : undefined;
61
+ // Draw the drop shadow (if any) BEFORE the shape so the shape paints
62
+ // over the inside-of-SDF region. Shadow opacity scales with the
63
+ // element's overall opacity so animating the shape's opacity fades
64
+ // the shadow alongside it.
65
+ if (element.shadow && typeof element.shadow.color === 'string') {
66
+ const shadowPremul = parseColorPremultipliedWithOpacity(element.shadow.color, w.opacity01);
67
+ const offsetX = numberOr(element.shadow.offset_x, 0);
68
+ const offsetY = numberOr(element.shadow.offset_y, 0);
69
+ const blur = Math.max(0, numberOr(element.shadow.blur, 0));
70
+ backend.drawShapeShadow({
71
+ cx: w.cx,
72
+ cy: w.cy,
73
+ width: matrixPath ? width : w.width,
74
+ height: matrixPath ? height : w.height,
75
+ rotation: w.rotation,
76
+ skewX,
77
+ skewY,
78
+ // Under 3D the EXPANDED quad foreshortens with the element while
79
+ // the offset translates in the PARENT plane — consistent with 2D,
80
+ // where a rotated shape's shadow offset stays screen-aligned.
81
+ transform: matrixPath
82
+ ? quadWorldTransform(ctx.modelMatrix, cx + offsetX, cy + offsetY, width + blur * 2, height + blur * 2, rotation, skewX, skewY, t3d)
83
+ : undefined,
84
+ cornerRadius,
85
+ shape: isEllipse ? 'ellipse' : 'rectangle',
86
+ offsetX,
87
+ offsetY,
88
+ blur,
89
+ color: shadowPremul,
90
+ });
91
+ }
92
+ // §4.8 PBR lighting: when the shape carries a material and the scene
93
+ // has lights, build the lit payload (world-space normal + position via
94
+ // the camera-FREE world matrix, straight-alpha albedo). gradient fills
95
+ // aren't lit in Phase 1.
96
+ const material = !gradient ? resolveMaterial(element, ctx.time) : null;
97
+ const opacityFactor = Math.max(0, Math.min(1, w.opacity01));
98
+ const lit = material
99
+ ? buildLitParams(ctx, quadWorldTransform(ctx.worldMatrix, cx, cy, width, height, rotation, skewX, skewY, t3d), material, straightWithOpacity(fillColor, opacityFactor), strokeColorStr && strokeWidth > 0 ? straightWithOpacity(strokeColorStr, opacityFactor) : undefined)
100
+ : null;
101
+ backend.drawShape({
102
+ cx: w.cx,
103
+ cy: w.cy,
104
+ // Matrix path: local dims (the SDF works in element pixel space and
105
+ // the projection lives in `transform`); 2D path: decomposed dims.
106
+ width: matrixPath ? width : w.width,
107
+ height: matrixPath ? height : w.height,
108
+ rotation: w.rotation,
109
+ skewX,
110
+ skewY,
111
+ transform,
112
+ color: straight,
113
+ gradient,
114
+ cornerRadius,
115
+ shape: isEllipse ? 'ellipse' : 'rectangle',
116
+ strokeColor: strokePremul,
117
+ strokeWidth: strokePremul ? strokeWidth : 0,
118
+ blend: element.blend_mode,
119
+ lit: lit ?? undefined,
120
+ });
121
+ }
122
+ function straightWithOpacity(hex, opacityFactor) {
123
+ const c = parseColor(typeof hex === 'string' ? hex : '#ffffff');
124
+ return [c[0], c[1], c[2], c[3] * opacityFactor];
125
+ }
126
+ function compileGradient(g, opacity01) {
127
+ const opacityFactor = Math.max(0, Math.min(1, opacity01));
128
+ const stops = g.stops.slice(0, 4).map((s) => {
129
+ const c = parseColorPremultiplied(s.color);
130
+ return {
131
+ offset: Math.max(0, Math.min(1, s.offset)),
132
+ color: [
133
+ c[0] * opacityFactor,
134
+ c[1] * opacityFactor,
135
+ c[2] * opacityFactor,
136
+ c[3] * opacityFactor,
137
+ ],
138
+ };
139
+ });
140
+ if (g.type === 'linear') {
141
+ // CSS `linear-gradient(θ)`: 0° = to top, clockwise (90° = to right,
142
+ // 180° = to bottom). Default 180 (to bottom). The shader projects
143
+ // centered UV onto (cos, sin) of its angle, whose basis is 0° = +x
144
+ // (right), 90° = +y (down) — so map CSS θ → shader (θ − 90).
145
+ const angleDeg = typeof g.angle === 'number' ? g.angle : 180;
146
+ return { type: 'linear', angle: ((angleDeg - 90) * Math.PI) / 180, stops };
147
+ }
148
+ return {
149
+ type: 'radial',
150
+ cx: typeof g.cx === 'number' ? g.cx : 0.5,
151
+ cy: typeof g.cy === 'number' ? g.cy : 0.5,
152
+ radius: typeof g.radius === 'number' ? g.radius : 0.5,
153
+ stops,
154
+ };
155
+ }
156
+ function numberOr(value, fallback) {
157
+ if (typeof value === 'number' && Number.isFinite(value))
158
+ return value;
159
+ if (typeof value === 'string') {
160
+ const n = parseFloat(value);
161
+ if (Number.isFinite(n))
162
+ return n;
163
+ }
164
+ return fallback;
165
+ }
166
+ function parseColorPremultipliedWithOpacity(hex, opacity01) {
167
+ const c = parseColorPremultiplied(typeof hex === 'string' ? hex : '#ffffff');
168
+ const opacityFactor = Math.max(0, Math.min(1, opacity01));
169
+ return [c[0] * opacityFactor, c[1] * opacityFactor, c[2] * opacityFactor, c[3] * opacityFactor];
170
+ }
171
+ //# sourceMappingURL=shape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shape.js","sourceRoot":"","sources":["../../../src/compositor/element-renderers/shape.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ShapeElement } from '@clipkit/protocol';
2
+ import type { RenderContext } from '../render-context.js';
3
+ export declare function renderPathShape(element: ShapeElement, ctx: RenderContext): void;
4
+ //# sourceMappingURL=svg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svg.d.ts","sourceRoot":"","sources":["../../../src/compositor/element-renderers/svg.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAY,YAAY,EAAQ,MAAM,mBAAmB,CAAC;AAUtE,OAAO,KAAK,EACV,aAAa,EAGd,MAAM,sBAAsB,CAAC;AAU9B,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAqG/E"}
@@ -0,0 +1,210 @@
1
+ // SVG element renderer.
2
+ //
3
+ // Each frame:
4
+ // 1. Resolve per-path stroke_progress values (animatable via keyframes).
5
+ // 2. Get or create a cached OffscreenCanvas + Texture sized to the viewBox
6
+ // at a 2× supersampling factor.
7
+ // 3. Rasterize the paths into the OffscreenCanvas.
8
+ // 4. Upload the canvas contents into the texture.
9
+ // 5. Draw as a textured quad at the element's animated transform.
10
+ import { interpolateKeyframes } from '../../animation/keyframes.js';
11
+ import { isExpr, evalExpr } from '../../animation/expr.js';
12
+ import { applyEasing } from '../../animation/easings.js';
13
+ import { morphD } from '../../svg/morph.js';
14
+ import { rasterizeSvgElement } from '../../svg/svg-renderer.js';
15
+ import { applyModelTransform, quadWorldTransform } from '../mat4.js';
16
+ import { resolveAnchor, resolveLength } from '../unit.js';
17
+ import { anchorToCenter } from '../transform.js';
18
+ import { applyAnimation, applyAspectRatio, resolve3D, resolveScalePair, resolveSkewPair } from '../resolve.js';
19
+ const SUPERSAMPLE = 2;
20
+ // Cap the rasterization canvas. Going past this wastes memory + GPU
21
+ // without visible improvement at typical canvas sizes.
22
+ const MAX_RASTER = 2048;
23
+ // Renders the PATH form of a `shape` (an element carrying `paths`) — rasterized
24
+ // to a cached OffscreenCanvas and drawn as a textured quad. The primitive form
25
+ // (rectangle/ellipse, no `paths`) goes through renderShapeElement instead.
26
+ export function renderPathShape(element, ctx) {
27
+ const { canvas, backend, svgRasters } = ctx;
28
+ const paths = element.paths;
29
+ if (!paths || paths.length === 0)
30
+ return;
31
+ const viewBox = element.view_box ?? [0, 0, 100, 100];
32
+ const [, , vbW, vbH] = viewBox;
33
+ const x = applyAnimation(element, 'x', resolveLength(element.x, canvas.width, canvas), ctx);
34
+ const y = applyAnimation(element, 'y', resolveLength(element.y, canvas.height, canvas), ctx);
35
+ const { sx, sy } = resolveScalePair(element, ctx);
36
+ const box = applyAspectRatio(element, applyAnimation(element, 'width', resolveLength(element.width, canvas.width, canvas, vbW), ctx), applyAnimation(element, 'height', resolveLength(element.height, canvas.height, canvas, vbH), ctx));
37
+ const width = sx * box.width;
38
+ const height = sy * box.height;
39
+ const rotation = applyAnimation(element, 'rotation', numberOr(element.rotation ?? element.z_rotation, 0), ctx);
40
+ const opacity01 = applyAnimation(element, 'opacity', numberOr(element.opacity, 1), ctx);
41
+ const xAnchor = resolveAnchor(element.x_anchor);
42
+ const yAnchor = resolveAnchor(element.y_anchor);
43
+ const { cx, cy } = anchorToCenter(x, y, width, height, xAnchor, yAnchor);
44
+ const w = applyModelTransform(ctx.modelMatrix, ctx.opacityFactor, cx, cy, rotation, opacity01, width, height);
45
+ const opacity = clamp01(w.opacity01);
46
+ if (opacity <= 0 || w.width <= 0 || w.height <= 0)
47
+ return;
48
+ // Resolve per-path trim windows at this frame (§5.6.1) —
49
+ // stroke_progress is sugar for [0, progress, 0].
50
+ const elementStart = ctx.timeOffset + numberOr(element.time, 0);
51
+ const localTime = ctx.time - elementStart;
52
+ const trims = paths.flatMap((p) => resolveTrim(p, localTime));
53
+ const ds = paths.map((p) => resolveD(p.d, localTime));
54
+ // Get or create the per-element raster target.
55
+ //
56
+ // The canvas resolution drives clarity at display. If we used the viewBox
57
+ // dimensions alone (e.g. 20×20 for an SVG icon), an element drawn at
58
+ // 320×320 px would upscale the texture 16× and look blurry. So we size
59
+ // the canvas to max(viewBox, display) × supersample, capped to avoid
60
+ // blowing up GPU memory.
61
+ const targetRasterW = Math.min(MAX_RASTER, Math.max(1, Math.ceil(Math.max(vbW, width) * SUPERSAMPLE)));
62
+ const targetRasterH = Math.min(MAX_RASTER, Math.max(1, Math.ceil(Math.max(vbH, height) * SUPERSAMPLE)));
63
+ const cacheKey = typeof element.id === 'string' ? element.id : `__svg_${JSON.stringify(viewBox)}`;
64
+ let target = svgRasters.get(cacheKey);
65
+ if (!target || target.canvas.width !== targetRasterW || target.canvas.height !== targetRasterH) {
66
+ const off = new OffscreenCanvas(targetRasterW, targetRasterH);
67
+ const offCtx = off.getContext('2d');
68
+ if (!offCtx)
69
+ return;
70
+ // We have to initialize the texture with the canvas to pin its size.
71
+ const texture = backend.createTexture(off);
72
+ target = { canvas: off, ctx: offCtx, texture };
73
+ svgRasters.set(cacheKey, target);
74
+ }
75
+ // Memoize the raster + upload — skip both when nothing about the
76
+ // rendered pixels has changed since the last frame. For a complex
77
+ // SVG (US map: 50+ paths, 2048×2048 raster, 16MB texture upload),
78
+ // this is the difference between ~50ms per frame and ~0ms while the
79
+ // element is sitting on screen post-animation. Stroke-progress
80
+ // animations still re-raster every frame because their progresses
81
+ // genuinely change frame-to-frame; the moment they settle at 1.0
82
+ // the cache kicks in.
83
+ const nextSignature = {
84
+ trims,
85
+ ds,
86
+ pathsRef: paths,
87
+ gradientsRef: element.gradients,
88
+ rasterW: targetRasterW,
89
+ rasterH: targetRasterH,
90
+ };
91
+ if (!signaturesEqual(target.lastSignature, nextSignature)) {
92
+ rasterizeSvgElement(element, trims, ds, target);
93
+ backend.updateTexture(target.texture, target.canvas);
94
+ target.lastSignature = nextSignature;
95
+ }
96
+ // Draw the rasterized SVG as a textured quad. Tint by opacity (premul).
97
+ // CKP/1.0 3D (§4.4): full-matrix hand-off when 3D is in play.
98
+ const t3d = resolve3D(element, ctx);
99
+ const matrixPath = t3d !== null || !ctx.modelMatrix.aff;
100
+ const { skewX, skewY } = resolveSkewPair(element, ctx);
101
+ backend.drawTexturedQuad({
102
+ cx: w.cx,
103
+ cy: w.cy,
104
+ width: matrixPath ? width : w.width,
105
+ height: matrixPath ? height : w.height,
106
+ rotation: w.rotation,
107
+ skewX,
108
+ skewY,
109
+ transform: matrixPath
110
+ ? quadWorldTransform(ctx.modelMatrix, cx, cy, width, height, rotation, skewX, skewY, t3d)
111
+ : undefined,
112
+ texture: target.texture,
113
+ tint: [opacity, opacity, opacity, opacity],
114
+ blend: element.blend_mode,
115
+ });
116
+ }
117
+ function resolveTrim(p, localTime) {
118
+ const rp = (v) => {
119
+ if (v === undefined)
120
+ return undefined;
121
+ if (typeof v === 'number')
122
+ return v;
123
+ if (isExpr(v))
124
+ return evalExpr(v, { t: localTime, dur: 0, i: 0, n: 1, value: 0 });
125
+ if (Array.isArray(v))
126
+ return interpolateKeyframes(v, localTime);
127
+ return undefined;
128
+ };
129
+ const hasTrim = p.trim_start !== undefined || p.trim_end !== undefined || p.trim_offset !== undefined;
130
+ if (hasTrim) {
131
+ return [
132
+ clamp01p(rp(p.trim_start) ?? 0),
133
+ clamp01p(rp(p.trim_end) ?? 1),
134
+ rp(p.trim_offset) ?? 0,
135
+ ];
136
+ }
137
+ return [0, clamp01p(rp(p.stroke_progress) ?? 1), 0];
138
+ }
139
+ function clamp01p(v) {
140
+ return Math.max(0, Math.min(1, v));
141
+ }
142
+ /**
143
+ * Resolve a path's d at element-local time: a plain string passes
144
+ * through; keyframed d-strings MORPH between compatible command lists
145
+ * (§5.6.2) and SNAP at the destination keyframe otherwise.
146
+ */
147
+ function resolveD(d, localTime) {
148
+ if (typeof d === 'string')
149
+ return d;
150
+ if (!Array.isArray(d) || d.length === 0)
151
+ return '';
152
+ const tv = (k) => typeof k.time === 'number' ? k.time : parseFloat(String(k.time)) || 0;
153
+ const first = d[0];
154
+ const last = d[d.length - 1];
155
+ if (localTime <= tv(first))
156
+ return String(first.value);
157
+ if (localTime >= tv(last))
158
+ return String(last.value);
159
+ for (let i = 0; i < d.length - 1; i++) {
160
+ const a = d[i];
161
+ const b = d[i + 1];
162
+ const at = tv(a);
163
+ const bt = tv(b);
164
+ if (localTime >= at && localTime <= bt) {
165
+ const span = bt - at;
166
+ const u = applyEasing(b.easing, span > 0 ? (localTime - at) / span : 1);
167
+ const morphed = morphD(String(a.value), String(b.value), u);
168
+ return morphed ?? String(a.value);
169
+ }
170
+ }
171
+ return String(last.value);
172
+ }
173
+ function numberOr(value, fallback) {
174
+ if (typeof value === 'number' && Number.isFinite(value))
175
+ return value;
176
+ if (typeof value === 'string') {
177
+ const n = parseFloat(value);
178
+ if (Number.isFinite(n))
179
+ return n;
180
+ }
181
+ return fallback;
182
+ }
183
+ function clamp01(n) {
184
+ return n < 0 ? 0 : n > 1 ? 1 : n;
185
+ }
186
+ function signaturesEqual(prev, next) {
187
+ if (!prev)
188
+ return false;
189
+ if (prev.pathsRef !== next.pathsRef)
190
+ return false;
191
+ if (prev.gradientsRef !== next.gradientsRef)
192
+ return false;
193
+ if (prev.rasterW !== next.rasterW || prev.rasterH !== next.rasterH) {
194
+ return false;
195
+ }
196
+ if (prev.trims.length !== next.trims.length)
197
+ return false;
198
+ for (let i = 0; i < prev.trims.length; i++) {
199
+ if (prev.trims[i] !== next.trims[i])
200
+ return false;
201
+ }
202
+ if (prev.ds.length !== next.ds.length)
203
+ return false;
204
+ for (let i = 0; i < prev.ds.length; i++) {
205
+ if (prev.ds[i] !== next.ds[i])
206
+ return false;
207
+ }
208
+ return true;
209
+ }
210
+ //# sourceMappingURL=svg.js.map