
Product
Socket Now Protects the Firefox Extension Ecosystem
Socket is bringing experimental protection to Firefox, scanning 97,000+ extensions in Mozilla's official directory for malware and risky updates.
@mythxengine/glyphkit
Advanced tools
GlyphKit — 16-bit pixel-art React design system with genre-specific themes, runtime CSS variable generation, and optional Framer Motion integration.
@mythxengine/glyphkit— a 16-bit pixel-art React design system
GlyphKit is a dark-mode-first, genre-aware design system built for retro and TTRPG-style applications. Themes are generated as CSS custom properties at runtime, so swapping between Fantasy, Sci-Fi, Paranoia, Horror, and Dungeon aesthetics is a single hook call — no static CSS bundle, no FOUC.
An optional @mythxengine/glyphkit/motion subpath ships pixel-perfect Framer Motion wrappers with step-based easing that matches steps(N, end) timing.
pnpm add @mythxengine/glyphkit
# or
npm install @mythxengine/glyphkit
Peer dependencies:
| Package | Version | Required? |
|---|---|---|
react | ^18.0.0 || ^19.0.0 | yes |
react-dom | ^18.0.0 || ^19.0.0 | yes |
framer-motion | ^11.0.0 || ^12.0.0 | optional, only if you import from @mythxengine/glyphkit/motion |
import { ThemeProvider, themeRegistry, useTheme } from "@mythxengine/glyphkit";
function App() {
return (
<ThemeProvider themes={themeRegistry} defaultTheme="kingdom-quest">
<YourApp />
</ThemeProvider>
);
}
function YourApp() {
const { theme, setTheme } = useTheme();
return (
<div>
<h1 style={{ color: "var(--color-primary-500)" }}>{theme.displayName}</h1>
<button onClick={() => setTheme("neon-terminal")}>Switch to Sci-Fi</button>
</div>
);
}
ThemeProvider injects the active theme's CSS custom properties on <html> and listens for prefers-color-scheme changes.
For the pixel-utility classes (.border-pixel*, .shadow-pixel-*, .font-pixel, .effect-scanlines, etc.) plus reduced-motion / focus-visible defaults, import the baseline stylesheet once at app entry:
import "@mythxengine/glyphkit/styles";
The stylesheet is theme-neutral — ThemeProvider will overwrite the first-paint defaults at runtime.
| Subpath | Purpose |
|---|---|
@mythxengine/glyphkit | Theme provider, registry, generator, components, transitions |
@mythxengine/glyphkit/motion | Framer Motion wrappers (PixelButton, PixelCard, hooks, …) |
@mythxengine/glyphkit/icons | Theme-aware icon registry built on pixelarticons |
@mythxengine/glyphkit/styles | Baseline stylesheet: pixel utility classes, effects, a11y defaults (CSS) |
| ID | Name | Genre | Primary | Accent |
|---|---|---|---|---|
kingdom-quest | Kingdom Quest | Fantasy | Purple (#9686ab) | Gold (#d4a72c) |
neon-terminal | Neon Terminal | Sci-Fi | Cyan (#00d4ff) | Magenta (#ff00ff) |
alpha-complex | Alpha Complex | Paranoia | Red (#cc0000) | Yellow (#ffcc00) |
shadow-realm | Shadow Realm | Horror | Crimson (#8b2942) | Sickly Green (#4a8b2a) |
deep-dungeon | Deep Dungeon | Dungeon | Stone Gray (#4a4a58) | Torchlight (#e07020) |
<ThemeProvider /><ThemeProvider
themes={themeRegistry} // required
defaultTheme="kingdom-quest" // optional initial preset
defaultColorScheme="dark" // "dark" | "light"
storageKey="glyphkit-theme" // localStorage key (default)
>
{children}
</ThemeProvider>
useTheme()const {
theme, // PixelThemeConfig
themeId, // ThemePresetId
colorScheme, // "dark" | "light"
setTheme, // (id: ThemePresetId) => void
setColorScheme,
transition, // TransitionVariant
setTransition,
isLoaded, // boolean — true after hydration
} = useTheme();
import { ThemeSelector, ThemeToggle } from "@mythxengine/glyphkit";
<ThemeSelector /> // button grid
<ThemeSelector compact /> // dropdown
<ThemeToggle /> // cycle through themes
Every preset emits a consistent token surface:
/* Colors */
--color-primary-500;
--color-accent-500;
--background-primary;
--foreground-primary;
--surface-primary;
/* Pixel styling */
--grid-unit: 8px;
--border-thin: 1px;
--border-medium: 2px;
--border-thick: 4px;
--shadow-inset;
--shadow-raised;
--shadow-glow;
/* Typography */
--font-pixel: "Press Start 2P", monospace;
--font-terminal: "VT323", monospace;
/* Animation */
--timing-function: steps(4, end);
--duration-fast: 100ms;
--duration-normal: 200ms;
--duration-slow: 400ms;
import { generateFullStylesheet, generateCSSVariables } from "@mythxengine/glyphkit";
const css = generateFullStylesheet(theme, "dark"); // full :root + [data-theme] block
const vars = generateCSSVariables(theme, "dark"); // object for inline styles or SSR
pnpm add framer-motion
import { PixelMotion, PixelButton, pixelEasing } from "@mythxengine/glyphkit/motion";
<PixelButton variant="pixel" onClick={onClick}>Press Start</PixelButton>
<PixelMotion
as="div"
steps={4}
duration="fast"
pixelSnap
whileHover={{ y: -2 }}
whileTap={{ y: 2 }}
>
Hover me
</PixelMotion>
| Preset | Steps | Duration | Use case |
|---|---|---|---|
instant | 1 | 0ms | Snap |
retro2 | 2 | 100ms | NES-style |
retro4 | 4 | 200ms | SNES-style (default) |
retro8 | 8 | 400ms | Smoother retro |
Components: PixelMotion, PixelButton, PixelCard, PixelStatusBar, PixelDialog, PixelIcon.
Hooks: usePixelAnimation, usePixelSpring, useReducedMotion.
All motion respects prefers-reduced-motion.
The motion module is opinionated about step-based easing (steps(N, end)) because that's what makes the aesthetic work. For animations that need genuinely smooth easing (bezier curves, spring physics that mid-flight, page-turn transitions, etc.), import framer-motion directly:
import { motion, AnimatePresence } from "framer-motion";
// Custom bezier, smooth — explicitly outside the step-easing model.
<motion.div animate={{ x: 100 }} transition={{ duration: 0.4, ease: [0.2, 0.8, 0.2, 1] }} />;
The genre/variants helpers (buttonVariants, cardVariantPresets, etc.) compose with raw framer-motion — pass them into your own motion.X and you keep the look without going through PixelMotion.
Each variant family has its own lifecycle state names. Stick to these when composing custom motion.X elements with a preset:
| Family | States |
|---|---|
buttonVariantPresets | initial, hover, tap, disabled, pulse (neon only) |
cardVariantPresets | initial, hover, tap, selected, hidden, visible, enter, exit |
dialogVariantPresets | hidden, visible, exit (note: no initial) |
statusBarVariantPresets | complete, countdown, counting, critical, damage, … |
cursorVariantPresets | still, visible, blink, bob, pulse, spin, selected |
| genre presets | each variant exposes its own (chestOpen, hologram, bloodDrip, …) |
import { createRegistry, themeRegistry, ThemeProvider } from "@mythxengine/glyphkit";
const custom = createRegistry({
"kingdom-quest": {
...themeRegistry["kingdom-quest"],
colors: {
...themeRegistry["kingdom-quest"].colors,
dark: {
...themeRegistry["kingdom-quest"].colors.dark,
primary: { 500: "#ff0000" },
},
},
},
});
<ThemeProvider themes={custom}>...</ThemeProvider>;
Wrap the provider in a client component:
"use client";
import { ThemeProvider, themeRegistry } from "@mythxengine/glyphkit";
export function Providers({ children }: { children: React.ReactNode }) {
return <ThemeProvider themes={themeRegistry}>{children}</ThemeProvider>;
}
The motion subpath requires the same "use client" boundary because Framer Motion is client-only.
GlyphKit follows Semantic Versioning. Releases are managed with Changesets; see the monorepo .changeset/ directory for in-flight changes.
MIT © Josh Mabry / protoLabs. See LICENSE.
FAQs
GlyphKit — 16-bit pixel-art React design system with genre-specific themes, runtime CSS variable generation, and optional Framer Motion integration.
The npm package @mythxengine/glyphkit receives a total of 15 weekly downloads. As such, @mythxengine/glyphkit popularity was classified as not popular.
We found that @mythxengine/glyphkit demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket is bringing experimental protection to Firefox, scanning 97,000+ extensions in Mozilla's official directory for malware and risky updates.

Research
/Security News
Three compromised Rust crates pulled in a malicious dependency that downloaded and executed cross-platform malware during Cargo builds.

Research
/Security News
Socket uncovered 77 linked Firefox extensions, including 40 that steal wallet secrets or credentials and 37 deceptive sports-score shells.