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

gamifiedui-css

v0.4.0

Published

Tailwind CSS v4 game UI: pixel-framed 2.5D buttons, panels, HP/MP/XP bars, dialogs, sprite and isometric utilities.

Readme

gamifiedui-css

Game-style 2D / 2.5D components for Tailwind CSS v4. CSS only, works with any framework.

npm i gamifiedui-css tailwindcss @tailwindcss/vite
npm i @fontsource/press-start-2p   # optional pixel font
npm i @fontsource/fusion-pixel-12px-proportional-tc   # optional, Chinese (Traditional)
npm i @fontsource/fusion-pixel-12px-proportional-sc   # optional, Chinese (Simplified)
/* app.css */
@import "tailwindcss";
@import "gamifiedui-css";

The stylesheet is a Tailwind v4 entry point, so Tailwind must process it (Vite or PostCSS plugin). Without that the build succeeds but @theme and @utility stay unprocessed.

CDN (no build step)

dist/ holds prebuilt stylesheets that need no Tailwind:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/press-start-2p/index.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/gamifiedui.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/src/all.css">

| File | Contains | |---|---| | dist/gamifiedui.min.css | Tailwind preflight (reset), every token, all components and utilities | | dist/gamifiedui-core.min.css | the same without preflight, for pages that bring their own reset (use this one on an existing site, including Tailwind v3 apps, so its headings, links and tables keep their look) |

Both have an unminified .css twin, and unpkg.com/gamifiedui-css serves the same files. Before the npm release, or to pin a commit, use jsDelivr's GitHub mirror: https://cdn.jsdelivr.net/gh/carsonhung/gamifiedUI@<tag>/packages/gamifiedui-css/dist/gamifiedui.min.css.

The prebuilt files can't generate arbitrary values. They include gx-depth-0 to -8, gx-sprite-{w,h}-{8,12,16,24,32,48,64,96,128}, gx-sprite-frames-1 to -16, gx-sprite-scale-1 to -8, gx-sprite-ms-100 to -2000 (in steps of 100) and sr-only. Any other value can be set inline: style="--gx-sprite-frames: 24". For Chinese, also load @fontsource/fusion-pixel-12px-proportional-tc (or -sc) the same way.

Components

| Class | Markup | Modifiers | |---|---|---| | gx-btn | <button> | gx-btn-{primary,danger,success,warning,ghost}, gx-btn-{sm,lg}, aria-pressed="true", gx-btn-tint + --gx-btn-tint, gx-btn-tile (gx-btn-art, gx-btn-label, gx-btn-meta), gx-btn-tile-stacked | | gx-panel | any block | gx-panel-title, gx-panel-flat | | gx-bar | role="meter" + style="--gx-value: 0.6" | gx-bar-{hp,mp,xp}, gx-bar-smooth, gx-bar-critical | | gx-badge | <span> | gx-badge-{primary,danger,success} | | gx-dialog | <dialog> opened with showModal() | gx-dialog-{scene,text,actions} | | gx-textbox | dialogue box | gx-textbox-{speaker,text,next,choices} | | gx-alert | block, role="alert" only if urgent | gx-alert-{info,success,warning,danger}, parts -icon, -title, -body | | gx-toast | inside one gx-toast-stack region; role="status" / "alert" | same tones + gx-toast-achievement, parts -icon, -title, -body, -close; data-leaving plays the exit | | gx-spinner | inside role="status" with text | gx-spinner-lg | | gx-tooltip | wrapper; content role="tooltip" linked by aria-describedby | gx-tooltip-bottom | | gx-tabs / gx-tab | role="tablist" / role="tab" + aria-selected | panel: gx-panel gx-tab-panel | | gx-field, gx-input | <input>, <textarea>, <select> | gx-field-{label,hint,error}, aria-invalid="true" | | gx-checkbox, gx-radio, gx-switch | native inputs (role="switch" for the switch) in label.gx-choice | | | gx-card | block, or <button> / <a> to make it pressable | gx-card-{title,meta}, gx-rarity-* | | gx-slot | inventory cell, <button aria-pressed> | gx-slot-count, gx-rarity-* | | gx-card-grid | <ul> of cards (or cards as children); columns fill automatically and cards in a row share a height | gx-card-grid-{sm,lg}, --gx-card-grid-min, --gx-card-grid-gap | | gx-inventory | recessed tray of gx-slot buttons, role="group" with aria-label; fixed columns that shrink to fit narrow screens, down to a 44px touch target, then the tray scrolls sideways; aria-disabled marks locked cells | --gx-inventory-cols (set fewer on phones, e.g. [--gx-inventory-cols:4] sm:[--gx-inventory-cols:6]), --gx-inventory-slot, --gx-inventory-slot-min | | gx-kbd | <kbd> key prompt | | | gx-rarity-* | modifier for cards and slots | common, rare, epic, legendary (also print the name) | | gx-frame | <figure> around <img>, <picture>, <canvas> or <video> | gx-frame-caption, gx-frame-pixelated, gx-frame-cover + gx-frame-{square,wide,portrait}, gx-rarity-* | | gx-avatar | <span> with an <img alt>, or initials + role="img" aria-label | gx-avatar-{sm,lg}, gx-rarity-* | | gx-video | gx-frame gx-video > gx-video-screen > <video controls> with <track kind="captions"> | gx-video-play start overlay (a real <button>) | | gx-menu / gx-menu-item | <ul> of <button>s or links; blinking ▶ cursor on hover, focus and aria-current | gx-menu-hint | | gx-dropdown | <details> > <summary> + gx-dropdown-panel | gx-dropdown-end | | gx-accordion | <details> (share a name for one-open-at-a-time) | gx-accordion-meta, gx-accordion-body | | gx-slider | <input type="range">; script sets --gx-value (0..1) for the WebKit fill | gx-slider-{hp,mp,xp} | | gx-table | <table> in gx-table-wrap; tr[aria-current] highlights a row | gx-table-num, gx-rank + gx-rank-{1,2,3} | | gx-pagination / gx-page | <ul> of buttons or links, aria-current="page" | gx-breadcrumb (<nav><ol>) | | gx-drawer | <dialog> opened with showModal() | gx-drawer-start | | gx-stepper / gx-step | <ol>; data-state="cleared\|current\|locked" | gx-step-node | | gx-chip | <span>, or <button aria-pressed> for a filter | tones as buttons | | gx-divider | <hr> | gx-divider-text (a labelled divider) | | gx-skeleton | placeholder inside aria-busy="true" | gx-skeleton-{text,avatar,block}, --gx-skeleton-w | | gx-rating | role="img" + aria-label, style="--gx-value: 3" | gx-rating-stars, gx-rating-{sm,lg}, --gx-rating-max | | gx-counter | icon + gx-counter-value; data-bump plays a pop | gx-counter-{xp,hp} | | gx-quantity | − N + stepper: two gx-quantity-btn around a number gx-quantity-value; aria-disabled sinks a button at a limit, data-bump pops the value | --gx-quantity-digits | | gx-reward | gx-dialog gx-reward with gx-reward-item (spinning rays) | gx-reward-{title,name} | | gx-gauge | timing gauge: gx-gauge-zone (with gx-gauge-sweet) and gx-gauge-marker; gx-gauge-vertical with gx-gauge-fill for hold-to-fill | --gx-value, --gx-zone-start, --gx-zone-size, --gx-sweet-start, --gx-sweet-size (0..1) | | gx-lane | rhythm lane: gx-lane-line (the hit line) and gx-lane-note (data-done hides a hit note) | --gx-at on a note (0 on the line, 1 at the far end), --gx-lane-hit | | gx-dpad | four gx-btn in a cross: gx-dpad-{up,right,down,left}; data-lit lights one even while disabled | | | gx-btn-hold | press-and-hold button without the phone long-press menu; pair with holdButton() | | | gx-flip | <li> in a gx-flip-row holding gx-flip-back (aria-hidden) and gx-flip-face; turns over once when inserted | --gx-flip-delay (stagger), --gx-flip-w, --gx-flip-h, gx-rarity-* | | gx-quest / gx-objective | HUD quest tracker; data-done ticks an objective | gx-quest-{title,list}, gx-objective-{text,count} | | gx-skill | <button>; --gx-cooldown (1..0) sweeps, aria-disabled while cooling | gx-skill-key, gx-skill-timer, data-ready | | gx-float | short text in a gx-float-layer; rises and fades once | gx-float-{damage,heal,xp,crit} | | gx-timer | role="timer" with gx-timer-label + <time class="gx-timer-value">; --gx-value (1..0) drains the strip | data-state="warning\|critical\|done", gx-timer-lg | | gx-calendar | month grid of <button class="gx-day">; rendered by calendar() in gamifiedui-utils | day: aria-current="date", aria-pressed, data-range="start\|middle\|end\|preview", data-outside, aria-disabled, data-event + gx-rarity-*, data-claimed | | gx-datepicker | .gx-input + gx-datepicker-toggle + [popover].gx-datepicker-panel holding a gx-calendar | single date or a range; anchored under the field where CSS anchor positioning exists | | gx-time | scrolling list (role="listbox") of gx-time-option; rendered by timeList() in gamifiedui-utils | option: aria-selected, data-range="start\|middle\|end\|preview", aria-disabled, gx-time-tag (+1 for next day); gx-time-title, gx-time-summary, --gx-time-rows | | gx-timepicker | .gx-input + gx-timepicker-toggle + [popover].gx-timepicker-panel holding a gx-time | single time or a range (overnight allowed); same anchoring as gx-datepicker | | gx-dropzone | <label> wrapping <input type="file"> (click and keyboard work without JS) | gx-dropzone-{title,hint}, data-dragging, data-invalid | | gx-file-list / gx-file | <ul> of uploads | gx-file-{name,size,remove,status}, gx-bar gx-file-progress, data-state="uploading\|done\|error" | | gx-icon | <span aria-hidden="true"> + an icon class from gamifiedui-icons | gx-icon-{sm,lg,xl} (16/48/64px; default 32), tones, gx-icon-shadow, gx-icon-tile |

Particles

  • Bursts: a gx-burst inside any positioned element, holding gx-particle children. Each child gets --gx-dx, --gx-dy (in rem), --gx-rot and --gx-delay. Colours are gx-particle-{coin,heart,xp,petal,rarity} and gx-particle-lg. gx-particle-confetti cycles five theme colours by position and falls further; add gx-particle-ribbon for a pixel zigzag streamer. Add an icon class such as gx-i-coin to use that shape. burst() in gamifiedui-utils builds all of this for you.
  • Ambient: <div class="gx-ambient gx-ambient-snow" aria-hidden="true"> with 12 empty <i>, placed inside a positioned element. It needs no script. Kinds are snow, rain, embers, petals and confetti (tumbling pieces with a streamer every fourth).

Both are hidden under reduced motion, since they are decoration.

JavaScript

Every component works without script. A few effects only make sense when driven, so gamifiedui-utils ships small optional helpers for them: toasts, typewriter, number roll, skill cooldown, floating text, bursts, tabs, the slider fill, timers, calendars and date (range) pickers, and drag-and-drop upload.

A file button needs no script: <label class="gx-btn">Choose file<input type="file" class="sr-only"></label>.

Any colour for a button, with hover and a readable black or white label worked out for you:

<button class="gx-btn gx-btn-tint" style="--gx-btn-tint: #8a3ab9">Epic</button>

Item, shop or level buttons with a picture (an <img>, <svg> or gx-icon):

<button class="gx-btn gx-btn-tile gx-btn-tint" style="--gx-btn-tint: #3a6b4a">
  <span class="gx-btn-art"><img src="potion.png" alt=""></span>
  <span class="gx-btn-label">Green potion</span>
  <span class="gx-btn-meta">+20 HP</span>
</button>

gx-btn-tile-stacked puts the picture on top as a postcard (--gx-btn-art-ratio, default 16 / 9); an optional gx-icon after it sits beside the label. --gx-btn-art-size sets the side picture (default 2.5rem), and --gx-btn-tint-fg overrides the automatic label colour.

Utilities

  • gx-depth-{n}: depth of raised components, in pixel units (--gx-px, default 4px).
  • gx-pixel-frame, gx-pixelated.
  • gx-iso: true isometric camera (orthographic). Pair children with Tailwind transform-3d and translate-z-*.
  • gx-sprite with gx-sprite-w-16 gx-sprite-frames-8 gx-sprite-scale-4 gx-sprite-ms-800 and bg-[url(/hero.png)]: horizontal sprite strip played with steps().

Themes and motion

Set data-gx-theme="vintage" or "glass" on any element (themes nest); no attribute means arcade. Override any --color-gx-* token to make your own. vintage is a classic Windows PC game desktop: white window frames, thin grey borders, soft shadows, lightly rounded tiles, a light blue taskbar tone and sentence-case labels in the system UI face.

glass is a modern, XR-style spatial look rather than a pixel one: lightly translucent flat surfaces with a thin light rim, soft depth, no bevels or gradients, pill controls and sentence-case labels in --font-gx-body. It is built on shape hooks any theme can set, each defaulting to the square pixel look: --gx-radius, --gx-radius-control, --gx-backdrop, --gx-radius-field, --gx-radius-check, --gx-elevation, --gx-case, --color-gx-frame, --gx-line, --gx-focus-width, --gx-bevel, --gx-sheen, --gx-bar-height, --gx-bar-texture and --gx-bar-easing. --gx-px stays the sizing grid, so thinner lines never shrink icons or spacing. Every animation stops under prefers-reduced-motion: reduce or inside data-gx-motion="reduce" (for an in-app setting).

Chinese, Japanese and Korean

Press Start 2P only covers Latin, so --font-gx falls back to Fusion Pixel 12px (Traditional Chinese by default). Set lang on <html> or any element:

  • lang="zh-Hant" / zh-TW / zh-HK: Traditional glyphs.
  • lang="zh-Hans" / zh-CN / zh-SG: Simplified glyphs.
  • Any zh, ja or ko: pixel-font sizes snap to 12px and 24px (the font's grid, so glyphs stay crisp) and line-break: strict keeps punctuation off line starts.

Each Fusion Pixel file is about 600 KB, but browsers only fetch it once a CJK character is on screen. For typewriter effects, split text with Intl.Segmenter (graphemes), not slice.

License

Apache License 2.0. Free for commercial use, with an explicit patent grant. See NOTICE.