@yewdiel21/motion-kit 0.9.0 → 0.10.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 +3 -35
- package/README.md +93 -81
- package/dist/auto/index.d.ts +22 -3
- package/dist/auto/index.js +43 -5
- package/dist/auto/index.js.map +1 -1
- package/dist/{chunk-KLY5BRRI.js → chunk-34EZ7DF4.js} +1 -1
- package/dist/chunk-34EZ7DF4.js.map +1 -0
- package/dist/{chunk-RFDIZYFX.js → chunk-DOOMULVV.js} +20 -20
- package/dist/chunk-DOOMULVV.js.map +1 -0
- package/dist/{chunk-ABNRDDO7.js → chunk-I3DXF2KQ.js} +2 -2
- package/dist/{chunk-Q4LVFNLN.js → chunk-IKQ5FODN.js} +4 -4
- package/dist/chunk-IKQ5FODN.js.map +1 -0
- package/dist/{chunk-2BQGFOA7.js → chunk-J6OCFNGU.js} +2 -2
- package/dist/chunk-J6OCFNGU.js.map +1 -0
- package/dist/{chunk-6OJAP6ZL.js → chunk-QFBOHPWZ.js} +3 -3
- package/dist/chunk-QFBOHPWZ.js.map +1 -0
- package/dist/{chunk-J27KH2A2.js → chunk-RVSKEBIC.js} +1 -1
- package/dist/chunk-RVSKEBIC.js.map +1 -0
- package/dist/{chunk-34XYOXHG.js → chunk-TFNRIZHU.js} +1615 -12
- package/dist/chunk-TFNRIZHU.js.map +1 -0
- package/dist/{chunk-FS2HJVVY.js → chunk-XAKC2QY7.js} +1204 -5
- package/dist/chunk-XAKC2QY7.js.map +1 -0
- package/dist/css/components/calendar.css +159 -0
- package/dist/css/components/chat-background.css +2 -2
- package/dist/css/components/chat.css +1 -1
- package/dist/css/components/cursor.css +3 -3
- package/dist/css/components/dialog.css +3 -3
- package/dist/css/components/hover-card.css +14 -0
- package/dist/css/components/input-otp.css +10 -0
- package/dist/css/components/island.css +1 -1
- package/dist/css/components/menu.css +1 -1
- package/dist/css/components/nav.css +1 -5
- package/dist/css/components/pagination.css +11 -0
- package/dist/css/components/quantity.css +16 -0
- package/dist/css/components/slot-picker.css +126 -0
- package/dist/css/components/steps.css +2 -2
- package/dist/css/components/studio-dock.css +35 -0
- package/dist/css/components/theme-picker.css +1 -1
- package/dist/css/components/toast.css +1 -1
- package/dist/css/components/trailer.css +37 -0
- package/dist/css/controls.css +78 -13
- package/dist/css/effects.css +8 -8
- package/dist/css/fonts.css +1 -1
- package/dist/css/themes/black-green.css +1 -1
- package/dist/css/themes/black.css +1 -1
- package/dist/css/themes/blue.css +1 -1
- package/dist/css/themes/brown.css +1 -1
- package/dist/css/themes/cold-blue.css +1 -1
- package/dist/css/themes/funny.css +1 -1
- package/dist/css/themes/gray.css +1 -1
- package/dist/css/themes/green.css +1 -1
- package/dist/css/themes/modern-1.css +1 -1
- package/dist/css/themes/neogreen.css +1 -1
- package/dist/css/themes/new.css +1 -1
- package/dist/css/themes/new2.css +1 -1
- package/dist/css/themes/oled.css +1 -1
- package/dist/css/themes/orange.css +1 -1
- package/dist/css/themes/pastel-pink.css +1 -1
- package/dist/css/themes/pink.css +1 -1
- package/dist/css/themes/purple.css +1 -1
- package/dist/css/themes/red.css +1 -1
- package/dist/css/themes/super-blue.css +1 -1
- package/dist/css/themes.css +19 -19
- package/dist/css/tokens.css +9 -9
- package/dist/elements/index.d.ts +75 -7
- package/dist/elements/index.js +172 -6
- package/dist/elements/index.js.map +1 -1
- package/dist/{engine-CUr9QijM.d.ts → engine-GDGwQnJE.d.ts} +2 -2
- package/dist/gl/index.js +3 -3
- package/dist/index.css +1076 -63
- package/dist/index.d.ts +17 -17
- package/dist/index.js +49 -7
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.ts +139 -40
- package/dist/react/index.js +355 -8
- package/dist/react/index.js.map +1 -1
- package/dist/{reduced-BM4Ls0g5.d.ts → reduced-BmBzKH94.d.ts} +215 -18
- package/dist/{reveal-WFUWDrei.d.ts → reveal-jsX-uwUz.d.ts} +233 -24
- package/dist/{store-Bqy_obnD.d.ts → store-DYb3tTsZ.d.ts} +5 -5
- package/dist/theme/generate.d.ts +1 -1
- package/dist/theme/generate.js +2 -2
- package/dist/theme/generate.js.map +1 -1
- package/dist/theme/index.d.ts +2 -2
- package/dist/theme/index.js +2 -2
- package/dist/{theme-BFMoCzi6.d.ts → theme-Bjf9qIIy.d.ts} +1 -1
- package/package.json +2 -2
- package/registry.json +230 -156
- package/skills/motion-kit/SKILL.md +209 -189
- package/skills/motion-kit/reference/components.md +5 -5
- package/skills/motion-kit/reference/design.md +14 -14
- package/skills/motion-kit/reference/recipes.md +48 -49
- package/src/auto/auto-init.ts +38 -0
- package/src/components/calendar/README.md +82 -0
- package/src/components/calendar/calendar.css +158 -0
- package/src/components/calendar/element.ts +27 -0
- package/src/components/calendar/engine.ts +412 -0
- package/src/components/calendar/react.tsx +69 -0
- package/src/components/chat/README.md +1 -3
- package/src/components/chat/chat.css +1 -1
- package/src/components/chat/engine.ts +1 -1
- package/src/components/chat/react.tsx +1 -1
- package/src/components/chat-background/README.md +1 -3
- package/src/components/chat-background/audio.ts +1 -1
- package/src/components/chat-background/chat-background.css +2 -2
- package/src/components/chat-background/engine.ts +1 -1
- package/src/components/chat-background/react.tsx +1 -1
- package/src/components/cursor/README.md +3 -5
- package/src/components/cursor/cursor.css +3 -3
- package/src/components/cursor/element.ts +2 -2
- package/src/components/cursor/engine.ts +5 -5
- package/src/components/cursor/react.tsx +1 -1
- package/src/components/dialog/README.md +4 -8
- package/src/components/dialog/dialog.css +3 -3
- package/src/components/dialog/engine.ts +2 -2
- package/src/components/dialog/react.tsx +1 -1
- package/src/components/hover-card/README.md +16 -0
- package/src/components/hover-card/element.ts +8 -0
- package/src/components/hover-card/engine.ts +69 -0
- package/src/components/hover-card/hover-card.css +13 -0
- package/src/components/hover-card/react.tsx +19 -0
- package/src/components/input-otp/README.md +18 -0
- package/src/components/input-otp/element.ts +14 -0
- package/src/components/input-otp/engine.ts +106 -0
- package/src/components/input-otp/input-otp.css +9 -0
- package/src/components/input-otp/react.tsx +21 -0
- package/src/components/island/README.md +7 -7
- package/src/components/island/engine.ts +3 -3
- package/src/components/island/island.css +1 -1
- package/src/components/island/react.tsx +3 -3
- package/src/components/menu/README.md +2 -4
- package/src/components/menu/engine.ts +1 -1
- package/src/components/menu/menu.css +1 -1
- package/src/components/menu/react.tsx +1 -1
- package/src/components/nav/README.md +12 -14
- package/src/components/nav/engine.ts +5 -5
- package/src/components/nav/nav.css +1 -5
- package/src/components/nav/react.tsx +3 -3
- package/src/components/pagination/README.md +17 -0
- package/src/components/pagination/element.ts +14 -0
- package/src/components/pagination/engine.ts +102 -0
- package/src/components/pagination/pagination.css +10 -0
- package/src/components/pagination/react.tsx +22 -0
- package/src/components/quantity/README.md +20 -0
- package/src/components/quantity/element.ts +14 -0
- package/src/components/quantity/engine.ts +85 -0
- package/src/components/quantity/quantity.css +15 -0
- package/src/components/quantity/react.tsx +21 -0
- package/src/components/slot-picker/README.md +68 -0
- package/src/components/slot-picker/element.ts +27 -0
- package/src/components/slot-picker/engine.ts +412 -0
- package/src/components/slot-picker/react.tsx +76 -0
- package/src/components/slot-picker/slot-picker.css +125 -0
- package/src/components/steps/README.md +1 -3
- package/src/components/steps/engine.ts +3 -3
- package/src/components/steps/react.tsx +2 -2
- package/src/components/steps/steps.css +2 -2
- package/src/components/studio-dock/README.md +44 -0
- package/src/components/studio-dock/element.ts +11 -0
- package/src/components/studio-dock/engine.ts +212 -0
- package/src/components/studio-dock/react.tsx +23 -0
- package/src/components/studio-dock/studio-dock.css +34 -0
- package/src/components/theme-picker/README.md +3 -5
- package/src/components/theme-picker/engine.ts +2 -2
- package/src/components/theme-picker/react.tsx +1 -1
- package/src/components/theme-picker/theme-picker.css +1 -1
- package/src/components/toast/README.md +1 -3
- package/src/components/toast/engine.ts +2 -2
- package/src/components/toast/react.tsx +1 -1
- package/src/components/toast/store.ts +1 -2
- package/src/components/toast/toast.css +1 -1
- package/src/components/trailer/README.md +28 -0
- package/src/components/trailer/element.ts +13 -0
- package/src/components/trailer/engine.ts +189 -0
- package/src/components/trailer/react.tsx +16 -0
- package/src/components/trailer/trailer.css +36 -0
- package/src/core/channels.ts +3 -3
- package/src/core/curves.ts +3 -3
- package/src/core/dates.ts +98 -0
- package/src/core/gsap.ts +2 -2
- package/src/core/loop.ts +1 -1
- package/src/core/math.ts +1 -1
- package/src/core/physics-spring.ts +2 -2
- package/src/core/scroll-track.ts +2 -4
- package/src/core/spring.ts +1 -1
- package/src/core/timing.ts +21 -22
- package/src/css/controls/README.md +24 -20
- package/src/css/controls/burger.css +1 -1
- package/src/css/controls/button.css +4 -4
- package/src/css/controls/checkbox.css +1 -1
- package/src/css/controls/chip.css +1 -1
- package/src/css/controls/field.css +2 -2
- package/src/css/controls/glass.css +4 -4
- package/src/css/controls/status.css +63 -0
- package/src/css/default-theme.css +1 -1
- package/src/css/effects/README.md +19 -21
- package/src/css/effects/anim.css +1 -1
- package/src/css/effects/fade.css +1 -1
- package/src/css/effects/float.css +1 -1
- package/src/css/effects/frost.css +1 -1
- package/src/css/effects/grain.css +1 -1
- package/src/css/effects/loading.css +1 -1
- package/src/css/effects/success.css +1 -1
- package/src/css/effects/text.css +1 -1
- package/src/css/fonts.css +1 -1
- package/src/css/states.css +1 -1
- package/src/css/themes/black-green.css +1 -1
- package/src/css/themes/black.css +1 -1
- package/src/css/themes/blue.css +1 -1
- package/src/css/themes/brown.css +1 -1
- package/src/css/themes/cold-blue.css +1 -1
- package/src/css/themes/funny.css +1 -1
- package/src/css/themes/gray.css +1 -1
- package/src/css/themes/green.css +1 -1
- package/src/css/themes/modern-1.css +1 -1
- package/src/css/themes/neogreen.css +1 -1
- package/src/css/themes/new.css +1 -1
- package/src/css/themes/new2.css +1 -1
- package/src/css/themes/oled.css +1 -1
- package/src/css/themes/orange.css +1 -1
- package/src/css/themes/pastel-pink.css +1 -1
- package/src/css/themes/pink.css +1 -1
- package/src/css/themes/purple.css +1 -1
- package/src/css/themes/red.css +1 -1
- package/src/css/themes/super-blue.css +1 -1
- package/src/css/tokens.css +8 -8
- package/src/elements/index.ts +24 -0
- package/src/gl/liquid-blend/README.md +3 -3
- package/src/gl/matcap/README.md +3 -3
- package/src/gl/particle-hero/README.md +1 -1
- package/src/gl/particle-hero/create-particle-hero.ts +3 -5
- package/src/gl/particle-hero/shaders.ts +1 -1
- package/src/gl/shader-blur/README.md +3 -3
- package/src/gl/shader-grain/README.md +3 -3
- package/src/index.ts +25 -0
- package/src/motion/chat.ts +2 -2
- package/src/motion/confetti.ts +1 -1
- package/src/motion/count.ts +1 -1
- package/src/motion/details.ts +1 -1
- package/src/motion/drag-dismiss.ts +1 -1
- package/src/motion/effects.ts +1 -1
- package/src/motion/entrances.ts +1 -1
- package/src/motion/floating.ts +1 -1
- package/src/motion/flow.ts +2 -2
- package/src/motion/indicator.ts +1 -1
- package/src/motion/layout.ts +1 -1
- package/src/motion/liquid.ts +1 -1
- package/src/motion/morph.ts +2 -2
- package/src/motion/reveal.ts +1 -1
- package/src/motion/sheet.ts +1 -1
- package/src/motion/surface.ts +1 -1
- package/src/react/animated-number.tsx +2 -2
- package/src/react/flip-group.tsx +1 -1
- package/src/react/frost.tsx +1 -1
- package/src/react/index.ts +21 -0
- package/src/react/slot-text.tsx +1 -1
- package/src/react/use-action-button.ts +6 -0
- package/src/react/use-card-dock.ts +1 -1
- package/src/react/use-cascade.ts +1 -1
- package/src/react/use-contrast.ts +1 -1
- package/src/react/use-depth-grid.ts +1 -1
- package/src/react/use-editorial-reveal.ts +7 -0
- package/src/react/use-fill-text.ts +1 -1
- package/src/react/use-film-hero.ts +6 -0
- package/src/react/use-font-cycle.ts +7 -0
- package/src/react/use-frame-zoom.ts +1 -1
- package/src/react/use-image-zoom.ts +5 -0
- package/src/react/use-joined-cta.ts +5 -0
- package/src/react/use-letters.ts +1 -1
- package/src/react/use-local-clock.ts +5 -0
- package/src/react/use-marquee.ts +1 -1
- package/src/react/use-mask-text.ts +1 -1
- package/src/react/use-parallax.ts +1 -1
- package/src/react/use-particle-hero.ts +1 -1
- package/src/react/use-scroll-dock.ts +5 -0
- package/src/react/use-snap-strip.ts +1 -1
- package/src/react/use-sticker.ts +5 -0
- package/src/react/use-studio-dock.ts +8 -0
- package/src/react/use-text-roll.ts +1 -1
- package/src/react/use-thumbnail-nav.ts +7 -0
- package/src/react/use-trailer.ts +6 -0
- package/src/react/use-weight-hover.ts +5 -0
- package/src/recipes/action-button/README.md +31 -0
- package/src/recipes/action-button/action-button.css +113 -0
- package/src/recipes/action-button/create-action-button.ts +56 -0
- package/src/recipes/card-dock/README.md +1 -1
- package/src/recipes/card-dock/card-dock.css +1 -1
- package/src/recipes/card-dock/create-card-dock.ts +2 -2
- package/src/recipes/cascade/README.md +1 -3
- package/src/recipes/cascade/create-cascade.ts +3 -3
- package/src/recipes/contrast/README.md +0 -2
- package/src/recipes/contrast/create-contrast.ts +1 -1
- package/src/recipes/counter/README.md +0 -2
- package/src/recipes/counter/create-counter.ts +1 -1
- package/src/recipes/curved-carousel/README.md +0 -2
- package/src/recipes/curved-carousel/create-curved-carousel.ts +2 -2
- package/src/recipes/curved-carousel/curved-carousel.css +1 -1
- package/src/recipes/depth-grid/README.md +0 -2
- package/src/recipes/depth-grid/create-depth-grid.ts +3 -4
- package/src/recipes/details/README.md +0 -2
- package/src/recipes/details/create-details.ts +1 -1
- package/src/recipes/dock-pill/README.md +3 -3
- package/src/recipes/drag-ruler/README.md +3 -3
- package/src/recipes/editorial-reveal/README.md +35 -0
- package/src/recipes/editorial-reveal/create-editorial-reveal.ts +91 -0
- package/src/recipes/editorial-reveal/editorial-reveal.css +17 -0
- package/src/recipes/fill-text/README.md +1 -1
- package/src/recipes/fill-text/create-fill-text.ts +1 -1
- package/src/recipes/film-hero/README.md +23 -0
- package/src/recipes/film-hero/create-film-hero.ts +65 -0
- package/src/recipes/film-hero/film-hero.css +29 -0
- package/src/recipes/fit-text/README.md +0 -2
- package/src/recipes/flow/README.md +0 -2
- package/src/recipes/flow/create-flow.ts +1 -1
- package/src/recipes/font-cycle/README.md +11 -0
- package/src/recipes/font-cycle/create-font-cycle.ts +126 -0
- package/src/recipes/font-cycle/font-cycle.css +36 -0
- package/src/recipes/frame-zoom/README.md +1 -3
- package/src/recipes/frame-zoom/create-frame-zoom.ts +2 -2
- package/src/recipes/image-zoom/README.md +16 -0
- package/src/recipes/image-zoom/create-image-zoom.ts +27 -0
- package/src/recipes/image-zoom/image-zoom.css +7 -0
- package/src/recipes/infinite-reel/README.md +3 -3
- package/src/recipes/joined-cta/README.md +13 -0
- package/src/recipes/joined-cta/create-joined-cta.ts +22 -0
- package/src/recipes/joined-cta/joined-cta.css +17 -0
- package/src/recipes/letters/README.md +2 -4
- package/src/recipes/letters/create-letters.ts +3 -3
- package/src/recipes/local-clock/README.md +31 -0
- package/src/recipes/local-clock/create-local-clock.ts +61 -0
- package/src/recipes/marquee/README.md +0 -2
- package/src/recipes/marquee/create-marquee.ts +3 -3
- package/src/recipes/marquee/marquee.css +1 -1
- package/src/recipes/mask-text/README.md +3 -5
- package/src/recipes/mask-text/create-mask-text.ts +4 -4
- package/src/recipes/parallax/README.md +1 -3
- package/src/recipes/parallax/create-parallax.ts +1 -1
- package/src/recipes/pile/README.md +0 -2
- package/src/recipes/pile/create-pile.ts +1 -1
- package/src/recipes/pile/pile-math.ts +1 -1
- package/src/recipes/pile/pile.css +1 -1
- package/src/recipes/pill/README.md +0 -2
- package/src/recipes/pill/pill.css +2 -2
- package/src/recipes/pop/README.md +0 -2
- package/src/recipes/pop/create-pop.ts +1 -1
- package/src/recipes/radial-menu/README.md +0 -2
- package/src/recipes/radial-menu/create-radial-menu.ts +1 -1
- package/src/recipes/radial-menu/radial-menu.css +1 -1
- package/src/recipes/reflow/README.md +3 -5
- package/src/recipes/reflow/create-reflow.ts +1 -1
- package/src/recipes/repel-bento/README.md +3 -3
- package/src/recipes/reveal/README.md +0 -2
- package/src/recipes/reveal/create-reveal.ts +1 -1
- package/src/recipes/rotator/README.md +3 -3
- package/src/recipes/scroll-dock/README.md +46 -0
- package/src/recipes/scroll-dock/create-scroll-dock.ts +72 -0
- package/src/recipes/scroll-dock/scroll-dock.css +70 -0
- package/src/recipes/slot-text/README.md +0 -2
- package/src/recipes/slot-text/create-slot-text.ts +1 -1
- package/src/recipes/snap-strip/README.md +1 -1
- package/src/recipes/snap-strip/create-snap-strip.ts +5 -6
- package/src/recipes/snap-strip/snap-strip.css +1 -1
- package/src/recipes/sortable/README.md +3 -5
- package/src/recipes/sortable/create-sortable.ts +4 -4
- package/src/recipes/sortable/sortable.css +1 -1
- package/src/recipes/spring-cards/README.md +0 -2
- package/src/recipes/spring-cards/create-spring-cards.ts +1 -1
- package/src/recipes/spring-cards/spring-cards.css +1 -1
- package/src/recipes/sticker/README.md +59 -0
- package/src/recipes/sticker/create-sticker.ts +490 -0
- package/src/recipes/sticker/sticker.css +112 -0
- package/src/recipes/stretch-footer/README.md +0 -2
- package/src/recipes/stretch-footer/create-stretch-footer.ts +1 -1
- package/src/recipes/stretch-footer/stretch-footer.css +1 -1
- package/src/recipes/tabs/README.md +0 -2
- package/src/recipes/tabs/create-tabs.ts +1 -1
- package/src/recipes/text-roll/README.md +1 -3
- package/src/recipes/text-roll/create-text-roll.ts +3 -3
- package/src/recipes/text-roll/text-roll.css +1 -1
- package/src/recipes/thumbnail-nav/README.md +16 -0
- package/src/recipes/thumbnail-nav/create-thumbnail-nav.ts +165 -0
- package/src/recipes/thumbnail-nav/thumbnail-nav.css +108 -0
- package/src/recipes/ticket-menu/README.md +3 -3
- package/src/recipes/weight-hover/README.md +37 -0
- package/src/recipes/weight-hover/create-weight-hover.ts +136 -0
- package/src/recipes/weight-hover/weight-hover.css +7 -0
- package/src/recipes/words/README.md +0 -2
- package/src/recipes/words/create-words.ts +1 -1
- package/src/theme/generate.ts +1 -1
- package/src/theme/presets.ts +2 -2
- package/src/theme/theme.ts +1 -2
- package/dist/chunk-2BQGFOA7.js.map +0 -1
- package/dist/chunk-34XYOXHG.js.map +0 -1
- package/dist/chunk-6OJAP6ZL.js.map +0 -1
- package/dist/chunk-FS2HJVVY.js.map +0 -1
- package/dist/chunk-J27KH2A2.js.map +0 -1
- package/dist/chunk-KLY5BRRI.js.map +0 -1
- package/dist/chunk-Q4LVFNLN.js.map +0 -1
- package/dist/chunk-RFDIZYFX.js.map +0 -1
- /package/dist/{chunk-ABNRDDO7.js.map → chunk-I3DXF2KQ.js.map} +0 -0
|
@@ -1,189 +1,209 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: motion-kit
|
|
3
|
-
description:
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# motion-kit
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
| Layer | Import | What |
|
|
11
|
-
|---|---|---|
|
|
12
|
-
| Core + motion functions | `@yewdiel21/motion-kit` | `registerMotion`, `EASE`, `TIMING`, `flowIn`, `revealFrom`, `slideIndicator`, `countTo`, `captureLayout`/`reflowLayout`, `enterMessages`… |
|
|
13
|
-
| Recipes | same + `/auto` + `/react` | `createX(root, options) → { destroy, …controls }`; `data-mk="x"` + `autoInit()`; `useX(ref, options)` |
|
|
14
|
-
| Components | engine in `.`, `<mk-x>` in `/elements`, `<X>` in `/react` | own markup + styles: `dialog`, `menu`, `toast`, `theme-picker`, `chat`, `chat-background`, `nav`, `steps`, `cursor`, `island` |
|
|
15
|
-
| WebGL (optional) | `@yewdiel21/motion-kit/gl` (+ matching hooks in `/react`) | `createParticleHero`, `createLiquidBlend`, `createMatcap`, `createShaderGrain`, `createShaderBlur`; reduced motion and fallback |
|
|
16
|
-
| Effects | `/css/effects` (in `/css`) + `.` / `/react` | `.mk-anim-*`, `.mk-loading`, `.mk-text-gradient`, `.mk-frost`, `.mk-float`, `.mk-grain`, `.mk-success`; `animate(el, name)`, `leave(el, exit)`, `confetti(origin)`, `<Frost />` |
|
|
17
|
-
| Design line | `/css`, `/css/themes`, `/css/fonts`, `/theme`, `/theme/generate` | tokens, 19 themes, controls, theme runtime and generator |
|
|
18
|
-
|
|
19
|
-
## 1. Install (pick one)
|
|
20
|
-
|
|
21
|
-
**Package** (public npm registry
|
|
22
|
-
|
|
23
|
-
```sh
|
|
24
|
-
npm i @yewdiel21/motion-kit gsap
|
|
25
|
-
npm i -D @material/material-color-utilities@^0.3.0
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
**Copy the code** (editable, no runtime dependency on the package):
|
|
29
|
-
|
|
30
|
-
```sh
|
|
31
|
-
npx @yewdiel21/motion-kit list
|
|
32
|
-
npx @yewdiel21/motion-kit add tabs slot-text theme-picker --react --elements --dir src/motion-kit
|
|
33
|
-
npx @yewdiel21/motion-kit add theme neogreen oled
|
|
34
|
-
npx @yewdiel21/motion-kit add controls
|
|
35
|
-
npx @yewdiel21/motion-kit theme brand --seed "#ff6a3d" --out src/styles
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
`add` copies each entry, what it `requires`, only the core files it imports, the base CSS (tokens, default theme, base, entrance states) and, with `--react` / `--elements`, the hook/component and custom element. Imports are relative, so nothing needs rewriting. `gsap` must be installed.
|
|
39
|
-
|
|
40
|
-
## 2. Wire it once
|
|
41
|
-
|
|
42
|
-
1. CSS: `import '@yewdiel21/motion-kit/css'` (tokens, default theme, controls, recipe and component styles). Add `/css/themes` (all 19) or `/css/themes/<id>` and, for
|
|
43
|
-
2. Head, inline, in this order:
|
|
44
|
-
- `MK_THEME_HEAD_SCRIPT` (`/theme`): applies the stored theme/mode before the first paint.
|
|
45
|
-
- `MK_HEAD_SCRIPT` (`/auto` or `.`): adds `.mk-js` so entrances start hidden, `.mk-failed` if no recipe ran within 2.5 s.
|
|
46
|
-
3. `<body class="mk-app">` gives the page the theme's background, text colour and DM Sans.
|
|
47
|
-
4. Start things:
|
|
48
|
-
- **Astro / HTML**: `initTheme()`; `data-mk="<recipe>"` + `autoInit()`; `defineElements()` for `<mk-…>` components.
|
|
49
|
-
- **React / Next.js** (entries are `'use client'`): `<ThemeProvider>` at the root, hooks (`useTabs(ref)`), components (`<ThemePicker />`, `<SlotText text />`, `<AnimatedNumber value />`, `<FlipGroup>`). Keep `data-mk="<recipe>"` on recipe markup so the hidden entrance state applies before hydration.
|
|
50
|
-
|
|
51
|
-
## 3. Design line
|
|
52
|
-
|
|
53
|
-
- Colour: 37 Material 3 roles `--md-sys-color-*` per theme; components use the semantic layer `--mk-bg`, `--mk-surface`, `--mk-surface-1…5` (container lowest→highest), `--mk-text`, `--mk-muted`, `--mk-accent`, `--mk-on-accent`, `--mk-accent-soft`, `--mk-secondary-soft`, `--mk-outline(-soft)`, `--mk-error(-soft)`, `--mk-scrim`, `--mk-shadow-color`. Never hard-code colours in components: use these.
|
|
54
|
-
- Themes: `<html data-mk-theme="<id>" data-mk-mode="system|light|dark">`. Ids: blue, purple, neogreen (default), red, pink, pastel-pink, brown, super-blue, gray, oled (the 10
|
|
55
|
-
- Own brand colour: `applyTheme('#ff6a3d', { id: 'brand' })` at runtime, or `motion-kit theme brand --seed …` for a static file.
|
|
56
|
-
- Type: `--mk-font` (DM Sans), `--mk-font-mono` (Geist Mono), icons `.mk-icon` (Material Symbols Rounded). Scale classes `.mk-type-{display|headline|title|body|label}-{large|medium|small}`.
|
|
57
|
-
- Shape: capsules. `--mk-radius-{xs 8, sm 12, md 16, lg 24, xl 32, 2xl 40, 3xl 48, 4xl 64, full}`; bubble 32, dialog 40, chat 48, dock 64. Spacing `--mk-space-1…16` (4 px). Breakpoint 680 px.
|
|
58
|
-
- Controls (CSS only): `.mk-glass` (
|
|
59
|
-
- Full table: [reference/design.md](reference/design.md).
|
|
60
|
-
|
|
61
|
-
## 4. Recipes
|
|
62
|
-
|
|
63
|
-
| Recipe | Markup | Key options (defaults) | Controls |
|
|
64
|
-
|---|---|---|---|
|
|
65
|
-
| `tabs` | root with `[data-mk-tab]` buttons and a `[data-mk-indicator]` (use `.mk-segmented`) | `orientation 'horizontal'`, `duration .45`, `onSelect(i, tab)` (event `mk:tab`) | `select(i)`, `index` |
|
|
66
|
-
| `counter` | element with a number | `to` (text), `from 0`, `duration .6`, `decimals`, `locale`, `prefix`, `suffix`, `trigger 'scroll'` | `play()`, `set(n)` |
|
|
67
|
-
| `details` | container of `<details>` (chevron `[data-mk-chevron]` in the summary) | — | — |
|
|
68
|
-
| `reveal` | element to uncover | `speed 'fast'\|'normal'\|'slow'\|'slower'`, `origin` (selector), `trigger 'manual'\|'load'` | `play(origin?)` |
|
|
69
|
-
| `reflow` | list with `[data-mk-item][data-flip-id]` | `duration .62` | `capture()` before the DOM change, `play()` after |
|
|
70
|
-
| `slot-text` | text element | `duration 300` ms, `stagger 45`, `maxTilt 5` | `set(text)` |
|
|
71
|
-
| `spring-cards` | root with `[data-mk-card]` children, each with `.mk-card__shadow` + image | `push .4`, `falloff 6`, `initialOffset 100`, `stiffness .05`, `friction .8`, `stagger .08`, `delay .4` | — |
|
|
72
|
-
| `curved-carousel` | root with `[data-mk-slide]`; optional `.mk-carousel__media`, `.mk-carousel__title` | `friction .85`, `throwBoost 2`, `wheel .2`, `startIndex 0`, `onSelect(i, slide)` (auto: `mk:select` event) | `next()`, `prev()`, `goTo(i)`, `index` |
|
|
73
|
-
| `pile` | `.mk-pile > .mk-pile__stack > .mk-pile__layer > .mk-pile__media`; back layers styled with `pileStyle(pileLayers(n, seed)[i])` | `threshold .25` | — |
|
|
74
|
-
| `words` | any text element | `by 'words'\|'chars'`, `trigger 'scroll'\|'load'\|'manual'`, `duration .8`, `stagger .1` | `reveal()`, `replace(mutate)` |
|
|
75
|
-
| `flow` | container; its children animate | `y 20`, `blur 16`, `duration .5`, `stagger .05`, `style 1\|2`, `trigger` | `play()` |
|
|
76
|
-
| `pop` | any element | `scale .7`, `duration 1.1`, `trigger` | `play()` |
|
|
77
|
-
| `fit-text` | one-line element inside a parent | `safety .995` | `refit()` |
|
|
78
|
-
| `stretch-footer` | `footer[data-mk="stretch-footer"]` containing `[data-mk-footer-title]`, plus a `[data-mk-phantom]` spacer after `<main>` | `lambda .9` | — |
|
|
79
|
-
| `radial-menu` | root with `[data-mk-toggle]` and `[data-mk-item]` direct children | `radius '3.6rem'`, `startAngle 1.5708`, `spacing .9` | `open()`, `close()`, `toggle()`, `isOpen` |
|
|
80
|
-
| `pill` | `.mk-pill` button, `.mk-stretch` link | CSS only | — |
|
|
81
|
-
| `mask-text` | any text | `by 'lines'|'words'|'chars'`, `y 100
|
|
82
|
-
| `cascade` | block with `[data-mk-cascade="rule|fade|rise"]` children (`rise` inside a clip) | `delay` (`data-mk-delay`), `step .03`, `duration 1.2`, `once`, `trigger` | `play()`, `reset()` |
|
|
83
|
-
| `text-roll` | a title | `trigger 'load'|'scroll'|'hover'|'manual'`, `delay`, `interval
|
|
84
|
-
| `letters` | a word | `effect 'scale'|'blink'`, `colors`, `autoplay` | `play()` |
|
|
85
|
-
| `parallax` | clipped frame with a picture (`[data-mk-parallax-target]`) | `amount 1`, `lerp 1`, `scroll` | `seek(p)` |
|
|
86
|
-
| `depth-grid` | grid container | `start 'top center'`, `end 'bottom bottom'`, `lerp 1`, `scroll` | `seek(p)` |
|
|
87
|
-
| `frame-zoom` | frame with one picture/video child | `start 'top bottom'`, `end 'bottom top'`, `lerp 1` | `seek(p)`, `open(on)` |
|
|
88
|
-
| `contrast` | header; sections with `data-mk-tone="light|dark"` | `sections`, `attribute 'data-mk-on'` | `tone` |
|
|
89
|
-
| `marquee` | strip whose first child is the group | `axis 'x'|'y'`, `speed 2` (s per item), `reverse` | `refresh()` |
|
|
90
|
-
| `card-dock` | `.mk-card-dock` with `.mk-card-dock__item` (> `a.mk-card-dock__card` + `.mk-card-dock__title`), optional `.mk-card-dock__cta`; `mk-card-dock--fixed` | `intro 1600` (ms spread on load, 0 skips) | `expand()`, `collapse()`, `expanded` |
|
|
91
|
-
| `snap-strip` | `.mk-snap-strip` with the cards as children | `autoplay`, `interval 5000`, `resume 2000`, `delay 500` (`data-mk-delay`) | `next()`, `previous()`, `index` |
|
|
92
|
-
| `fill-text` | any text | `from .2`, `start 'top 90%'`, `end 'center 40%'`, `scroll` | `seek(p)`, `progress` |
|
|
93
|
-
| `sortable` | root with `[data-mk-item][data-mk-id]` (optional `[data-mk-sortable-group="key"]` lists, `data-mk-sortable-locked`, `[data-mk-sort-handle]`) | `mutate true` (`false` in `useSortable`), `handle`, `autoScroll true`, `follow {1100, 38}`, `onReorder(detail)` (event `mk:reorder`, cancelable) | `cancel()`, `dragging` |
|
|
94
|
-
|
|
95
|
-
React hooks: `useCardDock`, `useSnapStrip`, `useFillText`, `useParticleHero`, `useMaskText`, `useCascade`, `useTextRoll`, `useLetters`, `useParallax`, `useDepthGrid`, `useFrameZoom`, `useContrast`, `useMarquee`, `useSortable`, `useTabs`, `useCounter`, `useDetails`, `useReveal`, `useReflow`, `useSlotText`, `useSpringCards`, `useCurvedCarousel`, `usePile`, `useWords`, `useFlow`, `usePop`, `useFitText`, `useStretchFooter`, `useRadialMenu`. Markup and options: each recipe's `README.md` (`src/recipes/<name>/`). Parameters and
|
|
96
|
-
|
|
97
|
-
## 4b. Effects (v0.5)
|
|
98
|
-
|
|
99
|
-
| Name (`animate` / class `.mk-anim-<name>`) | Motion | Time |
|
|
100
|
-
|---|---|---|
|
|
101
|
-
| `out` / `out-left` / `out-bottom` | up 20 / left 64 / down 24 px, blur 16, fade | 0.5 s |
|
|
102
|
-
| `collapse` | folds height, padding and margin while blurring | 0.25 s |
|
|
103
|
-
| `highlight` | 4 px inner ring in primary-container | 1 s |
|
|
104
|
-
| `shake` / `shake-strong` | ±4 px / ±10 px | 0.5 s / 0.4 s |
|
|
105
|
-
| `fade`, `wipe`, `progress-in` | appear; a surface veil leaves to the right; appear late | 0.3 / 0.7 / 1 s |
|
|
106
|
-
|
|
107
|
-
`await animate(el, name)` replays even if already playing; `await leave(row, 'out-left' | 'collapse', { remove })` animates then removes (or hides). In React lists: `leave(item, 'out', { remove: false })`, then drop it from state. Classes: `.mk-loading` (+`--soft`), `.mk-shimmer`, `.mk-text-gradient` (theme), `.mk-text-rainbow`, `.mk-frost` (+ five `<i>`; `--top`, `--fixed`; `<Frost />`), `.mk-float` / `.mk-float-group`, `.mk-grain` (`--mk-grain`), `.mk-success` + `confetti(button)`. Reduced motion: loops stop, exits jump to the end, confetti does not draw.
|
|
108
|
-
|
|
109
|
-
## 5. Motion functions (no instance)
|
|
110
|
-
|
|
111
|
-
Use them inside your own components; they all honour reduced motion and return the tween (or `null`).
|
|
112
|
-
|
|
113
|
-
| Function |
|
|
114
|
-
|---|---|
|
|
115
|
-
| `flowIn(targets, { style, reverse, target })` / `flowOut(targets)` | lists, steps, settings entering / leaving |
|
|
116
|
-
| `stepChange(container, () => render next)` | wizard / onboarding steps (flow out → swap → flow in) |
|
|
117
|
-
| `flowInMenu`, `flowInPalette`, `flowInForm`, `flowInLanding`, `flowInContent` | menu options, swatches, form cards, landing, articles |
|
|
118
|
-
| `revealFrom(el, { origin, speed })` | a surface uncovered like a wave from the control that opened it |
|
|
119
|
-
| `toggleDetails(details, open)`, `installDetailsMotion(root)` | disclosures |
|
|
120
|
-
| `slideIndicator(indicator, target)` | any sliding selection indicator |
|
|
121
|
-
| `countTo(el, n)`, `revealCounter(el, n)`, `tweenNumber(a, b, cb)` | changing numbers, balances |
|
|
122
|
-
| `captureLayout` + `reflowLayout` | reorder / filter / add in lists |
|
|
123
|
-
| `enterMessages(bubbles)`, `fitComposer(textarea)`, `scrollToLatest(scroller)` | chat / comments |
|
|
124
|
-
| `capturePending(el)` + `morphPendingToReply(state, reply, list)` | a "thinking" placeholder turning into the answer (other frameworks) |
|
|
125
|
-
| `audioEnergy(stream, onEnergy)` | microphone level 0…1 for `chat-background` (never asks for the mic itself) |
|
|
126
|
-
| `channels(start, onChange)` + `spring()` / `eased()` | multi-property spring motion (liquid surfaces) |
|
|
127
|
-
| `trackScroll(el, { start, end, lerp, onUpdate })` | an element's 0→1 progress through the viewport (follows the page; `lerp < 1` smooths it) — build your own scroll effects |
|
|
128
|
-
| `motionSpring(stiffness, damping, mass?)` → `{ ease, duration }`, `springLinear(…)` | Motion/Framer springs
|
|
129
|
-
| `sheetOpen`, `sheetClose`, `pushUnderlay`, `releaseUnderlay` | a sheet rising from the bottom while the page behind sinks |
|
|
130
|
-
| `morphOpen(surface, opener)`, `morphClose`, `morphCloseWithGhost`, `liquidOpen/Close` | any surface growing out of / folding into a control |
|
|
131
|
-
| `attachDragDismiss(surface, { onDismiss })`, `attachFloating`, `anchorSurface` | drag to dismiss, floating windows, anchored panels |
|
|
132
|
-
| `fadeBackdrop(dialog, 'in')`, `ghostOf`, `clearStyles` | backdrop tint, inert close copies, cleaning without GSAP measuring hidden nodes |
|
|
133
|
-
|
|
134
|
-
Curves: `EASE.signature
|
|
135
|
-
|
|
136
|
-
## 6. Components
|
|
137
|
-
|
|
138
|
-
| Component | HTML / Astro | React |
|
|
139
|
-
|---|---|---|
|
|
140
|
-
| `dialog` | `<button data-mk-open="crear">` + `<mk-dialog id="crear" heading="…" [description] [variant="liquid|sheet"] [placement="anchor\|side"] [size="sm\|lg\|xl"] [float="key"] [shared="id"] [no-backdrop] [persistent] [no-drag]>` (children → body; `data-mk-part="footer"` stays below) | `<Dialog.Root variant placement float…><Dialog.Trigger/><Dialog.Content size><Dialog.Header><Dialog.Title/><Dialog.Close/></Dialog.Header><Dialog.Body/><Dialog.Footer/></Dialog.Content></Dialog.Root>` |
|
|
141
|
-
| `menu` | `<button data-mk-open="m">` + `<mk-menu id="m" label="…">` with `<button data-mk-item data-mk-value>`; listen `mk:select` | `<Menu.Root onSelect><Menu.Trigger/><Menu.Content><Menu.Item value/><Menu.Separator/></Menu.Content></Menu.Root>` |
|
|
142
|
-
| `toast` | `<mk-toaster>` once + `toast('Copiado', { origin: button, tone, action })` | `<Toaster />` once + `toast(…)` |
|
|
143
|
-
| `theme-picker` | `<mk-theme-picker [show-hidden] [themes="a,b"]>` | `<ThemePicker themes showHidden onChange />` inside `<ThemeProvider>` |
|
|
144
|
-
| `chat` | `<mk-chat [background] [mic] placeholder="…">` (history `[data-mk-message][data-mk-role]` inside); `mk:send` → `el.add('user', t)`, `el.pending()`, `el.reply(answer)` | `<Chat.Root onSend><ChatBackground /><Chat.Messages pending>{<Chat.Message role/>}</Chat.Messages><Chat.Confirm/><Chat.Composer/></Chat.Root>`; set the reply and `pending=false` in the same render |
|
|
145
|
-
| `chat-background` | `<mk-chat-background energy scale>` first inside a positioned box; `el.busy(true)` | `<ChatBackground energy scale />` |
|
|
146
|
-
| `nav` | `<div class="mk-shell"><main class="mk-shell__view">…</main><mk-nav class="mk-nav mk-nav--bonita" nav-style="bonita" [accent] [reveal] [storage-key]><div class="mk-nav__buttons"><a class="mk-nav__button" href aria-current="page">…</a></div></mk-nav></div>`; `mk:navigate` | `<Nav navStyle items active onSelect first actions accent reveal />` inside `.mk-shell` |
|
|
147
|
-
| `cursor` | `<mk-cursor>` once (chip over `[data-mk-cursor="Label"]`, `data-mk-cursor-shape="circle"`, `data-mk-cursor-icon`) · `<mk-cursor variant="dot" text arrows>` inside a zone (`data-mk-cursor-hide` hides it) | `<Cursor />` · `<Cursor variant="dot" text arrows zone />` |
|
|
148
|
-
| `island` | `<mk-island [class="mk-island--contained"] [entrance="false|manual"]>` with `.mk-island__backdrop[data-mk-island-close]`, `.mk-island__shell` (glass, header, `[data-mk-island-toggle="menu"]` buttons, `.mk-island__cta`), `.mk-island__content > div > [data-mk-island-panel="menu"]` with `[data-mk-island-item]` rows and `.mk-island-card`s; `mk:island` | `<Island brand cta panels={[{ name, label, icon, light, content }]} contained onChange />` |
|
|
149
|
-
| `steps` | `<mk-steps class="mk-steps">` + `[data-mk-step]` sections, `[data-mk-flow-item]`, `[data-mk-counter]`, `[data-mk-step-next/prev/goto]`; `el.busy(on)`, `mk:step` | `<Steps index onChange busy><ChatBackground /><Steps.Counter /><Steps.Step>…</Steps.Step></Steps>` |
|
|
150
|
-
|
|
151
|
-
Register elements with `defineElements()` (or a list of tag names). Engines for your own markup: `createDialog(dialogEl, opts)`, `createMenu(dialogEl, opts)`, `createToaster(hostEl)`, `createThemePicker(el)`, `createChat(el)`, `createChatBackground(el)`, `createNav(navEl, { style })`, `createSteps(el)`.
|
|
152
|
-
|
|
153
|
-
Dialog behaviour
|
|
154
|
-
|
|
155
|
-
Chat
|
|
156
|
-
|
|
157
|
-
**Adding a component** (in the motion-kit repo): `pnpm new component <name>` scaffolds `src/components/<name>/{engine.ts, <name>.css, element.ts, react.tsx, README.md}`, a test, playground demos, the registry entry and the exports. Fill the engine (works on existing markup, defaults from `TIMING`, reduced motion, `destroy()` restores the DOM), then `pnpm test`. See [reference/components.md](reference/components.md).
|
|
158
|
-
|
|
159
|
-
## 7. Rules
|
|
160
|
-
|
|
161
|
-
- Call `destroy()` when the element leaves (hooks, components and `autoInit()`'s returned function do it). Never leave instances running on removed nodes.
|
|
162
|
-
- Respect reduced motion: everything here already shows the final state under `prefers-reduced-motion: reduce`; custom motion must check `reduced()` too.
|
|
163
|
-
- Flip contract: measure before the DOM change, animate after it (`capture()`/`play()`, `<FlipGroup signature>`).
|
|
164
|
-
- Text that changes: `words.replace(() => …)`, `fit.refit()`, `slot.set(text)` — don't re-create.
|
|
165
|
-
- Elements inside a closed `<dialog>`: create `words` with `trigger: 'manual'` and call `reveal()` after `showModal()`.
|
|
166
|
-
- `stretch-footer` needs the page above it: `main { position: relative; z-index: 1; background: var(--mk-bg) }`.
|
|
167
|
-
- Theme: style with `--mk-*` tokens and controls; switch with `setTheme`/`setMode` (or `useTheme()`), never by swapping stylesheets.
|
|
168
|
-
- Override look with CSS variables (`--mk-button-bg`, `--mk-field-radius`, `--mk-swatch-size`, `--mk-tabs-indicator`, `--mk-shadow`…), not by editing package code.
|
|
169
|
-
|
|
170
|
-
## 8. Choosing
|
|
171
|
-
|
|
172
|
-
- New app with
|
|
173
|
-
- Segmented filters / view switch → `.mk-segmented` + `tabs`. Totals → `counter` / `<AnimatedNumber>`.
|
|
174
|
-
- Lists that reorder → `reflow` / `<FlipGroup>`; lists the user reorders by dragging (tasks, kanban) → `sortable`; lists that appear → `flow` (or `flowIn`).
|
|
175
|
-
- Editorial headlines → `mask-text` (lines; `y 120` for film-title feel); credits / spec lists → `cascade`; a hero title that keeps alive → `text-roll` with `interval`; a playful word → `letters`.
|
|
176
|
-
- Photos in long pages → `parallax`; a gallery section → `depth-grid`; a video section → `frame-zoom`; header over dark/light sections → `contrast`; logos / festivals → `marquee` (+ `.mk-fade-x`).
|
|
177
|
-
- Site header for a product / landing → `island` (menu + cart share it); a product switcher pinned to a corner → `card-dock` (`--fixed`); phone carousels → `snap-strip`; a manifesto paragraph → `fill-text`; a hero with a living background → `particle-hero` from `/gl` (keep the text in HTML).
|
|
178
|
-
- Portfolio cards → `cursor` chip (`data-mk-cursor="View project"`); a draggable reel or full-bleed hero → `cursor` dot.
|
|
179
|
-
- Glass actions or tags over photos / colour → `.mk-glass` (+ `.mk-float-group` for floating tags); bottom fade over scrolling content → `.mk-frost`; a cinematic hero → `.mk-grain`.
|
|
180
|
-
- Removing rows → `leave(row, 'out-left' | 'collapse')`; form error → `aria-invalid="true"` (vibrates) or `animate(el, 'shake')`; success → `.mk-success` + `confetti(button)`; loading cards → `.mk-loading`; AI / premium labels → `.mk-text-gradient`.
|
|
181
|
-
- Project detail over the page → `dialog` with `variant="sheet"` and `data-mk-underlay` on the page; mobile menu toggle → `.mk-burger`; "Explore" CTA → `.mk-button--roll`.
|
|
182
|
-
- App frame → `.mk-shell` + `nav` (let the user pick the style; `storageKey` remembers it). Assistant / support chat → `chat` + `chat-background`. First-run setup → `steps` (with `ChatBackground` and `busy` while saving).
|
|
183
|
-
- FAQ / settings groups → `details`. Date/time popovers → `revealFrom` from the field.
|
|
184
|
-
- Language switch on a title → `slot-text`.
|
|
185
|
-
- Portfolio hero → `spring-cards` + a giant `fit-text words` title; featured projects → `curved-carousel`; archive → `pile`; last screen → `stretch-footer`; corner quick actions → `radial-menu`.
|
|
186
|
-
- Film navigation → `ticket-menu` or `<Menu.Root ticket>` / `<mk-menu ticket>`; preserves menu focus, selection and keyboard handling.
|
|
187
|
-
- Circular archive → `infinite-reel` (wheel, drag, keyboard, axis x/y); interactive card grid → `repel-bento`; testimonials → `rotator` (8 s, pause on focus/hover).
|
|
188
|
-
- Numeric experience/time selector → `drag-ruler` (role slider, 60 px/unit, step .1); a shared active indicator in navigation → `dock-pill` (spring 380/30). Navigation remains the app's responsibility.
|
|
189
|
-
- GPU image transitions → `createLiquidBlend`; metal study → `createMatcap`; film processing → `createShaderGrain` / `createShaderBlur`, all from `/gl`. React hooks `useLiquidBlend`, `useMatcap`, `useShaderGrain`, `useShaderBlur` are in `/react`. Import explicitly: these are not autoInit recipes. Retain accessible HTML images and set dimensions on the host. See [reference/recipes.md](reference/recipes.md) and each recipe README for the
|
|
1
|
+
---
|
|
2
|
+
name: motion-kit
|
|
3
|
+
description: Use motion-kit components and animation recipes in vanilla JavaScript, Astro and React. Includes dialogs, menus, toasts, chat, navigation, onboarding, sortable lists, text and scroll effects, collections, themes, CSS controls and optional WebGL. Use for component installation, configuration, composition and motion-kit API examples.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# motion-kit
|
|
7
|
+
|
|
8
|
+
Motion components for vanilla JavaScript, Astro and React. Entry points:
|
|
9
|
+
|
|
10
|
+
| Layer | Import | What |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| Core + motion functions | `@yewdiel21/motion-kit` | `registerMotion`, `EASE`, `TIMING`, `flowIn`, `revealFrom`, `slideIndicator`, `countTo`, `captureLayout`/`reflowLayout`, `enterMessages`… |
|
|
13
|
+
| Recipes | same + `/auto` + `/react` | `createX(root, options) → { destroy, …controls }`; `data-mk="x"` + `autoInit()`; `useX(ref, options)` |
|
|
14
|
+
| Components | engine in `.`, `<mk-x>` in `/elements`, `<X>` in `/react` | own markup + styles: `dialog`, `menu`, `toast`, `theme-picker`, `chat`, `chat-background`, `nav`, `steps`, `cursor`, `island` |
|
|
15
|
+
| WebGL (optional) | `@yewdiel21/motion-kit/gl` (+ matching hooks in `/react`) | `createParticleHero`, `createLiquidBlend`, `createMatcap`, `createShaderGrain`, `createShaderBlur`; reduced motion and fallback |
|
|
16
|
+
| Effects | `/css/effects` (in `/css`) + `.` / `/react` | `.mk-anim-*`, `.mk-loading`, `.mk-text-gradient`, `.mk-frost`, `.mk-float`, `.mk-grain`, `.mk-success`; `animate(el, name)`, `leave(el, exit)`, `confetti(origin)`, `<Frost />` |
|
|
17
|
+
| Design line | `/css`, `/css/themes`, `/css/fonts`, `/theme`, `/theme/generate` | tokens, 19 themes, controls, theme runtime and generator |
|
|
18
|
+
|
|
19
|
+
## 1. Install (pick one)
|
|
20
|
+
|
|
21
|
+
**Package** (public npm registry):
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm i @yewdiel21/motion-kit gsap
|
|
25
|
+
npm i -D @material/material-color-utilities@^0.3.0 # only for the theme generator
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Copy the code** (editable, no runtime dependency on the package):
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
npx @yewdiel21/motion-kit list
|
|
32
|
+
npx @yewdiel21/motion-kit add tabs slot-text theme-picker --react --elements --dir src/motion-kit
|
|
33
|
+
npx @yewdiel21/motion-kit add theme neogreen oled
|
|
34
|
+
npx @yewdiel21/motion-kit add controls
|
|
35
|
+
npx @yewdiel21/motion-kit theme brand --seed "#ff6a3d" --out src/styles
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`add` copies each entry, what it `requires`, only the core files it imports, the base CSS (tokens, default theme, base, entrance states) and, with `--react` / `--elements`, the hook/component and custom element. Imports are relative, so nothing needs rewriting. `gsap` must be installed.
|
|
39
|
+
|
|
40
|
+
## 2. Wire it once
|
|
41
|
+
|
|
42
|
+
1. CSS: `import '@yewdiel21/motion-kit/css'` (tokens, default theme, controls, recipe and component styles). Add `/css/themes` (all 19) or `/css/themes/<id>` and, for fonts, `/css/fonts`.
|
|
43
|
+
2. Head, inline, in this order:
|
|
44
|
+
- `MK_THEME_HEAD_SCRIPT` (`/theme`): applies the stored theme/mode before the first paint.
|
|
45
|
+
- `MK_HEAD_SCRIPT` (`/auto` or `.`): adds `.mk-js` so entrances start hidden, `.mk-failed` if no recipe ran within 2.5 s.
|
|
46
|
+
3. `<body class="mk-app">` gives the page the theme's background, text colour and DM Sans.
|
|
47
|
+
4. Start things:
|
|
48
|
+
- **Astro / HTML**: `initTheme()`; `data-mk="<recipe>"` + `autoInit()`; `defineElements()` for `<mk-…>` components.
|
|
49
|
+
- **React / Next.js** (entries are `'use client'`): `<ThemeProvider>` at the root, hooks (`useTabs(ref)`), components (`<ThemePicker />`, `<SlotText text />`, `<AnimatedNumber value />`, `<FlipGroup>`). Keep `data-mk="<recipe>"` on recipe markup so the hidden entrance state applies before hydration.
|
|
50
|
+
|
|
51
|
+
## 3. Design line
|
|
52
|
+
|
|
53
|
+
- Colour: 37 Material 3 roles `--md-sys-color-*` per theme; components use the semantic layer `--mk-bg`, `--mk-surface`, `--mk-surface-1…5` (container lowest→highest), `--mk-text`, `--mk-muted`, `--mk-accent`, `--mk-on-accent`, `--mk-accent-soft`, `--mk-secondary-soft`, `--mk-outline(-soft)`, `--mk-error(-soft)`, `--mk-scrim`, `--mk-shadow-color`. Never hard-code colours in components: use these.
|
|
54
|
+
- Themes: `<html data-mk-theme="<id>" data-mk-mode="system|light|dark">`. Ids: blue, purple, neogreen (default), red, pink, pastel-pink, brown, super-blue, gray, oled (the 10 visible themes) + black, green, orange, cold-blue, modern-1, funny, new, new2, black-green. `setTheme(id)`, `setMode(mode)`, `getTheme()`, event `mk:theme`. Nested `[data-mk-theme]` sections work.
|
|
55
|
+
- Own brand colour: `applyTheme('#ff6a3d', { id: 'brand' })` at runtime, or `motion-kit theme brand --seed …` for a static file.
|
|
56
|
+
- Type: `--mk-font` (DM Sans), `--mk-font-mono` (Geist Mono), icons `.mk-icon` (Material Symbols Rounded). Scale classes `.mk-type-{display|headline|title|body|label}-{large|medium|small}`.
|
|
57
|
+
- Shape: capsules. `--mk-radius-{xs 8, sm 12, md 16, lg 24, xl 32, 2xl 40, 3xl 48, 4xl 64, full}`; bubble 32, dialog 40, chat 48, dock 64. Spacing `--mk-space-1…16` (4 px). Breakpoint 680 px.
|
|
58
|
+
- Controls (CSS only): `.mk-glass` (glass on any button/chip; `<span class="mk-glass__shadow">` inside for its shadow), `.mk-burger` (three lines → X with `aria-expanded`), `.mk-button--roll` (`.mk-roll[data-text]` for the label and `.mk-roll__arrow` for the arrow), `.mk-button` (`--primary`, `--tonal`, `--outlined`, `--text`, `--icon`, `--sm`, `--lg`; squash on pointer focus), `.mk-field` (+ `__label`, `__hint`, `aria-invalid`), `.mk-switch` (`<input type=checkbox role=switch>`), `.mk-checkbox`, `.mk-chip` (`--filter[aria-pressed]`, `--input`), `.mk-segmented` (with the `tabs` recipe), `.mk-icon`.
|
|
59
|
+
- Full table: [reference/design.md](reference/design.md).
|
|
60
|
+
|
|
61
|
+
## 4. Recipes
|
|
62
|
+
|
|
63
|
+
| Recipe | Markup | Key options (defaults) | Controls |
|
|
64
|
+
|---|---|---|---|
|
|
65
|
+
| `tabs` | root with `[data-mk-tab]` buttons and a `[data-mk-indicator]` (use `.mk-segmented`) | `orientation 'horizontal'`, `duration .45`, `onSelect(i, tab)` (event `mk:tab`) | `select(i)`, `index` |
|
|
66
|
+
| `counter` | element with a number | `to` (text), `from 0`, `duration .6`, `decimals`, `locale`, `prefix`, `suffix`, `trigger 'scroll'` | `play()`, `set(n)` |
|
|
67
|
+
| `details` | container of `<details>` (chevron `[data-mk-chevron]` in the summary) | — | — |
|
|
68
|
+
| `reveal` | element to uncover | `speed 'fast'\|'normal'\|'slow'\|'slower'`, `origin` (selector), `trigger 'manual'\|'load'` | `play(origin?)` |
|
|
69
|
+
| `reflow` | list with `[data-mk-item][data-flip-id]` | `duration .62` | `capture()` before the DOM change, `play()` after |
|
|
70
|
+
| `slot-text` | text element | `duration 300` ms, `stagger 45`, `maxTilt 5` | `set(text)` |
|
|
71
|
+
| `spring-cards` | root with `[data-mk-card]` children, each with `.mk-card__shadow` + image | `push .4`, `falloff 6`, `initialOffset 100`, `stiffness .05`, `friction .8`, `stagger .08`, `delay .4` | — |
|
|
72
|
+
| `curved-carousel` | root with `[data-mk-slide]`; optional `.mk-carousel__media`, `.mk-carousel__title` | `friction .85`, `throwBoost 2`, `wheel .2`, `startIndex 0`, `onSelect(i, slide)` (auto: `mk:select` event) | `next()`, `prev()`, `goTo(i)`, `index` |
|
|
73
|
+
| `pile` | `.mk-pile > .mk-pile__stack > .mk-pile__layer > .mk-pile__media`; back layers styled with `pileStyle(pileLayers(n, seed)[i])` | `threshold .25` | — |
|
|
74
|
+
| `words` | any text element | `by 'words'\|'chars'`, `trigger 'scroll'\|'load'\|'manual'`, `duration .8`, `stagger .1` | `reveal()`, `replace(mutate)` |
|
|
75
|
+
| `flow` | container; its children animate | `y 20`, `blur 16`, `duration .5`, `stagger .05`, `style 1\|2`, `trigger` | `play()` |
|
|
76
|
+
| `pop` | any element | `scale .7`, `duration 1.1`, `trigger` | `play()` |
|
|
77
|
+
| `fit-text` | one-line element inside a parent | `safety .995` | `refit()` |
|
|
78
|
+
| `stretch-footer` | `footer[data-mk="stretch-footer"]` containing `[data-mk-footer-title]`, plus a `[data-mk-phantom]` spacer after `<main>` | `lambda .9` | — |
|
|
79
|
+
| `radial-menu` | root with `[data-mk-toggle]` and `[data-mk-item]` direct children | `radius '3.6rem'`, `startAngle 1.5708`, `spacing .9` | `open()`, `close()`, `toggle()`, `isOpen` |
|
|
80
|
+
| `pill` | `.mk-pill` button, `.mk-stretch` link | CSS only | — |
|
|
81
|
+
| `mask-text` | any text | `by 'lines'|'words'|'chars'`, `y 100`, `duration 1.2`, `delay .1`, `stagger .02`, `trigger 'scroll'|'load'|'manual'`, `once` | `play()`, `hide()`, `split` |
|
|
82
|
+
| `cascade` | block with `[data-mk-cascade="rule|fade|rise"]` children (`rise` inside a clip) | `delay` (`data-mk-delay`), `step .03`, `duration 1.2`, `once`, `trigger` | `play()`, `reset()` |
|
|
83
|
+
| `text-roll` | a title | `trigger 'load'|'scroll'|'hover'|'manual'`, `delay`, `interval`, `duration 2`, `stagger .04` | `play()` |
|
|
84
|
+
| `letters` | a word | `effect 'scale'|'blink'`, `colors`, `autoplay` | `play()` |
|
|
85
|
+
| `parallax` | clipped frame with a picture (`[data-mk-parallax-target]`) | `amount 1`, `lerp 1`, `scroll` | `seek(p)` |
|
|
86
|
+
| `depth-grid` | grid container | `start 'top center'`, `end 'bottom bottom'`, `lerp 1`, `scroll` | `seek(p)` |
|
|
87
|
+
| `frame-zoom` | frame with one picture/video child | `start 'top bottom'`, `end 'bottom top'`, `lerp 1` | `seek(p)`, `open(on)` |
|
|
88
|
+
| `contrast` | header; sections with `data-mk-tone="light|dark"` | `sections`, `attribute 'data-mk-on'` | `tone` |
|
|
89
|
+
| `marquee` | strip whose first child is the group | `axis 'x'|'y'`, `speed 2` (s per item), `reverse` | `refresh()` |
|
|
90
|
+
| `card-dock` | `.mk-card-dock` with `.mk-card-dock__item` (> `a.mk-card-dock__card` + `.mk-card-dock__title`), optional `.mk-card-dock__cta`; `mk-card-dock--fixed` | `intro 1600` (ms spread on load, 0 skips) | `expand()`, `collapse()`, `expanded` |
|
|
91
|
+
| `snap-strip` | `.mk-snap-strip` with the cards as children | `autoplay`, `interval 5000`, `resume 2000`, `delay 500` (`data-mk-delay`) | `next()`, `previous()`, `index` |
|
|
92
|
+
| `fill-text` | any text | `from .2`, `start 'top 90%'`, `end 'center 40%'`, `scroll` | `seek(p)`, `progress` |
|
|
93
|
+
| `sortable` | root with `[data-mk-item][data-mk-id]` (optional `[data-mk-sortable-group="key"]` lists, `data-mk-sortable-locked`, `[data-mk-sort-handle]`) | `mutate true` (`false` in `useSortable`), `handle`, `autoScroll true`, `follow {1100, 38}`, `onReorder(detail)` (event `mk:reorder`, cancelable) | `cancel()`, `dragging` |
|
|
94
|
+
|
|
95
|
+
React hooks: `useCardDock`, `useSnapStrip`, `useFillText`, `useParticleHero`, `useMaskText`, `useCascade`, `useTextRoll`, `useLetters`, `useParallax`, `useDepthGrid`, `useFrameZoom`, `useContrast`, `useMarquee`, `useSortable`, `useTabs`, `useCounter`, `useDetails`, `useReveal`, `useReflow`, `useSlotText`, `useSpringCards`, `useCurvedCarousel`, `usePile`, `useWords`, `useFlow`, `usePop`, `useFitText`, `useStretchFooter`, `useRadialMenu`. Markup and options: each recipe's `README.md` (`src/recipes/<name>/`). Parameters and options: [reference/recipes.md](reference/recipes.md).
|
|
96
|
+
|
|
97
|
+
## 4b. Effects (v0.5)
|
|
98
|
+
|
|
99
|
+
| Name (`animate` / class `.mk-anim-<name>`) | Motion | Time |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| `out` / `out-left` / `out-bottom` | up 20 / left 64 / down 24 px, blur 16, fade | 0.5 s |
|
|
102
|
+
| `collapse` | folds height, padding and margin while blurring | 0.25 s |
|
|
103
|
+
| `highlight` | 4 px inner ring in primary-container | 1 s |
|
|
104
|
+
| `shake` / `shake-strong` | ±4 px / ±10 px | 0.5 s / 0.4 s |
|
|
105
|
+
| `fade`, `wipe`, `progress-in` | appear; a surface veil leaves to the right; appear late | 0.3 / 0.7 / 1 s |
|
|
106
|
+
|
|
107
|
+
`await animate(el, name)` replays even if already playing; `await leave(row, 'out-left' | 'collapse', { remove })` animates then removes (or hides). In React lists: `leave(item, 'out', { remove: false })`, then drop it from state. Classes: `.mk-loading` (+`--soft`), `.mk-shimmer`, `.mk-text-gradient` (theme), `.mk-text-rainbow`, `.mk-frost` (+ five `<i>`; `--top`, `--fixed`; `<Frost />`), `.mk-float` / `.mk-float-group`, `.mk-grain` (`--mk-grain`), `.mk-success` + `confetti(button)`. Reduced motion: loops stop, exits jump to the end, confetti does not draw.
|
|
108
|
+
|
|
109
|
+
## 5. Motion functions (no instance)
|
|
110
|
+
|
|
111
|
+
Use them inside your own components; they all honour reduced motion and return the tween (or `null`).
|
|
112
|
+
|
|
113
|
+
| Function | use |
|
|
114
|
+
|---|---|
|
|
115
|
+
| `flowIn(targets, { style, reverse, target })` / `flowOut(targets)` | lists, steps, settings entering / leaving |
|
|
116
|
+
| `stepChange(container, () => render next)` | wizard / onboarding steps (flow out → swap → flow in) |
|
|
117
|
+
| `flowInMenu`, `flowInPalette`, `flowInForm`, `flowInLanding`, `flowInContent` | menu options, swatches, form cards, landing, articles |
|
|
118
|
+
| `revealFrom(el, { origin, speed })` | a surface uncovered like a wave from the control that opened it |
|
|
119
|
+
| `toggleDetails(details, open)`, `installDetailsMotion(root)` | disclosures |
|
|
120
|
+
| `slideIndicator(indicator, target)` | any sliding selection indicator |
|
|
121
|
+
| `countTo(el, n)`, `revealCounter(el, n)`, `tweenNumber(a, b, cb)` | changing numbers, balances |
|
|
122
|
+
| `captureLayout` + `reflowLayout` | reorder / filter / add in lists |
|
|
123
|
+
| `enterMessages(bubbles)`, `fitComposer(textarea)`, `scrollToLatest(scroller)` | chat / comments |
|
|
124
|
+
| `capturePending(el)` + `morphPendingToReply(state, reply, list)` | a "thinking" placeholder turning into the answer (other frameworks) |
|
|
125
|
+
| `audioEnergy(stream, onEnergy)` | microphone level 0…1 for `chat-background` (never asks for the mic itself) |
|
|
126
|
+
| `channels(start, onChange)` + `spring()` / `eased()` | multi-property spring motion (liquid surfaces) |
|
|
127
|
+
| `trackScroll(el, { start, end, lerp, onUpdate })` | an element's 0→1 progress through the viewport (follows the page; `lerp < 1` smooths it) — build your own scroll effects |
|
|
128
|
+
| `motionSpring(stiffness, damping, mass?)` → `{ ease, duration }`, `springLinear(…)` | Motion/Framer springs as a GSAP ease or a CSS `linear()` |
|
|
129
|
+
| `sheetOpen`, `sheetClose`, `pushUnderlay`, `releaseUnderlay` | a sheet rising from the bottom while the page behind sinks |
|
|
130
|
+
| `morphOpen(surface, opener)`, `morphClose`, `morphCloseWithGhost`, `liquidOpen/Close` | any surface growing out of / folding into a control |
|
|
131
|
+
| `attachDragDismiss(surface, { onDismiss })`, `attachFloating`, `anchorSurface` | drag to dismiss, floating windows, anchored panels |
|
|
132
|
+
| `fadeBackdrop(dialog, 'in')`, `ghostOf`, `clearStyles` | backdrop tint, inert close copies, cleaning without GSAP measuring hidden nodes |
|
|
133
|
+
|
|
134
|
+
Curves: `EASE.signature`, `EASE.flow`, `EASE.fadeAway`, `EASE.blurAway`, `EASE.layoutReflow`…; CSS: `var(--mk-ease-signature)`, `--mk-ease-flow`, `--mk-ease-close`. Times: `TIMING.*`.
|
|
135
|
+
|
|
136
|
+
## 6. Components
|
|
137
|
+
|
|
138
|
+
| Component | HTML / Astro | React |
|
|
139
|
+
|---|---|---|
|
|
140
|
+
| `dialog` | `<button data-mk-open="crear">` + `<mk-dialog id="crear" heading="…" [description] [variant="liquid|sheet"] [placement="anchor\|side"] [size="sm\|lg\|xl"] [float="key"] [shared="id"] [no-backdrop] [persistent] [no-drag]>` (children → body; `data-mk-part="footer"` stays below) | `<Dialog.Root variant placement float…><Dialog.Trigger/><Dialog.Content size><Dialog.Header><Dialog.Title/><Dialog.Close/></Dialog.Header><Dialog.Body/><Dialog.Footer/></Dialog.Content></Dialog.Root>` |
|
|
141
|
+
| `menu` | `<button data-mk-open="m">` + `<mk-menu id="m" label="…">` with `<button data-mk-item data-mk-value>`; listen `mk:select` | `<Menu.Root onSelect><Menu.Trigger/><Menu.Content><Menu.Item value/><Menu.Separator/></Menu.Content></Menu.Root>` |
|
|
142
|
+
| `toast` | `<mk-toaster>` once + `toast('Copiado', { origin: button, tone, action })` | `<Toaster />` once + `toast(…)` |
|
|
143
|
+
| `theme-picker` | `<mk-theme-picker [show-hidden] [themes="a,b"]>` | `<ThemePicker themes showHidden onChange />` inside `<ThemeProvider>` |
|
|
144
|
+
| `chat` | `<mk-chat [background] [mic] placeholder="…">` (history `[data-mk-message][data-mk-role]` inside); `mk:send` → `el.add('user', t)`, `el.pending()`, `el.reply(answer)` | `<Chat.Root onSend><ChatBackground /><Chat.Messages pending>{<Chat.Message role/>}</Chat.Messages><Chat.Confirm/><Chat.Composer/></Chat.Root>`; set the reply and `pending=false` in the same render |
|
|
145
|
+
| `chat-background` | `<mk-chat-background energy scale>` first inside a positioned box; `el.busy(true)` | `<ChatBackground energy scale />` |
|
|
146
|
+
| `nav` | `<div class="mk-shell"><main class="mk-shell__view">…</main><mk-nav class="mk-nav mk-nav--bonita" nav-style="bonita" [accent] [reveal] [storage-key]><div class="mk-nav__buttons"><a class="mk-nav__button" href aria-current="page">…</a></div></mk-nav></div>`; `mk:navigate` | `<Nav navStyle items active onSelect first actions accent reveal />` inside `.mk-shell` |
|
|
147
|
+
| `cursor` | `<mk-cursor>` once (chip over `[data-mk-cursor="Label"]`, `data-mk-cursor-shape="circle"`, `data-mk-cursor-icon`) · `<mk-cursor variant="dot" text arrows>` inside a zone (`data-mk-cursor-hide` hides it) | `<Cursor />` · `<Cursor variant="dot" text arrows zone />` |
|
|
148
|
+
| `island` | `<mk-island [class="mk-island--contained"] [entrance="false|manual"]>` with `.mk-island__backdrop[data-mk-island-close]`, `.mk-island__shell` (glass, header, `[data-mk-island-toggle="menu"]` buttons, `.mk-island__cta`), `.mk-island__content > div > [data-mk-island-panel="menu"]` with `[data-mk-island-item]` rows and `.mk-island-card`s; `mk:island` | `<Island brand cta panels={[{ name, label, icon, light, content }]} contained onChange />` |
|
|
149
|
+
| `steps` | `<mk-steps class="mk-steps">` + `[data-mk-step]` sections, `[data-mk-flow-item]`, `[data-mk-counter]`, `[data-mk-step-next/prev/goto]`; `el.busy(on)`, `mk:step` | `<Steps index onChange busy><ChatBackground /><Steps.Counter /><Steps.Step>…</Steps.Step></Steps>` |
|
|
150
|
+
|
|
151
|
+
Register elements with `defineElements()` (or a list of tag names). Engines for your own markup: `createDialog(dialogEl, opts)`, `createMenu(dialogEl, opts)`, `createToaster(hostEl)`, `createThemePicker(el)`, `createChat(el)`, `createChatBackground(el)`, `createNav(navEl, { style })`, `createSteps(el)`.
|
|
152
|
+
|
|
153
|
+
Dialog behaviour: the opener turns into the dialog (0.7 s signature, colour handover 0.3 s, content from an 8 px blur) and it folds back on close (0.5 s, content blur 32 + radius 400, via an inert ghost so focus returns at once); without an opener it scales from .92. `data-mk-shared="id"` on a piece of the opener and of the dialog flies that text between them. Auto-resize 0.45 s; drag down > 100 px dismisses (also on phones); `float` lifts it into a movable, resizable window on desktop; full screen with radius 0 under 680 px. Events: `mk:open`, `mk:close` (cancelable), `mk:closed`. `[data-mk-close]` inside closes it. `open(null)` opens with no opener (scale-in).
|
|
154
|
+
|
|
155
|
+
Chat: bubbles grow from their speaker's side (scale .5, blur 24, 0.7 s) while words rise; "Pensando…" only after 500 ms, then it morphs (Flip 0.7 s) into the reply; Enter sends, Shift+Enter breaks the line; the composer grows from 64 px (0.18 s). Nav styles: `clasica`, `bonita`, `dock`, `guapa`, `tasks`, `melon`, `tunnel` (`NAV_STYLES`), one glass bar under 680 px; `accent` highlights the active page. Steps: flow out → swap → flow in (0.5 s), counter rolls, focus goes to the step's title. Sortable: lift 0.18 s, spring 1100/38, tilt up to 14°, neighbours slide 0.62 s, land 0.42 s; touch drags only from the handle; Space/arrows/Escape on the keyboard.
|
|
156
|
+
|
|
157
|
+
**Adding a component** (in the motion-kit repo): `pnpm new component <name>` scaffolds `src/components/<name>/{engine.ts, <name>.css, element.ts, react.tsx, README.md}`, a test, playground demos, the registry entry and the exports. Fill the engine (works on existing markup, defaults from `TIMING`, reduced motion, `destroy()` restores the DOM), then `pnpm test`. See [reference/components.md](reference/components.md).
|
|
158
|
+
|
|
159
|
+
## 7. Rules
|
|
160
|
+
|
|
161
|
+
- Call `destroy()` when the element leaves (hooks, components and `autoInit()`'s returned function do it). Never leave instances running on removed nodes.
|
|
162
|
+
- Respect reduced motion: everything here already shows the final state under `prefers-reduced-motion: reduce`; custom motion must check `reduced()` too.
|
|
163
|
+
- Flip contract: measure before the DOM change, animate after it (`capture()`/`play()`, `<FlipGroup signature>`).
|
|
164
|
+
- Text that changes: `words.replace(() => …)`, `fit.refit()`, `slot.set(text)` — don't re-create.
|
|
165
|
+
- Elements inside a closed `<dialog>`: create `words` with `trigger: 'manual'` and call `reveal()` after `showModal()`.
|
|
166
|
+
- `stretch-footer` needs the page above it: `main { position: relative; z-index: 1; background: var(--mk-bg) }`.
|
|
167
|
+
- Theme: style with `--mk-*` tokens and controls; switch with `setTheme`/`setMode` (or `useTheme()`), never by swapping stylesheets.
|
|
168
|
+
- Override look with CSS variables (`--mk-button-bg`, `--mk-field-radius`, `--mk-swatch-size`, `--mk-tabs-indicator`, `--mk-shadow`…), not by editing package code.
|
|
169
|
+
|
|
170
|
+
## 8. Choosing
|
|
171
|
+
|
|
172
|
+
- New app with look → `/css` + `/css/themes` + `/css/fonts`, `.mk-app`, controls, `theme-picker` in settings.
|
|
173
|
+
- Segmented filters / view switch → `.mk-segmented` + `tabs`. Totals → `counter` / `<AnimatedNumber>`.
|
|
174
|
+
- Lists that reorder → `reflow` / `<FlipGroup>`; lists the user reorders by dragging (tasks, kanban) → `sortable`; lists that appear → `flow` (or `flowIn`).
|
|
175
|
+
- Editorial headlines → `mask-text` (lines; `y 120` for film-title feel); credits / spec lists → `cascade`; a hero title that keeps alive → `text-roll` with `interval`; a playful word → `letters`.
|
|
176
|
+
- Photos in long pages → `parallax`; a gallery section → `depth-grid`; a video section → `frame-zoom`; header over dark/light sections → `contrast`; logos / festivals → `marquee` (+ `.mk-fade-x`).
|
|
177
|
+
- Site header for a product / landing → `island` (menu + cart share it); a product switcher pinned to a corner → `card-dock` (`--fixed`); phone carousels → `snap-strip`; a manifesto paragraph → `fill-text`; a hero with a living background → `particle-hero` from `/gl` (keep the text in HTML).
|
|
178
|
+
- Portfolio cards → `cursor` chip (`data-mk-cursor="View project"`); a draggable reel or full-bleed hero → `cursor` dot.
|
|
179
|
+
- Glass actions or tags over photos / colour → `.mk-glass` (+ `.mk-float-group` for floating tags); bottom fade over scrolling content → `.mk-frost`; a cinematic hero → `.mk-grain`.
|
|
180
|
+
- Removing rows → `leave(row, 'out-left' | 'collapse')`; form error → `aria-invalid="true"` (vibrates) or `animate(el, 'shake')`; success → `.mk-success` + `confetti(button)`; loading cards → `.mk-loading`; AI / premium labels → `.mk-text-gradient`.
|
|
181
|
+
- Project detail over the page → `dialog` with `variant="sheet"` and `data-mk-underlay` on the page; mobile menu toggle → `.mk-burger`; "Explore" CTA → `.mk-button--roll`.
|
|
182
|
+
- App frame → `.mk-shell` + `nav` (let the user pick the style; `storageKey` remembers it). Assistant / support chat → `chat` + `chat-background`. First-run setup → `steps` (with `ChatBackground` and `busy` while saving).
|
|
183
|
+
- FAQ / settings groups → `details`. Date/time popovers → `revealFrom` from the field.
|
|
184
|
+
- Language switch on a title → `slot-text`.
|
|
185
|
+
- Portfolio hero → `spring-cards` + a giant `fit-text words` title; featured projects → `curved-carousel`; archive → `pile`; last screen → `stretch-footer`; corner quick actions → `radial-menu`.
|
|
186
|
+
- Film navigation → `ticket-menu` or `<Menu.Root ticket>` / `<mk-menu ticket>`; preserves menu focus, selection and keyboard handling.
|
|
187
|
+
- Circular archive → `infinite-reel` (wheel, drag, keyboard, axis x/y); interactive card grid → `repel-bento`; testimonials → `rotator` (8 s, pause on focus/hover).
|
|
188
|
+
- Numeric experience/time selector → `drag-ruler` (role slider, 60 px/unit, step .1); a shared active indicator in navigation → `dock-pill` (spring 380/30). Navigation remains the app's responsibility.
|
|
189
|
+
- GPU image transitions → `createLiquidBlend`; metal study → `createMatcap`; film processing → `createShaderGrain` / `createShaderBlur`, all from `/gl`. React hooks `useLiquidBlend`, `useMatcap`, `useShaderGrain`, `useShaderBlur` are in `/react`. Import explicitly: these are not autoInit recipes. Retain accessible HTML images and set dimensions on the host. See [reference/recipes.md](reference/recipes.md) and each recipe README for the parameters and controls.
|
|
190
|
+
|
|
191
|
+
## Referencias y básicos (próxima versión)
|
|
192
|
+
|
|
193
|
+
- Contact CTA en tres piezas: `createJoinedCta`, `useJoinedCta`, `data-mk="joined-cta"`; tres spans dentro de `.mk-joined-cta`.
|
|
194
|
+
- Media contrazoom: `createImageZoom`, `useImageZoom`, `data-mk="image-zoom"`; `[data-mk-zoom-frame]` con imagen dentro.
|
|
195
|
+
- Fuente alternada/rodillo y overlay propio opcional: `createFontCycle`/`useFontCycle` (`font-cycle`); navegación de categorías con miniaturas: `createThumbnailNav`/`useThumbnailNav` (`thumbnail-nav`).
|
|
196
|
+
- Botones de presión y etiqueta film: `createActionButton`/`useActionButton` (`action-button`); hero editorial de cine: `createFilmHero`/`useFilmHero` (`film-hero`).
|
|
197
|
+
- Hero/tarjetas/contacto: `createEditorialReveal`/`useEditorialReveal` (`editorial-reveal`), compone mask-text/cascade/parallax/contrast.
|
|
198
|
+
- Dock bento: `createStudioDock`, `<StudioDock>`, `<mk-studio-dock>`, `useStudioDock`; páginas, contacto y reel.
|
|
199
|
+
- Video modal nativo: `createTrailer`, `<Trailer>`, `<mk-trailer>`, `useTrailer`; video suministrado por la app; fullscreen se aplica a su stage.
|
|
200
|
+
- Básicos: `createQuantity`/`<Quantity>`/`<mk-quantity>`; `createPagination`/`<Pagination>`/`<mk-pagination>`; `createHoverCard`/`<HoverCard>`/`<mk-hover-card>`; `createInputOtp`/`<InputOtp>`/`<mk-input-otp>`.
|
|
201
|
+
- Quantity limita min/max/step; pagination limita total/page y mantiene foco; hover-card soporta hover/foco/tap/Escape; OTP usa un input nativo con slots decorativos para pegado/autofill/ceros iniciales.
|
|
202
|
+
- En React, props value/page opcionales controlan el estado; al omitirlas los controles conservan edición/selección entre cambios de opciones.
|
|
203
|
+
- Calendario de citas: `createCalendar`/`<Calendar>`/`<mk-calendar>` (`calendar`); eventos `{id,title,start,end?,status?,color?}`, `setEvents`, `mk:select`/`mk:event`/`mk:navigate`; requiere `[data-mk-calendar-grid]`.
|
|
204
|
+
- Reservas/citas: `createSlotPicker`/`<SlotPicker>`/`<mk-slot-picker>` (`slot-picker`); `slots` lista, mapa por día o función/promesa; valor `YYYY-MM-DDTHH:mm` en `[data-mk-slot-value]` y `mk:change`.
|
|
205
|
+
- Titular que adelgaza bajo el puntero: `createWeightHover`/`useWeightHover` (`weight-hover`), fuente variable con eje `wght`.
|
|
206
|
+
- Stickers holográficos que se despegan: `createSticker`/`useSticker` (`sticker`), arte `.mk-sticker__pill`/`__badge`/`__art`, `--mk-sticker-rot`, `aria-hidden` si es decoración.
|
|
207
|
+
- Navegación que aparece con el scroll: `createScrollDock`/`useScrollDock` (`scroll-dock`), `hideWhen` para el footer, `.mk-scroll-dock--sticky` dentro de contenedores con scroll.
|
|
208
|
+
- Hora de otra zona: `createLocalClock`/`useLocalClock` (`local-clock`); píldora de disponibilidad `.mk-status` + `.mk-status__dot` (controles).
|
|
209
|
+
- Cada carpeta src/recipes/<name>/README.md o src/components/<name>/README.md define marcado, valores, eventos y controles. No reconstruir estas APIs por intuición.
|
|
@@ -8,19 +8,19 @@ A component brings its own markup and styles; recipes animate yours. Each one li
|
|
|
8
8
|
| `<name>.css` | Styles on `--mk-*` tokens; parts as `[data-mk-part="…"]`; own variables `--mk-<name>-*`. |
|
|
9
9
|
| `element.ts` | `<mk-<name>>` custom element on `MkElement` (light DOM). `static options` maps attributes (kebab-case) to engine options: `string`, `number`, `boolean` (presence), `list` (comma separated), `json`. The engine is created on connect, recreated on attribute change, destroyed on disconnect. |
|
|
10
10
|
| `react.tsx` | `'use client'` component that renders the root and creates the engine in a layout effect; callbacks read through refs; `className`, `style`, `unstyled`. |
|
|
11
|
-
| `README.md` | Markup (HTML and React), options/attributes, events, CSS variables, accessibility
|
|
11
|
+
| `README.md` | Markup (HTML and React), options/attributes, events, CSS variables, accessibility and parameter defaults. |
|
|
12
12
|
|
|
13
13
|
`registry.json` lists it (`kind: "component"`, `files`, `element`, `react`, `requires`, `since`). The CLI (`list`, `add --elements --react`), the CSS build (`dist/css/components/<name>.css`, included in `/css`), the playground and this skill read from there. `pnpm test` checks that every component has the five files.
|
|
14
14
|
|
|
15
15
|
## Add one
|
|
16
16
|
|
|
17
17
|
```sh
|
|
18
|
-
pnpm new component demo-card
|
|
18
|
+
pnpm new component demo-card # from the repo root
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
It writes the five files, `test/components/demo-card.test.ts`, `apps/playground/src/demos/demo-card/{Vanilla.astro,React.tsx}`, the registry entry (`since` = next minor) and the exports in `src/index.ts`, `src/react/index.ts` and `src/elements/index.ts`. Then:
|
|
22
22
|
|
|
23
|
-
1.
|
|
23
|
+
1. Implement the engine with defaults from `TIMING`, reduced-motion support and complete cleanup in `destroy()`.
|
|
24
24
|
2. Fill the README and the description in `registry.json`.
|
|
25
25
|
3. Extend the test (behaviour + destroy restores markup, with and without reduced motion).
|
|
26
26
|
4. `pnpm test`, `pnpm dev` and check the playground page in light and dark.
|
|
@@ -67,7 +67,7 @@ It writes the five files, `test/components/demo-card.test.ts`, `apps/playground/
|
|
|
67
67
|
## nav (v0.4)
|
|
68
68
|
|
|
69
69
|
- `createNav(nav, { style, accent, reveal, storageKey, labels, onSelect })` → `{ select(i | value), setStyle(name), setAccent(on), index, style, items, destroy }`. Items: `.mk-nav__buttons .mk-nav__button` (value = `data-mk-value` or `href`); current = `aria-current="page"`; click → cancelable `mk:navigate` (`detail.originalEvent` for SPA routers). `revealShell(nav)` uncovers `.mk-shell` from the first button.
|
|
70
|
-
- CSS:
|
|
70
|
+
- CSS: seven `.app-nav.style-N` as `.mk-nav--{clasica|bonita|dock|guapa|tasks|melon|tunnel}`, `variant-1` → `.mk-nav--accent`, mobile-style-1 under 680 px, shell `.mk-shell` / `__view` / `__header` / `__title` / `__content`. Names hidden by a style stay readable (clip, not display none). Current icon fills (`mk-nav-icon` 125 ms, `--mk-icon-fill` registered with `@property`).
|
|
71
71
|
- `<mk-nav nav-style accent reveal storage-key>` (style and accent change in place), `<Nav items active onSelect navStyle accent reveal first actions />`.
|
|
72
72
|
|
|
73
73
|
## steps (v0.4)
|
|
@@ -83,4 +83,4 @@ Reading a transform (`gsap.getProperty(el, 'y')`, Flip) also writes `translate/r
|
|
|
83
83
|
|
|
84
84
|
## Ticket menu (v0.8)
|
|
85
85
|
|
|
86
|
-
Use `<mk-menu ticket label="Sections">` or `<Menu.Root ticket>` for
|
|
86
|
+
Use `<mk-menu ticket label="Sections">` or `<Menu.Root ticket>` for ticket presentation. The existing menu engine still handles roles, roving focus, disabled items, selection, Escape, focus return and the dialog lifecycle. Direct factory: `createTicketMenu(dialog, MenuOptions)`; declarative: `data-mk="ticket-menu"`. It uses a local clip-path opening (.9 s) and rows from 150% (1.1 s, .02 stagger), adapting grid-row panels. The underlying `createMenu` also accepts `ticket: true`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Design
|
|
1
|
+
# Design tokens and themes
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Color roles, typography, shape and controls used by the components.
|
|
4
4
|
|
|
5
5
|
## Colour
|
|
6
6
|
|
|
@@ -23,22 +23,22 @@ Semantic layer (declared on `:root` and every `[data-mk-theme]`):
|
|
|
23
23
|
| `error-soft` / `on-error-soft` | error-container / on-error-container |
|
|
24
24
|
| `scrim` / `shadow-color` | scrim / shadow |
|
|
25
25
|
|
|
26
|
-
Note:
|
|
26
|
+
Note: dark palettes often set `primary` to white (neogreen dark: `#ffffff`) and put the colour in `primary-container` (`#00f46b`). That is why the default `.mk-button` uses `accent-soft`.
|
|
27
27
|
|
|
28
28
|
## Themes
|
|
29
29
|
|
|
30
|
-
| Id | Name |
|
|
30
|
+
| Id | Name | Visible by default | Seed (dark surface-tint) |
|
|
31
31
|
|---|---|---|---|
|
|
32
32
|
| blue | Blue | yes | #b3c5ff |
|
|
33
33
|
| purple | Purple | yes | #d2bcff |
|
|
34
|
-
| neogreen | Neogreen (default
|
|
34
|
+
| neogreen | Neogreen (default) | yes | #00e563 |
|
|
35
35
|
| red | Red | yes | #ffb4ac |
|
|
36
36
|
| pink | Pink | yes | #f7acff |
|
|
37
37
|
| pastel-pink | Pastel Pink | yes | #ffcee8 |
|
|
38
38
|
| brown | Brown | yes | #ffb783 |
|
|
39
39
|
| super-blue | Super Blue | yes | #bcc2ff |
|
|
40
40
|
| gray | Gray | yes | #c6c6c6 |
|
|
41
|
-
| oled | Oled (
|
|
41
|
+
| oled | Oled (dark theme; dark only, light uses Black) | yes | #9fb8e4 |
|
|
42
42
|
| black, green, orange, cold-blue, modern-1, funny, new, new2, black-green | — | hidden | see `THEMES` |
|
|
43
43
|
|
|
44
44
|
Selectors: light `[data-mk-theme="id"]`; dark `[data-mk-theme="id"][data-mk-mode="dark"]` or inside `[data-mk-mode="dark"]`; system dark through `prefers-color-scheme` unless `data-mk-mode="light"`. Default palette (neogreen) sits in `:where(:root)` with zero specificity.
|
|
@@ -55,15 +55,15 @@ Generator: `generateTheme(seed, { variant, contrast })` (Material Color Utilitie
|
|
|
55
55
|
| body | 16/24, 400, .5 | 14/20, 400, .25 | 12/16, 400, .4 |
|
|
56
56
|
| label | 14/20, 500, .1 | 12/16, 500, .5 | 11/16, 500, .5 |
|
|
57
57
|
|
|
58
|
-
Tokens `--md-sys-typescale-<role>-<size>-{font,size,line-height,weight,tracking}`; classes `.mk-type-<role>-<size>`.
|
|
58
|
+
Tokens `--md-sys-typescale-<role>-<size>-{font,size,line-height,weight,tracking}`; classes `.mk-type-<role>-<size>`. Font weights are unitless. Fonts: DM Sans (`--mk-font`), Geist Mono (`--mk-font-mono`), Material Symbols Rounded (`.mk-icon`).
|
|
59
59
|
|
|
60
60
|
## Shape, space, motion
|
|
61
61
|
|
|
62
|
-
- Radii: xs 8, sm 12, md 16, lg 24, xl 32 (bubble), 2xl 40 (dialog
|
|
62
|
+
- Radii: xs 8, sm 12, md 16, lg 24, xl 32 (bubble), 2xl 40 (dialog), 3xl 48 (chat window), 4xl 64 (mobile dock), full 999. Mobile dialogs go full screen with radius 0 under 680 px.
|
|
63
63
|
- Space: `--mk-space-n` = n × 4 px (1…16).
|
|
64
64
|
- CSS curves: `--mk-ease-signature`, `--mk-ease-tint` (same), `--mk-ease-flow` (`cubic-bezier(.25,.1,.25,1)`), `--mk-ease-close`, `--mk-ease-blur-away`, `--mk-ease-nav-radius` (`.38,.49,0,2`), `--mk-ease-nav-move` (`.38,.49,0,1.2`), `--mk-ease-swatch` (`.38,.49,0,1.5`), `--mk-ease-swatch-light` (`.11,1,0,1`), `--mk-ease-slot`. Durations `--mk-dur-fast .25s`, `--mk-dur .45s`, `--mk-dur-slow .7s`.
|
|
65
65
|
|
|
66
|
-
## Controls
|
|
66
|
+
## Controls
|
|
67
67
|
|
|
68
68
|
| Control | Values |
|
|
69
69
|
|---|---|
|
|
@@ -74,9 +74,9 @@ Tokens `--md-sys-typescale-<role>-<size>-{font,size,line-height,weight,tracking}
|
|
|
74
74
|
| Menu | radius 16 |
|
|
75
75
|
| Switch | 52 × 32 track, thumb 16 → 24 px |
|
|
76
76
|
|
|
77
|
-
## Glass
|
|
77
|
+
## Glass
|
|
78
78
|
|
|
79
|
-
`.mk-glass` on any button, link or chip; one element, no JS (`css/controls/glass.css`).
|
|
79
|
+
`.mk-glass` on any button, link or chip; one element, no JS (`css/controls/glass.css`). layers:
|
|
80
80
|
|
|
81
81
|
| Layer | Value |
|
|
82
82
|
|---|---|
|
|
@@ -84,9 +84,9 @@ Tokens `--md-sys-typescale-<role>-<size>-{font,size,line-height,weight,tracking}
|
|
|
84
84
|
| Ring (`::before`) | `conic-gradient(from var(--mk-glass-angle-1), …)` + vertical gradient, masked to a `clamp(1px, .0625em, 4px)` border (`mask-composite: exclude`); angle −75° → −125° on hover, 0.5 s (`@property`) |
|
|
85
85
|
| Shine (`::after`) | band `transparent → 55 % white 40–50 % → transparent` at `--mk-glass-angle-2` (−45°), `200% 200%`, `mix-blend-mode: screen`; position 0 % → 25 % hover → `50% 15%` and −15° pressed, 0.5 s `cubic-bezier(.25,1,.5,1)` |
|
|
86
86
|
| Shadow (`.mk-glass__shadow`, optional) | blurred gradient ring 22 % → 10 % black (dark 85 % → 55 %) under the button; only its lower part shows |
|
|
87
|
-
| Press | `scale(.95)` on
|
|
87
|
+
| Press | `scale(.95)` on 400/10 spring (`--mk-ease-press`, `--mk-dur-press`) |
|
|
88
88
|
|
|
89
|
-
Light/dark through `light-dark()` (themes set `color-scheme`). Without `backdrop-filter`: an almost opaque background. It is layered CSS, not refraction
|
|
89
|
+
Light/dark through `light-dark()` (themes set `color-scheme`). Without `backdrop-filter`: an almost opaque background. It is layered CSS, not refraction.
|
|
90
90
|
|
|
91
|
-
Related tokens: `--mk-ease-glass`, `--mk-ease-sheet`, `--mk-ease-
|
|
91
|
+
Related tokens: `--mk-ease-glass`, `--mk-ease-sheet`, `--mk-ease-quint`, `--mk-ease-press` / `--mk-dur-press` (400/10), `--mk-ease-success` / `--mk-dur-success` (260/18). `motionSpring(k, c)` and `springLinear(k, c)` turn any Motion spring into a GSAP ease or a CSS `linear()`.
|
|
92
92
|
|