@cosmictraveler002/anim-kit 1.3.0 → 1.5.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 CHANGED
@@ -98,7 +98,7 @@ resolves declarations through the same map — no `typesVersions` shim needed.
98
98
 
99
99
  No build step on the consumer's end: `dist/` is served as-is from the npm
100
100
  tarball by any npm CDN. Every URL is **version-pinned** — npm versions are
101
- immutable, so `@cosmictraveler002/anim-kit@1.3.0` always resolves to exactly that build, forever
101
+ immutable, so `@cosmictraveler002/anim-kit@1.5.0` always resolves to exactly that build, forever
102
102
  (only a new version creates a new URL; nothing floats unless you ask for a
103
103
  range).
104
104
 
@@ -109,12 +109,12 @@ plugins anim-kit uses) and `lenis` **inlined** — no import map, one URL, works
109
109
  identically on jsDelivr and unpkg:
110
110
 
111
111
  ```html
112
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.3.0/dist/styles/anim-kit.css" />
112
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.5.0/dist/styles/anim-kit.css" />
113
113
 
114
114
  <script type="module">
115
115
  import {
116
116
  smoothScroll, lineReveal, marquee,
117
- } from "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.3.0/dist/anim-kit.standalone.js";
117
+ } from "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.5.0/dist/anim-kit.standalone.js";
118
118
 
119
119
  smoothScroll();
120
120
  lineReveal("[data-lines]", { mode: "scroll" });
@@ -122,7 +122,7 @@ identically on jsDelivr and unpkg:
122
122
  </script>
123
123
  ```
124
124
 
125
- unpkg serves the same file: `https://unpkg.com/@cosmictraveler002/anim-kit@1.3.0/dist/anim-kit.standalone.js`
125
+ unpkg serves the same file: `https://unpkg.com/@cosmictraveler002/anim-kit@1.5.0/dist/anim-kit.standalone.js`
126
126
 
127
127
  ### Option 2 — jsDelivr `+esm`
128
128
 
@@ -131,7 +131,7 @@ per version):
131
131
 
132
132
  ```html
133
133
  <script type="module">
134
- import { lineReveal } from "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.3.0/+esm";
134
+ import { lineReveal } from "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.5.0/+esm";
135
135
  </script>
136
136
  ```
137
137
 
@@ -143,13 +143,13 @@ locally, with CDN URLs — and the way to share one GSAP between anim-kit and
143
143
  the rest of your page:
144
144
 
145
145
  ```html
146
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.3.0/dist/styles/anim-kit.css" />
146
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.5.0/dist/styles/anim-kit.css" />
147
147
 
148
148
  <script type="importmap">
149
149
  {
150
150
  "imports": {
151
- "@cosmictraveler002/anim-kit": "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.3.0/dist/index.js",
152
- "@cosmictraveler002/anim-kit/three": "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.3.0/dist/three/index.js",
151
+ "@cosmictraveler002/anim-kit": "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.5.0/dist/index.js",
152
+ "@cosmictraveler002/anim-kit/three": "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.5.0/dist/three/index.js",
153
153
  "three": "https://cdn.jsdelivr.net/npm/three@0.186.1/build/three.module.js",
154
154
  "gsap": "https://cdn.jsdelivr.net/npm/gsap@3.15.0/index.js",
155
155
  "gsap/ScrollTrigger": "https://cdn.jsdelivr.net/npm/gsap@3.15.0/ScrollTrigger.js",
@@ -170,7 +170,7 @@ the rest of your page:
170
170
  </script>
171
171
  ```
172
172
 
173
- Swap the host for unpkg (`https://unpkg.com/@cosmictraveler002/anim-kit@1.3.0/dist/index.js`, …) —
173
+ Swap the host for unpkg (`https://unpkg.com/@cosmictraveler002/anim-kit@1.5.0/dist/index.js`, …) —
174
174
  the file layout is identical. GSAP subpaths are listed one by one because
175
175
  import maps match specifiers literally: a trailing-slash prefix map would
176
176
  produce extension-less URLs, which CDNs don't serve. The `gsap`/`lenis` pins
@@ -276,8 +276,12 @@ configured before first paint.
276
276
  ## Smooth scroll
277
277
 
278
278
  Lenis is wired to ScrollTrigger the canonical way: Lenis drives the scroll,
279
- `lenis.on("scroll", ScrollTrigger.update)` keeps triggers in sync, `lenis.raf`
280
- is ticked from `gsap.ticker`, and `lagSmoothing(0)` is disabled.
279
+ `lenis.on("scroll", ScrollTrigger.update)` keeps triggers in sync, and
280
+ `lenis.raf` is ticked from `gsap.ticker` so scroll and tweens run off one
281
+ clock. GSAP's lag smoothing stays **on**: ticker listeners receive the same
282
+ adjusted clock the tweens use, so a stalled frame (GC pause, buffer tick)
283
+ advances one short step everywhere instead of snapping the scroll and every
284
+ scroll-linked tween to a new time in a single jump.
281
285
 
282
286
  ```ts
283
287
  const scroller = smoothScroll({
@@ -287,6 +291,11 @@ const scroller = smoothScroll({
287
291
  orientation: "vertical",
288
292
  initialScroll: 0,
289
293
  useScrollerProxy: false, // opt-in scrollerProxy for nested scrollers
294
+ touchMultiplier: 1, // touch-drag sensitivity (Lenis default 1)
295
+ wheelMultiplier: 1, // mouse-wheel sensitivity (Lenis default 1)
296
+ // Lag smoothing: leave unset for GSAP's built-in 500ms → 33ms compensation,
297
+ // false to disable it (the old behaviour), or retune for short hitches:
298
+ lagSmoothing: { threshold: 150 },
290
299
  });
291
300
 
292
301
  scroller.scrollTo("#work", { duration: 1.2 }); // programmatic, smoothed
@@ -320,7 +329,7 @@ prompt dock, and backs the `category` / `subcategory` fields on
320
329
  | Scroll & media | Parallax & depth | `parallax` |
321
330
  | Scroll & media | Heroes & media | `heroShrink`, `mediaSettle` |
322
331
  | Scroll & media | Enter reveals | `revealRule`, `unfoldReveal`, `clipWipe` |
323
- | WebGL | Shader media | `webglMedia` |
332
+ | WebGL | Shader media | `webglMedia`, `glRail` |
324
333
  | Loops & marquees | Marquees | `marquee` |
325
334
  | Loops & marquees | Draggables & rails | `dragStrip`, `dragRail` |
326
335
  | Loops & marquees | Equalizers | `audioBars` |
@@ -847,6 +856,68 @@ alt text in its `<img>`; the canvas takes over only after the texture has
847
856
  loaded. `destroy()` kills ticker + tweens + resize observer and disposes
848
857
  geometry, material, texture and renderer.
849
858
 
859
+ #### `glRail(track, options?) => destroy`
860
+
861
+ > From `@cosmictraveler002/anim-kit/three`, not the core barrel.
862
+
863
+ The bounded drag rail drawn as a **WebGL overlay**: one fixed alpha canvas
864
+ covers the stage and re-creates every card's picture from its DOM rect each
865
+ frame, with the surface bent around an invisible cylinder — `dragRail`'s
866
+ physics (intent/pos ticker, tanh rubber-band, throw momentum, Lenis-safe
867
+ wheel) underneath, and a perspective grid floor that fades into the horizon
868
+ and drifts with the rail. The DOM keeps layout, labels and hit areas: the
869
+ canvas paints *under* the track, so a caption sits over the GL media for
870
+ free, and only each `<img>` gets hidden — after its texture has loaded.
871
+
872
+ The bend is one uniform per card in the vertex shader: each vertex maps its
873
+ offset onto the cylinder (`a = o / R`, `x = R·sin a`, `z = −R·(1−cos a)`)
874
+ re-centred on the card's own middle — the centre stays glued to the DOM
875
+ position while the edges foreshorten, and the rotation arrives free from the
876
+ curve. `axis: "auto"` hands the same rule to physics *and* bend: a row
877
+ overflows → horizontal, only the column overflows → vertical, so one init
878
+ serves the desktop row and the mobile stack.
879
+
880
+ ```html
881
+ <div class="rail-screen"> <!-- position: relative; overflow: hidden -->
882
+ <div data-rail>
883
+ <article class="rail-card"><img src="card-01.jpg" alt="" /><p>Night Atlas</p></article>
884
+ <article class="rail-card"><img src="card-02.jpg" alt="" /><p>Signal Bloom</p></article>
885
+ </div>
886
+ </div>
887
+ ```
888
+
889
+ ```ts
890
+ import { glRail } from "@cosmictraveler002/anim-kit/three";
891
+
892
+ glRail("[data-rail]", { radius: 1200, grid: true, throwScale: 14 });
893
+ ```
894
+
895
+ | Option | Default | Notes |
896
+ | --- | --- | --- |
897
+ | `viewport` | track's parent | the stage the canvas covers — keep it `overflow: hidden` |
898
+ | `card` | `":scope > *"` | cards re-rendered — each needs an `<img>` |
899
+ | `axis` | `"auto"` | `"x"` / `"y"` / `"auto"` — picks motion **and** bend axis |
900
+ | `radius` | `1200` | cylinder radius the cards bend around, px |
901
+ | `corner` | `16` | corner radius, px (SDF, not `border-radius`) |
902
+ | `grid` | `true` | perspective grid floor under the cards |
903
+ | `dpr` | `2` | device-pixel-ratio cap |
904
+ | `lerp` / `edge` / `throwScale` / `wheel` / `onTick` | `0.1` / `140` / `14` / `true` / — | `dragRail` physics passthrough |
905
+ | `force` | `false` | run even under `prefers-reduced-motion` |
906
+
907
+ **Silent no-op ladder.** Missing target → no-op; no `WebGLRenderingContext`
908
+ (SSR, jsdom, WebGL disabled) → the **flat `dragRail` rail** still runs
909
+ (plain `<img>`s, full motion) *before* any context probe; renderer refused
910
+ → flat rail; texture 404 → that one card keeps its image; reduced motion →
911
+ nothing mounts. Nothing ever logs. `destroy()` unwinds physics + GPU
912
+ together (listeners, ticker, observers, geometry, materials, textures,
913
+ renderer, canvas) and restores image opacities + the stage's inline
914
+ position.
915
+
916
+ **DOM.** Stage `position: relative; overflow: hidden` with a transparent
917
+ card background; the track is a flex row (or `flex-direction: column; width:
918
+ 100%; height: max-content` for the vertical layout) with `cursor: grab;
919
+ user-select: none`.
920
+
850
921
  ---
851
922
 
852
923
  ### Loops & marquees
@@ -929,14 +1000,17 @@ GSAP's `deltaRatio`, so the settle rate is framerate-independent), past
929
1000
  either end the intent squashes through a tanh rubber-band
930
1001
  (`edge * tanh(overshoot / edge)` — pull further, gain less, never a hard
931
1002
  stop), and a release coasts on velocity sampled over the last few frames.
1003
+ Horizontal by default; `axis: "auto"` flips the rail vertical when only the
1004
+ column overflows, so a mobile card stack needs no re-init.
932
1005
 
933
1006
  ```ts
934
- dragRail("[data-rail]", { tilt: 0.05, throwScale: 14, wheel: true });
1007
+ dragRail("[data-rail]", { tilt: 0.05, throwScale: 14, wheel: true, axis: "auto" });
935
1008
  ```
936
1009
 
937
1010
  | Option | Default | Notes |
938
1011
  | --- | --- | --- |
939
1012
  | `viewport` | track's parent | scroll viewport around the track |
1013
+ | `axis` | `"x"` | `"x"` / `"y"` / `"auto"` — auto follows the layout (`pan-y` / `pan-x` claims the rail's own gesture) |
940
1014
  | `item` | `":scope > *"` | children that tilt with velocity |
941
1015
  | `lerp` | `0.1` | follow speed toward intent, per 60fps frame (0..1) |
942
1016
  | `edge` | `140` | rubber-band resistance distance past the ends, px |
@@ -959,6 +1033,13 @@ wheel passes through to the page — the section never traps the reader. When
959
1033
  input stops, a restore force springs any overscrolled intent home while the
960
1034
  lerp chases it.
961
1035
 
1036
+ **Two axes.** `axis: "auto"` re-resolves on every measure (only the column
1037
+ overflows → vertical) and re-keys the transform on a flip instead of leaving
1038
+ the stale axis behind — resize across the breakpoint and the rail just
1039
+ follows. **vs `glRail`**: the identical physics runs beneath `glRail`'s
1040
+ WebGL overlay (bent cards + grid floor, `/three` subpath) — use plain
1041
+ `dragRail` for DOM media, `glRail` when the pictures should curve.
1042
+
962
1043
  **DOM:** same shape as `dragStrip` — `overflow: hidden` viewport, flex track
963
1044
  of `width: max-content`; the effect sets inline `cursor` / `user-select` /
964
1045
  `touch-action` and clears them plus the transform/tilt on `destroy()`. Feed