Catalog npm
Back to packageRELEASE DETAILS

1.1.0

npm

9am-ui

The shared design language, NUI plumbing and FiveM CEF workarounds behind every 9AM Studios script — an open shadcn registry.

ceffivemnuireactshadcnshadcn-registrytailwindcssui
Published14 Aug 2026
Direct dependencies27
Transitive dependenciesNot calculated

README

Current package documentation

9AM UI

The shared design language, NUI plumbing and FiveM CEF workarounds behind every 9AM Studios script.

Distributed as a shadcn registry: components are copied into each script rather than imported from a package, so a script can diverge when it genuinely needs to — while 9am-ui check makes sure nobody diverges by accident.

Extracted from 9am-vehicleshop v1.2.8, which is consumer #0.


What's in it

LayerItemsWhat it gives you
Theme@9am/themeOKLCH tokens for both palettes, the primary-50…950 ramp, radius scale, class-driven dark: variant, and the NUI base rules (transparent body, suppressed focus rings, scrollbar utilities). Locked — see Drift policy.
Fonts@9am/fontsPoppins + Phudu embedded as base64. Kept out of @9am/theme on purpose — see Fonts. Locked.
Primitives19 itemsbutton (8 variants), card, input, label, field, select, multi-select, switch, separator, table, data-table, tabs, dialog, popover, tooltip, info-tip, calendar, chart, viewport
Icons47 items@9am/icon-* — hand-built animated SVGs, no icon library dependency. Each exposes startAnimation()/stopAnimation() through a ref so a parent (a tab, a table row) can drive it.
NUI@9am/nui, @9am/visibility, @9am/use-theme, @9am/i18nfetchNui, useNuiEvent, debugData, browser-dev detection, frame visibility with ESC + focus release, theme store, and runtime i18n pulled from Lua.
Lib@9am/utils, @9am/smooth-scrollcn(), and the global wheel handler that repairs scrolling in CEF.
Scaffold@9am/scaffold + 9am-ui luaA whole new script's UI: vite/tsconfig/eslint/postcss, index.html, main.tsx, starter App, plus the Lua side.

Browse it all: bun run preview → http://localhost:5173.

The two pieces that matter most

@9am/viewport is the house scroll container: a drag-able custom scrollbar, layered "liquid glass" edge blur, and a header that blur-swaps to a sticky copy as you scroll. It also carries the CEF-103 workarounds — clipPath instead of overflow+radius, stacked fixed-blur bands because mask doesn't apply to backdrop-filter output, and JS-computed grid columns because :has() and @container don't exist in Chromium 103.

@9am/smooth-scroll exists because CEF will not wheel-scroll a clip-path'd container at all. Without it, the viewport is unscrollable in-game while working fine in your browser.


Use it in a new script

mkdir -p my-script/web && cd my-script/web
bun init -y

Add components.json:

{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york", "rsc": false, "tsx": true,
  "tailwind": {
    "config": "", "css": "src/index.css",
    "baseColor": "neutral", "cssVariables": true, "prefix": ""
  },
  "aliases": {
    "components": "@/components", "utils": "@/lib/utils",
    "ui": "@/components/ui", "lib": "@/lib", "hooks": "@/hooks"
  },
  "registries": {
    "@9am": {
      "url": "https://raw.githubusercontent.com/ilovehugetits/9am-ui/main/r/{name}.json"
    }
  }
}

Then:

bunx shadcn@latest add @9am/scaffold     # web skeleton + every dependency
cd .. && bunx 9am-ui lua                 # Lua side, from the resource root

The CLI is on npm as 9am-ui. Examples use bunx because the rest of the kit assumes bun, but npx 9am-ui works identically — the published binary is plain ESM with a node shebang.

Finally, edit web/src/nui.config.ts — it is the one kit file you are meant to change:

export const nuiConfig = {
  resourceName: "my-script",
  themeStorageKey: "my-script:theme",
  defaultTheme: "dark",
}

Keep the localStorage key in index.html in sync with themeStorageKey (it runs before first paint to avoid a theme flash), then:

cd web && bun install && bun run build
bunx 9am-ui doctor    # confirms the registry, theme import and the CEF css setup

Use it in an existing script

Add the registries block above to your components.json, then take what you want:

bunx shadcn@latest add @9am/theme @9am/viewport @9am/data-table

Transitive dependencies resolve automatically — @9am/data-table pulls button, input, table, i18n and its three icons.

After adding @9am/theme, import it from your entry stylesheet:

@import "tailwindcss";
@import "tw-animate-css";
@import "./styles/9am-fonts.css";   /* or 9am-fonts-linked.css — see below */
@import "./styles/9am-theme.css";

Fonts

9am-theme.css deliberately does not import a font stylesheet, because which one you want depends on your app:

Use whenHow
@9am/fonts (base64)Single html entry — the common casebunx shadcn@latest add @9am/fonts
Linked woff2Several html entries, especially DUI texture pagesbunx 9am-ui fonts, then import 9am-fonts-linked.css

Embedding is the better default: one command, nothing else to fetch, and in a NUI everything is served off local disk so there is no network round-trip to save. It becomes the wrong choice as soon as you have multiple entry points — every DUI is its own CEF instance, so each one would decode the entire 322 KB payload again with nothing shared between them.

9am-vehicleshop is the worked example: it has three entries (main NUI, phone, showroom stand) and client/showroom.lua calls CreateDui once per showroom slot, so it uses the linked variant everywhere.


Non-negotiables for CEF

FiveM's CEF is Chromium 103. Two things will silently ruin a build:

  1. postcss.config.js must keep postcss-color-converter. The tokens are authored in oklch(), which CEF cannot parse. Without the conversion the UI renders completely unstyled in-game while looking perfect in bun run start. Verify with:
    bun run build && grep -c oklch dist/assets/*.css   # must be 0
    
  2. installSmoothScroll() must run in main.tsx. Otherwise nothing scrolls in-game.

bunx 9am-ui doctor checks both, including scanning your built CSS for surviving oklch().


Drift policy

bunx 9am-ui check     # run from web/, wire it into CI
What changedResult
src/styles/9am-theme.css or 9am-fonts.cssFails (exit 1). Identical tokens are what make the scripts read as siblings. Restore with bunx shadcn@latest add @9am/theme @9am/fonts --overwrite, or make the change here and release it.
Any component or iconWarns (exit 0). Allowed — teams need the escape hatch — but a local fix helps nobody else. Consider upstreaming.
src/nui.config.tsIgnored. It is supposed to differ.
Anything from @9am/scaffoldIgnored. A starting point, not a managed artifact.

Releasing a change

bun run build       # regenerates fonts, registry.json and r/
bun run typecheck
bun run preview     # eyeball it in both themes
git commit -am "feat(button): ..." && git push

r/ is committed on purpose — raw.githubusercontent.com serves committed files, which is what lets this repo act as a registry with no hosting at all.

Consumers pick the change up on their next shadcn add ... --overwrite. Nothing auto-updates; that is deliberate.

See CONTRIBUTING.md for adding a component.


License

MIT. Copy the components into your own scripts freely — that is what a copy-in registry is for.

Poppins and Phudu ship under the SIL Open Font License 1.1, which travels with them.

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 27

Native requirements
27 direct targetsNot calculated transitive count
Package / targetRequirementRelationship
clsx
Environment
{
  "local_name": "clsx",
  "alias": false,
  "peer_metadata": null
}
^2.1.1runtime
react
Environment
{
  "local_name": "react",
  "alias": false,
  "peer_metadata": null
}
19.2.8runtime
motion
Environment
{
  "local_name": "motion",
  "alias": false,
  "peer_metadata": null
}
^12.42.2runtime
zustand
Environment
{
  "local_name": "zustand",
  "alias": false,
  "peer_metadata": null
}
^5.0.14runtime
recharts
Environment
{
  "local_name": "recharts",
  "alias": false,
  "peer_metadata": null
}
^3.10.0runtime
react-dom
Environment
{
  "local_name": "react-dom",
  "alias": false,
  "peer_metadata": null
}
19.2.8runtime
tailwindcss
Environment
{
  "local_name": "tailwindcss",
  "alias": false,
  "peer_metadata": null
}
^4.3.3runtime
tailwind-merge
Environment
{
  "local_name": "tailwind-merge",
  "alias": false,
  "peer_metadata": null
}
^3.6.0runtime
tw-animate-css
Environment
{
  "local_name": "tw-animate-css",
  "alias": false,
  "peer_metadata": null
}
^1.4.0runtime
react-day-picker
Environment
{
  "local_name": "react-day-picker",
  "alias": false,
  "peer_metadata": null
}
^10.0.1runtime
@tailwindcss/vite
Environment
{
  "local_name": "@tailwindcss/vite",
  "alias": false,
  "peer_metadata": null
}
^4.3.3runtime
@radix-ui/react-slot
Environment
{
  "local_name": "@radix-ui/react-slot",
  "alias": false,
  "peer_metadata": null
}
^1.3.1runtime
@radix-ui/react-tabs
Environment
{
  "local_name": "@radix-ui/react-tabs",
  "alias": false,
  "peer_metadata": null
}
^1.1.19runtime
@radix-ui/react-label
Environment
{
  "local_name": "@radix-ui/react-label",
  "alias": false,
  "peer_metadata": null
}
^2.1.13runtime
@tanstack/react-table
Environment
{
  "local_name": "@tanstack/react-table",
  "alias": false,
  "peer_metadata": null
}
^8.21.3runtime
@radix-ui/react-dialog
Environment
{
  "local_name": "@radix-ui/react-dialog",
  "alias": false,
  "peer_metadata": null
}
^1.1.21runtime
@radix-ui/react-select
Environment
{
  "local_name": "@radix-ui/react-select",
  "alias": false,
  "peer_metadata": null
}
^2.3.5runtime
@radix-ui/react-switch
Environment
{
  "local_name": "@radix-ui/react-switch",
  "alias": false,
  "peer_metadata": null
}
^1.3.5runtime
@radix-ui/react-popover
Environment
{
  "local_name": "@radix-ui/react-popover",
  "alias": false,
  "peer_metadata": null
}
^1.1.21runtime
@radix-ui/react-tooltip
Environment
{
  "local_name": "@radix-ui/react-tooltip",
  "alias": false,
  "peer_metadata": null
}
^1.2.14runtime
class-variance-authority
Environment
{
  "local_name": "class-variance-authority",
  "alias": false,
  "peer_metadata": null
}
^0.7.1runtime
vite
Environment
{
  "local_name": "vite",
  "alias": false,
  "peer_metadata": null
}
^8.1.5development
@types/bun
Environment
{
  "local_name": "@types/bun",
  "alias": false,
  "peer_metadata": null
}
^1.3.5development
typescript
Environment
{
  "local_name": "typescript",
  "alias": false,
  "peer_metadata": null
}
^5.9.3development
@types/react
Environment
{
  "local_name": "@types/react",
  "alias": false,
  "peer_metadata": null
}
^19.2.17development
@types/react-dom
Environment
{
  "local_name": "@types/react-dom",
  "alias": false,
  "peer_metadata": null
}
^19.2.3development
@vitejs/plugin-react
Environment
{
  "local_name": "@vitejs/plugin-react",
  "alias": false,
  "peer_metadata": null
}
^6.0.4development

Distribution files

1 collected
Distribution 1

Source distribution

Source file
Checksums from source
{
  "shasum": "fb486fbc84c51b79d02466ac7c451df532ea1b2f",
  "tarball": "https://registry.npmjs.org/9am-ui/-/9am-ui-1.1.0.tgz",
  "fileCount": 201,
  "integrity": "sha512-8pg6dLkMOzmFI7juHMWdT0MDnkQQ8Emn+/ifTr8MtXRd+KN1M/ehyWf7Jwbj0OtKXDjkiwHDaOMFakEQjagUAQ==",
  "signatures": [
    {
      "sig": "MEYCIQCc69RXhYamiEjzT8+pffWZ2f/uUhZBQHyeUjUrV00oOQIhAKyrqUZlLnjaGedkI4ZTHkrKRbDFEOaHK5yP/REagLVv",
      "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
    }
  ],
  "attestations": {
    "url": "https://registry.npmjs.org/-/npm/v1/attestations/9am-ui@1.1.0",
    "provenance": {
      "predicateType": "https://slsa.dev/provenance/v1"
    }
  },
  "unpackedSize": 1636127
}

Repository

PENDING
ilovehugetits/9am-ui

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 21:35 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:207e6b724a570bf0bc0ec5861a53d3cc8b98bc89e296f145ab734d7f74b686e4

Other collected versions

1.0.014 AugView all collected versions →