hyperframes 0.2.2 → 0.2.3-alpha.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.
Files changed (54) hide show
  1. package/dist/cli.js +7926 -7426
  2. package/dist/skills/gsap/SKILL.md +222 -0
  3. package/dist/skills/gsap/references/effects.md +304 -0
  4. package/dist/skills/gsap/references/frameworks.md +56 -0
  5. package/dist/skills/gsap/references/plugins.md +194 -0
  6. package/dist/skills/gsap/references/react.md +80 -0
  7. package/dist/skills/gsap/references/scrolltrigger.md +147 -0
  8. package/dist/skills/gsap/references/utils.md +91 -0
  9. package/dist/skills/gsap/scripts/extract-audio-data.py +188 -0
  10. package/dist/skills/{hyperframes-compose → hyperframes}/SKILL.md +43 -43
  11. package/dist/skills/hyperframes/references/audio-reactive.md +76 -0
  12. package/dist/skills/hyperframes/references/captions.md +132 -0
  13. package/dist/skills/hyperframes/references/css-patterns.md +371 -0
  14. package/dist/skills/hyperframes/references/examples.md +146 -0
  15. package/dist/skills/hyperframes/references/marker-highlight.md +158 -0
  16. package/dist/skills/hyperframes/references/transitions/catalog.md +132 -0
  17. package/dist/skills/hyperframes/references/transitions/css-3d.md +12 -0
  18. package/dist/skills/hyperframes/references/transitions/css-blur.md +51 -0
  19. package/dist/skills/hyperframes/references/transitions/css-cover.md +43 -0
  20. package/dist/skills/hyperframes/references/transitions/css-destruction.md +95 -0
  21. package/dist/skills/hyperframes/references/transitions/css-dissolve.md +66 -0
  22. package/dist/skills/hyperframes/references/transitions/css-distortion.md +45 -0
  23. package/dist/skills/hyperframes/references/transitions/css-grid.md +10 -0
  24. package/dist/skills/hyperframes/references/transitions/css-light.md +49 -0
  25. package/dist/skills/hyperframes/references/transitions/css-mechanical.md +30 -0
  26. package/dist/skills/hyperframes/references/transitions/css-other.md +36 -0
  27. package/dist/skills/hyperframes/references/transitions/css-push.md +41 -0
  28. package/dist/skills/hyperframes/references/transitions/css-radial.md +37 -0
  29. package/dist/skills/hyperframes/references/transitions/css-scale.md +24 -0
  30. package/dist/skills/hyperframes/references/transitions/shader-setup.md +463 -0
  31. package/dist/skills/hyperframes/references/transitions/shader-transitions.md +329 -0
  32. package/dist/skills/hyperframes/references/transitions.md +96 -0
  33. package/dist/skills/hyperframes/references/tts.md +56 -0
  34. package/dist/skills/hyperframes-cli/SKILL.md +114 -0
  35. package/dist/templates/_shared/CLAUDE.md +5 -7
  36. package/dist/templates/blank/index.html +8 -10
  37. package/package.json +2 -4
  38. package/dist/skills/hyperframes-captions/SKILL.md +0 -212
  39. package/dist/skills/hyperframes-tts/SKILL.md +0 -79
  40. package/dist/templates/blank/compositions/captions.html +0 -95
  41. /package/dist/skills/{hyperframes-compose → hyperframes}/data-in-motion.md +0 -0
  42. /package/dist/skills/{hyperframes-compose → hyperframes}/house-style.md +0 -0
  43. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/bold-energetic.md +0 -0
  44. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/clean-corporate.md +0 -0
  45. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/dark-premium.md +0 -0
  46. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/jewel-rich.md +0 -0
  47. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/monochrome.md +0 -0
  48. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/nature-earth.md +0 -0
  49. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/neon-electric.md +0 -0
  50. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/pastel-soft.md +0 -0
  51. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/warm-editorial.md +0 -0
  52. /package/dist/skills/{hyperframes-compose → hyperframes}/patterns.md +0 -0
  53. /package/dist/skills/{hyperframes-captions → hyperframes/references}/dynamic-techniques.md +0 -0
  54. /package/dist/skills/{hyperframes-captions → hyperframes/references}/transcript-guide.md +0 -0
@@ -0,0 +1,371 @@
1
+ # CSS Patterns for Marker Highlighting
2
+
3
+ Pure CSS + GSAP implementations of all five MarkerHighlight.js drawing modes. Use these for deterministic rendering in HyperFrames compositions — no external library dependency, full GSAP timeline control.
4
+
5
+ ## Table of Contents
6
+
7
+ - [1. Highlight Mode](#1-highlight-mode) — Yellow marker sweep behind text
8
+ - [2. Circle Mode](#2-circle-mode) — Hand-drawn ellipse around text
9
+ - [3. Burst Mode](#3-burst-mode) — Radiating lines from text
10
+ - [4. Scribble Mode](#4-scribble-mode) — Chaotic scribble over text
11
+ - [5. Sketchout Mode](#5-sketchout-mode) — Rough rectangle outline
12
+
13
+ ## 1. Highlight Mode
14
+
15
+ Yellow marker sweep behind text. The most common mode.
16
+
17
+ ```html
18
+ <div class="mh-highlight-wrap">
19
+ <div class="mh-highlight-bar" id="hl-1"></div>
20
+ <span class="mh-highlight-text">highlighted text</span>
21
+ </div>
22
+ ```
23
+
24
+ ```css
25
+ .mh-highlight-wrap {
26
+ position: relative;
27
+ display: inline-block;
28
+ }
29
+ .mh-highlight-bar {
30
+ position: absolute;
31
+ top: 0;
32
+ left: -6px;
33
+ right: -6px;
34
+ bottom: 0;
35
+ background: #fdd835;
36
+ opacity: 0.35;
37
+ transform: scaleX(0);
38
+ transform-origin: left center;
39
+ border-radius: 3px;
40
+ z-index: 0;
41
+ }
42
+ .mh-highlight-text {
43
+ position: relative;
44
+ z-index: 1;
45
+ }
46
+ ```
47
+
48
+ ```js
49
+ // Sweep in from left
50
+ tl.to("#hl-1", { scaleX: 1, duration: 0.5, ease: "power2.out" }, 0.6);
51
+
52
+ // Optional: skew for hand-drawn feel
53
+ // gsap.set("#hl-1", { skewX: -2 });
54
+ ```
55
+
56
+ ### Multi-line Highlight
57
+
58
+ Stagger bars across multiple lines:
59
+
60
+ ```js
61
+ tl.to(
62
+ ".mh-highlight-bar",
63
+ {
64
+ scaleX: 1,
65
+ duration: 0.5,
66
+ ease: "power2.out",
67
+ stagger: 0.3,
68
+ },
69
+ 0.6,
70
+ );
71
+ ```
72
+
73
+ ## 2. Circle Mode
74
+
75
+ Hand-drawn circle around text. Use `border-radius: 50%` with a slight rotation for organic feel.
76
+
77
+ ```html
78
+ <div class="mh-circle-wrap">
79
+ <span class="mh-circle-text" id="circle-word">IMPORTANT</span>
80
+ <div class="mh-circle-ring" id="circle-1"></div>
81
+ </div>
82
+ ```
83
+
84
+ ```css
85
+ .mh-circle-wrap {
86
+ position: relative;
87
+ display: inline-block;
88
+ }
89
+ .mh-circle-text {
90
+ position: relative;
91
+ z-index: 1;
92
+ }
93
+ .mh-circle-ring {
94
+ position: absolute;
95
+ top: 50%;
96
+ left: 50%;
97
+ width: 130%;
98
+ height: 160%;
99
+ transform: translate(-50%, -50%) rotate(-3deg) scale(0);
100
+ border: 3px solid #e53935;
101
+ border-radius: 50%;
102
+ pointer-events: none;
103
+ z-index: 0;
104
+ }
105
+ ```
106
+
107
+ ```js
108
+ // Circle scales in with a wobble
109
+ tl.to(
110
+ "#circle-1",
111
+ {
112
+ scale: 1,
113
+ rotation: -3,
114
+ duration: 0.6,
115
+ ease: "back.out(1.7)",
116
+ transformOrigin: "center center",
117
+ },
118
+ 0.7,
119
+ );
120
+ ```
121
+
122
+ ### Variations
123
+
124
+ ```css
125
+ /* Tighter circle (for short words) */
126
+ .mh-circle-ring.tight {
127
+ width: 150%;
128
+ height: 180%;
129
+ }
130
+
131
+ /* Squared circle (rounded rectangle) */
132
+ .mh-circle-ring.rounded {
133
+ border-radius: 30%;
134
+ width: 120%;
135
+ height: 140%;
136
+ }
137
+
138
+ /* Ellipse (wider than tall) */
139
+ .mh-circle-ring.ellipse {
140
+ width: 150%;
141
+ height: 130%;
142
+ border-radius: 50%;
143
+ }
144
+ ```
145
+
146
+ ## 3. Burst Mode
147
+
148
+ Radiating lines from text center. Each line is a positioned div rotated to its angle.
149
+
150
+ ```html
151
+ <div class="mh-burst-wrap">
152
+ <span class="mh-burst-text">WOW</span>
153
+ <div class="mh-burst-container" id="burst-1">
154
+ <div class="mh-burst-line" style="--angle: 0deg; --len: 70px;"></div>
155
+ <div class="mh-burst-line" style="--angle: 30deg; --len: 55px;"></div>
156
+ <div class="mh-burst-line" style="--angle: 60deg; --len: 80px;"></div>
157
+ <div class="mh-burst-line" style="--angle: 90deg; --len: 45px;"></div>
158
+ <div class="mh-burst-line" style="--angle: 120deg; --len: 65px;"></div>
159
+ <div class="mh-burst-line" style="--angle: 150deg; --len: 75px;"></div>
160
+ <div class="mh-burst-line" style="--angle: 180deg; --len: 50px;"></div>
161
+ <div class="mh-burst-line" style="--angle: 210deg; --len: 60px;"></div>
162
+ <div class="mh-burst-line" style="--angle: 240deg; --len: 80px;"></div>
163
+ <div class="mh-burst-line" style="--angle: 270deg; --len: 40px;"></div>
164
+ <div class="mh-burst-line" style="--angle: 300deg; --len: 70px;"></div>
165
+ <div class="mh-burst-line" style="--angle: 330deg; --len: 55px;"></div>
166
+ </div>
167
+ </div>
168
+ ```
169
+
170
+ ```css
171
+ .mh-burst-wrap {
172
+ position: relative;
173
+ display: inline-block;
174
+ }
175
+ .mh-burst-text {
176
+ position: relative;
177
+ z-index: 2;
178
+ }
179
+ .mh-burst-container {
180
+ position: absolute;
181
+ top: 50%;
182
+ left: 50%;
183
+ width: 0;
184
+ height: 0;
185
+ z-index: 1;
186
+ }
187
+ .mh-burst-line {
188
+ position: absolute;
189
+ width: 3px;
190
+ height: var(--len);
191
+ background: #1e88e5;
192
+ left: -1.5px;
193
+ top: calc(-1 * var(--len));
194
+ transform: rotate(var(--angle));
195
+ transform-origin: bottom center;
196
+ opacity: 0;
197
+ }
198
+ ```
199
+
200
+ ```js
201
+ // All lines burst outward simultaneously with slight stagger
202
+ tl.fromTo(
203
+ "#burst-1 .mh-burst-line",
204
+ { scaleY: 0, opacity: 0 },
205
+ { scaleY: 1, opacity: 1, duration: 0.4, ease: "power2.out", stagger: 0.03 },
206
+ 0.7,
207
+ );
208
+ ```
209
+
210
+ **Vary line lengths** (40-80px range) for an organic, hand-drawn feel. Equal lengths look mechanical.
211
+
212
+ ## 4. Scribble Mode
213
+
214
+ Wavy SVG underlines and strikethroughs that draw themselves via `stroke-dashoffset`.
215
+
216
+ ```html
217
+ <div class="mh-scribble-wrap">
218
+ <span class="mh-scribble-text">underlined text</span>
219
+ <svg class="mh-scribble-svg" viewBox="0 0 500 24" preserveAspectRatio="none">
220
+ <path
221
+ id="scribble-1"
222
+ d="M0,12 Q31,0 62,12 Q93,24 125,12 Q156,0 187,12 Q218,24 250,12 Q281,0 312,12 Q343,24 375,12 Q406,0 437,12 Q468,24 500,12"
223
+ fill="none"
224
+ stroke="#FDD835"
225
+ stroke-width="3"
226
+ stroke-linecap="round"
227
+ />
228
+ </svg>
229
+ </div>
230
+ ```
231
+
232
+ ```css
233
+ .mh-scribble-wrap {
234
+ position: relative;
235
+ display: inline-block;
236
+ }
237
+ .mh-scribble-text {
238
+ position: relative;
239
+ z-index: 1;
240
+ }
241
+ .mh-scribble-svg {
242
+ position: absolute;
243
+ left: 0;
244
+ bottom: -6px;
245
+ width: 100%;
246
+ height: 24px;
247
+ z-index: 0;
248
+ }
249
+ ```
250
+
251
+ ```js
252
+ // Measure path length and set initial dash state
253
+ var path = document.querySelector("#scribble-1");
254
+ var len = path.getTotalLength();
255
+ gsap.set(path, { strokeDasharray: len, strokeDashoffset: len });
256
+
257
+ // Draw the line
258
+ tl.to(
259
+ "#scribble-1",
260
+ {
261
+ strokeDashoffset: 0,
262
+ duration: 0.8,
263
+ ease: "power1.inOut",
264
+ },
265
+ 0.7,
266
+ );
267
+ ```
268
+
269
+ ### Strikethrough Variant
270
+
271
+ Position the SVG at `top: 50%; transform: translateY(-50%)` instead of `bottom: -6px`.
272
+
273
+ ### Wavy Path Generator
274
+
275
+ Scale the path's viewBox width to match text width. The wave pattern `Q x1,y1 x2,y2` alternates between `y=0` and `y=24` for a natural wobble. Adjust the control points for tighter or looser waves:
276
+
277
+ - **Tight waves**: smaller x-increments (25px per half-wave)
278
+ - **Loose waves**: larger x-increments (50px per half-wave)
279
+ - **Amplitude**: change the y range (0-24 for standard, 0-16 for subtle)
280
+
281
+ ## 5. Sketchout Mode
282
+
283
+ Cross-hatch lines over de-emphasized text. Multiple angled lines create a "crossed out" effect.
284
+
285
+ ```html
286
+ <div class="mh-sketchout-wrap">
287
+ <span class="mh-sketchout-text">old price</span>
288
+ <div class="mh-sketchout-lines" id="sketchout-1">
289
+ <div class="mh-sketchout-line mh-sketchout-fwd"></div>
290
+ <div class="mh-sketchout-line mh-sketchout-bwd"></div>
291
+ </div>
292
+ </div>
293
+ ```
294
+
295
+ ```css
296
+ .mh-sketchout-wrap {
297
+ position: relative;
298
+ display: inline-block;
299
+ }
300
+ .mh-sketchout-text {
301
+ position: relative;
302
+ z-index: 0;
303
+ }
304
+ .mh-sketchout-lines {
305
+ position: absolute;
306
+ top: 0;
307
+ left: -4px;
308
+ right: -4px;
309
+ bottom: 0;
310
+ overflow: hidden;
311
+ z-index: 1;
312
+ }
313
+ .mh-sketchout-line {
314
+ position: absolute;
315
+ top: 50%;
316
+ left: 0;
317
+ width: 100%;
318
+ height: 2px;
319
+ background: #e53935;
320
+ transform-origin: left center;
321
+ transform: scaleX(0);
322
+ }
323
+ .mh-sketchout-fwd {
324
+ transform: scaleX(0) rotate(-12deg);
325
+ }
326
+ .mh-sketchout-bwd {
327
+ transform: scaleX(0) rotate(12deg);
328
+ }
329
+ ```
330
+
331
+ ```js
332
+ // Forward slash draws first
333
+ tl.to(
334
+ "#sketchout-1 .mh-sketchout-fwd",
335
+ {
336
+ scaleX: 1,
337
+ duration: 0.3,
338
+ ease: "power2.out",
339
+ },
340
+ 1.0,
341
+ );
342
+
343
+ // Backward slash follows
344
+ tl.to(
345
+ "#sketchout-1 .mh-sketchout-bwd",
346
+ {
347
+ scaleX: 1,
348
+ duration: 0.3,
349
+ ease: "power2.out",
350
+ },
351
+ 1.15,
352
+ );
353
+ ```
354
+
355
+ ## Combining Modes in Captions
356
+
357
+ Use mode cycling for visual variety across caption groups:
358
+
359
+ ```js
360
+ var MODES = ["highlight", "circle", "burst", "scribble"];
361
+
362
+ GROUPS.forEach(function (group, gi) {
363
+ var mode = MODES[gi % MODES.length];
364
+ // Apply the mode's CSS pattern to emphasis words in this group
365
+ group.emphasisWords.forEach(function (word) {
366
+ applyMode(word.el, mode, tl, word.start);
367
+ });
368
+ });
369
+ ```
370
+
371
+ Cycle every 2-3 groups for high energy, every 3-4 for medium, every 4-5 for low.
@@ -0,0 +1,146 @@
1
+ # Marker Highlight Examples
2
+
3
+ ## Recipes
4
+
5
+ ### Underline
6
+
7
+ ```html
8
+ <mark
9
+ data-height="0.15"
10
+ data-offset="0.8"
11
+ data-padding="0"
12
+ data-highlight='{"amplitude":0.2,"wavelength":5,"roughEnds":0}'
13
+ data-color="rgba(30, 136, 229, 0.6)"
14
+ >important</mark
15
+ >
16
+ ```
17
+
18
+ ### Strikethrough
19
+
20
+ ```html
21
+ <mark
22
+ data-drawing-mode="highlight"
23
+ data-height="0.1"
24
+ data-offset="0"
25
+ data-highlight='{"amplitude":0.1,"wavelength":3}'
26
+ data-color="rgba(229, 57, 53, 0.8)"
27
+ >wrong answer</mark
28
+ >
29
+ ```
30
+
31
+ ### Circled Annotation
32
+
33
+ ```html
34
+ <mark
35
+ data-drawing-mode="circle"
36
+ data-circle='{"curve":0.8,"wobble":0.4,"loops":2,"thickness":3}'
37
+ data-animation-speed="1200"
38
+ data-color="rgba(229, 57, 53, 0.6)"
39
+ >this one</mark
40
+ >
41
+ ```
42
+
43
+ ## Full Example in a Composition
44
+
45
+ ```html
46
+ <div data-composition-id="highlight-demo" data-width="1920" data-height="1080">
47
+ <div
48
+ id="content"
49
+ style="
50
+ position: absolute; inset: 0;
51
+ display: flex; align-items: center; justify-content: center;
52
+ font-family: 'Inter', sans-serif; font-size: 72px; color: #fff;
53
+ background: #111;
54
+ "
55
+ >
56
+ <p id="hero">
57
+ The <mark id="m1" data-color="rgba(255, 220, 50, 0.5)">fastest</mark> way to
58
+ <mark
59
+ id="m2"
60
+ data-drawing-mode="circle"
61
+ data-circle='{"curve":0.8,"wobble":0.3,"loops":2,"thickness":3}'
62
+ data-color="rgba(229, 57, 53, 0.6)"
63
+ >ship</mark
64
+ >
65
+ </p>
66
+ </div>
67
+
68
+ <style>
69
+ [data-composition-id="highlight-demo"] mark {
70
+ background-color: transparent;
71
+ color: inherit;
72
+ }
73
+ </style>
74
+
75
+ <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
76
+ <script src="marker-highlight.global.js"></script>
77
+ <script>
78
+ window.__timelines = window.__timelines || {};
79
+ var tl = gsap.timeline({ paused: true });
80
+
81
+ // Set colors via data attribute (no visible flash)
82
+ document.querySelectorAll("mark[data-color]").forEach(function (m) {
83
+ m.setAttribute("data-original-bgcolor", m.getAttribute("data-color"));
84
+ });
85
+
86
+ // Init once after fonts, then hide all canvases
87
+ var hl;
88
+ document.fonts.ready.then(function () {
89
+ setTimeout(function () {
90
+ hl = new MarkerHighlighter(document.getElementById("hero"), {
91
+ animate: false,
92
+ animationSpeed: 800,
93
+ padding: 0.3,
94
+ highlight: { amplitude: 0.3, wavelength: 5 },
95
+ });
96
+ setTimeout(function () {
97
+ document.querySelectorAll(".highlight").forEach(function (d) {
98
+ d.style.opacity = "0";
99
+ });
100
+ }, 100);
101
+ }, 50);
102
+ });
103
+
104
+ function addHighlight(markId, time) {
105
+ tl.to(
106
+ {},
107
+ {
108
+ duration: 0.001,
109
+ onStart: function () {
110
+ var mark = document.getElementById(markId);
111
+ var ref = mark.getAttribute("data-mark-ref");
112
+ if (!ref || !hl) return;
113
+ mark.parentElement
114
+ .querySelectorAll('.highlight[data-mark-id="' + ref + '"]')
115
+ .forEach(function (div) {
116
+ var c = div.querySelector("canvas");
117
+ if (c) c.getContext("2d").clearRect(0, 0, c.width, c.height);
118
+ div.style.opacity = "1";
119
+ });
120
+ hl.reanimateMark(mark);
121
+ },
122
+ onReverseComplete: function () {
123
+ var mark = document.getElementById(markId);
124
+ var ref = mark.getAttribute("data-mark-ref");
125
+ if (!ref) return;
126
+ mark.parentElement
127
+ .querySelectorAll('.highlight[data-mark-id="' + ref + '"]')
128
+ .forEach(function (div) {
129
+ div.style.opacity = "0";
130
+ });
131
+ },
132
+ },
133
+ time,
134
+ );
135
+ }
136
+
137
+ gsap.set("#hero", { opacity: 0 });
138
+ tl.to("#hero", { opacity: 1, duration: 0.6 }, 0);
139
+
140
+ addHighlight("m1", 0.8);
141
+ addHighlight("m2", 1.6);
142
+
143
+ window.__timelines["highlight-demo"] = tl;
144
+ </script>
145
+ </div>
146
+ ```
@@ -0,0 +1,158 @@
1
+ # Marker Highlight
2
+
3
+ Animated canvas-based text highlighting using MarkerHighlight.js. Wraps text in `<mark>` tags and renders effects (marker pen, circle, burst, scribble, sketchout) on a canvas overlay without modifying text DOM.
4
+
5
+ The library runs its own requestAnimationFrame loop — **not** GSAP-driven. Use `tl.call()` to trigger at specific timeline points.
6
+
7
+ ## Required Script
8
+
9
+ Download and convert to global script:
10
+
11
+ ```bash
12
+ curl -sL "https://cdn.jsdelivr.net/gh/Robincodes-Sandbox/marker-highlight@main/dist/marker-highlight.min.js" \
13
+ | sed 's/export{[^}]*};$/window.MarkerHighlighter=W;/' > marker-highlight.global.js
14
+ ```
15
+
16
+ ```html
17
+ <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
18
+ <script src="marker-highlight.global.js"></script>
19
+ ```
20
+
21
+ ## Color Setup
22
+
23
+ Set via `data-color`, copy to `data-original-bgcolor` before constructing. Never set `background-color` in CSS.
24
+
25
+ ```css
26
+ mark {
27
+ color: inherit;
28
+ background-color: transparent;
29
+ }
30
+ ```
31
+
32
+ ```html
33
+ <mark id="m1" data-color="rgba(255, 220, 50, 0.5)">highlighted</mark>
34
+ ```
35
+
36
+ ```js
37
+ document
38
+ .querySelectorAll("mark[data-color]")
39
+ .forEach((m) => m.setAttribute("data-original-bgcolor", m.getAttribute("data-color")));
40
+ ```
41
+
42
+ ## GSAP Integration Pattern
43
+
44
+ ONE MarkerHighlighter per container with `animate: false`, hide all canvases, then clear+show+reanimate per mark at trigger time.
45
+
46
+ ```js
47
+ var hl = new MarkerHighlighter(document.getElementById("text-container"), {
48
+ animate: false,
49
+ animationSpeed: 800,
50
+ padding: 0.3,
51
+ highlight: { amplitude: 0.3, wavelength: 5 },
52
+ });
53
+
54
+ setTimeout(function () {
55
+ document.querySelectorAll(".highlight").forEach((div) => (div.style.opacity = "0"));
56
+ }, 100);
57
+
58
+ function addHighlight(highlighter, markId, time) {
59
+ tl.to(
60
+ {},
61
+ {
62
+ duration: 0.001,
63
+ onStart: function () {
64
+ var mark = document.getElementById(markId);
65
+ var ref = mark.getAttribute("data-mark-ref");
66
+ var divs = mark.parentElement.querySelectorAll('.highlight[data-mark-id="' + ref + '"]');
67
+ divs.forEach(function (div) {
68
+ var canvas = div.querySelector("canvas");
69
+ if (canvas) canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);
70
+ div.style.opacity = "1";
71
+ });
72
+ highlighter.reanimateMark(mark);
73
+ },
74
+ onReverseComplete: function () {
75
+ var mark = document.getElementById(markId);
76
+ var ref = mark.getAttribute("data-mark-ref");
77
+ mark.parentElement
78
+ .querySelectorAll('.highlight[data-mark-id="' + ref + '"]')
79
+ .forEach((div) => (div.style.opacity = "0"));
80
+ },
81
+ },
82
+ time,
83
+ );
84
+ }
85
+
86
+ addHighlight(hl, "m1", 1.0);
87
+ ```
88
+
89
+ ## Drawing Modes
90
+
91
+ | Mode | Effect | Best for |
92
+ | ----------- | ---------------------------- | -------------------------- |
93
+ | `highlight` | Wavy marker stroke (default) | Phrases, key terms |
94
+ | `circle` | Hand-drawn ellipse | Single words, annotations |
95
+ | `burst` | Radiating lines/curves/puffs | Excitement, energy |
96
+ | `scribble` | Chaotic scribble | Crossing out, messy energy |
97
+ | `sketchout` | Rough rectangle outline | Boxed callouts, blueprint |
98
+
99
+ ```html
100
+ <mark data-drawing-mode="circle" data-color="rgba(229, 57, 53, 0.6)">critical</mark>
101
+ <mark
102
+ data-drawing-mode="burst"
103
+ data-burst='{"style":"cloud","count":20}'
104
+ data-color="rgba(255, 220, 50, 0.5)"
105
+ >amazing</mark
106
+ >
107
+ ```
108
+
109
+ ## Configuration
110
+
111
+ ### Global (constructor)
112
+
113
+ | Option | Default | Description |
114
+ | ---------------- | ------------- | ------------------------- |
115
+ | `animate` | `true` | `false` to defer for GSAP |
116
+ | `animationSpeed` | `5000` | Duration in ms |
117
+ | `drawingMode` | `"highlight"` | Default mode |
118
+ | `height` | `1` | Relative to line height |
119
+ | `offset` | `0` | Vertical shift |
120
+ | `padding` | `0` | Horizontal padding |
121
+
122
+ ### Per-Mode
123
+
124
+ **highlight**: `amplitude` (0.25), `wavelength` (1), `roughEnds` (5), `jitter` (0.1)
125
+ **circle**: `curve` (0.5), `wobble` (0.3), `loops` (3), `thickness` (5)
126
+ **burst**: `style` ("lines"/"curve"/"cloud"), `count` (10), `power` (1), `randomness` (0.5)
127
+
128
+ ### Named Styles
129
+
130
+ ```js
131
+ MarkerHighlighter.defineStyle("underline", {
132
+ animationSpeed: 400,
133
+ height: 0.15,
134
+ offset: 0.8,
135
+ padding: 0,
136
+ highlight: { amplitude: 0.2, wavelength: 5, roughEnds: 0 },
137
+ });
138
+ ```
139
+
140
+ ## Mode-to-Caption Energy Mapping
141
+
142
+ | Energy | Mode | Use for |
143
+ | ----------- | --------------------- | ------------------- |
144
+ | High | `burst` + `highlight` | Launches, hype |
145
+ | Medium-high | `circle` | Key stats, terms |
146
+ | Medium | `highlight` | Standard emphasis |
147
+ | Medium-low | `scribble` | Subtle, tutorials |
148
+ | Low | `sketchout` | Contrast, blueprint |
149
+
150
+ ## Notes
151
+
152
+ - One highlighter per container (clears all `.highlight` divs on init)
153
+ - Canvas pre-draw + clear pattern for clean reveals
154
+ - rAF-based — not seekable mid-stroke
155
+ - Use `onReverseComplete` for rewind support
156
+
157
+ For CSS+GSAP fallback (no library, fully seekable), see [css-patterns.md](css-patterns.md).
158
+ For full examples, see [examples.md](examples.md).