@meframe/core 0.4.7 → 0.5.1

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 (50) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +2 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/model/CompositionModel.d.ts +6 -0
  6. package/dist/model/CompositionModel.d.ts.map +1 -1
  7. package/dist/model/CompositionModel.js +49 -1
  8. package/dist/model/CompositionModel.js.map +1 -1
  9. package/dist/model/types.d.ts +8 -2
  10. package/dist/model/types.d.ts.map +1 -1
  11. package/dist/model/types.js +4 -0
  12. package/dist/model/types.js.map +1 -1
  13. package/dist/orchestrator/CompositionPlanner.d.ts +1 -0
  14. package/dist/orchestrator/CompositionPlanner.d.ts.map +1 -1
  15. package/dist/orchestrator/CompositionPlanner.js +22 -1
  16. package/dist/orchestrator/CompositionPlanner.js.map +1 -1
  17. package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
  18. package/dist/orchestrator/Orchestrator.js +8 -1
  19. package/dist/orchestrator/Orchestrator.js.map +1 -1
  20. package/dist/stages/compose/LayerRenderer.d.ts.map +1 -1
  21. package/dist/stages/compose/LayerRenderer.js +20 -9
  22. package/dist/stages/compose/LayerRenderer.js.map +1 -1
  23. package/dist/stages/compose/font-system/types.d.ts +1 -1
  24. package/dist/stages/compose/font-system/types.d.ts.map +1 -1
  25. package/dist/stages/compose/instructions.d.ts +1 -1
  26. package/dist/stages/compose/instructions.d.ts.map +1 -1
  27. package/dist/stages/compose/text-layer-animation-time.d.ts +8 -0
  28. package/dist/stages/compose/text-layer-animation-time.d.ts.map +1 -0
  29. package/dist/stages/compose/text-layer-animation-time.js +22 -0
  30. package/dist/stages/compose/text-layer-animation-time.js.map +1 -0
  31. package/dist/stages/compose/text-renderers/basic-text-renderer.js +1 -21
  32. package/dist/stages/compose/text-renderers/basic-text-renderer.js.map +1 -1
  33. package/dist/stages/compose/text-renderers/caption-stagger-entrance-renderer.d.ts +9 -0
  34. package/dist/stages/compose/text-renderers/caption-stagger-entrance-renderer.d.ts.map +1 -0
  35. package/dist/stages/compose/text-renderers/caption-stagger-entrance-renderer.js +188 -0
  36. package/dist/stages/compose/text-renderers/caption-stagger-entrance-renderer.js.map +1 -0
  37. package/dist/stages/compose/text-renderers/word-fancy-renderer.js +1 -1
  38. package/dist/stages/compose/text-utils/caption-layout.d.ts +63 -0
  39. package/dist/stages/compose/text-utils/caption-layout.d.ts.map +1 -0
  40. package/dist/stages/compose/text-utils/caption-layout.js +129 -0
  41. package/dist/stages/compose/text-utils/caption-layout.js.map +1 -0
  42. package/dist/stages/compose/text-utils/index.d.ts +1 -0
  43. package/dist/stages/compose/text-utils/index.d.ts.map +1 -1
  44. package/dist/stages/compose/types.d.ts +3 -1
  45. package/dist/stages/compose/types.d.ts.map +1 -1
  46. package/dist/workers/stages/export/{export.worker.Cw9iPvkh.js → export.worker.Dztm6GuN.js} +218 -28
  47. package/dist/workers/stages/export/export.worker.Dztm6GuN.js.map +1 -0
  48. package/dist/workers/worker-manifest.json +1 -1
  49. package/package.json +1 -1
  50. package/dist/workers/stages/export/export.worker.Cw9iPvkh.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../../src/stages/compose/instructions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../../src/stages/compose/instructions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { TextLayer } from './types';
2
+
3
+ export declare function attachmentEntranceRelativeTimeUs(clipRelativeTimeUs: number, activeRanges: Array<{
4
+ startUs: number;
5
+ endUs: number;
6
+ }> | undefined): number | undefined;
7
+ export declare function textAnimationFrameForTextLayer(layer: TextLayer, fallbackFrame: number, fps: number): number;
8
+ //# sourceMappingURL=text-layer-animation-time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-layer-animation-time.d.ts","sourceRoot":"","sources":["../../../src/stages/compose/text-layer-animation-time.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,wBAAgB,gCAAgC,CAC9C,kBAAkB,EAAE,MAAM,EAC1B,YAAY,EAAE,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,SAAS,GAClE,MAAM,GAAG,SAAS,CAQpB;AAED,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,SAAS,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,GACV,MAAM,CAOR"}
@@ -0,0 +1,22 @@
1
+ function attachmentEntranceRelativeTimeUs(clipRelativeTimeUs, activeRanges) {
2
+ const containing = activeRanges?.find(
3
+ (r) => clipRelativeTimeUs >= r.startUs && clipRelativeTimeUs < r.endUs
4
+ );
5
+ if (!containing) {
6
+ return void 0;
7
+ }
8
+ return Math.max(0, clipRelativeTimeUs - containing.startUs);
9
+ }
10
+ function textAnimationFrameForTextLayer(layer, fallbackFrame, fps) {
11
+ const et = layer.entranceRelativeTimeUs;
12
+ if (et != null && Number.isFinite(et)) {
13
+ const frameDurationUs = 1e6 / fps;
14
+ return Math.floor(et / frameDurationUs);
15
+ }
16
+ return fallbackFrame;
17
+ }
18
+ export {
19
+ attachmentEntranceRelativeTimeUs,
20
+ textAnimationFrameForTextLayer
21
+ };
22
+ //# sourceMappingURL=text-layer-animation-time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-layer-animation-time.js","sources":["../../../src/stages/compose/text-layer-animation-time.ts"],"sourcesContent":["import type { TextLayer } from './types';\n\nexport function attachmentEntranceRelativeTimeUs(\n clipRelativeTimeUs: number,\n activeRanges: Array<{ startUs: number; endUs: number }> | undefined\n): number | undefined {\n const containing = activeRanges?.find(\n (r) => clipRelativeTimeUs >= r.startUs && clipRelativeTimeUs < r.endUs\n );\n if (!containing) {\n return undefined;\n }\n return Math.max(0, clipRelativeTimeUs - containing.startUs);\n}\n\nexport function textAnimationFrameForTextLayer(\n layer: TextLayer,\n fallbackFrame: number,\n fps: number\n): number {\n const et = layer.entranceRelativeTimeUs;\n if (et != null && Number.isFinite(et)) {\n const frameDurationUs = 1_000_000 / fps;\n return Math.floor(et / frameDurationUs);\n }\n return fallbackFrame;\n}\n"],"names":[],"mappings":"AAEO,SAAS,iCACd,oBACA,cACoB;AACpB,QAAM,aAAa,cAAc;AAAA,IAC/B,CAAC,MAAM,sBAAsB,EAAE,WAAW,qBAAqB,EAAE;AAAA,EAAA;AAEnE,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AACA,SAAO,KAAK,IAAI,GAAG,qBAAqB,WAAW,OAAO;AAC5D;AAEO,SAAS,+BACd,OACA,eACA,KACQ;AACR,QAAM,KAAK,MAAM;AACjB,MAAI,MAAM,QAAQ,OAAO,SAAS,EAAE,GAAG;AACrC,UAAM,kBAAkB,MAAY;AACpC,WAAO,KAAK,MAAM,KAAK,eAAe;AAAA,EACxC;AACA,SAAO;AACT;"}
@@ -1,6 +1,5 @@
1
1
  import { formEvenLinesWithWords, wrapText } from "../text-utils/text-wrapper.js";
2
2
  import { getLetterCaseText } from "../text-utils/text-metrics.js";
3
- import { interpolate, springEasing } from "./animation-utils.js";
4
3
  import { needsSpaceBetweenWords } from "../text-utils/locale-detector.js";
5
4
  function calculateYPosition(canvasHeight, totalHeight, globalPosition) {
6
5
  if (!globalPosition) {
@@ -68,26 +67,7 @@ function renderBasicText(ctx, layer, canvasWidth, canvasHeight, _relativeFrame)
68
67
  }
69
68
  ctx.restore();
70
69
  }
71
- function renderTextWithEntrance(ctx, layer, canvasWidth, canvasHeight, relativeFrame) {
72
- const fontConfig = layer.fontConfig?.textStyle;
73
- if (!fontConfig) return;
74
- const entrance = springEasing(relativeFrame, {
75
- damping: 200,
76
- mass: 1,
77
- stiffness: 300
78
- });
79
- const opacity = interpolate(entrance, [0, 1], [0, 1]);
80
- const scale = interpolate(entrance, [0, 1], [0.9, 1]);
81
- ctx.save();
82
- ctx.globalAlpha = opacity;
83
- ctx.translate(canvasWidth / 2, canvasHeight / 2);
84
- ctx.scale(scale, scale);
85
- ctx.translate(-canvasWidth / 2, -canvasHeight / 2);
86
- renderBasicText(ctx, layer, canvasWidth, canvasHeight);
87
- ctx.restore();
88
- }
89
70
  export {
90
- renderBasicText,
91
- renderTextWithEntrance
71
+ renderBasicText
92
72
  };
93
73
  //# sourceMappingURL=basic-text-renderer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"basic-text-renderer.js","sources":["../../../../src/stages/compose/text-renderers/basic-text-renderer.ts"],"sourcesContent":["import type { TextLayer } from '../types';\nimport { wrapText, formEvenLinesWithWords } from '../text-utils/text-wrapper';\nimport { getLetterCaseText } from '../text-utils/text-metrics';\nimport { springEasing, interpolate } from './animation-utils';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\nfunction calculateYPosition(\n canvasHeight: number,\n totalHeight: number,\n globalPosition?: {\n position?: 'absolute';\n top?: string;\n bottom?: string;\n left?: string;\n right?: string;\n display?: string;\n alignItems?: string;\n justifyContent?: string;\n }\n): number {\n if (!globalPosition) {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n // Handle percentage-based positioning\n if (globalPosition.top) {\n const topPercent = parseFloat(globalPosition.top) / 100;\n return canvasHeight * topPercent;\n }\n\n if (globalPosition.bottom) {\n const bottomPercent = parseFloat(globalPosition.bottom) / 100;\n return canvasHeight * (1 - bottomPercent) - totalHeight;\n }\n\n // Handle center alignment\n if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n // Default to center\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderBasicText(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n _relativeFrame: number\n): void {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return;\n\n const fontSize = fontConfig.fontSize;\n const fontFamily = fontConfig.fontFamily;\n const fontWeight = fontConfig.fontWeight;\n const fill = fontConfig.fill;\n const stroke = fontConfig.stroke;\n const strokeWidth = fontConfig.strokeWidth || 0;\n const lineHeight = fontConfig.lineHeight || 1.2;\n\n const maxWidth = canvasWidth * 0.64;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n\n let lines: string[];\n if (layer.wordTimings && layer.wordTimings.length > 0) {\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const words = text.split(needsSpace ? /\\s+/ : '');\n lines = formEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n } else {\n lines = wrapText(ctx, text, maxWidth, fontSize, fontFamily, fontWeight);\n }\n\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.lineJoin = 'round';\n ctx.lineCap = 'round';\n\n const totalHeight = lines.length * fontSize * lineHeight;\n const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const y = startY + i * fontSize * lineHeight + fontSize / 2;\n\n if (stroke && strokeWidth > 0) {\n ctx.strokeStyle = stroke;\n ctx.lineWidth = strokeWidth;\n ctx.strokeText(line, canvasWidth / 2, y);\n }\n ctx.fillStyle = fill;\n ctx.fillText(line, canvasWidth / 2, y);\n }\n\n ctx.restore();\n}\n\nexport function renderTextWithEntrance(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number\n): void {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return;\n\n const entrance = springEasing(relativeFrame, {\n damping: 200,\n mass: 1,\n stiffness: 300,\n });\n\n const opacity = interpolate(entrance, [0, 1], [0, 1]);\n const scale = interpolate(entrance, [0, 1], [0.9, 1]);\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.translate(canvasWidth / 2, canvasHeight / 2);\n ctx.scale(scale, scale);\n ctx.translate(-canvasWidth / 2, -canvasHeight / 2);\n\n renderBasicText(ctx, layer, canvasWidth, canvasHeight, relativeFrame);\n\n ctx.restore();\n}\n"],"names":[],"mappings":";;;;AAMA,SAAS,mBACP,cACA,aACA,gBAUQ;AACR,MAAI,CAAC,gBAAgB;AACnB,WAAO,eAAe,IAAI,cAAc;AAAA,EAC1C;AAGA,MAAI,eAAe,KAAK;AACtB,UAAM,aAAa,WAAW,eAAe,GAAG,IAAI;AACpD,WAAO,eAAe;AAAA,EACxB;AAEA,MAAI,eAAe,QAAQ;AACzB,UAAM,gBAAgB,WAAW,eAAe,MAAM,IAAI;AAC1D,WAAO,gBAAgB,IAAI,iBAAiB;AAAA,EAC9C;AAGA,MAAI,eAAe,mBAAmB,YAAY,eAAe,eAAe,UAAU;AACxF,WAAO,eAAe,IAAI,cAAc;AAAA,EAC1C;AAGA,SAAO,eAAe,IAAI,cAAc;AAC1C;AAEO,SAAS,gBACd,KACA,OACA,aACA,cACA,gBACM;AACN,QAAM,aAAa,MAAM,YAAY;AACrC,MAAI,CAAC,WAAY;AAEjB,QAAM,WAAW,WAAW;AAC5B,QAAM,aAAa,WAAW;AAC9B,QAAM,aAAa,WAAW;AAC9B,QAAM,OAAO,WAAW;AACxB,QAAM,SAAS,WAAW;AAC1B,QAAM,cAAc,WAAW,eAAe;AAC9C,QAAM,aAAa,WAAW,cAAc;AAE5C,QAAM,WAAW,cAAc;AAC/B,QAAM,OAAO,kBAAkB,MAAM,MAAM,MAAM,UAAU;AAE3D,MAAI;AACJ,MAAI,MAAM,eAAe,MAAM,YAAY,SAAS,GAAG;AACrD,UAAM,aAAa,uBAAuB,MAAM,cAAc,SAAS,IAAI;AAC3E,UAAM,QAAQ,KAAK,MAAM,aAAa,QAAQ,EAAE;AAChD,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ,OAAO;AACL,YAAQ,SAAS,KAAK,MAAM,UAAU,UAAU,YAAY,UAAU;AAAA,EACxE;AAEA,MAAI,KAAA;AACJ,MAAI,OAAO,GAAG,UAAU,IAAI,QAAQ,MAAM,UAAU;AACpD,MAAI,YAAY;AAChB,MAAI,eAAe;AACnB,MAAI,WAAW;AACf,MAAI,UAAU;AAEd,QAAM,cAAc,MAAM,SAAS,WAAW;AAC9C,QAAM,SAAS,mBAAmB,cAAc,aAAa,MAAM,YAAY,cAAc;AAE7F,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,IAAI,SAAS,IAAI,WAAW,aAAa,WAAW;AAE1D,QAAI,UAAU,cAAc,GAAG;AAC7B,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,WAAW,MAAM,cAAc,GAAG,CAAC;AAAA,IACzC;AACA,QAAI,YAAY;AAChB,QAAI,SAAS,MAAM,cAAc,GAAG,CAAC;AAAA,EACvC;AAEA,MAAI,QAAA;AACN;AAEO,SAAS,uBACd,KACA,OACA,aACA,cACA,eACM;AACN,QAAM,aAAa,MAAM,YAAY;AACrC,MAAI,CAAC,WAAY;AAEjB,QAAM,WAAW,aAAa,eAAe;AAAA,IAC3C,SAAS;AAAA,IACT,MAAM;AAAA,IACN,WAAW;AAAA,EAAA,CACZ;AAED,QAAM,UAAU,YAAY,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACpD,QAAM,QAAQ,YAAY,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAEpD,MAAI,KAAA;AACJ,MAAI,cAAc;AAClB,MAAI,UAAU,cAAc,GAAG,eAAe,CAAC;AAC/C,MAAI,MAAM,OAAO,KAAK;AACtB,MAAI,UAAU,CAAC,cAAc,GAAG,CAAC,eAAe,CAAC;AAEjD,kBAAgB,KAAK,OAAO,aAAa,YAA2B;AAEpE,MAAI,QAAA;AACN;"}
1
+ {"version":3,"file":"basic-text-renderer.js","sources":["../../../../src/stages/compose/text-renderers/basic-text-renderer.ts"],"sourcesContent":["import type { TextLayer } from '../types';\nimport { wrapText, formEvenLinesWithWords } from '../text-utils/text-wrapper';\nimport { getLetterCaseText } from '../text-utils/text-metrics';\nimport { springEasing, interpolate } from './animation-utils';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\nfunction calculateYPosition(\n canvasHeight: number,\n totalHeight: number,\n globalPosition?: {\n position?: 'absolute';\n top?: string;\n bottom?: string;\n left?: string;\n right?: string;\n display?: string;\n alignItems?: string;\n justifyContent?: string;\n }\n): number {\n if (!globalPosition) {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n // Handle percentage-based positioning\n if (globalPosition.top) {\n const topPercent = parseFloat(globalPosition.top) / 100;\n return canvasHeight * topPercent;\n }\n\n if (globalPosition.bottom) {\n const bottomPercent = parseFloat(globalPosition.bottom) / 100;\n return canvasHeight * (1 - bottomPercent) - totalHeight;\n }\n\n // Handle center alignment\n if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n // Default to center\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderBasicText(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n _relativeFrame: number\n): void {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return;\n\n const fontSize = fontConfig.fontSize;\n const fontFamily = fontConfig.fontFamily;\n const fontWeight = fontConfig.fontWeight;\n const fill = fontConfig.fill;\n const stroke = fontConfig.stroke;\n const strokeWidth = fontConfig.strokeWidth || 0;\n const lineHeight = fontConfig.lineHeight || 1.2;\n\n const maxWidth = canvasWidth * 0.64;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n\n let lines: string[];\n if (layer.wordTimings && layer.wordTimings.length > 0) {\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const words = text.split(needsSpace ? /\\s+/ : '');\n lines = formEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n } else {\n lines = wrapText(ctx, text, maxWidth, fontSize, fontFamily, fontWeight);\n }\n\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.lineJoin = 'round';\n ctx.lineCap = 'round';\n\n const totalHeight = lines.length * fontSize * lineHeight;\n const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const y = startY + i * fontSize * lineHeight + fontSize / 2;\n\n if (stroke && strokeWidth > 0) {\n ctx.strokeStyle = stroke;\n ctx.lineWidth = strokeWidth;\n ctx.strokeText(line, canvasWidth / 2, y);\n }\n ctx.fillStyle = fill;\n ctx.fillText(line, canvasWidth / 2, y);\n }\n\n ctx.restore();\n}\n\nexport function renderTextWithEntrance(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number\n): void {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return;\n\n const entrance = springEasing(relativeFrame, {\n damping: 200,\n mass: 1,\n stiffness: 300,\n });\n\n const opacity = interpolate(entrance, [0, 1], [0, 1]);\n const scale = interpolate(entrance, [0, 1], [0.9, 1]);\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.translate(canvasWidth / 2, canvasHeight / 2);\n ctx.scale(scale, scale);\n ctx.translate(-canvasWidth / 2, -canvasHeight / 2);\n\n renderBasicText(ctx, layer, canvasWidth, canvasHeight, relativeFrame);\n\n ctx.restore();\n}\n"],"names":[],"mappings":";;;AAMA,SAAS,mBACP,cACA,aACA,gBAUQ;AACR,MAAI,CAAC,gBAAgB;AACnB,WAAO,eAAe,IAAI,cAAc;AAAA,EAC1C;AAGA,MAAI,eAAe,KAAK;AACtB,UAAM,aAAa,WAAW,eAAe,GAAG,IAAI;AACpD,WAAO,eAAe;AAAA,EACxB;AAEA,MAAI,eAAe,QAAQ;AACzB,UAAM,gBAAgB,WAAW,eAAe,MAAM,IAAI;AAC1D,WAAO,gBAAgB,IAAI,iBAAiB;AAAA,EAC9C;AAGA,MAAI,eAAe,mBAAmB,YAAY,eAAe,eAAe,UAAU;AACxF,WAAO,eAAe,IAAI,cAAc;AAAA,EAC1C;AAGA,SAAO,eAAe,IAAI,cAAc;AAC1C;AAEO,SAAS,gBACd,KACA,OACA,aACA,cACA,gBACM;AACN,QAAM,aAAa,MAAM,YAAY;AACrC,MAAI,CAAC,WAAY;AAEjB,QAAM,WAAW,WAAW;AAC5B,QAAM,aAAa,WAAW;AAC9B,QAAM,aAAa,WAAW;AAC9B,QAAM,OAAO,WAAW;AACxB,QAAM,SAAS,WAAW;AAC1B,QAAM,cAAc,WAAW,eAAe;AAC9C,QAAM,aAAa,WAAW,cAAc;AAE5C,QAAM,WAAW,cAAc;AAC/B,QAAM,OAAO,kBAAkB,MAAM,MAAM,MAAM,UAAU;AAE3D,MAAI;AACJ,MAAI,MAAM,eAAe,MAAM,YAAY,SAAS,GAAG;AACrD,UAAM,aAAa,uBAAuB,MAAM,cAAc,SAAS,IAAI;AAC3E,UAAM,QAAQ,KAAK,MAAM,aAAa,QAAQ,EAAE;AAChD,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ,OAAO;AACL,YAAQ,SAAS,KAAK,MAAM,UAAU,UAAU,YAAY,UAAU;AAAA,EACxE;AAEA,MAAI,KAAA;AACJ,MAAI,OAAO,GAAG,UAAU,IAAI,QAAQ,MAAM,UAAU;AACpD,MAAI,YAAY;AAChB,MAAI,eAAe;AACnB,MAAI,WAAW;AACf,MAAI,UAAU;AAEd,QAAM,cAAc,MAAM,SAAS,WAAW;AAC9C,QAAM,SAAS,mBAAmB,cAAc,aAAa,MAAM,YAAY,cAAc;AAE7F,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,IAAI,SAAS,IAAI,WAAW,aAAa,WAAW;AAE1D,QAAI,UAAU,cAAc,GAAG;AAC7B,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,WAAW,MAAM,cAAc,GAAG,CAAC;AAAA,IACzC;AACA,QAAI,YAAY;AAChB,QAAI,SAAS,MAAM,cAAc,GAAG,CAAC;AAAA,EACvC;AAEA,MAAI,QAAA;AACN;"}
@@ -0,0 +1,9 @@
1
+ import { TextLayer } from '../types';
2
+
3
+ export declare function charProgress(relativeFrame: number, fps: number, charIndex: number, staggerMs: number, durationMs: number): number;
4
+ export type CaptionStaggerPreset = 'fade' | 'slideUp' | 'scale' | 'rotateScale' | 'blur' | 'flip3d' | 'typewriter' | 'letterSpread';
5
+ /**
6
+ * Per-character stagger entrance aligned with medeo-web preview (anime.js easeOutExpo, 800ms, 50ms stagger).
7
+ */
8
+ export declare function renderCaptionStaggerEntrance(ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D, layer: TextLayer, canvasWidth: number, canvasHeight: number, relativeFrame: number, fps: number, preset: CaptionStaggerPreset): void;
9
+ //# sourceMappingURL=caption-stagger-entrance-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caption-stagger-entrance-renderer.d.ts","sourceRoot":"","sources":["../../../../src/stages/compose/text-renderers/caption-stagger-entrance-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAkD1C,wBAAgB,YAAY,CAC1B,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,CAMR;AAED,MAAM,MAAM,oBAAoB,GAC5B,MAAM,GACN,SAAS,GACT,OAAO,GACP,aAAa,GACb,MAAM,GACN,QAAQ,GACR,YAAY,GACZ,cAAc,CAAC;AA0EnB;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,iCAAiC,GAAG,wBAAwB,EACjE,KAAK,EAAE,SAAS,EAChB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,oBAAoB,GAC3B,IAAI,CA6GN"}
@@ -0,0 +1,188 @@
1
+ import { formEvenLinesWithWords, wrapText } from "../text-utils/text-wrapper.js";
2
+ import { getLetterCaseText, measureTextWidth } from "../text-utils/text-metrics.js";
3
+ import { needsSpaceBetweenWords } from "../text-utils/locale-detector.js";
4
+ const DEFAULT_DURATION_MS = 800;
5
+ const DEFAULT_STAGGER_MS = 50;
6
+ const SLIDE_BASE_PX = 50;
7
+ const LETTER_SPREAD_BASE_PX = 20;
8
+ const BLUR_START_PX = 10;
9
+ const FONT_REF_PX = 40;
10
+ function easeOutExpo(t) {
11
+ if (t <= 0) return 0;
12
+ if (t >= 1) return 1;
13
+ return 1 - Math.pow(2, -10 * t);
14
+ }
15
+ function calculateYPosition(canvasHeight, totalHeight, globalPosition) {
16
+ if (!globalPosition) {
17
+ return canvasHeight / 2 - totalHeight / 2;
18
+ }
19
+ if (globalPosition.top) {
20
+ const topPercent = parseFloat(globalPosition.top) / 100;
21
+ return canvasHeight * topPercent;
22
+ }
23
+ if (globalPosition.bottom) {
24
+ const bottomPercent = parseFloat(globalPosition.bottom) / 100;
25
+ return canvasHeight * (1 - bottomPercent) - totalHeight;
26
+ }
27
+ if (globalPosition.justifyContent === "center" || globalPosition.alignItems === "center") {
28
+ return canvasHeight / 2 - totalHeight / 2;
29
+ }
30
+ return canvasHeight / 2 - totalHeight / 2;
31
+ }
32
+ function charProgress(relativeFrame, fps, charIndex, staggerMs, durationMs) {
33
+ const tMs = relativeFrame / fps * 1e3;
34
+ const startMs = charIndex * staggerMs;
35
+ if (tMs <= startMs) return 0;
36
+ const raw = (tMs - startMs) / durationMs;
37
+ return easeOutExpo(Math.min(1, raw));
38
+ }
39
+ function buildCharSlots(ctx, layer, canvasWidth, canvasHeight) {
40
+ const fontConfig = layer.fontConfig?.textStyle;
41
+ if (!fontConfig) return null;
42
+ const fontSize = fontConfig.fontSize;
43
+ const fontFamily = fontConfig.fontFamily;
44
+ const fontWeight = fontConfig.fontWeight;
45
+ const lineHeight = fontConfig.lineHeight || 1.2;
46
+ const maxWidth = canvasWidth * 0.64;
47
+ const text = getLetterCaseText(layer.text, layer.letterCase);
48
+ let lines;
49
+ if (layer.wordTimings && layer.wordTimings.length > 0) {
50
+ const needsSpace = needsSpaceBetweenWords(layer.localeCode || "en-US", text);
51
+ const words = text.split(needsSpace ? /\s+/ : "");
52
+ lines = formEvenLinesWithWords(
53
+ ctx,
54
+ words,
55
+ maxWidth,
56
+ fontSize,
57
+ needsSpace,
58
+ fontFamily,
59
+ fontWeight
60
+ );
61
+ } else {
62
+ lines = wrapText(ctx, text, maxWidth, fontSize, fontFamily, fontWeight);
63
+ }
64
+ const totalHeight = lines.length * fontSize * lineHeight;
65
+ const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);
66
+ ctx.save();
67
+ ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
68
+ const slots = [];
69
+ let globalIndex = 0;
70
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
71
+ const line = lines[lineIndex];
72
+ const y = startY + lineIndex * fontSize * lineHeight + fontSize / 2;
73
+ const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);
74
+ let cx = canvasWidth / 2 - lineWidth / 2;
75
+ for (const ch of Array.from(line)) {
76
+ const cw = measureTextWidth(ctx, ch, fontSize, fontFamily, fontWeight);
77
+ slots.push({
78
+ ch,
79
+ x: cx + cw / 2,
80
+ y,
81
+ globalIndex
82
+ });
83
+ globalIndex++;
84
+ cx += cw;
85
+ }
86
+ }
87
+ ctx.restore();
88
+ return { slots, fontSize, lineHeight };
89
+ }
90
+ function renderCaptionStaggerEntrance(ctx, layer, canvasWidth, canvasHeight, relativeFrame, fps, preset) {
91
+ const built = buildCharSlots(ctx, layer, canvasWidth, canvasHeight);
92
+ if (!built) return;
93
+ const { slots, fontSize } = built;
94
+ const fontConfig = layer.fontConfig.textStyle;
95
+ const fontFamily = fontConfig.fontFamily;
96
+ const fontWeight = fontConfig.fontWeight;
97
+ const fill = fontConfig.fill;
98
+ const stroke = fontConfig.stroke;
99
+ const strokeWidth = fontConfig.strokeWidth || 0;
100
+ const scalePx = fontSize / FONT_REF_PX;
101
+ const staggerMs = DEFAULT_STAGGER_MS;
102
+ ctx.save();
103
+ ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
104
+ ctx.textAlign = "center";
105
+ ctx.textBaseline = "middle";
106
+ ctx.lineJoin = "round";
107
+ ctx.lineCap = "round";
108
+ const tMsGlobal = relativeFrame / fps * 1e3;
109
+ for (const slot of slots) {
110
+ let p;
111
+ if (preset === "typewriter") {
112
+ const startMs = slot.globalIndex * staggerMs;
113
+ p = tMsGlobal >= startMs ? 1 : 0;
114
+ } else {
115
+ p = charProgress(relativeFrame, fps, slot.globalIndex, staggerMs, DEFAULT_DURATION_MS);
116
+ }
117
+ if (p <= 0 && preset !== "blur") continue;
118
+ const slidePx = SLIDE_BASE_PX * scalePx;
119
+ const spreadPx = LETTER_SPREAD_BASE_PX * scalePx;
120
+ ctx.save();
121
+ let opacity = p;
122
+ let tx = 0;
123
+ let ty = 0;
124
+ let rot = 0;
125
+ let sc = 1;
126
+ let sy = 1;
127
+ let blurPx = 0;
128
+ switch (preset) {
129
+ case "fade":
130
+ opacity = p;
131
+ break;
132
+ case "slideUp":
133
+ opacity = p;
134
+ ty = (1 - p) * slidePx;
135
+ break;
136
+ case "scale":
137
+ opacity = p;
138
+ sc = Math.max(0.04, p);
139
+ break;
140
+ case "rotateScale":
141
+ opacity = p;
142
+ rot = (1 - p) * 45 * Math.PI / 180;
143
+ sc = 0.5 + p * 0.5;
144
+ break;
145
+ case "blur":
146
+ opacity = p;
147
+ blurPx = (1 - p) * BLUR_START_PX;
148
+ break;
149
+ case "flip3d":
150
+ opacity = p;
151
+ sy = Math.max(0.04, p);
152
+ sc = 1;
153
+ break;
154
+ case "typewriter":
155
+ opacity = p >= 1 ? 1 : p;
156
+ break;
157
+ case "letterSpread":
158
+ opacity = p;
159
+ tx = (1 - p) * spreadPx * slot.globalIndex;
160
+ break;
161
+ }
162
+ ctx.globalAlpha = opacity;
163
+ if (blurPx > 0.01) {
164
+ ctx.filter = `blur(${blurPx}px)`;
165
+ }
166
+ ctx.translate(slot.x + tx, slot.y + ty);
167
+ ctx.rotate(rot);
168
+ if (preset === "flip3d") {
169
+ ctx.scale(1, sy);
170
+ } else {
171
+ ctx.scale(sc, sc);
172
+ }
173
+ if (stroke && strokeWidth > 0) {
174
+ ctx.strokeStyle = stroke;
175
+ ctx.lineWidth = strokeWidth;
176
+ ctx.strokeText(slot.ch, 0, 0);
177
+ }
178
+ ctx.fillStyle = fill;
179
+ ctx.fillText(slot.ch, 0, 0);
180
+ ctx.restore();
181
+ }
182
+ ctx.restore();
183
+ }
184
+ export {
185
+ charProgress,
186
+ renderCaptionStaggerEntrance
187
+ };
188
+ //# sourceMappingURL=caption-stagger-entrance-renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caption-stagger-entrance-renderer.js","sources":["../../../../src/stages/compose/text-renderers/caption-stagger-entrance-renderer.ts"],"sourcesContent":["import type { TextLayer } from '../types';\nimport { wrapText, formEvenLinesWithWords } from '../text-utils/text-wrapper';\nimport { getLetterCaseText, measureTextWidth } from '../text-utils/text-metrics';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\n/** Matches medeo-web caption preview (`caption-anime-effects` + anime.js defaults). */\nconst DEFAULT_DURATION_MS = 800;\nconst DEFAULT_STAGGER_MS = 50;\nconst SLIDE_BASE_PX = 50;\nconst LETTER_SPREAD_BASE_PX = 20;\nconst BLUR_START_PX = 10;\nconst FONT_REF_PX = 40;\n\nfunction easeOutExpo(t: number): number {\n if (t <= 0) return 0;\n if (t >= 1) return 1;\n return 1 - Math.pow(2, -10 * t);\n}\n\nfunction calculateYPosition(\n canvasHeight: number,\n totalHeight: number,\n globalPosition?: {\n position?: 'absolute';\n top?: string;\n bottom?: string;\n left?: string;\n right?: string;\n display?: string;\n alignItems?: string;\n justifyContent?: string;\n }\n): number {\n if (!globalPosition) {\n return canvasHeight / 2 - totalHeight / 2;\n }\n if (globalPosition.top) {\n const topPercent = parseFloat(globalPosition.top) / 100;\n return canvasHeight * topPercent;\n }\n if (globalPosition.bottom) {\n const bottomPercent = parseFloat(globalPosition.bottom) / 100;\n return canvasHeight * (1 - bottomPercent) - totalHeight;\n }\n if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function charProgress(\n relativeFrame: number,\n fps: number,\n charIndex: number,\n staggerMs: number,\n durationMs: number\n): number {\n const tMs = (relativeFrame / fps) * 1000;\n const startMs = charIndex * staggerMs;\n if (tMs <= startMs) return 0;\n const raw = (tMs - startMs) / durationMs;\n return easeOutExpo(Math.min(1, raw));\n}\n\nexport type CaptionStaggerPreset =\n | 'fade'\n | 'slideUp'\n | 'scale'\n | 'rotateScale'\n | 'blur'\n | 'flip3d'\n | 'typewriter'\n | 'letterSpread';\n\ninterface CharSlot {\n ch: string;\n x: number;\n y: number;\n globalIndex: number;\n}\n\nfunction buildCharSlots(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number\n): { slots: CharSlot[]; fontSize: number; lineHeight: number } | null {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return null;\n\n const fontSize = fontConfig.fontSize;\n const fontFamily = fontConfig.fontFamily;\n const fontWeight = fontConfig.fontWeight;\n const lineHeight = fontConfig.lineHeight || 1.2;\n const maxWidth = canvasWidth * 0.64;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n\n let lines: string[];\n if (layer.wordTimings && layer.wordTimings.length > 0) {\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const words = text.split(needsSpace ? /\\s+/ : '');\n lines = formEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n } else {\n lines = wrapText(ctx, text, maxWidth, fontSize, fontFamily, fontWeight);\n }\n\n const totalHeight = lines.length * fontSize * lineHeight;\n const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);\n\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n\n const slots: CharSlot[] = [];\n let globalIndex = 0;\n\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n const line = lines[lineIndex]!;\n const y = startY + lineIndex * fontSize * lineHeight + fontSize / 2;\n const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);\n let cx = canvasWidth / 2 - lineWidth / 2;\n\n for (const ch of Array.from(line)) {\n const cw = measureTextWidth(ctx, ch, fontSize, fontFamily, fontWeight);\n slots.push({\n ch,\n x: cx + cw / 2,\n y,\n globalIndex,\n });\n globalIndex++;\n cx += cw;\n }\n }\n\n ctx.restore();\n return { slots, fontSize, lineHeight };\n}\n\n/**\n * Per-character stagger entrance aligned with medeo-web preview (anime.js easeOutExpo, 800ms, 50ms stagger).\n */\nexport function renderCaptionStaggerEntrance(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number,\n fps: number,\n preset: CaptionStaggerPreset\n): void {\n const built = buildCharSlots(ctx, layer, canvasWidth, canvasHeight);\n if (!built) return;\n\n const { slots, fontSize } = built;\n const fontConfig = layer.fontConfig!.textStyle!;\n const fontFamily = fontConfig.fontFamily;\n const fontWeight = fontConfig.fontWeight;\n const fill = fontConfig.fill;\n const stroke = fontConfig.stroke;\n const strokeWidth = fontConfig.strokeWidth || 0;\n\n const scalePx = fontSize / FONT_REF_PX;\n const staggerMs = DEFAULT_STAGGER_MS;\n\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.lineJoin = 'round';\n ctx.lineCap = 'round';\n\n const tMsGlobal = (relativeFrame / fps) * 1000;\n\n for (const slot of slots) {\n let p: number;\n if (preset === 'typewriter') {\n const startMs = slot.globalIndex * staggerMs;\n p = tMsGlobal >= startMs ? 1 : 0;\n } else {\n p = charProgress(relativeFrame, fps, slot.globalIndex, staggerMs, DEFAULT_DURATION_MS);\n }\n if (p <= 0 && preset !== 'blur') continue;\n\n const slidePx = SLIDE_BASE_PX * scalePx;\n const spreadPx = LETTER_SPREAD_BASE_PX * scalePx;\n\n ctx.save();\n\n let opacity = p;\n let tx = 0;\n let ty = 0;\n let rot = 0;\n let sc = 1;\n let sy = 1;\n let blurPx = 0;\n\n switch (preset) {\n case 'fade':\n opacity = p;\n break;\n case 'slideUp':\n opacity = p;\n ty = (1 - p) * slidePx;\n break;\n case 'scale':\n opacity = p;\n sc = Math.max(0.04, p);\n break;\n case 'rotateScale':\n opacity = p;\n rot = ((1 - p) * 45 * Math.PI) / 180;\n sc = 0.5 + p * 0.5;\n break;\n case 'blur':\n opacity = p;\n blurPx = (1 - p) * BLUR_START_PX;\n break;\n case 'flip3d':\n opacity = p;\n sy = Math.max(0.04, p);\n sc = 1;\n break;\n case 'typewriter':\n opacity = p >= 1 ? 1 : p;\n break;\n case 'letterSpread':\n opacity = p;\n tx = (1 - p) * spreadPx * slot.globalIndex;\n break;\n default:\n break;\n }\n\n ctx.globalAlpha = opacity;\n if (blurPx > 0.01) {\n ctx.filter = `blur(${blurPx}px)`;\n }\n\n ctx.translate(slot.x + tx, slot.y + ty);\n ctx.rotate(rot);\n if (preset === 'flip3d') {\n ctx.scale(1, sy);\n } else {\n ctx.scale(sc, sc);\n }\n\n if (stroke && strokeWidth > 0) {\n ctx.strokeStyle = stroke;\n ctx.lineWidth = strokeWidth;\n ctx.strokeText(slot.ch, 0, 0);\n }\n ctx.fillStyle = fill;\n ctx.fillText(slot.ch, 0, 0);\n\n ctx.restore();\n }\n\n ctx.restore();\n}\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { formEvenLinesWithWords } from "../text-utils/text-wrapper.js";
2
2
  import { getLetterCaseText, measureTextWidth } from "../text-utils/text-metrics.js";
3
- import { springEasing, interpolate } from "./animation-utils.js";
3
+ import { interpolate, springEasing } from "./animation-utils.js";
4
4
  import { needsSpaceBetweenWords } from "../text-utils/locale-detector.js";
5
5
  function usToFrame(us, fps) {
6
6
  return Math.floor(us / (1e6 / fps));
@@ -0,0 +1,63 @@
1
+ import { GlobalPositionStyle } from '../font-system/types';
2
+
3
+ export interface CaptionLayoutInput {
4
+ text: string;
5
+ canvasWidth: number;
6
+ canvasHeight: number;
7
+ localeCode?: string;
8
+ fontTemplate?: string;
9
+ fontFamily?: string;
10
+ /** When set, overrides the font template (same as compose `fontConfig.textStyle` merge). */
11
+ fontSize?: number;
12
+ fontWeight?: string | number;
13
+ fill?: string;
14
+ wordTimings?: Array<{
15
+ text: string;
16
+ startUs: number;
17
+ endUs: number;
18
+ }>;
19
+ letterCase?: 'upper' | 'lower' | 'none';
20
+ animation?: {
21
+ type: string;
22
+ [key: string]: unknown;
23
+ };
24
+ }
25
+ export interface CaptionLayout {
26
+ lines: CaptionLine[];
27
+ style: CaptionStyle;
28
+ container: CaptionContainer;
29
+ }
30
+ export interface CaptionLine {
31
+ text: string;
32
+ lineIndex: number;
33
+ words: CaptionWord[];
34
+ }
35
+ export interface CaptionWord {
36
+ text: string;
37
+ wordIndex: number;
38
+ timing?: {
39
+ startUs: number;
40
+ endUs: number;
41
+ };
42
+ }
43
+ export interface CaptionStyle {
44
+ fontSize: number;
45
+ fontFamily: string;
46
+ fontWeight: string | number;
47
+ fill: string;
48
+ stroke?: string;
49
+ strokeWidth?: number;
50
+ lineHeight: number;
51
+ letterSpacing?: string | number;
52
+ paintOrder?: string;
53
+ }
54
+ export interface CaptionContainer {
55
+ maxWidth: number;
56
+ maxWidthPercent: number;
57
+ position: Pick<GlobalPositionStyle, 'top' | 'bottom' | 'alignItems' | 'justifyContent'>;
58
+ backgroundColor?: string;
59
+ padding?: string;
60
+ borderRadius?: number;
61
+ }
62
+ export declare function computeCaptionLayout(input: CaptionLayoutInput): CaptionLayout;
63
+ //# sourceMappingURL=caption-layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caption-layout.d.ts","sourceRoot":"","sources":["../../../../src/stages/compose/text-utils/caption-layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA8B,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAQ5F,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtE,UAAU,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;IACxC,SAAS,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;CACtD;AAID,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,KAAK,EAAE,YAAY,CAAC;IACpB,SAAS,EAAE,gBAAgB,CAAC;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,IAAI,CAAC,mBAAmB,EAAE,KAAK,GAAG,QAAQ,GAAG,YAAY,GAAG,gBAAgB,CAAC,CAAC;IACxF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAqFD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,kBAAkB,GAAG,aAAa,CA4E7E"}
@@ -0,0 +1,129 @@
1
+ import { getFontConfig } from "../font-system/FontManager.js";
2
+ import { formEvenLinesWithWords, wrapText } from "./text-wrapper.js";
3
+ import { getLetterCaseText } from "./text-metrics.js";
4
+ import { needsSpaceBetweenWords } from "./locale-detector.js";
5
+ const DEFAULT_MAX_WIDTH_RATIO = 0.64;
6
+ const KTV_MAX_WIDTH_RATIO = 0.9;
7
+ const DEFAULT_FONT_TEMPLATE = "baseSubtitle";
8
+ let sharedCtx = null;
9
+ function getSharedCtx() {
10
+ if (!sharedCtx) {
11
+ const canvas = new OffscreenCanvas(1, 1);
12
+ sharedCtx = canvas.getContext("2d");
13
+ }
14
+ return sharedCtx;
15
+ }
16
+ function getMaxWidthRatio(animationType) {
17
+ return animationType === "characterKTV" ? KTV_MAX_WIDTH_RATIO : DEFAULT_MAX_WIDTH_RATIO;
18
+ }
19
+ function buildContainer(maxWidth, maxWidthPercent, globalPosition, containerStyle) {
20
+ return {
21
+ maxWidth,
22
+ maxWidthPercent,
23
+ position: {
24
+ top: globalPosition?.top,
25
+ bottom: globalPosition?.bottom,
26
+ alignItems: globalPosition?.alignItems,
27
+ justifyContent: globalPosition?.justifyContent
28
+ },
29
+ backgroundColor: containerStyle?.backgroundColor,
30
+ padding: containerStyle?.padding,
31
+ borderRadius: containerStyle?.borderRadius
32
+ };
33
+ }
34
+ function buildLinesWithWordMapping(lines, needsSpace, wordTimings) {
35
+ let globalWordIndex = 0;
36
+ return lines.map((lineText, lineIndex) => {
37
+ const lineWords = lineText.split(needsSpace ? /\s+/ : "").filter(Boolean);
38
+ const words = lineWords.map((wordText) => {
39
+ const timing = wordTimings?.[globalWordIndex];
40
+ const word = {
41
+ text: wordText,
42
+ wordIndex: globalWordIndex,
43
+ timing: timing ? { startUs: timing.startUs, endUs: timing.endUs } : void 0
44
+ };
45
+ globalWordIndex++;
46
+ return word;
47
+ });
48
+ return { text: lineText, lineIndex, words };
49
+ });
50
+ }
51
+ function buildLinesWithoutWordMapping(lines) {
52
+ return lines.map((lineText, lineIndex) => ({
53
+ text: lineText,
54
+ lineIndex,
55
+ words: [{ text: lineText, wordIndex: lineIndex }]
56
+ }));
57
+ }
58
+ function computeCaptionLayout(input) {
59
+ const {
60
+ text: rawText,
61
+ canvasWidth,
62
+ localeCode: inputLocale,
63
+ fontTemplate: inputTemplate,
64
+ fontFamily: inputFontFamily,
65
+ fontSize: inputFontSize,
66
+ fontWeight: inputFontWeight,
67
+ fill: inputFill,
68
+ wordTimings,
69
+ letterCase,
70
+ animation
71
+ } = input;
72
+ const locale = inputLocale || "en-US";
73
+ const fontTemplate = inputTemplate || DEFAULT_FONT_TEMPLATE;
74
+ const fontConfig = getFontConfig(locale, fontTemplate, inputFontFamily);
75
+ let textStyle = { ...fontConfig.textStyle };
76
+ if (inputFontSize != null) {
77
+ textStyle.fontSize = inputFontSize;
78
+ }
79
+ if (inputFontWeight != null) {
80
+ textStyle.fontWeight = inputFontWeight;
81
+ }
82
+ if (inputFill != null) {
83
+ textStyle.fill = inputFill;
84
+ }
85
+ const { containerStyle, globalPosition } = fontConfig;
86
+ const text = getLetterCaseText(rawText, letterCase);
87
+ const hasWordTimings = wordTimings && wordTimings.length > 0;
88
+ const ratio = getMaxWidthRatio(animation?.type);
89
+ const maxWidth = canvasWidth * ratio;
90
+ const maxWidthPercent = ratio * 100;
91
+ const ctx = getSharedCtx();
92
+ const { fontSize, fontFamily, fontWeight } = textStyle;
93
+ let lines;
94
+ let captionLines;
95
+ if (hasWordTimings) {
96
+ const needsSpace = needsSpaceBetweenWords(locale, text);
97
+ const words = text.split(needsSpace ? /\s+/ : "");
98
+ lines = formEvenLinesWithWords(
99
+ ctx,
100
+ words,
101
+ maxWidth,
102
+ fontSize,
103
+ needsSpace,
104
+ fontFamily,
105
+ fontWeight
106
+ );
107
+ captionLines = buildLinesWithWordMapping(lines, needsSpace, wordTimings);
108
+ } else {
109
+ lines = wrapText(ctx, text, maxWidth, fontSize, fontFamily, fontWeight);
110
+ captionLines = buildLinesWithoutWordMapping(lines);
111
+ }
112
+ const style = {
113
+ fontSize,
114
+ fontFamily,
115
+ fontWeight,
116
+ fill: textStyle.fill,
117
+ stroke: textStyle.stroke,
118
+ strokeWidth: textStyle.strokeWidth,
119
+ lineHeight: textStyle.lineHeight || 1.2,
120
+ letterSpacing: textStyle.letterSpacing,
121
+ paintOrder: textStyle.paintOrder
122
+ };
123
+ const container = buildContainer(maxWidth, maxWidthPercent, globalPosition, containerStyle);
124
+ return { lines: captionLines, style, container };
125
+ }
126
+ export {
127
+ computeCaptionLayout
128
+ };
129
+ //# sourceMappingURL=caption-layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caption-layout.js","sources":["../../../../src/stages/compose/text-utils/caption-layout.ts"],"sourcesContent":["import type { LocaleCode, ContainerStyle, GlobalPositionStyle } from '../font-system/types';\nimport { getFontConfig } from '../font-system/FontManager';\nimport { wrapText, formEvenLinesWithWords } from './text-wrapper';\nimport { getLetterCaseText } from './text-metrics';\nimport { needsSpaceBetweenWords } from './locale-detector';\n\n// ────── Input ──────\n\nexport interface CaptionLayoutInput {\n text: string;\n canvasWidth: number;\n canvasHeight: number;\n localeCode?: string;\n fontTemplate?: string;\n fontFamily?: string;\n /** When set, overrides the font template (same as compose `fontConfig.textStyle` merge). */\n fontSize?: number;\n fontWeight?: string | number;\n fill?: string;\n wordTimings?: Array<{ text: string; startUs: number; endUs: number }>;\n letterCase?: 'upper' | 'lower' | 'none';\n animation?: { type: string; [key: string]: unknown };\n}\n\n// ────── Output ──────\n\nexport interface CaptionLayout {\n lines: CaptionLine[];\n style: CaptionStyle;\n container: CaptionContainer;\n}\n\nexport interface CaptionLine {\n text: string;\n lineIndex: number;\n words: CaptionWord[];\n}\n\nexport interface CaptionWord {\n text: string;\n wordIndex: number;\n timing?: { startUs: number; endUs: number };\n}\n\nexport interface CaptionStyle {\n fontSize: number;\n fontFamily: string;\n fontWeight: string | number;\n fill: string;\n stroke?: string;\n strokeWidth?: number;\n lineHeight: number;\n letterSpacing?: string | number;\n paintOrder?: string;\n}\n\nexport interface CaptionContainer {\n maxWidth: number;\n maxWidthPercent: number;\n position: Pick<GlobalPositionStyle, 'top' | 'bottom' | 'alignItems' | 'justifyContent'>;\n backgroundColor?: string;\n padding?: string;\n borderRadius?: number;\n}\n\n// ────── Constants ──────\n\nconst DEFAULT_MAX_WIDTH_RATIO = 0.64;\nconst KTV_MAX_WIDTH_RATIO = 0.9;\nconst DEFAULT_FONT_TEMPLATE = 'baseSubtitle';\n\n// ────── Implementation ──────\n\nlet sharedCtx: OffscreenCanvasRenderingContext2D | null = null;\n\nfunction getSharedCtx(): OffscreenCanvasRenderingContext2D {\n if (!sharedCtx) {\n const canvas = new OffscreenCanvas(1, 1);\n sharedCtx = canvas.getContext('2d')!;\n }\n return sharedCtx;\n}\n\nfunction getMaxWidthRatio(animationType?: string): number {\n return animationType === 'characterKTV' ? KTV_MAX_WIDTH_RATIO : DEFAULT_MAX_WIDTH_RATIO;\n}\n\nfunction buildContainer(\n maxWidth: number,\n maxWidthPercent: number,\n globalPosition?: Partial<GlobalPositionStyle>,\n containerStyle?: Partial<ContainerStyle>\n): CaptionContainer {\n return {\n maxWidth,\n maxWidthPercent,\n position: {\n top: globalPosition?.top,\n bottom: globalPosition?.bottom,\n alignItems: globalPosition?.alignItems,\n justifyContent: globalPosition?.justifyContent,\n },\n backgroundColor: containerStyle?.backgroundColor,\n padding: containerStyle?.padding,\n borderRadius: containerStyle?.borderRadius,\n };\n}\n\n/**\n * Build CaptionLine[] with word-to-line mapping from lines produced by\n * formEvenLinesWithWords (wordTimings path).\n */\nfunction buildLinesWithWordMapping(\n lines: string[],\n needsSpace: boolean,\n wordTimings?: CaptionLayoutInput['wordTimings']\n): CaptionLine[] {\n let globalWordIndex = 0;\n\n return lines.map((lineText, lineIndex) => {\n const lineWords = lineText.split(needsSpace ? /\\s+/ : '').filter(Boolean);\n const words: CaptionWord[] = lineWords.map((wordText) => {\n const timing = wordTimings?.[globalWordIndex];\n const word: CaptionWord = {\n text: wordText,\n wordIndex: globalWordIndex,\n timing: timing ? { startUs: timing.startUs, endUs: timing.endUs } : undefined,\n };\n globalWordIndex++;\n return word;\n });\n\n return { text: lineText, lineIndex, words };\n });\n}\n\n/**\n * Build CaptionLine[] from lines produced by wrapText (no wordTimings).\n * Each line gets a single word entry covering the entire line text.\n */\nfunction buildLinesWithoutWordMapping(lines: string[]): CaptionLine[] {\n return lines.map((lineText, lineIndex) => ({\n text: lineText,\n lineIndex,\n words: [{ text: lineText, wordIndex: lineIndex }],\n }));\n}\n\nexport function computeCaptionLayout(input: CaptionLayoutInput): CaptionLayout {\n const {\n text: rawText,\n canvasWidth,\n localeCode: inputLocale,\n fontTemplate: inputTemplate,\n fontFamily: inputFontFamily,\n fontSize: inputFontSize,\n fontWeight: inputFontWeight,\n fill: inputFill,\n wordTimings,\n letterCase,\n animation,\n } = input;\n\n const locale = (inputLocale || 'en-US') as LocaleCode;\n const fontTemplate = inputTemplate || DEFAULT_FONT_TEMPLATE;\n const fontConfig = getFontConfig(locale, fontTemplate, inputFontFamily);\n let textStyle = { ...fontConfig.textStyle };\n if (inputFontSize != null) {\n textStyle.fontSize = inputFontSize;\n }\n if (inputFontWeight != null) {\n textStyle.fontWeight = inputFontWeight;\n }\n if (inputFill != null) {\n textStyle.fill = inputFill;\n }\n const { containerStyle, globalPosition } = fontConfig;\n\n const text = getLetterCaseText(rawText, letterCase);\n const hasWordTimings = wordTimings && wordTimings.length > 0;\n\n const ratio = getMaxWidthRatio(animation?.type);\n const maxWidth = canvasWidth * ratio;\n const maxWidthPercent = ratio * 100;\n\n const ctx = getSharedCtx();\n const { fontSize, fontFamily, fontWeight } = textStyle;\n\n let lines: string[];\n let captionLines: CaptionLine[];\n\n if (hasWordTimings) {\n const needsSpace = needsSpaceBetweenWords(locale, text);\n const words = text.split(needsSpace ? /\\s+/ : '');\n lines = formEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n captionLines = buildLinesWithWordMapping(lines, needsSpace, wordTimings);\n } else {\n lines = wrapText(ctx, text, maxWidth, fontSize, fontFamily, fontWeight);\n captionLines = buildLinesWithoutWordMapping(lines);\n }\n\n const style: CaptionStyle = {\n fontSize,\n fontFamily,\n fontWeight,\n fill: textStyle.fill,\n stroke: textStyle.stroke,\n strokeWidth: textStyle.strokeWidth,\n lineHeight: textStyle.lineHeight || 1.2,\n letterSpacing: textStyle.letterSpacing,\n paintOrder: textStyle.paintOrder,\n };\n\n const container = buildContainer(maxWidth, maxWidthPercent, globalPosition, containerStyle);\n\n return { lines: captionLines, style, container };\n}\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  export * from './locale-detector';
2
2
  export * from './text-wrapper';
3
3
  export * from './text-metrics';
4
+ export * from './caption-layout';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/stages/compose/text-utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/stages/compose/text-utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC"}
@@ -218,9 +218,11 @@ export interface TextLayer extends Layer {
218
218
  endUs: number;
219
219
  }>;
220
220
  letterCase?: 'upper' | 'lower' | 'none';
221
+ /** Microseconds since this attachment became active; drives entrance/word-sync animation per segment. */
222
+ entranceRelativeTimeUs?: number;
221
223
  }
222
224
  export interface TextAnimation {
223
- type: 'none' | 'fade' | 'slide' | 'typewriter' | 'wave' | 'bounce' | 'wordByWord' | 'characterKTV' | 'wordByWordFancy' | 'wordByWordSlideUp';
225
+ type: 'none' | 'fade' | 'slide' | 'typewriter' | 'wave' | 'bounce' | 'wordByWord' | 'characterKTV' | 'wordByWordFancy' | 'wordByWordSlideUp' | 'slideUp' | 'scale' | 'rotateScale' | 'blur' | 'flip3d' | 'letterSpread';
224
226
  durationUs: number;
225
227
  delayUs?: number;
226
228
  easing?: 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';