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

@objectifthunes/royal-games-ui

v1.3.1

Published

Hand-authored React graphics library for Capacitor games with Enamel and Gloss themes.

Readme

@objectifthunes/royal-games-ui

A hand-authored React graphics library for Capacitor mobile games. The package provides the Midnight Court visual system as accessible React components with two complete themes:

  • Enamel uses dark contours, gold frames, inset tracks, and material faces.
  • Gloss uses borderless extrusion, brighter highlights, and deeper shadows.

Both themes use the same component APIs and semantic CSS tokens. Theme changes never replace component structure or behavior.

Install

pnpm add @objectifthunes/royal-games-ui react react-dom

React and React DOM 19 or newer are peer dependencies. The package has no runtime dependencies.

Import the public tokens once at the application entry point:

import "@objectifthunes/royal-games-ui/tokens.css";

Component modules retain their own CSS imports. A downstream bundler can remove unrelated component JavaScript and styles.

Application shell

import { useState } from "react";
import {
  Body,
  BottomStack,
  Button,
  Chrome,
  ChromeRow,
  Dock,
  Screen,
  ScreenName,
  SkinProvider,
  Tab,
  TabBar,
} from "@objectifthunes/royal-games-ui";

export function StoreScreen() {
  const [section, setSection] = useState("store");

  return (
    <SkinProvider skin="enamel">
      <Screen aria-label="Royal store">
        <Chrome>
          <ChromeRow>Host-owned identity and resources</ChromeRow>
          <ScreenName>Store</ScreenName>
        </Chrome>

        <Body layout="commerce">Host-owned store content</Body>

        <BottomStack>
          <Dock>
            <Button>Continue</Button>
          </Dock>
          <TabBar aria-label="Main navigation" value={section} onValueChange={setSection}>
            <Tab value="home">Home</Tab>
            <Tab value="store">Store</Tab>
            <Tab value="profile">Profile</Tab>
          </TabBar>
        </BottomStack>
      </Screen>
    </SkinProvider>
  );
}

Screen is the sole owner of design scaling, the usable content rectangle, container classification, orientation adjustments, and safe-area resolution. Chrome, Body, BottomStack, Dock, FloatChrome, and TabBar consume that geometry instead of guessing the current device. Screen classification is measured from the component itself, not the browser viewport, so an embedded portrait game surface does not accidentally receive landscape placement.

Body provides structural dashboard, commerce, form, list, and result layouts in addition to its neutral flow default. In portrait, BottomStack occupies a real lower-shell slot and the Body scrollport ends exactly above it. In short landscape geometry, Screen deliberately moves the lower shell onto the scene plane and preserves a measured scroll reserve. Hosts should not add screen-specific padding or absolute footer offsets around these primitives.

The documentation site publishes complete, executable recipes for dashboard, shop, settings, map, victory, and leaderboard screens at Royal Games UI screens. The source shown on each recipe page is read from the same TSX file as its live preview; abbreviated pseudo-code is not used.

Switching themes

SkinProvider supports controlled and uncontrolled operation:

function ThemeButton() {
  const { skin, setSkin } = useSkin();
  return (
    <Button onClick={() => setSkin(skin === "enamel" ? "gloss" : "enamel")}>
      Use {skin === "enamel" ? "Gloss" : "Enamel"}
    </Button>
  );
}

<SkinProvider defaultSkin="enamel">
  <ThemeButton />
</SkinProvider>;

Nested providers create independent theme scopes. In controlled mode, setSkin requests a change through onSkinChange and does not invent local state.

Native controls

Actions and form components keep native browser behavior:

  • Button is a native button, defaults to type="button", and uses a stable geometry width preset instead of measuring its label. Use width="compact|standard|wide|extended|full" for layout intent.
  • Toggle and Checkbox are native checkbox inputs.
  • Slider is a native range input.
  • Field forwards its ref and standard props to its native input.
  • Segmented implements radio-group semantics and roving focus.
  • TabBar and Tab implement context registration and the tab keyboard pattern without DOM queries.

Accessible names are required where visible content cannot provide one. Interactive targets have a 3rem minimum hit box and visible focus treatment.

Design units and placement

All component geometry derives from --rg-u. It is 1px for standalone components and scales from the 332-wide reference container inside a screen. Scaling caps at the reviewed 410-wide geometry on large and tablet surfaces; a Screen whose own measured geometry is landscape uses its shorter axis so controls do not become oversized or collide with the lower shell.

import { MapPin, u } from "@objectifthunes/royal-games-ui";

<MapPin
  variant="button"
  state="current"
  label="Open destination seven"
  onPress={openDestination}
  style={{ insetInlineStart: u(70), insetBlockStart: u(190) }}
>
  7
</MapPin>;

Hosts can override the documented safe-inset tokens in deterministic WebView or browser fixtures. Descendants must not apply env(safe-area-inset-*) again.

Artwork and product state

The host supplies player identity, text, images, SVG artwork, prices, purchase callbacks, navigation, rankings, rewards, and all game state. The library does not ship binary artwork, emoji placeholders, payment logic, progression rules, timers, or mock product content.

Components do not assume a router, state library, network layer, localization system, or game rule model. Polymorphic components such as MapPin and SettingsRow expose discriminated native roots and forward the appropriate HTML attributes, refs, data-* hooks, and test identifiers. Spacing presets use geometry names such as compact, roomy, and tight; they never infer what a host puts inside a component.

Gameplay-specific boards, keyboards, letter tiles, joysticks, and rule-driven controls are intentionally outside this package.

Motion

Entrance choreography is separate from interaction feedback. Interaction states have no fixed delay. useEntranceMotion measures the actual finite Web Animations attached to an element and settles React entrance state when they finish. Reduced-motion preferences disable nonessential animation.

Development

pnpm install --frozen-lockfile
pnpm check
pnpm test:browser
pnpm test:package

The checks validate formatting, strict TypeScript and negative type contracts, source authorship rules, unit and accessibility integration flows, the production build, packed Vite and Next.js consumers, and browser interaction. Visual baselines cover both themes in Chromium and WebKit across the required compact, reference, large, tablet, and landscape fixtures.