tegaki 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +2 -2
- package/dist/{core-Cw5jNWFa.mjs → core-D68zOEne.mjs} +84 -14
- package/dist/core-D68zOEne.mjs.map +1 -0
- package/dist/fonts/caveat/bundle.d.mts +825 -0
- package/dist/fonts/caveat/bundle.mjs +11874 -0
- package/dist/fonts/caveat/bundle.mjs.map +1 -0
- package/dist/fonts/caveat/caveat.ttf +0 -0
- package/dist/fonts/italianno/bundle.d.mts +821 -0
- package/dist/fonts/italianno/bundle.mjs +16422 -0
- package/dist/fonts/italianno/bundle.mjs.map +1 -0
- package/dist/fonts/italianno/italianno.ttf +0 -0
- package/dist/fonts/parisienne/bundle.d.mts +825 -0
- package/dist/fonts/parisienne/bundle.mjs +17763 -0
- package/dist/fonts/parisienne/bundle.mjs.map +1 -0
- package/dist/fonts/parisienne/parisienne.ttf +0 -0
- package/dist/fonts/tangerine/bundle.d.mts +825 -0
- package/dist/fonts/tangerine/bundle.mjs +15417 -0
- package/dist/fonts/tangerine/bundle.mjs.map +1 -0
- package/dist/fonts/tangerine/tangerine.ttf +0 -0
- package/dist/index-B2v8wlaN.d.mts +34 -0
- package/dist/{index-YdGpXlqf.d.mts → index-BdBLaKjh.d.mts} +51 -4
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +3 -3
- package/dist/react/index.d.mts +3 -3
- package/dist/react/index.mjs +3 -3
- package/dist/react-Cgxpndhg.mjs +88 -0
- package/dist/react-Cgxpndhg.mjs.map +1 -0
- package/dist/solid/index.d.mts +2 -2
- package/dist/solid/index.mjs +2 -2
- package/dist/wc/index.d.mts +3 -3
- package/dist/wc/index.mjs +12 -4
- package/dist/wc/index.mjs.map +1 -1
- package/package.json +26 -6
- package/src/core/createBundle.ts +45 -0
- package/src/core/engine.ts +83 -16
- package/src/core/index.ts +1 -0
- package/src/react/TegakiRenderer.tsx +86 -26
- package/src/wc/TegakiElement.ts +8 -2
- package/dist/core-Cw5jNWFa.mjs.map +0 -1
- package/dist/index-Bmbc0eTI.d.mts +0 -39
- package/dist/react-DfB_wEik.mjs +0 -60
- package/dist/react-DfB_wEik.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# tegaki
|
|
2
2
|
|
|
3
|
+
## 0.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`7198553`](https://github.com/KurtGokhan/tegaki/commit/719855392734a8f1b6056db9f0718ac7a8213527) Thanks [@KurtGokhan](https://github.com/KurtGokhan)! - Add controlled progress mode to allow users to specify the exact progress of the animation that is a value between 0 and 1.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- [`b326f00`](https://github.com/KurtGokhan/tegaki/commit/b326f00d52b97ef19e0214cb4595bd31cd501cf4) Thanks [@KurtGokhan](https://github.com/KurtGokhan)! - Add delay and loop gap for uncontrolled animations
|
|
12
|
+
|
|
13
|
+
- [`1449890`](https://github.com/KurtGokhan/tegaki/commit/144989014c0d9cdbf80fafbb77af646b96065832) Thanks [@KurtGokhan](https://github.com/KurtGokhan)! - Add docs and example for using Tegaki with Remotion. The example is a simple composition that renders a single text prop, but the same principles apply to more complex compositions and dynamic props.
|
|
14
|
+
|
|
15
|
+
- [`1449890`](https://github.com/KurtGokhan/tegaki/commit/144989014c0d9cdbf80fafbb77af646b96065832) Thanks [@KurtGokhan](https://github.com/KurtGokhan)! - Fix rendering when zoom level was not 100%.
|
|
16
|
+
|
|
17
|
+
## 0.9.0
|
|
18
|
+
|
|
19
|
+
### Minor Changes
|
|
20
|
+
|
|
21
|
+
- [#12](https://github.com/KurtGokhan/tegaki/pull/12) [`e43197f`](https://github.com/KurtGokhan/tegaki/commit/e43197f5719368bed5280aa106c8fcb7afe05b4e) Thanks [@KurtGokhan](https://github.com/KurtGokhan)! - Add CDN-friendly font bundles and `createBundle` helper
|
|
22
|
+
|
|
23
|
+
- Built font bundles now use `new URL(..., import.meta.url)` instead of bundler-specific import attributes, making them work natively in browsers and on CDN services like esm.sh and jsDelivr
|
|
24
|
+
- Glyph data JSON is inlined in the built output so no import attributes are needed at runtime
|
|
25
|
+
- Added `createBundle()` to `tegaki/core` and `tegaki/wc` for manually assembling a font bundle from fetched glyph data and a font URL
|
|
26
|
+
|
|
3
27
|
## 0.8.0
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
package/dist/core/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
export { BBox, CSSLength, CreateElementFn, FontOutput, GlyphData, LineCap, PathCommand, Point, ResolvedEffect, Stroke, TegakiBundle, TegakiEffectConfigs, TegakiEffectName, TegakiEffects, TegakiEngine, TegakiEngineOptions, TegakiGlyphData, TegakiMultiEffectName, TegakiSingletonEffectName, TextLayout, TimeControlMode, TimeControlProp, TimedPoint, Timeline, TimelineConfig, TimelineEntry, computeTextLayout, computeTimeline, drawGlyph, ensureFontFace, resolveEffects };
|
|
1
|
+
import { A as TegakiMultiEffectName, C as Point, D as TegakiEffectName, E as TegakiEffectConfigs, M as TimedPoint, O as TegakiEffects, S as PathCommand, T as TegakiBundle, _ as BBox, a as TimeControlProp, b as GlyphData, c as TimelineConfig, d as TextLayout, f as computeTextLayout, g as resolveEffects, h as ResolvedEffect, i as TimeControlMode, j as TegakiSingletonEffectName, k as TegakiGlyphData, l as TimelineEntry, m as drawGlyph, n as TegakiEngine, o as createBundle, p as ensureFontFace, r as TegakiEngineOptions, s as Timeline, t as CreateElementFn, u as computeTimeline, v as CSSLength, w as Stroke, x as LineCap, y as FontOutput } from "../index-BdBLaKjh.mjs";
|
|
2
|
+
export { BBox, CSSLength, CreateElementFn, FontOutput, GlyphData, LineCap, PathCommand, Point, ResolvedEffect, Stroke, TegakiBundle, TegakiEffectConfigs, TegakiEffectName, TegakiEffects, TegakiEngine, TegakiEngineOptions, TegakiGlyphData, TegakiMultiEffectName, TegakiSingletonEffectName, TextLayout, TimeControlMode, TimeControlProp, TimedPoint, Timeline, TimelineConfig, TimelineEntry, computeTextLayout, computeTimeline, createBundle, drawGlyph, ensureFontFace, resolveEffects };
|
package/dist/core/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { TegakiEngine, computeTextLayout, computeTimeline, drawGlyph, ensureFontFace, resolveEffects };
|
|
1
|
+
import { a as ensureFontFace, c as resolveEffects, i as computeTextLayout, n as createBundle, o as drawGlyph, r as computeTimeline, t as TegakiEngine } from "../core-D68zOEne.mjs";
|
|
2
|
+
export { TegakiEngine, computeTextLayout, computeTimeline, createBundle, drawGlyph, ensureFontFace, resolveEffects };
|
|
@@ -494,6 +494,35 @@ function computeTimeline(text, font, config) {
|
|
|
494
494
|
};
|
|
495
495
|
}
|
|
496
496
|
//#endregion
|
|
497
|
+
//#region src/core/createBundle.ts
|
|
498
|
+
/**
|
|
499
|
+
* Creates a {@link TegakiBundle} from its constituent parts.
|
|
500
|
+
*
|
|
501
|
+
* Useful when loading font data from a CDN or other source where the
|
|
502
|
+
* pre-built bundle modules aren't available:
|
|
503
|
+
*
|
|
504
|
+
* ```js
|
|
505
|
+
* const glyphData = await fetch('.../glyphData.json').then(r => r.json());
|
|
506
|
+
* const bundle = createBundle({
|
|
507
|
+
* family: 'Caveat',
|
|
508
|
+
* fontUrl: '.../caveat.ttf',
|
|
509
|
+
* glyphData,
|
|
510
|
+
* });
|
|
511
|
+
* ```
|
|
512
|
+
*/
|
|
513
|
+
function createBundle({ family, fontUrl, glyphData, lineCap = "round", unitsPerEm = 1e3, ascender = 800, descender = -200 }) {
|
|
514
|
+
return {
|
|
515
|
+
family,
|
|
516
|
+
lineCap,
|
|
517
|
+
fontUrl,
|
|
518
|
+
fontFaceCSS: `@font-face { font-family: '${family}'; src: url(${fontUrl}); }`,
|
|
519
|
+
unitsPerEm,
|
|
520
|
+
ascender,
|
|
521
|
+
descender,
|
|
522
|
+
glyphData
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
//#endregion
|
|
497
526
|
//#region src/lib/css-properties.ts
|
|
498
527
|
const CSS_TIME = "--tegaki-time";
|
|
499
528
|
const CSS_PROGRESS = "--tegaki-progress";
|
|
@@ -571,7 +600,7 @@ function buildRootProps(options) {
|
|
|
571
600
|
const font = resolveBundle(options.font);
|
|
572
601
|
const fontFamily = font?.family;
|
|
573
602
|
const duration = text && font ? computeTimeline(text, font, options.timing).totalDuration : 0;
|
|
574
|
-
const time = typeof options.time === "number" ? options.time : typeof options.time === "object" && options.time?.mode === "controlled" ? options.time.value : typeof options.time === "object" && options.time?.mode === "uncontrolled" ? options.time.initialTime ?? 0 : 0;
|
|
603
|
+
const time = typeof options.time === "number" ? options.time : typeof options.time === "object" && options.time?.mode === "controlled" ? options.time.unit === "progress" ? options.time.value * duration : options.time.value : typeof options.time === "object" && options.time?.mode === "uncontrolled" ? options.time.initialTime ?? 0 : 0;
|
|
575
604
|
const progress = duration > 0 ? time / duration : 0;
|
|
576
605
|
return {
|
|
577
606
|
"data-tegaki": "root",
|
|
@@ -591,7 +620,10 @@ function buildChildren(options, h) {
|
|
|
591
620
|
const text = options.text ?? "";
|
|
592
621
|
const isCss = options.time === "css" || typeof options.time === "object" && options.time?.mode === "css";
|
|
593
622
|
const showOverlay = options.showOverlay;
|
|
594
|
-
return h("
|
|
623
|
+
return h("span", { style: {
|
|
624
|
+
display: "block",
|
|
625
|
+
position: "relative"
|
|
626
|
+
} }, h("span", {
|
|
595
627
|
"data-tegaki": "sentinel",
|
|
596
628
|
"aria-hidden": "true",
|
|
597
629
|
style: {
|
|
@@ -621,9 +653,10 @@ function buildChildren(options, h) {
|
|
|
621
653
|
display: "inline-block",
|
|
622
654
|
padding: `${PAD_V_CSS} 0.2em`
|
|
623
655
|
}
|
|
624
|
-
}, text)), h("
|
|
656
|
+
}, text)), h("span", {
|
|
625
657
|
"data-tegaki": "overlay",
|
|
626
658
|
style: {
|
|
659
|
+
display: "block",
|
|
627
660
|
userSelect: "auto",
|
|
628
661
|
whiteSpace: "pre-wrap",
|
|
629
662
|
overflowWrap: "break-word",
|
|
@@ -701,6 +734,8 @@ var TegakiEngine = class TegakiEngine {
|
|
|
701
734
|
_cssTime = 0;
|
|
702
735
|
_playing = true;
|
|
703
736
|
_smoothedBoost = 0;
|
|
737
|
+
_delayRemaining = 0;
|
|
738
|
+
_loopGapRemaining = 0;
|
|
704
739
|
_lastTs = null;
|
|
705
740
|
_rafId = 0;
|
|
706
741
|
_prevCompleted = false;
|
|
@@ -752,7 +787,7 @@ var TegakiEngine = class TegakiEngine {
|
|
|
752
787
|
get currentTime() {
|
|
753
788
|
const tc = this._timeControl;
|
|
754
789
|
if (tc.mode === "css") return this._cssTime;
|
|
755
|
-
if (tc.mode === "controlled") return tc.value;
|
|
790
|
+
if (tc.mode === "controlled") return tc.unit === "progress" ? tc.value * this._timeline.totalDuration : tc.value;
|
|
756
791
|
return this._internalTime;
|
|
757
792
|
}
|
|
758
793
|
get duration() {
|
|
@@ -780,6 +815,8 @@ var TegakiEngine = class TegakiEngine {
|
|
|
780
815
|
seek(time) {
|
|
781
816
|
if (this._timeControl.mode !== "uncontrolled") return;
|
|
782
817
|
this._internalTime = Math.max(0, Math.min(time, this._timeline.totalDuration));
|
|
818
|
+
this._delayRemaining = 0;
|
|
819
|
+
this._loopGapRemaining = 0;
|
|
783
820
|
this._checkCompletion();
|
|
784
821
|
this._notifyTimeChange();
|
|
785
822
|
this._render();
|
|
@@ -790,6 +827,8 @@ var TegakiEngine = class TegakiEngine {
|
|
|
790
827
|
this._internalTime = 0;
|
|
791
828
|
this._playing = true;
|
|
792
829
|
this._prevCompleted = false;
|
|
830
|
+
this._delayRemaining = this._timeControl.delay ?? 0;
|
|
831
|
+
this._loopGapRemaining = 0;
|
|
793
832
|
this._notifyTimeChange();
|
|
794
833
|
this._evaluatePlayback();
|
|
795
834
|
}
|
|
@@ -817,11 +856,19 @@ var TegakiEngine = class TegakiEngine {
|
|
|
817
856
|
const newTc = resolveTimeControl(options.time);
|
|
818
857
|
const oldTc = this._timeControl;
|
|
819
858
|
const modeChanged = newTc.mode !== oldTc.mode;
|
|
820
|
-
const controlledValueChanged = newTc.mode === "controlled" && oldTc.mode === "controlled" && newTc.value !== oldTc.value;
|
|
821
|
-
const uncontrolledChanged = newTc.mode === "uncontrolled" && oldTc.mode === "uncontrolled" && (newTc.speed !== oldTc.speed || newTc.playing !== oldTc.playing || newTc.loop !== oldTc.loop || newTc.catchUp !== oldTc.catchUp);
|
|
859
|
+
const controlledValueChanged = newTc.mode === "controlled" && oldTc.mode === "controlled" && (newTc.value !== oldTc.value || newTc.unit !== oldTc.unit);
|
|
860
|
+
const uncontrolledChanged = newTc.mode === "uncontrolled" && oldTc.mode === "uncontrolled" && (newTc.speed !== oldTc.speed || newTc.playing !== oldTc.playing || newTc.loop !== oldTc.loop || newTc.delay !== oldTc.delay || newTc.loopGap !== oldTc.loopGap || newTc.catchUp !== oldTc.catchUp);
|
|
822
861
|
if (modeChanged || controlledValueChanged || uncontrolledChanged) {
|
|
823
862
|
this._timeControl = newTc;
|
|
824
|
-
if (newTc.mode === "uncontrolled")
|
|
863
|
+
if (newTc.mode === "uncontrolled") {
|
|
864
|
+
this._playing = newTc.playing ?? true;
|
|
865
|
+
const oldDelay = oldTc.mode === "uncontrolled" ? oldTc.delay ?? 0 : 0;
|
|
866
|
+
const newDelay = newTc.delay ?? 0;
|
|
867
|
+
if (modeChanged || oldDelay !== newDelay) {
|
|
868
|
+
this._delayRemaining = newDelay;
|
|
869
|
+
this._loopGapRemaining = 0;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
825
872
|
dirtyPlayback = true;
|
|
826
873
|
dirtyRender = true;
|
|
827
874
|
this._updateSentinelTransition();
|
|
@@ -878,7 +925,7 @@ var TegakiEngine = class TegakiEngine {
|
|
|
878
925
|
_updateDom() {
|
|
879
926
|
this._rootEl.style.fontFamily = this._font?.family ?? "";
|
|
880
927
|
this._updateCssProperties();
|
|
881
|
-
this._overlayEl.textContent = this._text;
|
|
928
|
+
if (this._overlayEl.textContent !== this._text) this._overlayEl.textContent = this._text;
|
|
882
929
|
this._canvasFallbackEl.textContent = this._text;
|
|
883
930
|
}
|
|
884
931
|
_updateCssProperties() {
|
|
@@ -1032,6 +1079,24 @@ var TegakiEngine = class TegakiEngine {
|
|
|
1032
1079
|
this._rafId = requestAnimationFrame(this._tick);
|
|
1033
1080
|
return;
|
|
1034
1081
|
}
|
|
1082
|
+
if (this._delayRemaining > 0) {
|
|
1083
|
+
this._delayRemaining = Math.max(0, this._delayRemaining - dtSec);
|
|
1084
|
+
this._rafId = requestAnimationFrame(this._tick);
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
if (this._loopGapRemaining > 0) {
|
|
1088
|
+
this._loopGapRemaining = Math.max(0, this._loopGapRemaining - dtSec);
|
|
1089
|
+
if (this._loopGapRemaining <= 0) {
|
|
1090
|
+
this._internalTime = 0;
|
|
1091
|
+
this._prevCompleted = false;
|
|
1092
|
+
this._smoothedBoost = 0;
|
|
1093
|
+
}
|
|
1094
|
+
this._notifyTimeChange();
|
|
1095
|
+
this._render();
|
|
1096
|
+
this._updateCssProperties();
|
|
1097
|
+
this._rafId = requestAnimationFrame(this._tick);
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1035
1100
|
let effectiveSpeed = speed;
|
|
1036
1101
|
if (catchUp > 0) {
|
|
1037
1102
|
const remaining = Math.max(0, totalDur - this._internalTime);
|
|
@@ -1044,7 +1109,13 @@ var TegakiEngine = class TegakiEngine {
|
|
|
1044
1109
|
}
|
|
1045
1110
|
let next = this._internalTime + dtSec * effectiveSpeed;
|
|
1046
1111
|
if (next >= totalDur) {
|
|
1047
|
-
|
|
1112
|
+
if (loop) {
|
|
1113
|
+
const loopGap = tc.loopGap ?? 0;
|
|
1114
|
+
if (loopGap > 0) {
|
|
1115
|
+
next = totalDur;
|
|
1116
|
+
this._loopGapRemaining = loopGap;
|
|
1117
|
+
} else next = next % totalDur;
|
|
1118
|
+
} else next = totalDur;
|
|
1048
1119
|
this._smoothedBoost = 0;
|
|
1049
1120
|
}
|
|
1050
1121
|
this._internalTime = next;
|
|
@@ -1072,9 +1143,8 @@ var TegakiEngine = class TegakiEngine {
|
|
|
1072
1143
|
const fontSize = this._fontSize;
|
|
1073
1144
|
if (!font?.glyphData || !layout || !fontSize) return;
|
|
1074
1145
|
const dpr = window.devicePixelRatio || 1;
|
|
1075
|
-
const
|
|
1076
|
-
const
|
|
1077
|
-
const h = canvasRect.height;
|
|
1146
|
+
const w = canvas.offsetWidth;
|
|
1147
|
+
const h = canvas.offsetHeight;
|
|
1078
1148
|
if (canvas.width !== Math.round(w * dpr) || canvas.height !== Math.round(h * dpr)) {
|
|
1079
1149
|
canvas.width = Math.round(w * dpr);
|
|
1080
1150
|
canvas.height = Math.round(h * dpr);
|
|
@@ -1123,6 +1193,6 @@ var TegakiEngine = class TegakiEngine {
|
|
|
1123
1193
|
}
|
|
1124
1194
|
};
|
|
1125
1195
|
//#endregion
|
|
1126
|
-
export {
|
|
1196
|
+
export { ensureFontFace as a, resolveEffects as c, computeTextLayout as i, createBundle as n, drawGlyph as o, computeTimeline as r, coerceToString as s, TegakiEngine as t };
|
|
1127
1197
|
|
|
1128
|
-
//# sourceMappingURL=core-
|
|
1198
|
+
//# sourceMappingURL=core-D68zOEne.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core-D68zOEne.mjs","names":[],"sources":["../src/lib/effects.ts","../src/lib/utils.ts","../src/lib/drawGlyph.ts","../src/lib/font.ts","../src/lib/textLayout.ts","../src/lib/timeline.ts","../src/core/createBundle.ts","../src/lib/css-properties.ts","../src/lib/drawFallbackGlyph.ts","../src/core/engine.ts"],"sourcesContent":["import type { TegakiEffectConfigs, TegakiEffectName } from '../types.ts';\n\nexport interface ResolvedEffect<K extends TegakiEffectName = TegakiEffectName> {\n effect: K;\n order: number;\n config: TegakiEffectConfigs[K];\n}\n\nconst defaultEffects: Record<string, any> = { pressureWidth: true };\nconst knownEffects: Set<string> = new Set(['glow', 'wobble', 'pressureWidth', 'taper', 'gradient']);\n\n/**\n * Normalizes an effects record into a sorted array of resolved effects.\n * Known keys infer the effect name; custom keys read it from the `effect` field.\n * Boolean `true` becomes an empty config. `false`/absent entries are skipped.\n */\nexport function resolveEffects(effects: Record<string, any> | undefined): ResolvedEffect[] {\n const merged = { ...defaultEffects, ...effects };\n\n const result: ResolvedEffect[] = [];\n\n for (const [key, value] of Object.entries(merged)) {\n if (value === false || value == null) continue;\n\n let effectName: TegakiEffectName;\n let config: Record<string, any>;\n let order: number;\n\n if (value === true) {\n effectName = (knownEffects.has(key) ? key : undefined) as TegakiEffectName;\n if (!effectName) continue;\n config = {};\n order = 0;\n } else {\n if (value.enabled === false) continue;\n effectName = value.effect ?? (knownEffects.has(key) ? key : undefined);\n if (!effectName) continue;\n const { effect: _, order: o, enabled: __, ...rest } = value;\n config = rest;\n order = o ?? 0;\n }\n\n result.push({ effect: effectName, order, config });\n }\n\n result.sort((a, b) => a.order - b.order);\n return result;\n}\n\n/** Check if a specific effect is active. */\nexport function findEffect<K extends TegakiEffectName>(effects: ResolvedEffect[], name: K): ResolvedEffect<K> | undefined {\n return effects.find((e) => e.effect === name) as ResolvedEffect<K> | undefined;\n}\n\n/** Get all instances of a specific effect (for duplicates). */\nexport function findEffects<K extends TegakiEffectName>(effects: ResolvedEffect[], name: K): ResolvedEffect<K>[] {\n return effects.filter((e) => e.effect === name) as ResolvedEffect<K>[];\n}\n","import type { CSSLength } from '../types.ts';\n\nconst segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });\n\n/** Resolve a CSSLength to pixels. Plain numbers are px, `\"Nem\"` is N * fontSize. */\nexport function resolveCSSLength(value: CSSLength, fontSize: number): number {\n if (typeof value === 'number') return value;\n return parseFloat(value) * fontSize;\n}\n\nexport function graphemes(text: string): string[] {\n return Array.from(segmenter.segment(text), (s) => s.segment);\n}\nexport type Coercible = string | number | boolean | null | undefined | readonly Coercible[];\n\nexport function coerceToString(value: unknown): string {\n if (value == null || typeof value === 'boolean') return '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'bigint') return String(value);\n if (Array.isArray(value)) return value.map(coerceToString).join('');\n return '';\n}\n","import type { LineCap, TegakiGlyphData } from '../types.ts';\nimport { findEffect, findEffects, type ResolvedEffect } from './effects.ts';\nimport { resolveCSSLength } from './utils.ts';\n\ninterface GlyphPosition {\n /** X offset in CSS pixels */\n x: number;\n /** Y offset in CSS pixels (top of em square) */\n y: number;\n /** Font size in CSS pixels */\n fontSize: number;\n /** Units per em from the font */\n unitsPerEm: number;\n /** Font ascender in font units */\n ascender: number;\n /** Font descender in font units (negative) */\n descender: number;\n}\n\n// --- Color helpers ---\n\nfunction parseColor(color: string): [number, number, number, number] {\n const h = color.replace('#', '');\n if (h.length === 3) {\n return [parseInt(h[0]! + h[0]!, 16), parseInt(h[1]! + h[1]!, 16), parseInt(h[2]! + h[2]!, 16), 1];\n }\n if (h.length === 4) {\n return [parseInt(h[0]! + h[0]!, 16), parseInt(h[1]! + h[1]!, 16), parseInt(h[2]! + h[2]!, 16), parseInt(h[3]! + h[3]!, 16) / 255];\n }\n if (h.length === 8) {\n return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16), parseInt(h.slice(6, 8), 16) / 255];\n }\n return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16), 1];\n}\n\nfunction lerpColor(a: [number, number, number, number], b: [number, number, number, number], t: number): string {\n const r = Math.round(a[0] + (b[0] - a[0]) * t);\n const g = Math.round(a[1] + (b[1] - a[1]) * t);\n const bl = Math.round(a[2] + (b[2] - a[2]) * t);\n const al = a[3] + (b[3] - a[3]) * t;\n if (al >= 1) return `rgb(${r},${g},${bl})`;\n return `rgba(${r},${g},${bl},${al.toFixed(3)})`;\n}\n\nfunction gradientColor(progress: number, colors: string[], seed: number): string {\n if (colors.length === 0) return '#000';\n if (colors.length === 1) return colors[0]!;\n const t = (((progress + seed * 0.1) % 1) + 1) % 1;\n const scaledT = t * (colors.length - 1);\n const i = Math.min(Math.floor(scaledT), colors.length - 2);\n const frac = scaledT - i;\n return lerpColor(parseColor(colors[i]!), parseColor(colors[i + 1]!), frac);\n}\n\nfunction rainbowColor(progress: number, saturation: number, lightness: number, seed: number): string {\n const hue = (progress * 360 + seed * 137.5) % 360;\n return `hsl(${hue}, ${saturation}%, ${lightness}%)`;\n}\n\n// --- Noise helper for wobble ---\n\nfunction hash(x: number): number {\n let h = (x * 2654435761) | 0;\n h = ((h >>> 16) ^ h) * 0x45d9f3b;\n h = ((h >>> 16) ^ h) * 0x45d9f3b;\n h = (h >>> 16) ^ h;\n return (h & 0x7fffffff) / 0x7fffffff; // 0-1\n}\n\nfunction noise1d(x: number, seed: number): number {\n const i = Math.floor(x);\n const f = x - i;\n const t = f * f * (3 - 2 * f); // smoothstep\n return hash(i + seed * 7919) * (1 - t) + hash(i + 1 + seed * 7919) * t;\n}\n\n/**\n * Draw a single glyph's strokes onto a canvas context, animated up to `localTime`.\n * `localTime` is seconds relative to this glyph's start (0 = glyph begins).\n */\nexport function drawGlyph(\n ctx: CanvasRenderingContext2D,\n glyph: TegakiGlyphData,\n pos: GlyphPosition,\n localTime: number,\n lineCap: LineCap,\n color: string,\n effects: ResolvedEffect[] = [],\n seed = 0,\n segmentSize?: number,\n) {\n const scale = pos.fontSize / pos.unitsPerEm;\n const ox = pos.x;\n const oy = pos.y;\n\n const glowEffects = findEffects(effects, 'glow');\n const wobbleEffect = findEffect(effects, 'wobble');\n const pressureEffect = findEffect(effects, 'pressureWidth');\n const taperEffect = findEffect(effects, 'taper');\n const gradientEffect = findEffect(effects, 'gradient');\n\n // Pressure params (0 = uniform avg width, 1 = fully per-point width)\n const pressureAmount = pressureEffect ? Math.max(0, Math.min(pressureEffect.config.strength ?? 1, 1)) : 0;\n\n // Wobble params\n const wobbleAmplitude = wobbleEffect ? (wobbleEffect.config.amplitude ?? 1.5) : 0;\n const wobbleFrequency = wobbleEffect ? (wobbleEffect.config.frequency ?? 8) : 0;\n const wobbleMode = wobbleEffect?.config.mode ?? 'sine';\n\n // Taper params\n const taperStart = taperEffect ? Math.max(0, Math.min(taperEffect.config.startLength ?? 0.15, 1)) : 0;\n const taperEnd = taperEffect ? Math.max(0, Math.min(taperEffect.config.endLength ?? 0.15, 1)) : 0;\n\n // Gradient params\n const gradientColors = gradientEffect?.config.colors;\n const isRainbow = gradientColors === 'rainbow';\n const gradientColorStops = Array.isArray(gradientColors) ? gradientColors : undefined;\n const gradientSaturation = gradientEffect?.config.saturation ?? 80;\n const gradientLightness = gradientEffect?.config.lightness ?? 55;\n\n // Helper: apply wobble offset to a point in font units\n const wobbleX = (x: number, y: number, idx: number) => {\n if (!wobbleEffect) return x;\n if (wobbleMode === 'noise') {\n return x + wobbleAmplitude * (noise1d(y * 0.1 + idx * 0.7, seed) * 2 - 1);\n }\n return x + wobbleAmplitude * Math.sin(wobbleFrequency * (y * 0.01 + idx * 0.7) + seed);\n };\n const wobbleY = (x: number, y: number, idx: number) => {\n if (!wobbleEffect) return y;\n if (wobbleMode === 'noise') {\n return y + wobbleAmplitude * (noise1d(x * 0.1 + idx * 0.5, seed * 1.3 + 1000) * 2 - 1);\n }\n return y + wobbleAmplitude * Math.cos(wobbleFrequency * (x * 0.01 + idx * 0.5) + seed * 1.3);\n };\n\n // Helper: convert font-unit point to pixel\n const px = (x: number) => ox + x * scale;\n const py = (y: number) => oy + (y + pos.ascender) * scale;\n\n // Helper: get color for a given stroke progress\n const colorAt = (progress: number): string => {\n if (isRainbow) return rainbowColor(progress, gradientSaturation, gradientLightness, seed);\n if (gradientColorStops) return gradientColor(progress, gradientColorStops, seed);\n return color;\n };\n const hasGradient = !!gradientEffect;\n\n // Helper: taper multiplier (0-1) for a given stroke progress\n const taperMultiplier = (progress: number): number => {\n let m = 1;\n if (taperStart > 0 && progress < taperStart) m = Math.min(m, progress / taperStart);\n if (taperEnd > 0 && progress > 1 - taperEnd) m = Math.min(m, (1 - progress) / taperEnd);\n return m;\n };\n\n for (const stroke of glyph.s) {\n if (localTime < stroke.d) continue;\n const elapsed = localTime - stroke.d;\n const progress = Math.min(elapsed / stroke.a, 1);\n\n const pts = stroke.p;\n if (pts.length === 0) continue;\n\n const avgWidth = pts.reduce((s, p) => s + p[2], 0) / pts.length;\n const baseLineWidth = Math.max(avgWidth, 0.5) * scale;\n\n // --- Single-point dot ---\n if (pts.length === 1) {\n if (progress <= 0) continue;\n const p = pts[0]!;\n const dotX = px(wobbleX(p[0], p[1], 0));\n const dotY = py(wobbleY(p[0], p[1], 0));\n const perPointDot = Math.max(p[2], 0.5) * scale;\n let dotWidth = baseLineWidth + (perPointDot - baseLineWidth) * pressureAmount;\n dotWidth *= taperMultiplier(0.5);\n\n // Glow passes for dots\n for (const glow of glowEffects) {\n ctx.save();\n ctx.shadowBlur = resolveCSSLength(glow.config.radius ?? 8, pos.fontSize);\n ctx.shadowColor = glow.config.color ?? color;\n ctx.shadowOffsetX = (glow.config.offsetX ?? 0) * scale;\n ctx.shadowOffsetY = (glow.config.offsetY ?? 0) * scale;\n ctx.fillStyle = glow.config.color ?? color;\n ctx.beginPath();\n if (lineCap === 'round') {\n ctx.arc(dotX, dotY, dotWidth / 2, 0, Math.PI * 2);\n } else {\n ctx.rect(dotX - dotWidth / 2, dotY - dotWidth / 2, dotWidth, dotWidth);\n }\n ctx.fill();\n ctx.restore();\n }\n\n // Main dot\n ctx.fillStyle = colorAt(0);\n ctx.beginPath();\n if (lineCap === 'round') {\n ctx.arc(dotX, dotY, dotWidth / 2, 0, Math.PI * 2);\n ctx.fill();\n } else {\n ctx.fillRect(dotX - dotWidth / 2, dotY - dotWidth / 2, dotWidth, dotWidth);\n }\n continue;\n }\n\n // --- Compute total path length ---\n let totalLen = 0;\n for (let j = 1; j < pts.length; j++) {\n const dx = pts[j]![0] - pts[j - 1]![0];\n const dy = pts[j]![1] - pts[j - 1]![1];\n totalLen += Math.sqrt(dx * dx + dy * dy);\n }\n\n const drawLen = totalLen * progress;\n if (drawLen <= 0) continue;\n\n // --- Collect drawable segments ---\n const segments: {\n x0: number;\n y0: number;\n x1: number;\n y1: number;\n width0: number;\n width1: number;\n segProgress: number;\n }[] = [];\n\n let accumulated = 0;\n for (let j = 1; j < pts.length; j++) {\n const prev = pts[j - 1]!;\n const cur = pts[j]!;\n const dx = cur[0] - prev[0];\n const dy = cur[1] - prev[1];\n const segLen = Math.sqrt(dx * dx + dy * dy);\n\n if (accumulated + segLen <= drawLen) {\n segments.push({\n x0: px(wobbleX(prev[0], prev[1], j - 1)),\n y0: py(wobbleY(prev[0], prev[1], j - 1)),\n x1: px(wobbleX(cur[0], cur[1], j)),\n y1: py(wobbleY(cur[0], cur[1], j)),\n width0: prev[2],\n width1: cur[2],\n segProgress: (accumulated + segLen / 2) / totalLen,\n });\n accumulated += segLen;\n } else {\n const remaining = drawLen - accumulated;\n const frac = segLen > 0 ? remaining / segLen : 0;\n const ix = prev[0] + dx * frac;\n const iy = prev[1] + dy * frac;\n const iw = prev[2] + (cur[2] - prev[2]) * frac;\n segments.push({\n x0: px(wobbleX(prev[0], prev[1], j - 1)),\n y0: py(wobbleY(prev[0], prev[1], j - 1)),\n x1: px(wobbleX(ix, iy, j)),\n y1: py(wobbleY(ix, iy, j)),\n width0: prev[2],\n width1: iw,\n segProgress: (accumulated + remaining / 2) / totalLen,\n });\n break;\n }\n }\n\n if (segments.length === 0) continue;\n\n // Keep coarse segments for glow (shadowBlur is expensive per draw call)\n const coarseSegments = segments.slice();\n\n // --- Subdivide long segments for smooth effect transitions ---\n const effectsNeedSubdivision = pressureAmount > 0 || hasGradient || !!wobbleEffect || !!taperEffect;\n const resolvedSegmentSize = segmentSize ?? (effectsNeedSubdivision ? 2 : undefined);\n if (resolvedSegmentSize != null) {\n const maxSegLen = resolvedSegmentSize * scale;\n const subdivided: typeof segments = [];\n for (const seg of segments) {\n const dx = seg.x1 - seg.x0;\n const dy = seg.y1 - seg.y0;\n const len = Math.sqrt(dx * dx + dy * dy);\n const count = Math.max(1, Math.ceil(len / maxSegLen));\n for (let k = 0; k < count; k++) {\n const t0 = k / count;\n const t1 = (k + 1) / count;\n subdivided.push({\n x0: seg.x0 + dx * t0,\n y0: seg.y0 + dy * t0,\n x1: seg.x0 + dx * t1,\n y1: seg.y0 + dy * t1,\n width0: seg.width0 + (seg.width1 - seg.width0) * t0,\n width1: seg.width0 + (seg.width1 - seg.width0) * t1,\n segProgress: seg.segProgress,\n });\n }\n }\n for (let k = 0; k < subdivided.length; k++) {\n subdivided[k]!.segProgress = subdivided.length > 1 ? k / (subdivided.length - 1) : 0;\n }\n segments.length = 0;\n segments.push(...subdivided);\n }\n\n // Helper: compute segment line width with pressure and taper\n const segWidth = (seg: (typeof segments)[0]) => {\n const perPoint = ((seg.width0 + seg.width1) / 2) * scale;\n const w = Math.max(baseLineWidth + (perPoint - baseLineWidth) * pressureAmount, 0.5 * scale);\n return w * taperMultiplier(seg.segProgress);\n };\n\n const needsPerSegment = pressureAmount > 0 || taperEffect;\n\n const drawStrokePath = () => {\n if (needsPerSegment) {\n for (const seg of segments) {\n ctx.lineWidth = segWidth(seg);\n ctx.beginPath();\n ctx.moveTo(seg.x0, seg.y0);\n ctx.lineTo(seg.x1, seg.y1);\n ctx.stroke();\n }\n } else {\n ctx.lineWidth = baseLineWidth;\n ctx.beginPath();\n ctx.moveTo(segments[0]!.x0, segments[0]!.y0);\n for (const seg of segments) {\n ctx.lineTo(seg.x1, seg.y1);\n }\n ctx.stroke();\n }\n };\n\n const drawGradientPath = () => {\n for (const seg of segments) {\n ctx.strokeStyle = colorAt(seg.segProgress);\n if (needsPerSegment) ctx.lineWidth = segWidth(seg);\n ctx.beginPath();\n ctx.moveTo(seg.x0, seg.y0);\n ctx.lineTo(seg.x1, seg.y1);\n ctx.stroke();\n }\n };\n\n ctx.lineCap = lineCap;\n ctx.lineJoin = 'round';\n\n // --- Glow passes (use coarse segments to avoid expensive per-subsegment shadowBlur) ---\n for (const glow of glowEffects) {\n ctx.save();\n ctx.shadowBlur = resolveCSSLength(glow.config.radius ?? 8, pos.fontSize);\n ctx.shadowColor = glow.config.color ?? color;\n ctx.shadowOffsetX = (glow.config.offsetX ?? 0) * scale;\n ctx.shadowOffsetY = (glow.config.offsetY ?? 0) * scale;\n ctx.strokeStyle = glow.config.color ?? color;\n ctx.lineWidth = baseLineWidth;\n ctx.beginPath();\n ctx.moveTo(coarseSegments[0]!.x0, coarseSegments[0]!.y0);\n for (const seg of coarseSegments) {\n ctx.lineTo(seg.x1, seg.y1);\n }\n ctx.stroke();\n ctx.restore();\n }\n\n // --- Main stroke ---\n if (hasGradient) {\n drawGradientPath();\n } else {\n ctx.strokeStyle = color;\n drawStrokePath();\n }\n }\n}\n","import type { TegakiBundle } from '../types.ts';\n\nconst fontFaceCache = new Map<string, Promise<void>>();\n\n/**\n * Ensures the bundle's font face is loaded and available for rendering.\n * Resolves immediately if the font is already loaded.\n */\nexport async function ensureFontFace(bundle: TegakiBundle): Promise<void> {\n await ensureFont(bundle.family, bundle.fontUrl);\n}\n\nexport function ensureFont(family: string, url: string): Promise<void> | null {\n if (typeof document === 'undefined') return Promise.resolve();\n for (const face of document.fonts) {\n if (face.family === family) {\n if (face.status === 'loaded') return null;\n if (face.status === 'loading') return face.loaded.then(() => {});\n }\n }\n let cached = fontFaceCache.get(url);\n if (!cached) {\n cached = new FontFace(family, `url(${url})`, { featureSettings: \"'calt' 0, 'liga' 0\" }).load().then((loaded) => {\n document.fonts.add(loaded);\n });\n fontFaceCache.set(url, cached);\n }\n return cached;\n}\n","import { layoutWithLines, prepareWithSegments } from '@chenglou/pretext';\nimport { graphemes } from './utils.ts';\n\nexport interface TextLayout {\n /** Character indices per line */\n lines: number[][];\n /** Width in em per character index */\n charWidths: number[];\n /** Kerning adjustment in em between character at index i and i+1 */\n kernings: number[];\n /** Intrinsic (single-line) width in em */\n intrinsicWidth: number;\n}\n\nexport function computeTextLayout(text: string, fontFamily: string, fontSize: number, lineHeight: number, maxWidth: number): TextLayout {\n const fontStr = `${fontSize}px ${fontFamily}`;\n const chars = graphemes(text);\n\n // Measure unique character widths\n const widthCache = new Map<string, number>();\n const charWidths: number[] = [];\n for (const char of chars) {\n let w = widthCache.get(char);\n if (w === undefined) {\n if (char === '\\n') {\n w = 0;\n } else {\n const p = prepareWithSegments(char, fontStr, { whiteSpace: 'pre-wrap' });\n const r = layoutWithLines(p, Infinity, lineHeight);\n w = r.lines.length > 0 ? r.lines[0]!.width / fontSize : 0;\n }\n widthCache.set(char, w);\n }\n charWidths.push(w);\n }\n\n // Compute intrinsic width (single-line, no wrapping)\n const prepared = prepareWithSegments(text, fontStr, { whiteSpace: 'pre-wrap' });\n const singleLineResult = layoutWithLines(prepared, Infinity, lineHeight);\n const intrinsicWidth = Math.max(0, ...singleLineResult.lines.map((l) => l.width)) / fontSize;\n\n // Line breaking at actual available width\n const result = layoutWithLines(prepared, maxWidth, lineHeight);\n\n // Map line texts back to character indices (grapheme-based)\n // Build a mapping from UTF-16 offset to grapheme index\n const utf16ToCodePoint: number[] = [];\n for (let ci = 0; ci < chars.length; ci++) {\n for (let j = 0; j < chars[ci]!.length; j++) {\n utf16ToCodePoint.push(ci);\n }\n }\n\n const lines: number[][] = [];\n let utf16Offset = 0;\n for (const line of result.lines) {\n const indices: number[] = [];\n const seen = new Set<number>();\n for (let i = 0; i < line.text.length; i++) {\n const cpIdx = utf16ToCodePoint[utf16Offset + i]!;\n if (!seen.has(cpIdx)) {\n seen.add(cpIdx);\n indices.push(cpIdx);\n }\n }\n utf16Offset += line.text.length;\n // Consume the newline that caused this line break\n if (utf16Offset < text.length && text[utf16Offset] === '\\n') {\n const cpIdx = utf16ToCodePoint[utf16Offset]!;\n indices.push(cpIdx);\n utf16Offset++;\n }\n lines.push(indices);\n }\n\n // Any remaining characters (shouldn't happen, but safety)\n if (utf16Offset < text.length) {\n const indices: number[] = [];\n const seen = new Set<number>();\n for (let i = utf16Offset; i < text.length; i++) {\n const cpIdx = utf16ToCodePoint[i]!;\n if (!seen.has(cpIdx)) {\n seen.add(cpIdx);\n indices.push(cpIdx);\n }\n }\n lines.push(indices);\n }\n\n // Measure kerning between adjacent character pairs\n const kernings: number[] = [];\n const pairCache = new Map<string, number>();\n for (let i = 0; i < chars.length - 1; i++) {\n const a = chars[i]!;\n const b = chars[i + 1]!;\n if (a === '\\n' || b === '\\n') {\n kernings.push(0);\n continue;\n }\n const pair = `${a}${b}`;\n let k = pairCache.get(pair);\n if (k === undefined) {\n const p = prepareWithSegments(pair, fontStr, { whiteSpace: 'pre-wrap' });\n const r = layoutWithLines(p, Infinity, lineHeight);\n const pairWidth = r.lines.length > 0 ? r.lines[0]!.width / fontSize : 0;\n k = pairWidth - (widthCache.get(a) ?? 0) - (widthCache.get(b) ?? 0);\n if (Math.abs(k) < 0.001) k = 0;\n pairCache.set(pair, k);\n }\n kernings.push(k);\n }\n\n return { lines, charWidths, kernings, intrinsicWidth };\n}\n","import type { TegakiBundle } from '../types.ts';\nimport { graphemes } from './utils.ts';\n\nexport interface TimelineConfig {\n /** Pause between glyphs (seconds). Default: `0.1` */\n glyphGap?: number;\n /** Pause after a space character (seconds). Default: `0.15` */\n wordGap?: number;\n /** Pause after a newline / line break (seconds). Default: `0.3` */\n lineGap?: number;\n /** Duration for characters without glyph data (seconds). Default: `0.2` */\n unknownDuration?: number;\n}\n\nconst DEFAULTS: Required<TimelineConfig> = {\n glyphGap: 0.1,\n wordGap: 0.15,\n lineGap: 0.3,\n unknownDuration: 0.2,\n};\n\nexport interface TimelineEntry {\n char: string;\n offset: number;\n duration: number;\n hasGlyph: boolean;\n}\n\nexport interface Timeline {\n entries: TimelineEntry[];\n totalDuration: number;\n}\n\nexport function computeTimeline(text: string, font: TegakiBundle, config?: TimelineConfig): Timeline {\n const glyphGap = config?.glyphGap ?? DEFAULTS.glyphGap;\n const wordGap = config?.wordGap ?? DEFAULTS.wordGap;\n const lineGap = config?.lineGap ?? DEFAULTS.lineGap;\n const unknownDuration = config?.unknownDuration ?? DEFAULTS.unknownDuration;\n\n const chars = graphemes(text);\n const entries: TimelineEntry[] = [];\n let offset = 0;\n for (const char of chars) {\n const glyph = font.glyphData[char];\n const hasGlyph = !!glyph;\n const duration = hasGlyph ? (glyph.t ?? 1) : unknownDuration;\n entries.push({ char, offset, duration, hasGlyph });\n offset += duration;\n\n // Gap after this character\n if (char === '\\n') {\n offset += lineGap;\n } else if (char === ' ') {\n offset += wordGap;\n } else {\n offset += glyphGap;\n }\n }\n // Remove trailing gap\n if (entries.length > 0) {\n const lastChar = chars[chars.length - 1]!;\n const trailingGap = lastChar === '\\n' ? lineGap : lastChar === ' ' ? wordGap : glyphGap;\n offset -= trailingGap;\n }\n return { entries, totalDuration: Math.max(0, offset) };\n}\n","import type { LineCap, TegakiBundle, TegakiGlyphData } from '../types.ts';\n\n/**\n * Creates a {@link TegakiBundle} from its constituent parts.\n *\n * Useful when loading font data from a CDN or other source where the\n * pre-built bundle modules aren't available:\n *\n * ```js\n * const glyphData = await fetch('.../glyphData.json').then(r => r.json());\n * const bundle = createBundle({\n * family: 'Caveat',\n * fontUrl: '.../caveat.ttf',\n * glyphData,\n * });\n * ```\n */\nexport function createBundle({\n family,\n fontUrl,\n glyphData,\n lineCap = 'round',\n unitsPerEm = 1000,\n ascender = 800,\n descender = -200,\n}: {\n family: string;\n fontUrl: string;\n glyphData: Record<string, TegakiGlyphData>;\n lineCap?: LineCap;\n unitsPerEm?: number;\n ascender?: number;\n descender?: number;\n}): TegakiBundle {\n return {\n family,\n lineCap,\n fontUrl,\n fontFaceCSS: `@font-face { font-family: '${family}'; src: url(${fontUrl}); }`,\n unitsPerEm,\n ascender,\n descender,\n glyphData,\n };\n}\n","export const CSS_TIME = '--tegaki-time';\nexport const CSS_PROGRESS = '--tegaki-progress';\nexport const CSS_DURATION = '--tegaki-duration';\n\nexport const PADDING_H_EM = 0.2;\nexport const MIN_LINE_HEIGHT_EM = 1.8;\nexport const MIN_PADDING_V_EM = 0.2;\n\n// Register custom properties so they are animatable (typed as <number>).\n// Deferred to first use to avoid running at import time during SSR.\nlet cssPropertiesRegistered = false;\nexport function registerCssProperties() {\n if (cssPropertiesRegistered) return;\n cssPropertiesRegistered = true;\n if (typeof CSS !== 'undefined' && 'registerProperty' in CSS) {\n for (const prop of [CSS_TIME, CSS_PROGRESS, CSS_DURATION]) {\n try {\n CSS.registerProperty({ name: prop, syntax: '<number>', inherits: true, initialValue: '0' });\n } catch {\n // Already registered — ignore.\n }\n }\n }\n}\n","import { findEffect, findEffects, type ResolvedEffect } from './effects.ts';\nimport { resolveCSSLength } from './utils.ts';\n\n/**\n * Draw a fallback glyph (plain text) with applicable effects (glow, gradient, wobble).\n */\nexport function drawFallbackGlyph(\n ctx: CanvasRenderingContext2D,\n char: string,\n x: number,\n baseline: number,\n fontSize: number,\n fontFamily: string,\n color: string,\n effects: ResolvedEffect[] = [],\n seed = 0,\n) {\n const glowEffects = findEffects(effects, 'glow');\n const wobbleEffect = findEffect(effects, 'wobble');\n const gradientEffect = findEffect(effects, 'gradient');\n\n // Wobble offsets\n let dx = 0;\n let dy = 0;\n if (wobbleEffect) {\n const amplitude = (wobbleEffect.config.amplitude ?? 1.5) * (fontSize / 100);\n const frequency = wobbleEffect.config.frequency ?? 8;\n dx = amplitude * Math.sin(frequency * (baseline * 0.01) + seed);\n dy = amplitude * Math.cos(frequency * (x * 0.01) + seed * 1.3);\n }\n\n const drawX = x + dx;\n const drawY = baseline + dy;\n\n // Gradient / rainbow color\n let fillColor = color;\n if (gradientEffect) {\n const colors = gradientEffect.config.colors;\n if (colors === 'rainbow') {\n const saturation = gradientEffect.config.saturation ?? 80;\n const lightness = gradientEffect.config.lightness ?? 55;\n const hue = (seed * 137.5) % 360;\n fillColor = `hsl(${hue}, ${saturation}%, ${lightness}%)`;\n } else if (Array.isArray(colors) && colors.length > 0) {\n fillColor = colors[Math.floor(seed) % colors.length]!;\n }\n }\n\n ctx.save();\n ctx.font = `${fontSize}px ${fontFamily}`;\n ctx.textBaseline = 'alphabetic';\n\n // Glow passes\n for (const glow of glowEffects) {\n ctx.save();\n ctx.shadowBlur = resolveCSSLength(glow.config.radius ?? 8, fontSize);\n ctx.shadowColor = glow.config.color ?? color;\n ctx.shadowOffsetX = glow.config.offsetX ?? 0;\n ctx.shadowOffsetY = glow.config.offsetY ?? 0;\n ctx.fillStyle = glow.config.color ?? color;\n ctx.fillText(char, drawX, drawY);\n ctx.restore();\n }\n\n // Main text\n ctx.fillStyle = fillColor;\n ctx.fillText(char, drawX, drawY);\n\n ctx.restore();\n}\n","import {\n CSS_DURATION,\n CSS_PROGRESS,\n CSS_TIME,\n MIN_LINE_HEIGHT_EM,\n MIN_PADDING_V_EM,\n PADDING_H_EM,\n registerCssProperties,\n} from '../lib/css-properties.ts';\nimport { drawFallbackGlyph } from '../lib/drawFallbackGlyph.ts';\nimport { drawGlyph } from '../lib/drawGlyph.ts';\nimport { type ResolvedEffect, resolveEffects } from '../lib/effects.ts';\nimport { ensureFont } from '../lib/font.ts';\nimport type { TextLayout } from '../lib/textLayout.ts';\nimport { computeTextLayout } from '../lib/textLayout.ts';\nimport type { Timeline, TimelineConfig, TimelineEntry } from '../lib/timeline.ts';\nimport { computeTimeline } from '../lib/timeline.ts';\nimport { graphemes } from '../lib/utils.ts';\nimport type { TegakiBundle, TegakiEffects } from '../types.ts';\n\n// ---------------------------------------------------------------------------\n// Time control types (shared with adapters)\n// ---------------------------------------------------------------------------\n\nexport type TimeControlMode = {\n controlled: {\n mode: 'controlled';\n /** Current time in seconds (default), or progress 0–1 when `unit` is `'progress'`. */\n value: number;\n /** Interpret `value` as seconds (default) or as a 0–1 progress ratio. */\n unit?: 'seconds' | 'progress';\n };\n uncontrolled: {\n mode: 'uncontrolled';\n /** Initial time in seconds. Default: `0` */\n initialTime?: number;\n /** Playback speed multiplier. Default: `1` */\n speed?: number;\n /** Whether animation is playing. Default: `true` */\n playing?: boolean;\n /** Loop animation when it reaches the end. Default: `false` */\n loop?: boolean;\n /**\n * Delay before the animation starts (seconds). Applied once on\n * initialization and again on {@link TegakiEngine.restart}. Default: `0`\n */\n delay?: number;\n /**\n * Pause between loop iterations (seconds). Only effective when\n * `loop` is `true`. Default: `0`\n */\n loopGap?: number;\n /**\n * Catch-up strength. When positive, playback speeds up when there is a\n * large amount of remaining animation and decays back to normal gradually.\n * `0` disables catch-up (default). Higher values ramp up more aggressively.\n * Typical range: `0.2` – `2`.\n */\n catchUp?: number;\n /** Called on every frame with the current time. */\n onTimeChange?: (time: number) => void;\n };\n css: {\n mode: 'css';\n };\n};\n\n/**\n * A plain number is shorthand for `{ mode: 'controlled', value: number }`.\n * `'css'` is shorthand for `{ mode: 'css' }`.\n * Omit for uncontrolled mode with default settings.\n */\nexport type TimeControlProp = null | undefined | number | 'css' | TimeControlMode[keyof TimeControlMode];\n\n// ---------------------------------------------------------------------------\n// Engine options\n// ---------------------------------------------------------------------------\n\nexport interface TegakiEngineOptions {\n text?: string;\n /** A font bundle, or a registered bundle name (see {@link TegakiEngine.registerBundle}). */\n font?: TegakiBundle | string;\n time?: TimeControlProp;\n effects?: TegakiEffects<Record<string, any>>;\n timing?: TimelineConfig;\n segmentSize?: number;\n showOverlay?: boolean;\n onComplete?: () => void;\n}\n\n// ---------------------------------------------------------------------------\n// Render elements\n// ---------------------------------------------------------------------------\n\nexport type CreateElementFn<T> = (tag: string, props: Record<string, any>, ...children: (T | string)[]) => T;\n\nconst PAD_V_CSS = 'max(0.2em, 0.9em - 0.5lh)';\n\nfunction buildRootProps(options: TegakiEngineOptions): Record<string, any> {\n const text = options.text ?? '';\n const font = resolveBundle(options.font);\n const fontFamily = font?.family;\n\n const duration = text && font ? computeTimeline(text, font, options.timing).totalDuration : 0;\n const time =\n typeof options.time === 'number'\n ? options.time\n : typeof options.time === 'object' && options.time?.mode === 'controlled'\n ? options.time.unit === 'progress'\n ? options.time.value * duration\n : options.time.value\n : typeof options.time === 'object' && options.time?.mode === 'uncontrolled'\n ? (options.time.initialTime ?? 0)\n : 0;\n const progress = duration > 0 ? time / duration : 0;\n\n return {\n 'data-tegaki': 'root',\n style: {\n position: 'relative',\n maxWidth: '100%',\n width: 'auto',\n height: 'auto',\n fontFamily: fontFamily ?? undefined,\n [CSS_DURATION]: duration,\n [CSS_TIME]: time,\n [CSS_PROGRESS]: progress,\n },\n };\n}\n\nfunction buildChildren<T>(options: TegakiEngineOptions, h: CreateElementFn<T>): T {\n const text = options.text ?? '';\n const isCss = options.time === 'css' || (typeof options.time === 'object' && options.time?.mode === 'css');\n const showOverlay = options.showOverlay;\n\n return h(\n 'span',\n { style: { display: 'block', position: 'relative' } },\n h('span', {\n 'data-tegaki': 'sentinel',\n 'aria-hidden': 'true',\n style: {\n position: 'absolute',\n width: 0,\n overflow: 'hidden',\n pointerEvents: 'none',\n fontSize: 'inherit',\n lineHeight: 'inherit',\n visibility: 'hidden',\n transition: isCss\n ? `font-size 0.001s, line-height 0.001s, color 0.001s, ${CSS_PROGRESS} 0.001s`\n : 'font-size 0.001s, line-height 0.001s, color 0.001s',\n },\n }),\n h(\n 'canvas',\n {\n 'data-tegaki': 'canvas',\n 'aria-hidden': 'true',\n style: {\n position: 'absolute',\n inset: `calc(-1 * ${PAD_V_CSS}) -0.2em`,\n width: 'calc(100% + 0.4em)',\n height: `calc(100% + 2 * ${PAD_V_CSS})`,\n pointerEvents: 'none',\n overflow: 'visible',\n },\n },\n h(\n 'span',\n {\n 'data-tegaki': 'canvas-fallback',\n style: { display: 'inline-block', padding: `${PAD_V_CSS} 0.2em` },\n },\n text,\n ),\n ),\n h(\n 'span',\n {\n 'data-tegaki': 'overlay',\n style: {\n display: 'block',\n userSelect: 'auto',\n whiteSpace: 'pre-wrap',\n overflowWrap: 'break-word',\n paddingRight: 1,\n WebkitTextFillColor: showOverlay ? undefined : 'transparent',\n color: showOverlay ? 'rgba(255, 0, 0, 0.4)' : undefined,\n },\n },\n text,\n ),\n );\n}\n\n// ---------------------------------------------------------------------------\n// DOM createElement helper (for vanilla JS constructor)\n// ---------------------------------------------------------------------------\n\nfunction domCreateElement(tag: string, props: Record<string, any>, ...children: (HTMLElement | string)[]): HTMLElement {\n const el = document.createElement(tag);\n for (const [key, value] of Object.entries(props)) {\n if (key === 'style' && typeof value === 'object') {\n for (const [k, v] of Object.entries(value as Record<string, any>)) {\n if (v !== undefined && v !== null) {\n if (k.startsWith('--')) {\n el.style.setProperty(k, String(v));\n } else {\n (el.style as any)[k] = typeof v === 'number' && k !== 'opacity' && k !== 'zIndex' ? `${v}px` : v;\n }\n }\n }\n } else if (key === 'aria-hidden') {\n el.setAttribute('aria-hidden', String(value));\n } else if (key.startsWith('data-')) {\n el.setAttribute(key, String(value));\n }\n }\n for (const child of children) {\n if (typeof child === 'string') {\n el.appendChild(document.createTextNode(child));\n } else {\n el.appendChild(child);\n }\n }\n return el;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction resolveTimeControl(prop: TimeControlProp): TimeControlMode[keyof TimeControlMode] {\n if (prop == null) return { mode: 'uncontrolled' };\n if (typeof prop === 'number') return { mode: 'controlled', value: prop };\n if (prop === 'css') return { mode: 'css' };\n return prop;\n}\n\n// ---------------------------------------------------------------------------\n// TegakiEngine\n// ---------------------------------------------------------------------------\n\nfunction resolveBundle(font: TegakiBundle | string | undefined): TegakiBundle | undefined {\n if (typeof font === 'string') {\n const bundle = TegakiEngine.getBundle(font);\n if (!bundle) throw new Error(`TegakiEngine: no bundle registered for \"${font}\". Call TegakiEngine.registerBundle() first.`);\n return bundle;\n }\n return font;\n}\n\nexport class TegakiEngine {\n // --- Bundle registry ---\n private static _bundles = new Map<string, TegakiBundle>();\n\n /** Register a font bundle so it can be referenced by family name. */\n static registerBundle(bundle: TegakiBundle): void {\n TegakiEngine._bundles.set(bundle.family, bundle);\n }\n\n /** Look up a registered bundle by family name. */\n static getBundle(family: string): TegakiBundle | undefined {\n return TegakiEngine._bundles.get(family);\n }\n\n // --- DOM elements ---\n private _rootEl: HTMLElement;\n private _contentEl: HTMLElement | null = null; // non-null only in non-adopt mode\n private _sentinelEl: HTMLSpanElement;\n private _canvasEl: HTMLCanvasElement;\n private _overlayEl: HTMLElement;\n private _canvasFallbackEl: HTMLSpanElement;\n\n // --- Options ---\n private _text = '';\n private _font: TegakiBundle | null = null;\n private _timeControl: TimeControlMode[keyof TimeControlMode] = { mode: 'uncontrolled' };\n private _effects: Record<string, any> | undefined;\n private _timing: TimelineConfig | undefined;\n private _segmentSize: number | undefined;\n private _showOverlay = false;\n private _onComplete: (() => void) | undefined;\n\n // --- Derived / cached ---\n private _resolvedEffects: ResolvedEffect[] = resolveEffects(undefined);\n private _seed: number;\n private _timeline: Timeline = { entries: [] as TimelineEntry[], totalDuration: 0 };\n private _layout: TextLayout | null = null;\n private _fontReady = false;\n\n // --- Measured from DOM ---\n private _containerWidth = 0;\n private _fontSize = 0;\n private _lineHeight = 0;\n private _currentColor = '';\n\n // --- Playback state ---\n private _internalTime = 0;\n private _cssTime = 0;\n private _playing = true;\n private _smoothedBoost = 0;\n private _delayRemaining = 0;\n private _loopGapRemaining = 0;\n private _lastTs: number | null = null;\n private _rafId = 0;\n private _prevCompleted = false;\n private _prefersReducedMotion = false;\n private _destroyed = false;\n\n // --- Observers & listeners ---\n private _resizeObserver: ResizeObserver;\n private _mql: MediaQueryList | null = null;\n\n /**\n * Returns the props (including style) that should be applied to the container element,\n * plus the inner content tree rendered via a framework `createElement` callback.\n *\n * Each child element receives a `data-tegaki` attribute so the engine can adopt\n * pre-rendered elements later via `new TegakiEngine(container, { adopt: true })`.\n */\n static renderElements<T>(\n options: TegakiEngineOptions,\n createElement: CreateElementFn<T>,\n ): { rootProps: Record<string, any>; content: T } {\n return {\n rootProps: buildRootProps(options),\n content: buildChildren(options, createElement),\n };\n }\n\n constructor(container: HTMLElement, options?: TegakiEngineOptions & { adopt?: boolean }) {\n registerCssProperties();\n this._seed = Math.random() * 1000;\n\n // --- Resolve DOM elements ---\n // The container itself is the root element. In adopt mode, the adapter has\n // already rendered children inside it. In non-adopt mode, we create them.\n this._rootEl = container;\n\n if (options?.adopt) {\n // Adopt pre-rendered children (created by renderElements)\n } else {\n // Create DOM from scratch\n const content = buildChildren(options ?? {}, domCreateElement);\n container.appendChild(content);\n this._contentEl = content;\n // Apply root styles to the container\n const rootProps = buildRootProps(options ?? {});\n for (const [key, value] of Object.entries(rootProps.style as Record<string, any>)) {\n if (value !== undefined && value !== null) {\n if (key.startsWith('--')) {\n container.style.setProperty(key, String(value));\n } else {\n (container.style as any)[key] = typeof value === 'number' && key !== 'opacity' && key !== 'zIndex' ? `${value}px` : value;\n }\n }\n }\n container.dataset.tegaki = 'root';\n }\n\n this._sentinelEl = container.querySelector('[data-tegaki=\"sentinel\"]') as HTMLSpanElement;\n this._canvasEl = container.querySelector('[data-tegaki=\"canvas\"]') as HTMLCanvasElement;\n this._canvasFallbackEl = container.querySelector('[data-tegaki=\"canvas-fallback\"]') as HTMLSpanElement;\n this._overlayEl = container.querySelector('[data-tegaki=\"overlay\"]') as HTMLElement;\n\n // --- ResizeObserver ---\n this._resizeObserver = new ResizeObserver(this._onResize);\n this._resizeObserver.observe(this._rootEl);\n\n // --- Sentinel transitions ---\n this._sentinelEl.addEventListener('transitionend', this._onSentinelTransition);\n\n // --- Reduced motion ---\n if (typeof window !== 'undefined') {\n this._mql = window.matchMedia('(prefers-reduced-motion: reduce)');\n this._prefersReducedMotion = this._mql.matches;\n this._mql.addEventListener('change', this._onReducedMotionChange);\n }\n\n // --- Initial measurement (must run before update so layout has valid dimensions) ---\n this._measure();\n\n // --- Apply initial options ---\n if (options) this.update(options);\n }\n\n // =========================================================================\n // Public API\n // =========================================================================\n\n get currentTime(): number {\n const tc = this._timeControl;\n if (tc.mode === 'css') return this._cssTime;\n if (tc.mode === 'controlled') return tc.unit === 'progress' ? tc.value * this._timeline.totalDuration : tc.value;\n return this._internalTime;\n }\n\n get duration(): number {\n return this._timeline.totalDuration;\n }\n\n get isPlaying(): boolean {\n return this._playing;\n }\n\n get isComplete(): boolean {\n return this._timeline.totalDuration > 0 && this.currentTime >= this._timeline.totalDuration;\n }\n\n get element(): HTMLElement {\n return this._rootEl;\n }\n\n play(): void {\n if (this._timeControl.mode !== 'uncontrolled') return;\n this._playing = true;\n this._evaluatePlayback();\n }\n\n pause(): void {\n if (this._timeControl.mode !== 'uncontrolled') return;\n this._playing = false;\n this._evaluatePlayback();\n }\n\n seek(time: number): void {\n if (this._timeControl.mode !== 'uncontrolled') return;\n this._internalTime = Math.max(0, Math.min(time, this._timeline.totalDuration));\n this._delayRemaining = 0;\n this._loopGapRemaining = 0;\n this._checkCompletion();\n this._notifyTimeChange();\n this._render();\n this._updateCssProperties();\n }\n\n restart(): void {\n if (this._timeControl.mode !== 'uncontrolled') return;\n this._internalTime = 0;\n this._playing = true;\n this._prevCompleted = false;\n this._delayRemaining = this._timeControl.delay ?? 0;\n this._loopGapRemaining = 0;\n this._notifyTimeChange();\n this._evaluatePlayback();\n }\n\n update(options: Partial<TegakiEngineOptions>): void {\n if (this._destroyed) return;\n\n let dirtyTimeline = false;\n let dirtyLayout = false;\n let dirtyRender = false;\n let dirtyPlayback = false;\n\n if ('text' in options && options.text !== this._text) {\n this._text = options.text ?? '';\n dirtyTimeline = true;\n dirtyLayout = true;\n }\n\n if ('font' in options) {\n const resolved = resolveBundle(options.font) ?? null;\n if (resolved !== this._font) {\n this._loadFont(resolved);\n dirtyTimeline = true;\n dirtyLayout = true;\n dirtyPlayback = true;\n }\n }\n\n if ('time' in options) {\n const newTc = resolveTimeControl(options.time);\n const oldTc = this._timeControl;\n\n // Detect meaningful changes\n const modeChanged = newTc.mode !== oldTc.mode;\n const controlledValueChanged =\n newTc.mode === 'controlled' && oldTc.mode === 'controlled' && (newTc.value !== oldTc.value || newTc.unit !== oldTc.unit);\n const uncontrolledChanged =\n newTc.mode === 'uncontrolled' &&\n oldTc.mode === 'uncontrolled' &&\n (newTc.speed !== oldTc.speed ||\n newTc.playing !== oldTc.playing ||\n newTc.loop !== oldTc.loop ||\n newTc.delay !== oldTc.delay ||\n newTc.loopGap !== oldTc.loopGap ||\n newTc.catchUp !== oldTc.catchUp);\n\n if (modeChanged || controlledValueChanged || uncontrolledChanged) {\n this._timeControl = newTc;\n\n if (newTc.mode === 'uncontrolled') {\n this._playing = newTc.playing ?? true;\n const oldDelay = oldTc.mode === 'uncontrolled' ? (oldTc.delay ?? 0) : 0;\n const newDelay = newTc.delay ?? 0;\n if (modeChanged || oldDelay !== newDelay) {\n this._delayRemaining = newDelay;\n this._loopGapRemaining = 0;\n }\n }\n\n dirtyPlayback = true;\n dirtyRender = true;\n\n // Update sentinel transition for css mode\n this._updateSentinelTransition();\n }\n }\n\n if ('effects' in options && options.effects !== this._effects) {\n this._effects = options.effects as Record<string, any>;\n this._resolvedEffects = resolveEffects(this._effects);\n dirtyRender = true;\n }\n\n if ('timing' in options && options.timing !== this._timing) {\n this._timing = options.timing;\n dirtyTimeline = true;\n }\n\n if ('segmentSize' in options && options.segmentSize !== this._segmentSize) {\n this._segmentSize = options.segmentSize;\n dirtyRender = true;\n }\n\n if ('showOverlay' in options && options.showOverlay !== this._showOverlay) {\n this._showOverlay = options.showOverlay ?? false;\n this._updateOverlayStyle();\n dirtyRender = true;\n }\n\n if ('onComplete' in options) {\n this._onComplete = options.onComplete;\n }\n\n // --- Recompute ---\n if (dirtyTimeline) this._recomputeTimeline();\n if (dirtyLayout) this._recomputeLayout();\n if (dirtyPlayback) this._evaluatePlayback();\n if (dirtyRender || dirtyTimeline || dirtyLayout) {\n this._updateDom();\n this._render();\n }\n }\n\n destroy(): void {\n this._destroyed = true;\n this._stopLoop();\n this._resizeObserver.disconnect();\n this._sentinelEl.removeEventListener('transitionend', this._onSentinelTransition);\n this._mql?.removeEventListener('change', this._onReducedMotionChange);\n // Only remove content we created (non-adopt mode). The container is owned by the caller.\n this._contentEl?.remove();\n }\n\n // =========================================================================\n // Internal: DOM updates\n // =========================================================================\n\n /** Estimate line-height from font metrics when CSS returns \"normal\". */\n private _fallbackLineHeight(fontSize: number): number {\n if (this._font) {\n return ((this._font.ascender - this._font.descender) / this._font.unitsPerEm) * fontSize;\n }\n return fontSize * 1.2;\n }\n\n private _measure(): void {\n const styles = getComputedStyle(this._rootEl);\n this._containerWidth = this._rootEl.getBoundingClientRect().width;\n this._fontSize = Number.parseFloat(styles.fontSize);\n const parsedLh = Number.parseFloat(styles.lineHeight);\n this._lineHeight = Number.isNaN(parsedLh) ? this._fallbackLineHeight(this._fontSize) : parsedLh;\n this._currentColor = styles.color;\n }\n\n private _updateDom(): void {\n // Font family\n this._rootEl.style.fontFamily = this._font?.family ?? '';\n\n // CSS custom properties\n this._updateCssProperties();\n\n // Overlay text (guard to preserve cursor position when contentEditable)\n if (this._overlayEl.textContent !== this._text) {\n this._overlayEl.textContent = this._text;\n }\n this._canvasFallbackEl.textContent = this._text;\n }\n\n private _updateCssProperties(): void {\n const time = this.currentTime;\n const dur = this._timeline.totalDuration;\n this._rootEl.style.setProperty(CSS_DURATION, String(dur));\n this._rootEl.style.setProperty(CSS_TIME, String(time));\n this._rootEl.style.setProperty(CSS_PROGRESS, String(dur > 0 ? time / dur : 0));\n }\n\n private _updateOverlayStyle(): void {\n if (this._showOverlay) {\n this._overlayEl.style.webkitTextFillColor = '';\n this._overlayEl.style.color = 'rgba(255, 0, 0, 0.4)';\n } else {\n this._overlayEl.style.webkitTextFillColor = 'transparent';\n this._overlayEl.style.color = '';\n }\n }\n\n private _updateSentinelTransition(): void {\n const isCss = this._timeControl.mode === 'css';\n this._sentinelEl.style.transition = isCss\n ? `font-size 0.001s, line-height 0.001s, color 0.001s, ${CSS_PROGRESS} 0.001s`\n : 'font-size 0.001s, line-height 0.001s, color 0.001s';\n }\n\n // =========================================================================\n // Internal: Resize & sentinel observers\n // =========================================================================\n\n private _onResize = (entries: ResizeObserverEntry[]): void => {\n const entry = entries[0];\n if (!entry) return;\n const newWidth = entry.contentRect.width;\n const styles = getComputedStyle(this._rootEl);\n const newFontSize = Number.parseFloat(styles.fontSize);\n const parsedLh = Number.parseFloat(styles.lineHeight);\n const newLineHeight = Number.isNaN(parsedLh) ? this._fallbackLineHeight(newFontSize) : parsedLh;\n const newColor = styles.color;\n\n let changed = false;\n let layoutChanged = false;\n\n if (newWidth !== this._containerWidth) {\n this._containerWidth = newWidth;\n layoutChanged = true;\n changed = true;\n }\n if (newFontSize !== this._fontSize) {\n this._fontSize = newFontSize;\n layoutChanged = true;\n changed = true;\n }\n if (newLineHeight !== this._lineHeight) {\n this._lineHeight = newLineHeight;\n layoutChanged = true;\n changed = true;\n }\n if (newColor !== this._currentColor) {\n this._currentColor = newColor;\n changed = true;\n }\n\n if (layoutChanged) this._recomputeLayout();\n if (changed) this._render();\n };\n\n private _onSentinelTransition = (e: TransitionEvent): void => {\n const styles = getComputedStyle(this._sentinelEl);\n let changed = false;\n\n if (e.propertyName === 'font-size' || e.propertyName === 'line-height') {\n const newFontSize = Number.parseFloat(styles.fontSize);\n const parsedLh = Number.parseFloat(styles.lineHeight);\n const newLineHeight = Number.isNaN(parsedLh) ? this._fallbackLineHeight(newFontSize) : parsedLh;\n if (newFontSize !== this._fontSize || newLineHeight !== this._lineHeight) {\n this._fontSize = newFontSize;\n this._lineHeight = newLineHeight;\n this._recomputeLayout();\n changed = true;\n }\n }\n\n if (e.propertyName === 'color') {\n const newColor = styles.color;\n if (newColor !== this._currentColor) {\n this._currentColor = newColor;\n changed = true;\n }\n }\n\n if (e.propertyName === CSS_PROGRESS) {\n const rawProgress = Number(styles.getPropertyValue(CSS_PROGRESS));\n this._cssTime = rawProgress * this._timeline.totalDuration;\n changed = true;\n }\n\n if (changed) this._render();\n };\n\n // =========================================================================\n // Internal: Reduced motion\n // =========================================================================\n\n private _onReducedMotionChange = (e: MediaQueryListEvent): void => {\n this._prefersReducedMotion = e.matches;\n if (this._prefersReducedMotion && this._timeControl.mode === 'uncontrolled' && this._timeline.totalDuration > 0) {\n this._internalTime = this._timeline.totalDuration;\n }\n this._evaluatePlayback();\n this._render();\n };\n\n // =========================================================================\n // Internal: Font loading\n // =========================================================================\n\n private _loadFont(font: TegakiBundle | null): void {\n this._font = font;\n this._fontReady = false;\n\n if (!font) return;\n\n const pending = ensureFont(font.family, font.fontUrl);\n if (pending === null) {\n this._fontReady = true;\n return;\n }\n\n const currentFont = font;\n pending.then(() => {\n if (this._font === currentFont && !this._destroyed) {\n this._fontReady = true;\n this._recomputeTimeline();\n this._recomputeLayout();\n this._evaluatePlayback();\n this._updateDom();\n this._render();\n }\n });\n }\n\n // =========================================================================\n // Internal: Recomputation\n // =========================================================================\n\n private _recomputeTimeline(): void {\n if (this._font && this._text) {\n this._timeline = computeTimeline(this._text, this._font, this._timing);\n } else {\n this._timeline = { entries: [] as TimelineEntry[], totalDuration: 0 };\n }\n }\n\n private _recomputeLayout(): void {\n const fontFamily = this._font?.family;\n if (this._fontReady && fontFamily && this._fontSize && this._containerWidth && this._text) {\n this._layout = computeTextLayout(this._text, fontFamily, this._fontSize, this._lineHeight, this._containerWidth);\n } else {\n this._layout = null;\n }\n }\n\n // =========================================================================\n // Internal: Playback loop\n // =========================================================================\n\n private _evaluatePlayback(): void {\n const tc = this._timeControl;\n const shouldRun = tc.mode === 'uncontrolled' && this._playing && !!this._font && this._fontReady && !this._prefersReducedMotion;\n\n if (shouldRun) {\n this._startLoop();\n } else {\n this._stopLoop();\n }\n }\n\n private _startLoop(): void {\n if (this._rafId) return;\n this._lastTs = null;\n this._smoothedBoost = 0;\n this._rafId = requestAnimationFrame(this._tick);\n }\n\n private _stopLoop(): void {\n if (this._rafId) {\n cancelAnimationFrame(this._rafId);\n this._rafId = 0;\n }\n }\n\n private _tick = (ts: number): void => {\n if (this._destroyed) return;\n\n if (this._lastTs === null) this._lastTs = ts;\n const dtSec = (ts - this._lastTs) / 1000;\n this._lastTs = ts;\n\n const tc = this._timeControl;\n if (tc.mode !== 'uncontrolled') return;\n\n const speed = tc.speed ?? 1;\n const loop = tc.loop ?? false;\n const catchUp = tc.catchUp ?? 0;\n const totalDur = this._timeline.totalDuration;\n\n if (totalDur === 0 || (!loop && this._internalTime >= totalDur)) {\n this._internalTime = totalDur;\n this._rafId = requestAnimationFrame(this._tick);\n return;\n }\n\n // --- Initial delay ---\n if (this._delayRemaining > 0) {\n this._delayRemaining = Math.max(0, this._delayRemaining - dtSec);\n this._rafId = requestAnimationFrame(this._tick);\n return;\n }\n\n // --- Loop gap (waiting between iterations) ---\n if (this._loopGapRemaining > 0) {\n this._loopGapRemaining = Math.max(0, this._loopGapRemaining - dtSec);\n if (this._loopGapRemaining <= 0) {\n this._internalTime = 0;\n this._prevCompleted = false;\n this._smoothedBoost = 0;\n }\n this._notifyTimeChange();\n this._render();\n this._updateCssProperties();\n this._rafId = requestAnimationFrame(this._tick);\n return;\n }\n\n // Compute effective speed with catch-up\n let effectiveSpeed = speed;\n if (catchUp > 0) {\n const remaining = Math.max(0, totalDur - this._internalTime);\n const excess = Math.max(0, remaining - 2);\n const targetBoost = catchUp * excess;\n const attackRate = 4;\n const releaseRate = loop ? 30 : 2;\n const rate = targetBoost > this._smoothedBoost ? attackRate : releaseRate;\n this._smoothedBoost += (targetBoost - this._smoothedBoost) * (1 - Math.exp(-rate * dtSec));\n effectiveSpeed = speed + this._smoothedBoost;\n }\n\n let next = this._internalTime + dtSec * effectiveSpeed;\n if (next >= totalDur) {\n if (loop) {\n const loopGap = tc.loopGap ?? 0;\n if (loopGap > 0) {\n // Hold at the end and start the loop gap countdown\n next = totalDur;\n this._loopGapRemaining = loopGap;\n } else {\n next = next % totalDur;\n }\n } else {\n next = totalDur;\n }\n this._smoothedBoost = 0;\n }\n this._internalTime = next;\n\n this._notifyTimeChange();\n this._checkCompletion();\n this._render();\n this._updateCssProperties();\n\n this._rafId = requestAnimationFrame(this._tick);\n };\n\n private _notifyTimeChange(): void {\n const tc = this._timeControl;\n if (tc.mode === 'uncontrolled' && tc.onTimeChange) {\n tc.onTimeChange(this._internalTime);\n }\n }\n\n private _checkCompletion(): void {\n const complete = this._timeline.totalDuration > 0 && this.currentTime >= this._timeline.totalDuration;\n if (complete && !this._prevCompleted) {\n this._prevCompleted = true;\n this._onComplete?.();\n } else if (!complete) {\n this._prevCompleted = false;\n }\n }\n\n // =========================================================================\n // Internal: Canvas rendering\n // =========================================================================\n\n private _render(): void {\n const canvas = this._canvasEl;\n const font = this._font;\n const layout = this._layout;\n const fontSize = this._fontSize;\n\n if (!font?.glyphData || !layout || !fontSize) return;\n\n const dpr = window.devicePixelRatio || 1;\n const w = canvas.offsetWidth;\n const h = canvas.offsetHeight;\n\n const needsResize = canvas.width !== Math.round(w * dpr) || canvas.height !== Math.round(h * dpr);\n if (needsResize) {\n canvas.width = Math.round(w * dpr);\n canvas.height = Math.round(h * dpr);\n }\n\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.clearRect(0, 0, w, h);\n\n const padH = PADDING_H_EM * fontSize;\n const lineHeight = this._lineHeight;\n const padV = Math.max(MIN_PADDING_V_EM * fontSize, (MIN_LINE_HEIGHT_EM * fontSize - lineHeight) / 2);\n ctx.translate(padH, padV);\n\n const color = this._currentColor || 'black';\n const emHeight = (font.ascender - font.descender) / font.unitsPerEm;\n const emHeightPx = emHeight * fontSize;\n const halfLeading = (lineHeight - emHeightPx) / 2;\n const characters = graphemes(this._text);\n const currentTime = this.currentTime;\n\n let y = 0;\n for (const lineIndices of layout.lines) {\n let x = 0;\n for (const charIdx of lineIndices) {\n const char = characters[charIdx]!;\n if (char === '\\n') continue;\n const entry = this._timeline.entries[charIdx]!;\n const charWidth = layout.charWidths[charIdx] ?? 0;\n const kerning = layout.kernings[charIdx] ?? 0;\n const glyph = font.glyphData[char];\n\n if (glyph && entry.hasGlyph) {\n const localTime = Math.max(0, Math.min(currentTime - entry.offset, entry.duration));\n const glyphY = y + halfLeading;\n drawGlyph(\n ctx,\n glyph,\n {\n x,\n y: glyphY,\n fontSize,\n unitsPerEm: font.unitsPerEm,\n ascender: font.ascender,\n descender: font.descender,\n },\n localTime,\n font.lineCap,\n color,\n this._resolvedEffects,\n this._seed + charIdx,\n this._segmentSize,\n );\n } else if (!entry.hasGlyph && currentTime >= entry.offset + entry.duration) {\n const baseline = y + halfLeading + (font.ascender / font.unitsPerEm) * fontSize;\n drawFallbackGlyph(ctx, char, x, baseline, fontSize, font.family, color, this._resolvedEffects, this._seed + charIdx);\n }\n\n x += (charWidth + kerning) * fontSize;\n }\n y += lineHeight;\n }\n }\n}\n"],"mappings":"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"}
|