@meframe/core 0.5.7 → 0.5.9
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.
- package/dist/meframe-service/node_modules/.pnpm/mp4-muxer@5.2.2/node_modules/mp4-muxer/build/mp4-muxer.js.map +1 -0
- package/dist/{node_modules → meframe-service/node_modules}/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js +14 -14
- package/dist/meframe-service/node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js.map +1 -0
- package/dist/model/CompositionModel.d.ts.map +1 -1
- package/dist/model/CompositionModel.js +12 -0
- package/dist/model/CompositionModel.js.map +1 -1
- package/dist/model/types.d.ts +4 -0
- package/dist/model/types.d.ts.map +1 -1
- package/dist/model/types.js.map +1 -1
- package/dist/orchestrator/CompositionPlanner.d.ts.map +1 -1
- package/dist/orchestrator/CompositionPlanner.js +14 -0
- package/dist/orchestrator/CompositionPlanner.js.map +1 -1
- package/dist/stages/compose/font-system/FontManager.js +1 -1
- package/dist/stages/compose/font-system/FontManager.js.map +1 -1
- package/dist/stages/compose/font-system/font-templates.js +4 -4
- package/dist/stages/compose/font-system/font-templates.js.map +1 -1
- package/dist/stages/compose/font-system/types.d.ts +1 -1
- package/dist/stages/compose/font-system/types.d.ts.map +1 -1
- package/dist/stages/compose/instructions.d.ts +2 -2
- package/dist/stages/compose/instructions.d.ts.map +1 -1
- package/dist/stages/compose/text-renderers/basic-text-renderer.js +3 -3
- package/dist/stages/compose/text-renderers/basic-text-renderer.js.map +1 -1
- package/dist/stages/compose/text-renderers/caption-stagger-entrance-renderer.d.ts.map +1 -1
- package/dist/stages/compose/text-renderers/caption-stagger-entrance-renderer.js +6 -3
- package/dist/stages/compose/text-renderers/caption-stagger-entrance-renderer.js.map +1 -1
- package/dist/stages/compose/text-renderers/character-ktv-renderer.js +3 -3
- package/dist/stages/compose/text-renderers/character-ktv-renderer.js.map +1 -1
- package/dist/stages/compose/text-renderers/word-by-word-renderer.js +7 -7
- package/dist/stages/compose/text-renderers/word-by-word-renderer.js.map +1 -1
- package/dist/stages/compose/text-renderers/word-fancy-renderer.js +3 -3
- package/dist/stages/compose/text-renderers/word-fancy-renderer.js.map +1 -1
- package/dist/stages/compose/text-utils/caption-layout.d.ts +1 -1
- package/dist/stages/compose/text-utils/caption-layout.d.ts.map +1 -1
- package/dist/stages/compose/text-utils/caption-layout.js +1 -1
- package/dist/stages/compose/text-utils/caption-layout.js.map +1 -1
- package/dist/stages/compose/text-utils/text-layout-cache.js +1 -1
- package/dist/stages/compose/text-utils/text-layout-cache.js.map +1 -1
- package/dist/stages/compose/types.d.ts +2 -2
- package/dist/stages/compose/types.d.ts.map +1 -1
- package/dist/stages/mux/MP4Muxer.js +1 -1
- package/dist/utils/mp4box.js +1 -1
- package/dist/workers/stages/export/{export.worker.p7X_YtxQ.js → export.worker.CWPrx2Nf.js} +24 -21
- package/dist/workers/stages/export/export.worker.CWPrx2Nf.js.map +1 -0
- package/dist/workers/worker-manifest.json +1 -1
- package/package.json +1 -1
- package/dist/node_modules/.pnpm/mp4-muxer@5.2.2/node_modules/mp4-muxer/build/mp4-muxer.js.map +0 -1
- package/dist/node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js.map +0 -1
- package/dist/workers/stages/export/export.worker.p7X_YtxQ.js.map +0 -1
- /package/dist/{node_modules → meframe-service/node_modules}/.pnpm/mp4-muxer@5.2.2/node_modules/mp4-muxer/build/mp4-muxer.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"font-templates.js","sources":["../../../../src/stages/compose/font-system/font-templates.ts"],"sourcesContent":["import type { TextStyle, ContainerStyle, GlobalPositionStyle } from './types';\n\nexport interface FontTemplate {\n name: string;\n textStyle?: Partial<TextStyle>;\n containerStyle?: Partial<ContainerStyle>;\n globalPosition?: Partial<GlobalPositionStyle>;\n}\n\nexport function mergeFontTemplates(...templates: FontTemplate[]): FontTemplate {\n const merged: FontTemplate = { name: 'merged' };\n\n for (const template of templates) {\n if (template.textStyle) {\n merged.textStyle = { ...merged.textStyle, ...template.textStyle };\n }\n if (template.containerStyle) {\n merged.containerStyle = { ...merged.containerStyle, ...template.containerStyle };\n }\n if (template.globalPosition) {\n merged.globalPosition = { ...merged.globalPosition, ...template.globalPosition };\n }\n }\n\n return merged;\n}\n\nconst normal30: FontTemplate = {\n name: 'normal-30',\n textStyle: { fontSize: 30 },\n};\n\nconst normal40: FontTemplate = {\n name: 'normal-40',\n textStyle: { fontSize: 40 },\n};\n\nconst normal50: FontTemplate = {\n name: 'normal-50',\n textStyle: { fontSize: 50 },\n};\n\nconst normal60: FontTemplate = {\n name: 'normal-60',\n textStyle: { fontSize: 60 },\n};\n\nconst normal80: FontTemplate = {\n name: 'normal-80',\n textStyle: { fontSize: 80 },\n};\n\nconst bold40: FontTemplate = {\n name: 'bold-40',\n textStyle: { fontWeight: 'bold', fontSize: 40 },\n};\n\nconst bold50: FontTemplate = {\n name: 'bold-50',\n textStyle: { fontWeight: 'bold', fontSize: 50 },\n};\n\nconst bold60: FontTemplate = {\n name: 'bold-60',\n textStyle: { fontWeight: 'bold', letterSpacing: '0.05em', fontSize: 60 },\n};\n\nconst fillBlack: FontTemplate = {\n name: 'fill-black',\n textStyle: { fill: 'rgb(0, 0, 0)' },\n};\n\nconst fillWhite: FontTemplate = {\n name: 'fill-white',\n textStyle: { fill: 'rgb(255, 255, 255)' },\n};\n\nconst fillYellow: FontTemplate = {\n name: 'fill-yellow',\n textStyle: { fill: 'rgb(255, 215, 0)' },\n};\n\nconst fillRed: FontTemplate = {\n name: 'fill-red',\n textStyle: { fill: 'rgb(255, 77, 77)' },\n};\n\nconst fillPink: FontTemplate = {\n name: 'fill-pink',\n textStyle: { fill: 'rgb(255, 192, 203)' },\n};\n\nconst strokeBlack: FontTemplate = {\n name: 'stroke-black',\n textStyle: {\n paintOrder: 'stroke',\n strokeLinejoin: 'round',\n strokeLinecap: 'round',\n stroke: 'rgb(0, 0, 0)',\n },\n};\n\nconst strokeWhite: FontTemplate = {\n name: 'stroke-white',\n textStyle: {\n paintOrder: 'stroke',\n strokeLinejoin: 'round',\n strokeLinecap: 'round',\n stroke: 'rgb(255, 255, 255)',\n },\n};\n\nconst strokeYellow: FontTemplate = {\n name: 'stroke-yellow',\n textStyle: {\n paintOrder: 'stroke',\n strokeLinejoin: 'round',\n strokeLinecap: 'round',\n stroke: 'rgb(255, 215, 0)',\n },\n};\n\nconst stroke0: FontTemplate = {\n name: 'stroke-0',\n textStyle: { strokeWidth: 0 },\n};\n\nconst stroke2: FontTemplate = {\n name: 'stroke-2',\n textStyle: { strokeWidth: 2 },\n};\n\nconst stroke4: FontTemplate = {\n name: 'stroke-4',\n textStyle: { strokeWidth: 4 },\n};\n\nconst stroke6: FontTemplate = {\n name: 'stroke-6',\n textStyle: { strokeWidth: 6 },\n};\n\nconst stroke8: FontTemplate = {\n name: 'stroke-8',\n textStyle: { strokeWidth: 8 },\n};\n\nconst stroke16: FontTemplate = {\n name: 'stroke-16',\n textStyle: { strokeWidth: 16 },\n};\n\nconst strokeBlack4 = mergeFontTemplates(strokeBlack, stroke4);\nstrokeBlack4.name = 'stroke-black-4';\n\nconst strokeBlack6 = mergeFontTemplates(strokeBlack, stroke6);\nstrokeBlack6.name = 'stroke-black-6';\n\nconst strokeBlack8 = mergeFontTemplates(strokeBlack, stroke8);\nstrokeBlack8.name = 'stroke-black-8';\n\nconst strokeBlack16 = mergeFontTemplates(strokeBlack, stroke16);\nstrokeBlack16.name = 'stroke-black-16';\n\nconst strokeWhite4 = mergeFontTemplates(strokeWhite, stroke4);\nstrokeWhite4.name = 'stroke-white-4';\n\nconst strokeWhite8 = mergeFontTemplates(strokeWhite, stroke8);\nstrokeWhite8.name = 'stroke-white-8';\n\nconst strokeYellow4 = mergeFontTemplates(strokeYellow, stroke4);\nstrokeYellow4.name = 'stroke-yellow-4';\n\nconst strokeYellow8 = mergeFontTemplates(strokeYellow, stroke8);\nstrokeYellow8.name = 'stroke-yellow-8';\n\nconst containerFull: FontTemplate = {\n name: 'container-full',\n containerStyle: { width: '100%' },\n};\n\nconst container60: FontTemplate = {\n name: 'container-60',\n containerStyle: { width: '60%' },\n};\n\nconst container80: FontTemplate = {\n name: 'container-80',\n containerStyle: { width: '80%' },\n};\n\nconst container95: FontTemplate = {\n name: 'container-95',\n containerStyle: { width: '95%' },\n};\n\nconst container98: FontTemplate = {\n name: 'container-98',\n containerStyle: { width: '98%' },\n};\n\nconst containerBlack: FontTemplate = {\n name: 'container-black',\n containerStyle: {\n backgroundColor: 'black',\n padding: '10px 10px 4px 10px',\n borderRadius: 10,\n width: '80%',\n },\n};\n\nconst containerWhite: FontTemplate = {\n name: 'container-white',\n containerStyle: {\n backgroundColor: 'white',\n padding: '10px 10px 4px 10px',\n borderRadius: 10,\n width: '80%',\n },\n};\n\nconst containerYellow: FontTemplate = {\n name: 'container-yellow',\n containerStyle: {\n backgroundColor: 'yellow',\n padding: '10px 10px 4px 10px',\n borderRadius: 10,\n width: '80%',\n },\n};\n\nconst containerBlackOpacity40: FontTemplate = {\n name: 'container-black-opacity-40',\n containerStyle: {\n backgroundColor: 'rgba(0, 0, 0, 0.4)',\n padding: '10px 10px 4px 10px',\n borderRadius: 10,\n width: '80%',\n },\n};\n\nconst globalCenter: FontTemplate = {\n name: 'global-center',\n globalPosition: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n },\n};\n\nconst globalHorizontalCenter: FontTemplate = {\n name: 'global-horizontal-center',\n globalPosition: {\n display: 'flex',\n justifyContent: 'center',\n },\n};\n\nconst globalTop5: FontTemplate = {\n name: 'global-top-5',\n globalPosition: {\n position: 'absolute',\n top: '5%',\n },\n};\n\nconst globalTop10: FontTemplate = {\n name: 'global-top-10',\n globalPosition: {\n position: 'absolute',\n top: '10%',\n },\n};\n\nconst globalTop20: FontTemplate = {\n name: 'global-top-20',\n globalPosition: {\n position: 'absolute',\n top: '20%',\n },\n};\n\nconst globalTop70: FontTemplate = {\n name: 'global-top-70',\n globalPosition: {\n position: 'absolute',\n top: '70%',\n },\n};\n\nconst globalTop80: FontTemplate = {\n name: 'global-top-80',\n globalPosition: {\n position: 'absolute',\n top: '80%',\n },\n};\n\nconst globalTop92: FontTemplate = {\n name: 'global-top-92',\n globalPosition: {\n position: 'absolute',\n top: '92%',\n },\n};\n\nconst globalBottom5: FontTemplate = {\n name: 'global-bottom-5',\n globalPosition: {\n position: 'absolute',\n bottom: '5%',\n },\n};\n\nconst globalBottom10: FontTemplate = {\n name: 'global-bottom-10',\n globalPosition: {\n position: 'absolute',\n bottom: '10%',\n },\n};\n\nconst globalBottom15: FontTemplate = {\n name: 'global-bottom-15',\n globalPosition: {\n position: 'absolute',\n bottom: '15%',\n },\n};\n\nconst yellowText = mergeFontTemplates(normal40, fillYellow, strokeBlack8);\nyellowText.name = 'yellowText';\n\nconst whiteText = mergeFontTemplates(normal40, fillWhite, strokeBlack8);\nwhiteText.name = 'whiteText';\n\nconst blackText = mergeFontTemplates(normal40, fillBlack, strokeWhite8);\nblackText.name = 'blackText';\n\nconst baseSubtitle = mergeFontTemplates(normal40, fillWhite, strokeBlack8, globalTop70);\nbaseSubtitle.name = 'baseSubtitle';\n\nconst baseSubtitleCenter = mergeFontTemplates(\n normal40,\n fillWhite,\n strokeBlack8,\n globalTop70,\n container60\n);\nbaseSubtitleCenter.name = 'baseSubtitleCenter';\n\nconst baseSubtitle16_9 = mergeFontTemplates(normal40, fillWhite, strokeBlack4, globalTop92);\nbaseSubtitle16_9.name = 'baseSubtitle16_9';\n\nconst yellowSubtitle = mergeFontTemplates(yellowText, globalTop70);\nyellowSubtitle.name = 'yellowSubtitle';\n\nconst whiteSubtitle = mergeFontTemplates(whiteText, globalTop70);\nwhiteSubtitle.name = 'whiteSubtitle';\n\nconst blackSubtitle = mergeFontTemplates(blackText, globalTop70);\nblackSubtitle.name = 'blackSubtitle';\n\nconst subtitleBackgroundBlack = mergeFontTemplates(\n normal40,\n fillWhite,\n globalTop70,\n containerBlack\n);\nsubtitleBackgroundBlack.name = 'subtitleBackgroundBlack';\n\nconst title = mergeFontTemplates(yellowText, bold50, globalTop5, container95);\ntitle.name = 'title';\n\nconst subtitle = mergeFontTemplates(normal30, fillWhite, strokeBlack8, globalTop5, container80);\nsubtitle.name = 'subtitle';\n\nexport const FONT_TEMPLATES: Record<string, FontTemplate> = {\n 'normal-30': normal30,\n 'normal-40': normal40,\n 'normal-50': normal50,\n 'normal-60': normal60,\n 'normal-80': normal80,\n 'bold-40': bold40,\n 'bold-50': bold50,\n 'bold-60': bold60,\n 'fill-black': fillBlack,\n 'fill-white': fillWhite,\n 'fill-yellow': fillYellow,\n 'fill-red': fillRed,\n 'fill-pink': fillPink,\n 'stroke-black': strokeBlack,\n 'stroke-white': strokeWhite,\n 'stroke-yellow': strokeYellow,\n 'stroke-0': stroke0,\n 'stroke-2': stroke2,\n 'stroke-4': stroke4,\n 'stroke-6': stroke6,\n 'stroke-8': stroke8,\n 'stroke-16': stroke16,\n 'stroke-black-4': strokeBlack4,\n 'stroke-black-6': strokeBlack6,\n 'stroke-black-8': strokeBlack8,\n 'stroke-black-16': strokeBlack16,\n 'stroke-white-4': strokeWhite4,\n 'stroke-white-8': strokeWhite8,\n 'stroke-yellow-4': strokeYellow4,\n 'stroke-yellow-8': strokeYellow8,\n 'container-full': containerFull,\n 'container-60': container60,\n 'container-80': container80,\n 'container-95': container95,\n 'container-98': container98,\n 'container-black': containerBlack,\n 'container-white': containerWhite,\n 'container-yellow': containerYellow,\n 'container-black-opacity-40': containerBlackOpacity40,\n 'global-center': globalCenter,\n 'global-horizontal-center': globalHorizontalCenter,\n 'global-top-5': globalTop5,\n 'global-top-10': globalTop10,\n 'global-top-20': globalTop20,\n 'global-top-70': globalTop70,\n 'global-top-80': globalTop80,\n 'global-top-92': globalTop92,\n 'global-bottom-5': globalBottom5,\n 'global-bottom-10': globalBottom10,\n 'global-bottom-15': globalBottom15,\n yellowText,\n whiteText,\n blackText,\n baseSubtitle,\n baseSubtitleCenter,\n baseSubtitle16_9,\n yellowSubtitle,\n whiteSubtitle,\n blackSubtitle,\n subtitleBackgroundBlack,\n title,\n subtitle,\n};\n\nexport function getTemplate(templateName: string): FontTemplate {\n const templateNames = templateName.split(' ').filter(Boolean);\n const templates = templateNames\n .map((name) => FONT_TEMPLATES[name])\n .filter((t): t is FontTemplate => t !== undefined);\n\n if (templates.length === 0) {\n return {\n name: 'default',\n textStyle: {\n fontSize: 40,\n fontWeight: 400,\n fontFamily: 'Arial, sans-serif',\n fill: 'rgb(255, 255, 255)',\n stroke: 'rgb(0, 0, 0)',\n strokeWidth: 8,\n lineHeight: 1.2,\n },\n };\n }\n\n if (templates.length === 1) {\n return templates[0]!;\n }\n\n return mergeFontTemplates(...templates);\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"font-templates.js","sources":["../../../../src/stages/compose/font-system/font-templates.ts"],"sourcesContent":["import type { TextStyle, ContainerStyle, GlobalPositionStyle } from './types';\n\nexport interface FontTemplate {\n name: string;\n textStyle?: Partial<TextStyle>;\n containerStyle?: Partial<ContainerStyle>;\n globalPosition?: Partial<GlobalPositionStyle>;\n}\n\nexport function mergeFontTemplates(...templates: FontTemplate[]): FontTemplate {\n const merged: FontTemplate = { name: 'merged' };\n\n for (const template of templates) {\n if (template.textStyle) {\n merged.textStyle = { ...merged.textStyle, ...template.textStyle };\n }\n if (template.containerStyle) {\n merged.containerStyle = { ...merged.containerStyle, ...template.containerStyle };\n }\n if (template.globalPosition) {\n merged.globalPosition = { ...merged.globalPosition, ...template.globalPosition };\n }\n }\n\n return merged;\n}\n\nconst normal30: FontTemplate = {\n name: 'normal-30',\n textStyle: { fontSize: 30 },\n};\n\nconst normal40: FontTemplate = {\n name: 'normal-40',\n textStyle: { fontSize: 40 },\n};\n\nconst normal50: FontTemplate = {\n name: 'normal-50',\n textStyle: { fontSize: 50 },\n};\n\nconst normal60: FontTemplate = {\n name: 'normal-60',\n textStyle: { fontSize: 60 },\n};\n\nconst normal80: FontTemplate = {\n name: 'normal-80',\n textStyle: { fontSize: 80 },\n};\n\nconst bold40: FontTemplate = {\n name: 'bold-40',\n textStyle: { fontWeight: 'bold', fontSize: 40 },\n};\n\nconst bold50: FontTemplate = {\n name: 'bold-50',\n textStyle: { fontWeight: 'bold', fontSize: 50 },\n};\n\nconst bold60: FontTemplate = {\n name: 'bold-60',\n textStyle: { fontWeight: 'bold', letterSpacing: '0.05em', fontSize: 60 },\n};\n\nconst fillBlack: FontTemplate = {\n name: 'fill-black',\n textStyle: { fill: 'rgb(0, 0, 0)' },\n};\n\nconst fillWhite: FontTemplate = {\n name: 'fill-white',\n textStyle: { fill: 'rgb(255, 255, 255)' },\n};\n\nconst fillYellow: FontTemplate = {\n name: 'fill-yellow',\n textStyle: { fill: 'rgb(255, 215, 0)' },\n};\n\nconst fillRed: FontTemplate = {\n name: 'fill-red',\n textStyle: { fill: 'rgb(255, 77, 77)' },\n};\n\nconst fillPink: FontTemplate = {\n name: 'fill-pink',\n textStyle: { fill: 'rgb(255, 192, 203)' },\n};\n\nconst strokeBlack: FontTemplate = {\n name: 'stroke-black',\n textStyle: {\n paintOrder: 'stroke',\n strokeLinejoin: 'round',\n strokeLinecap: 'round',\n strokeColor: 'rgb(0, 0, 0)',\n },\n};\n\nconst strokeWhite: FontTemplate = {\n name: 'stroke-white',\n textStyle: {\n paintOrder: 'stroke',\n strokeLinejoin: 'round',\n strokeLinecap: 'round',\n strokeColor: 'rgb(255, 255, 255)',\n },\n};\n\nconst strokeYellow: FontTemplate = {\n name: 'stroke-yellow',\n textStyle: {\n paintOrder: 'stroke',\n strokeLinejoin: 'round',\n strokeLinecap: 'round',\n strokeColor: 'rgb(255, 215, 0)',\n },\n};\n\nconst stroke0: FontTemplate = {\n name: 'stroke-0',\n textStyle: { strokeWidth: 0 },\n};\n\nconst stroke2: FontTemplate = {\n name: 'stroke-2',\n textStyle: { strokeWidth: 2 },\n};\n\nconst stroke4: FontTemplate = {\n name: 'stroke-4',\n textStyle: { strokeWidth: 4 },\n};\n\nconst stroke6: FontTemplate = {\n name: 'stroke-6',\n textStyle: { strokeWidth: 6 },\n};\n\nconst stroke8: FontTemplate = {\n name: 'stroke-8',\n textStyle: { strokeWidth: 8 },\n};\n\nconst stroke16: FontTemplate = {\n name: 'stroke-16',\n textStyle: { strokeWidth: 16 },\n};\n\nconst strokeBlack4 = mergeFontTemplates(strokeBlack, stroke4);\nstrokeBlack4.name = 'stroke-black-4';\n\nconst strokeBlack6 = mergeFontTemplates(strokeBlack, stroke6);\nstrokeBlack6.name = 'stroke-black-6';\n\nconst strokeBlack8 = mergeFontTemplates(strokeBlack, stroke8);\nstrokeBlack8.name = 'stroke-black-8';\n\nconst strokeBlack16 = mergeFontTemplates(strokeBlack, stroke16);\nstrokeBlack16.name = 'stroke-black-16';\n\nconst strokeWhite4 = mergeFontTemplates(strokeWhite, stroke4);\nstrokeWhite4.name = 'stroke-white-4';\n\nconst strokeWhite8 = mergeFontTemplates(strokeWhite, stroke8);\nstrokeWhite8.name = 'stroke-white-8';\n\nconst strokeYellow4 = mergeFontTemplates(strokeYellow, stroke4);\nstrokeYellow4.name = 'stroke-yellow-4';\n\nconst strokeYellow8 = mergeFontTemplates(strokeYellow, stroke8);\nstrokeYellow8.name = 'stroke-yellow-8';\n\nconst containerFull: FontTemplate = {\n name: 'container-full',\n containerStyle: { width: '100%' },\n};\n\nconst container60: FontTemplate = {\n name: 'container-60',\n containerStyle: { width: '60%' },\n};\n\nconst container80: FontTemplate = {\n name: 'container-80',\n containerStyle: { width: '80%' },\n};\n\nconst container95: FontTemplate = {\n name: 'container-95',\n containerStyle: { width: '95%' },\n};\n\nconst container98: FontTemplate = {\n name: 'container-98',\n containerStyle: { width: '98%' },\n};\n\nconst containerBlack: FontTemplate = {\n name: 'container-black',\n containerStyle: {\n backgroundColor: 'black',\n padding: '10px 10px 4px 10px',\n borderRadius: 10,\n width: '80%',\n },\n};\n\nconst containerWhite: FontTemplate = {\n name: 'container-white',\n containerStyle: {\n backgroundColor: 'white',\n padding: '10px 10px 4px 10px',\n borderRadius: 10,\n width: '80%',\n },\n};\n\nconst containerYellow: FontTemplate = {\n name: 'container-yellow',\n containerStyle: {\n backgroundColor: 'yellow',\n padding: '10px 10px 4px 10px',\n borderRadius: 10,\n width: '80%',\n },\n};\n\nconst containerBlackOpacity40: FontTemplate = {\n name: 'container-black-opacity-40',\n containerStyle: {\n backgroundColor: 'rgba(0, 0, 0, 0.4)',\n padding: '10px 10px 4px 10px',\n borderRadius: 10,\n width: '80%',\n },\n};\n\nconst globalCenter: FontTemplate = {\n name: 'global-center',\n globalPosition: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n },\n};\n\nconst globalHorizontalCenter: FontTemplate = {\n name: 'global-horizontal-center',\n globalPosition: {\n display: 'flex',\n justifyContent: 'center',\n },\n};\n\nconst globalTop5: FontTemplate = {\n name: 'global-top-5',\n globalPosition: {\n position: 'absolute',\n top: '5%',\n },\n};\n\nconst globalTop10: FontTemplate = {\n name: 'global-top-10',\n globalPosition: {\n position: 'absolute',\n top: '10%',\n },\n};\n\nconst globalTop20: FontTemplate = {\n name: 'global-top-20',\n globalPosition: {\n position: 'absolute',\n top: '20%',\n },\n};\n\nconst globalTop70: FontTemplate = {\n name: 'global-top-70',\n globalPosition: {\n position: 'absolute',\n top: '70%',\n },\n};\n\nconst globalTop80: FontTemplate = {\n name: 'global-top-80',\n globalPosition: {\n position: 'absolute',\n top: '80%',\n },\n};\n\nconst globalTop92: FontTemplate = {\n name: 'global-top-92',\n globalPosition: {\n position: 'absolute',\n top: '92%',\n },\n};\n\nconst globalBottom5: FontTemplate = {\n name: 'global-bottom-5',\n globalPosition: {\n position: 'absolute',\n bottom: '5%',\n },\n};\n\nconst globalBottom10: FontTemplate = {\n name: 'global-bottom-10',\n globalPosition: {\n position: 'absolute',\n bottom: '10%',\n },\n};\n\nconst globalBottom15: FontTemplate = {\n name: 'global-bottom-15',\n globalPosition: {\n position: 'absolute',\n bottom: '15%',\n },\n};\n\nconst yellowText = mergeFontTemplates(normal40, fillYellow, strokeBlack8);\nyellowText.name = 'yellowText';\n\nconst whiteText = mergeFontTemplates(normal40, fillWhite, strokeBlack8);\nwhiteText.name = 'whiteText';\n\nconst blackText = mergeFontTemplates(normal40, fillBlack, strokeWhite8);\nblackText.name = 'blackText';\n\nconst baseSubtitle = mergeFontTemplates(normal40, fillWhite, strokeBlack8, globalTop70);\nbaseSubtitle.name = 'baseSubtitle';\n\nconst baseSubtitleCenter = mergeFontTemplates(\n normal40,\n fillWhite,\n strokeBlack8,\n globalTop70,\n container60\n);\nbaseSubtitleCenter.name = 'baseSubtitleCenter';\n\nconst baseSubtitle16_9 = mergeFontTemplates(normal40, fillWhite, strokeBlack4, globalTop92);\nbaseSubtitle16_9.name = 'baseSubtitle16_9';\n\nconst yellowSubtitle = mergeFontTemplates(yellowText, globalTop70);\nyellowSubtitle.name = 'yellowSubtitle';\n\nconst whiteSubtitle = mergeFontTemplates(whiteText, globalTop70);\nwhiteSubtitle.name = 'whiteSubtitle';\n\nconst blackSubtitle = mergeFontTemplates(blackText, globalTop70);\nblackSubtitle.name = 'blackSubtitle';\n\nconst subtitleBackgroundBlack = mergeFontTemplates(\n normal40,\n fillWhite,\n globalTop70,\n containerBlack\n);\nsubtitleBackgroundBlack.name = 'subtitleBackgroundBlack';\n\nconst title = mergeFontTemplates(yellowText, bold50, globalTop5, container95);\ntitle.name = 'title';\n\nconst subtitle = mergeFontTemplates(normal30, fillWhite, strokeBlack8, globalTop5, container80);\nsubtitle.name = 'subtitle';\n\nexport const FONT_TEMPLATES: Record<string, FontTemplate> = {\n 'normal-30': normal30,\n 'normal-40': normal40,\n 'normal-50': normal50,\n 'normal-60': normal60,\n 'normal-80': normal80,\n 'bold-40': bold40,\n 'bold-50': bold50,\n 'bold-60': bold60,\n 'fill-black': fillBlack,\n 'fill-white': fillWhite,\n 'fill-yellow': fillYellow,\n 'fill-red': fillRed,\n 'fill-pink': fillPink,\n 'stroke-black': strokeBlack,\n 'stroke-white': strokeWhite,\n 'stroke-yellow': strokeYellow,\n 'stroke-0': stroke0,\n 'stroke-2': stroke2,\n 'stroke-4': stroke4,\n 'stroke-6': stroke6,\n 'stroke-8': stroke8,\n 'stroke-16': stroke16,\n 'stroke-black-4': strokeBlack4,\n 'stroke-black-6': strokeBlack6,\n 'stroke-black-8': strokeBlack8,\n 'stroke-black-16': strokeBlack16,\n 'stroke-white-4': strokeWhite4,\n 'stroke-white-8': strokeWhite8,\n 'stroke-yellow-4': strokeYellow4,\n 'stroke-yellow-8': strokeYellow8,\n 'container-full': containerFull,\n 'container-60': container60,\n 'container-80': container80,\n 'container-95': container95,\n 'container-98': container98,\n 'container-black': containerBlack,\n 'container-white': containerWhite,\n 'container-yellow': containerYellow,\n 'container-black-opacity-40': containerBlackOpacity40,\n 'global-center': globalCenter,\n 'global-horizontal-center': globalHorizontalCenter,\n 'global-top-5': globalTop5,\n 'global-top-10': globalTop10,\n 'global-top-20': globalTop20,\n 'global-top-70': globalTop70,\n 'global-top-80': globalTop80,\n 'global-top-92': globalTop92,\n 'global-bottom-5': globalBottom5,\n 'global-bottom-10': globalBottom10,\n 'global-bottom-15': globalBottom15,\n yellowText,\n whiteText,\n blackText,\n baseSubtitle,\n baseSubtitleCenter,\n baseSubtitle16_9,\n yellowSubtitle,\n whiteSubtitle,\n blackSubtitle,\n subtitleBackgroundBlack,\n title,\n subtitle,\n};\n\nexport function getTemplate(templateName: string): FontTemplate {\n const templateNames = templateName.split(' ').filter(Boolean);\n const templates = templateNames\n .map((name) => FONT_TEMPLATES[name])\n .filter((t): t is FontTemplate => t !== undefined);\n\n if (templates.length === 0) {\n return {\n name: 'default',\n textStyle: {\n fontSize: 40,\n fontWeight: 400,\n fontFamily: 'Arial, sans-serif',\n fill: 'rgb(255, 255, 255)',\n strokeColor: 'rgb(0, 0, 0)',\n strokeWidth: 8,\n lineHeight: 1.2,\n },\n };\n }\n\n if (templates.length === 1) {\n return templates[0]!;\n }\n\n return mergeFontTemplates(...templates);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/stages/compose/font-system/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAEnF,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/stages/compose/font-system/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAEnF,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,cAAc,CAAC,EAAE,mBAAmB,CAAC;CACtC;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,cAAc,CAAC,EAAE,mBAAmB,CAAC;CACtC;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EACA,MAAM,GACN,MAAM,GACN,YAAY,GACZ,cAAc,GACd,iBAAiB,GACjB,mBAAmB,GACnB,SAAS,GACT,OAAO,GACP,aAAa,GACb,MAAM,GACN,QAAQ,GACR,YAAY,GACZ,cAAc,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,SAAS,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -74,7 +74,7 @@ export interface SerializedTextLayerPayload extends LayerPayloadBase {
|
|
|
74
74
|
fontWeight: string | number;
|
|
75
75
|
fontFamily: string;
|
|
76
76
|
fill: string;
|
|
77
|
-
|
|
77
|
+
strokeColor?: string;
|
|
78
78
|
strokeWidth?: number;
|
|
79
79
|
letterSpacing?: string | number;
|
|
80
80
|
lineHeight?: number;
|
|
@@ -107,7 +107,7 @@ export interface SerializedTextLayerPayload extends LayerPayloadBase {
|
|
|
107
107
|
highlightColor?: string;
|
|
108
108
|
highlightTextStyle?: {
|
|
109
109
|
fill?: string;
|
|
110
|
-
|
|
110
|
+
strokeColor?: string;
|
|
111
111
|
};
|
|
112
112
|
[key: string]: unknown;
|
|
113
113
|
};
|
|
@@ -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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"}
|
|
@@ -25,7 +25,7 @@ function drawBasicTextLines(ctx, layer, canvasWidth, canvasHeight, lines) {
|
|
|
25
25
|
const fontFamily = fontConfig.fontFamily;
|
|
26
26
|
const fontWeight = fontConfig.fontWeight;
|
|
27
27
|
const fill = fontConfig.fill;
|
|
28
|
-
const
|
|
28
|
+
const strokeColor = fontConfig.strokeColor;
|
|
29
29
|
const strokeWidth = fontConfig.strokeWidth || 0;
|
|
30
30
|
const lineHeight = fontConfig.lineHeight || 1.2;
|
|
31
31
|
ctx.save();
|
|
@@ -39,8 +39,8 @@ function drawBasicTextLines(ctx, layer, canvasWidth, canvasHeight, lines) {
|
|
|
39
39
|
for (let i = 0; i < lines.length; i++) {
|
|
40
40
|
const line = lines[i];
|
|
41
41
|
const y = startY + i * fontSize * lineHeight + fontSize / 2;
|
|
42
|
-
if (
|
|
43
|
-
ctx.strokeStyle =
|
|
42
|
+
if (strokeColor && strokeWidth > 0) {
|
|
43
|
+
ctx.strokeStyle = strokeColor;
|
|
44
44
|
ctx.lineWidth = strokeWidth;
|
|
45
45
|
ctx.strokeText(line, canvasWidth / 2, y);
|
|
46
46
|
}
|
|
@@ -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 {\n getCachedEvenLinesWithWords,\n getCachedWrapText,\n getCachedBasicTextRaster,\n} from '../text-utils/text-layout-cache';\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 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 if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nfunction drawBasicTextLines(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n lines: string[]\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
|
|
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 {\n getCachedEvenLinesWithWords,\n getCachedWrapText,\n getCachedBasicTextRaster,\n} from '../text-utils/text-layout-cache';\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 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 if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nfunction drawBasicTextLines(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n lines: string[]\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 strokeColor = fontConfig.strokeColor;\n const strokeWidth = fontConfig.strokeWidth || 0;\n const lineHeight = fontConfig.lineHeight || 1.2;\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 (strokeColor && strokeWidth > 0) {\n ctx.strokeStyle = strokeColor;\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\nfunction resolveBasicTextLines(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number\n): string[] {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return [];\n\n const maxWidth = canvasWidth * 0.64;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n\n if (layer.wordTimings && layer.wordTimings.length > 0) {\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const words = needsSpace ? text.split(/\\s+/) : Array.from(text);\n return getCachedEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontConfig.fontSize,\n needsSpace,\n fontConfig.fontFamily,\n fontConfig.fontWeight\n );\n }\n\n return getCachedWrapText(\n ctx,\n text,\n maxWidth,\n fontConfig.fontSize,\n fontConfig.fontFamily,\n fontConfig.fontWeight\n );\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 raster = getCachedBasicTextRaster(layer, canvasWidth, canvasHeight, (offCtx) => {\n const lines = resolveBasicTextLines(offCtx, layer, canvasWidth);\n if (lines.length === 0) return;\n drawBasicTextLines(offCtx, layer, canvasWidth, canvasHeight, lines);\n });\n\n if (raster) {\n ctx.drawImage(raster, 0, 0);\n return;\n }\n\n const lines = resolveBasicTextLines(ctx, layer, canvasWidth);\n if (lines.length === 0) return;\n drawBasicTextLines(ctx, layer, canvasWidth, canvasHeight, lines);\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":["lines"],"mappings":"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"}
|
|
@@ -1 +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;
|
|
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;AA8CnB,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAO5F;AAwMD,wBAAgB,wBAAwB,IAAI,IAAI,CAM/C;AAED;;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,CA0BN"}
|
|
@@ -49,6 +49,9 @@ function layoutCacheKey(layer, canvasWidth, canvasHeight) {
|
|
|
49
49
|
ts?.fontSize,
|
|
50
50
|
ts?.fontFamily,
|
|
51
51
|
ts?.fontWeight,
|
|
52
|
+
ts?.fill,
|
|
53
|
+
ts?.strokeColor,
|
|
54
|
+
ts?.strokeWidth,
|
|
52
55
|
ts?.lineHeight,
|
|
53
56
|
JSON.stringify(layer.fontConfig?.globalPosition ?? null)
|
|
54
57
|
].join("");
|
|
@@ -133,7 +136,7 @@ function drawStaggerEntranceFrame(ctx, layer, built, relativeFrame, fps, preset)
|
|
|
133
136
|
const fontFamily = fontConfig.fontFamily;
|
|
134
137
|
const fontWeight = fontConfig.fontWeight;
|
|
135
138
|
const fill = fontConfig.fill;
|
|
136
|
-
const
|
|
139
|
+
const strokeColor = fontConfig.strokeColor;
|
|
137
140
|
const strokeWidth = fontConfig.strokeWidth || 0;
|
|
138
141
|
const scalePx = fontSize / FONT_REF_PX;
|
|
139
142
|
const staggerMs = DEFAULT_STAGGER_MS;
|
|
@@ -208,8 +211,8 @@ function drawStaggerEntranceFrame(ctx, layer, built, relativeFrame, fps, preset)
|
|
|
208
211
|
} else {
|
|
209
212
|
ctx.scale(sc, sc);
|
|
210
213
|
}
|
|
211
|
-
if (
|
|
212
|
-
ctx.strokeStyle =
|
|
214
|
+
if (strokeColor && strokeWidth > 0) {
|
|
215
|
+
ctx.strokeStyle = strokeColor;
|
|
213
216
|
ctx.lineWidth = strokeWidth;
|
|
214
217
|
ctx.strokeText(slot.ch, 0, 0);
|
|
215
218
|
}
|
|
@@ -1 +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 { getCachedEvenLinesWithWords, getCachedWrapText } from '../text-utils/text-layout-cache';\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\ninterface CharSlotsLayout {\n slots: CharSlot[];\n fontSize: number;\n lineHeight: number;\n}\n\nconst charSlotsCache = new Map<string, CharSlotsLayout>();\nconst staggerFinalRasterCache = new Map<string, ImageBitmap>();\n\nfunction layoutCacheKey(layer: TextLayer, canvasWidth: number, canvasHeight: number): string {\n const ts = layer.fontConfig?.textStyle;\n return [\n layer.id,\n layer.text,\n layer.letterCase ?? '',\n canvasWidth,\n canvasHeight,\n ts?.fontSize,\n ts?.fontFamily,\n ts?.fontWeight,\n ts?.lineHeight,\n JSON.stringify(layer.fontConfig?.globalPosition ?? null),\n ].join('\\x1f');\n}\n\nfunction staggerRasterKey(\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n preset: CaptionStaggerPreset\n): string {\n return `${layoutCacheKey(layer, canvasWidth, canvasHeight)}\\x1f${preset}`;\n}\n\nexport function staggerEntranceEndMs(slotCount: number, preset: CaptionStaggerPreset): number {\n if (slotCount <= 0) return 0;\n const lastIndex = slotCount - 1;\n if (preset === 'typewriter') {\n return lastIndex * DEFAULT_STAGGER_MS + DEFAULT_STAGGER_MS;\n }\n return lastIndex * DEFAULT_STAGGER_MS + DEFAULT_DURATION_MS;\n}\n\nfunction buildCharSlots(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number\n): CharSlotsLayout | 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 = needsSpace ? text.split(/\\s+/) : Array.from(text);\n lines = getCachedEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n } else {\n lines = getCachedWrapText(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\nfunction getCachedCharSlots(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number\n): CharSlotsLayout | null {\n const key = layoutCacheKey(layer, canvasWidth, canvasHeight);\n const cached = charSlotsCache.get(key);\n if (cached) {\n return cached;\n }\n const built = buildCharSlots(ctx, layer, canvasWidth, canvasHeight);\n if (built) {\n charSlotsCache.set(key, built);\n }\n return built;\n}\n\nfunction drawStaggerEntranceFrame(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n built: CharSlotsLayout,\n relativeFrame: number,\n fps: number,\n preset: CaptionStaggerPreset\n): void {\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\nexport function clearCaptionStaggerCache(): void {\n charSlotsCache.clear();\n for (const bitmap of staggerFinalRasterCache.values()) {\n bitmap.close();\n }\n staggerFinalRasterCache.clear();\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 = getCachedCharSlots(ctx, layer, canvasWidth, canvasHeight);\n if (!built) return;\n\n const endMs = staggerEntranceEndMs(built.slots.length, preset);\n const endFrame = Math.ceil((endMs / 1000) * fps);\n\n if (relativeFrame >= endFrame) {\n const rasterKey = staggerRasterKey(layer, canvasWidth, canvasHeight, preset);\n let bitmap = staggerFinalRasterCache.get(rasterKey);\n if (!bitmap) {\n const offscreen = new OffscreenCanvas(canvasWidth, canvasHeight);\n const offCtx = offscreen.getContext('2d');\n if (!offCtx) {\n drawStaggerEntranceFrame(ctx, layer, built, endFrame, fps, preset);\n return;\n }\n drawStaggerEntranceFrame(offCtx, layer, built, endFrame, fps, preset);\n bitmap = offscreen.transferToImageBitmap();\n staggerFinalRasterCache.set(rasterKey, bitmap);\n }\n ctx.drawImage(bitmap, 0, 0);\n return;\n }\n\n drawStaggerEntranceFrame(ctx, layer, built, relativeFrame, fps, preset);\n}\n"],"names":[],"mappings":"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"}
|
|
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 { getCachedEvenLinesWithWords, getCachedWrapText } from '../text-utils/text-layout-cache';\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\ninterface CharSlotsLayout {\n slots: CharSlot[];\n fontSize: number;\n lineHeight: number;\n}\n\nconst charSlotsCache = new Map<string, CharSlotsLayout>();\nconst staggerFinalRasterCache = new Map<string, ImageBitmap>();\n\nfunction layoutCacheKey(layer: TextLayer, canvasWidth: number, canvasHeight: number): string {\n const ts = layer.fontConfig?.textStyle;\n return [\n layer.id,\n layer.text,\n layer.letterCase ?? '',\n canvasWidth,\n canvasHeight,\n ts?.fontSize,\n ts?.fontFamily,\n ts?.fontWeight,\n ts?.fill,\n ts?.strokeColor,\n ts?.strokeWidth,\n ts?.lineHeight,\n JSON.stringify(layer.fontConfig?.globalPosition ?? null),\n ].join('\\x1f');\n}\n\nfunction staggerRasterKey(\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n preset: CaptionStaggerPreset\n): string {\n return `${layoutCacheKey(layer, canvasWidth, canvasHeight)}\\x1f${preset}`;\n}\n\nexport function staggerEntranceEndMs(slotCount: number, preset: CaptionStaggerPreset): number {\n if (slotCount <= 0) return 0;\n const lastIndex = slotCount - 1;\n if (preset === 'typewriter') {\n return lastIndex * DEFAULT_STAGGER_MS + DEFAULT_STAGGER_MS;\n }\n return lastIndex * DEFAULT_STAGGER_MS + DEFAULT_DURATION_MS;\n}\n\nfunction buildCharSlots(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number\n): CharSlotsLayout | 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 = needsSpace ? text.split(/\\s+/) : Array.from(text);\n lines = getCachedEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n } else {\n lines = getCachedWrapText(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\nfunction getCachedCharSlots(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number\n): CharSlotsLayout | null {\n const key = layoutCacheKey(layer, canvasWidth, canvasHeight);\n const cached = charSlotsCache.get(key);\n if (cached) {\n return cached;\n }\n const built = buildCharSlots(ctx, layer, canvasWidth, canvasHeight);\n if (built) {\n charSlotsCache.set(key, built);\n }\n return built;\n}\n\nfunction drawStaggerEntranceFrame(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n built: CharSlotsLayout,\n relativeFrame: number,\n fps: number,\n preset: CaptionStaggerPreset\n): void {\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 strokeColor = fontConfig.strokeColor;\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 (strokeColor && strokeWidth > 0) {\n ctx.strokeStyle = strokeColor;\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\nexport function clearCaptionStaggerCache(): void {\n charSlotsCache.clear();\n for (const bitmap of staggerFinalRasterCache.values()) {\n bitmap.close();\n }\n staggerFinalRasterCache.clear();\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 = getCachedCharSlots(ctx, layer, canvasWidth, canvasHeight);\n if (!built) return;\n\n const endMs = staggerEntranceEndMs(built.slots.length, preset);\n const endFrame = Math.ceil((endMs / 1000) * fps);\n\n if (relativeFrame >= endFrame) {\n const rasterKey = staggerRasterKey(layer, canvasWidth, canvasHeight, preset);\n let bitmap = staggerFinalRasterCache.get(rasterKey);\n if (!bitmap) {\n const offscreen = new OffscreenCanvas(canvasWidth, canvasHeight);\n const offCtx = offscreen.getContext('2d');\n if (!offCtx) {\n drawStaggerEntranceFrame(ctx, layer, built, endFrame, fps, preset);\n return;\n }\n drawStaggerEntranceFrame(offCtx, layer, built, endFrame, fps, preset);\n bitmap = offscreen.transferToImageBitmap();\n staggerFinalRasterCache.set(rasterKey, bitmap);\n }\n ctx.drawImage(bitmap, 0, 0);\n return;\n }\n\n drawStaggerEntranceFrame(ctx, layer, built, relativeFrame, fps, preset);\n}\n"],"names":[],"mappings":";;;AAMA,MAAM,sBAAsB;AAC5B,MAAM,qBAAqB;AAC3B,MAAM,gBAAgB;AACtB,MAAM,wBAAwB;AAC9B,MAAM,gBAAgB;AACtB,MAAM,cAAc;AAEpB,SAAS,YAAY,GAAmB;AACtC,MAAI,KAAK,EAAG,QAAO;AACnB,MAAI,KAAK,EAAG,QAAO;AACnB,SAAO,IAAI,KAAK,IAAI,GAAG,MAAM,CAAC;AAChC;AAEA,SAAS,mBACP,cACA,aACA,gBAUQ;AACR,MAAI,CAAC,gBAAgB;AACnB,WAAO,eAAe,IAAI,cAAc;AAAA,EAC1C;AACA,MAAI,eAAe,KAAK;AACtB,UAAM,aAAa,WAAW,eAAe,GAAG,IAAI;AACpD,WAAO,eAAe;AAAA,EACxB;AACA,MAAI,eAAe,QAAQ;AACzB,UAAM,gBAAgB,WAAW,eAAe,MAAM,IAAI;AAC1D,WAAO,gBAAgB,IAAI,iBAAiB;AAAA,EAC9C;AACA,MAAI,eAAe,mBAAmB,YAAY,eAAe,eAAe,UAAU;AACxF,WAAO,eAAe,IAAI,cAAc;AAAA,EAC1C;AACA,SAAO,eAAe,IAAI,cAAc;AAC1C;AAEO,SAAS,aACd,eACA,KACA,WACA,WACA,YACQ;AACR,QAAM,MAAO,gBAAgB,MAAO;AACpC,QAAM,UAAU,YAAY;AAC5B,MAAI,OAAO,QAAS,QAAO;AAC3B,QAAM,OAAO,MAAM,WAAW;AAC9B,SAAO,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC;AACrC;AAyBA,MAAM,qCAAqB,IAAA;AAC3B,MAAM,8CAA8B,IAAA;AAEpC,SAAS,eAAe,OAAkB,aAAqB,cAA8B;AAC3F,QAAM,KAAK,MAAM,YAAY;AAC7B,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM,cAAc;AAAA,IACpB;AAAA,IACA;AAAA,IACA,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,KAAK,UAAU,MAAM,YAAY,kBAAkB,IAAI;AAAA,EAAA,EACvD,KAAK,GAAM;AACf;AAEA,SAAS,iBACP,OACA,aACA,cACA,QACQ;AACR,SAAO,GAAG,eAAe,OAAO,aAAa,YAAY,CAAC,IAAO,MAAM;AACzE;AAEO,SAAS,qBAAqB,WAAmB,QAAsC;AAC5F,MAAI,aAAa,EAAG,QAAO;AAC3B,QAAM,YAAY,YAAY;AAC9B,MAAI,WAAW,cAAc;AAC3B,WAAO,YAAY,qBAAqB;AAAA,EAC1C;AACA,SAAO,YAAY,qBAAqB;AAC1C;AAEA,SAAS,eACP,KACA,OACA,aACA,cACwB;AACxB,QAAM,aAAa,MAAM,YAAY;AACrC,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,WAAW,WAAW;AAC5B,QAAM,aAAa,WAAW;AAC9B,QAAM,aAAa,WAAW;AAC9B,QAAM,aAAa,WAAW,cAAc;AAC5C,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,aAAa,KAAK,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI;AAC9D,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ,OAAO;AACL,YAAQ,kBAAkB,KAAK,MAAM,UAAU,UAAU,YAAY,UAAU;AAAA,EACjF;AAEA,QAAM,cAAc,MAAM,SAAS,WAAW;AAC9C,QAAM,SAAS,mBAAmB,cAAc,aAAa,MAAM,YAAY,cAAc;AAE7F,MAAI,KAAA;AACJ,MAAI,OAAO,GAAG,UAAU,IAAI,QAAQ,MAAM,UAAU;AAEpD,QAAM,QAAoB,CAAA;AAC1B,MAAI,cAAc;AAElB,WAAS,YAAY,GAAG,YAAY,MAAM,QAAQ,aAAa;AAC7D,UAAM,OAAO,MAAM,SAAS;AAC5B,UAAM,IAAI,SAAS,YAAY,WAAW,aAAa,WAAW;AAClE,UAAM,YAAY,iBAAiB,KAAK,MAAM,UAAU,YAAY,UAAU;AAC9E,QAAI,KAAK,cAAc,IAAI,YAAY;AAEvC,eAAW,MAAM,MAAM,KAAK,IAAI,GAAG;AACjC,YAAM,KAAK,iBAAiB,KAAK,IAAI,UAAU,YAAY,UAAU;AACrE,YAAM,KAAK;AAAA,QACT;AAAA,QACA,GAAG,KAAK,KAAK;AAAA,QACb;AAAA,QACA;AAAA,MAAA,CACD;AACD;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAEA,MAAI,QAAA;AACJ,SAAO,EAAE,OAAO,UAAU,WAAA;AAC5B;AAEA,SAAS,mBACP,KACA,OACA,aACA,cACwB;AACxB,QAAM,MAAM,eAAe,OAAO,aAAa,YAAY;AAC3D,QAAM,SAAS,eAAe,IAAI,GAAG;AACrC,MAAI,QAAQ;AACV,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,eAAe,KAAK,OAAO,aAAa,YAAY;AAClE,MAAI,OAAO;AACT,mBAAe,IAAI,KAAK,KAAK;AAAA,EAC/B;AACA,SAAO;AACT;AAEA,SAAS,yBACP,KACA,OACA,OACA,eACA,KACA,QACM;AACN,QAAM,EAAE,OAAO,SAAA,IAAa;AAC5B,QAAM,aAAa,MAAM,WAAY;AACrC,QAAM,aAAa,WAAW;AAC9B,QAAM,aAAa,WAAW;AAC9B,QAAM,OAAO,WAAW;AACxB,QAAM,cAAc,WAAW;AAC/B,QAAM,cAAc,WAAW,eAAe;AAE9C,QAAM,UAAU,WAAW;AAC3B,QAAM,YAAY;AAElB,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,YAAa,gBAAgB,MAAO;AAE1C,aAAW,QAAQ,OAAO;AACxB,QAAI;AACJ,QAAI,WAAW,cAAc;AAC3B,YAAM,UAAU,KAAK,cAAc;AACnC,UAAI,aAAa,UAAU,IAAI;AAAA,IACjC,OAAO;AACL,UAAI,aAAa,eAAe,KAAK,KAAK,aAAa,WAAW,mBAAmB;AAAA,IACvF;AACA,QAAI,KAAK,KAAK,WAAW,OAAQ;AAEjC,UAAM,UAAU,gBAAgB;AAChC,UAAM,WAAW,wBAAwB;AAEzC,QAAI,KAAA;AAEJ,QAAI,UAAU;AACd,QAAI,KAAK;AACT,QAAI,KAAK;AACT,QAAI,MAAM;AACV,QAAI,KAAK;AACT,QAAI,KAAK;AACT,QAAI,SAAS;AAEb,YAAQ,QAAA;AAAA,MACN,KAAK;AACH,kBAAU;AACV;AAAA,MACF,KAAK;AACH,kBAAU;AACV,cAAM,IAAI,KAAK;AACf;AAAA,MACF,KAAK;AACH,kBAAU;AACV,aAAK,KAAK,IAAI,MAAM,CAAC;AACrB;AAAA,MACF,KAAK;AACH,kBAAU;AACV,eAAQ,IAAI,KAAK,KAAK,KAAK,KAAM;AACjC,aAAK,MAAM,IAAI;AACf;AAAA,MACF,KAAK;AACH,kBAAU;AACV,kBAAU,IAAI,KAAK;AACnB;AAAA,MACF,KAAK;AACH,kBAAU;AACV,aAAK,KAAK,IAAI,MAAM,CAAC;AACrB,aAAK;AACL;AAAA,MACF,KAAK;AACH,kBAAU,KAAK,IAAI,IAAI;AACvB;AAAA,MACF,KAAK;AACH,kBAAU;AACV,cAAM,IAAI,KAAK,WAAW,KAAK;AAC/B;AAAA,IAEA;AAGJ,QAAI,cAAc;AAClB,QAAI,SAAS,MAAM;AACjB,UAAI,SAAS,QAAQ,MAAM;AAAA,IAC7B;AAEA,QAAI,UAAU,KAAK,IAAI,IAAI,KAAK,IAAI,EAAE;AACtC,QAAI,OAAO,GAAG;AACd,QAAI,WAAW,UAAU;AACvB,UAAI,MAAM,GAAG,EAAE;AAAA,IACjB,OAAO;AACL,UAAI,MAAM,IAAI,EAAE;AAAA,IAClB;AAEA,QAAI,eAAe,cAAc,GAAG;AAClC,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,WAAW,KAAK,IAAI,GAAG,CAAC;AAAA,IAC9B;AACA,QAAI,YAAY;AAChB,QAAI,SAAS,KAAK,IAAI,GAAG,CAAC;AAE1B,QAAI,QAAA;AAAA,EACN;AAEA,MAAI,QAAA;AACN;AAEO,SAAS,2BAAiC;AAC/C,iBAAe,MAAA;AACf,aAAW,UAAU,wBAAwB,UAAU;AACrD,WAAO,MAAA;AAAA,EACT;AACA,0BAAwB,MAAA;AAC1B;AAKO,SAAS,6BACd,KACA,OACA,aACA,cACA,eACA,KACA,QACM;AACN,QAAM,QAAQ,mBAAmB,KAAK,OAAO,aAAa,YAAY;AACtE,MAAI,CAAC,MAAO;AAEZ,QAAM,QAAQ,qBAAqB,MAAM,MAAM,QAAQ,MAAM;AAC7D,QAAM,WAAW,KAAK,KAAM,QAAQ,MAAQ,GAAG;AAE/C,MAAI,iBAAiB,UAAU;AAC7B,UAAM,YAAY,iBAAiB,OAAO,aAAa,cAAc,MAAM;AAC3E,QAAI,SAAS,wBAAwB,IAAI,SAAS;AAClD,QAAI,CAAC,QAAQ;AACX,YAAM,YAAY,IAAI,gBAAgB,aAAa,YAAY;AAC/D,YAAM,SAAS,UAAU,WAAW,IAAI;AACxC,UAAI,CAAC,QAAQ;AACX,iCAAyB,KAAK,OAAO,OAAO,UAAU,KAAK,MAAM;AACjE;AAAA,MACF;AACA,+BAAyB,QAAQ,OAAO,OAAO,UAAU,KAAK,MAAM;AACpE,eAAS,UAAU,sBAAA;AACnB,8BAAwB,IAAI,WAAW,MAAM;AAAA,IAC/C;AACA,QAAI,UAAU,QAAQ,GAAG,CAAC;AAC1B;AAAA,EACF;AAEA,2BAAyB,KAAK,OAAO,OAAO,eAAe,KAAK,MAAM;AACxE;"}
|
|
@@ -28,7 +28,7 @@ function renderCharacterKTV(ctx, layer, canvasWidth, canvasHeight, relativeFrame
|
|
|
28
28
|
const fontFamily = fontConfig.fontFamily;
|
|
29
29
|
const fontWeight = fontConfig.fontWeight;
|
|
30
30
|
const baseFill = fontConfig.fill;
|
|
31
|
-
const
|
|
31
|
+
const strokeColor = fontConfig.strokeColor;
|
|
32
32
|
const strokeWidth = fontConfig.strokeWidth || 0;
|
|
33
33
|
const lineHeight = fontConfig.lineHeight || 1.2;
|
|
34
34
|
const highlightFill = layer.animation?.highlightTextStyle?.fill || "rgb(255, 215, 0)";
|
|
@@ -112,8 +112,8 @@ function renderCharacterKTV(ctx, layer, canvasWidth, canvasHeight, relativeFrame
|
|
|
112
112
|
} else {
|
|
113
113
|
ctx.shadowBlur = 0;
|
|
114
114
|
}
|
|
115
|
-
if (
|
|
116
|
-
ctx.strokeStyle =
|
|
115
|
+
if (strokeColor && strokeWidth > 0) {
|
|
116
|
+
ctx.strokeStyle = strokeColor;
|
|
117
117
|
ctx.lineWidth = strokeWidth;
|
|
118
118
|
ctx.strokeText(char, currentX, y);
|
|
119
119
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"character-ktv-renderer.js","sources":["../../../../src/stages/compose/text-renderers/character-ktv-renderer.ts"],"sourcesContent":["import type { TextLayer } from '../types';\nimport { wrapText } from '../text-utils/text-wrapper';\nimport { getLetterCaseText, measureTextWidth } from '../text-utils/text-metrics';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\ninterface CharacterTiming {\n char: string;\n index: number;\n startFrame: number;\n}\n\nfunction usToFrame(us: number, fps: number): number {\n return Math.floor(us / (1000000 / fps));\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\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 if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderCharacterKTV(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number,\n fps: number = 30\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 baseFill = fontConfig.fill;\n const
|
|
1
|
+
{"version":3,"file":"character-ktv-renderer.js","sources":["../../../../src/stages/compose/text-renderers/character-ktv-renderer.ts"],"sourcesContent":["import type { TextLayer } from '../types';\nimport { wrapText } from '../text-utils/text-wrapper';\nimport { getLetterCaseText, measureTextWidth } from '../text-utils/text-metrics';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\ninterface CharacterTiming {\n char: string;\n index: number;\n startFrame: number;\n}\n\nfunction usToFrame(us: number, fps: number): number {\n return Math.floor(us / (1000000 / fps));\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\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 if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderCharacterKTV(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number,\n fps: number = 30\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 baseFill = fontConfig.fill;\n const strokeColor = fontConfig.strokeColor;\n const strokeWidth = fontConfig.strokeWidth || 0;\n const lineHeight = fontConfig.lineHeight || 1.2;\n\n const highlightFill = layer.animation?.highlightTextStyle?.fill || 'rgb(255, 215, 0)';\n const glowColor = layer.animation?.glowColor || '#ffffff';\n const glowIntensity = layer.animation?.glowIntensity || 3;\n const transitionFrames = layer.animation?.transitionFrames || 10;\n\n const maxWidth = canvasWidth * 0.9;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const characterTimings: CharacterTiming[] = [];\n\n if (layer.wordTimings && layer.wordTimings.length > 0) {\n let charIndex = 0;\n\n for (let wordIndex = 0; wordIndex < layer.wordTimings.length; wordIndex++) {\n const word = layer.wordTimings[wordIndex]!;\n const wordChars = word.text.split('');\n const wordStartFrame = usToFrame(word.startUs, fps);\n const wordEndFrame = usToFrame(word.endUs, fps);\n const framesPerChar =\n wordChars.length > 0 ? (wordEndFrame - wordStartFrame) / wordChars.length : 0;\n\n for (let i = 0; i < wordChars.length; i++) {\n const charStartFrame = Math.floor(wordStartFrame + i * framesPerChar);\n characterTimings.push({\n char: wordChars[i]!,\n index: charIndex,\n startFrame: charStartFrame,\n });\n charIndex++;\n }\n\n if (needsSpace && wordIndex < layer.wordTimings.length - 1) {\n const nextWord = layer.wordTimings[wordIndex + 1];\n const nextWordFirstChar = nextWord?.text?.[0] || '';\n const isPunctuation = /[.,!?;:)]/.test(nextWordFirstChar);\n\n if (!isPunctuation) {\n const spaceStartFrame = characterTimings[characterTimings.length - 1]?.startFrame || 0;\n characterTimings.push({\n char: ' ',\n index: charIndex,\n startFrame: spaceStartFrame,\n });\n charIndex++;\n }\n }\n }\n } else {\n const totalFrames = 100;\n const chars = text.split('');\n const framesPerChar = chars.length > 0 ? totalFrames / chars.length : 0;\n\n for (let i = 0; i < chars.length; i++) {\n characterTimings.push({\n char: chars[i]!,\n index: i,\n startFrame: Math.floor(i * framesPerChar),\n });\n }\n }\n\n const fullText = characterTimings.map((ct) => ct.char).join('');\n const fullTextLines = wrapText(ctx, fullText, maxWidth, fontSize, fontFamily, fontWeight);\n\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.lineJoin = 'round';\n ctx.lineCap = 'round';\n\n const totalHeight = fullTextLines.length * fontSize * lineHeight;\n const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);\n\n let charIndexInText = 0;\n\n for (let lineIndex = 0; lineIndex < fullTextLines.length; lineIndex++) {\n const line = fullTextLines[lineIndex]!;\n const y = startY + lineIndex * fontSize * lineHeight + fontSize / 2;\n const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);\n let currentX = canvasWidth / 2 - lineWidth / 2;\n\n for (let i = 0; i < line.length; i++) {\n const char = line[i]!;\n const timing = characterTimings[charIndexInText];\n\n if (timing) {\n const hasScanned = relativeFrame >= timing.startFrame;\n const isCurrentlySinging =\n hasScanned && relativeFrame < timing.startFrame + transitionFrames;\n\n ctx.fillStyle = hasScanned ? highlightFill : baseFill;\n\n if (isCurrentlySinging) {\n ctx.shadowColor = glowColor;\n ctx.shadowBlur = glowIntensity * 10;\n } else {\n ctx.shadowBlur = 0;\n }\n\n if (strokeColor && strokeWidth > 0) {\n ctx.strokeStyle = strokeColor;\n ctx.lineWidth = strokeWidth;\n ctx.strokeText(char, currentX, y);\n }\n ctx.fillText(char, currentX, y);\n ctx.shadowBlur = 0;\n }\n\n currentX += measureTextWidth(ctx, char, fontSize, fontFamily, fontWeight);\n charIndexInText++;\n }\n }\n\n ctx.restore();\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -29,11 +29,11 @@ function renderWordByWord(ctx, layer, canvasWidth, canvasHeight, relativeFrame,
|
|
|
29
29
|
const fontFamily = fontConfig.fontFamily;
|
|
30
30
|
const fontWeight = fontConfig.fontWeight;
|
|
31
31
|
const fill = fontConfig.fill;
|
|
32
|
-
const
|
|
32
|
+
const strokeColor = fontConfig.strokeColor;
|
|
33
33
|
const strokeWidth = fontConfig.strokeWidth || 0;
|
|
34
34
|
const lineHeight = fontConfig.lineHeight || 1.2;
|
|
35
35
|
const highlightFill = layer.animation?.highlightTextStyle?.fill || "rgb(255, 215, 0)";
|
|
36
|
-
const highlightStroke = layer.animation?.highlightTextStyle?.
|
|
36
|
+
const highlightStroke = layer.animation?.highlightTextStyle?.strokeColor || strokeColor;
|
|
37
37
|
const maxWidth = canvasWidth * 0.64;
|
|
38
38
|
const text = getLetterCaseText(layer.text, layer.letterCase);
|
|
39
39
|
const needsSpace = needsSpaceBetweenWords(layer.localeCode || "en-US", text);
|
|
@@ -84,7 +84,7 @@ function renderWordByWord(ctx, layer, canvasWidth, canvasHeight, relativeFrame,
|
|
|
84
84
|
ctx.lineCap = "round";
|
|
85
85
|
for (const wordPos of wordPositions) {
|
|
86
86
|
let currentFill = fill;
|
|
87
|
-
let currentStroke =
|
|
87
|
+
let currentStroke = strokeColor;
|
|
88
88
|
if (wordPos.timing) {
|
|
89
89
|
const { startFrame, endFrame } = wordPos.timing;
|
|
90
90
|
if (relativeFrame >= startFrame && relativeFrame <= endFrame) {
|
|
@@ -98,8 +98,8 @@ function renderWordByWord(ctx, layer, canvasWidth, canvasHeight, relativeFrame,
|
|
|
98
98
|
}
|
|
99
99
|
);
|
|
100
100
|
currentFill = interpolateColor(fill, highlightFill, transitionProgressIn);
|
|
101
|
-
if (
|
|
102
|
-
currentStroke = interpolateColor(
|
|
101
|
+
if (strokeColor && highlightStroke) {
|
|
102
|
+
currentStroke = interpolateColor(strokeColor, highlightStroke, transitionProgressIn);
|
|
103
103
|
}
|
|
104
104
|
} else if (relativeFrame > endFrame) {
|
|
105
105
|
const transitionProgressOut = interpolate(relativeFrame, [endFrame, endFrame + 3], [1, 0], {
|
|
@@ -107,8 +107,8 @@ function renderWordByWord(ctx, layer, canvasWidth, canvasHeight, relativeFrame,
|
|
|
107
107
|
extrapolateRight: "clamp"
|
|
108
108
|
});
|
|
109
109
|
currentFill = interpolateColor(fill, highlightFill, transitionProgressOut);
|
|
110
|
-
if (
|
|
111
|
-
currentStroke = interpolateColor(
|
|
110
|
+
if (strokeColor && highlightStroke) {
|
|
111
|
+
currentStroke = interpolateColor(strokeColor, highlightStroke, transitionProgressOut);
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"word-by-word-renderer.js","sources":["../../../../src/stages/compose/text-renderers/word-by-word-renderer.ts"],"sourcesContent":["import type { TextLayer } from '../types';\nimport { formEvenLinesWithWords } from '../text-utils/text-wrapper';\nimport { getLetterCaseText, measureTextWidth } from '../text-utils/text-metrics';\nimport { interpolate, interpolateColor } from './animation-utils';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\ninterface WordPosition {\n text: string;\n x: number;\n y: number;\n lineIndex: number;\n wordIndex: number;\n timing?: { startFrame: number; endFrame: number };\n}\n\nfunction usToFrame(us: number, fps: number): number {\n return Math.floor(us / (1000000 / fps));\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\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 if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderWordByWord(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number,\n fps: number = 30\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
|
|
1
|
+
{"version":3,"file":"word-by-word-renderer.js","sources":["../../../../src/stages/compose/text-renderers/word-by-word-renderer.ts"],"sourcesContent":["import type { TextLayer } from '../types';\nimport { formEvenLinesWithWords } from '../text-utils/text-wrapper';\nimport { getLetterCaseText, measureTextWidth } from '../text-utils/text-metrics';\nimport { interpolate, interpolateColor } from './animation-utils';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\ninterface WordPosition {\n text: string;\n x: number;\n y: number;\n lineIndex: number;\n wordIndex: number;\n timing?: { startFrame: number; endFrame: number };\n}\n\nfunction usToFrame(us: number, fps: number): number {\n return Math.floor(us / (1000000 / fps));\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\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 if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderWordByWord(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number,\n fps: number = 30\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 strokeColor = fontConfig.strokeColor;\n const strokeWidth = fontConfig.strokeWidth || 0;\n const lineHeight = fontConfig.lineHeight || 1.2;\n\n const highlightFill = layer.animation?.highlightTextStyle?.fill || 'rgb(255, 215, 0)';\n const highlightStroke = layer.animation?.highlightTextStyle?.strokeColor || strokeColor;\n\n const maxWidth = canvasWidth * 0.64;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const words = text.split(needsSpace ? /\\s+/ : '');\n const lines = formEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n\n const wordPositions: WordPosition[] = [];\n let wordIndex = 0;\n\n const totalHeight = lines.length * fontSize * lineHeight;\n const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);\n\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n const line = lines[lineIndex]!;\n const lineWords = line.split(needsSpace ? /\\s+/ : '');\n const y = startY + lineIndex * fontSize * lineHeight + fontSize / 2;\n\n const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);\n let currentX = canvasWidth / 2 - lineWidth / 2;\n\n for (const word of lineWords) {\n const wordWidth = measureTextWidth(ctx, word, fontSize, fontFamily, fontWeight);\n const wordTimingUs = layer.wordTimings?.[wordIndex];\n\n const wordTiming = wordTimingUs\n ? {\n startFrame: usToFrame(wordTimingUs.startUs, fps),\n endFrame: usToFrame(wordTimingUs.endUs, fps),\n }\n : undefined;\n\n wordPositions.push({\n text: word,\n x: currentX + wordWidth / 2,\n y,\n lineIndex,\n wordIndex,\n timing: wordTiming,\n });\n\n currentX +=\n wordWidth + (needsSpace ? measureTextWidth(ctx, ' ', fontSize, fontFamily, fontWeight) : 0);\n wordIndex++;\n }\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 for (const wordPos of wordPositions) {\n let currentFill = fill;\n let currentStroke = strokeColor;\n\n if (wordPos.timing) {\n const { startFrame, endFrame } = wordPos.timing;\n\n if (relativeFrame >= startFrame && relativeFrame <= endFrame) {\n const transitionProgressIn = interpolate(\n relativeFrame,\n [startFrame, startFrame + 3],\n [0, 1],\n {\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n }\n );\n\n currentFill = interpolateColor(fill, highlightFill, transitionProgressIn);\n if (strokeColor && highlightStroke) {\n currentStroke = interpolateColor(strokeColor, highlightStroke, transitionProgressIn);\n }\n } else if (relativeFrame > endFrame) {\n const transitionProgressOut = interpolate(relativeFrame, [endFrame, endFrame + 3], [1, 0], {\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n });\n\n currentFill = interpolateColor(fill, highlightFill, transitionProgressOut);\n if (strokeColor && highlightStroke) {\n currentStroke = interpolateColor(strokeColor, highlightStroke, transitionProgressOut);\n }\n }\n }\n\n if (currentStroke && strokeWidth > 0) {\n ctx.strokeStyle = currentStroke;\n ctx.lineWidth = strokeWidth;\n ctx.strokeText(wordPos.text, wordPos.x, wordPos.y);\n }\n ctx.fillStyle = currentFill;\n ctx.fillText(wordPos.text, wordPos.x, wordPos.y);\n }\n\n ctx.restore();\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -29,7 +29,7 @@ function renderWordByWordFancy(ctx, layer, canvasWidth, canvasHeight, relativeFr
|
|
|
29
29
|
const fontFamily = fontConfig.fontFamily;
|
|
30
30
|
const fontWeight = fontConfig.fontWeight;
|
|
31
31
|
const fill = fontConfig.fill;
|
|
32
|
-
const
|
|
32
|
+
const strokeColor = fontConfig.strokeColor;
|
|
33
33
|
const strokeWidth = fontConfig.strokeWidth || 0;
|
|
34
34
|
const lineHeight = fontConfig.lineHeight || 1.2;
|
|
35
35
|
const highlightBackgroundColor = layer.animation?.highlightColor || "rgb(255, 215, 0)";
|
|
@@ -119,8 +119,8 @@ function renderWordByWordFancy(ctx, layer, canvasWidth, canvasHeight, relativeFr
|
|
|
119
119
|
ctx.restore();
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
-
if (
|
|
123
|
-
ctx.strokeStyle =
|
|
122
|
+
if (strokeColor && strokeWidth > 0) {
|
|
123
|
+
ctx.strokeStyle = strokeColor;
|
|
124
124
|
ctx.lineWidth = strokeWidth;
|
|
125
125
|
ctx.strokeText(wordPos.text, wordPos.x, wordPos.y);
|
|
126
126
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"word-fancy-renderer.js","sources":["../../../../src/stages/compose/text-renderers/word-fancy-renderer.ts"],"sourcesContent":["import type { TextLayer } from '../types';\nimport { formEvenLinesWithWords } from '../text-utils/text-wrapper';\nimport { getLetterCaseText, measureTextWidth } from '../text-utils/text-metrics';\nimport { springEasing, interpolate } from './animation-utils';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\ninterface WordPosition {\n text: string;\n x: number;\n y: number;\n width: number;\n lineIndex: number;\n wordIndex: number;\n timing?: { startFrame: number; endFrame: number };\n}\n\nfunction usToFrame(us: number, fps: number): number {\n return Math.floor(us / (1000000 / fps));\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\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 if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderWordByWordFancy(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number,\n fps: number = 30\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
|
|
1
|
+
{"version":3,"file":"word-fancy-renderer.js","sources":["../../../../src/stages/compose/text-renderers/word-fancy-renderer.ts"],"sourcesContent":["import type { TextLayer } from '../types';\nimport { formEvenLinesWithWords } from '../text-utils/text-wrapper';\nimport { getLetterCaseText, measureTextWidth } from '../text-utils/text-metrics';\nimport { springEasing, interpolate } from './animation-utils';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\ninterface WordPosition {\n text: string;\n x: number;\n y: number;\n width: number;\n lineIndex: number;\n wordIndex: number;\n timing?: { startFrame: number; endFrame: number };\n}\n\nfunction usToFrame(us: number, fps: number): number {\n return Math.floor(us / (1000000 / fps));\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\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 if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderWordByWordFancy(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number,\n fps: number = 30\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 strokeColor = fontConfig.strokeColor;\n const strokeWidth = fontConfig.strokeWidth || 0;\n const lineHeight = fontConfig.lineHeight || 1.2;\n\n const highlightBackgroundColor = layer.animation?.highlightColor || 'rgb(255, 215, 0)';\n\n const maxWidth = canvasWidth * 0.64;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const words = text.split(needsSpace ? /\\s+/ : '');\n const lines = formEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n\n const wordPositions: WordPosition[] = [];\n let wordIndex = 0;\n\n const totalHeight = lines.length * fontSize * lineHeight;\n const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);\n\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n const line = lines[lineIndex]!;\n const lineWords = line.split(needsSpace ? /\\s+/ : '');\n const y = startY + lineIndex * fontSize * lineHeight + fontSize / 2;\n\n const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);\n let currentX = canvasWidth / 2 - lineWidth / 2;\n\n for (const word of lineWords) {\n const wordWidth = measureTextWidth(ctx, word, fontSize, fontFamily, fontWeight);\n const wordTimingUs = layer.wordTimings?.[wordIndex];\n\n const wordTiming = wordTimingUs\n ? {\n startFrame: usToFrame(wordTimingUs.startUs, fps),\n endFrame: usToFrame(wordTimingUs.endUs, fps),\n }\n : undefined;\n\n wordPositions.push({\n text: word,\n x: currentX + wordWidth / 2,\n y,\n width: wordWidth,\n lineIndex,\n wordIndex,\n timing: wordTiming,\n });\n\n currentX +=\n wordWidth + (needsSpace ? measureTextWidth(ctx, ' ', fontSize, fontFamily, fontWeight) : 0);\n wordIndex++;\n }\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 for (const wordPos of wordPositions) {\n let backgroundOpacity = 0;\n let backgroundScale = 0.8;\n\n if (wordPos.timing) {\n const { startFrame, endFrame } = wordPos.timing;\n const preStartFrames = 3;\n const isActive = relativeFrame >= startFrame && relativeFrame <= endFrame;\n\n if (isActive) {\n const scaleSpringIn = springEasing(relativeFrame - (startFrame - preStartFrames), {\n damping: 6,\n mass: 0.35,\n stiffness: 200,\n overshootClamping: false,\n });\n\n const inProgress = interpolate(relativeFrame, [startFrame, startFrame + 1], [0, 1], {\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n });\n\n backgroundOpacity = 0.9 * inProgress;\n backgroundScale = 0.8 + scaleSpringIn * 0.45;\n } else if (relativeFrame > endFrame) {\n backgroundOpacity = 0;\n backgroundScale = 0.8;\n }\n\n if (backgroundOpacity > 0) {\n const padding = 8;\n const bgWidth = (wordPos.width + padding * 2) * backgroundScale;\n const bgHeight = (fontSize + padding) * backgroundScale;\n\n ctx.save();\n ctx.globalAlpha = backgroundOpacity;\n ctx.fillStyle = highlightBackgroundColor;\n ctx.beginPath();\n ctx.roundRect(wordPos.x - bgWidth / 2, wordPos.y - bgHeight / 2, bgWidth, bgHeight, 8);\n ctx.fill();\n ctx.restore();\n }\n }\n\n if (strokeColor && strokeWidth > 0) {\n ctx.strokeStyle = strokeColor;\n ctx.lineWidth = strokeWidth;\n ctx.strokeText(wordPos.text, wordPos.x, wordPos.y);\n }\n ctx.fillStyle = fill;\n ctx.fillText(wordPos.text, wordPos.x, wordPos.y);\n }\n\n ctx.restore();\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +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,
|
|
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,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,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"}
|