@cosmictraveler002/anim-kit 1.5.0 → 1.6.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/README.md +245 -21
- package/dist/anim-kit.standalone.js +5 -5
- package/dist/anim-kit.standalone.js.map +1 -1
- package/dist/effects/horizontal-scroll.d.ts.map +1 -1
- package/dist/effects/horizontal-scroll.js +3 -0
- package/dist/effects/horizontal-scroll.js.map +1 -1
- package/dist/effects/ink-wipe.d.ts +41 -0
- package/dist/effects/ink-wipe.d.ts.map +1 -0
- package/dist/effects/ink-wipe.js +342 -0
- package/dist/effects/ink-wipe.js.map +1 -0
- package/dist/effects/scatter-text.d.ts.map +1 -1
- package/dist/effects/scatter-text.js +3 -0
- package/dist/effects/scatter-text.js.map +1 -1
- package/dist/effects/stacked-cards.d.ts.map +1 -1
- package/dist/effects/stacked-cards.js +3 -0
- package/dist/effects/stacked-cards.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/three/coverflow-wheel.d.ts +26 -0
- package/dist/three/coverflow-wheel.d.ts.map +1 -0
- package/dist/three/coverflow-wheel.js +495 -0
- package/dist/three/coverflow-wheel.js.map +1 -0
- package/dist/three/dither-reveal.d.ts +36 -0
- package/dist/three/dither-reveal.d.ts.map +1 -0
- package/dist/three/dither-reveal.js +292 -0
- package/dist/three/dither-reveal.js.map +1 -0
- package/dist/three/index.d.ts +8 -0
- package/dist/three/index.d.ts.map +1 -1
- package/dist/three/index.js +4 -0
- package/dist/three/index.js.map +1 -1
- package/dist/three/tear-reveal.d.ts +54 -0
- package/dist/three/tear-reveal.d.ts.map +1 -0
- package/dist/three/tear-reveal.js +269 -0
- package/dist/three/tear-reveal.js.map +1 -0
- package/dist/three/wordmark-wave.d.ts +29 -0
- package/dist/three/wordmark-wave.d.ts.map +1 -0
- package/dist/three/wordmark-wave.js +461 -0
- package/dist/three/wordmark-wave.js.map +1 -0
- package/package.json +1 -1
- package/src/effects/horizontal-scroll.ts +3 -0
- package/src/effects/ink-wipe.ts +409 -0
- package/src/effects/scatter-text.ts +3 -0
- package/src/effects/stacked-cards.ts +3 -0
- package/src/index.ts +3 -0
- package/src/three/coverflow-wheel.ts +569 -0
- package/src/three/dither-reveal.ts +365 -0
- package/src/three/index.ts +8 -0
- package/src/three/tear-reveal.ts +351 -0
- package/src/three/wordmark-wave.ts +517 -0
package/README.md
CHANGED
|
@@ -30,6 +30,7 @@ destroy();
|
|
|
30
30
|
- [Core](#core)
|
|
31
31
|
- [Text animations](#text-animations)
|
|
32
32
|
- [Scroll & media](#scroll--media)
|
|
33
|
+
- [WebGL](#webgl)
|
|
33
34
|
- [Loops & marquees](#loops--marquees)
|
|
34
35
|
- [Buttons & links](#buttons--links)
|
|
35
36
|
- [Navigation & overlays](#navigation--overlays)
|
|
@@ -78,7 +79,7 @@ inside the published tarball):
|
|
|
78
79
|
|
|
79
80
|
| Specifier | Resolves to | Use for |
|
|
80
81
|
|---|---|---|
|
|
81
|
-
| `@cosmictraveler002/anim-kit` | `dist/index.js` + `dist/index.d.ts` | the full barrel —
|
|
82
|
+
| `@cosmictraveler002/anim-kit` | `dist/index.js` + `dist/index.d.ts` | the full barrel — 48 exports |
|
|
82
83
|
| `@cosmictraveler002/anim-kit/effects/<name>` | `dist/effects/<name>.js` + `.d.ts` | one effect in isolation (`marquee`, `lineReveal`, …) |
|
|
83
84
|
| `@cosmictraveler002/anim-kit/three` | `dist/three/index.js` + `.d.ts` | WebGL effects — needs the optional `three` peer (never a core dep) |
|
|
84
85
|
| `@cosmictraveler002/anim-kit/standalone` | `dist/anim-kit.standalone.js` (types → `index.d.ts`) | the self-contained bundle — same API |
|
|
@@ -98,7 +99,7 @@ resolves declarations through the same map — no `typesVersions` shim needed.
|
|
|
98
99
|
|
|
99
100
|
No build step on the consumer's end: `dist/` is served as-is from the npm
|
|
100
101
|
tarball by any npm CDN. Every URL is **version-pinned** — npm versions are
|
|
101
|
-
immutable, so `@cosmictraveler002/anim-kit@1.
|
|
102
|
+
immutable, so `@cosmictraveler002/anim-kit@1.6.0` always resolves to exactly that build, forever
|
|
102
103
|
(only a new version creates a new URL; nothing floats unless you ask for a
|
|
103
104
|
range).
|
|
104
105
|
|
|
@@ -109,12 +110,12 @@ plugins anim-kit uses) and `lenis` **inlined** — no import map, one URL, works
|
|
|
109
110
|
identically on jsDelivr and unpkg:
|
|
110
111
|
|
|
111
112
|
```html
|
|
112
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.
|
|
113
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.6.0/dist/styles/anim-kit.css" />
|
|
113
114
|
|
|
114
115
|
<script type="module">
|
|
115
116
|
import {
|
|
116
117
|
smoothScroll, lineReveal, marquee,
|
|
117
|
-
} from "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.
|
|
118
|
+
} from "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.6.0/dist/anim-kit.standalone.js";
|
|
118
119
|
|
|
119
120
|
smoothScroll();
|
|
120
121
|
lineReveal("[data-lines]", { mode: "scroll" });
|
|
@@ -122,7 +123,7 @@ identically on jsDelivr and unpkg:
|
|
|
122
123
|
</script>
|
|
123
124
|
```
|
|
124
125
|
|
|
125
|
-
unpkg serves the same file: `https://unpkg.com/@cosmictraveler002/anim-kit@1.
|
|
126
|
+
unpkg serves the same file: `https://unpkg.com/@cosmictraveler002/anim-kit@1.6.0/dist/anim-kit.standalone.js`
|
|
126
127
|
|
|
127
128
|
### Option 2 — jsDelivr `+esm`
|
|
128
129
|
|
|
@@ -131,7 +132,7 @@ per version):
|
|
|
131
132
|
|
|
132
133
|
```html
|
|
133
134
|
<script type="module">
|
|
134
|
-
import { lineReveal } from "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.
|
|
135
|
+
import { lineReveal } from "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.6.0/+esm";
|
|
135
136
|
</script>
|
|
136
137
|
```
|
|
137
138
|
|
|
@@ -143,13 +144,13 @@ locally, with CDN URLs — and the way to share one GSAP between anim-kit and
|
|
|
143
144
|
the rest of your page:
|
|
144
145
|
|
|
145
146
|
```html
|
|
146
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.
|
|
147
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.6.0/dist/styles/anim-kit.css" />
|
|
147
148
|
|
|
148
149
|
<script type="importmap">
|
|
149
150
|
{
|
|
150
151
|
"imports": {
|
|
151
|
-
"@cosmictraveler002/anim-kit": "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.
|
|
152
|
-
"@cosmictraveler002/anim-kit/three": "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.
|
|
152
|
+
"@cosmictraveler002/anim-kit": "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.6.0/dist/index.js",
|
|
153
|
+
"@cosmictraveler002/anim-kit/three": "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.6.0/dist/three/index.js",
|
|
153
154
|
"three": "https://cdn.jsdelivr.net/npm/three@0.186.1/build/three.module.js",
|
|
154
155
|
"gsap": "https://cdn.jsdelivr.net/npm/gsap@3.15.0/index.js",
|
|
155
156
|
"gsap/ScrollTrigger": "https://cdn.jsdelivr.net/npm/gsap@3.15.0/ScrollTrigger.js",
|
|
@@ -170,7 +171,7 @@ the rest of your page:
|
|
|
170
171
|
</script>
|
|
171
172
|
```
|
|
172
173
|
|
|
173
|
-
Swap the host for unpkg (`https://unpkg.com/@cosmictraveler002/anim-kit@1.
|
|
174
|
+
Swap the host for unpkg (`https://unpkg.com/@cosmictraveler002/anim-kit@1.6.0/dist/index.js`, …) —
|
|
174
175
|
the file layout is identical. GSAP subpaths are listed one by one because
|
|
175
176
|
import maps match specifiers literally: a trailing-slash prefix map would
|
|
176
177
|
produce extension-less URLs, which CDNs don't serve. The `gsap`/`lenis` pins
|
|
@@ -329,7 +330,9 @@ prompt dock, and backs the `category` / `subcategory` fields on
|
|
|
329
330
|
| Scroll & media | Parallax & depth | `parallax` |
|
|
330
331
|
| Scroll & media | Heroes & media | `heroShrink`, `mediaSettle` |
|
|
331
332
|
| Scroll & media | Enter reveals | `revealRule`, `unfoldReveal`, `clipWipe` |
|
|
332
|
-
| WebGL | Shader media | `webglMedia`, `glRail` |
|
|
333
|
+
| WebGL | Shader media | `webglMedia`, `glRail`, `coverflowWheel` |
|
|
334
|
+
| WebGL | Scenes & overlays | `tearReveal`, `ditherReveal` |
|
|
335
|
+
| WebGL | Kinetic type | `wordmarkWave` |
|
|
333
336
|
| Loops & marquees | Marquees | `marquee` |
|
|
334
337
|
| Loops & marquees | Draggables & rails | `dragStrip`, `dragRail` |
|
|
335
338
|
| Loops & marquees | Equalizers | `audioBars` |
|
|
@@ -340,6 +343,7 @@ prompt dock, and backs the `category` / `subcategory` fields on
|
|
|
340
343
|
| Navigation & overlays | Cursors | `cursorFollower` |
|
|
341
344
|
| Intros & transitions | Preloaders | `preloader` |
|
|
342
345
|
| Intros & transitions | Theme wipes | `themeReveal` |
|
|
346
|
+
| Intros & transitions | Page transitions | `inkWipe` |
|
|
343
347
|
| Logos & SVG | Path reveals | `logoReveal` |
|
|
344
348
|
|
|
345
349
|
**Growing the library:** a subcategory is the slot sibling effects land in —
|
|
@@ -806,7 +810,8 @@ the entrance.
|
|
|
806
810
|
|
|
807
811
|
### WebGL
|
|
808
812
|
|
|
809
|
-
GPU media — three.js re-renders your
|
|
813
|
+
GPU media — three.js re-renders your content as shader cards, kinetic type
|
|
814
|
+
and reveal scenes. This is the only
|
|
810
815
|
category behind the `@cosmictraveler002/anim-kit/three` subpath: `three` is an
|
|
811
816
|
**optional peer** (see [Subpath exports](#subpath-exports)), so the core
|
|
812
817
|
barrel and the standalone bundle stay three-free.
|
|
@@ -920,6 +925,183 @@ user-select: none`.
|
|
|
920
925
|
|
|
921
926
|
---
|
|
922
927
|
|
|
928
|
+
#### `coverflowWheel(target, options?) => handle`
|
|
929
|
+
|
|
930
|
+
Media cards on a flattened vertical wheel: each card bends along the arc in
|
|
931
|
+
the vertex shader instead of staying a rigid plane, fronts face you bright
|
|
932
|
+
while the backs show mirrored, one mip blurrier and half-lit, and the strip
|
|
933
|
+
dissolves into the floor below instead of ending on a hard edge. Drag to
|
|
934
|
+
scrub — a release within 5 % of a slot commits to the neighbouring card,
|
|
935
|
+
smaller drags spring back — and while idle the wheel creeps a slot's lead-in
|
|
936
|
+
and then advances on its own.
|
|
937
|
+
|
|
938
|
+
```ts
|
|
939
|
+
import { coverflowWheel } from "@cosmictraveler002/anim-kit/three";
|
|
940
|
+
|
|
941
|
+
const wheel = coverflowWheel("#deck", { idle: 5 });
|
|
942
|
+
wheel.goTo(3); // jump to a card (wraps)
|
|
943
|
+
wheel.next(); // one card on, 0.5 s
|
|
944
|
+
wheel.destroy();
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
| Option | Default | Notes |
|
|
948
|
+
| --- | --- | --- |
|
|
949
|
+
| `index` | `0` | first card on show (wraps) |
|
|
950
|
+
| `autoplay` / `idle` | `true` / `5` | idle advance — seconds of stillness (with a 1/8-slot lead-in creep) |
|
|
951
|
+
| `duration` | `1.15` | `goTo()` tween, seconds (`next()` / `prev()` use 0.5) |
|
|
952
|
+
| `margin` | `0.1` | gap between cards, as a fraction of one slot |
|
|
953
|
+
| `dpr` | `2` | device-pixel-ratio cap |
|
|
954
|
+
|
|
955
|
+
Cards are the host's own `<img>`s — cover-cropped into textures at mount (a
|
|
956
|
+
failed decode drops that card; fewer than two survivors → inert) and restored
|
|
957
|
+
from their inline opacity on teardown. Pointer capture keeps the drag over the
|
|
958
|
+
deck wherever the pointer is and native image-dragging is blocked so a card
|
|
959
|
+
never swallows the stream; the host claims `cursor: grab` + `touch-action:
|
|
960
|
+
pan-y` and a `data-ak-coverflow` stamp, all restored by `destroy()`. Card
|
|
961
|
+
backs reuse the front texture (mirrored, half light, bottom-faded in-shader) —
|
|
962
|
+
no second texture, no extra pass.
|
|
963
|
+
|
|
964
|
+
**Silent no-op ladder.** Missing target → inert handle; no
|
|
965
|
+
`WebGLRenderingContext` (SSR, jsdom, WebGL disabled) → inert *before* any
|
|
966
|
+
context probe; renderer refused → inert; reduced motion → inert, nothing
|
|
967
|
+
mounts. Every call on an inert handle is a safe no-op — nothing ever logs.
|
|
968
|
+
`destroy()` kills the tween + ticker, disconnects the observers, removes the
|
|
969
|
+
canvas and restores the images, host styles and dataset.
|
|
970
|
+
|
|
971
|
+
---
|
|
972
|
+
|
|
973
|
+
#### `tearReveal(target, options?) => destroy`
|
|
974
|
+
|
|
975
|
+
A torn-edge sheet that sweeps a section in (or out): a noise-displaced
|
|
976
|
+
boundary travels across the overlay — the fbm joins the field *before*
|
|
977
|
+
thresholding, so patches tear away ahead of the front and ride across as
|
|
978
|
+
separate shards — while a barrel warp bows the edge into an arriving curve
|
|
979
|
+
instead of a straight line wobbling in place.
|
|
980
|
+
|
|
981
|
+
```ts
|
|
982
|
+
tearReveal("[data-tear]", {
|
|
983
|
+
color: ["#ff8a1e", "#ff5252"], // [foot, top] gradient stops (or one colour)
|
|
984
|
+
blend: "multiply", // tint the section instead of covering it
|
|
985
|
+
direction: "up", // up | down | left | right
|
|
986
|
+
mode: "scroll", // play on enter — or "immediate"
|
|
987
|
+
duration: 1, // seconds for the timed run
|
|
988
|
+
});
|
|
989
|
+
// …or bind it to scroll instead:
|
|
990
|
+
tearReveal("[data-tall]", { scrub: 0.4, start: "top 90%", end: "top 30%" });
|
|
991
|
+
tearReveal(document.body, { fixed: true }); // page-sized sweep over the viewport
|
|
992
|
+
```
|
|
993
|
+
|
|
994
|
+
| Option | Default | Notes |
|
|
995
|
+
| --- | --- | --- |
|
|
996
|
+
| `color` | `"#111111"` | one colour or `[foot, top]` gradient stops |
|
|
997
|
+
| `blend` | `"none"` | CSS `mix-blend-mode` — `multiply` tints what is under the sheet |
|
|
998
|
+
| `direction` | `"up"` | `up` / `down` / `left` / `right` |
|
|
999
|
+
| `dispAmp` / `dispScale` / `dispDetail` / `dispDrift` | `0.175` / `12.2` / `5` / `0` | tear shape — how far, how big, how gritty, how fast it crawls |
|
|
1000
|
+
| `soft` | `0.001` | threshold half-width — small keeps shards crisp |
|
|
1001
|
+
| `lens` | `-0.275` | barrel warp — negative bows the middle of the boundary up |
|
|
1002
|
+
| `duration` / `ease` | `1` / `"power2.inOut"` | timed run (`mode: "scroll"` or `"immediate"`) |
|
|
1003
|
+
| `scrub` | — | smoothing seconds (or `true`) — progress follows the scroll, both ways |
|
|
1004
|
+
| `start` / `end` | `"top 85%"` / `"top 25%"` | ScrollTrigger positions |
|
|
1005
|
+
| `replay` | `false` | re-run on every viewport entry |
|
|
1006
|
+
| `fixed` / `z` / `dpr` | `false` / `1` / `2` | viewport-sized canvas, stacking, pixel-ratio cap |
|
|
1007
|
+
|
|
1008
|
+
Both ends of the travel are **sealed**: the displaced boundary reaches the
|
|
1009
|
+
far side with its deepest tear at exactly zero, so the last half-covered
|
|
1010
|
+
pixels never read as speckle or leftover haze.
|
|
1011
|
+
|
|
1012
|
+
**Silent no-op ladder.** Missing target → no-op; no `WebGLRenderingContext`
|
|
1013
|
+
(SSR, jsdom, WebGL disabled) → no-op *before* any context probe; renderer
|
|
1014
|
+
refused → no-op; reduced motion → nothing mounts. Nothing ever logs.
|
|
1015
|
+
`destroy()` kills the tween + ScrollTrigger, removes the canvas and restores
|
|
1016
|
+
the host's styles.
|
|
1017
|
+
|
|
1018
|
+
**DOM.** `position: relative; overflow: hidden` on the target — or skip the
|
|
1019
|
+
target box entirely with `fixed: true` for a page-sized sweep.
|
|
1020
|
+
|
|
1021
|
+
---
|
|
1022
|
+
|
|
1023
|
+
#### `ditherReveal(target, options?) => destroy`
|
|
1024
|
+
|
|
1025
|
+
A photo punches through its placeholder in a hard-edged, fbm-speckled ring
|
|
1026
|
+
expanding from the centre outward — no soft dissolve, no crossfade: every
|
|
1027
|
+
pixel on the boundary flips between hole and not-hole. The noise spread
|
|
1028
|
+
ramps to zero at both ends of the travel, so progress 0 is exactly empty
|
|
1029
|
+
and progress 1 exactly solid.
|
|
1030
|
+
|
|
1031
|
+
```ts
|
|
1032
|
+
ditherReveal("[data-reveal]", {
|
|
1033
|
+
plate: "#14140f", // flat placeholder where the mask has not opened yet
|
|
1034
|
+
duration: 1.15, // seconds, ease "power4.out"
|
|
1035
|
+
maskScale: 50, // fbm frequency across the element — lump scale of the edge
|
|
1036
|
+
hard: true, // the signature speckle (false = a soft dissolve)
|
|
1037
|
+
play: "visible", // fire on first viewport entry ("load" = when the texture decodes)
|
|
1038
|
+
});
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1041
|
+
| Option | Default | Notes |
|
|
1042
|
+
| --- | --- | --- |
|
|
1043
|
+
| `src` | first `<img>` | image source override when the wrapper has no image |
|
|
1044
|
+
| `duration` / `ease` | `1.15` / `"power4.out"` | the reveal clock |
|
|
1045
|
+
| `plate` | — | flat placeholder colour (omit → the wrapper's own background shows through) |
|
|
1046
|
+
| `maskScale` / `spread` / `detail` | `50` / `0.35` / `4` | edge shape — frequency, reach, fbm octaves |
|
|
1047
|
+
| `hard` | `true` | hard speckle vs soft dissolve |
|
|
1048
|
+
| `play` | `"visible"` | `"visible"` fires on first viewport entry, `"load"` on texture decode |
|
|
1049
|
+
| `dpr` | `2` | device-pixel-ratio cap |
|
|
1050
|
+
|
|
1051
|
+
The `<img>` keeps layout and alt text: the canvas covers the wrapper and
|
|
1052
|
+
only takes over its pixels once the texture has decoded — with a plate the
|
|
1053
|
+
placeholder covers from load, without one the image only steps aside when
|
|
1054
|
+
the reveal actually starts. The cover-crop runs in-shader (`object-fit:
|
|
1055
|
+
cover` maths), so any source aspect fills any card aspect.
|
|
1056
|
+
|
|
1057
|
+
**Silent no-op ladder.** Missing target → no-op; no `WebGLRenderingContext`
|
|
1058
|
+
(SSR, jsdom, WebGL disabled) → no-op *before* any context probe; renderer
|
|
1059
|
+
refused → no-op; texture 404 → the plain `<img>` stays untouched; reduced
|
|
1060
|
+
motion → the canvas never mounts and the static image is the resting state.
|
|
1061
|
+
Nothing ever logs. `destroy()` kills the tween + observers, disposes
|
|
1062
|
+
geometry/material/texture/renderer, removes the canvas and restores the
|
|
1063
|
+
image opacity and wrapper position.
|
|
1064
|
+
|
|
1065
|
+
---
|
|
1066
|
+
|
|
1067
|
+
#### `wordmarkWave(target, options?) => destroy`
|
|
1068
|
+
|
|
1069
|
+
The target's own headline rendered to a texture and simulated as a spring
|
|
1070
|
+
lattice: the pointer shears the letters like thick liquid, red and cyan split
|
|
1071
|
+
out of the colour while the surface deforms, and every vertex springs back to
|
|
1072
|
+
exact rest. Text, font and colour come from the element itself — nothing to
|
|
1073
|
+
export, nothing to align.
|
|
1074
|
+
|
|
1075
|
+
```ts
|
|
1076
|
+
import { wordmarkWave } from "@cosmictraveler002/anim-kit/three";
|
|
1077
|
+
|
|
1078
|
+
const destroy = wordmarkWave("#mark", {
|
|
1079
|
+
drag: 1, // pointer-velocity term — how hard the letters smear
|
|
1080
|
+
push: 0, // radial push — vertices flee the cursor while it sits still
|
|
1081
|
+
chroma: true, // red/cyan fringes while deforming
|
|
1082
|
+
});
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1085
|
+
| Option | Default | Notes |
|
|
1086
|
+
| --- | --- | --- |
|
|
1087
|
+
| `text` / `font` / `color` | target's own | override what is drawn (the host's colour is hidden while mounted) |
|
|
1088
|
+
| `outline` / `tracking` | `0` / `0` | stroke width, px (0 = filled) and extra letter spacing, px |
|
|
1089
|
+
| `drag` / `push` | `1` / `0` | pointer-velocity and radial-push terms of the simulation |
|
|
1090
|
+
| `chroma` | `true` | red/cyan chromatic split while deforming |
|
|
1091
|
+
| `segments` | `0` | grid columns — auto (≈10 px cells, ~5 k vertices) |
|
|
1092
|
+
| `opacity` / `z` / `dpr` | `1` / `1` / `2` | canvas opacity, stacking order, pixel-ratio cap |
|
|
1093
|
+
|
|
1094
|
+
The simulation steps at a fixed 60 Hz (max 4 steps per frame; a gap over
|
|
1095
|
+
0.2 s counts as one step) so a backgrounded tab resumes where it left instead
|
|
1096
|
+
of exploding, and the ticker idles while the host is off-screen. **Silent
|
|
1097
|
+
no-op ladder**: missing target → no-op; no `WebGLRenderingContext` (SSR,
|
|
1098
|
+
jsdom, WebGL disabled) → no-op *before* any context probe; renderer refused →
|
|
1099
|
+
no-op; reduced motion → nothing mounts, the real text simply stays. Nothing
|
|
1100
|
+
ever logs. `destroy()` stops the ticker + observers, disposes the renderer,
|
|
1101
|
+
removes the canvas and restores the host colour it hid.
|
|
1102
|
+
|
|
1103
|
+
---
|
|
1104
|
+
|
|
923
1105
|
### Loops & marquees
|
|
924
1106
|
|
|
925
1107
|
Continuous motion — marquees, draggable rails, equaliser bars.
|
|
@@ -1245,6 +1427,46 @@ theme.set("dark"); theme.toggle(); theme.current(); theme.destroy();
|
|
|
1245
1427
|
|
|
1246
1428
|
---
|
|
1247
1429
|
|
|
1430
|
+
#### `inkWipe(options?) => handle`
|
|
1431
|
+
|
|
1432
|
+
A brush-loaded ink sheet sweeps across the whole page: `cover()` paints it
|
|
1433
|
+
over, the swap happens at full cover, `unveil()` lets the new page arrive
|
|
1434
|
+
behind the *same* stroke — one continuous left→right travel whose edge is
|
|
1435
|
+
seeded, so it never boils between frames. Bristle spurs and flecks run
|
|
1436
|
+
ahead of the front.
|
|
1437
|
+
|
|
1438
|
+
```ts
|
|
1439
|
+
const wipe = inkWipe({ links: "[data-wipe]" }); // intercepts links; next page auto-unveils
|
|
1440
|
+
|
|
1441
|
+
await wipe.cover(); // resolves at full cover — swap your DOM here
|
|
1442
|
+
await wipe.unveil(); // the new page arrives behind the same stroke
|
|
1443
|
+
wipe.destroy();
|
|
1444
|
+
|
|
1445
|
+
// Options-object form or target-first form both work:
|
|
1446
|
+
inkWipe({ host: "#overlay", color: "#111" });
|
|
1447
|
+
inkWipe(document.body, { coverMs: 700 });
|
|
1448
|
+
```
|
|
1449
|
+
|
|
1450
|
+
| Option | Default | Notes |
|
|
1451
|
+
| --- | --- | --- |
|
|
1452
|
+
| `host` | `document.body` | overlay host the canvas is appended to (target arg also works) |
|
|
1453
|
+
| `color` | `"#0b0b0b"` | ink colour |
|
|
1454
|
+
| `coverMs` / `unveilMs` | `550` / `650` | sweep durations |
|
|
1455
|
+
| `ease` | `"power2.inOut"` | GSAP ease for both halves |
|
|
1456
|
+
| `tilt` / `rough` / `bristle` | `0.35` / `44` / `180` | edge lean (× height), noise amplitude px, longest spur px |
|
|
1457
|
+
| `links` | — | selectors intercepted — a click runs the wipe before navigating |
|
|
1458
|
+
| `sessionKey` / `autoUnveil` | `"ak-ink-wipe"` / `true` | cross-page handoff flag + the page-load unveil |
|
|
1459
|
+
| `z` | `9998` | overlay z-index |
|
|
1460
|
+
|
|
1461
|
+
**The MPA handoff** is a sessionStorage flag: a covered navigation stores
|
|
1462
|
+
`sessionKey`, the next page reads it, covers instantly and unveils — no
|
|
1463
|
+
flash between documents. Reduced motion snaps both halves instantly to a
|
|
1464
|
+
solid sheet, so navigation still never flashes the swap; without a 2D
|
|
1465
|
+
context (SSR, jsdom) both promises resolve immediately and nothing paints.
|
|
1466
|
+
`destroy()` removes the canvas, its listeners and the link interception.
|
|
1467
|
+
|
|
1468
|
+
---
|
|
1469
|
+
|
|
1248
1470
|
### Logos & SVG
|
|
1249
1471
|
|
|
1250
1472
|
Vector reveals for brand marks.
|
|
@@ -1417,7 +1639,7 @@ curl http://localhost:4321/api/prompts/marquee # one prompt, text/plain
|
|
|
1417
1639
|
```
|
|
1418
1640
|
|
|
1419
1641
|
On the page, every labelled section carries a **copy prompt** chip, and the
|
|
1420
|
-
floating **⧉ prompts (
|
|
1642
|
+
floating **⧉ prompts (38)** button at the bottom right opens the full
|
|
1421
1643
|
catalogue grouped by [effect category](#effect-categories) — one click copies
|
|
1422
1644
|
an effect's prompt (the prompt states its category), *copy all* puts the
|
|
1423
1645
|
entire set on the clipboard. The catalogue lives in `scripts/prompts.mjs`:
|
|
@@ -1428,17 +1650,19 @@ and slotting the effect into a subcategory.
|
|
|
1428
1650
|
**Unit smoke** (`scripts/smoke.mjs`) runs the built bundle in **jsdom** and
|
|
1429
1651
|
asserts:
|
|
1430
1652
|
|
|
1431
|
-
1. all
|
|
1653
|
+
1. all 48 exports are present;
|
|
1432
1654
|
2. plugins (`ScrollTrigger`, `SplitText`, `Draggable`, `CustomEase`,
|
|
1433
1655
|
`Flip`, `ScrollSmoother`) and the 4 custom eases are registered;
|
|
1434
1656
|
3. every effect no-ops safely on missing targets;
|
|
1435
|
-
4.
|
|
1436
|
-
5.
|
|
1437
|
-
|
|
1657
|
+
4. 27 effects mount on real markup and unmount cleanly;
|
|
1658
|
+
5. pinning effects claim `refreshPriority: 1`, so ScrollTrigger refresh
|
|
1659
|
+
measures in document order (root README bug class E);
|
|
1660
|
+
6. `preloader` ticks in both the positional and options-object call forms;
|
|
1661
|
+
7. `lineReveal` actually splits into masked lines (and per-character masks
|
|
1438
1662
|
with `split: "chars"`) and restores markup on destroy;
|
|
1439
|
-
|
|
1663
|
+
8. `scrambleText` restores its text, `rollText` wraps/unwraps its rows, and
|
|
1440
1664
|
`counter({ progress: true })` renders a scrubbed readout;
|
|
1441
|
-
|
|
1665
|
+
9. `utils`, `compose` and `guard` behave per contract.
|
|
1442
1666
|
|
|
1443
1667
|
**Demo smoke** (`scripts/demo-smoke.mjs`) loads the real `demo/index.html` and
|
|
1444
1668
|
executes the real `demo/demo.js` wiring against it, then asserts the effects
|
|
@@ -1471,9 +1695,9 @@ anim-kit/
|
|
|
1471
1695
|
│ │ ├─ guard.ts reduced-motion gate
|
|
1472
1696
|
│ │ ├─ util.ts toArray/one/onReady/compose/raf
|
|
1473
1697
|
│ │ └─ types.ts TargetLike / Destroy / CommonOptions
|
|
1474
|
-
│ ├─ effects/ one file per effect (
|
|
1698
|
+
│ ├─ effects/ one file per effect (27 files, 31 effect functions)
|
|
1475
1699
|
│ ├─ styles/anim-kit.css companion stylesheet
|
|
1476
|
-
│ └─ index.ts barrel —
|
|
1700
|
+
│ └─ index.ts barrel — 48 exports
|
|
1477
1701
|
├─ demo/ visual demo (import map, no bundler)
|
|
1478
1702
|
├─ scripts/
|
|
1479
1703
|
│ ├─ serve.mjs static server + /api/prompts (:4321)
|