@make-pictures/kits 0.0.0-stage → 2.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 (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +49 -2
  3. package/dist/chunk-3SUIELJV.mjs +601 -0
  4. package/dist/chunk-4Z3G6FPZ.mjs +485 -0
  5. package/dist/chunk-AHA23PHC.mjs +678 -0
  6. package/dist/chunk-CW623YVB.mjs +1124 -0
  7. package/dist/chunk-NNA7XXQB.mjs +1059 -0
  8. package/dist/chunk-S4CHTWOS.mjs +1237 -0
  9. package/dist/chunk-WAA7P5FT.mjs +912 -0
  10. package/dist/data-storytelling/AnimatedBarRace.d.ts +37 -0
  11. package/dist/data-storytelling/MetricComparisonCard.d.ts +29 -0
  12. package/dist/data-storytelling/TimelineTrack.d.ts +29 -0
  13. package/dist/data-storytelling/index.cjs +1224 -0
  14. package/dist/data-storytelling/index.d.ts +3 -0
  15. package/dist/data-storytelling/index.mjs +10 -0
  16. package/dist/index.cjs +6010 -0
  17. package/dist/index.d.ts +7 -0
  18. package/dist/index.mjs +108 -0
  19. package/dist/isometric-3d/IsometricStudioEnvironment.d.ts +8 -0
  20. package/dist/isometric-3d/Stylized3DCharacter.d.ts +29 -0
  21. package/dist/isometric-3d/index.cjs +611 -0
  22. package/dist/isometric-3d/index.d.ts +2 -0
  23. package/dist/isometric-3d/index.mjs +8 -0
  24. package/dist/kinetic-typography/AnimatedMetricCounter.d.ts +36 -0
  25. package/dist/kinetic-typography/ImpactKeywordCard.d.ts +31 -0
  26. package/dist/kinetic-typography/WordByWordStage.d.ts +47 -0
  27. package/dist/kinetic-typography/index.cjs +665 -0
  28. package/dist/kinetic-typography/index.d.ts +3 -0
  29. package/dist/kinetic-typography/index.mjs +14 -0
  30. package/dist/motion-diagrams-2d/CameraRig.d.ts +34 -0
  31. package/dist/motion-diagrams-2d/CodePayloadToast.d.ts +14 -0
  32. package/dist/motion-diagrams-2d/DataFlowEdge.d.ts +24 -0
  33. package/dist/motion-diagrams-2d/NodeBox.d.ts +65 -0
  34. package/dist/motion-diagrams-2d/SystemNode.d.ts +21 -0
  35. package/dist/motion-diagrams-2d/index.cjs +1137 -0
  36. package/dist/motion-diagrams-2d/index.d.ts +5 -0
  37. package/dist/motion-diagrams-2d/index.mjs +28 -0
  38. package/dist/paper-diorama-3d/ImageCutout3D.d.ts +47 -0
  39. package/dist/paper-diorama-3d/PaperCutout3D.d.ts +62 -0
  40. package/dist/paper-diorama-3d/PaperPopUpBook3D.d.ts +51 -0
  41. package/dist/paper-diorama-3d/PaperStageLighting3D.d.ts +12 -0
  42. package/dist/paper-diorama-3d/index.cjs +1087 -0
  43. package/dist/paper-diorama-3d/index.d.ts +4 -0
  44. package/dist/paper-diorama-3d/index.mjs +34 -0
  45. package/dist/product-frames/BrowserFrame.d.ts +28 -0
  46. package/dist/product-frames/PhoneFrame.d.ts +23 -0
  47. package/dist/product-frames/ScreenSpotlightOverlay.d.ts +34 -0
  48. package/dist/product-frames/frameMedia.d.ts +24 -0
  49. package/dist/product-frames/index.cjs +507 -0
  50. package/dist/product-frames/index.d.ts +8 -0
  51. package/dist/product-frames/index.mjs +12 -0
  52. package/dist/vfx/CinematicLensOverlay.d.ts +29 -0
  53. package/dist/vfx/ParticleField.d.ts +18 -0
  54. package/dist/vfx/SceneTransition.d.ts +24 -0
  55. package/dist/vfx/StagePostProcessing3D.d.ts +44 -0
  56. package/dist/vfx/index.cjs +933 -0
  57. package/dist/vfx/index.d.ts +4 -0
  58. package/dist/vfx/index.mjs +14 -0
  59. package/package.json +95 -4
@@ -0,0 +1,665 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // packages/kits/src/kinetic-typography/index.ts
21
+ var kinetic_typography_exports = {};
22
+ __export(kinetic_typography_exports, {
23
+ AnimatedMetricCounter: () => AnimatedMetricCounter,
24
+ ImpactKeywordCard: () => ImpactKeywordCard,
25
+ WordByWordStage: () => WordByWordStage,
26
+ formatTabularMetric: () => formatTabularMetric,
27
+ groupWordsIntoBeats: () => groupWordsIntoBeats
28
+ });
29
+ module.exports = __toCommonJS(kinetic_typography_exports);
30
+
31
+ // packages/kits/src/kinetic-typography/WordByWordStage.tsx
32
+ var import_react = require("react");
33
+ var import_remotion = require("remotion");
34
+ var import_theme = require("@make-pictures/core");
35
+ var import_timestamps = require("@make-pictures/core");
36
+ var import_jsx_runtime = require("react/jsx-runtime");
37
+ function buildFallbackWords(text, fps, durationInFrames) {
38
+ const tokens = text.trim().split(/\s+/).filter(Boolean);
39
+ if (tokens.length === 0) return [];
40
+ const usableStart = Math.min(12, Math.floor(durationInFrames * 0.08));
41
+ const usableSpan = Math.max(tokens.length * 6, durationInFrames - usableStart - 16);
42
+ const perWord = usableSpan / tokens.length;
43
+ return tokens.map((token, idx) => {
44
+ const sf = Math.round(usableStart + idx * perWord);
45
+ const ef = Math.max(sf + 4, Math.round(usableStart + (idx + 0.86) * perWord));
46
+ return {
47
+ word: token,
48
+ normalizedWord: token.replace(/^[.,!?;:"'()[\]{}—–-]+|[.,!?;:"'()[\]{}—–-]+$/g, "").toLowerCase(),
49
+ start: sf / fps,
50
+ end: ef / fps,
51
+ startFrame: sf,
52
+ endFrame: ef
53
+ };
54
+ });
55
+ }
56
+ function groupWordsIntoBeats(words, wordsPerBeat = 4, fps = 60) {
57
+ if (!words.length) return [];
58
+ const maxWords = Math.max(2, Math.min(7, Math.round(wordsPerBeat)));
59
+ const pauseThresholdFrames = Math.round(fps * 0.36);
60
+ const beats = [];
61
+ let bucket = [];
62
+ const flush = () => {
63
+ if (!bucket.length) return;
64
+ beats.push({
65
+ words: bucket,
66
+ startFrame: bucket[0].startFrame,
67
+ endFrame: bucket[bucket.length - 1].endFrame
68
+ });
69
+ bucket = [];
70
+ };
71
+ for (let i = 0; i < words.length; i++) {
72
+ const curr = words[i];
73
+ const prev = bucket[bucket.length - 1];
74
+ if (prev && curr.startFrame - prev.endFrame >= pauseThresholdFrames && bucket.length >= 2) {
75
+ flush();
76
+ }
77
+ bucket.push(curr);
78
+ const endsSentence = /[.!?;:—]$/.test(curr.word);
79
+ const endsClause = /[,–]$/.test(curr.word) && bucket.length >= 3;
80
+ if (bucket.length >= maxWords || endsSentence && bucket.length >= 2 || endsClause) {
81
+ flush();
82
+ }
83
+ }
84
+ flush();
85
+ return beats;
86
+ }
87
+ var WordByWordStage = ({
88
+ words,
89
+ sceneId,
90
+ voiceoverManifest,
91
+ fallbackText,
92
+ sceneStartFrame = 0,
93
+ wordsPerBeat = 4,
94
+ accentColor = import_theme.STUDIO_THEME.colors.brand[600],
95
+ variant = "transparent",
96
+ eyebrow,
97
+ fontSize,
98
+ safeBox9x16 = true,
99
+ enterFrame,
100
+ startFrame,
101
+ style
102
+ }) => {
103
+ const frame = (0, import_remotion.useCurrentFrame)();
104
+ const { fps, width, height, durationInFrames } = (0, import_remotion.useVideoConfig)();
105
+ (0, import_theme.useStudioFontsReady)();
106
+ const resolvedWords = (0, import_react.useMemo)(() => {
107
+ if (words && words.length > 0) return words;
108
+ if (sceneId) {
109
+ const vo = (0, import_timestamps.getSceneVoiceover)(sceneId, voiceoverManifest);
110
+ if (vo && vo.words.length > 0) return vo.words;
111
+ if (vo?.text) return buildFallbackWords(vo.text, fps, durationInFrames);
112
+ }
113
+ if (fallbackText) {
114
+ return buildFallbackWords(fallbackText, fps, durationInFrames);
115
+ }
116
+ return [];
117
+ }, [words, sceneId, voiceoverManifest, fallbackText, fps, durationInFrames]);
118
+ const beats = (0, import_react.useMemo)(
119
+ () => groupWordsIntoBeats(resolvedWords, wordsPerBeat, fps),
120
+ [resolvedWords, wordsPerBeat, fps]
121
+ );
122
+ const stageEnter = (0, import_remotion.spring)({
123
+ frame: frame - Math.max(2, startFrame ?? enterFrame ?? 2),
124
+ fps,
125
+ config: import_theme.SPRING_PRESETS.snappy
126
+ });
127
+ if (stageEnter <= 5e-3 || beats.length === 0) {
128
+ return null;
129
+ }
130
+ const localFrame = frame - sceneStartFrame;
131
+ let activeBeatIndex = 0;
132
+ for (let i = 0; i < beats.length; i++) {
133
+ const b = beats[i];
134
+ const nextBeat = beats[i + 1];
135
+ if (localFrame >= b.startFrame - 4) {
136
+ activeBeatIndex = i;
137
+ }
138
+ if (nextBeat && localFrame < nextBeat.startFrame - 4) {
139
+ break;
140
+ }
141
+ }
142
+ const activeBeat = beats[activeBeatIndex];
143
+ const beatEnter = (0, import_remotion.spring)({
144
+ frame: Math.max(0, localFrame - (activeBeat.startFrame - 4)),
145
+ fps,
146
+ config: import_theme.SPRING_PRESETS.snappy
147
+ });
148
+ let activeWordIdx = -1;
149
+ for (let i = 0; i < activeBeat.words.length; i++) {
150
+ const w = activeBeat.words[i];
151
+ if (localFrame >= w.startFrame - 1 && localFrame <= w.endFrame + 8) {
152
+ activeWordIdx = i;
153
+ }
154
+ }
155
+ const isVertical = height > width;
156
+ const isLight = variant === "light";
157
+ const textPrimary = isLight ? import_theme.STUDIO_THEME.colors.text.slate900 : import_theme.THEME.colors.textPrimary;
158
+ const resolvedFontSize = fontSize ?? (isVertical ? 64 : 74);
159
+ const containerPaddingStyle = isVertical && safeBox9x16 ? {
160
+ paddingLeft: Math.round(44 * (width / 1080)),
161
+ paddingRight: Math.round((1080 - 906) * (width / 1080)),
162
+ paddingTop: Math.round(230 * (height / 1920)),
163
+ paddingBottom: Math.round((1920 - 1370) * (height / 1920))
164
+ } : {
165
+ padding: "72px 120px"
166
+ };
167
+ const beatProgress = (0, import_remotion.interpolate)(
168
+ localFrame,
169
+ [activeBeat.startFrame, Math.max(activeBeat.startFrame + 1, activeBeat.endFrame)],
170
+ [0, 1],
171
+ { extrapolateLeft: "clamp", extrapolateRight: "clamp" }
172
+ );
173
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
174
+ import_remotion.AbsoluteFill,
175
+ {
176
+ style: {
177
+ backgroundColor: variant === "dark" ? import_theme.THEME.colors.bgPrimary : variant === "light" ? import_theme.STUDIO_THEME.colors.bgCanvas : "transparent",
178
+ display: "flex",
179
+ flexDirection: "column",
180
+ alignItems: "center",
181
+ justifyContent: "center",
182
+ boxSizing: "border-box",
183
+ opacity: stageEnter,
184
+ pointerEvents: "none",
185
+ ...containerPaddingStyle,
186
+ ...style
187
+ },
188
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
189
+ "div",
190
+ {
191
+ style: {
192
+ maxWidth: isVertical ? 840 : 1420,
193
+ width: "100%",
194
+ display: "flex",
195
+ flexDirection: "column",
196
+ alignItems: "center",
197
+ gap: 24,
198
+ transform: `translateY(${(0, import_remotion.interpolate)(beatEnter, [0, 1], [16, 0]).toFixed(2)}px) scale(${(0, import_remotion.interpolate)(stageEnter, [0, 1], [0.95, 1]).toFixed(4)})`
199
+ },
200
+ children: [
201
+ eyebrow && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
202
+ "div",
203
+ {
204
+ style: {
205
+ fontFamily: import_theme.FONTS.mono,
206
+ fontSize: isVertical ? 18 : 19,
207
+ fontWeight: 700,
208
+ letterSpacing: "0.08em",
209
+ textTransform: "uppercase",
210
+ padding: "8px 18px",
211
+ borderRadius: 9999,
212
+ color: isLight ? accentColor : "#FFFFFF",
213
+ backgroundColor: isLight ? `${accentColor}16` : `${accentColor}33`,
214
+ border: `1.5px solid ${accentColor}66`
215
+ },
216
+ children: eyebrow
217
+ }
218
+ ),
219
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
220
+ "div",
221
+ {
222
+ style: {
223
+ display: "flex",
224
+ flexWrap: "wrap",
225
+ justifyContent: "center",
226
+ alignItems: "center",
227
+ gap: isVertical ? "14px 16px" : "16px 22px",
228
+ textAlign: "center"
229
+ },
230
+ children: activeBeat.words.map((w, idx) => {
231
+ const isCurrent = idx === activeWordIdx;
232
+ const isPast = localFrame > w.endFrame + 8;
233
+ const wordPop = (0, import_remotion.spring)({
234
+ frame: Math.max(0, localFrame - w.startFrame),
235
+ fps,
236
+ config: import_theme.SPRING_PRESETS.micro
237
+ });
238
+ const scale = isCurrent ? (0, import_remotion.interpolate)(wordPop, [0, 1], [0.96, 1.07]) : 1;
239
+ const yShift = isCurrent || isPast ? 0 : (0, import_remotion.interpolate)(wordPop, [0, 1], [6, 0]);
240
+ const wordOpacity = isCurrent ? 1 : isPast ? 0.94 : 0.38;
241
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
242
+ "span",
243
+ {
244
+ style: {
245
+ display: "inline-block",
246
+ fontFamily: import_theme.FONTS.display,
247
+ fontSize: resolvedFontSize,
248
+ fontWeight: 800,
249
+ lineHeight: 1.15,
250
+ letterSpacing: "-0.025em",
251
+ padding: isCurrent ? "6px 20px" : "6px 8px",
252
+ borderRadius: 18,
253
+ color: isCurrent ? "#FFFFFF" : textPrimary,
254
+ backgroundColor: isCurrent ? accentColor : "transparent",
255
+ boxShadow: isCurrent ? `0 14px 36px ${accentColor}66, 0 0 0 2px rgba(255,255,255,0.22) inset` : "none",
256
+ opacity: wordOpacity,
257
+ transform: `translateY(${yShift.toFixed(2)}px) scale(${scale.toFixed(4)})`,
258
+ textShadow: !isCurrent && variant === "transparent" ? "0 4px 22px rgba(9, 10, 15, 0.55)" : "none"
259
+ },
260
+ children: w.word
261
+ },
262
+ `${activeBeatIndex}-${idx}-${w.startFrame}`
263
+ );
264
+ })
265
+ }
266
+ ),
267
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
268
+ "div",
269
+ {
270
+ style: {
271
+ width: isVertical ? 220 : 280,
272
+ height: 5,
273
+ borderRadius: 9999,
274
+ backgroundColor: isLight ? "rgba(15, 23, 42, 0.10)" : "rgba(255, 255, 255, 0.14)",
275
+ overflow: "hidden"
276
+ },
277
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
278
+ "div",
279
+ {
280
+ style: {
281
+ width: `${Math.round(beatProgress * 100)}%`,
282
+ height: "100%",
283
+ borderRadius: 9999,
284
+ backgroundColor: accentColor
285
+ }
286
+ }
287
+ )
288
+ }
289
+ )
290
+ ]
291
+ }
292
+ )
293
+ }
294
+ );
295
+ };
296
+
297
+ // packages/kits/src/kinetic-typography/ImpactKeywordCard.tsx
298
+ var import_lucide_react = require("lucide-react");
299
+ var import_remotion2 = require("remotion");
300
+ var import_theme2 = require("@make-pictures/core");
301
+ var import_jsx_runtime2 = require("react/jsx-runtime");
302
+ var ImpactKeywordCard = ({
303
+ keyword,
304
+ eyebrow,
305
+ sublabel,
306
+ badge,
307
+ icon,
308
+ accentColor = import_theme2.STUDIO_THEME.colors.brand[600],
309
+ variant = "dark",
310
+ enterFrame,
311
+ startFrame,
312
+ exitFrame,
313
+ safeBox9x16 = true,
314
+ style
315
+ }) => {
316
+ const frame = (0, import_remotion2.useCurrentFrame)();
317
+ const { fps, width, height } = (0, import_remotion2.useVideoConfig)();
318
+ (0, import_theme2.useStudioFontsReady)();
319
+ const effectiveStart = Math.max(2, startFrame ?? enterFrame ?? 2);
320
+ const enter = (0, import_remotion2.spring)({
321
+ frame: frame - effectiveStart,
322
+ fps,
323
+ config: import_theme2.SPRING_PRESETS.snappy
324
+ });
325
+ const exit = typeof exitFrame === "number" ? (0, import_remotion2.spring)({
326
+ frame: frame - exitFrame,
327
+ fps,
328
+ config: import_theme2.SPRING_PRESETS.smooth
329
+ }) : 0;
330
+ const visibility = Math.max(0, enter * (1 - exit));
331
+ if (visibility <= 5e-3) {
332
+ return null;
333
+ }
334
+ const isVertical = height > width;
335
+ const isLight = variant === "light";
336
+ const translateY = (0, import_remotion2.interpolate)(enter, [0, 1], [28, 0]) - exit * 18;
337
+ const scale = (0, import_remotion2.interpolate)(visibility, [0, 1], [0.93, 1]);
338
+ const accentBarScale = (0, import_remotion2.spring)({
339
+ frame: frame - effectiveStart - 4,
340
+ fps,
341
+ config: import_theme2.SPRING_PRESETS.smooth
342
+ });
343
+ const resolvedIcon = icon === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Sparkles, { size: isVertical ? 30 : 34, color: "#FFFFFF", strokeWidth: 2.4 }) : icon;
344
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
345
+ "div",
346
+ {
347
+ style: {
348
+ position: "relative",
349
+ display: "inline-flex",
350
+ alignItems: "center",
351
+ gap: isVertical ? 22 : 28,
352
+ maxWidth: isVertical && safeBox9x16 ? 830 : 1080,
353
+ padding: isVertical ? "28px 34px" : "32px 42px",
354
+ borderRadius: 26,
355
+ boxSizing: "border-box",
356
+ backgroundColor: isLight ? import_theme2.STUDIO_THEME.colors.bgSurfaceGlass : "rgba(13, 15, 26, 0.86)",
357
+ border: isLight ? `1.5px solid ${import_theme2.STUDIO_THEME.colors.border.subtle}` : `1.5px solid rgba(255, 255, 255, 0.14)`,
358
+ boxShadow: isLight ? import_theme2.STUDIO_THEME.shadows.cardElevated : import_theme2.THEME.shadows.glow(accentColor, 0.9),
359
+ backdropFilter: "blur(16px)",
360
+ opacity: visibility,
361
+ transform: `translate3d(0, ${translateY.toFixed(2)}px, 0) scale(${scale.toFixed(4)})`,
362
+ overflow: "hidden",
363
+ ...style
364
+ },
365
+ children: [
366
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
367
+ "div",
368
+ {
369
+ style: {
370
+ position: "absolute",
371
+ left: 0,
372
+ top: 0,
373
+ bottom: 0,
374
+ width: 8,
375
+ backgroundColor: accentColor,
376
+ transformOrigin: "top center",
377
+ transform: `scaleY(${accentBarScale.toFixed(4)})`
378
+ }
379
+ }
380
+ ),
381
+ resolvedIcon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
382
+ "div",
383
+ {
384
+ style: {
385
+ width: isVertical ? 64 : 72,
386
+ height: isVertical ? 64 : 72,
387
+ borderRadius: 20,
388
+ flexShrink: 0,
389
+ display: "flex",
390
+ alignItems: "center",
391
+ justifyContent: "center",
392
+ background: `linear-gradient(135deg, ${accentColor} 0%, ${accentColor}CC 100%)`,
393
+ boxShadow: `0 12px 28px ${accentColor}55`
394
+ },
395
+ children: resolvedIcon
396
+ }
397
+ ),
398
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
399
+ "div",
400
+ {
401
+ style: {
402
+ display: "flex",
403
+ flexDirection: "column",
404
+ gap: 6,
405
+ minWidth: 0
406
+ },
407
+ children: [
408
+ (eyebrow || badge) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
409
+ "div",
410
+ {
411
+ style: {
412
+ display: "flex",
413
+ alignItems: "center",
414
+ gap: 12,
415
+ flexWrap: "wrap"
416
+ },
417
+ children: [
418
+ eyebrow && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
419
+ "span",
420
+ {
421
+ style: {
422
+ fontFamily: import_theme2.FONTS.mono,
423
+ fontSize: 15,
424
+ fontWeight: 700,
425
+ letterSpacing: "0.08em",
426
+ textTransform: "uppercase",
427
+ color: isLight ? import_theme2.STUDIO_THEME.colors.text.muted : import_theme2.THEME.colors.textSecondary
428
+ },
429
+ children: eyebrow
430
+ }
431
+ ),
432
+ badge && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
433
+ "span",
434
+ {
435
+ style: {
436
+ fontFamily: import_theme2.FONTS.mono,
437
+ fontSize: 14,
438
+ fontWeight: 700,
439
+ padding: "3px 11px",
440
+ borderRadius: 9999,
441
+ color: "#FFFFFF",
442
+ backgroundColor: accentColor
443
+ },
444
+ children: badge
445
+ }
446
+ )
447
+ ]
448
+ }
449
+ ),
450
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
451
+ "div",
452
+ {
453
+ style: {
454
+ fontFamily: import_theme2.FONTS.display,
455
+ fontSize: isVertical ? 44 : 52,
456
+ fontWeight: 800,
457
+ lineHeight: 1.1,
458
+ letterSpacing: "-0.025em",
459
+ color: isLight ? import_theme2.STUDIO_THEME.colors.text.slate900 : import_theme2.THEME.colors.textPrimary
460
+ },
461
+ children: keyword
462
+ }
463
+ ),
464
+ sublabel && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
465
+ "div",
466
+ {
467
+ style: {
468
+ fontFamily: import_theme2.FONTS.sans,
469
+ fontSize: isVertical ? 20 : 22,
470
+ fontWeight: 500,
471
+ color: isLight ? import_theme2.STUDIO_THEME.colors.text.secondary : import_theme2.THEME.colors.textSecondary
472
+ },
473
+ children: sublabel
474
+ }
475
+ )
476
+ ]
477
+ }
478
+ )
479
+ ]
480
+ }
481
+ );
482
+ };
483
+
484
+ // packages/kits/src/kinetic-typography/AnimatedMetricCounter.tsx
485
+ var import_remotion3 = require("remotion");
486
+ var import_theme3 = require("@make-pictures/core");
487
+ var import_jsx_runtime3 = require("react/jsx-runtime");
488
+ function formatTabularMetric(val, decimals = 0, thousandSeparator = ",") {
489
+ const safeDecimals = Math.max(0, Math.min(6, Math.round(decimals)));
490
+ const fixed = val.toFixed(safeDecimals);
491
+ const [intPart, decPart] = fixed.split(".");
492
+ const sign = intPart.startsWith("-") ? "-" : "";
493
+ const digits = sign ? intPart.slice(1) : intPart;
494
+ const grouped = thousandSeparator ? digits.replace(/\B(?=(\d{3})+(?!\d))/g, thousandSeparator) : digits;
495
+ return decPart !== void 0 ? `${sign}${grouped}.${decPart}` : `${sign}${grouped}`;
496
+ }
497
+ var AnimatedMetricCounter = ({
498
+ value,
499
+ fromValue = 0,
500
+ prefix = "",
501
+ suffix = "",
502
+ decimals = 0,
503
+ startFrame = 2,
504
+ durationInFrames = 54,
505
+ label,
506
+ badge,
507
+ accentColor = import_theme3.STUDIO_THEME.colors.accents.emerald,
508
+ variant = "dark",
509
+ thousandSeparator = ",",
510
+ fontSize,
511
+ style
512
+ }) => {
513
+ const frame = (0, import_remotion3.useCurrentFrame)();
514
+ const { fps, width, height } = (0, import_remotion3.useVideoConfig)();
515
+ (0, import_theme3.useStudioFontsReady)();
516
+ const effectiveStart = Math.max(2, startFrame);
517
+ const dur = Math.max(6, durationInFrames);
518
+ const enter = (0, import_remotion3.spring)({
519
+ frame: frame - effectiveStart,
520
+ fps,
521
+ config: import_theme3.SPRING_PRESETS.snappy
522
+ });
523
+ const countProgress = (0, import_remotion3.interpolate)(
524
+ frame,
525
+ [effectiveStart, effectiveStart + dur],
526
+ [0, 1],
527
+ {
528
+ easing: import_remotion3.Easing.out(import_remotion3.Easing.cubic),
529
+ extrapolateLeft: "clamp",
530
+ extrapolateRight: "clamp"
531
+ }
532
+ );
533
+ const currentVal = fromValue + (value - fromValue) * countProgress;
534
+ const formatted = `${prefix}${formatTabularMetric(
535
+ currentVal,
536
+ decimals,
537
+ thousandSeparator
538
+ )}${suffix}`;
539
+ if (variant === "inline") {
540
+ if (frame === 0 && startFrame >= 1) {
541
+ return null;
542
+ }
543
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
544
+ "span",
545
+ {
546
+ style: {
547
+ fontFamily: import_theme3.FONTS.display,
548
+ fontVariantNumeric: "tabular-nums",
549
+ fontWeight: 800,
550
+ letterSpacing: "-0.03em",
551
+ fontSize: fontSize ?? 56,
552
+ opacity: enter,
553
+ ...style
554
+ },
555
+ children: formatted
556
+ }
557
+ );
558
+ }
559
+ if (enter <= 5e-3) {
560
+ return null;
561
+ }
562
+ const isVertical = height > width;
563
+ const isLight = variant === "light";
564
+ const resolvedFontSize = fontSize ?? (isVertical ? 68 : 76);
565
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
566
+ "div",
567
+ {
568
+ style: {
569
+ display: "inline-flex",
570
+ flexDirection: "column",
571
+ alignItems: "flex-start",
572
+ gap: 10,
573
+ padding: isVertical ? "26px 32px" : "30px 38px",
574
+ borderRadius: 24,
575
+ boxSizing: "border-box",
576
+ backgroundColor: isLight ? import_theme3.STUDIO_THEME.colors.bgSurfaceGlass : "rgba(13, 15, 26, 0.86)",
577
+ border: isLight ? `1.5px solid ${import_theme3.STUDIO_THEME.colors.border.subtle}` : "1.5px solid rgba(255, 255, 255, 0.12)",
578
+ boxShadow: isLight ? import_theme3.STUDIO_THEME.shadows.cardElevated : import_theme3.THEME.shadows.glow(accentColor, 0.75),
579
+ opacity: enter,
580
+ transform: `translateY(${(0, import_remotion3.interpolate)(enter, [0, 1], [22, 0]).toFixed(2)}px) scale(${(0, import_remotion3.interpolate)(enter, [0, 1], [0.94, 1]).toFixed(4)})`,
581
+ ...style
582
+ },
583
+ children: [
584
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
585
+ "div",
586
+ {
587
+ style: {
588
+ display: "flex",
589
+ alignItems: "baseline",
590
+ gap: 14
591
+ },
592
+ children: [
593
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
594
+ "span",
595
+ {
596
+ style: {
597
+ fontFamily: import_theme3.FONTS.display,
598
+ fontVariantNumeric: "tabular-nums",
599
+ fontSize: resolvedFontSize,
600
+ fontWeight: 800,
601
+ lineHeight: 1,
602
+ letterSpacing: "-0.035em",
603
+ color: isLight ? import_theme3.STUDIO_THEME.colors.text.slate900 : import_theme3.THEME.colors.textPrimary
604
+ },
605
+ children: formatted
606
+ }
607
+ ),
608
+ badge && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
609
+ "span",
610
+ {
611
+ style: {
612
+ fontFamily: import_theme3.FONTS.mono,
613
+ fontSize: 15,
614
+ fontWeight: 700,
615
+ padding: "5px 12px",
616
+ borderRadius: 9999,
617
+ color: "#FFFFFF",
618
+ backgroundColor: accentColor
619
+ },
620
+ children: badge
621
+ }
622
+ )
623
+ ]
624
+ }
625
+ ),
626
+ label && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
627
+ "div",
628
+ {
629
+ style: {
630
+ fontFamily: import_theme3.FONTS.sans,
631
+ fontSize: isVertical ? 20 : 21,
632
+ fontWeight: 600,
633
+ color: isLight ? import_theme3.STUDIO_THEME.colors.text.secondary : import_theme3.THEME.colors.textSecondary
634
+ },
635
+ children: label
636
+ }
637
+ ),
638
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
639
+ "div",
640
+ {
641
+ style: {
642
+ width: "100%",
643
+ height: 5,
644
+ marginTop: 4,
645
+ borderRadius: 9999,
646
+ backgroundColor: isLight ? "rgba(15, 23, 42, 0.08)" : "rgba(255, 255, 255, 0.12)",
647
+ overflow: "hidden"
648
+ },
649
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
650
+ "div",
651
+ {
652
+ style: {
653
+ width: `${Math.round(countProgress * 100)}%`,
654
+ height: "100%",
655
+ borderRadius: 9999,
656
+ backgroundColor: accentColor
657
+ }
658
+ }
659
+ )
660
+ }
661
+ )
662
+ ]
663
+ }
664
+ );
665
+ };
@@ -0,0 +1,3 @@
1
+ export * from './WordByWordStage';
2
+ export * from './ImpactKeywordCard';
3
+ export * from './AnimatedMetricCounter';
@@ -0,0 +1,14 @@
1
+ import {
2
+ AnimatedMetricCounter,
3
+ ImpactKeywordCard,
4
+ WordByWordStage,
5
+ formatTabularMetric,
6
+ groupWordsIntoBeats
7
+ } from "../chunk-AHA23PHC.mjs";
8
+ export {
9
+ AnimatedMetricCounter,
10
+ ImpactKeywordCard,
11
+ WordByWordStage,
12
+ formatTabularMetric,
13
+ groupWordsIntoBeats
14
+ };