@cadencestudio/creative-kit
v0.2.1
Published
Cadence Studio shared creative plumbing. Motion presets, scroll orchestration, a Rive wrapper, the SgIcon system, view transitions helpers, and a reduced motion guard. Token agnostic by contract: the host app supplies all colors, durations, easings, and g
Readme
@cadencestudio/creative-kit
Cadence Studio's shared creative plumbing. One package, built and maintained once, that every Cadence build installs to get our motion, scroll, Rive, icon, and transition primitives.
The kit is token agnostic and framework modular: it defines the contract, the host app supplies its own tokens and brand art. It ships plumbing only. No brand animations, no brand glyphs, no colors, no durations.
Install
Published PREBUILT to the public npm registry (dist/ ships in the artifact;
consumers never run a build or lifecycle script at install time, so
--ignore-scripts CI and Vercel installs just work):
npm i @cadencestudio/creative-kitThen install the peer dependencies your entry points need (see the table below). The kit bundles none of them.
Versions before 0.2.0 installed as a private git dependency
(github:cadence-studio-creative/creative-kit#v0.1.x) and built at install
time via a prepare script. That method is retired; migrate any consumer still
on it to the registry package.
Entry points
| Entry | What it gives you | Peer deps required |
| --- | --- | --- |
| @cadencestudio/creative-kit/motion | useMotionPresets (fade, slideUp, stagger), ckTransition, CK_TOKENS | motion, react |
| @cadencestudio/creative-kit/scroll | registerScroll, useGsapContext, useScrollDeck | gsap, react |
| @cadencestudio/creative-kit/rive | <RiveGraphic> with built in reduced motion and load failure fallback | @rive-app/react-canvas, react |
| @cadencestudio/creative-kit/icons | createSgIcon (typed sprite icon factory), fromLucide adapter | react (lucide-react only if you use fromLucide) |
| @cadencestudio/creative-kit/transitions | startViewTransition, supportsViewTransitions, viewTransitionName | none |
| @cadencestudio/creative-kit/a11y | useReducedMotion hook, prefersReducedMotion check | react (hook only) |
| @cadencestudio/creative-kit/tooling/icons/build-sprite | Node script: glyph dir in, sprite.svg + IconName union out | svgo (host devDependency) |
Every module respects prefers-reduced-motion through the shared a11y
guard: presets collapse to instant state changes, the scroll deck stops
snapping, Rive renders its static fallback, and view transitions skip the
crossfade while still applying the DOM update.
Choosing a motion library
Three motion technologies ship here on purpose, because they solve different problems. Pick by what the motion is, not by habit. If two seem to fit, prefer the one earlier in this list and reach for a second only when the first genuinely cannot do the job. That discipline is what keeps three libraries from turning into three ways to do one thing.
transitions(View Transitions + CSS), the free baseline. Start here. Page and same-page DOM crossfades, plus anything CSS@keyframesor Tailwind animate utilities can express. Zero JS bundle. If a CSS transition or a view transition does it, stop here.motion(Motion), the default for React UI motion. Component and state-driven animation: enter and exit, layout shifts, list reordering, hover, tap, drag, presence. Declarative and tied to the React lifecycle. The workhorse for everyday interface motion once CSS is not enough. Reach for it when the animation belongs to a component's state.scroll(GSAP + ScrollTrigger), scroll-driven and timeline choreography. Motion driven by scroll position, or precise multi-step timelines that outgrow declarative component animation: hero choreography, scroll-linked reveals, pinned scroll decks, sequenced storytelling. Keep it to brand-narrative surfaces. Do not use it for data-dense UI, wheremotionor plain CSS is lighter and simpler.rive(Rive), authored interactive vector art only. A designed vector artboard with its own state machine, authored by a designer in Rive: mascots, icons that morph on input, loaders, signature brand motion. It renders a canvas graphic, not DOM, so never use it to animate or lay out interface elements. If the motion is not a purpose-built Rive artboard, it is not a Rive job.
Tie-breaker, in order:
- Can CSS or a view transition already do it? Use
transitionsand skip the rest. - Is DOM or React state animating? Use
motion. - Is it driven by scroll, or a precise timeline? Use
scroll(GSAP). - Is it a designed, interactive vector artboard? Use
rive.
Per framework guide
| | Next.js (App Router) | Astro (React islands) | React Native / Expo |
| --- | --- | --- | --- |
| motion | Yes | Yes, inside a React island | No. Use the RN Reanimated stack; this web kit is out of scope |
| scroll | Yes | Yes, inside a React island | No |
| rive | Yes (client component) | Yes, inside a React island | No. RN hosts swap in rive-react-native |
| icons | Yes | Yes (component in islands; the sprite itself also works from plain Astro markup via <use>) | Component is web only; the sprite BUILD tooling still works for generating assets |
| transitions | Yes | Prefer Astro's built in view transitions for routing; use this module for imperative same page updates | No |
| a11y | Yes | Yes, inside a React island | No. Use RN's AccessibilityInfo.isReduceMotionEnabled |
| Peer deps to install | motion, gsap, @rive-app/react-canvas (plus lucide-react if used) | @astrojs/react, react, react-dom, plus the peers for the entries you use | n/a for this kit |
| Notes | All entries are prebuilt with the "use client" directive; import them directly from server components without wrapper files | Islands need a client: directive (client:visible fits scroll and Rive work) | RN is intentionally out of scope for v0.x |
Token contract
The kit never hardcodes a color, duration, easing, or distance. The host
defines these CSS custom properties (usually on :root), mapped from its own
brand tokens:
| Token | Type | Used by | Example shape |
| --- | --- | --- | --- |
| --ck-duration-fast | time (ms or s) | motion | small hovers and micro fades |
| --ck-duration-base | time | motion | default reveal speed |
| --ck-duration-slow | time | motion | large surface reveals |
| --ck-ease-standard | cubic-bezier(...) or CSS keyword | motion | default easing |
| --ck-ease-emphasized | cubic-bezier(...) or CSS keyword | motion (opt in via easeToken) | entrances that should feel springy |
| --ck-motion-distance | length (px or rem) | motion | slide up offset |
| --ck-stagger-step | time | motion | delay between staggered children |
Token names are exported as CK_TOKENS from the motion entry. Behavior when
a token is missing: time and length tokens fall back to 0 (instant, no
offset) and easing tokens fall back to the library default, each with a one
time console warning. Define the contract and you will never see the warning.
Colors are never read by the kit at all: icons and glyphs inherit
currentColor, and everything else (deck panel styling, transition visuals)
is host CSS.
Performance and spend
The kit is sideEffects: false and split per entry point, so a primitive's cost
(and its peer dependency) only ships to the pages or islands that import it.
Nothing is global. transitions and a11y are tiny; scroll pulls in GSAP and
rive pulls in the Rive WASM runtime, so those two are the ones to spend
deliberately.
Match the spend to the surface:
- Content and client sites can use motion freely where it serves the work.
- Lean, SEO-critical surfaces (a marketing site whose speed is itself a
selling point) should treat each primitive as opt-in per page, not a default.
Add motion only where a page earns it, and keep the rest zero-JS. A consumer
with a strict speed budget should write its own rule down in its README; see
cadence-sitefor a worked example.
The SgIcon system
The kit ships the pattern, not the glyphs:
Put your brand glyphs in a directory, one
.svgper icon.Add
svgoas a devDependency and generate the sprite plus the type union:node node_modules/@cadencestudio/creative-kit/tooling/icons/build-sprite.mjs \ --in src/icons --out public/icons/sprite.svg --types src/icon-names.tsCreate your typed component once:
import { createSgIcon } from "@cadencestudio/creative-kit/icons"; import type { IconName } from "./icon-names"; export const SgIcon = createSgIcon<IconName>("/icons/sprite.svg");Use it:
<SgIcon name="wave" />. Unknown names are compile errors.
Glyph colors are normalized to currentColor by the shared SVGO config, and
icons default to 1em so they scale with the text they sit beside.
Example app
examples/kitchen-sink is a Vite React harness that imports every entry
point, renders one of each primitive, and builds clean. It doubles as the
reference for the token contract stub (see src/styles.css). It is not part
of the published package.
npm install && npm run build # build the kit
cd examples/kitchen-sink
npm install
npm run icons # prove the sprite tooling
npm run build # typecheck + vite build
npm run dev # eyeball itReleases
npm version <patch|minor|major> # bumps package.json and tags vX.Y.Z
git push origin HEAD --tags
npm publish # prepack builds dist/ into the tarballConsumers are on semver ranges (^0.x), so Renovate picks up new releases
from the registry automatically. After a minor or major bump, also update the
version references in cadence-skills (standing rule + starter templates).
