@yewdiel21/motion-kit 0.0.0-stage → 0.9.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/NOTICE +38 -0
- package/README.md +80 -2
- package/bin/motion-kit.mjs +242 -0
- package/css.d.ts +2 -0
- package/dist/auto/index.d.ts +63 -0
- package/dist/auto/index.js +207 -0
- package/dist/auto/index.js.map +1 -0
- package/dist/chunk-2BQGFOA7.js +177 -0
- package/dist/chunk-2BQGFOA7.js.map +1 -0
- package/dist/chunk-34XYOXHG.js +2374 -0
- package/dist/chunk-34XYOXHG.js.map +1 -0
- package/dist/chunk-6OJAP6ZL.js +832 -0
- package/dist/chunk-6OJAP6ZL.js.map +1 -0
- package/dist/chunk-ABNRDDO7.js +28 -0
- package/dist/chunk-ABNRDDO7.js.map +1 -0
- package/dist/chunk-FS2HJVVY.js +3320 -0
- package/dist/chunk-FS2HJVVY.js.map +1 -0
- package/dist/chunk-J27KH2A2.js +157 -0
- package/dist/chunk-J27KH2A2.js.map +1 -0
- package/dist/chunk-KLY5BRRI.js +18 -0
- package/dist/chunk-KLY5BRRI.js.map +1 -0
- package/dist/chunk-Q4LVFNLN.js +1617 -0
- package/dist/chunk-Q4LVFNLN.js.map +1 -0
- package/dist/chunk-RFDIZYFX.js +304 -0
- package/dist/chunk-RFDIZYFX.js.map +1 -0
- package/dist/chunk-TGV27ZWM.js +17 -0
- package/dist/chunk-TGV27ZWM.js.map +1 -0
- package/dist/confetti-BSX1CLLV.d.ts +41 -0
- package/dist/css/components/chat-background.css +87 -0
- package/dist/css/components/chat.css +237 -0
- package/dist/css/components/cursor.css +178 -0
- package/dist/css/components/dialog.css +259 -0
- package/dist/css/components/island.css +301 -0
- package/dist/css/components/menu.css +105 -0
- package/dist/css/components/nav.css +1054 -0
- package/dist/css/components/steps.css +50 -0
- package/dist/css/components/theme-picker.css +115 -0
- package/dist/css/components/toast.css +115 -0
- package/dist/css/controls.css +950 -0
- package/dist/css/effects.css +587 -0
- package/dist/css/fonts.css +3 -0
- package/dist/css/themes/black-green.css +126 -0
- package/dist/css/themes/black.css +126 -0
- package/dist/css/themes/blue.css +126 -0
- package/dist/css/themes/brown.css +126 -0
- package/dist/css/themes/cold-blue.css +126 -0
- package/dist/css/themes/funny.css +126 -0
- package/dist/css/themes/gray.css +126 -0
- package/dist/css/themes/green.css +126 -0
- package/dist/css/themes/modern-1.css +126 -0
- package/dist/css/themes/neogreen.css +126 -0
- package/dist/css/themes/new.css +126 -0
- package/dist/css/themes/new2.css +126 -0
- package/dist/css/themes/oled.css +126 -0
- package/dist/css/themes/orange.css +126 -0
- package/dist/css/themes/pastel-pink.css +126 -0
- package/dist/css/themes/pink.css +126 -0
- package/dist/css/themes/purple.css +126 -0
- package/dist/css/themes/red.css +126 -0
- package/dist/css/themes/super-blue.css +126 -0
- package/dist/css/themes.css +2431 -0
- package/dist/css/tokens.css +452 -0
- package/dist/elements/index.d.ts +183 -0
- package/dist/elements/index.js +472 -0
- package/dist/elements/index.js.map +1 -0
- package/dist/engine-CUr9QijM.d.ts +46 -0
- package/dist/gl/index.d.ts +61 -0
- package/dist/gl/index.js +18 -0
- package/dist/gl/index.js.map +1 -0
- package/dist/index.css +5296 -0
- package/dist/index.d.ts +440 -0
- package/dist/index.js +390 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.d.ts +476 -0
- package/dist/react/index.js +969 -0
- package/dist/react/index.js.map +1 -0
- package/dist/reduced-BM4Ls0g5.d.ts +566 -0
- package/dist/reveal-WFUWDrei.d.ts +416 -0
- package/dist/store-Bqy_obnD.d.ts +195 -0
- package/dist/theme/generate.d.ts +18 -0
- package/dist/theme/generate.js +64 -0
- package/dist/theme/generate.js.map +1 -0
- package/dist/theme/index.d.ts +17 -0
- package/dist/theme/index.js +32 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme-BFMoCzi6.d.ts +158 -0
- package/dist/types-BkS_raL8.d.ts +7 -0
- package/package.json +114 -3
- package/registry.json +469 -0
- package/skills/motion-kit/SKILL.md +189 -0
- package/skills/motion-kit/reference/components.md +86 -0
- package/skills/motion-kit/reference/design.md +92 -0
- package/skills/motion-kit/reference/recipes.md +172 -0
- package/src/auto/auto-init.ts +151 -0
- package/src/auto/index.ts +3 -0
- package/src/auto/parse-options.ts +68 -0
- package/src/components/chat/README.md +90 -0
- package/src/components/chat/chat.css +236 -0
- package/src/components/chat/element.ts +98 -0
- package/src/components/chat/engine.ts +295 -0
- package/src/components/chat/react.tsx +196 -0
- package/src/components/chat-background/README.md +50 -0
- package/src/components/chat-background/audio.ts +56 -0
- package/src/components/chat-background/chat-background.css +86 -0
- package/src/components/chat-background/element.ts +31 -0
- package/src/components/chat-background/engine.ts +108 -0
- package/src/components/chat-background/react.tsx +36 -0
- package/src/components/cursor/README.md +53 -0
- package/src/components/cursor/cursor.css +177 -0
- package/src/components/cursor/element.ts +23 -0
- package/src/components/cursor/engine.ts +254 -0
- package/src/components/cursor/react.tsx +26 -0
- package/src/components/dialog/README.md +106 -0
- package/src/components/dialog/dialog.css +258 -0
- package/src/components/dialog/element.ts +118 -0
- package/src/components/dialog/engine.ts +432 -0
- package/src/components/dialog/react.tsx +200 -0
- package/src/components/icon.tsx +10 -0
- package/src/components/icons.ts +24 -0
- package/src/components/island/README.md +91 -0
- package/src/components/island/element.ts +45 -0
- package/src/components/island/engine.ts +200 -0
- package/src/components/island/island.css +300 -0
- package/src/components/island/react.tsx +115 -0
- package/src/components/menu/README.md +67 -0
- package/src/components/menu/element.ts +55 -0
- package/src/components/menu/engine.ts +142 -0
- package/src/components/menu/menu.css +104 -0
- package/src/components/menu/react.tsx +82 -0
- package/src/components/nav/README.md +85 -0
- package/src/components/nav/element.ts +39 -0
- package/src/components/nav/engine.ts +164 -0
- package/src/components/nav/nav.css +1053 -0
- package/src/components/nav/react.tsx +90 -0
- package/src/components/steps/README.md +70 -0
- package/src/components/steps/element.ts +43 -0
- package/src/components/steps/engine.ts +185 -0
- package/src/components/steps/react.tsx +91 -0
- package/src/components/steps/steps.css +49 -0
- package/src/components/theme-picker/README.md +57 -0
- package/src/components/theme-picker/element.ts +20 -0
- package/src/components/theme-picker/engine.ts +91 -0
- package/src/components/theme-picker/react.tsx +31 -0
- package/src/components/theme-picker/theme-picker.css +114 -0
- package/src/components/toast/README.md +60 -0
- package/src/components/toast/element.ts +25 -0
- package/src/components/toast/engine.ts +483 -0
- package/src/components/toast/react.tsx +22 -0
- package/src/components/toast/store.ts +122 -0
- package/src/components/toast/toast.css +114 -0
- package/src/core/channels.ts +165 -0
- package/src/core/curves.ts +35 -0
- package/src/core/frame.ts +12 -0
- package/src/core/gsap.ts +65 -0
- package/src/core/loop.ts +44 -0
- package/src/core/math.ts +9 -0
- package/src/core/physics-spring.ts +59 -0
- package/src/core/pointer.ts +63 -0
- package/src/core/reduced.ts +21 -0
- package/src/core/scope.ts +70 -0
- package/src/core/scroll-track.ts +106 -0
- package/src/core/split.ts +68 -0
- package/src/core/spring.ts +22 -0
- package/src/core/styles.ts +31 -0
- package/src/core/timing.ts +204 -0
- package/src/core/types.ts +20 -0
- package/src/core/visible.ts +19 -0
- package/src/css/base.css +142 -0
- package/src/css/controls/README.md +122 -0
- package/src/css/controls/burger.css +67 -0
- package/src/css/controls/button.css +226 -0
- package/src/css/controls/checkbox.css +53 -0
- package/src/css/controls/chip.css +85 -0
- package/src/css/controls/field.css +124 -0
- package/src/css/controls/glass.css +220 -0
- package/src/css/controls/icon.css +26 -0
- package/src/css/controls/segmented.css +60 -0
- package/src/css/controls/switch.css +72 -0
- package/src/css/default-theme.css +123 -0
- package/src/css/effects/README.md +134 -0
- package/src/css/effects/anim.css +224 -0
- package/src/css/effects/fade.css +15 -0
- package/src/css/effects/float.css +64 -0
- package/src/css/effects/frost.css +62 -0
- package/src/css/effects/grain.css +58 -0
- package/src/css/effects/loading.css +60 -0
- package/src/css/effects/success.css +22 -0
- package/src/css/effects/text.css +67 -0
- package/src/css/fonts.css +3 -0
- package/src/css/states.css +51 -0
- package/src/css/themes/black-green.css +126 -0
- package/src/css/themes/black.css +126 -0
- package/src/css/themes/blue.css +126 -0
- package/src/css/themes/brown.css +126 -0
- package/src/css/themes/cold-blue.css +126 -0
- package/src/css/themes/funny.css +126 -0
- package/src/css/themes/gray.css +126 -0
- package/src/css/themes/green.css +126 -0
- package/src/css/themes/modern-1.css +126 -0
- package/src/css/themes/neogreen.css +126 -0
- package/src/css/themes/new.css +126 -0
- package/src/css/themes/new2.css +126 -0
- package/src/css/themes/oled.css +126 -0
- package/src/css/themes/orange.css +126 -0
- package/src/css/themes/pastel-pink.css +126 -0
- package/src/css/themes/pink.css +126 -0
- package/src/css/themes/purple.css +126 -0
- package/src/css/themes/red.css +126 -0
- package/src/css/themes/super-blue.css +126 -0
- package/src/css/tokens.css +182 -0
- package/src/elements/base.ts +76 -0
- package/src/elements/index.ts +48 -0
- package/src/gl/index.ts +15 -0
- package/src/gl/liquid-blend/README.md +23 -0
- package/src/gl/liquid-blend/create-liquid-blend.ts +7 -0
- package/src/gl/liquid-blend/shader.ts +9 -0
- package/src/gl/matcap/README.md +23 -0
- package/src/gl/matcap/create-matcap.ts +7 -0
- package/src/gl/matcap/shader.ts +16 -0
- package/src/gl/particle-hero/README.md +41 -0
- package/src/gl/particle-hero/create-particle-hero.ts +544 -0
- package/src/gl/particle-hero/particle-hero.css +19 -0
- package/src/gl/particle-hero/shaders.ts +84 -0
- package/src/gl/shader-blur/README.md +23 -0
- package/src/gl/shader-blur/create-shader-blur.ts +7 -0
- package/src/gl/shader-blur/shader.ts +11 -0
- package/src/gl/shader-grain/README.md +23 -0
- package/src/gl/shader-grain/create-shader-grain.ts +7 -0
- package/src/gl/shader-grain/shader.ts +6 -0
- package/src/gl/shared/create-shader-effect.ts +186 -0
- package/src/gl/shared/shader.css +3 -0
- package/src/gl/shared/shaders.ts +30 -0
- package/src/index.ts +177 -0
- package/src/motion/anchor.ts +45 -0
- package/src/motion/chat.ts +97 -0
- package/src/motion/confetti.ts +130 -0
- package/src/motion/count.ts +95 -0
- package/src/motion/details.ts +70 -0
- package/src/motion/drag-dismiss.ts +231 -0
- package/src/motion/effects.ts +81 -0
- package/src/motion/entrances.ts +27 -0
- package/src/motion/floating.ts +389 -0
- package/src/motion/flow.ts +115 -0
- package/src/motion/indicator.ts +44 -0
- package/src/motion/layout.ts +39 -0
- package/src/motion/liquid.ts +227 -0
- package/src/motion/morph.ts +540 -0
- package/src/motion/reveal.ts +112 -0
- package/src/motion/sheet.ts +65 -0
- package/src/motion/surface.ts +108 -0
- package/src/react/animated-number.tsx +30 -0
- package/src/react/flip-group.tsx +44 -0
- package/src/react/frost.tsx +33 -0
- package/src/react/index.ts +80 -0
- package/src/react/slot-text.tsx +44 -0
- package/src/react/theme-provider.tsx +42 -0
- package/src/react/use-card-dock.ts +9 -0
- package/src/react/use-cascade.ts +9 -0
- package/src/react/use-contrast.ts +9 -0
- package/src/react/use-counter.ts +8 -0
- package/src/react/use-curved-carousel.ts +10 -0
- package/src/react/use-depth-grid.ts +9 -0
- package/src/react/use-details.ts +7 -0
- package/src/react/use-dock-pill.ts +10 -0
- package/src/react/use-drag-ruler.ts +10 -0
- package/src/react/use-fill-text.ts +9 -0
- package/src/react/use-fit-text.ts +8 -0
- package/src/react/use-flow.ts +8 -0
- package/src/react/use-frame-zoom.ts +9 -0
- package/src/react/use-infinite-reel.ts +8 -0
- package/src/react/use-letters.ts +9 -0
- package/src/react/use-liquid-blend.ts +8 -0
- package/src/react/use-marquee.ts +9 -0
- package/src/react/use-mask-text.ts +9 -0
- package/src/react/use-matcap.ts +8 -0
- package/src/react/use-parallax.ts +9 -0
- package/src/react/use-particle-hero.ts +9 -0
- package/src/react/use-pile.ts +8 -0
- package/src/react/use-pop.ts +8 -0
- package/src/react/use-radial-menu.ts +10 -0
- package/src/react/use-recipe.ts +38 -0
- package/src/react/use-reflow.ts +9 -0
- package/src/react/use-repel-bento.ts +8 -0
- package/src/react/use-reveal.ts +8 -0
- package/src/react/use-rotator.ts +10 -0
- package/src/react/use-shader-blur.ts +8 -0
- package/src/react/use-shader-grain.ts +8 -0
- package/src/react/use-slot-text.ts +17 -0
- package/src/react/use-snap-strip.ts +9 -0
- package/src/react/use-sortable.ts +14 -0
- package/src/react/use-spring-cards.ts +8 -0
- package/src/react/use-stretch-footer.ts +20 -0
- package/src/react/use-tabs.ts +10 -0
- package/src/react/use-text-roll.ts +9 -0
- package/src/react/use-ticket-menu.ts +15 -0
- package/src/react/use-words.ts +8 -0
- package/src/recipes/card-dock/README.md +36 -0
- package/src/recipes/card-dock/card-dock.css +178 -0
- package/src/recipes/card-dock/create-card-dock.ts +97 -0
- package/src/recipes/cascade/README.md +33 -0
- package/src/recipes/cascade/create-cascade.ts +111 -0
- package/src/recipes/contrast/README.md +29 -0
- package/src/recipes/contrast/create-contrast.ts +68 -0
- package/src/recipes/counter/README.md +42 -0
- package/src/recipes/counter/create-counter.ts +84 -0
- package/src/recipes/curved-carousel/README.md +50 -0
- package/src/recipes/curved-carousel/carousel-math.ts +20 -0
- package/src/recipes/curved-carousel/create-curved-carousel.ts +257 -0
- package/src/recipes/curved-carousel/curved-carousel.css +50 -0
- package/src/recipes/depth-grid/README.md +30 -0
- package/src/recipes/depth-grid/create-depth-grid.ts +120 -0
- package/src/recipes/details/README.md +31 -0
- package/src/recipes/details/create-details.ts +27 -0
- package/src/recipes/dock-pill/README.md +23 -0
- package/src/recipes/dock-pill/create-dock-pill.ts +68 -0
- package/src/recipes/dock-pill/dock-pill.css +5 -0
- package/src/recipes/drag-ruler/README.md +21 -0
- package/src/recipes/drag-ruler/create-drag-ruler.ts +95 -0
- package/src/recipes/drag-ruler/drag-ruler.css +16 -0
- package/src/recipes/fill-text/README.md +27 -0
- package/src/recipes/fill-text/create-fill-text.ts +93 -0
- package/src/recipes/fit-text/README.md +37 -0
- package/src/recipes/fit-text/create-fit-text.ts +55 -0
- package/src/recipes/fit-text/fit-text.css +6 -0
- package/src/recipes/flow/README.md +46 -0
- package/src/recipes/flow/create-flow.ts +55 -0
- package/src/recipes/frame-zoom/README.md +29 -0
- package/src/recipes/frame-zoom/create-frame-zoom.ts +91 -0
- package/src/recipes/infinite-reel/README.md +23 -0
- package/src/recipes/infinite-reel/create-infinite-reel.ts +140 -0
- package/src/recipes/infinite-reel/infinite-reel.css +8 -0
- package/src/recipes/letters/README.md +30 -0
- package/src/recipes/letters/create-letters.ts +113 -0
- package/src/recipes/marquee/README.md +32 -0
- package/src/recipes/marquee/create-marquee.ts +74 -0
- package/src/recipes/marquee/marquee.css +41 -0
- package/src/recipes/mask-text/README.md +39 -0
- package/src/recipes/mask-text/create-mask-text.ts +134 -0
- package/src/recipes/parallax/README.md +31 -0
- package/src/recipes/parallax/create-parallax.ts +74 -0
- package/src/recipes/pile/README.md +48 -0
- package/src/recipes/pile/create-pile.ts +50 -0
- package/src/recipes/pile/pile-math.ts +27 -0
- package/src/recipes/pile/pile.css +63 -0
- package/src/recipes/pill/README.md +30 -0
- package/src/recipes/pill/pill.css +48 -0
- package/src/recipes/pop/README.md +36 -0
- package/src/recipes/pop/create-pop.ts +52 -0
- package/src/recipes/radial-menu/README.md +44 -0
- package/src/recipes/radial-menu/create-radial-menu.ts +96 -0
- package/src/recipes/radial-menu/radial-menu.css +45 -0
- package/src/recipes/reflow/README.md +47 -0
- package/src/recipes/reflow/create-reflow.ts +49 -0
- package/src/recipes/repel-bento/README.md +21 -0
- package/src/recipes/repel-bento/create-repel-bento.ts +65 -0
- package/src/recipes/repel-bento/repel-bento.css +3 -0
- package/src/recipes/reveal/README.md +36 -0
- package/src/recipes/reveal/create-reveal.ts +48 -0
- package/src/recipes/rotator/README.md +21 -0
- package/src/recipes/rotator/create-rotator.ts +66 -0
- package/src/recipes/rotator/rotator.css +3 -0
- package/src/recipes/slot-text/README.md +44 -0
- package/src/recipes/slot-text/create-slot-text.ts +244 -0
- package/src/recipes/slot-text/slot-text.css +42 -0
- package/src/recipes/snap-strip/README.md +31 -0
- package/src/recipes/snap-strip/create-snap-strip.ts +133 -0
- package/src/recipes/snap-strip/snap-strip.css +23 -0
- package/src/recipes/sortable/README.md +88 -0
- package/src/recipes/sortable/create-sortable.ts +863 -0
- package/src/recipes/sortable/sortable.css +40 -0
- package/src/recipes/spring-cards/README.md +48 -0
- package/src/recipes/spring-cards/create-spring-cards.ts +140 -0
- package/src/recipes/spring-cards/spring-cards.css +23 -0
- package/src/recipes/stretch-footer/README.md +44 -0
- package/src/recipes/stretch-footer/create-stretch-footer.ts +69 -0
- package/src/recipes/stretch-footer/stretch-footer.css +28 -0
- package/src/recipes/tabs/README.md +39 -0
- package/src/recipes/tabs/create-tabs.ts +91 -0
- package/src/recipes/tabs/tabs.css +19 -0
- package/src/recipes/text-roll/README.md +35 -0
- package/src/recipes/text-roll/create-text-roll.ts +137 -0
- package/src/recipes/text-roll/text-roll.css +21 -0
- package/src/recipes/ticket-menu/README.md +24 -0
- package/src/recipes/ticket-menu/create-ticket-menu.ts +6 -0
- package/src/recipes/words/README.md +43 -0
- package/src/recipes/words/create-words.ts +114 -0
- package/src/theme/css-format.ts +32 -0
- package/src/theme/generate.ts +72 -0
- package/src/theme/index.ts +15 -0
- package/src/theme/presets.ts +79 -0
- package/src/theme/theme.ts +119 -0
package/NOTICE
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
motion-kit
|
|
2
|
+
Copyright 2026 Yewdiel Medina. All rights reserved.
|
|
3
|
+
|
|
4
|
+
The recipes and motion functions re-implement motion parameters observed in the
|
|
5
|
+
public frontends of spencergabor.com and of the Stepbro apps (Tasks, Money),
|
|
6
|
+
recovered with the REA reverse-engineering tools for study. No source code,
|
|
7
|
+
images or fonts from those sites are included in this repository or in the
|
|
8
|
+
published package.
|
|
9
|
+
|
|
10
|
+
The 19 theme palettes (css/themes/*.css, css/default-theme.css) reproduce the
|
|
11
|
+
colour values of Stepbro's themes as data, and the controls reproduce the sizes
|
|
12
|
+
of its Material Web overrides. Fonts (DM Sans, Geist Mono, Material Symbols) are
|
|
13
|
+
loaded from Google Fonts, not bundled.
|
|
14
|
+
|
|
15
|
+
The glass control, progressive frost, floating tags, success confetti and
|
|
16
|
+
sheet dialog reproduce parameters observed in dousanmiao.com; the burger icon
|
|
17
|
+
and rolling button reproduce timings of siena.film's public CSS. No code from
|
|
18
|
+
their bundles is included; the film grain is an original CSS approximation.
|
|
19
|
+
The text and scroll recipes and the cursors (v0.6) reproduce parameters
|
|
20
|
+
observed in offficestud.io (masked type), siena.film (slot title, reveal group,
|
|
21
|
+
parallax, depth grid, video mask, header contrast, marquee, dot cursor) and
|
|
22
|
+
dousanmiao.com (hero letters, glass chip cursor); they are original code.
|
|
23
|
+
The island navbar, card dock, snap strip, fill text and particle hero (v0.7)
|
|
24
|
+
reproduce parameters observed in iyo.ai (floating navbar, product dock, phone
|
|
25
|
+
cards, fill-text, GPU particle hero); they are original code. The particle hero
|
|
26
|
+
is an own WebGL2 implementation of the observed mechanism, with its own shaders
|
|
27
|
+
and locally drawn words: no iyo.ai code, shaders, images, models or fonts.
|
|
28
|
+
|
|
29
|
+
The collections (v0.8) re-implement Siena's ticket menu and inertial reels and
|
|
30
|
+
Dousan's bento entry/repulsion, testimonials, years ruler and active dock pill.
|
|
31
|
+
The image effects (v0.9) use original WebGL shaders: OFFFICE's liquid/matcap
|
|
32
|
+
mechanisms adapted to images and an analytic sphere, and Siena's observed
|
|
33
|
+
grain intensity and directional blur weights. No third-party shaders, models,
|
|
34
|
+
images or fonts are redistributed. Playground SVG illustrations are original.
|
|
35
|
+
|
|
36
|
+
Parts of the Stepbro recipes, the spring channels, slot text, swatches, flip
|
|
37
|
+
group and animated number reuse code written by the same author for Kayro
|
|
38
|
+
(Apache License 2.0).
|
package/README.md
CHANGED
|
@@ -1,3 +1,81 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @yewdiel21/motion-kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Motion toolkit for vanilla JavaScript, Astro and React/Next.js. GSAP recipes, accessible UI components, 19 Material 3 themes, CSS controls and optional WebGL effects.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @yewdiel21/motion-kit gsap
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
For React components, install React 18 or newer. The theme generator additionally requires `@material/material-color-utilities@^0.3.0`.
|
|
12
|
+
|
|
13
|
+
## Vanilla / Astro
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import '@yewdiel21/motion-kit/css';
|
|
17
|
+
import { autoInit } from '@yewdiel21/motion-kit/auto';
|
|
18
|
+
|
|
19
|
+
const destroy = autoInit(document);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<div class="mk-segmented" data-mk="tabs">
|
|
24
|
+
<button data-mk-tab aria-selected="true">Today</button>
|
|
25
|
+
<button data-mk-tab>Week</button>
|
|
26
|
+
<span data-mk-indicator></span>
|
|
27
|
+
</div>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Call `destroy()` before replacing the DOM. Add `MK_HEAD_SCRIPT` from `/auto` inline to `<head>` when using entrance recipes, and `defineElements()` from `/elements` to register the `mk-*` custom elements.
|
|
31
|
+
|
|
32
|
+
## React / Next.js
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
'use client';
|
|
36
|
+
|
|
37
|
+
import '@yewdiel21/motion-kit/css';
|
|
38
|
+
import { useRef } from 'react';
|
|
39
|
+
import { useTabs } from '@yewdiel21/motion-kit/react';
|
|
40
|
+
|
|
41
|
+
export function Tabs() {
|
|
42
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
43
|
+
useTabs(ref);
|
|
44
|
+
return (
|
|
45
|
+
<div ref={ref} className="mk-segmented">
|
|
46
|
+
<button data-mk-tab aria-selected="true">Today</button>
|
|
47
|
+
<button data-mk-tab>Week</button>
|
|
48
|
+
<span data-mk-indicator="" />
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Hooks create the engine after mount and destroy it on unmount. Import themes separately from `/css/themes`, fonts from `/css/fonts`, and theme utilities from `/theme`.
|
|
55
|
+
|
|
56
|
+
## Copy source with the CLI
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
npx @yewdiel21/motion-kit list
|
|
60
|
+
npx @yewdiel21/motion-kit add tabs island drag-ruler --react --elements --dir src/motion-kit
|
|
61
|
+
npx @yewdiel21/motion-kit skill
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The CLI copies the selected components, their dependencies and CSS. Each copied folder includes its README. It does not overwrite files without `--force`.
|
|
65
|
+
|
|
66
|
+
## Entry points
|
|
67
|
+
|
|
68
|
+
| Import | Contents |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `@yewdiel21/motion-kit` | Factories, motion functions, easings and timing constants |
|
|
71
|
+
| `/auto` | Declarative `data-mk` initialization and head script |
|
|
72
|
+
| `/react` | Hooks and React components |
|
|
73
|
+
| `/elements` | Custom elements |
|
|
74
|
+
| `/theme` | Theme runtime and head script |
|
|
75
|
+
| `/theme/generate` | Optional Material 3 palette generator |
|
|
76
|
+
| `/gl` | Particle hero, liquid blend, matcap, shader grain and blur |
|
|
77
|
+
| `/css`, `/css/themes`, `/css/fonts` | Styles, theme palettes and font imports |
|
|
78
|
+
|
|
79
|
+
WebGL is optional. Keep accessible text and images in HTML; effects provide a fallback when graphics support is unavailable. Motion recipes respect reduced-motion preferences and return an idempotent `destroy()`.
|
|
80
|
+
|
|
81
|
+
Full recipe documentation and the playground source are in the [repository](https://github.com/YewdielMartinez/motion-kit). Parameters and attribution are documented in `NOTICE` and the source READMEs. License: `UNLICENSED`; all rights reserved.
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// motion-kit CLI — copy recipes, components, controls and themes (and the Claude skill)
|
|
3
|
+
// out of the installed package, and generate themes from a colour.
|
|
4
|
+
// No dependencies: it reads src/, registry.json and skills/ shipped inside the package.
|
|
5
|
+
import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
import { dirname, join, posix, resolve } from 'node:path';
|
|
8
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
9
|
+
|
|
10
|
+
const PKG = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
11
|
+
const SRC = join(PKG, 'src');
|
|
12
|
+
const registry = JSON.parse(readFileSync(join(PKG, 'registry.json'), 'utf8'));
|
|
13
|
+
const entries = registry.entries;
|
|
14
|
+
const THEME_IDS = readdirSync(join(SRC, 'css', 'themes'))
|
|
15
|
+
.filter((file) => file.endsWith('.css'))
|
|
16
|
+
.map((file) => file.slice(0, -4))
|
|
17
|
+
.sort();
|
|
18
|
+
|
|
19
|
+
const argv = process.argv.slice(2);
|
|
20
|
+
const VALUE_FLAGS = new Set(['--dir', '--seed', '--out', '--variant']);
|
|
21
|
+
const flags = new Map();
|
|
22
|
+
const positional = [];
|
|
23
|
+
for (let i = 0; i < argv.length; i++) {
|
|
24
|
+
const arg = argv[i];
|
|
25
|
+
if (arg.startsWith('--')) {
|
|
26
|
+
const [name, inline] = arg.split('=');
|
|
27
|
+
if (VALUE_FLAGS.has(name)) flags.set(name, inline ?? argv[++i]);
|
|
28
|
+
else flags.set(name, true);
|
|
29
|
+
} else positional.push(arg);
|
|
30
|
+
}
|
|
31
|
+
const [command, ...names] = positional;
|
|
32
|
+
|
|
33
|
+
const out = (line = '') => process.stdout.write(`${line}\n`);
|
|
34
|
+
const fail = (message, code = 1) => {
|
|
35
|
+
process.stderr.write(`motion-kit: ${message}\n`);
|
|
36
|
+
process.exit(code);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function help() {
|
|
40
|
+
out('Usage: motion-kit <command> [options]');
|
|
41
|
+
out();
|
|
42
|
+
out(' list Show recipes, components, controls and themes');
|
|
43
|
+
out(' add <name...> [--react] [--elements]');
|
|
44
|
+
out(' Copy recipes/components/controls and the core they use');
|
|
45
|
+
out(' --dir <path> Destination (default: src/motion-kit)');
|
|
46
|
+
out(' --react Also copy the React hook / component');
|
|
47
|
+
out(' --elements Also copy the custom element of each component');
|
|
48
|
+
out(' --force Overwrite files that already exist');
|
|
49
|
+
out(' add theme <id...> Copy theme stylesheets (css/themes/<id>.css)');
|
|
50
|
+
out(' theme <id> --seed <#rrggbb> Generate a Material 3 theme stylesheet from a colour');
|
|
51
|
+
out(' --out <dir> Destination (default: src/styles)');
|
|
52
|
+
out(' --variant <name> tonal-spot (default), vibrant, expressive, neutral, content, fidelity, monochrome');
|
|
53
|
+
out(' skill [--global] [--force] Install the Claude Code skill into .claude/skills/ (or ~/.claude/skills/)');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Relative imports only (by design): from './x', from '../../core/x', import './x'
|
|
57
|
+
const IMPORT_RE = /(?:import|export)\s[^'"]*?from\s*['"](\.{1,2}\/[^'"]+)['"]|import\s*['"](\.{1,2}\/[^'"]+)['"]/g;
|
|
58
|
+
|
|
59
|
+
function resolveImport(fromFile, spec) {
|
|
60
|
+
const base = posix.normalize(posix.join(posix.dirname(fromFile), spec));
|
|
61
|
+
for (const candidate of [base, `${base}.ts`, `${base}.tsx`, `${base}/index.ts`]) {
|
|
62
|
+
const full = join(SRC, candidate);
|
|
63
|
+
if (existsSync(full) && statSync(full).isFile()) return candidate;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Entry files plus every source file they import, transitively. */
|
|
69
|
+
function closure(start) {
|
|
70
|
+
const seen = new Set();
|
|
71
|
+
const queue = [...start];
|
|
72
|
+
while (queue.length) {
|
|
73
|
+
const file = queue.shift();
|
|
74
|
+
if (seen.has(file)) continue;
|
|
75
|
+
if (!existsSync(join(SRC, file))) fail(`missing source file ${file} (broken package?)`, 2);
|
|
76
|
+
seen.add(file);
|
|
77
|
+
if (!/\.tsx?$/.test(file)) continue;
|
|
78
|
+
const code = readFileSync(join(SRC, file), 'utf8');
|
|
79
|
+
for (const match of code.matchAll(IMPORT_RE)) {
|
|
80
|
+
const spec = match[1] ?? match[2];
|
|
81
|
+
const resolved = resolveImport(file, spec);
|
|
82
|
+
if (!resolved) fail(`cannot resolve "${spec}" from ${file}`, 2);
|
|
83
|
+
queue.push(resolved);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return [...seen].filter((file) => !/\.test\.tsx?$/.test(file)).sort();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const GROUPS = [
|
|
90
|
+
['recipe', 'Recipes'],
|
|
91
|
+
['component', 'Components (--elements, --react)'],
|
|
92
|
+
['controls', 'Controls'],
|
|
93
|
+
['effects', 'Effects'],
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
function list() {
|
|
97
|
+
const width = Math.max(...Object.keys(entries).map((name) => name.length));
|
|
98
|
+
for (const [kind, title] of GROUPS) {
|
|
99
|
+
const group = Object.entries(entries).filter(([, entry]) => entry.kind === kind);
|
|
100
|
+
if (!group.length) continue;
|
|
101
|
+
out(`${title}:`);
|
|
102
|
+
for (const [name, entry] of group) out(` ${name.padEnd(width)} ${entry.description}`);
|
|
103
|
+
out();
|
|
104
|
+
}
|
|
105
|
+
out(`Themes (add theme <id>):`);
|
|
106
|
+
out(` ${THEME_IDS.join(', ')}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function copyInto(files) {
|
|
110
|
+
const dir = resolve(process.cwd(), flags.get('--dir') ?? 'src/motion-kit');
|
|
111
|
+
const existing = files.filter((file) => existsSync(join(dir, file)));
|
|
112
|
+
if (existing.length && !flags.has('--force')) {
|
|
113
|
+
fail(`these files already exist in ${dir}:\n ${existing.join('\n ')}\nRe-run with --force to overwrite them.`);
|
|
114
|
+
}
|
|
115
|
+
for (const file of files) {
|
|
116
|
+
const target = join(dir, file);
|
|
117
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
118
|
+
copyFileSync(join(SRC, file), target);
|
|
119
|
+
}
|
|
120
|
+
out(`Copied ${files.length} files into ${dir}:`);
|
|
121
|
+
for (const file of files) out(` ${file}`);
|
|
122
|
+
return dir;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function addThemes(ids) {
|
|
126
|
+
if (!ids.length) fail(`name at least one theme: ${THEME_IDS.join(', ')}`);
|
|
127
|
+
const unknown = ids.filter((id) => !THEME_IDS.includes(id));
|
|
128
|
+
if (unknown.length) fail(`unknown theme(s): ${unknown.join(', ')}\nAvailable: ${THEME_IDS.join(', ')}`);
|
|
129
|
+
const dir = copyInto(ids.map((id) => `css/themes/${id}.css`));
|
|
130
|
+
out();
|
|
131
|
+
out('Next steps:');
|
|
132
|
+
out(` 1. Import the stylesheets after the tokens, e.g. import './${posix.relative(process.cwd(), dir).split('\\').join('/')}/css/themes/${ids[0]}.css';`);
|
|
133
|
+
out(` 2. Set <html data-mk-theme="${ids[0]}"> (or call setTheme('${ids[0]}') from theme/theme.ts).`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function add() {
|
|
137
|
+
if (names[0] === 'theme') return addThemes(names.slice(1));
|
|
138
|
+
if (!names.length) fail('name at least one recipe or component. Run "motion-kit list".');
|
|
139
|
+
const unknown = names.filter((name) => !entries[name]);
|
|
140
|
+
if (unknown.length) {
|
|
141
|
+
process.stderr.write(`motion-kit: unknown name(s): ${unknown.join(', ')}\nAvailable:\n`);
|
|
142
|
+
list();
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
// Requested entries plus what they require, transitively.
|
|
146
|
+
const chosen = [];
|
|
147
|
+
const visit = (name) => {
|
|
148
|
+
if (chosen.includes(name)) return;
|
|
149
|
+
for (const dep of entries[name].requires ?? []) visit(dep);
|
|
150
|
+
chosen.push(name);
|
|
151
|
+
};
|
|
152
|
+
names.forEach(visit);
|
|
153
|
+
|
|
154
|
+
const withReact = flags.has('--react');
|
|
155
|
+
const withElements = flags.has('--elements');
|
|
156
|
+
const start = [
|
|
157
|
+
...registry.css,
|
|
158
|
+
...chosen.flatMap((name) => {
|
|
159
|
+
const entry = entries[name];
|
|
160
|
+
return [
|
|
161
|
+
...entry.files,
|
|
162
|
+
...(withReact && entry.react ? [entry.react] : []),
|
|
163
|
+
...(withElements && entry.element ? [entry.element] : []),
|
|
164
|
+
];
|
|
165
|
+
}),
|
|
166
|
+
];
|
|
167
|
+
const files = closure(start);
|
|
168
|
+
const dir = copyInto(files);
|
|
169
|
+
const rel = posix.relative(process.cwd(), dir).split('\\').join('/');
|
|
170
|
+
|
|
171
|
+
out();
|
|
172
|
+
out('Next steps:');
|
|
173
|
+
out(` 1. Install GSAP${withReact ? ' (and React)' : ''}: npm i gsap`);
|
|
174
|
+
out(' 2. Import the CSS once (tokens, default theme, base, entrance states, then each piece):');
|
|
175
|
+
for (const file of files.filter((file) => file.endsWith('.css'))) out(` import './${posix.join(rel, file)}';`);
|
|
176
|
+
out(' 3. Add MK_HEAD_SCRIPT (core/reduced.ts) inline in <head> to hide entrances until JS runs.');
|
|
177
|
+
const components = chosen.filter((name) => entries[name].kind === 'component');
|
|
178
|
+
if (withElements && components.length) {
|
|
179
|
+
out(' 4. Register the custom elements:');
|
|
180
|
+
for (const name of components) {
|
|
181
|
+
const pascal = name.replace(/(^|-)([a-z0-9])/g, (_, __, c) => c.toUpperCase());
|
|
182
|
+
out(` import { define${pascal} } from './${posix.join(rel, entries[name].element.replace(/\.ts$/, ''))}'; define${pascal}();`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
out(' Each folder has a README with markup and options.');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async function theme() {
|
|
189
|
+
const [id] = names;
|
|
190
|
+
const seed = flags.get('--seed');
|
|
191
|
+
if (!id || !/^[a-z][a-z0-9-]*$/.test(id)) fail('usage: motion-kit theme <kebab-id> --seed "#rrggbb" [--out dir]');
|
|
192
|
+
if (!seed || !/^#?[0-9a-f]{6}$/i.test(seed)) fail('--seed must be a colour like "#00e563"');
|
|
193
|
+
let generate;
|
|
194
|
+
try {
|
|
195
|
+
generate = await import(pathToFileURL(join(PKG, 'dist', 'theme', 'generate.js')).href);
|
|
196
|
+
} catch (error) {
|
|
197
|
+
if (String(error?.message).includes('material-color-utilities')) {
|
|
198
|
+
fail('the generator needs the optional peer: npm i -D @material/material-color-utilities@^0.3.0');
|
|
199
|
+
}
|
|
200
|
+
fail(`cannot load the generator (${error?.message ?? error}). Is the package built?`, 2);
|
|
201
|
+
}
|
|
202
|
+
const css = generate.themeCss(id, generate.generateTheme(seed, { variant: flags.get('--variant') }));
|
|
203
|
+
const dir = resolve(process.cwd(), flags.get('--out') ?? 'src/styles');
|
|
204
|
+
const target = join(dir, `${id}.css`);
|
|
205
|
+
if (existsSync(target) && !flags.has('--force')) fail(`${target} already exists. Re-run with --force to replace it.`);
|
|
206
|
+
mkdirSync(dir, { recursive: true });
|
|
207
|
+
writeFileSync(target, `/* Theme "${id}" generated by motion-kit from ${seed} (Material 3, ${flags.get('--variant') ?? 'tonal-spot'}). */\n${css}`);
|
|
208
|
+
out(`Wrote ${target}`);
|
|
209
|
+
out(`Import it after the motion-kit CSS and set <html data-mk-theme="${id}"> (or registerTheme('${id}') + setTheme('${id}')).`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function skill() {
|
|
213
|
+
const source = join(PKG, 'skills', 'motion-kit');
|
|
214
|
+
if (!existsSync(source)) fail('skill files are missing from the package', 2);
|
|
215
|
+
const base = flags.has('--global') ? join(homedir(), '.claude') : join(process.cwd(), '.claude');
|
|
216
|
+
const target = join(base, 'skills', 'motion-kit');
|
|
217
|
+
if (existsSync(target) && !flags.has('--force')) fail(`${target} already exists. Re-run with --force to replace it.`);
|
|
218
|
+
cpSync(source, target, { recursive: true, force: true });
|
|
219
|
+
out(`Installed the motion-kit skill in ${target}`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
switch (command) {
|
|
223
|
+
case 'list':
|
|
224
|
+
list();
|
|
225
|
+
break;
|
|
226
|
+
case 'add':
|
|
227
|
+
add();
|
|
228
|
+
break;
|
|
229
|
+
case 'theme':
|
|
230
|
+
await theme();
|
|
231
|
+
break;
|
|
232
|
+
case 'skill':
|
|
233
|
+
skill();
|
|
234
|
+
break;
|
|
235
|
+
case undefined:
|
|
236
|
+
case 'help':
|
|
237
|
+
help();
|
|
238
|
+
break;
|
|
239
|
+
default:
|
|
240
|
+
help();
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
package/css.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { c as createSpringCards, C as CurvedCarouselInstance, a as createPile, b as createWords, d as createFlow, e as createPop, f as createFitText, g as createStretchFooter, h as createRadialMenu, i as createTabs, j as createCounter, k as createReveal, l as createReflow, m as createSlotText, n as createSortable, o as createMaskText, p as createCascade, q as createTextRoll, r as createLetters, s as createParallax, t as createDepthGrid, u as createFrameZoom, v as createContrast, w as createMarquee, x as createCardDock, y as createSnapStrip, z as createFillText, T as TicketMenuOptions, A as TicketMenuInstance, B as createInfiniteReel, D as createRepelBento, E as createRotator, F as createDragRuler, G as createDockPill } from '../reduced-BM4Ls0g5.js';
|
|
2
|
+
export { M as MK_HEAD_SCRIPT } from '../reduced-BM4Ls0g5.js';
|
|
3
|
+
import { I as Instance } from '../types-BkS_raL8.js';
|
|
4
|
+
import '../reveal-WFUWDrei.js';
|
|
5
|
+
import 'gsap/SplitText';
|
|
6
|
+
|
|
7
|
+
declare const factories: {
|
|
8
|
+
'spring-cards': typeof createSpringCards;
|
|
9
|
+
'curved-carousel': (el: HTMLElement, options: Record<string, unknown>) => CurvedCarouselInstance;
|
|
10
|
+
pile: typeof createPile;
|
|
11
|
+
words: typeof createWords;
|
|
12
|
+
flow: typeof createFlow;
|
|
13
|
+
pop: typeof createPop;
|
|
14
|
+
'fit-text': typeof createFitText;
|
|
15
|
+
'stretch-footer': typeof createStretchFooter;
|
|
16
|
+
'radial-menu': typeof createRadialMenu;
|
|
17
|
+
tabs: typeof createTabs;
|
|
18
|
+
counter: typeof createCounter;
|
|
19
|
+
details: (el: HTMLElement) => Instance;
|
|
20
|
+
reveal: typeof createReveal;
|
|
21
|
+
reflow: typeof createReflow;
|
|
22
|
+
'slot-text': typeof createSlotText;
|
|
23
|
+
sortable: typeof createSortable;
|
|
24
|
+
'mask-text': typeof createMaskText;
|
|
25
|
+
cascade: typeof createCascade;
|
|
26
|
+
'text-roll': typeof createTextRoll;
|
|
27
|
+
letters: typeof createLetters;
|
|
28
|
+
parallax: typeof createParallax;
|
|
29
|
+
'depth-grid': typeof createDepthGrid;
|
|
30
|
+
'frame-zoom': typeof createFrameZoom;
|
|
31
|
+
contrast: typeof createContrast;
|
|
32
|
+
marquee: typeof createMarquee;
|
|
33
|
+
'card-dock': typeof createCardDock;
|
|
34
|
+
'snap-strip': typeof createSnapStrip;
|
|
35
|
+
'fill-text': typeof createFillText;
|
|
36
|
+
'ticket-menu': (root: HTMLElement | null, options?: TicketMenuOptions) => TicketMenuInstance;
|
|
37
|
+
'infinite-reel': typeof createInfiniteReel;
|
|
38
|
+
'repel-bento': typeof createRepelBento;
|
|
39
|
+
rotator: typeof createRotator;
|
|
40
|
+
'drag-ruler': typeof createDragRuler;
|
|
41
|
+
'dock-pill': typeof createDockPill;
|
|
42
|
+
};
|
|
43
|
+
type RecipeName = keyof typeof factories;
|
|
44
|
+
declare const recipeNames: RecipeName[];
|
|
45
|
+
interface AutoInitOptions {
|
|
46
|
+
/** Only start these recipes. */
|
|
47
|
+
only?: RecipeName[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Start every `[data-mk]` recipe inside `root` (an element may list several:
|
|
51
|
+
* `data-mk="fit-text words"`). Options come from `data-mk-*` attributes.
|
|
52
|
+
* Returns a function that destroys what this call created. Safe to call again:
|
|
53
|
+
* elements that already run a recipe are skipped.
|
|
54
|
+
*/
|
|
55
|
+
declare function autoInit(root?: ParentNode, { only }?: AutoInitOptions): () => void;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* `data-mk-<option>` attributes → options object.
|
|
59
|
+
* `data-mk-throw-boost="2.5"` → `{ throwBoost: 2.5 }`, `data-mk-trigger="load"` → `{ trigger: 'load' }`.
|
|
60
|
+
*/
|
|
61
|
+
declare function parseOptions(el: HTMLElement): Record<string, unknown>;
|
|
62
|
+
|
|
63
|
+
export { type AutoInitOptions, type RecipeName, autoInit, parseOptions, recipeNames };
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createCardDock,
|
|
3
|
+
createCascade,
|
|
4
|
+
createContrast,
|
|
5
|
+
createCounter,
|
|
6
|
+
createCurvedCarousel,
|
|
7
|
+
createDepthGrid,
|
|
8
|
+
createDetails,
|
|
9
|
+
createDockPill,
|
|
10
|
+
createDragRuler,
|
|
11
|
+
createFillText,
|
|
12
|
+
createFitText,
|
|
13
|
+
createFlow,
|
|
14
|
+
createFrameZoom,
|
|
15
|
+
createInfiniteReel,
|
|
16
|
+
createLetters,
|
|
17
|
+
createMarquee,
|
|
18
|
+
createMaskText,
|
|
19
|
+
createParallax,
|
|
20
|
+
createPile,
|
|
21
|
+
createPop,
|
|
22
|
+
createRadialMenu,
|
|
23
|
+
createReflow,
|
|
24
|
+
createRepelBento,
|
|
25
|
+
createReveal,
|
|
26
|
+
createRotator,
|
|
27
|
+
createSlotText,
|
|
28
|
+
createSnapStrip,
|
|
29
|
+
createSortable,
|
|
30
|
+
createSpringCards,
|
|
31
|
+
createStretchFooter,
|
|
32
|
+
createTabs,
|
|
33
|
+
createTextRoll,
|
|
34
|
+
createTicketMenu,
|
|
35
|
+
createWords
|
|
36
|
+
} from "../chunk-FS2HJVVY.js";
|
|
37
|
+
import {
|
|
38
|
+
ScrollTrigger
|
|
39
|
+
} from "../chunk-34XYOXHG.js";
|
|
40
|
+
import "../chunk-KLY5BRRI.js";
|
|
41
|
+
import {
|
|
42
|
+
MK_HEAD_SCRIPT
|
|
43
|
+
} from "../chunk-RFDIZYFX.js";
|
|
44
|
+
import {
|
|
45
|
+
warnOnce
|
|
46
|
+
} from "../chunk-TGV27ZWM.js";
|
|
47
|
+
|
|
48
|
+
// src/auto/parse-options.ts
|
|
49
|
+
var RESERVED = /* @__PURE__ */ new Set([
|
|
50
|
+
"",
|
|
51
|
+
"ready",
|
|
52
|
+
"inview",
|
|
53
|
+
"carousel",
|
|
54
|
+
"open",
|
|
55
|
+
"card",
|
|
56
|
+
"slide",
|
|
57
|
+
"toggle",
|
|
58
|
+
"item",
|
|
59
|
+
"phantom",
|
|
60
|
+
"footerTitle",
|
|
61
|
+
"tab",
|
|
62
|
+
"indicator",
|
|
63
|
+
"chevron",
|
|
64
|
+
"text",
|
|
65
|
+
"role",
|
|
66
|
+
"motion",
|
|
67
|
+
"veil",
|
|
68
|
+
"swatch",
|
|
69
|
+
"part",
|
|
70
|
+
"sorting",
|
|
71
|
+
"sortableGroup",
|
|
72
|
+
"sortableLocked",
|
|
73
|
+
"cascade",
|
|
74
|
+
"on",
|
|
75
|
+
"tone",
|
|
76
|
+
"cursorZone",
|
|
77
|
+
"hidden",
|
|
78
|
+
"pressed",
|
|
79
|
+
"parallaxTarget",
|
|
80
|
+
"spread",
|
|
81
|
+
"expanded",
|
|
82
|
+
"settled",
|
|
83
|
+
"mode",
|
|
84
|
+
"active",
|
|
85
|
+
"islandToggle",
|
|
86
|
+
"islandPanel",
|
|
87
|
+
"islandItem",
|
|
88
|
+
"islandClose",
|
|
89
|
+
"reelTrack",
|
|
90
|
+
"reelCopy",
|
|
91
|
+
"dragging",
|
|
92
|
+
"dockItem"
|
|
93
|
+
]);
|
|
94
|
+
var coerce = (value) => {
|
|
95
|
+
if (value === "" || value === "true") return true;
|
|
96
|
+
if (value === "false") return false;
|
|
97
|
+
if (/^-?\d*\.?\d+$/.test(value)) return Number(value);
|
|
98
|
+
return value;
|
|
99
|
+
};
|
|
100
|
+
function parseOptions(el) {
|
|
101
|
+
const options = {};
|
|
102
|
+
for (const [key, raw] of Object.entries(el.dataset)) {
|
|
103
|
+
if (!key.startsWith("mk") || key.length === 2) continue;
|
|
104
|
+
const name = key.charAt(2).toLowerCase() + key.slice(3);
|
|
105
|
+
if (RESERVED.has(name)) continue;
|
|
106
|
+
options[name] = coerce(raw ?? "");
|
|
107
|
+
}
|
|
108
|
+
return options;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/auto/auto-init.ts
|
|
112
|
+
var factories = {
|
|
113
|
+
"spring-cards": createSpringCards,
|
|
114
|
+
"curved-carousel": (el, options) => createCurvedCarousel(el, {
|
|
115
|
+
...options,
|
|
116
|
+
onSelect: (index, slide) => el.dispatchEvent(new CustomEvent("mk:select", { detail: { index, slide }, bubbles: true }))
|
|
117
|
+
}),
|
|
118
|
+
pile: createPile,
|
|
119
|
+
words: createWords,
|
|
120
|
+
flow: createFlow,
|
|
121
|
+
pop: createPop,
|
|
122
|
+
"fit-text": createFitText,
|
|
123
|
+
"stretch-footer": createStretchFooter,
|
|
124
|
+
"radial-menu": createRadialMenu,
|
|
125
|
+
tabs: createTabs,
|
|
126
|
+
counter: createCounter,
|
|
127
|
+
details: (el) => createDetails(el),
|
|
128
|
+
reveal: createReveal,
|
|
129
|
+
reflow: createReflow,
|
|
130
|
+
"slot-text": createSlotText,
|
|
131
|
+
sortable: createSortable,
|
|
132
|
+
"mask-text": createMaskText,
|
|
133
|
+
cascade: createCascade,
|
|
134
|
+
"text-roll": createTextRoll,
|
|
135
|
+
letters: createLetters,
|
|
136
|
+
parallax: createParallax,
|
|
137
|
+
"depth-grid": createDepthGrid,
|
|
138
|
+
"frame-zoom": createFrameZoom,
|
|
139
|
+
contrast: createContrast,
|
|
140
|
+
marquee: createMarquee,
|
|
141
|
+
"card-dock": createCardDock,
|
|
142
|
+
"snap-strip": createSnapStrip,
|
|
143
|
+
"fill-text": createFillText,
|
|
144
|
+
"ticket-menu": createTicketMenu,
|
|
145
|
+
"infinite-reel": createInfiniteReel,
|
|
146
|
+
"repel-bento": createRepelBento,
|
|
147
|
+
"rotator": createRotator,
|
|
148
|
+
"drag-ruler": createDragRuler,
|
|
149
|
+
"dock-pill": createDockPill
|
|
150
|
+
};
|
|
151
|
+
var recipeNames = Object.keys(factories);
|
|
152
|
+
var AFTER_FONTS = ["fit-text", "words", "slot-text"];
|
|
153
|
+
var instances = /* @__PURE__ */ new WeakMap();
|
|
154
|
+
function autoInit(root = document, { only } = {}) {
|
|
155
|
+
if (typeof window === "undefined") return () => {
|
|
156
|
+
};
|
|
157
|
+
const created = [];
|
|
158
|
+
let cancelled = false;
|
|
159
|
+
const elements = [...root.querySelectorAll("[data-mk]")];
|
|
160
|
+
if (root instanceof HTMLElement && root.matches("[data-mk]")) elements.unshift(root);
|
|
161
|
+
const start = (el, name) => {
|
|
162
|
+
if (cancelled) return;
|
|
163
|
+
const running = instances.get(el) ?? /* @__PURE__ */ new Map();
|
|
164
|
+
if (running.has(name)) return;
|
|
165
|
+
const instance = factories[name](el, parseOptions(el));
|
|
166
|
+
running.set(name, instance);
|
|
167
|
+
instances.set(el, running);
|
|
168
|
+
created.push([el, name, instance]);
|
|
169
|
+
};
|
|
170
|
+
const now = [];
|
|
171
|
+
const later = [];
|
|
172
|
+
for (const el of elements) {
|
|
173
|
+
for (const raw of (el.dataset.mk ?? "").split(/\s+/).filter(Boolean)) {
|
|
174
|
+
if (!(raw in factories)) {
|
|
175
|
+
warnOnce(`autoInit: unknown recipe "${raw}" (known: ${recipeNames.join(", ")})`);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const name = raw;
|
|
179
|
+
if (only && !only.includes(name)) continue;
|
|
180
|
+
(AFTER_FONTS.includes(name) ? later : now).push([el, name]);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
now.forEach(([el, name]) => start(el, name));
|
|
184
|
+
if (later.length) {
|
|
185
|
+
later.sort((a, b) => AFTER_FONTS.indexOf(a[1]) - AFTER_FONTS.indexOf(b[1]));
|
|
186
|
+
const fonts = document.fonts?.ready ?? Promise.resolve();
|
|
187
|
+
void Promise.race([fonts, new Promise((resolve) => setTimeout(resolve, 1500))]).then(() => {
|
|
188
|
+
later.forEach(([el, name]) => start(el, name));
|
|
189
|
+
if (!cancelled) ScrollTrigger.refresh();
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
return () => {
|
|
193
|
+
cancelled = true;
|
|
194
|
+
for (const [el, name, instance] of created.reverse()) {
|
|
195
|
+
instance.destroy();
|
|
196
|
+
instances.get(el)?.delete(name);
|
|
197
|
+
}
|
|
198
|
+
created.length = 0;
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
export {
|
|
202
|
+
MK_HEAD_SCRIPT,
|
|
203
|
+
autoInit,
|
|
204
|
+
parseOptions,
|
|
205
|
+
recipeNames
|
|
206
|
+
};
|
|
207
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/auto/parse-options.ts","../../src/auto/auto-init.ts"],"sourcesContent":["/** Attributes the recipes write themselves or use for children; never options. */\nconst RESERVED = new Set([\n '',\n 'ready',\n 'inview',\n 'carousel',\n 'open',\n 'card',\n 'slide',\n 'toggle',\n 'item',\n 'phantom',\n 'footerTitle',\n 'tab',\n 'indicator',\n 'chevron',\n 'text',\n 'role',\n 'motion',\n 'veil',\n 'swatch',\n 'part',\n 'sorting',\n 'sortableGroup',\n 'sortableLocked',\n 'cascade',\n 'on',\n 'tone',\n 'cursorZone',\n 'hidden',\n 'pressed',\n 'parallaxTarget',\n 'spread',\n 'expanded',\n 'settled',\n 'mode',\n 'active',\n 'islandToggle',\n 'islandPanel',\n 'islandItem',\n 'islandClose',\n 'reelTrack',\n 'reelCopy',\n 'dragging',\n 'dockItem',\n]);\n\nconst coerce = (value: string): unknown => {\n if (value === '' || value === 'true') return true;\n if (value === 'false') return false;\n if (/^-?\\d*\\.?\\d+$/.test(value)) return Number(value);\n return value;\n};\n\n/**\n * `data-mk-<option>` attributes → options object.\n * `data-mk-throw-boost=\"2.5\"` → `{ throwBoost: 2.5 }`, `data-mk-trigger=\"load\"` → `{ trigger: 'load' }`.\n */\nexport function parseOptions(el: HTMLElement): Record<string, unknown> {\n const options: Record<string, unknown> = {};\n for (const [key, raw] of Object.entries(el.dataset)) {\n if (!key.startsWith('mk') || key.length === 2) continue;\n const name = key.charAt(2).toLowerCase() + key.slice(3);\n if (RESERVED.has(name)) continue;\n options[name] = coerce(raw ?? '');\n }\n return options;\n}\n","import { ScrollTrigger } from '../core/gsap';\nimport { warnOnce, type Instance } from '../core/types';\nimport { createSpringCards } from '../recipes/spring-cards/create-spring-cards';\nimport { createCurvedCarousel } from '../recipes/curved-carousel/create-curved-carousel';\nimport { createPile } from '../recipes/pile/create-pile';\nimport { createWords } from '../recipes/words/create-words';\nimport { createFlow } from '../recipes/flow/create-flow';\nimport { createPop } from '../recipes/pop/create-pop';\nimport { createFitText } from '../recipes/fit-text/create-fit-text';\nimport { createStretchFooter } from '../recipes/stretch-footer/create-stretch-footer';\nimport { createRadialMenu } from '../recipes/radial-menu/create-radial-menu';\nimport { createTabs } from '../recipes/tabs/create-tabs';\nimport { createCounter } from '../recipes/counter/create-counter';\nimport { createDetails } from '../recipes/details/create-details';\nimport { createReveal } from '../recipes/reveal/create-reveal';\nimport { createReflow } from '../recipes/reflow/create-reflow';\nimport { createSlotText } from '../recipes/slot-text/create-slot-text';\nimport { createSortable } from '../recipes/sortable/create-sortable';\nimport { createMaskText } from '../recipes/mask-text/create-mask-text';\nimport { createCascade } from '../recipes/cascade/create-cascade';\nimport { createTextRoll } from '../recipes/text-roll/create-text-roll';\nimport { createLetters } from '../recipes/letters/create-letters';\nimport { createParallax } from '../recipes/parallax/create-parallax';\nimport { createDepthGrid } from '../recipes/depth-grid/create-depth-grid';\nimport { createFrameZoom } from '../recipes/frame-zoom/create-frame-zoom';\nimport { createContrast } from '../recipes/contrast/create-contrast';\nimport { createMarquee } from '../recipes/marquee/create-marquee';\nimport { createCardDock } from '../recipes/card-dock/create-card-dock';\nimport { createSnapStrip } from '../recipes/snap-strip/create-snap-strip';\nimport { createFillText } from '../recipes/fill-text/create-fill-text';\nimport { parseOptions } from './parse-options';\nimport { createTicketMenu } from '../recipes/ticket-menu/create-ticket-menu';\nimport { createInfiniteReel } from '../recipes/infinite-reel/create-infinite-reel';\nimport { createRepelBento } from '../recipes/repel-bento/create-repel-bento';\nimport { createRotator } from '../recipes/rotator/create-rotator';\nimport { createDragRuler } from '../recipes/drag-ruler/create-drag-ruler';\nimport { createDockPill } from '../recipes/dock-pill/create-dock-pill';\n\ntype Factory = (el: HTMLElement, options: Record<string, unknown>) => Instance;\n\nconst factories = {\n 'spring-cards': createSpringCards,\n 'curved-carousel': (el, options) =>\n createCurvedCarousel(el, {\n ...options,\n onSelect: (index, slide) => el.dispatchEvent(new CustomEvent('mk:select', { detail: { index, slide }, bubbles: true })),\n }),\n pile: createPile,\n words: createWords,\n flow: createFlow,\n pop: createPop,\n 'fit-text': createFitText,\n 'stretch-footer': createStretchFooter,\n 'radial-menu': createRadialMenu,\n tabs: createTabs,\n counter: createCounter,\n details: (el) => createDetails(el),\n reveal: createReveal,\n reflow: createReflow,\n 'slot-text': createSlotText,\n sortable: createSortable,\n 'mask-text': createMaskText,\n cascade: createCascade,\n 'text-roll': createTextRoll,\n letters: createLetters,\n parallax: createParallax,\n 'depth-grid': createDepthGrid,\n 'frame-zoom': createFrameZoom,\n contrast: createContrast,\n marquee: createMarquee,\n 'card-dock': createCardDock,\n 'snap-strip': createSnapStrip,\n 'fill-text': createFillText,\n 'ticket-menu': createTicketMenu,\n 'infinite-reel': createInfiniteReel,\n 'repel-bento': createRepelBento,\n 'rotator': createRotator,\n 'drag-ruler': createDragRuler,\n 'dock-pill': createDockPill,\n} satisfies Record<string, Factory>;\n\nexport type RecipeName = keyof typeof factories;\nexport const recipeNames = Object.keys(factories) as RecipeName[];\n\n/** Measured text: wait for web fonts, fit before splitting into words. */\nconst AFTER_FONTS: RecipeName[] = ['fit-text', 'words', 'slot-text'];\n\nconst instances = new WeakMap<HTMLElement, Map<RecipeName, Instance>>();\n\nexport interface AutoInitOptions {\n /** Only start these recipes. */\n only?: RecipeName[];\n}\n\n/**\n * Start every `[data-mk]` recipe inside `root` (an element may list several:\n * `data-mk=\"fit-text words\"`). Options come from `data-mk-*` attributes.\n * Returns a function that destroys what this call created. Safe to call again:\n * elements that already run a recipe are skipped.\n */\nexport function autoInit(root: ParentNode = document, { only }: AutoInitOptions = {}): () => void {\n if (typeof window === 'undefined') return () => {};\n const created: Array<[HTMLElement, RecipeName, Instance]> = [];\n let cancelled = false;\n\n const elements = [...root.querySelectorAll<HTMLElement>('[data-mk]')];\n if (root instanceof HTMLElement && root.matches('[data-mk]')) elements.unshift(root);\n\n const start = (el: HTMLElement, name: RecipeName) => {\n if (cancelled) return;\n const running = instances.get(el) ?? new Map<RecipeName, Instance>();\n if (running.has(name)) return;\n const instance = (factories[name] as Factory)(el, parseOptions(el));\n running.set(name, instance);\n instances.set(el, running);\n created.push([el, name, instance]);\n };\n\n const now: Array<[HTMLElement, RecipeName]> = [];\n const later: Array<[HTMLElement, RecipeName]> = [];\n for (const el of elements) {\n for (const raw of (el.dataset.mk ?? '').split(/\\s+/).filter(Boolean)) {\n if (!(raw in factories)) {\n warnOnce(`autoInit: unknown recipe \"${raw}\" (known: ${recipeNames.join(', ')})`);\n continue;\n }\n const name = raw as RecipeName;\n if (only && !only.includes(name)) continue;\n (AFTER_FONTS.includes(name) ? later : now).push([el, name]);\n }\n }\n\n now.forEach(([el, name]) => start(el, name));\n if (later.length) {\n later.sort((a, b) => AFTER_FONTS.indexOf(a[1]) - AFTER_FONTS.indexOf(b[1]));\n const fonts = document.fonts?.ready ?? Promise.resolve();\n void Promise.race([fonts, new Promise((resolve) => setTimeout(resolve, 1500))]).then(() => {\n later.forEach(([el, name]) => start(el, name));\n if (!cancelled) ScrollTrigger.refresh();\n });\n }\n\n return () => {\n cancelled = true;\n for (const [el, name, instance] of created.reverse()) {\n instance.destroy();\n instances.get(el)?.delete(name);\n }\n created.length = 0;\n };\n}\n"],"mappings":"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","names":[]}
|