File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 1+ ---
2+ " tegaki " : patch
3+ ---
4+
5+ feat: add stroke and glyph easing functions
Original file line number Diff line number Diff line change @@ -743,7 +743,11 @@ export class TegakiEngine {
743743 const glyph = font . glyphData [ char ] ;
744744
745745 if ( glyph && entry . hasGlyph ) {
746- const localTime = Math . max ( 0 , Math . min ( currentTime - entry . offset , entry . duration ) ) ;
746+ let localTime = Math . max ( 0 , Math . min ( currentTime - entry . offset , entry . duration ) ) ;
747+ const glyphEasing = this . _timing ?. glyphEasing ;
748+ if ( glyphEasing && entry . duration > 0 ) {
749+ localTime = glyphEasing ( localTime / entry . duration ) * entry . duration ;
750+ }
747751 const glyphY = y + halfLeading ;
748752 drawGlyph (
749753 ctx ,
@@ -762,6 +766,7 @@ export class TegakiEngine {
762766 this . _resolvedEffects ,
763767 this . _seed + charIdx ,
764768 this . _segmentSize ,
769+ this . _timing ?. strokeEasing ,
765770 ) ;
766771 } else if ( ! entry . hasGlyph && currentTime >= entry . offset + entry . duration ) {
767772 const baseline = y + halfLeading + ( font . ascender / font . unitsPerEm ) * fontSize ;
Original file line number Diff line number Diff line change @@ -74,6 +74,11 @@ function noise1d(x: number, seed: number): number {
7474 return hash ( i + seed * 7919 ) * ( 1 - t ) + hash ( i + 1 + seed * 7919 ) * t ;
7575}
7676
77+ /** Default stroke easing: ease-out exponential. */
78+ function defaultStrokeEasing ( t : number ) : number {
79+ return 1 - ( 1 - t ) * ( 1 - t ) ; // Ease out quad
80+ }
81+
7782/**
7883 * Draw a single glyph's strokes onto a canvas context, animated up to `localTime`.
7984 * `localTime` is seconds relative to this glyph's start (0 = glyph begins).
@@ -88,6 +93,7 @@ export function drawGlyph(
8893 effects : ResolvedEffect [ ] = [ ] ,
8994 seed = 0 ,
9095 segmentSize ?: number ,
96+ strokeEasing : ( ( t : number ) => number ) | undefined = defaultStrokeEasing ,
9197) {
9298 const scale = pos . fontSize / pos . unitsPerEm ;
9399 const ox = pos . x ;
@@ -157,7 +163,8 @@ export function drawGlyph(
157163 for ( const stroke of glyph . s ) {
158164 if ( localTime < stroke . d ) continue ;
159165 const elapsed = localTime - stroke . d ;
160- const progress = Math . min ( elapsed / stroke . a , 1 ) ;
166+ const linearProgress = Math . min ( elapsed / stroke . a , 1 ) ;
167+ const progress = strokeEasing ? strokeEasing ( linearProgress ) : linearProgress ;
161168
162169 const pts = stroke . p ;
163170 if ( pts . length === 0 ) continue ;
Original file line number Diff line number Diff line change @@ -10,9 +10,21 @@ export interface TimelineConfig {
1010 lineGap ?: number ;
1111 /** Duration for characters without glyph data (seconds). Default: `0.2` */
1212 unknownDuration ?: number ;
13+ /**
14+ * Easing function for each stroke's animation progress `(0–1) → (0–1)`.
15+ * Applied per-stroke to map linear draw progress to eased progress.
16+ * Default: ease-out exponential (`1 - 2^(-10t)`).
17+ */
18+ strokeEasing ?: ( t : number ) => number ;
19+ /**
20+ * Easing function for each glyph's local time progress `(0–1) → (0–1)`.
21+ * Applied per-glyph to map linear time within the glyph to eased time.
22+ * Default: linear (no easing).
23+ */
24+ glyphEasing ?: ( t : number ) => number ;
1325}
1426
15- const DEFAULTS : Required < TimelineConfig > = {
27+ const DEFAULTS = {
1628 glyphGap : 0.1 ,
1729 wordGap : 0.15 ,
1830 lineGap : 0.3 ,
You can’t perform that action at this time.
0 commit comments