Components

Headless primitives and utilities you can add to a project as a dependency or copy in as source - behaviour, timing and accessibility, with no styles of their own.

Interaction logic is behaviour, and behaviour that has already been measured and tested belongs in a package, not in a snippet an agent rewrites on every screen. Two packages hold it:

  • @enigmax/primitives - interaction behaviour: timing, pointer handling, accessibility. No visual styles.
  • @enigmax/utils - what renders nothing: a short-TTL read cache, and a breached-password check.

Both are plain npm packages. Nothing about them requires enigma - enigma add is a convenience that also lets an agent discover what exists.

marquee
Claude CodeCodexopencodeKimi CodeMCPGuardrailsRecallDashboard

Every preview on these pages is a real instance of the published package. Grab this one and throw it.

Installation

Adds the package and prints the import to use. Append --copy to write the source into your project instead.

enigma add --all

Installs with your project's own package manager - npm, pnpm, yarn or bun - read from its packageManager field or its lockfile.

The enigma tab adds the package and prints the import to use. The copy tab writes the source into your project instead, so it is yours to edit - the same choice shadcn made, applied to behaviour rather than markup.

--dest <dir> chooses where copies land (default src/lib/enigma, or lib/enigma when the project has no src). --target overrides the detected framework. --dry-run reports without writing.

Copy mode rewrites the internal import specifiers to relative ones, so the copied files stand alone. It refuses to run when the package source is not on disk rather than inventing it.

Which framework

The core of every primitive is framework-agnostic TypeScript with no dependencies, so vanilla JS and Astro work today through the main entry - this page is Astro, and the demo above is the vanilla entry. React has a thin adapter. Vue, Svelte and TanStack adapters are not written yet; they will reuse the same core rather than reimplement it.

Target Entry Marquee export
Vanilla, Astro @enigmax/primitives createMarquee
React @enigmax/primitives/react useMarquee

Styling: Tailwind by default, CSS on request

The primitives themselves ship no styles and never will. Utility classes inside the engine would break every project without Tailwind and tie a behaviour package to a CSS framework’s major version; being styleless is what makes them work in any design.

The styling lives one layer up, in recipes - complete styled components, not fragments - that reach your project through enigma add --copy:

what --copy writes
enigma add marquee --copy --style tailwind
# lib/enigma/marquee/marquee.ts      the headless engine
# lib/enigma/marquee/use-marquee.ts  the React hook
# lib/enigma/marquee/Marquee.tsx     a styled component, utility classes, yours to edit

You do not have to pass --style. The default is read from your project: tailwindcss, @tailwindcss/vite or @tailwindcss/postcss in the manifest means Tailwind, anything else means plain CSS. Writing utility classes into a project without Tailwind would produce a component styled by nothing, which is worse than the CSS variant - so “Tailwind by default” means “where Tailwind is”.

--style none copies the headless files only. And cache has no recipe on purpose: it renders nothing, so there is nothing to style.

A Tailwind v4 trap worth knowing

Tailwind v4 writes translate-* to the CSS translate property, which composes with transform rather than replacing it. The marquee drives the track’s transform every frame, so a translate-x-* utility on that element does not override it - the two add up and the row drifts. Offset the lane or an inner element instead, never the moved one. Both marquee recipes carry that warning at the top of the file.

They ship no styles

A primitive applies only what its behaviour requires - overflow, touch-action, user-select, will-change, transform - and never anything that is a look. State is published as data attributes, so the styling stays entirely yours:

[data-enigma-marquee]                 { cursor: grab; }
[data-enigma-marquee][data-dragging]  { cursor: grabbing; }
[data-enigma-marquee][data-hovering]  { --logo-opacity: 1; }
[data-enigma-marquee-track]           { display: flex; }

Pass manageStyles: false to take even the functional styles back.

A themes package that styles these hooks for you is planned; the attributes are already stable, so anything you write against them now keeps working.

The catalogue an agent reads is the one you installed

enigma add looks for the registry inside the package installed in your project first, and only falls back to the copy bundled with the CLI. So an agent is shown the API your project actually compiles against, instead of a catalogue frozen into a skill that drifts the first time you upgrade.

In this section

  • Marquee - draggable infinite row: logo walls, testimonial strips, pill rails.
  • Cache - short-TTL read cache with in-flight deduplication.
  • Notifications - queue, dedupe and dismiss timers that hold when the tab is hidden.