@cosmictraveler002/anim-kit 1.3.0 → 1.4.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.4.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.4.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.4.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.4.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.4.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.4.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.4.0/dist/index.js",
152
+ "@cosmictraveler002/anim-kit/three": "https://cdn.jsdelivr.net/npm/@cosmictraveler002/anim-kit@1.4.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.4.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
@@ -320,7 +320,7 @@ prompt dock, and backs the `category` / `subcategory` fields on
320
320
  | Scroll & media | Parallax & depth | `parallax` |
321
321
  | Scroll & media | Heroes & media | `heroShrink`, `mediaSettle` |
322
322
  | Scroll & media | Enter reveals | `revealRule`, `unfoldReveal`, `clipWipe` |
323
- | WebGL | Shader media | `webglMedia` |
323
+ | WebGL | Shader media | `webglMedia`, `glRail` |
324
324
  | Loops & marquees | Marquees | `marquee` |
325
325
  | Loops & marquees | Draggables & rails | `dragStrip`, `dragRail` |
326
326
  | Loops & marquees | Equalizers | `audioBars` |
@@ -847,6 +847,68 @@ alt text in its `<img>`; the canvas takes over only after the texture has
847
847
  loaded. `destroy()` kills ticker + tweens + resize observer and disposes
848
848
  geometry, material, texture and renderer.
849
849
 
850
+ #### `glRail(track, options?) => destroy`
851
+
852
+ > From `@cosmictraveler002/anim-kit/three`, not the core barrel.
853
+
854
+ The bounded drag rail drawn as a **WebGL overlay**: one fixed alpha canvas
855
+ covers the stage and re-creates every card's picture from its DOM rect each
856
+ frame, with the surface bent around an invisible cylinder — `dragRail`'s
857
+ physics (intent/pos ticker, tanh rubber-band, throw momentum, Lenis-safe
858
+ wheel) underneath, and a perspective grid floor that fades into the horizon
859
+ and drifts with the rail. The DOM keeps layout, labels and hit areas: the
860
+ canvas paints *under* the track, so a caption sits over the GL media for
861
+ free, and only each `<img>` gets hidden — after its texture has loaded.
862
+
863
+ The bend is one uniform per card in the vertex shader: each vertex maps its
864
+ offset onto the cylinder (`a = o / R`, `x = R·sin a`, `z = −R·(1−cos a)`)
865
+ re-centred on the card's own middle — the centre stays glued to the DOM
866
+ position while the edges foreshorten, and the rotation arrives free from the
867
+ curve. `axis: "auto"` hands the same rule to physics *and* bend: a row
868
+ overflows → horizontal, only the column overflows → vertical, so one init
869
+ serves the desktop row and the mobile stack.
870
+
871
+ ```html
872
+ <div class="rail-screen"> <!-- position: relative; overflow: hidden -->
873
+ <div data-rail>
874
+ <article class="rail-card"><img src="card-01.jpg" alt="" /><p>Night Atlas</p></article>
875
+ <article class="rail-card"><img src="card-02.jpg" alt="" /><p>Signal Bloom</p></article>
876
+ </div>
877
+ </div>
878
+ ```
879
+
880
+ ```ts
881
+ import { glRail } from "@cosmictraveler002/anim-kit/three";
882
+
883
+ glRail("[data-rail]", { radius: 1200, grid: true, throwScale: 14 });
884
+ ```
885
+
886
+ | Option | Default | Notes |
887
+ | --- | --- | --- |
888
+ | `viewport` | track's parent | the stage the canvas covers — keep it `overflow: hidden` |
889
+ | `card` | `":scope > *"` | cards re-rendered — each needs an `<img>` |
890
+ | `axis` | `"auto"` | `"x"` / `"y"` / `"auto"` — picks motion **and** bend axis |
891
+ | `radius` | `1200` | cylinder radius the cards bend around, px |
892
+ | `corner` | `16` | corner radius, px (SDF, not `border-radius`) |
893
+ | `grid` | `true` | perspective grid floor under the cards |
894
+ | `dpr` | `2` | device-pixel-ratio cap |
895
+ | `lerp` / `edge` / `throwScale` / `wheel` / `onTick` | `0.1` / `140` / `14` / `true` / — | `dragRail` physics passthrough |
896
+ | `force` | `false` | run even under `prefers-reduced-motion` |
897
+
898
+ **Silent no-op ladder.** Missing target → no-op; no `WebGLRenderingContext`
899
+ (SSR, jsdom, WebGL disabled) → the **flat `dragRail` rail** still runs
900
+ (plain `<img>`s, full motion) *before* any context probe; renderer refused
901
+ → flat rail; texture 404 → that one card keeps its image; reduced motion →
902
+ nothing mounts. Nothing ever logs. `destroy()` unwinds physics + GPU
903
+ together (listeners, ticker, observers, geometry, materials, textures,
904
+ renderer, canvas) and restores image opacities + the stage's inline
905
+ position.
906
+
907
+ **DOM.** Stage `position: relative; overflow: hidden` with a transparent
908
+ card background; the track is a flex row (or `flex-direction: column; width:
909
+ 100%; height: max-content` for the vertical layout) with `cursor: grab;
910
+ user-select: none`.
911
+
850
912
  ---
851
913
 
852
914
  ### Loops & marquees
@@ -929,14 +991,17 @@ GSAP's `deltaRatio`, so the settle rate is framerate-independent), past
929
991
  either end the intent squashes through a tanh rubber-band
930
992
  (`edge * tanh(overshoot / edge)` — pull further, gain less, never a hard
931
993
  stop), and a release coasts on velocity sampled over the last few frames.
994
+ Horizontal by default; `axis: "auto"` flips the rail vertical when only the
995
+ column overflows, so a mobile card stack needs no re-init.
932
996
 
933
997
  ```ts
934
- dragRail("[data-rail]", { tilt: 0.05, throwScale: 14, wheel: true });
998
+ dragRail("[data-rail]", { tilt: 0.05, throwScale: 14, wheel: true, axis: "auto" });
935
999
  ```
936
1000
 
937
1001
  | Option | Default | Notes |
938
1002
  | --- | --- | --- |
939
1003
  | `viewport` | track's parent | scroll viewport around the track |
1004
+ | `axis` | `"x"` | `"x"` / `"y"` / `"auto"` — auto follows the layout (`pan-y` / `pan-x` claims the rail's own gesture) |
940
1005
  | `item` | `":scope > *"` | children that tilt with velocity |
941
1006
  | `lerp` | `0.1` | follow speed toward intent, per 60fps frame (0..1) |
942
1007
  | `edge` | `140` | rubber-band resistance distance past the ends, px |
@@ -959,6 +1024,13 @@ wheel passes through to the page — the section never traps the reader. When
959
1024
  input stops, a restore force springs any overscrolled intent home while the
960
1025
  lerp chases it.
961
1026
 
1027
+ **Two axes.** `axis: "auto"` re-resolves on every measure (only the column
1028
+ overflows → vertical) and re-keys the transform on a flip instead of leaving
1029
+ the stale axis behind — resize across the breakpoint and the rail just
1030
+ follows. **vs `glRail`**: the identical physics runs beneath `glRail`'s
1031
+ WebGL overlay (bent cards + grid floor, `/three` subpath) — use plain
1032
+ `dragRail` for DOM media, `glRail` when the pictures should curve.
1033
+
962
1034
  **DOM:** same shape as `dragStrip` — `overflow: hidden` viewport, flex track
963
1035
  of `width: max-content`; the effect sets inline `cursor` / `user-select` /
964
1036
  `touch-action` and clears them plus the transform/tilt on `destroy()`. Feed