DOCUMENTATION
Three steps to your first rendered component. Then dig into icons, animation, and the rest of the kit.
Install · Wrap with provider · Use components
Getting Started
Step 1 — Install. One command pulls @pxlkit/core and whichever icon packs you actually need. Pure SVG, no font loading, tree-shakeable — every pack is its own npm module under the @pxlkit scope.
npm install @pxlkit/core @pxlkit/gamification @pxlkit/feedback @pxlkit/social @pxlkit/weather @pxlkit/ui @pxlkit/effects @pxlkit/parallaxStep 2 — Wrap with the provider (only needed for the UI Kit). Mount <PxlKitSurfaceProvider> once at the root of your app to set the default surface — "pixel" for the retro 8-bit aesthetic, "linear" for a flat modern one. Every UI Kit component reads from it, and any component can override locally with its own surface prop.
import { PxlKitSurfaceProvider } from '@pxlkit/ui-kit';
import '@pxlkit/ui-kit/styles.css';
export default function RootLayout({ children }) {
return (
<html>
<body>
<PxlKitSurfaceProvider surface="pixel">
{children}
</PxlKitSurfaceProvider>
</body>
</html>
);
}Step 3 — Use components. Import any icon and any UI Kit primitive and render. Icons accept palette (default), tinted, and solid appearance modes — same prop, three looks.
import { PxlKitIcon } from '@pxlkit/core';
import { Trophy } from '@pxlkit/gamification';
import { CheckCircle } from '@pxlkit/feedback';
import { Heart } from '@pxlkit/social';
import { Sun } from '@pxlkit/weather';
function App() {
return (
<div>
{/* Palette colors (default) — uses the icon's original palette */}
<PxlKitIcon icon={Trophy} size={32} />
{/* Solid mode — every pixel flattened to one color */}
<PxlKitIcon icon={CheckCircle} size={32} appearance="solid" color="#00FF88" />
{/* Tinted mode — palette + colour overlay, preserves luminance */}
<PxlKitIcon icon={Heart} size={48} appearance="tinted" color="#FF0000" />
</div>
);
}Available Packs
Pxlkit ships with 7 icon packs (6 standard 16×16 packs plus the 3D parallax pack documented below). Each standard pack can contain both static and animated icons. Install only the ones you need — they're fully tree-shakeable.
@pxlkit/gamification+ANIMATED
Icons for game mechanics, achievements, rewards, and RPG elements
51 icons
@pxlkit/feedback+ANIMATED
Icons for notifications, alerts, status messages, and toasts
33 icons
@pxlkit/social+ANIMATED
Icons for social media, community, and user interaction
43 icons
@pxlkit/weather+ANIMATED
Icons for weather conditions, seasons, and natural phenomena
36 icons
@pxlkit/ui+ANIMATED
Icons for interface controls, editor tools, and common actions
41 icons
@pxlkit/effects+ANIMATED
Animated visual effects — explosions, signals, particles, glows, and VFX
12 icons
npm install @pxlkit/core @pxlkit/socialIcon Format
Icons are defined using a simple, human-readable format: a grid of characters where each character maps to a color via a palette. The . character is always transparent.
This format is designed to be easy to read, write by hand, and generate with AI. Each row is a string of exactly N characters (where N matches the grid size).
type GridSize = 8 | 16 | 24 | 32 | 48 | 64;
interface PxlKitData {
name: string; // kebab-case identifier
size: GridSize; // grid dimensions (NxN)
category: string; // pack/category name
grid: string[]; // N rows of N characters each
palette: Record<string, string>; // char → hex color (#RGB / #RRGGBB / #RRGGBBAA)
tags: string[]; // searchable tags
author?: string; // attribution
}export const Trophy: PxlKitData = {
name: 'trophy',
size: 16,
category: 'gamification',
grid: [
'................',
'..GGGGGGGGGGGG..',
'.GG.YYYYYYYY.GG.',
'.G..YYYYYYYY..G.',
'.G..YYYWYYYY..G.',
'.GG.YYYYYYYY.GG.',
'..GGGGGGGGGGGG..',
'....GGGGGGGG....',
'.....GGGGGG.....',
'......GGGG......',
'......GGGG......',
'.....DDDDDD.....',
'....DDDDDDDD....',
'....BBBBBBBB....',
'...BBBBBBBBBB...',
'................',
],
palette: {
'G': '#FFD700', // Gold
'Y': '#FFF44F', // Yellow
'D': '#B8860B', // Dark gold
'B': '#8B4513', // Brown
'W': '#FFFFFF', // White
},
tags: ['trophy', 'achievement'],
};Key insight: This same format can be output by an AI model. The grid is essentially ASCII art with a legend. You can ask ChatGPT, Claude, or any LLM to generate it.
Opacity / Alpha
Each palette color supports per-pixel opacity via the #RRGGBBAA format. The last two hex digits represent the alpha channel (00 = fully transparent, FF = fully opaque).
palette: {
'A': '#FF000080', // Red at 50% opacity
'B': '#00FF00CC', // Green at 80% opacity
'C': '#0000FF', // Blue at 100% (default)
'D': '#FFD70040', // Gold at 25% opacity
}Supported hex formats:
#RGB— shorthand (expanded to #RRGGBB, fully opaque)#RRGGBB— standard 6-digit hex (fully opaque)#RRGGBBAA— 8-digit hex with alpha channel
The <PxlKitIcon /> component, SVG utilities, and Builder UI all handle opacity automatically. When generating SVG, pixels with opacity < 1 get a fill-opacity attribute.
import { parseHexColor, encodeHexColor } from '@pxlkit/core';
// Parse: extract color and opacity from hex string
const { color, opacity } = parseHexColor('#FF000080');
// color = '#FF0000', opacity = 0.502
// Encode: combine color and opacity back to hex
const hex = encodeHexColor('#FF0000', 0.5);
// hex = '#FF000080'
// If opacity is 1 (or omitted), returns 6-digit hex
const solid = encodeHexColor('#FF0000');
// solid = '#FF0000'React Component
The <PxlKitIcon /> component renders pixel art as an <img> element whose src is an inline SVG document encoded as a data URI (MIME image/svg+xml). The source format stays SVG end-to-end — vector, hi-DPI sharp, exportable — but the wrapping <img> lets us use image-rendering: pixelated, the only browser-honoured directive that guarantees true nearest-neighbour scaling for pixel art at any size from 8 px to 512 px.
type IconAppearance =
| 'palette' // (default) original artwork colours
| 'tinted' // palette + colour overlay (preserves luminance & detail)
| 'solid'; // every pixel flattened to a single colourinterface PxlKitProps {
icon: PxlKitData; // Icon data (required)
size?: number; // Visual size in px (default: 32)
appearance?: IconAppearance; // Colour mode (default: 'palette')
color?: string; // Tint hue / flat colour for 'tinted' & 'solid'
className?: string; // CSS class names (applied to the <img>)
'aria-label'?: string; // Accessibility label (becomes <img alt>)
style?: React.CSSProperties; // Inline styles (merged onto the <img>)
/** @deprecated since v1.3 — use `appearance="palette" | "solid"` instead. */
colorful?: boolean;
/** @deprecated since v1.3 — use `appearance="solid"` instead. */
solid?: boolean;
/** @deprecated since v1.3 — use `appearance="tinted" color="..."` instead. */
tint?: string;
}// Default — original artwork palette
<PxlKitIcon icon={Trophy} size={32} />
// Tinted — keep the palette luminance, shift the hue
<PxlKitIcon icon={Trophy} size={32} appearance="tinted" color="#00FF88" />
// Solid — every pixel becomes one colour
<PxlKitIcon icon={Trophy} size={32} appearance="solid" color="#FF0000" />MIGRATION FROM v1.2.x
<PxlKitIcon icon={X} colorful />→ omit the prop (paletteis the default)<PxlKitIcon icon={X} />(legacy mono) →<PxlKitIcon icon={X} appearance="solid" /><PxlKitIcon icon={X} color="#FF0000" />→<PxlKitIcon icon={X} appearance="solid" color="#FF0000" /><PxlKitIcon icon={X} tint="#FF0000" />→<PxlKitIcon icon={X} appearance="tinted" color="#FF0000" />
The deprecated colorful / solid / tint aliases silently resolve to the new appearance axis at runtime so existing code keeps working. TypeScript marks them as @deprecated; plan to migrate before v2.
Animated Icons
Animated icons extend the pixel art format with frame-based playback. Each frame shares a base palette and can optionally override individual colors. Playback behavior is controlled by the trigger prop.
interface AnimatedPxlKitData {
name: string;
size: GridSize; // 8 | 16 | 24 | 32 | 48 | 64
category: string;
palette: Record<string, string>; // shared base palette across all frames
frames: AnimationFrame[]; // array of frames (in display order)
frameDuration: number; // ms per frame (e.g. 150)
loop: boolean; // @deprecated — use trigger instead
trigger?: AnimationTrigger; // controls playback behavior
tags: string[];
author?: string;
}
interface AnimationFrame {
grid: string[]; // same grid format as PxlKitData
palette?: Record<string, string>; // optional per-frame palette overrides
}
type AnimationTrigger = 'loop' | 'once' | 'hover' | 'appear' | 'ping-pong';interface AnimatedPxlKitProps {
icon: AnimatedPxlKitData;
size?: number; // size in px (default: 32)
appearance?: IconAppearance; // colour mode (default: 'palette')
color?: string; // tint / solid colour
trigger?: AnimationTrigger; // override icon.trigger
speed?: number; // multiplier: 2 = 2× faster, 0.5 = half (0.1–10)
fps?: number; // fixed FPS — takes priority over speed (1–60)
playing?: boolean; // manual play/pause override
className?: string;
style?: React.CSSProperties;
'aria-label'?: string;
/** @deprecated since v1.3 — use `appearance` instead. */
colorful?: boolean;
/** @deprecated since v1.3 — use `appearance="solid"` instead. */
solid?: boolean;
/** @deprecated since v1.3 — use `appearance="tinted" color="..."` instead. */
tint?: string;
}import { AnimatedPxlKitIcon } from '@pxlkit/core';
import { FireSword } from '@pxlkit/gamification';
// Loop forever in palette mode (default)
<AnimatedPxlKitIcon icon={FireSword} size={48} />
// Solid colour loop — flatten every pixel to one colour
<AnimatedPxlKitIcon icon={FireSword} size={32} appearance="solid" color="#00FF88" />
// Tinted loop — keep luminance, shift hue
<AnimatedPxlKitIcon icon={FireSword} size={32} appearance="tinted" color="#FF00AA" />// 'loop' — plays continuously (default)
<AnimatedPxlKitIcon icon={FireSword} trigger="loop" />
// 'once' — plays one time, stops on last frame
<AnimatedPxlKitIcon icon={FireSword} trigger="once" />
// 'hover' — plays only while the user hovers
<AnimatedPxlKitIcon icon={FireSword} trigger="hover" />
// 'appear' — plays once when it enters the viewport
<AnimatedPxlKitIcon icon={FireSword} trigger="appear" />
// 'ping-pong' — loops forward then backward alternating
<AnimatedPxlKitIcon icon={FireSword} trigger="ping-pong" />// 2× speed — double frame rate
<AnimatedPxlKitIcon icon={FireSword} speed={2} />
// Half speed
<AnimatedPxlKitIcon icon={FireSword} speed={0.5} />
// Fixed FPS — takes priority over speed and icon.frameDuration
<AnimatedPxlKitIcon icon={FireSword} fps={6} />
// Paused manually
<AnimatedPxlKitIcon icon={FireSword} playing={false} />import { generateAnimatedSvg } from '@pxlkit/core';
import { FireSword } from '@pxlkit/gamification';
// Colorful animated SVG with CSS keyframe animation (default)
const svg = generateAnimatedSvg(FireSword);
// Monochrome animated SVG
// (note: generateAnimatedSvg is a utility — its options use the legacy
// colorful/monoColor shape; the React component uses the new appearance API)
const monoSvg = generateAnimatedSvg(FireSword, {
colorful: false,
monoColor: '#00FF88',
});loop
hover
ping-pong
LIVE PREVIEW
FireSword — 4 frames · 150ms
hover center icon to trigger it
Parallax 3D Icons
The @pxlkit/parallax pack introduces multi-layer 3D parallax pixel icons — interactive depth-based icons where each layer floats at a different Z-depth. Mouse movement across the viewport rotates the entire scene, creating a true 3D effect. Click interactions trigger particle bursts, layer explosions, and color shifts.
npm install @pxlkit/core @pxlkit/parallaximport { ParallaxPxlKitIcon } from '@pxlkit/core';
import { GhostFriend, CoolEmoji } from '@pxlkit/parallax';
// Basic 3D parallax icon (palette is the default — every layer keeps its colours)
<ParallaxPxlKitIcon icon={GhostFriend} size={64} />
// Large interactive icon with custom strength + a tint applied to every layer
<ParallaxPxlKitIcon
icon={CoolEmoji}
size={128}
strength={20}
interactive
appearance="tinted"
color="#FFD700"
/>How it works: Each parallax icon is composed of multiple animated layers stacked at different Z-depths using CSS perspective + preserve-3d + per-layer translateZ. The component tracks mouse position across the entire viewport and applies rotateX/rotateY transforms to the scene with smooth lerp interpolation.
interface ParallaxPxlKitData {
name: string; // kebab-case identifier
size: GridSize; // grid dimensions (e.g. 16)
category: string; // always 'parallax'
layers: ParallaxLayer[]; // ordered back→front (first = deepest)
tags: string[]; // searchable tags
author?: string;
}
interface ParallaxLayer {
icon: AnimatedPxlKitData; // each layer is an animated icon
depth: number; // Z-depth: positive = far, negative = near
// depth: 3.0 → far background (shadow, trail)
// depth: 0 → center baseline (body)
// depth: -2.0 → near foreground (face details, blush)
}interface ParallaxPxlKitProps {
icon: ParallaxPxlKitData; // The parallax icon data (required)
size?: number; // Container size in px (default: 64)
strength?: number; // Mouse reaction intensity (default: 18)
appearance?: IconAppearance; // Colour mode applied to every layer (default: 'palette')
color?: string; // Tint / solid colour applied to every layer
smoothing?: number; // Lerp factor 0–1 (default: 0.06)
perspective?: number; // CSS perspective in px (default: max(200, size×2.5))
layerGap?: number; // Z spacing between layers (default: max(12, size×0.2))
shadow?: boolean; // Depth shadow between layers (default: true)
interactive?: boolean; // Click effects enabled (default: true)
onActivate?: (active: boolean) => void; // Click toggle callback
className?: string;
style?: React.CSSProperties;
'aria-label'?: string;
/** @deprecated since v1.3 — use `appearance` instead. */
colorful?: boolean;
/** @deprecated since v1.3 — use `appearance="solid"` instead. */
solid?: boolean;
/** @deprecated since v1.3 — use `appearance="tinted" color="..."` instead. */
tint?: string;
}Key features:
- True 3D Depth — CSS perspective + preserve-3d + per-layer translateZ for real depth
- Page-Wide Tracking — Mouse rotation works across the entire viewport, not just the icon
- Click Interactions — Particle bursts, layer explosions, random rotation jolt, color hue-shift on click
- Animated Layers — Each layer is a full
AnimatedPxlKitDatawith frame-based animation (e.g., blinking eyes, flickering shadows) - Peel-Apart Intro — Layers spread out in a dramatic animation on mount
- Depth Shadows — Soft CSS shadows between layers for visual depth
// GhostFriend has 5 animated layers at different depths:
const GhostFriend: ParallaxPxlKitData = {
name: 'ghost-friend',
size: 16,
category: 'parallax',
layers: [
{ icon: GhostShadow, depth: 3.0 }, // far background shadow
{ icon: GhostTrail, depth: 1.5 }, // wispy trail behind
{ icon: GhostBody, depth: 0 }, // main body (center)
{ icon: GhostFace, depth: -1.0 }, // eyes + mouth (closer)
{ icon: GhostBlush, depth: -2.0 }, // blush cheeks (nearest)
],
tags: ['ghost', 'cute', 'friendly', '3d', 'parallax'],
};import { ParallaxPack } from '@pxlkit/parallax';
import {
CoolEmoji, // Sunglasses emoji with sparkle layers
PixelHeart, // Beating heart with glow + particles
RetroTV, // CRT monitor with scan lines
PixelRocket, // Rocket ship with exhaust + stars
GhostFriend, // Cute ghost with blush + trail
NeonSkull, // Glowing skull with neon effects
MagicOrb, // Floating orb with energy rings
PixelCrown, // Crown with sparkles
RetroJoystick, // Gamepad with button highlights
CyberEye, // Cyberpunk eye with scan effects
} from '@pxlkit/parallax';GhostFriend
CoolEmoji
LIVE 3D PREVIEW
10 parallax icons
move mouse to rotate · click to interact
UI KIT PARALLAX COMPONENTS
The UI Kit also includes scroll-based and cursor-tracking parallax wrapper components:PixelParallaxLayer (scroll-based), PixelParallaxGroup (clipped container), and PixelMouseParallax (cursor-tracking). See the UI Kit Parallax docs for details.
Toast Notifications
Toast notifications come in two layers — both documented in the UI Kit:
- /ui-kit#pixel-toast — the low-level
<PixelToast>component shipped from@pxlkit/core: 15 props for visibility, title/message, icon, position, duration, colours, close button. - /ui-kit#use-toast — the
<ToastProvider>+useToast()hook pattern that stacks multiple toasts, handles timers, and exposessuccess/error/info/warningshortcuts. Use this in app code.
import { useToast } from '@/components/ToastProvider';
import { PixelButton } from '@pxlkit/ui-kit';
import { CheckCircle } from '@pxlkit/feedback';
function App() {
const { success } = useToast();
return (
<PixelButton tone="green"
onClick={() => success('SAVED', 'Your changes have been saved', CheckCircle)}
>
Show Toast
</PixelButton>
);
}Available tones: success, error, warning, info. Each tone has default colors and icons, but you can override them with any Pxlkit icon — including animated ones.
DETAILED UI KIT DOCS
Open the dedicated UI Kit section for interactive controls and full prop details:
Open PixelToast Docs →SVG Generation
You can generate standalone SVG files from icon data using the utility functions:
import { gridToSvg } from '@pxlkit/core';
import { Trophy } from '@pxlkit/gamification';
// Colorful SVG string
const colorSvg = gridToSvg(Trophy, { mode: 'colorful' });
// Monochrome SVG
const monoSvg = gridToSvg(Trophy, {
mode: 'monochrome',
monoColor: '#333333',
});
// With XML declaration (for standalone files)
const fileSvg = gridToSvg(Trophy, {
mode: 'colorful',
xmlDeclaration: true,
});import {
gridToPixels, // PxlKitData → Array<{ x, y, color, opacity? }>
pixelsToGrid, // pixels + size + palette → { grid, palette }
pixelsToSvg, // pixels + size + SvgOptions → SVG string
svgToDataUri, // SVG string → "data:image/svg+xml,..."
svgToBase64, // SVG string → "data:image/svg+xml;base64,..."
} from '@pxlkit/core';import {
validateIconData, // (icon) => string[] — array of error messages (empty = valid)
isValidIconData, // (icon) => boolean — shorthand
parseIconCode, // (code: string) => PxlKitData | null — strict
parseAnyIconCode, // (code: string) => AnyIcon | null — handles Pxl / Animated / Parallax
generateIconCode, // (icon) => string — PxlKitData → TS source
isAnimatedIcon, // (icon) => icon is AnimatedPxlKitData — type guard
isParallaxIcon, // (icon) => icon is ParallaxPxlKitData — type guard
} from '@pxlkit/core';import {
generateAnimatedSvg, // (icon, { colorful?, monoColor?, pixelSize?, xmlDeclaration? }) => string
animatedToFrameIcons, // (icon) => Array<{ icon: PxlKitData; duration: number }>
} from '@pxlkit/core';
// Drive your own raf/canvas loop from animatedToFrameIcons():
const frames = animatedToFrameIcons(FireSword);
frames.forEach(({ icon, duration }) => {
// icon is a static PxlKitData snapshot of the frame
// duration is the ms to display it before advancing
});import {
parseHexColor, // ('#RRGGBBAA') => { color: string; opacity: number }
encodeHexColor, // (hex, opacity?) => string — inverse of parseHexColor
adjustBrightness, // (hex, amount: -1..1) => string — lighten/darken
hexToRgb, // ('#RRGGBB') => { r, g, b }
rgbToHex, // (r, g, b) => '#RRGGBB'
getPerceivedBrightness, // ('#RRGGBB') => number (0..255 luma) — useful for picking dark/light text
RETRO_PALETTES, // Record<name, string[]> — the curated retro palettes used across the site
} from '@pxlkit/core';
// Pick a readable text colour automatically:
const luma = getPerceivedBrightness(bgHex);
const textColor = luma > 140 ? '#000' : '#fff';AI Generation
The grid format was specifically designed to work well with AI code generation. Here's a prompt template you can use with any LLM:
Generate a 16x16 pixel art icon in this JSON format:
{
"name": "icon-name-here",
"size": 16,
"category": "your-category",
"grid": [
"................",
// 16 rows, each with exactly 16 characters
// "." = transparent pixel
// Letters map to colors via palette
],
"palette": {
"A": "#HEX001",
"B": "#HEX002"
},
"tags": ["tag1", "tag2"]
}
Rules:
- Grid: exactly 16 rows of 16 chars
- "." is always transparent
- Use 3-6 colors max for clean pixel art
- Each non-"." character must have a palette entry
Create a [YOUR DESCRIPTION] icon.After the AI generates the code, you can paste it into the Builder to preview it, or use parseIconCode() programmatically:
import { parseIconCode, validateIconData } from '@pxlkit/core';
const aiOutput = `{ "name": "fire", ... }`;
const icon = parseIconCode(aiOutput);
if (icon) {
const errors = validateIconData(icon);
if (errors.length === 0) {
// Valid icon! Use it or save it
console.log('Icon parsed successfully:', icon.name);
}
}UI Kit Components
Pxlkit includes a full React + TypeScript component library with 111 production-ready components: buttons, inputs, cards, selects, modals, toasts, tables, badges, avatars, skeletons, layout primitives, and animation wrappers.
/ui-kit#getting-startednpm install @pxlkit/core @pxlkit/ui-kit tailwindcss/* Add this to your global stylesheet (e.g., globals.css or index.css) */
@import "tailwindcss";
@import "@pxlkit/ui-kit/styles.css";
/* Tell Tailwind to scan the package for its utility classes */
@source "../node_modules/@pxlkit/ui-kit";import { PixelButton, PixelCard, PixelInput, PixelSelect } from '@pxlkit/ui-kit';
import { PxlKitIcon } from '@pxlkit/core';
import { Trophy } from '@pxlkit/gamification';
<PixelButton tone="green" iconLeft={<PxlKitIcon icon={Trophy} size={16} />}>
Create Quest
</PixelButton>The UI Kit page includes live previews, props tables, and copy-ready code examples for each element. Use the sidebar to browse everything by category, includingPixelToast and animation utilities.
Contributing
Pxlkit is community-driven, with MIT code packages and source-available asset packs. Here's how you can contribute:
- Add icons to existing packs — Create new icons using the Builder, copy the TypeScript code, and submit a PR
- Create new icon packs — See the section below for the pack structure
- Improve the Builder — Add new tools, improve UX, fix bugs
- Improve core utilities — Optimize SVG generation, add new export formats
- Documentation — Fix typos, add examples, improve guides
NAMING CONVENTIONS
- Icon names:
kebab-case(e.g., fire-sword) - Export names:
PascalCase(e.g., FireSword) - Pack names:
kebab-case(e.g., fantasy-rpg) - Tags: lowercase, comma-separated
- Colors: uppercase hex with # (e.g., #FF0000)
- Maximum 6 colors per icon for clarity
Creating Packs
A pack is a separate npm package under @pxlkit/. Here's the structure:
packages/your-pack/
├── src/
│ ├── icons/
│ │ ├── icon-one.ts # Individual icon files
│ │ ├── icon-two.ts
│ │ └── icon-three.ts
│ └── index.ts # Export all icons + IconPack
├── package.json
├── tsconfig.json
└── tsup.config.tsimport type { IconPack } from '@pxlkit/core';
import { IconOne } from './icons/icon-one';
import { IconTwo } from './icons/icon-two';
export { IconOne } from './icons/icon-one';
export { IconTwo } from './icons/icon-two';
export const YourPack: IconPack = {
id: 'your-pack',
name: 'Your Pack Name',
description: 'A collection of ... icons',
icons: [IconOne, IconTwo],
version: '0.1.0',
author: 'your-name',
};After creating your pack, add it to the monorepo workspaces, register it in the web app's icon registry, and submit a pull request.