opsinjs
HandbookRegistry & distribution

Preset codes

The short code that carries a whole theme, how opsinjs namespaces its own, and how to encode, decode and apply one.

Overview

A preset code is a short opaque string that stands for a complete theme configuration: style, base colour, icon library, font and radius. It exists so that "use this theme" can be six characters in a chat message rather than a paste of a stylesheet.

opsinjs uses two related things and it is worth separating them immediately:

  • shadcn preset codes are opaque short codes the shadcn CLI decodes and applies. This documentation site was itself initialised from one.
  • opsinjs preset names are readable, namespaced names such as opsinjs-default, served as registry items at /r/themes/<name>.json.

The first is a compact wire format for shadcn's own configuration space. The second is a theme in the opsinjs sense, which is a larger thing: role tokens for both themes, shape, spacing, the P3 escalation.

Decode before you apply

Never apply a code you have not decoded. It is opaque by design, and applying one modifies your stylesheet and your components.json.

npx shadcn@latest preset decode <code>

It prints the style, base colour, theme, chart colour, icon library, font and radius the code stands for. Reading that output takes two seconds and is the difference between a deliberate change and a surprising one. The named lyra preset, for instance, brings a different icon library and a monospace UI font, which is not obvious from the name and was exactly the surprise this project avoided by using the code form instead.

Related commands:

npx shadcn@latest preset resolve

Prints the preset your project currently matches. That is the fastest answer to "what theme is this project actually on".

npx shadcn@latest preset url <code>
npx shadcn@latest preset open <code>

The URL for the code, and the same thing opened in a browser.

Apply one

npx shadcn@latest apply <code>

To take only the colours, or only the typography, without reinstalling components:

npx shadcn@latest apply <code> --only theme

--only accepts theme and font. In an existing opsinjs project this is almost always what you want: a full apply may touch component-level configuration you have already tuned.

apply edits app/globals.css. The order of that file is load-bearing. The generated token layer sits at a fixed position and the dark variant is pinned last on purpose. After applying anything, re-read the file's own header comment and check that the structure survived. See Tailwind v4.

The opsinjs preset name format

opsinjs preset names are readable and namespaced:

opsinjs-<name>

Every one begins with opsinjs-, for the same reason the registry namespace is @opsinjs: shadcn publishes its own style names, and a collision would be silent and unresolvable. The full argument is in Presets and in Namespaces.

A preset name resolves to a registry item:

npx shadcn@latest add https://opsinjs.pensievelabs.org/r/themes/opsinjs-default.json

Unlike a shadcn code, the name is not compressed and carries no hidden fields. The JSON it resolves to is the whole configuration, readable, in one request. That is a deliberate trade: longer to type, impossible to be surprised by.

Encoding your own

Producing a shareable code from a theme you have built is specified and not implemented. Today, the shareable artefact is the registry item: generate a theme in the theme generator, export it as registry:item JSON with cssVars, and serve it. That works now, works everywhere, and needs no encoder.

The third question in the block above is the one that matters. A code that can silently redefine the clinical status ramp is a code that can change what a screen asserts about somebody's health by being pasted into a terminal. The likely answer is no. See Status palettes.

Verify it worked

Decode matches your intent

preset decode before, preset resolve after. The two should describe the same configuration.

The stylesheet still has its structure

Confirm the generated token import is still in position and there is exactly one active @custom-variant dark declaration, at the end.

The status ramp did not move

--opsin-status-urgent-line should be unchanged by any theme operation. If it moved, something wrote outside the role tier.

Troubleshooting

apply changed more than the theme. Use --only theme.

A code is rejected as invalid. Codes are version-sensitive; one produced by a much older or newer CLI may not decode. Pin the CLI version that produced it.

preset resolve prints nothing recognisable. The project has drifted from every known preset. That is normal after hand edits, and not an error.

A named preset and a code disagree. They are different systems. The name resolves to opsinjs JSON; the code resolves to shadcn configuration. Prefer the name for anything opsinjs-specific.

Next

On this page