Install 57 components — by agent or by hand.
ReactOmega is not an npm install. Every component is one self-contained file that gets copied into your repo — you own it, you edit it, nothing updates behind your back. There are four ways to get it there. The first one is why this registry exists.
What your project needs first
Four things, and the installer assumes all of them. Get these wrong and the component lands but does not compile — that is the single most common failure, so it is worth thirty seconds now.
- React 18 or 19 — Every component is a client component and starts with "use client".
- Tailwind CSS — Styling is Tailwind utility classes. No CSS file ships with the component.
- A @/* path alias — Components import from @/lib/utils and @/hooks/*. Without the alias the imports fail.
- clsx + tailwind-merge — The cn() primitive depends on them. The installer prints the npm line for you.
If your tsconfig.json came from create-next-app, the alias is already there. Otherwise:
{
"compilerOptions": {
"paths": { "@/*": ["./*"] }
}
}MCP — let the agent install it
recommendedThis is the path ReactOmega was built for. The registry ships an MCP server, so Claude or Cursor does not read these docs and guess — it queries a structured contract and writes the exact files. Add this once:
{
"mcpServers": {
"reactomega": {
"command": "npx",
"args": ["-y", "github:Edwson/ReactOmega", "reactomega-mcp"]
}
}
}Put it in claude_desktop_config.json for Claude Desktop, in .mcp.json at your project root for Claude Code, or under Settings → MCP in Cursor. Restart the client afterwards. Nothing is installed globally — npx fetches the server on demand.
“add a ReactOmega magnetic button to my hero”
“what ReactOmega shaders are there? install the glass one”
“give me a scroll-driven reveal from ReactOmega”
The server exposes three tools. Your agent picks; you rarely need to name them:
list_componentscategory? · query?Browse or search the catalog. Returns name, title, category, description and tags.
get_componentnameThe full contract for one component: description, tags, npm + registry dependencies, and the source.
add_componentnameEverything needed to install: both install commands, the npm line, and every file to write — component plus resolved primitives.
Why this beats pasting from docs: add_component resolves the dependency chain itself. Ask for a shader and it returns four files — the component, lib/utils.ts, hooks/use-prefers-reduced-motion.ts and hooks/use-shader.ts — because the shader needs the WebGL2 primitive, which needs the reduced-motion hook. An agent reading prose forgets the third file. The registry cannot.
CLI — one line, no config
Runs straight from GitHub. Nothing to install, nothing published to npm required.
npx -y github:Edwson/ReactOmega add refracted-glass magneticBrowse first, filter by category:
npx -y github:Edwson/ReactOmega list
npx -y github:Edwson/ReactOmega list --category shaderUseful flags: --dry prints what it would write without touching disk, --cwd targets another directory, and --registry points at a local checkout or your own fork.
shadcn — if that is already your workflow
Every component is also a shadcn-compatible registry item, served over jsDelivr. Same files, your existing tool.
npx shadcn@latest add https://cdn.jsdelivr.net/gh/Edwson/ReactOmega@main/public/r/refracted-glass.jsonSwap @main for a tag such as @v1.2.0 to pin an immutable version.
By hand — it is one file
No tooling at all: open any component on the components page, copy the source from its registry item, and paste it in. You still need the primitives — the cn() helper, the reduced-motion hook, and use-shader.ts if it is one of the 12 shaders.
https://cdn.jsdelivr.net/gh/Edwson/ReactOmega@main/public/r/<name>.jsonWhere the files land
Whichever path you take, the layout is the same. Primitives are shared, so the second component is cheaper.
lib/utils.ts ← cn() · needs clsx + tailwind-merge
hooks/use-prefers-reduced-motion.ts ← the accessibility contract
hooks/use-shader.ts ← only for shader components (raw WebGL2)
components/reactomega/<name>.tsx ← the component itselfThen import it like any local file. Give a full-bleed component a sized parent — it fills its container, it does not invent a height:
import { RefractedGlass } from "@/components/reactomega/refracted-glass";
export default function Hero() {
return (
<div className="relative h-[70vh] overflow-hidden">
<RefractedGlass tint="#c9d4ff" dispersion={1.2} />
</div>
);
}Every prop is typed and documented inline with its default, so your editor tells you the options without a round trip to this page.
Two guarantees you inherit
Every component honors prefers-reduced-motion and degrades to a calm, still, still-functional state. It is enforced by a test in CI, not a promise in a README — including transitively, so a shader inherits it from the primitive.
Shaders ask for a WebGL2 context. If the browser cannot give one they render a CSS gradient in the same palette rather than a blank rectangle — so an old machine sees something composed, never something broken.
If something does not work
The @/* alias is missing from tsconfig.json, or your bundler is not reading it. See step 00.
Tailwind is not scanning components/reactomega. Add it to the content globs in your Tailwind config.
That is the fallback, working. The browser has no WebGL2 — check the console for a context warning.
Either the OS has reduce-motion on (that is the contract), or the parent has no height so the canvas is 0px tall.
A server component imported it. The component already declares "use client"; the file importing it needs to be a client component too, or render it from one.