npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sharedex/ui

v0.10.0

Published

Headless React components: an animated carousel with pure-function layout effects, page sections (Hero, About, Services, Contact) with layout presets and token-driven default looks, and 88 background effects (CSS, SVG, canvas, WebGL, Three.js) on one chea

Readme

@sharedex/ui

A headless, animated carousel for React — where every visual effect is a pure function.

Coverflow, a fanned hand of cards, a spotlight, a deck, a wave — each is a ~10-line function of one number, not a fork of the library. Physics is a config field. The markup is entirely yours.

React 19 · motion · Tailwind v4 preset · ESM · RSC-safe


The idea

Most carousels give you a component and a bag of boolean props. This one gives you a small engine and four clean seams:

Config for numbers. Pure functions for motion. Children for markup. Hooks for anything that writes.

  • Numbers — gap, buffer, autoplay delay, axis — live in one five-section config object.
  • Motion — what a card looks like at a given distance from centre — is a pure (buffer, slot, frame) => void function. Swap it, compose it, write your own.
  • Markup — the card itself — is your component. The library never renders a pixel of content.
  • Writes — filtering, stepping, jumping — go through hooks and a typed engine handle.

Everything visual is derived from one unbounded float — a card's signed, fractional distance from the centre. A slot 1.5 positions to the right is at distance = 1.5; its transform, opacity and z-index all fall out of that.

Effects

| Preset | What it does | | --- | --- | | wave() | Cards at their measured pitch; height swells along a curve peaking at centre. The default. | | scale() | Centre card full size, every other card smaller the further out it sits. | | coverflow() | Neighbours turn away in 3D and sink back on the z-axis; distant cards converge into a stack behind the centre instead of stringing across the screen. | | fan() | A hand of cards, each tilted around a pivot below the deck so the row bows into an arc. | | spotlight() | One card in focus; the rest shrink, dim, and blur out of it. | | deck() | A near-solid pile — cards behind nudge down and tilt a few degrees. | | panorama() | A curved strip seen from inside: the outer cards come closer, look bigger and turn in. | | expo() | Small cards on one line; the active one opens to full size and pushes the others aside. | | material() | The Material You hero carousel: one large card, clipped (not squashed) strips of its neighbours. | | superFlow() | A scale row whose cards lean back against the motion while it moves. | | barrel() | Cards around the outside of a cylinder; with no angle a full circle that turns forever. | | helix() | A spiral staircase: each card a step further round the axis and a little further along it. | | ring() | Cards around a flat circle like a clock face, each pointing outward; an open arc with angle. | | staircase() | A row on a slanted track that also runs into the page: the next cards climb up and back. | | fallAway() | Leaving cards drop (or rise), turn, shrink, blur and fade with their distance from the focus. | | sphere() | Cards on a globe that turns so the focused card faces you; drag walks a loop over the whole sphere. |

// A subtle 3D lean, in full — this is a complete, usable effect:
export const tilt = () =>
  composeLayout(
    "tilt",
    track({ overlap: 0.15 }),
    curve("rotateY", [-1, 0, 1], [12, 0, -12]),
    curve("opacity", [-2, 0, 2], [0.4, 1, 0.4]),
  );

Physics is just as swappable — momentumSnap (flick, decay, land on a slot), snapToNearest (spring to the closest), freeScroll (coast to a stop), or pagedBy(n) (advance in groups). One config field each.

Beyond one row

  • Speed looks: modify(layout, speedWave(), speedTilt()) adds a wave or a lean while the cards move, exactly zero at rest.
  • Scroll-driven: useScrollLink(engine, { pxPerCard }) lets the page scroll turn the carousel.
  • Morphs: change config.layout and every card springs from the old shape into the new one (list → helix → sphere), each a few ms after its neighbour.
  • Enter and exit: engine.enter / engine.exit take a preset (presence.fade, contract, expand, scatter, slideAlong) for the first reveal, filter swaps and engine.hide() / show().
  • Open views: engine.open: openView.detail() (a big card over a thumbnail strip), panel() (with <Carousel.Panel> for your text) or inline(); engine.open(i) / close(), Esc.
  • Stacks: stage(cardStack({ exit: "throw" })) is a deck you swipe cards off.

How it's built

  • One source of truth. position is an unbounded float in index space, not pixels. There is no scroll container, no accumulated offset, no ring width to measure — a slot's placement is a pure function of its own distance.
  • One write per slot per frame. A layout resolves into a single serialized transform string, which short-circuits motion's 18-property serialisation loop. A rich seven-term coverflow costs the same as a two-term wave.
  • Virtualized. Only 2·buffer + visible slots mount, however many items exist. Looping is a modulo, not cloned nodes.
  • Zero-allocation reads. Frame and slot state are read into caller-owned objects reused every frame — no garbage on the hot path.
  • Split contexts. A motion slice (stable refs / MotionValues) and a data slice (filter, metrics) so a hover or a resize doesn't re-render every card.
  • Pixel-identity gated. The wave preset is frozen and tested bit-for-bit against motion's own interpolator, so the core animation can never silently drift.

Install

npm install @sharedex/ui

Peers: react 19, react-dom 19, motion 12, 13 or 14; three ≥ 0.165 only for @sharedex/ui/three (optional). ESM only, ships compiled dist/ with types. SSR / React Server Component safe (a "use client" island, no next dependency).

Wire up Tailwind (v4)

In your Tailwind entry stylesheet, after @import "tailwindcss";:

@import "tailwindcss";
@import "@sharedex/ui/theme.css";

theme.css registers three namespaced color tokens (--color-sx-primary, --color-sx-secondary, --color-sx-accent) and tries to add this package's compiled code as a scan source.

If a component renders unstyled, add an explicit source (adjust the ../ depth to your node_modules):

@source "../node_modules/@sharedex/ui/dist/**/*.js";

Theming / dark mode

Override the tokens in your own @theme (it runs after the import and wins), or under a dark selector ([data-theme="dark"], @media (prefers-color-scheme: dark)). The carousel reads only those three tokens.

[data-theme="dark"] {
  --color-sx-primary: #e7f2f1;
  --color-sx-secondary: #0b1416;
  --color-sx-accent: #6c5ce7;
}

The package ships no --breakpoint-* — the sm: / md: / lg: steps in your slotClassName resolve to your own breakpoint scale.

A taste

import { Carousel, coverflow, snapToNearest } from "@sharedex/ui";

const CONFIG = { layout: coverflow(), physics: { settle: snapToNearest() } };
const SLOT = "w-[240px] sm:w-[280px] h-80"; // width/height here IS the pitch

export function Templates({ items }) {
  return (
    <div className="mx-auto w-full max-w-3xl">
      <Carousel.Root items={items} config={CONFIG} slotClassName={SLOT}>
        <Carousel.Viewport>
          <Carousel.Track>
            <Carousel.Window>
              {(slot) => (
                <Carousel.Slot key={slot.key} index={slot.index}
                  ringIndex={slot.ringIndex} itemIndex={slot.itemIndex}>
                  {slot.item ? <MyCard item={slot.item} /> : <MyPlaceholder />}
                </Carousel.Slot>
              )}
            </Carousel.Window>
          </Carousel.Track>
        </Carousel.Viewport>
      </Carousel.Root>
    </div>
  );
}

Drag and autoplay come for free from Track. Arrows, filter pills and pagination you build from the engine handle — a render-prop form of Root hands it to you.

  • Memoize items (and a custom filters array, and the config object). A new identity on every parent render rebuilds the slot ring / re-resolves the engine config.
  • Wrap a horizontal carousel in a parent with a definite width; give a vertical one (config={{ engine: { axis: "y" } }}) a sized viewport.

Controls & filters

Built-in Controls / Filters components are on the roadmap. For now use the render-prop form of Root to reach the engine handle:

<Carousel.Root items={ITEMS} filters={FILTERS} config={CONFIG} slotClassName={SLOT}>
  {(engine) => (
    <>
      {FILTERS.map((f) => (
        <button key={f.value} aria-pressed={engine.filter === f.value}
          onClick={() => engine.setFilter(f.value)}>
          {f.label}
        </button>
      ))}
      <Carousel.Viewport>{/* … Window … */}</Carousel.Viewport>
      <button onClick={() => engine.stepBy(-1)}>‹</button>
      <button onClick={() => engine.stepBy(1)}>›</button>
    </>
  )}
</Carousel.Root>

A filter swap fades the carousel out and back in. With engine: { filterTransition: "view" } the browser's View Transitions API plays it instead: cards in both lists move to their new place and the rest fade (a plain fade where the API is missing or motion is reduced).

config is a five-section partial (engine, physics, autoplay, layout, a11y). Build a project-wide baseline once with defineCarouselDefaults(...) and pass it as base=.

Anatomy

flowchart TD
  Root["Carousel.Root — items, config, filters, the engine"]
  Viewport["Carousel.Viewport — measured region, gestures, sizing probe"]
  Track["Carousel.Track — drag + autoplay, the reveal / cross-fade"]
  Window["Carousel.Window — virtualization, one WindowSlot per mounted position"]
  Slot["Carousel.Slot — the resolved transform; your card inside"]
  Root --> Viewport --> Track --> Window --> Slot

Page sections

Since 0.3.0 the package also ships headless page sections: Hero, About, Services and Contact. Each gives you layout presets, a typed content shape and the right semantics; the look is yours.

import { Hero } from "@sharedex/ui";

<Hero.Root
  layout="split"   // "split" | "centered" | "media-background"
  content={{
    title: "Fresh bread every morning",
    actions: [{ label: "Order for tomorrow", href: "/order" }],
    media: { kind: "image", src: "/bread.jpg", alt: "Loaves on a rack" },
  }}
/>
  • Default looks come with theme.css: plain CSS in Tailwind's components layer, built only on the sx-* tokens. Any class you pass via className sits in the later utilities layer, so it always wins.
  • unstyled on a section's Root drops the look and keeps the layout.
  • Layouts use container queries, so a section responds to the width it gets, not the viewport, and mirrors correctly in RTL.
  • Guides for Claude Code ship in guides/ (node_modules/@sharedex/ui/guides/hero.md …).
  • background on any section's Root takes a decorative layer (below).
  • reveal on any section's Root makes its main parts appear one after another as it scrolls into view (reveal, reveal={blurFade()}, reveal={{ effect, stagger, delay }}; see Transitions below).

Backgrounds

Since 0.4.0: 88 background effects (patterns, gradients, particles, scroll effects, shaders, fluid, 3D) as pure descriptions, plus image() / video() slots for your own files. One runtime under <Background.Root> pauses them off screen, honours reduced motion, caps the pixel ratio and picks a still fallback on devices too weak for an effect.

import { Background, Hero, aurora, filmGrain } from "@sharedex/ui";

<Hero.Root
  content={heroContent}
  background={
    <Background.Root>
      <Background.Layer effect={aurora({ speed: 0.6 })} />
      <Background.Layer effect={filmGrain({ opacity: 0.08 })} />
    </Background.Root>
  }
/>
  • Pay for what you mount. CSS effects inject their stylesheet only when used; WebGL effects run on a ~2 KB runner (no Three.js) and give their context back while off screen.
  • Three.js effects (liquidGlass, chrome, neonTubes …) live in a separate entry, @sharedex/ui/three, with three as an optional peer: npm i three only if you use them.
  • Tiers. Every effect is tagged all, mid or high (from the owner's Background Effects Atlas); heavier ones render their CSS fallback until the device is known, during SSR, and on weaker devices.
  • Guide for Claude Code: node_modules/@sharedex/ui/guides/backgrounds.md.

Transitions

Since 0.5.0: 40 transitions that play at a moment, every one a function of one number p (0 = hidden, 1 = shown): 8 one-card carousel looks, 18 CSS / SVG masks and reveals, 14 WebGL shaders on pictures. The same transition plays in a one-card carousel (dragging scrubs it) and as a section reveal.

import { Carousel, Reveal, Services, stage, cube, fadeUp, wipe, blurFade } from "@sharedex/ui";

<Carousel.Root items={slides} config={stage(cube())}>…</Carousel.Root>   // one card at a time
<Reveal effect={wipe({ from: "start" })}><img src="/team.jpg" alt="" /></Reveal>
<Services.Root content={services} reveal={blurFade()} />                // parts one after another
  • Reveals: Reveal, Reveal.Group (staggered), trigger="scroll" to follow the scroll, and the reveal prop on every section.
  • Shaders (noiseBurn, ripple, displacement, pageCurl …) blend pictures on one canvas (Carousel.Shader, <Reveal image>); weaker devices play a CSS fallback.
  • Scroll compositions: Curtain, StackCards, PinnedExpand, TextMaskZoom, SplitText, on native scroll timelines with a shared fallback.
  • Multi-card looks panorama, expo, material, superFlow, and engine.filterTransition: "view" for filter swaps with the View Transitions API.
  • Reduced motion and RTL are handled; no animation library beyond motion.
  • Guide for Claude Code: node_modules/@sharedex/ui/guides/transitions.md.

Ticker

A continuous marquee for items of any size, its own component (not a carousel option).

import { Ticker } from "@sharedex/ui";

<Ticker items={tools} velocity={60} gap={12} fade={64} hoverSpeed={0.2} drag aria-label="Tools we use">
  {(tool) => <span className="rounded-full border px-4 py-2">{tool}</span>}
</Ticker>
  • Drivers: time (velocity, px/s, the sign is the direction), any MotionValue as offset (page scroll for bands that move with the page, one each way), and drag with a glide on release. They add up.
  • Loops without a jump: the set is repeated just enough to cover the box plus one set, and one transform moves the row by the offset modulo the set's length. One ResizeObserver measures.
  • axis="y" for columns, fade for a CSS mask on both edges, hoverSpeed to slow or pause it under the pointer or keyboard focus. RTL runs towards the reading start; reduced motion keeps it still; copies are aria-hidden and inert; the time loop stops off screen.

Grid

An endless plane of cards you pan in any direction, flat or leaning back in 3D. Its own component.

import { Grid, gridOpen, type GridCell } from "@sharedex/ui";

<Grid.Root items={pieces} columns={6} gap={28} stagger={0.5} tilt={{ x: 24, z: -8 }} bulge={140} fog snap
  open={gridOpen.panel()} cellClassName="w-[200px] h-[250px]">
  <Grid.Viewport className="h-[80vh]" aria-label="Collection">
    {(cell: GridCell<Piece>) => <Card item={cell.item} />}
  </Grid.Viewport>
  <Grid.Panel>{(piece: Piece) => <Notes piece={piece} />}</Grid.Panel>
</Grid.Root>
  • Endless, virtualized: items are laid out in rows of columns and repeat by position (no copied data); only the cells on screen are mounted. stagger bricks the rows; repeat: "blank" leaves a short last row empty.
  • Drag in any direction with a glide; snap lands on a card. On a tilted plane the card under the finger stays under it. Opt-in wheel panning and an idle drift.
  • Looks: tilt (one 3D stage), bulge (a dome towards you at the centre), fog (fade with distance), or your own per-cell modifiers.
  • Open views: gridOpen.zoom(), strip() (a big card over a thumbnail strip) and panel() (room for Grid.Panel); the open card stands upright even on a tilted plane.
  • One tab stop with arrow keys, Enter to open, a live region naming the centre card; RTL; reduced motion.

Buttons

Button wears any number of effects at once: 73 effects from the owner's Button Effects Atlas (fills, borders, glow, depth, cursor, label and icon, press, state, idle, glass), each a plain descriptor.

import { Button, Hero, useButtonAction, glowShine, cursorMagnet, stateSwap } from "@sharedex/ui";

const primary = [glowShine(), cursorMagnet()];          // module level, like every effect

<Button effect={primary}>Book now</Button>
<Button as={Link} href="/shop" variant="outline">Shop</Button>

const save = useButtonAction(async () => { await post(); }, { resetAfter: 2000 });
<Button {...save} effect={stateSwap()} labels={{ loading: "Saving", success: "Saved" }}>Save</Button>

<Hero.Root content={content} actionEffect={primary} />   // the Hero's first action wears them
  • The element you click never moves. Hover and press come from a still outer element; what you see moves inside it, so a magnet or a lift never flickers at the edge. className styles what you see, hitClassName the outer element.
  • Effects stack (each paints its own layer, and two that would fight over one motion are reported in dev), ship their stylesheet only when mounted, and turn off under reduced motion. Heavy ones wear a -lite version on weaker devices.
  • Server Components: almost every effect is plain data. Six carry code (pressSpark, pressBurst, pressConfetti, pressSpray, labelScramble, glassRefract) and need a client page.
  • Busy is not disabled: state="loading" keeps focus, blocks a second click and announces the words.
  • Sections: actionEffect on Hero.Root renders its actions as Buttons. Left out, they stay plain links. Buttons follow the new --radius-sx-button token (the control radius unless a design sets its own).
  • Guide for Claude Code: node_modules/@sharedex/ui/guides/buttons.md.

Text

Text wears any number of text effects: 69 effects from the owner's Text Effects Atlas plus rows found online (entrances, fills, outlines and drawings, scramble, scroll, hover, glitch and warp, depth), each a plain descriptor. Typewriter, WordCycle, NumberRoll and TextPath cover text that changes or follows a shape; Text3D is in @sharedex/ui/three.

import { Text, Hero, About, WordCycle, NumberRoll, enterRise, inkGradient } from "@sharedex/ui";

const title = [enterRise({ by: "chars" }), inkGradient()];   // module level, like every effect

<Text as="h2" effect={title}>Fresh bread, every morning</Text>
<h1>We bake <WordCycle words={["bread", "cakes", "pies"]} look="flip" /></h1>
<NumberRoll value={1250} format={{ style: "currency", currency: "EUR" }} />

<Hero.Root content={{ title: "We build", titleWords: ["sites", "apps"] }} titleEffect={title} titleCycle={{ look: "flip" }} />
<About.Root content={content} statRoll={{ look: "spin" }} />   // "40+" rolls to 40, keeps its +
  • The words a reader gets and the pieces that move are two different things. One readable copy for screen readers and search engines; the moving letters, words, lines, copies and canvases are hidden from them. Words and letters are cut on the server, so the HTML holds the real text; nothing is hidden without a way back.
  • Effects stack (an entrance with a fill or a hover; two on one channel are reported in dev), letters are cut only where they stand alone (Arabic moves by the word), heavy ones wear a lighter version on weaker devices, and reduced motion shows the text still, in its look.
  • Sections: every Root takes titleEffect and eyebrowEffect; the Hero's content.titleWords + titleCycle add a cycling word; About's statRoll rolls the figures. Left out, the markup is as before.
  • Server Components: most effects are plain data; 17 carry code or pick by device and need a client page (the guide lists them).
  • Guide for Claude Code: node_modules/@sharedex/ui/guides/text.md.

Forms

Form controls whose real native element does all the work (the label, the keyboard, autofill, password managers, screen readers, a plain form submit), wearing any number of the 91 form effects from the owner's Form Effects Atlas plus rows found online: Field (with built-in tools: clear, show password, Caps Lock, counter, strength, an async check, a hint, auto-grow, inline), Checkbox, CheckGroup, RadioGroup, Switch, Select, our own Combobox, Range, NumberField, OtpField, TagsField, ChipGroup, FileDrop, FormSteps, FormReveal, FormSwap, InlineEdit, ErrorSummary, SaveStatus, PasswordRules and FormBuddy, a sign-in companion of our own.

import { Controller } from "react-hook-form";
import { Field, Checkbox, Combobox, inputFloat, validColor, checkDraw, pickerOpen } from "@sharedex/ui";

const fieldEffects = [inputFloat(), validColor()];   // module level, like every effect

<Field label="Email" type="email" effect={fieldEffects} error={errors.email?.message} {...register("email")} />
<Checkbox label="I agree" effect={checkDraw()} {...register("terms")} />
<Controller name="topics" control={control} render={({ field }) => (
  <Combobox label="Topics" multiple options={topics} effect={pickerOpen()} {...field} />
)} />
  • Every prop and the ref go on the native control, so React Hook Form's register() spreads straight onto it; a list or files go through a Controller. The package imports no form library: React Hook Form + Zod is a documented recipe. Errors need words: error sets aria-invalid, points aria-describedby at the message and announces it.
  • Effects read the control's state through CSS (:focus-visible, :user-invalid, :checked, :autofill), so nearly all are plain data a Server Component can pass; three carry code (checkConfetti, rangeElastic, inputCycle). They never scold while you type, keep their state under reduced motion and drop the movement.
  • Guide for Claude Code: node_modules/@sharedex/ui/guides/forms.md.

Option schemas (@sharedex/ui/schema)

Every configurable piece describes its options as data, for tools such as the sharedex Design System Builder: one form can edit any option, a config stores only what differs from the defaults, and a generator writes the same values back as code. The entry is data only (no React, no DOM, no effect code).

import { schemaOf, defaultsOf, sparseOptions, validateOptions, factoryPath, factoryArgs } from "@sharedex/ui/schema";

const schema = schemaOf("background", "water-ripple")!;  // fields: kind, label, range, default, help…
defaultsOf(schema);                                        // { strength: 0.8, … } (auto options left out)
sparseOptions(schema, { strength: 0.8, rain: false });     // { rain: false }: the default strength is dropped
validateOptions(schema, { strength: 3 }, schemaOf);        // ["strength: must be between 0 and 1"]
  • Families: background (88 effects + the image / video slots), transition (40), reveal, carousel-layout (16 presets), carousel-modifier, carousel-presence, carousel-open, carousel-physics, carousel (the whole config as one form), ticker, grid, grid-open, scroll (the five compositions), button (73 button effects), text (69 text effects), word-cycle, number-roll. SCHEMAS[family] lists them, schemaOf(family, id) finds one.
  • Every option is covered. defineSchema<Options>() requires a field (or a code entry, for functions, MotionValues and React nodes) for every key of the options type, so a piece that gains an option without a field fails to compile. Tests check that each default is what the piece really does with the option left out.
  • Forms for components: CAROUSEL_SETTINGS, TICKER_SETTINGS, GRID_SETTINGS, WORD_CYCLE_SETTINGS and NUMBER_ROLL_SETTINGS are their props as one flat form (CarouselSettings puts each key back in its section with CAROUSEL_SECTIONS; a Ticker's drive stands for its offset; a Grid's unset columns is "auto").
  • Calling a factory: factoryPath(schema) (["presence", "contract"]) and factoryArgs(schema, options) (positional for pagedBy(n, maxPages)), so a form, a generator and tests call it the same way.

Status

0.10.0 adds the form controls and 91 form effects (every row of the Form Effects Atlas, plus 62 found online): Field and its tools, Checkbox, CheckGroup, RadioGroup, Switch, Select, Combobox, Range, NumberField, OtpField, TagsField, ChipGroup, FileDrop, FormSteps, FormReveal, FormSwap, InlineEdit, ErrorSummary, SaveStatus, PasswordRules, FormBuddy, focusFirstError; the danger and success tokens; the form schema family. 0.9.0 added Text and 69 text effects (every row of the Text Effects Atlas, plus 26 found online), Typewriter, WordCycle, NumberRoll, TextPath, Text3D (in @sharedex/ui/three), the Ticker's scrollBoost, and on the sections titleEffect / eyebrowEffect (every Root), a cycling word in the Hero's title (titleWords, titleCycle) and rolling figures in About (statRoll); schema families text, word-cycle, number-roll. 0.8.0 added Button and 73 button effects (every row of the Button Effects Atlas but the Lottie / Rive recipe, which is in the docs), useButtonAction, an actionEffect prop on Hero.Root, the --radius-sx-button token and the button schema family. 0.7.0 added the option schemas (@sharedex/ui/schema): every background, transition, carousel piece and setting, the Ticker, the Grid and the scroll compositions described as data, the source of the Design System Builder's forms and export. Sections (<Hero.Root> …), Reveal.Group and the layout ids now work in React Server Components (Next.js App Router): their compound objects were built inside client modules, where the server sees only an opaque reference. The Grid now measures in CSS px under a scaled ancestor (a zoomed preview, a modal scaling in), as the carousel already did. 0.6.0 added the gallery effects: six 3D shapes (barrel, helix, ring, staircase, fallAway, sphere) on closed rings and place3d(), speed looks (speedWave, speedTilt), useScrollLink, layout morphs, enter / exit presets, open views with Carousel.Panel, the cardStack look, and two new components: Ticker (a marquee driven by time, scroll or drag) and Grid (an endless plane you pan in any direction, with tilt, bulge, fog and open views). 0.5.0 added transitions (40 effects: one-card carousel looks, CSS masks and reveals, WebGL shaders), Reveal, five scroll compositions, four multi-card presets, View Transitions filter swaps and a reveal prop on every section. 0.4.0 added Background (88 effects in CSS, SVG, canvas, WebGL and Three.js, the @sharedex/ui/three entry) and a background prop on every section. 0.3.0 added the page sections and an expanded sx-* token contract to the 0.2.0 headless carousel (engine, six layout presets, four physics policies, per-slot choreography hooks). A dark-themed documentation site has live demos of both. It is not published to npm yet.

Shipped: the compound carousel API, effects, physics, card-design hooks, category filtering, drag, autoplay; Hero, About, Services and Contact sections; backgrounds (all 94 rows of the Background Effects Atlas: 88 effects, 3 rows covered by the image() / video() slots, 3 docs recipes); transitions (all 51 rows of the Transition Effects Atlas); the gallery effects, Ticker and Grid; Button (75 of the 76 rows of the Button Effects Atlas, the last a docs recipe); Text (all 94 rows of the Text Effects Atlas: 69 effects and the text components); the form controls (all 134 rows of the Form Effects Atlas: 91 effects and the controls). Next: built-in Controls / Filters / Pagination components, full a11y wiring for the carousel (region label, live region, roving tabindex), RTL for the carousel.

Local development

This package lives in the sharedex monorepo (packages/ui). From the repo root:

npm install            # installs every workspace and builds dist/ (the root postinstall)
npm test               # node:test — kernel + preset placement (pixel-identity gate)
npm run dev:docs       # the dark documentation site, with every effect live

License

MIT © Mohamad Faseh