@staticcanvas/typeflow 0.34.0 → 0.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -516
- package/dist/typeflow-0.34.1.tar.gz +0 -0
- package/dist/typeflow-0.34.1.zip +0 -0
- package/dist/{typeflow/dist/typeflow.cjs → typeflow.cjs} +1 -1
- package/dist/{typeflow/dist/typeflow.esm.js → typeflow.esm.js} +1 -1
- package/dist/{typeflow/dist/typeflow.js → typeflow.js} +1 -1
- package/dist/{typeflow/dist/typeflow.mjs → typeflow.mjs} +1 -1
- package/jsr.jsonc +1 -1
- package/package.json +2 -56
- package/branding/dist/ico/typeflow-logo-16x16.ico +0 -0
- package/branding/dist/ico/typeflow-logo-256x256.ico +0 -0
- package/branding/dist/ico/typeflow-logo-32x32.ico +0 -0
- package/branding/dist/ico/typeflow-logo-48x48.ico +0 -0
- package/branding/dist/png/typeflow-logo-1024x1024.png +0 -0
- package/branding/dist/png/typeflow-logo-128x128.png +0 -0
- package/branding/dist/png/typeflow-logo-16x16.png +0 -0
- package/branding/dist/png/typeflow-logo-256x256.png +0 -0
- package/branding/dist/png/typeflow-logo-512x512.png +0 -0
- package/branding/dist/png/typeflow-logo-64x64.png +0 -0
- package/branding/dist/webp/typeflow-logo-1024x1024.webp +0 -0
- package/branding/dist/webp/typeflow-logo-128x128.webp +0 -0
- package/branding/dist/webp/typeflow-logo-16x16.webp +0 -0
- package/branding/dist/webp/typeflow-logo-256x256.webp +0 -0
- package/branding/dist/webp/typeflow-logo-32x32.webp +0 -0
- package/branding/dist/webp/typeflow-logo-48x48.webp +0 -0
- package/branding/dist/webp/typeflow-logo-512x512.webp +0 -0
- package/branding/dist/webp/typeflow-logo-64x64.webp +0 -0
- package/dist/typeflow/LICENSE +0 -21
- package/dist/typeflow/README.md +0 -231
- package/dist/typeflow/branding/dist/ico/typeflow-logo-16x16.ico +0 -0
- package/dist/typeflow/branding/dist/ico/typeflow-logo-256x256.ico +0 -0
- package/dist/typeflow/branding/dist/ico/typeflow-logo-32x32.ico +0 -0
- package/dist/typeflow/branding/dist/ico/typeflow-logo-48x48.ico +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-1024x1024.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-128x128.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-16x16.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-256x256.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-512x512.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-64x64.png +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-1024x1024.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-128x128.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-16x16.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-256x256.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-32x32.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-48x48.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-512x512.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-64x64.webp +0 -0
- package/dist/typeflow/branding/gen-logo.ps1 +0 -14
- package/dist/typeflow/branding/typeflow-logo.svg +0 -162
- package/dist/typeflow/jsr.jsonc +0 -27
- package/dist/typeflow/package.json +0 -79
- package/dist/typeflow/src/typeflow-audio-presets.js +0 -137
- package/dist/typeflow/src/typeflow-caret.d.ts +0 -65
- package/dist/typeflow/src/typeflow-caret.js +0 -303
- package/dist/typeflow/src/typeflow-debug.d.ts +0 -34
- package/dist/typeflow/src/typeflow-debug.js +0 -223
- package/dist/typeflow/src/typeflow-extchars.d.ts +0 -28
- package/dist/typeflow/src/typeflow-extchars.js +0 -132
- package/dist/typeflow/src/typeflow-keystroke.d.ts +0 -28
- package/dist/typeflow/src/typeflow-keystroke.js +0 -220
- package/dist/typeflow/src/typeflow-metrics.d.ts +0 -38
- package/dist/typeflow/src/typeflow-metrics.js +0 -556
- package/dist/typeflow/src/typeflow-parallel.d.ts +0 -36
- package/dist/typeflow/src/typeflow-parallel.js +0 -157
- package/dist/typeflow/src/typeflow-webaudio.d.ts +0 -83
- package/dist/typeflow/src/typeflow-webaudio.js +0 -517
- package/dist/typeflow/src/typeflow.d.ts +0 -328
- package/dist/typeflow/src/typeflow.js +0 -2119
- /package/dist/{typeflow/dist/typeflow-caret.cjs → typeflow-caret.cjs} +0 -0
- /package/dist/{typeflow/dist/typeflow-caret.cjs.map → typeflow-caret.cjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-caret.esm.js → typeflow-caret.esm.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-caret.esm.js.map → typeflow-caret.esm.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-caret.esm.min.js → typeflow-caret.esm.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-caret.esm.min.js.map → typeflow-caret.esm.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-caret.js → typeflow-caret.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-caret.js.map → typeflow-caret.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-caret.min.js → typeflow-caret.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-caret.min.js.map → typeflow-caret.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-caret.mjs → typeflow-caret.mjs} +0 -0
- /package/dist/{typeflow/dist/typeflow-caret.mjs.map → typeflow-caret.mjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-debug.cjs → typeflow-debug.cjs} +0 -0
- /package/dist/{typeflow/dist/typeflow-debug.cjs.map → typeflow-debug.cjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-debug.esm.js → typeflow-debug.esm.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-debug.esm.js.map → typeflow-debug.esm.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-debug.esm.min.js → typeflow-debug.esm.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-debug.esm.min.js.map → typeflow-debug.esm.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-debug.js → typeflow-debug.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-debug.js.map → typeflow-debug.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-debug.min.js → typeflow-debug.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-debug.min.js.map → typeflow-debug.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-debug.mjs → typeflow-debug.mjs} +0 -0
- /package/dist/{typeflow/dist/typeflow-debug.mjs.map → typeflow-debug.mjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-extchars.cjs → typeflow-extchars.cjs} +0 -0
- /package/dist/{typeflow/dist/typeflow-extchars.cjs.map → typeflow-extchars.cjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-extchars.esm.js → typeflow-extchars.esm.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-extchars.esm.js.map → typeflow-extchars.esm.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-extchars.esm.min.js → typeflow-extchars.esm.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-extchars.esm.min.js.map → typeflow-extchars.esm.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-extchars.js → typeflow-extchars.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-extchars.js.map → typeflow-extchars.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-extchars.min.js → typeflow-extchars.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-extchars.min.js.map → typeflow-extchars.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-extchars.mjs → typeflow-extchars.mjs} +0 -0
- /package/dist/{typeflow/dist/typeflow-extchars.mjs.map → typeflow-extchars.mjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-keystroke.cjs → typeflow-keystroke.cjs} +0 -0
- /package/dist/{typeflow/dist/typeflow-keystroke.cjs.map → typeflow-keystroke.cjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-keystroke.esm.js → typeflow-keystroke.esm.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-keystroke.esm.js.map → typeflow-keystroke.esm.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-keystroke.esm.min.js → typeflow-keystroke.esm.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-keystroke.esm.min.js.map → typeflow-keystroke.esm.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-keystroke.js → typeflow-keystroke.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-keystroke.js.map → typeflow-keystroke.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-keystroke.min.js → typeflow-keystroke.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-keystroke.min.js.map → typeflow-keystroke.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-keystroke.mjs → typeflow-keystroke.mjs} +0 -0
- /package/dist/{typeflow/dist/typeflow-keystroke.mjs.map → typeflow-keystroke.mjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-metrics.cjs → typeflow-metrics.cjs} +0 -0
- /package/dist/{typeflow/dist/typeflow-metrics.cjs.map → typeflow-metrics.cjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-metrics.esm.js → typeflow-metrics.esm.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-metrics.esm.js.map → typeflow-metrics.esm.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-metrics.esm.min.js → typeflow-metrics.esm.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-metrics.esm.min.js.map → typeflow-metrics.esm.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-metrics.js → typeflow-metrics.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-metrics.js.map → typeflow-metrics.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-metrics.min.js → typeflow-metrics.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-metrics.min.js.map → typeflow-metrics.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-metrics.mjs → typeflow-metrics.mjs} +0 -0
- /package/dist/{typeflow/dist/typeflow-metrics.mjs.map → typeflow-metrics.mjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-parallel.cjs → typeflow-parallel.cjs} +0 -0
- /package/dist/{typeflow/dist/typeflow-parallel.cjs.map → typeflow-parallel.cjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-parallel.esm.js → typeflow-parallel.esm.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-parallel.esm.js.map → typeflow-parallel.esm.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-parallel.esm.min.js → typeflow-parallel.esm.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-parallel.esm.min.js.map → typeflow-parallel.esm.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-parallel.js → typeflow-parallel.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-parallel.js.map → typeflow-parallel.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-parallel.min.js → typeflow-parallel.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-parallel.min.js.map → typeflow-parallel.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-parallel.mjs → typeflow-parallel.mjs} +0 -0
- /package/dist/{typeflow/dist/typeflow-parallel.mjs.map → typeflow-parallel.mjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-webaudio.cjs → typeflow-webaudio.cjs} +0 -0
- /package/dist/{typeflow/dist/typeflow-webaudio.cjs.map → typeflow-webaudio.cjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-webaudio.esm.js → typeflow-webaudio.esm.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-webaudio.esm.js.map → typeflow-webaudio.esm.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-webaudio.esm.min.js → typeflow-webaudio.esm.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-webaudio.esm.min.js.map → typeflow-webaudio.esm.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-webaudio.js → typeflow-webaudio.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-webaudio.js.map → typeflow-webaudio.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-webaudio.min.js → typeflow-webaudio.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow-webaudio.min.js.map → typeflow-webaudio.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow-webaudio.mjs → typeflow-webaudio.mjs} +0 -0
- /package/dist/{typeflow/dist/typeflow-webaudio.mjs.map → typeflow-webaudio.mjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow.cjs.map → typeflow.cjs.map} +0 -0
- /package/dist/{typeflow/dist/typeflow.esm.js.map → typeflow.esm.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow.esm.min.js → typeflow.esm.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow.esm.min.js.map → typeflow.esm.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow.js.map → typeflow.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow.min.js → typeflow.min.js} +0 -0
- /package/dist/{typeflow/dist/typeflow.min.js.map → typeflow.min.js.map} +0 -0
- /package/dist/{typeflow/dist/typeflow.mjs.map → typeflow.mjs.map} +0 -0
package/README.md
CHANGED
|
@@ -1,247 +1,91 @@
|
|
|
1
|
-
<
|
|
1
|
+
<img src="https://gitlab.com/staticcanvas/typeflow/-/raw/develop/branding/typeflow-logo.svg" width="64" height="64" alt="TypeFlow logo" />
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# **@staticcanvas/typeflow**
|
|
4
4
|
|
|
5
|
-
[](https://gitlab.com/staticcanvas/typeflow/-/work_items?sort=created_date&state=opened&first_page_size=20)
|
|
10
|
-
|
|
11
|
-
[](https://gitlab.com/staticcanvas/typeflow/-/releases/permalink/latest)
|
|
12
|
-
[](https://gitlab.com/staticcanvas/typeflow/-/tags)
|
|
13
|
-
|
|
14
|
-
[](https://www.npmjs.com/package/@staticcanvas/typeflow)
|
|
15
|
-
[](https://www.npmjs.com/package/@staticcanvas/typeflow)
|
|
16
|
-
|
|
17
|
-
[](https://jsr.io/%40staticcanvas/typeflow)
|
|
18
|
-
[](https://cdn.jsdelivr.net/package/npm/@staticcanvas/typeflow)
|
|
19
|
-
|
|
20
|
-
[](https://gitlab.com/api/v4/projects/staticcanvas%2Ftypeflow/jobs/artifacts/develop/raw/runtime-badge-flat.svg?job=generate-runtime-badge)
|
|
5
|
+
[](https://www.npmjs.com/package/@staticcanvas/typeflow)
|
|
6
|
+
[](https://jsr.io/%40staticcanvas/typeflow)
|
|
7
|
+
[](https://codecov.io/gl/staticcanvas/typeflow)
|
|
8
|
+
[](https://gitlab.com/staticcanvas/typeflow)
|
|
21
9
|
|
|
22
10
|
> **TypeFlow** is a lightweight, interruptible, framework-agnostic typewriter animation library designed for modern web applications and static sites.
|
|
23
11
|
|
|
24
|
-
|
|
12
|
+
---
|
|
25
13
|
|
|
26
|
-
|
|
27
|
-
|
|
14
|
+
## Highlights
|
|
15
|
+
|
|
16
|
+
- **Zero Dependencies**: Pure ECMAScript with native DOM batching (<7KB gzipped).
|
|
17
|
+
- **Safe HTML**: Parses structured markup without breaking tags or exposing script vectors.
|
|
18
|
+
- **Intl.Segmenter**: International character cluster and compound emoji safety (`🚀`, `👨👩👧👦`).
|
|
19
|
+
- **Multi-Directional Reveals**: Type left-to-right, right-to-left, or middle-outward (`direction: 'center'`).
|
|
20
|
+
- **Directional Erasing**: Backspace (`end`), left-erosion (`start`), inward shrink (`center`), `scramble`, `fade`, or `instant`.
|
|
21
|
+
- **Scramble Charset Presets**: Built-in glyph presets (`matrix`, `blocks`, `ascii`, `ascii-extended`, `binary`, `hex`, `braille`, `runic`, `cyber`).
|
|
22
|
+
- **Procedural Web Audio**: Built-in zero-asset keystrokes (`mechanical`, `beep`, `synth`).
|
|
23
|
+
- **Smart Morph Diffing**: Diff-erases only changed suffixes (`TypeFlow.morph()`).
|
|
24
|
+
- **Real-Time Stream Ingestion**: FIFO chunk stream buffer for LLM token streams (`TypeFlow.stream()`).
|
|
25
|
+
- **Animation Presets**: One-line profiles for common styles (`TypeFlow.preset('cyberpunk')`).
|
|
26
|
+
- **CLS Layout Shift Prevention**: Automatic dimension stabilization (`TypeFlow.fit()`).
|
|
27
|
+
- **Sequence Orchestration**: Coordinate multi-step flows with `seq.type`, `seq.erase`, `seq.pause`, `seq.visible`, and `seq.call`.
|
|
28
|
+
- **Framework Ready**: First-class adapters for React, Vue, Svelte, Solid.js, and Alpine.js, plus native Web Components and Astro client-side integration.
|
|
28
29
|
|
|
29
30
|
---
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
> 🔹 Use the playground [here](https://staticcanvas.gitlab.io/typeflow/playground/)
|
|
33
|
-
|
|
34
|
-
## **Overview**
|
|
35
|
-
|
|
36
|
-
TypeFlow delivers zero-dependency text animation with precise frame control, rich HTML tag preservation, automated sanitization, multi-style bidirectional erasing, sequential step orchestration, and integrations for React, Vue, Svelte, Solid.js, Alpine.js, Astro, and Web Components.
|
|
37
|
-
|
|
38
|
-
<details>
|
|
39
|
-
<summary><strong>📚Table of Contents</strong></summary>
|
|
40
|
-
|
|
41
|
-
- [Overview](#overview)
|
|
42
|
-
- [Features](#features)
|
|
43
|
-
- [Installation](#installation)
|
|
44
|
-
- [NPM](#npm)
|
|
45
|
-
- [JSR](#jsr)
|
|
46
|
-
- [CDN](#cdn)
|
|
47
|
-
- [Usage](#usage)
|
|
48
|
-
- [Basic Typing & Erasing](#basic-typing-erasing)
|
|
49
|
-
- [Multi-Directional Typing & Scramble Charsets](#multi-directional-typing-scramble-charsets)
|
|
50
|
-
- [Smart Morph Diffing](#smart-morph-diffing)
|
|
51
|
-
- [Real-Time LLM Token Streaming](#real-time-llm-token-streaming)
|
|
52
|
-
- [Animation Presets](#animation-presets)
|
|
53
|
-
- [HTML Mode with Sanitization](#html-mode-with-sanitization)
|
|
54
|
-
- [Sequential Multi-Step Orchestration & Viewport Triggers](#sequential-multi-step-orchestration-viewport-triggers)
|
|
55
|
-
- [Framework Adapters](#framework-adapters)
|
|
56
|
-
- [React](#react)
|
|
57
|
-
- [Vue](#vue)
|
|
58
|
-
- [Svelte](#svelte)
|
|
59
|
-
- [Solid.js](#solidjs)
|
|
60
|
-
- [Alpine.js](#alpinejs)
|
|
61
|
-
- [Astro](#astro)
|
|
62
|
-
- [Web Components](#web-components)
|
|
63
|
-
- [Angular](#angular)
|
|
64
|
-
- [Companion Extensions](#companion-extensions)
|
|
65
|
-
- [API Reference](#api-reference)
|
|
66
|
-
- [TypeFlowConfig](#typeflowconfig)
|
|
67
|
-
- [TypeFlowController](#typeflowcontroller)
|
|
68
|
-
- [Core Engine Methods](#core-engine-methods)
|
|
69
|
-
- [Development & NPM Scripts](#development-npm-scripts)
|
|
70
|
-
- [Extending TypeFlow & Developer Guide](#extending-typeflow-developer-guide)
|
|
71
|
-
- [1. Custom Audio Synthesizers & Keystroke Callbacks](#1-custom-audio-synthesizers-keystroke-callbacks)
|
|
72
|
-
- [Experimental Asciiam bridge](#experimental-asciiam-bridge)
|
|
73
|
-
- [2. Custom Scramble Charset & Character Pools](#2-custom-scramble-charset-character-pools)
|
|
74
|
-
- [3. Writing Custom Sequence Step Helpers](#3-writing-custom-sequence-step-helpers)
|
|
75
|
-
- [4. Creating Custom Framework Adapters](#4-creating-custom-framework-adapters)
|
|
76
|
-
- [Benchmarks](#benchmarks)
|
|
77
|
-
- [Synthetic Benchmarks (Node.js and JSDOM)](#synthetic-benchmarks-nodejs-and-jsdom)
|
|
78
|
-
- [Real-browser capacity benchmark](#real-browser-capacity-benchmark)
|
|
79
|
-
- [License](#license)
|
|
80
|
-
|
|
81
|
-
</details>
|
|
82
|
-
|
|
83
|
-
## **Features**
|
|
84
|
-
|
|
85
|
-
- **Zero Runtime Dependencies**: Pure ECMAScript with native DOM batching.
|
|
86
|
-
- **Safe HTML Support**: Parses and types structured markup while keeping HTML tags balanced and sanitized against script injection.
|
|
87
|
-
- **`Intl.Segmenter` Powered**: Accurate grapheme and word segmentation for international character clusters and compound emojis (`🚀`, `👨👩👧👦`).
|
|
88
|
-
- **Multi-Directional Reveals & Erasing**: Type left-to-right, right-to-left, or expand center-outward (`direction: 'center'`). Erase via backspace (`end`), left erosion (`start`), inward shrink (`center`), opacity fade (`fade`), or matrix decrypt (`scramble`).
|
|
89
|
-
- **Spatial Word-Motion Styles**: Layout-stable word reveals and erases — `word-fade`, directional `float-in-top/bottom/left/right`, and depth-scaled `zoom-in-space` — with configurable stagger, distance, and easing.
|
|
90
|
-
- **Scramble Charset Presets**: Built-in glyph presets (`matrix`, `blocks`, `ascii`, `ascii-extended`, `binary`, `hex`, `braille`, `runic`, `cyber`) and custom glyph overrides.
|
|
91
|
-
- **Procedural Web Audio Keystrokes**: Zero-asset procedural audio clicks, terminal pings, and cyber synth sounds (`audio: 'mechanical' | 'beep' | 'synth'`).
|
|
92
|
-
- **Smart Morph Diff Typing**: Computes longest common prefixes and only backspaces changed trailing characters (`TypeFlow.morph()`).
|
|
93
|
-
- **Real-Time Stream Ingestion**: Non-blocking FIFO token stream buffer for LLM / SSE token ingestion (`TypeFlow.stream()`).
|
|
94
|
-
- **Animation Presets**: One-line configuration profiles (`TypeFlow.preset('cyberpunk')`, `'terminal'`, `'writer'`, `'matrix'`, `'blocks'`, `'subtle'`).
|
|
95
|
-
- **CLS Layout Shift Prevention**: Automatic dimension stabilization (`TypeFlow.fit()`) preventing Cumulative Layout Shift during text rotations.
|
|
96
|
-
- **Natural Cadence Punctuation Pacing**: Micro-pauses at commas, colons, and sentence stops (`naturalCadence: true`).
|
|
97
|
-
- **Sequence Orchestration & Viewport Triggers**: Coordinate multi-step animations (`type`, `erase`, `pause`, `visible`, `call`) with `seq.visible()` IntersectionObserver delays.
|
|
98
|
-
- **Rotator Pattern & DOM Watcher**: Built-in helper for cyclic word replacements and automated mutation listeners.
|
|
99
|
-
- **Reduced Motion Compliance**: Respects `prefers-reduced-motion` settings automatically.
|
|
100
|
-
- **Interactive Caret**: Standalone, zero-dependency editable cursor (`Caret()`) — `jump()`/`move()` reposition instantly, `deleteChar()`/`deleteWord()` edit in place, `insert()` types new text at the caret position.
|
|
101
|
-
- **Framework Integrations**: First-class runtime adapters for React (`createTypeFlowReact`), Vue (`createTypeFlowVue`), Svelte (`createTypeFlowSvelte`), Solid.js (`createTypeFlowSolid`), and Alpine.js (`createTypeFlowAlpine`), plus native Web Components and framework-friendly Astro usage.
|
|
102
|
-
|
|
103
|
-
## **Installation**
|
|
104
|
-
|
|
105
|
-
### NPM
|
|
32
|
+
## Installation
|
|
106
33
|
|
|
107
34
|
```bash
|
|
35
|
+
# npm
|
|
108
36
|
npm install @staticcanvas/typeflow
|
|
109
|
-
```
|
|
110
37
|
|
|
111
|
-
|
|
38
|
+
# pnpm
|
|
39
|
+
pnpm add @staticcanvas/typeflow
|
|
112
40
|
|
|
113
|
-
|
|
41
|
+
# JSR
|
|
114
42
|
npx jsr add @staticcanvas/typeflow
|
|
115
43
|
```
|
|
116
44
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
```html
|
|
120
|
-
<!-- UMD (Global window.TypeFlow) -->
|
|
121
|
-
<script src="https://cdn.jsdelivr.net/npm/@staticcanvas/typeflow/dist/typeflow.js"></script>
|
|
122
|
-
|
|
123
|
-
<!-- ESM Module -->
|
|
124
|
-
<script type="module">
|
|
125
|
-
import {
|
|
126
|
-
TypeFlow,
|
|
127
|
-
seq,
|
|
128
|
-
} from 'https://cdn.jsdelivr.net/npm/@staticcanvas/typeflow/dist/typeflow.esm.js';
|
|
129
|
-
</script>
|
|
130
|
-
```
|
|
45
|
+
---
|
|
131
46
|
|
|
132
|
-
##
|
|
47
|
+
## Quickstart
|
|
133
48
|
|
|
134
|
-
###
|
|
49
|
+
### Vanilla JavaScript
|
|
135
50
|
|
|
136
51
|
```javascript
|
|
137
|
-
import { TypeFlow } from '@staticcanvas/typeflow';
|
|
52
|
+
import { TypeFlow, seq } from '@staticcanvas/typeflow';
|
|
138
53
|
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
speed:
|
|
54
|
+
// 1. Basic Typewriter with Natural Cadence & Procedural Audio
|
|
55
|
+
TypeFlow.type('#headline', 'Fast. Resilient. Zero dependencies.', {
|
|
56
|
+
speed: 40,
|
|
142
57
|
naturalCadence: true,
|
|
143
58
|
audio: 'mechanical',
|
|
144
59
|
cursor: '|',
|
|
145
|
-
cursorBlink: true,
|
|
146
|
-
onComplete: (text) => console.log('Typing complete:', text),
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// Erase inward toward center
|
|
150
|
-
TypeFlow.erase('#headline', {
|
|
151
|
-
speed: 20,
|
|
152
|
-
eraseStyle: 'center',
|
|
153
|
-
});
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### Multi-Directional Typing & Scramble Charsets
|
|
157
|
-
|
|
158
|
-
```javascript
|
|
159
|
-
import { TypeFlow } from '@staticcanvas/typeflow';
|
|
160
|
-
|
|
161
|
-
// Expand outward from center with matrix scramble glyphs
|
|
162
|
-
TypeFlow.type('#terminal', 'SYSTEM SECURE: ACCESS GRANTED', {
|
|
163
|
-
direction: 'center',
|
|
164
|
-
typeStyle: 'scramble',
|
|
165
|
-
scrambleCharset: 'matrix',
|
|
166
|
-
scrambleRounds: 2,
|
|
167
|
-
audio: 'synth',
|
|
168
|
-
speed: 35,
|
|
169
60
|
});
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Smart Morph Diffing
|
|
173
|
-
|
|
174
|
-
```javascript
|
|
175
|
-
import { TypeFlow } from '@staticcanvas/typeflow';
|
|
176
|
-
|
|
177
|
-
// Automatically keeps "TypeFlow is " and only erases & replaces the trailing word
|
|
178
|
-
await TypeFlow.type('#headline', 'TypeFlow is fast');
|
|
179
|
-
await TypeFlow.morph('#headline', 'TypeFlow is lightweight');
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### Real-Time LLM Token Streaming
|
|
183
61
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const stream = TypeFlow.stream('#ai-response', { speed: 20, cursor: '|' });
|
|
188
|
-
|
|
189
|
-
// Push incoming SSE / WebSocket chunks seamlessly
|
|
190
|
-
sse.onmessage = (event) => {
|
|
191
|
-
stream.push(event.data);
|
|
192
|
-
};
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### Animation Presets
|
|
196
|
-
|
|
197
|
-
```javascript
|
|
198
|
-
import { TypeFlow } from '@staticcanvas/typeflow';
|
|
199
|
-
|
|
200
|
-
// Cyberpunk scramble decrypt preset
|
|
201
|
-
TypeFlow.type('#cyber', 'NEURAL LINK ESTABLISHED', TypeFlow.preset('cyberpunk'));
|
|
62
|
+
// 2. Scramble / Decrypt Effect with Presets
|
|
63
|
+
TypeFlow.type('#terminal', 'SYSTEM ONLINE', TypeFlow.preset('cyberpunk'));
|
|
202
64
|
|
|
203
|
-
//
|
|
204
|
-
TypeFlow.type('#
|
|
205
|
-
|
|
65
|
+
// 3. Smart Morph Diffing
|
|
66
|
+
await TypeFlow.type('#target', 'Hello World');
|
|
67
|
+
await TypeFlow.morph('#target', 'Hello Universe');
|
|
206
68
|
|
|
207
|
-
|
|
69
|
+
// 4. Real-Time Stream Ingestion
|
|
70
|
+
const stream = TypeFlow.stream('#ai-output', { speed: 15 });
|
|
71
|
+
stream.push('First token chunk ');
|
|
72
|
+
stream.push('Second token chunk');
|
|
208
73
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
'
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
speed: 30,
|
|
218
|
-
allowedTags: ['strong', 'span'],
|
|
219
|
-
allowedAttributes: { span: ['class'] },
|
|
220
|
-
}
|
|
221
|
-
);
|
|
74
|
+
// 5. Sequential Multi-Step Orchestration
|
|
75
|
+
TypeFlow.sequence([
|
|
76
|
+
seq.visible('#step-1'), // Waits until element scrolls into view
|
|
77
|
+
seq.type('#step-1', 'Initializing kernel...'),
|
|
78
|
+
seq.pause(500),
|
|
79
|
+
seq.erase('#step-1', { eraseStyle: 'center' }),
|
|
80
|
+
seq.type('#step-1', 'Kernel active.'),
|
|
81
|
+
]);
|
|
222
82
|
```
|
|
223
83
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
```javascript
|
|
227
|
-
import { TypeFlow, seq } from '@staticcanvas/typeflow';
|
|
228
|
-
|
|
229
|
-
TypeFlow.sequence(
|
|
230
|
-
[
|
|
231
|
-
seq.visible('#step-1'), // Waits until element scrolls into view
|
|
232
|
-
seq.type('#step-1', 'Initializing runtime kernel...'),
|
|
233
|
-
seq.pause(600),
|
|
234
|
-
seq.call(() => console.log('Phase 1 complete')),
|
|
235
|
-
seq.erase('#step-1', { eraseStyle: 'fade', duration: 300 }),
|
|
236
|
-
seq.type('#step-2', 'All systems operational.'),
|
|
237
|
-
],
|
|
238
|
-
{ repeat: 1 }
|
|
239
|
-
);
|
|
240
|
-
```
|
|
84
|
+
---
|
|
241
85
|
|
|
242
|
-
|
|
86
|
+
## Framework Adapters
|
|
243
87
|
|
|
244
|
-
|
|
88
|
+
### React
|
|
245
89
|
|
|
246
90
|
```jsx
|
|
247
91
|
import React from 'react';
|
|
@@ -249,15 +93,13 @@ import { createTypeFlowReact } from '@staticcanvas/typeflow';
|
|
|
249
93
|
|
|
250
94
|
const useTypeFlow = createTypeFlowReact(React);
|
|
251
95
|
|
|
252
|
-
function Headline() {
|
|
253
|
-
const headlineRef = useTypeFlow('
|
|
96
|
+
export function Headline() {
|
|
97
|
+
const headlineRef = useTypeFlow('Modern React Typewriter', { speed: 40 });
|
|
254
98
|
return <h1 ref={headlineRef} />;
|
|
255
99
|
}
|
|
256
100
|
```
|
|
257
101
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
#### Vue
|
|
102
|
+
### Vue
|
|
261
103
|
|
|
262
104
|
```vue
|
|
263
105
|
<script setup>
|
|
@@ -265,18 +107,16 @@ import * as Vue from 'vue';
|
|
|
265
107
|
import { createTypeFlowVue } from '@staticcanvas/typeflow';
|
|
266
108
|
|
|
267
109
|
const useTypeFlow = createTypeFlowVue(Vue);
|
|
268
|
-
const
|
|
269
|
-
const
|
|
110
|
+
const message = Vue.ref('Reactive Typewriter');
|
|
111
|
+
const ref = useTypeFlow(() => message.value, { speed: 45 });
|
|
270
112
|
</script>
|
|
271
113
|
|
|
272
114
|
<template>
|
|
273
|
-
<h1 ref="
|
|
115
|
+
<h1 ref="ref"></h1>
|
|
274
116
|
</template>
|
|
275
117
|
```
|
|
276
118
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
#### Svelte
|
|
119
|
+
### Svelte
|
|
280
120
|
|
|
281
121
|
```svelte
|
|
282
122
|
<script>
|
|
@@ -284,10 +124,10 @@ const headlineRef = useTypeFlow(() => text.value, { speed: 50 });
|
|
|
284
124
|
const typeflow = createTypeFlowSvelte();
|
|
285
125
|
</script>
|
|
286
126
|
|
|
287
|
-
<h1 use:typeflow={{ text: 'Svelte Action
|
|
127
|
+
<h1 use:typeflow={{ text: 'Svelte Action', config: { speed: 40 } }}></h1>
|
|
288
128
|
```
|
|
289
129
|
|
|
290
|
-
|
|
130
|
+
### Solid.js
|
|
291
131
|
|
|
292
132
|
```jsx
|
|
293
133
|
import * as Solid from 'solid-js';
|
|
@@ -296,13 +136,13 @@ import { createTypeFlowSolid } from '@staticcanvas/typeflow';
|
|
|
296
136
|
const useTypeFlow = createTypeFlowSolid(Solid);
|
|
297
137
|
|
|
298
138
|
export function Hero() {
|
|
299
|
-
const [
|
|
300
|
-
const ref = useTypeFlow(
|
|
139
|
+
const [text] = Solid.createSignal('Solid Typography');
|
|
140
|
+
const ref = useTypeFlow(text, { speed: 40 });
|
|
301
141
|
return <h1 ref={ref} />;
|
|
302
142
|
}
|
|
303
143
|
```
|
|
304
144
|
|
|
305
|
-
|
|
145
|
+
### Alpine.js
|
|
306
146
|
|
|
307
147
|
```html
|
|
308
148
|
<script type="module">
|
|
@@ -318,317 +158,71 @@ export function Hero() {
|
|
|
318
158
|
</div>
|
|
319
159
|
```
|
|
320
160
|
|
|
321
|
-
|
|
161
|
+
### Astro and Web Components
|
|
322
162
|
|
|
323
|
-
Astro uses
|
|
163
|
+
Astro uses the browser-native ESM API from a client-side script or client island; it does not need a separate Astro runtime adapter. The native `<type-flow>` custom element is also available when a declarative integration is preferred. See the [framework adapter guide](https://staticcanvas.gitlab.io/typeflow/guides/framework-adapters/) for complete Astro and Web Components examples.
|
|
324
164
|
|
|
325
|
-
```astro
|
|
326
165
|
---
|
|
327
|
-
import { TypeFlow } from '@staticcanvas/typeflow';
|
|
328
|
-
|
|
329
|
-
const text = 'Astro island typography';
|
|
330
|
-
---
|
|
331
|
-
|
|
332
|
-
<h1 id="headline">{text}</h1>
|
|
333
|
-
|
|
334
|
-
<script>
|
|
335
|
-
import { TypeFlow } from '@staticcanvas/typeflow';
|
|
336
|
-
|
|
337
|
-
const target = document.querySelector('#headline');
|
|
338
|
-
if (target) TypeFlow.type(target, target.textContent ?? '', { speed: 40 });
|
|
339
|
-
</script>
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
For an Astro component that must hydrate with the rest of an island, place the DOM animation in a client component or use the native `<type-flow>` element below. TypeFlow does not require an Astro-specific runtime package.
|
|
343
|
-
|
|
344
|
-
#### Web Components
|
|
345
|
-
|
|
346
|
-
```html
|
|
347
|
-
<script type="module">
|
|
348
|
-
import { defineTypeFlowElement } from '@staticcanvas/typeflow';
|
|
349
|
-
defineTypeFlowElement();
|
|
350
|
-
</script>
|
|
351
|
-
|
|
352
|
-
<type-flow text="Framework-neutral custom element" speed="40"></type-flow>
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
#### Angular
|
|
356
|
-
|
|
357
|
-
TypeFlow does not ship an Angular-specific factory. Angular applications can use the core `TypeFlow` API from a small attribute directive and stop the returned controller in `ngOnDestroy`; the documentation site includes a complete directive recipe.
|
|
358
|
-
|
|
359
|
-
## Companion Extensions
|
|
360
166
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
167
|
+
## API Summary
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
// Core Engine
|
|
171
|
+
TypeFlow.type(target, text, config?): TypeFlowController
|
|
172
|
+
TypeFlow.erase(target, config?): TypeFlowController
|
|
173
|
+
TypeFlow.morph(target, nextText, config?): TypeFlowController
|
|
174
|
+
TypeFlow.stream(target, config?): TypeFlowStreamController
|
|
175
|
+
TypeFlow.preset(name, overrides?): TypeFlowConfig
|
|
176
|
+
TypeFlow.fit(target, candidates): void
|
|
177
|
+
TypeFlow.stagger(targets, texts?, config?): TypeFlowController
|
|
178
|
+
TypeFlow.sequence(steps, seqConfig?): TypeFlowController
|
|
179
|
+
TypeFlow.rotate(target, words, config?): TypeFlowController
|
|
180
|
+
TypeFlow.watch(container, selector, callback): { disconnect(): void }
|
|
181
|
+
TypeFlow.stop(target): void
|
|
182
|
+
TypeFlow.stopAll(): void
|
|
183
|
+
TypeFlow.isTyping(target): boolean
|
|
184
|
+
|
|
185
|
+
// Companion Subpaths:
|
|
186
|
+
// @staticcanvas/typeflow/metrics -> TypeFlowMetrics
|
|
187
|
+
// @staticcanvas/typeflow/debug -> TypeFlowDebug
|
|
188
|
+
// @staticcanvas/typeflow/webaudio -> TypeFlowWebAudio, createKeystrokeAudio
|
|
189
|
+
// @staticcanvas/typeflow/keystroke -> TypeFlowKeystroke, calculateKeyDistance
|
|
190
|
+
// @staticcanvas/typeflow/extchars -> TypeFlowExtChars, getExtendedCharset
|
|
385
191
|
```
|
|
386
192
|
|
|
387
|
-
## **API Reference**
|
|
388
|
-
|
|
389
|
-
### `TypeFlowConfig`
|
|
390
|
-
|
|
391
|
-
| Property | Type | Default | Description |
|
|
392
|
-
| :---------------------- | :------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------ | :----------------------------------------------------------------------------- |
|
|
393
|
-
| `speed` | `number` | `50` (type) / `25` (erase) | Milliseconds per character / word unit. |
|
|
394
|
-
| `delay` | `number` | `0` | Delay before animation starts in milliseconds. |
|
|
395
|
-
| `speedVariance` | `number` | `0` | Random variance range in milliseconds per unit. |
|
|
396
|
-
| `naturalCadence` | `boolean` | `false` | Automatic micro-pauses at punctuation (. , ! ?) and word breaks. |
|
|
397
|
-
| `granularity` | `"grapheme" \| "word"` | `"grapheme"` | Unit segmentation mode using `Intl.Segmenter`. |
|
|
398
|
-
| `direction` | `"left" \| "right" \| "center"` | `"left"` | Typing reveal direction (LTR, RTL, center-outward). |
|
|
399
|
-
| `typeStyle` | `"char" \| "word" \| "scramble" \| "fade-trail" \| "word-fade" \| "float-in-*" \| "zoom-in-space"` | `"char"` | Typing reveal style, including stable-layout opacity and spatial word motion. |
|
|
400
|
-
| `wordOrder` | `"left-to-right" \| "right-to-left" \| "random"` | `"left-to-right"` | Word reveal or erase order without changing the element's bidi direction. |
|
|
401
|
-
| `wordLayout` | `"opacity" \| "placeholder"` | `"opacity"` | Stable word layout strategy used by `word-fade`. |
|
|
402
|
-
| `wordFadeDuration` | `number` | `280` | Opacity transition duration for each word in milliseconds. |
|
|
403
|
-
| `wordStagger` | `number` | Current `speed` | Delay between consecutive word transitions. |
|
|
404
|
-
| `wordSeed` | `string \| number` | `undefined` | Reproducible shuffle seed when `wordOrder` is `"random"`. |
|
|
405
|
-
| `wordMotionDistance` | `number` | `24` | Translate distance in pixels for `float-in-*` word-motion styles. |
|
|
406
|
-
| `wordMotionDepth` | `number` | `160` | `translateZ` depth in pixels for the `zoom-in-space` word-motion style. |
|
|
407
|
-
| `wordMotionScale` | `number` | `0.82` | Starting scale (0-1) for the `zoom-in-space` word-motion style. |
|
|
408
|
-
| `wordMotionPerspective` | `number` | `600` | CSS `perspective` in pixels applied to the target element for `zoom-in-space`. |
|
|
409
|
-
| `wordMotionEasing` | `string` | `"ease"` | CSS timing function for `float-in-*` and `zoom-in-space` word transitions. |
|
|
410
|
-
| `trailFade` | `number \| boolean` | `undefined` | Soft trailing opacity gradient length in characters (e.g. `3` or `4`). |
|
|
411
|
-
| `trailMinOpacity` | `number` | `0.18` | Lowest opacity used by characters in the trailing fade. |
|
|
412
|
-
| `scrambleCharset` | `"matrix" \| "ascii" \| "ascii-extended" \| "blocks" \| "binary" \| "hex" \| "braille" \| "runic" \| "cyber"` | `undefined` | Built-in scramble glyph charset preset. |
|
|
413
|
-
| `scrambleGlyphs` | `string` | `"!<>-_\\/[]{}—=+*^?#________"` | Custom character pool used during scramble reveals. |
|
|
414
|
-
| `scrambleRounds` | `number` | `2` | Number of glyph iterations per character. |
|
|
415
|
-
| `scrambleColor` | `string` | `undefined` | CSS color applied to the active scramble glyph. |
|
|
416
|
-
| `scrambleGradient` | `string` | `undefined` | CSS gradient applied to the active scramble glyph; overrides `scrambleColor`. |
|
|
417
|
-
| `audio` | `"mechanical" \| "beep" \| "synth" \| boolean \| (() => void)` | `undefined` | Procedural Web Audio synthesized keystrokes or audio callback. |
|
|
418
|
-
| `cursor` | `string` | `"\|"` | Cursor character appended during animation. Set to `""` to disable. |
|
|
419
|
-
| `cursorBlink` | `boolean` | `true` | Enables post-completion cursor blinking. |
|
|
420
|
-
| `html` | `boolean` | `false` | Enables sanitized HTML parsing mode. |
|
|
421
|
-
| `mode` | `"replace" \| "append"` | `"replace"` | Clears target or appends to existing DOM child nodes. |
|
|
422
|
-
| `allowedTags` | `string[]` | Default allowlist | Array of permitted HTML tag names. |
|
|
423
|
-
| `allowedAttributes` | `Record<string, string[]>` | Default map | Map of allowed attributes per HTML tag. |
|
|
424
|
-
| `sanitizer` | `(html: string) => string` | `undefined` | Custom sanitizer function overriding default sanitizer. |
|
|
425
|
-
| `respectReducedMotion` | `boolean` | `true` | Instantly completes animation when reduced motion is preferred. |
|
|
426
|
-
| `ariaLive` | `"off" \| "polite" \| "assertive"` | `undefined` | ARIA live region policy applied to target element. |
|
|
427
|
-
| `eraseStyle` | `"end" \| "start" \| "center" \| "scramble" \| "fade-trail" \| "instant" \| "fade" \| "word-fade" \| "float-in-*" \| "zoom-in-space"` | `"end"` | Erase direction or visual transition mode. |
|
|
428
|
-
| `duration` | `number` | `250` | Transition duration in ms when `eraseStyle: "fade"`. |
|
|
429
|
-
| `preserveBaseline` | `boolean` | `true` | Preserves base content when erasing `append` mode elements. |
|
|
430
|
-
| `onStart` | `() => void` | `undefined` | Callback invoked when animation begins. |
|
|
431
|
-
| `onComplete` | `(text: string) => void` | `undefined` | Callback invoked upon animation completion. |
|
|
432
|
-
| `onInterrupt` | `() => void` | `undefined` | Callback invoked when controller is aborted before completion. |
|
|
433
|
-
|
|
434
|
-
### `TypeFlowController`
|
|
435
|
-
|
|
436
|
-
| Method / Property | Type | Description |
|
|
437
|
-
| :---------------- | :------------------------ | :---------------------------------------------------------------------------- |
|
|
438
|
-
| `stop()` | `() => void` | Immediately terminates the active animation without rejecting promises. |
|
|
439
|
-
| `promise` | `Promise<TypeFlowResult>` | Resolves with `{ completed: boolean, text: string }` upon completion or stop. |
|
|
440
|
-
|
|
441
|
-
### Core Engine Methods
|
|
442
|
-
|
|
443
|
-
| Method | Parameters | Returns | Description |
|
|
444
|
-
| :-------------------- | :-------------------------- | :--------------------------- | :----------------------------------------------------------------- |
|
|
445
|
-
| `TypeFlow.type()` | `target, text, config?` | `TypeFlowController` | Types text or sanitized HTML into target element. |
|
|
446
|
-
| `TypeFlow.erase()` | `target, config?` | `TypeFlowController` | Erases content from target element. |
|
|
447
|
-
| `TypeFlow.morph()` | `target, nextText, config?` | `TypeFlowController` | Smart diff typing: erases mismatched suffix and types new text. |
|
|
448
|
-
| `TypeFlow.stream()` | `target, config?` | `TypeFlowStreamController` | Creates a real-time FIFO chunk ingestion stream controller. |
|
|
449
|
-
| `TypeFlow.preset()` | `name, overrides?` | `TypeFlowConfig` | Returns pre-configured profile options for common animation types. |
|
|
450
|
-
| `TypeFlow.fit()` | `target, candidates` | `void` | Measures candidate phrases and locks min-width to prevent CLS. |
|
|
451
|
-
| `TypeFlow.stagger()` | `targets, texts?, config?` | `TypeFlowController` | Staggers typing across multiple elements with offset delays. |
|
|
452
|
-
| `TypeFlow.sequence()` | `steps, seqConfig?` | `TypeFlowController` | Executes an array of animation steps sequentially. |
|
|
453
|
-
| `TypeFlow.rotate()` | `target, words, config?` | `TypeFlowController` | Cycles through an array of strings in a loop. |
|
|
454
|
-
| `TypeFlow.watch()` | `container, selector, cb` | `{ disconnect: () => void }` | Observes and animates dynamically added DOM nodes. |
|
|
455
|
-
| `TypeFlow.stop()` | `target` | `void` | Stops the active animation and cursor timer for a target. |
|
|
456
|
-
| `TypeFlow.stopAll()` | `none` | `void` | Stops all currently active TypeFlow instances and timers. |
|
|
457
|
-
| `TypeFlow.isTyping()` | `target` | `boolean` | Returns active animation status for a target element. |
|
|
458
|
-
|
|
459
193
|
---
|
|
460
194
|
|
|
461
|
-
##
|
|
462
|
-
|
|
463
|
-
TypeFlow provides a full suite of NPM scripts for local development, automated testing, synthetic benchmarking, bundle validation, and documentation generation:
|
|
464
|
-
|
|
465
|
-
| Script | Command | Description |
|
|
466
|
-
| :----------------------------------------- | :------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------- |
|
|
467
|
-
| **`npm run dev`** | `vite` | Starts the local Vite development server for rapid iteration. |
|
|
468
|
-
| **`npm run build`** | `vite build` | Compiles production ESM, CJS, and UMD bundles into `dist/`. |
|
|
469
|
-
| **`npm test`** | `vitest run` | Runs the full Vitest unit test suite. |
|
|
470
|
-
| **`npm run test:coverage`** | `vitest run --coverage` | Executes tests with V8 code coverage report. |
|
|
471
|
-
| **`npm run benchmark`** | `node --expose-gc scripts/run-benchmark.mjs` | Runs the repeated 10k, 50k, 100k, and concurrency-tier synthetic suite. |
|
|
472
|
-
| **`npm run benchmark:quick`** | `node --expose-gc scripts/run-benchmark.mjs --quick` | Runs three samples over a reduced concurrency matrix. |
|
|
473
|
-
| **`npm run benchmark:md`** | `node --expose-gc scripts/run-benchmark.mjs --markdown` | Generates a Markdown result table. |
|
|
474
|
-
| **`npm run benchmark:json`** | `node --expose-gc scripts/run-benchmark.mjs --json` | Generates the benchmark report as JSON. |
|
|
475
|
-
| **`npm run benchmark:browser`** | Playwright Chromium + Firefox | Generates real-browser capacity JSON and Markdown with frame, heap, DOM, long-task, and leak metrics. |
|
|
476
|
-
| **`npm run benchmark:browser:quick`** | Reduced Playwright tier matrix | Regenerates a fast local browser benchmark sample. |
|
|
477
|
-
| **`npm run check:size`** | `node scripts/check-bundle-size.mjs` | Verifies the core bundle against the 10 KiB gzip budget. |
|
|
478
|
-
| **`npm run validate:docs-data`** | `node scripts/validate-doc-data.mjs` | Validates documentation splash data against its schema. |
|
|
479
|
-
| **`npm run check:quality`** | `npm run validate:docs-data && npm run build && npm run check:size && npm test` | Runs deterministic release quality checks. |
|
|
480
|
-
| **`npm run docs:build`** | `npm run build && hugo --source docs` | Compiles the static documentation and playground website into `public/`. |
|
|
481
|
-
| **`npm run release:docs:preview`** | Rivet release-document dry run | Previews generated release notes and Hugo changelog data from the latest reachable stable tag. |
|
|
482
|
-
| **`npm run release:docs`** | Rivet release-document sync | Updates `CHANGELOG.md`, `release-notes.md`, and `docs/data/changelog.json`; requires Rivet at `./rivet`. |
|
|
483
|
-
| **`npm run release:docs:rebuild:preview`** | Rivet history dry run | Previews a complete release-history rebuild across reachable tags. |
|
|
484
|
-
| **`npm run release:docs:rebuild`** | Rivet history sync | Rebuilds the canonical changelog and generated Hugo projection across all reachable tags. |
|
|
485
|
-
| **`npm run docs:serve`** | `npm run build && hugo server --source docs...` | Launches local live-reloading Hugo documentation server. |
|
|
486
|
-
| **`npm run lint`** | `eslint .` | Validates codebase with ESLint. |
|
|
487
|
-
| **`npm run lint:fix`** | `eslint . --fix` | Automatically resolves fixable lint issues. |
|
|
488
|
-
| **`npm run format`** | `prettier --write .` | Formats all source files with Prettier. |
|
|
489
|
-
|
|
490
|
-
---
|
|
491
|
-
|
|
492
|
-
## **Extending TypeFlow & Developer Guide**
|
|
493
|
-
|
|
494
|
-
### 1. Custom Audio Synthesizers & Keystroke Callbacks
|
|
495
|
-
|
|
496
|
-
You can provide custom audio callbacks to `audio` or connect external audio engines (Tone.js, Howler.js, or Web Audio API `AudioContext`):
|
|
497
|
-
|
|
498
|
-
```javascript
|
|
499
|
-
import { TypeFlow } from '@staticcanvas/typeflow';
|
|
500
|
-
|
|
501
|
-
const ctx = new AudioContext();
|
|
502
|
-
|
|
503
|
-
function playCustomBlip() {
|
|
504
|
-
const osc = ctx.createOscillator();
|
|
505
|
-
const gain = ctx.createGain();
|
|
506
|
-
osc.type = 'triangle';
|
|
507
|
-
osc.frequency.setValueAtTime(440, ctx.currentTime);
|
|
508
|
-
gain.gain.setValueAtTime(0.08, ctx.currentTime);
|
|
509
|
-
gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.04);
|
|
510
|
-
osc.connect(gain);
|
|
511
|
-
gain.connect(ctx.destination);
|
|
512
|
-
osc.start();
|
|
513
|
-
osc.stop(ctx.currentTime + 0.04);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
TypeFlow.type('#headline', 'Custom Synthesized Audio', {
|
|
517
|
-
audio: playCustomBlip,
|
|
518
|
-
speed: 40,
|
|
519
|
-
});
|
|
520
|
-
```
|
|
521
|
-
|
|
522
|
-
#### Experimental Asciiam bridge
|
|
523
|
-
|
|
524
|
-
An Asciiam adapter is being explored as a separate, opt-in integration. The
|
|
525
|
-
adapter would translate TypeFlow's unrestricted `audio` callback into small,
|
|
526
|
-
library-neutral keystroke events that Asciiam can consume and render on its
|
|
527
|
-
canvas. TypeFlow remains responsible only for text animation and event timing;
|
|
528
|
-
Asciiam remains responsible for audio visualization and canvas rendering.
|
|
529
|
-
|
|
530
|
-
This bridge is experimental, is not part of the stable TypeFlow API, and is
|
|
531
|
-
intentionally kept out of the documentation site until the event contract is
|
|
532
|
-
implemented and versioned. Neither library will require the other.
|
|
533
|
-
|
|
534
|
-
### 2. Custom Scramble Charset & Character Pools
|
|
195
|
+
## Development & NPM Scripts
|
|
535
196
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
speed: 45,
|
|
546
|
-
});
|
|
547
|
-
```
|
|
548
|
-
|
|
549
|
-
### 3. Writing Custom Sequence Step Helpers
|
|
550
|
-
|
|
551
|
-
Sequence steps in `TypeFlow.sequence` are plain JavaScript objects containing an `execute(runner)` function or one of the built-in step definitions:
|
|
552
|
-
|
|
553
|
-
```javascript
|
|
554
|
-
import { TypeFlow, seq } from '@staticcanvas/typeflow';
|
|
555
|
-
|
|
556
|
-
// Custom async step that fetches dynamic data before continuing sequence
|
|
557
|
-
const fetchStep = {
|
|
558
|
-
type: 'custom-fetch',
|
|
559
|
-
execute: async () => {
|
|
560
|
-
const res = await fetch('/api/status');
|
|
561
|
-
const data = await res.json();
|
|
562
|
-
console.log('Dynamic status:', data);
|
|
563
|
-
},
|
|
564
|
-
};
|
|
565
|
-
|
|
566
|
-
TypeFlow.sequence([
|
|
567
|
-
seq.type('#status', 'Checking server health...'),
|
|
568
|
-
seq.pause(400),
|
|
569
|
-
fetchStep,
|
|
570
|
-
seq.erase('#status', { eraseStyle: 'fade' }),
|
|
571
|
-
seq.type('#status', 'All systems green.'),
|
|
572
|
-
]);
|
|
573
|
-
```
|
|
574
|
-
|
|
575
|
-
### 4. Creating Custom Framework Adapters
|
|
576
|
-
|
|
577
|
-
TypeFlow exports a framework-agnostic engine. You can create custom adapters for any component library using its lifecycle hooks:
|
|
578
|
-
|
|
579
|
-
```javascript
|
|
580
|
-
import { TypeFlow } from '@staticcanvas/typeflow';
|
|
581
|
-
|
|
582
|
-
export function createTypeFlowCustomHook(useRef, useEffect) {
|
|
583
|
-
return function useTypeFlow(text, config = {}) {
|
|
584
|
-
const ref = useRef(null);
|
|
585
|
-
useEffect(() => {
|
|
586
|
-
if (!ref.current) return;
|
|
587
|
-
const controller = TypeFlow.type(ref.current, text, config);
|
|
588
|
-
return () => controller.stop();
|
|
589
|
-
}, [text]);
|
|
590
|
-
return ref;
|
|
591
|
-
};
|
|
592
|
-
}
|
|
593
|
-
```
|
|
197
|
+
| Script | Command | Description |
|
|
198
|
+
| :-------------------------- | :--------------------------------------------------------------------- | :---------------------------------------------------------- |
|
|
199
|
+
| **`npm run dev`** | `vite` | Starts local Vite development server. |
|
|
200
|
+
| **`npm run build`** | `vite build` | Compiles production ESM, CJS, and UMD bundles into `dist/`. |
|
|
201
|
+
| **`npm test`** | `vitest run` | Runs the full unit test suite. |
|
|
202
|
+
| **`npm run benchmark`** | `node --expose-gc scripts/run-benchmark.mjs` | Runs repeated 10k, 50k, 100k, and concurrency benchmarks. |
|
|
203
|
+
| **`npm run benchmark:md`** | `node --expose-gc scripts/run-benchmark.mjs --markdown` | Generates a Markdown benchmark table. |
|
|
204
|
+
| **`npm run benchmark:json`**| `node --expose-gc scripts/run-benchmark.mjs --json` | Generates machine-readable benchmark data. |
|
|
205
|
+
| **`npm run check:quality`** | `npm run validate:docs-data && npm run build && npm run check:size && npm test` | Runs deterministic release checks. |
|
|
594
206
|
|
|
595
207
|
---
|
|
596
208
|
|
|
597
|
-
##
|
|
598
|
-
|
|
599
|
-
TypeFlow is engineered with pre-compiled token caching and direct DOM window slicing, delivering sub-millisecond execution speeds even under 10,000+ character payloads.
|
|
600
|
-
|
|
601
|
-
### Synthetic Benchmarks (Node.js and JSDOM)
|
|
602
|
-
|
|
603
|
-
The synthetic suite measures engine completion time and heap deltas. Each scenario runs warm-up iterations followed by seven measured samples and reports minimum, median, p95, maximum, and standard deviation. It covers:
|
|
209
|
+
## Benchmarks
|
|
604
210
|
|
|
605
|
-
- 10,000, 50,000, and 100,000
|
|
606
|
-
- word segmentation, safe nested-HTML parsing, morphing, and instant erasing at each character tier;
|
|
607
|
-
- 1, 10, 25, 50, 100, 250, 500, and 1,000 concurrent short instances;
|
|
608
|
-
- raw and gzip production bundle size; and
|
|
609
|
-
- Node, JSDOM, operating system, processor, sample, garbage-collection, and commit metadata.
|
|
211
|
+
The JSDOM suite uses warm-up rounds and seven measured samples at 10,000, 50,000, and 100,000 characters. It reports minimum, median, p95, maximum, standard deviation, and heap delta for plain text, word segmentation, safe HTML, morph, and instant erase operations. It also measures 1–1,000 concurrent short instances.
|
|
610
212
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
Run the suite with formatted Markdown output:
|
|
213
|
+
These synthetic results do not measure browser layout, paint, frame rate, long tasks, or GPU composition and therefore do not define a supported browser instance limit.
|
|
614
214
|
|
|
615
215
|
```bash
|
|
616
216
|
npm run benchmark:md
|
|
617
|
-
```
|
|
618
|
-
|
|
619
|
-
Generate JSON without npm's command banner when piping the result:
|
|
620
|
-
|
|
621
|
-
```bash
|
|
622
217
|
npm run --silent benchmark:json > typeflow-benchmark.json
|
|
623
218
|
```
|
|
624
219
|
|
|
625
|
-
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Documentation
|
|
626
223
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
and a [generated report](benchmarks/results/browser-capacity.md), including the
|
|
630
|
-
machine/browser environment and the exact capacity budgets. Metrics unavailable
|
|
631
|
-
in a browser remain `null`; they are never inferred from JSDOM or another engine.
|
|
224
|
+
Full interactive documentation, API specifications, and live workbench:
|
|
225
|
+
👉 **[https://staticcanvas.gitlab.io/typeflow](https://staticcanvas.gitlab.io/typeflow)**
|
|
632
226
|
|
|
633
227
|
---
|
|
634
228
|
|