Skip to content

Releases: gkurt/tegaki

tegaki@0.20.0

Choose a tag to compare

@github-actions github-actions released this 30 Jun 13:56
8b75b28

Add TegakiEngine.toSVG() and a canvas accessor (2c578e9)

The engine can now serialize its current text to a standalone SVG string via toSVG({ animated, loop }) — either self-drawing (SMIL mask reveal, variable stroke width) or looping (CSS keyframes, constant width), with the viewBox cropped to the ink. The backing <canvas> is also exposed through a canvas getter so export tooling can read pixels without reaching through the DOM.

Pull request & contributors

Add a tegaki CLI and a textToSvg() export (2c578e9)

npx tegaki renders text to an animated handwriting SVG straight from the command line. The same output is available programmatically through the new textToSvg() export, along with its TextToSvgMode and TextToSvgOptions types.

Pull request & contributors

tegaki@0.19.0

Choose a tag to compare

@github-actions github-actions released this 28 Jun 14:12
b99602a

Minor Changes

  • 68ee58f: Support Korean (Hangul) writing system and add Nanum Pen Script as a built-in font. The bundle ships ~650 most-frequent precomposed Hangul syllables (KS X 1001 common band ∪ top-N Korean-Wikipedia-frequency, capped by the Google Fonts subsetting ceiling) plus the 40 modern compatibility jamo (19 consonants ㄱ–ㅎ + 21 vowels ㅏ–ㅣ) and the Latin baseline. Hangul is precomposed in Unicode, so no shaper is required.

Patch Changes

  • 29e111e: Fix Next.js App Router / Turbopack compatibility. Two build/packaging issues prevented tegaki from being used in a Next.js (App Router) app:

    • The bundler dropped the 'use client' directive from the React adapter's output chunk, so importing TegakiRenderer into a Server Component failed with "You're importing a module that depends on useState into a React Server Component". The directive is now preserved in the built output.
    • The font subpath exports (tegaki/fonts/*) resolved the node condition to the raw TypeScript source, which uses import ... with { type: 'url' } import attributes that Turbopack/webpack can't process. The node condition now points to the pre-built .mjs bundle (which loads the font via new URL('./font.ttf', import.meta.url)), so it works in any Node-based bundler.

tegaki@0.18.0

Choose a tag to compare

@github-actions github-actions released this 27 May 16:38
53560de

Minor Changes

  • b6e883b: Update Harfbuzz to v1.1.0
  • d358cbd: Add stagger timing mode where each glyph starts a fixed advance (seconds or "N%" of the previous glyph's effective duration) after the previous one, with an optional static per-glyph duration that scales strokes to fit. Exposed in the website previewer via the new st / sa / sd URL keys.

Patch Changes

  • 150296e: Fix the Astro adapter so passing font={bundle} hydrates without an explicit bundle prop and lookups by human-friendly font name resolve correctly. Animations now also re-hydrate after Astro View Transitions navigations.
  • 150296e: Make the Vue adapter's effects prop generic so custom effect configs are correctly type-inferred. Also drop a redundant Nuxt config type augmentation.

tegaki@0.17.1

Choose a tag to compare

@github-actions github-actions released this 08 May 11:51
8033add

Patch Changes

  • affe5a5: Add shorthand for setting time property to a percentage for controlled progress mode.

tegaki@0.17.0

Choose a tag to compare

@github-actions github-actions released this 08 May 00:20
d633f98

Minor Changes

  • 2b4b435: Support Devanagari writing system and add Tillana as built-in font. Also fixed a bug with generating n-grams, which affected Arabic fonts.

Patch Changes

  • ee2db76: Fix GPOS and advance width features for some Arabic fonts like "Aref Ruqaa"

tegaki@0.16.0

Choose a tag to compare

@github-actions github-actions released this 07 May 02:02
b286f5f

Minor Changes

  • 39e075e: Added support for font features and ligatures, RTL languages like Arabic and Hebrew, and text shaping with Harfbuzz. Three new built-in font bundles ship for non-Latin scripts: tegaki/fonts/suez-one (Hebrew), tegaki/fonts/amiri (Arabic), and tegaki/fonts/klee-one (Japanese — kana, JP punctuation, and Kyōiku grade 1–2 kanji).

tegaki@0.15.0

Choose a tag to compare

@github-actions github-actions released this 20 Apr 12:30
98e73f8

Minor Changes

  • ecba479: Split gradient into strokeGradient + globalGradient, and add render-stage hooks for layout-spanning effects. Closes #26.

    Breaking

    The gradient effect is renamed to strokeGradient with unchanged behavior (each stroke independently maps its progress to the color stops; colors: 'rainbow' still works). Rename the key in your effects prop:

    // before
    effects={{ gradient: { colors: ['#f00', '#00f'] } }}
    // after
    effects={{ strokeGradient: { colors: ['#f00', '#00f'] } }}

    New — globalGradient

    A canvas-space linear gradient that spans the full text bounding box — the leftmost pixel of the first glyph is colors[0] and the rightmost pixel of the last glyph is colors[N], regardless of stroke boundaries. Matches CSS background-clip: text semantics.

    effects={{
      globalGradient: {
        colors: ['#f00', '#00f'],
        angle: 0, // 0 = left→right (default); 90 = top→bottom; positive = clockwise
      },
    }}

    strokeGradient and globalGradient can be enabled independently. If both are on, strokeGradient wins per segment (its per-stroke color overrides globalGradient's canvas-wide paint); this combination is unusual but predictable.

    New — effect render-stage hooks

    Effects can now declare optional beforeRender(stage, config) / afterRender(stage, config) hooks on their EffectDefinition metadata. The stage context exposes the 2D context, the TextLayout, a pre-computed LayoutBBox, base color, and seed. Hooks run once around the glyph loop (before in forward order, after in reverse), so effects spanning the whole layout — like globalGradient — have a natural place to set up canvas state. Built-in per-stroke effects (glow, wobble, pressureWidth, taper, strokeGradient) declare no hooks and are unaffected.

    New public exports from tegaki/core: EffectDefinition, RenderStageContext, LayoutBBox, getEffectDefinition, hasRenderHooks, computeLayoutBbox, plus the previously-private findEffect / findEffects.

tegaki@0.14.0

Choose a tag to compare

@github-actions github-actions released this 19 Apr 22:06
6c72be0

Minor Changes

  • 79a0e6a: Add Nuxt module and usage example. Fixes #35.
  • 9a0d74a: Add quality.smoothing option that interpolates stroke points with a centripetal Catmull-Rom spline, hiding the faceted corners visible at large render sizes where the baked polyline resolution shows through. Enabling it forces subdivision on (default segmentSize=2 CSS px) and rebuilds the subdivision cache; the original points stay on the curve, so animation timing and wobble phase are unchanged. Default is false (existing bundles render identically). Also exposed on the web component as the smoothing attribute.

Patch Changes

  • 84ad2b2: text layout was broken when element had transform applied
  • b6967aa: canvas was not cleared when all text removed

tegaki@0.13.0

Choose a tag to compare

@github-actions github-actions released this 18 Apr 12:26
86e55ce

Minor Changes

  • 8fd875a: Add clipText quality option that clips handwriting strokes to the filled text shape using canvas composite operations. Accepts true for clipping with normal stroke widths, or a number to scale stroke widths (e.g. 2 for 2x wider strokes that fill more of the glyph interior).

Patch Changes

  • 2a46c09: fix compatibility with old Safari versions, and a bug with text layout when text is wrapped. Fixes #29

  • cdb2993: Fix timing around whitespace characters. Spaces and line breaks no longer consume unknownDuration on top of wordGap/lineGap — the gap alone now represents the full pause. \r\n and \r are normalized to \n, and all Unicode whitespace (NBSP, tab, ideographic space, etc.) is treated as a word gap.

    Fixes #28

tegaki@0.12.0

Choose a tag to compare

@github-actions github-actions released this 16 Apr 12:14
7e532a8

Minor Changes

  • be16624: Add bundle format versioning. Generated bundles now include a version field (currently 0) so the engine can detect incompatible bundles. The engine checks the version when a bundle is registered or resolved and logs a console warning (once per bundle) if the version is missing or unsupported.

    New exports: BUNDLE_VERSION, COMPATIBLE_BUNDLE_VERSIONS. New optional TegakiBundle field: version. Existing bundles without a version field trigger the warning but continue to work.

  • 9776ca3: Cache stroke subdivision across glyph instances. Subdivision now depends
    only on (stroke points, fontSize, segmentSize) and is reused by every
    occurrence of the same glyph in the rendered text. Wobble, progress
    truncation, pressure, taper, and gradient are applied at draw time on
    top of the shared geometry, and effect config changes no longer
    invalidate the cache. Glow draws the full truncated polyline in a single
    stroke() call, removing the previous per-sub-segment shadowBlur cost.

    Wobble is now sampled per sub-vertex (fractional original-point index
    keeps phase continuous), giving smoother curves than the previous
    lerp-between-wobbled-raw-vertices.

  • 1ce1324: Add subset font bundling with full-font fallback. Bundles generated from a character subset now ship two font files: a subsetted TTF for the generated glyphs and the full TTF as a CSS fallback. The subset font is registered under a scoped family name (<family> Tegaki <hash>) to avoid colliding with user-loaded fonts, while the full font uses the original family name. The renderer composes both in font-family so the browser automatically falls back to the full font for non-generated characters.

    New TegakiBundle fields: fullFamily, fullFontUrl. Existing bundles without these fields continue to work unchanged.

Patch Changes

  • 73a6b7e: Introduces TegakiQuality ({ pixelRatio, segmentSize }) on the engine
    options, replacing the top-level segmentSize. pixelRatio multiplies
    devicePixelRatio when sizing the canvas backing store and root
    transform, letting the browser downsample to the displayed size for
    higher-quality antialiasing at a quadratic cost in pixels filled.
    segmentSize retains its prior meaning under the new namespace.
  • d9b7c85: feat: add stroke and glyph easing functions
  • 7aaf5d2: add rtl direction support
  • 23757ca: Breaking: quality.segmentSize is now measured in CSS pixels instead of
    font units. Subdivision count now scales with rendered size, so small
    glyphs are no longer over-subdivided. A 100px stroke with segmentSize=1
    yields ~100 sub-segments; the same stroke at 10px yields ~10.