A professional CSS
box-shadowgenerator with multi-layer control, real-time preview, and cross-format code export.
Layerbox is a browser-based design tool for creating, visualizing, and exporting complex box-shadow stacks. It provides polar angle/distance controls, material simulation, a light source engine, shadow morphing, depth generation, and a comprehensive preset library. The application runs entirely on the client using Next.js and React.
Live site: layerbox.vercel.app
- Architecture Overview
- Core Types
- State Management
- Modules Reference
- Component Architecture
- Export Format System
- Mobile Responsiveness
- Development Guide
- Project Structure
- Contributing
- License
Layerbox follows a unidirectional data flow pattern:
User Interaction
|
v
Component Layer (React)
|
v
State Hook (useShadowState)
|
v
Lib Modules (pure functions)
|
v
CSS Output / Canvas Rendering
- State is centralized in a single
useShadowStatehook that manages shadow layers, undo/redo history, and URL synchronization. - Pure functions in
lib/handle all transformations: CSS generation, format conversion, encoding/decoding, material color modulation, and natural language parsing. - Components are split into three categories: controls (user input), preview (canvas rendering), and code (output display).
- URL state is the persistence mechanism. The entire shadow configuration is serialized into the
?s=query parameter, enabling shareable URLs without a server.
- User adjusts a control (blur, color, position, etc.)
- Component calls
updateLayer(id, patch)on the state hook - Hook applies the patch, pushes the new state to undo history, and triggers re-render
computeShadow()applies light source offsets if active- Preview canvas re-renders with the updated shadow layers
useEffectencodes the new state to the URL query parameter- Code output panel regenerates the formatted code string
Layerbox uses a custom design system built with CSS custom properties, Tailwind CSS v4 utility classes, and a consistent set of animation primitives.
The application defines a comprehensive set of CSS custom properties for theming. Two themes are provided: dark (default) and light. All UI components reference these tokens directly.
| Token | Dark Value | Light Value | Usage |
|---|---|---|---|
--bg |
#0b1414 |
#eef2f2 |
Page background |
--surface |
#111c1c |
#ffffff |
Card, panel, elevated surface |
--surface-raised |
#172020 |
#f0f5f5 |
Hovered/active surface |
--surface-code |
#0b1313 |
#f5f7f7 |
Code block background |
--border |
rgba(255,255,255,0.07) |
rgba(0,0,0,0.08) |
Default border |
--border-hover |
rgba(255,255,255,0.13) |
rgba(0,0,0,0.14) |
Hover/focus border |
--text |
#bdc1bb |
#0f2020 |
Primary text |
--text-muted |
#6e8a85 |
#4a6868 |
Secondary/meta text |
--text-faint |
#364d4d |
#7a9898 |
Placeholder, disabled text |
--accent |
#5e9e88 |
#3d8a72 |
Primary action, links, active state |
--accent-hover |
#4e8e78 |
#2e7a62 |
Accent hover state |
--destructive |
#c96060 |
#b04040 |
Delete, error states |
--header-bg |
rgba(11,20,20,0.88) |
rgba(238,242,242,0.88) |
Header background with blur |
| Token | Font | Usage |
|---|---|---|
--font-sans |
Satoshi, system-ui, sans-serif | UI text, headings, labels |
--font-serif |
Instrument Serif, Georgia, serif | Headings, accent text (via font-instrument-serif variable) |
--font-mono |
JetBrains Mono, Fira Code, monospace | Code output, technical values |
| Token | Dark Value | Light Value | Token Type |
|---|---|---|---|
--code-k |
#c586c0 |
#7b30a0 |
Keywords |
--code-s |
#ce9178 |
#a0522d |
Strings |
--code-n |
#b5cea8 |
#2e7d5e |
Numbers, hex colors |
--code-p |
#9cdcfe |
#1a6fc4 |
Properties |
--code-f |
#dcdcaa |
#b8860b |
Functions |
--code-c |
#6a9955 |
#5a8a5a |
Comments |
--code-o |
#6e7681 |
#999999 |
Operators, punctuation |
--code-d |
#d7ba7d |
#8b6914 |
CSS directives/pseudo |
--code-t |
#4ec9b0 |
#1a8a7a |
Types, classes |
| Class | Animation | Timing | Use Case |
|---|---|---|---|
.animate-fade-up |
fade-up | 0.35s cubic-bezier(0.16, 1, 0.3, 1) | Panel/mount entrances |
.animate-fade-in |
fade-in | 0.25s ease | Simple opacity reveals |
.animate-scale-in |
scale-in | 0.2s cubic-bezier(0.16, 1, 0.3, 1) | Modal, popover, tooltip |
.animate-check-pop |
check-pop | 0.25s cubic-bezier(0.34, 1.56, 0.64, 1) | Success indicators |
.animate-slide-in |
slide-in | 0.2s cubic-bezier(0.16, 1, 0.3, 1) | List item entrances |
Stagger classes (.stagger-1 through .stagger-4) add incremental delays for sequenced animations.
- Floating panels: Used for desktop side panels and code output. Fixed dimensions with
pointer-events: autofor interaction, wrapped in parents withpointer-events: none. - Bottom sheets: Mobile panels use a slide-up sheet at
max-height: 55vhwith a drag handle and close button. - Canvas overlays: Toolbars are centered horizontally above the preview canvas, with horizontal scroll on mobile.
- Code blocks: Syntax-highlighted output uses a monospace font with custom syntax tokens, rendered as HTML with inline CSS variables.
type Shadow = {
id: string; // Unique identifier (random alphanumeric)
x: number; // Horizontal offset in px
y: number; // Vertical offset in px
blur: number; // Blur radius in px (0-200)
spread: number; // Spread radius in px (-50 to 100)
opacity: number; // Opacity 0-1
color: string; // Hex color (#RRGGBB or #RGB)
inset: boolean; // True for inset shadow
visible: boolean; // Visibility toggle
};This is the fundamental data type throughout the application. Every shadow layer is represented by this interface.
type PreviewShape = "box" | "circle" | "button" | "card";Controls the shape of the element rendered on the preview canvas.
type ExportFormat = "css" | "tailwind" | "tailwind-config" | "scss" | "css-var" | "js" | "flutter";LightState:{ active: boolean, lx: number, ly: number }- normalized light position for the light source engine.GradientShadowParams:{ layers, falloff, depth, color, xOffset, yOffset }- configuration for the gradient shadow generator.DepthConfig:{ depth: number (0-1), color: string }- input to the depth meter engine.Material:{ id, name, badge, elementBg, shadowLightness, shadowOpacity, elementExtra?, description }- material definition for the material system.PaletteEntry:{ name, dotColor, description, shadow }- single entry in the generated shadow palette.Preset:{ name, category, shadows: Shadow[] }- a named preset for the gallery.
hooks/useShadowState.ts is the single source of truth for all shadow data. It is a custom React hook that encapsulates:
- Shadow layer array state
- Active layer selection
- Undo/redo history with configurable depth (default: 30 states)
- Light source state
- URL synchronization
| Method | Signature | Description |
|---|---|---|
shadows |
Shadow[] |
Current shadow layers |
activeId |
string |
ID of the selected layer |
setActiveId |
(id: string) => void |
Change active layer |
addLayer |
() => void |
Append a new layer with defaults |
removeLayer |
(id: string) => void |
Remove a layer (minimum 1 preserved) |
updateLayer |
(id: string, patch: Partial<Shadow>) => void |
Apply partial update to a layer |
duplicateLayer |
(id: string) => void |
Clone a layer and insert after it |
toggleLayerVisibility |
(id: string) => void |
Toggle a layer's visible flag |
reorderLayers |
(newOrder: Shadow[]) => void |
Replace entire order (for drag-to-reorder) |
loadPreset |
(presetShadows: Shadow[]) => void |
Load a preset, resetting history |
computeShadow |
(s: Shadow) => Shadow |
Apply light source offsets to a shadow |
lightState |
LightState |
Current light source position and active state |
toggleLight |
() => void |
Toggle light source on/off |
setLightPosition |
(lx: number, ly: number) => void |
Set light source coordinates |
undo |
() => void |
Pop undo stack |
redo |
() => void |
Push redo stack forward |
canUndo |
boolean |
Whether undo is available |
canRedo |
boolean |
Whether redo is available |
getShareUrl |
() => string |
Returns the current URL with encoded state |
The hook maintains a useRef-based history array with a cursor index. Every state mutation (except undo/redo themselves) pushes the new state onto the history stack. When the user performs an undo, the cursor moves backward and the state is replaced with the historical snapshot. A skipHistory ref prevents undo/redo actions from creating duplicate history entries.
History is trimmed to MAX_HISTORY (30) entries. Forward history is discarded when a new action is taken after an undo (standard branching behavior).
On mount, the hook reads ?s= from the URL and decodes it into shadow layers. On every state change, it writes the encoded state back to the URL via history.replaceState. This enables shareable links and browser back/forward navigation.
All modules in lib/ are pure functions with no React dependencies. They can be imported and tested independently.
| Function | Signature | Description |
|---|---|---|
hexToRgba |
(hex: string, opacity: number) => string |
Convert hex color + opacity to rgba() string |
shadowToCss |
(s: Shadow) => string |
Single shadow layer to CSS box-shadow value fragment |
shadowsToCssValue |
(shadows: Shadow[]) => string |
All visible layers to comma-separated CSS value |
shadowsToCssRule |
(shadows: Shadow[]) => string |
Full box-shadow: ...; CSS rule |
shadowsToTailwind |
(shadows: Shadow[]) => string |
Tailwind arbitrary shadow-[...] class |
encodeShadows |
(shadows: Shadow[]) => string |
JSON encode + URI encode shadows for URL |
decodeShadows |
`(str: string) => Shadow[] | null` |
genId |
() => string |
Generate a random 7-character alphanumeric ID |
| Function | Signature | Description |
|---|---|---|
toCss |
(shadows: Shadow[]) => string |
Standard CSS rule |
toTailwind |
(shadows: Shadow[]) => string |
Tailwind arbitrary class syntax |
toTailwindConfig |
(shadows: Shadow[], name?: string) => string |
Tailwind config theme extension |
toScss |
(shadows: Shadow[], name?: string) => string |
SCSS variable |
toCssVar |
(shadows: Shadow[], name?: string) => string |
CSS custom property |
toJs |
(shadows: Shadow[]) => string |
React inline style object |
toFlutter |
(shadows: Shadow[]) => string |
Flutter BoxDecoration with BoxShadow list |
getFormatCode |
(format: ExportFormat, shadows: Shadow[]) => string |
Dispatch function for all formats |
Each generator produces human-readable, syntactically correct code for its target format. The Flutter generator includes a note about inset shadow support limitations.
| Function | Signature | Description |
|---|---|---|
lightOffsets |
(lx: number, ly: number, lift: number, maxOffset: number) => { x, y } |
Compute shadow offsets from light position and layer lift |
lightAngle |
(lx: number, ly: number) => number |
Compute display angle in degrees (0 = top) |
The light source engine models a point light in 2D space. The shadow direction is computed as the vector from the light position toward the element center, scaled by the layer's lift (how high the element is above the surface). This creates physically plausible shadow behavior as the light moves.
| Function | Signature | Description |
|---|---|---|
generateDepthShadows |
(depth: number, color: string, baseOpacity?: number) => Shadow[] |
Generate 3-5 shadow layers from depth value |
depthLabel |
(depth: number) => string |
Human-readable label: Flat, Raised, Lifted, Floating, Hovering, Levitated |
Depth is normalized 0-1. Layer count increases with depth (3 at shallow, up to 5 at deep). Each layer has distinct blur, offset, and opacity characteristics mimicking real-world light falloff.
| Function | Signature | Description |
|---|---|---|
generateGradientShadow |
(params: GradientShadowParams) => Shadow[] |
Generate N-layer gradient shadow stack |
Each layer is progressively more blurred and transparent, following a power curve defined by the falloff parameter. This creates natural glow effects that single shadows cannot achieve.
| Function | Signature | Description |
|---|---|---|
parseNaturalLanguage |
`(input: string) => Shadow[] | null` |
getExamples |
() => string[] |
Return list of example phrases |
The parser operates in three stages:
- Tokenisation: Splits input into words and classifies each as intensity, direction, style, color, or layer keyword.
- Parsing: Converts tokens into a
ParsedIntentwith normalized intensity, direction, style, layer count, and color hint. - Generation: Maps the intent to concrete shadow parameters using predefined intensity/offset/blur/opacity tables. Handles special cases for inset, glow, floating, and multi-layer styles.
| Function | Signature | Description |
|---|---|---|
getMaterial |
(id: string) => Material |
Lookup material by ID |
applyMaterialToColor |
(rgba: string, material: Material) => string |
Apply material lightness/opacity modifiers to a color string |
Six materials are defined: Paper, Glass, Metal, Frosted, Fabric, Plastic. Each defines an element background color, shadow lightness multiplier, shadow opacity multiplier, and optional extra CSS. The material system modifies how shadows render by adjusting their perceived lightness and opacity based on surface reflectivity.
| Function | Signature | Description |
|---|---|---|
encodeDNA |
(shadows: Shadow[]) => string |
Encode visible shadows to compact pipe-delimited string |
decodeDNA |
`(dna: string) => Shadow[] | null` |
compressDNA |
(dna: string) => string |
Placeholder for further compression |
expandDNA |
(compressed: string) => string |
Placeholder for decompression |
Each layer is encoded as x_y_blur_spread_opacity_hex_inset_visible using base62 for numeric fields. Layers are joined with |. The resulting string is URL-safe without additional encoding.
| Function | Signature | Description |
|---|---|---|
generatePalette |
(seed: Shadow) => PaletteEntry[] |
Generate 6 harmonized shadow variations |
paletteShadowCss |
(entry: PaletteEntry) => string |
Convert palette entry to CSS value string |
Six variations: Subtle, Bold, Ethereal, Sharp, Warm, Cool. Each is generated by scaling offset/blur/opacity and shifting color channels using predefined transform rules.
| Function | Signature | Description |
|---|---|---|
highlightCode |
(code: string) => string |
Tokenize and wrap in semantic <span> elements |
A hand-written tokenizer supporting CSS, JavaScript/TypeScript, Dart/Flutter, JSON, and SCSS. Token types: keyword, string, number/hex, property, function, comment, operator, CSS pseudo/directive, type/class. Output is HTML with inline CSS custom property colors (defined in globals.css).
| Export | Type | Description |
|---|---|---|
PRESETS |
Preset[] |
40+ curated presets across 10 categories |
Preset |
{ name, category, shadows } |
Preset data structure |
Categories: Subtle, Elevated, Material, Apple, Soft UI, Glassmorphism, Neumorphism, Dashboard, Colored, Inset. Each preset is defined via a shorthand s() helper that creates a Shadow with default id and visible.
Routes:
/ -> EditorPage (app/page.tsx) - Shadow generator tool (main route)
RootLayout (layout.tsx)
+-- themeScript (inline script prevents flash)
+-- JSON-LD structured data (SoftwareApplication schema)
+-- EditorPage (app/page.tsx) [at /]
+-- useShadowState (hook)
|
+-- Header
| +-- Logo / Title
| +-- Tab Switcher (Editor / Scale / Presets)
| +-- Undo / Redo buttons
| +-- Light Source toggle
| +-- Panel Toggle
| +-- Theme toggle (light/dark)
|
+-- Left Panel (float, z-30)
| +-- ShadowLayerList
| +-- ShadowLayerControls
| +-- Angle/Distance polar widget
| +-- Blur slider
| +-- Spread slider
| +-- Opacity slider
| +-- Color picker (react-colorful)
| +-- Inset toggle
|
+-- Center Canvas (ShadowPreview, z-0)
| +-- Draggable/pannable viewport
| +-- Element renderer (box/circle/button/card)
| +-- Light Source Overlay (when active)
| +-- Material simulation
| +-- Hover/Focus/Active state preview
| +-- Element size and rotation controls
| +-- Split view (dark/light comparison)
| +-- Background preset selector
|
+-- Right Panel (float, z-30)
| +-- ShadowInspector (real-time statistics)
| +-- NaturalLanguageInput
| +-- ShadowMorph
| +-- DepthMeter
| +-- GradientShadow
| +-- ShadowDNA
| +-- FocusRingGenerator
| +-- ShadowPalette
|
+-- Bottom Panel (CodeOutput, float, z-30)
| +-- Format selector (7 formats)
| +-- Syntax-highlighted code display
| +-- Copy to clipboard
|
+-- Mobile Bottom Tabs (z-20)
+-- Layers, Controls, Tools, Code panels (slide-up, z-30)
+-- Presets / Scale quick buttons
| Component | File | Responsibility |
|---|---|---|
ShadowLayerList |
components/controls/ShadowLayerList.tsx |
Render and reorder layers, visibility toggle, duplicate, delete |
ShadowLayerControls |
components/controls/ShadowLayerControls.tsx |
Per-layer property editors |
ShadowPreview |
components/preview/ShadowPreview.tsx |
Live canvas with element rendering, dragging, background |
LightSourceOverlay |
components/preview/LightSourceOverlay.tsx |
Draggable light orb and ray visualization |
CodeOutput |
components/code/CodeOutput.tsx |
Format switcher, code generation, syntax highlighting, copy |
ShadowDNA |
components/code/ShadowDNA.tsx |
DNA encode/decode UI |
NaturalLanguageInput |
components/controls/NaturalLanguageInput.tsx |
NL parser UI with example prompts |
ShadowMorph |
components/controls/ShadowMorph.tsx |
A/B state animation controls |
DepthMeter |
components/controls/DepthMeter.tsx |
Depth slider and apply button |
GradientShadow |
components/controls/GradientShadow.tsx |
Gradient parameter controls |
ShadowInspector |
components/controls/ShadowInspector.tsx |
Real-time statistics display |
FocusRingGenerator |
components/controls/FocusRingGenerator.tsx |
Focus-visible ring CSS generator |
ShadowPalette |
components/controls/ShadowPalette.tsx |
6-variation palette display |
PresetsGallery |
components/controls/PresetsGallery.tsx |
Preset browser with categories |
ShadowScale |
components/scale/ShadowScale.tsx |
Side-by-side elevation visualization |
The export system follows a strategy pattern. Each format is implemented as a pure function with the same signature:
(shadows: Shadow[], ...options) => stringFormats:
| Format | Function | Use Case |
|---|---|---|
| CSS | toCss() |
Standard web development |
| Tailwind | toTailwind() |
Tailwind CSS projects |
| Tailwind Config | toTailwindConfig() |
Tailwind theme customization |
| SCSS | toScss() |
SCSS-based projects |
| CSS Variable | toCssVar() |
Design system tokens |
| JavaScript | toJs() |
React inline styles |
| Flutter | toFlutter() |
Flutter/Dart mobile apps |
The getFormatCode() dispatch function selects the appropriate generator based on the ExportFormat enum. All generated code is then passed through the syntax highlighter for display.
Layerbox has a single route:
/- The shadow generator tool with canvas, controls, and code output
Mobile detection is handled by the useMobile() hook in app/page.tsx which checks window.innerWidth < 1024.
- Three floating panels overlaid on the canvas:
- Left panel (270px): Layer list + per-layer controls
- Right panel (270px): Tools (inspector, NL input, morph, depth, gradient, DNA, focus ring, palette)
- Bottom panel: Code output with format switching (CSS, Tailwind, SCSS, JS, Flutter)
- Canvas is fully interactive with drag-to-pan, double-click to reset
- All toolbar overlays (material, shape, interaction state, background selector, size/rotation) centered horizontally above the canvas
- Panel toggle button in the header hides all panels for distraction-free full-canvas view
- Side panels replaced with a bottom tab bar containing four tabs:
- Layers: Layer list with drag-to-reorder, visibility toggle, duplicate, delete
- Controls: Per-layer property editors (angle/distance, blur, spread, opacity, color, inset)
- Tools: Full right-panel tool suite in a scrollable sheet
- Code: Syntax-highlighted code output with format switching and copy
- Each tab opens a slide-up bottom sheet overlay (max 55vh) above the tab bar
- Tap the active tab again or the close button to dismiss the sheet
- Tab bar stays visible while a panel is open
- Header buttons are compacted (smaller icons, no tab switcher)
- Presets and Scale pages are accessible via quick-access buttons next to the tab bar
- The page uses
100dvh(dynamic viewport height) withoverflow: hiddento prevent browser chrome scroll flicker - Canvas toolbars use
overflow-x: autowith hidden scrollbar for horizontal scrolling
- CSS:
overflow: hiddenandoverscroll-behavior: noneonhtml/bodyto lock the viewport - Mobile detection:
useMobile()hook checkswindow.innerWidth < 1024 - Floating panels use
pointer-events: auto/pointer-events: noneto handle interaction layering - The code panel supports format switching between CSS, Tailwind, SCSS, JS, and Flutter with syntax highlighting
- Node.js 18+ (LTS recommended)
- npm (ships with Node.js)
git clone https://github.com/Appaxaap/Layerbox.git
cd Layerbox
npm install
npm run devThe development server starts at http://localhost:3000.
| Command | Description |
|---|---|
npm run dev |
Start Next.js development server with hot module replacement |
npm run build |
Create optimized production build |
npm run start |
Start production server (run build first) |
npm run lint |
Run ESLint across the project |
- TypeScript with strict mode enabled
- React functional components with hooks (no class components)
- Tailwind CSS v4 for styling - use utility classes directly in JSX
- CSS custom properties defined in
globals.cssfor theming (light/dark) - Lucide React for all icons
- Custom hooks prefixed with
useand placed inhooks/ - Pure utility functions placed in
lib/ - No third-party state management -
useShadowStatehandles all state
The application supports light and dark themes. Theme is stored in localStorage under the key sg-theme. An inline script in layout.tsx applies the theme class before the first paint to prevent flash.
CSS custom properties for theme colors are defined in globals.css. The application uses a consistent set of tokens across both themes:
:root {
--bg: #0b1414; /* Page background */
--surface: #111c1c; /* Card, panel */
--surface-raised: #172020; /* Hovered surface */
--surface-code: #0b1313; /* Code block */
--border: rgba(255, 255, 255, 0.07); /* Default border */
--border-hover: rgba(255, 255, 255, 0.13); /* Hover border */
--text: #bdc1bb; /* Primary text */
--text-muted: #6e8a85; /* Secondary text */
--text-faint: #364d4d; /* Disabled text */
--accent: #5e9e88; /* Primary action */
--accent-hover: #4e8e78; /* Accent hover */
--destructive: #c96060; /* Error states */
}
:root.light {
--bg: #eef2f2;
--surface: #ffffff;
--surface-raised: #f0f5f5;
--surface-code: #f5f7f7;
--border: rgba(0, 0, 0, 0.08);
--border-hover: rgba(0, 0, 0, 0.14);
--text: #0f2020;
--text-muted: #4a6868;
--text-faint: #7a9898;
--accent: #3d8a72;
--accent-hover: #2e7a62;
--destructive: #b04040;
}Always run npm run build before committing to catch TypeScript errors and Turbopack compilation issues. The project uses Next.js 16 with Turbopack for development and Turbopack for production builds.
app/
globals.css - Global styles, CSS custom properties, theme variables, animations
layout.tsx - Root layout: metadata, JSON-LD, font loading, inline theme script
page.tsx - Shadow editor tool (canvas, controls, code output, mobile tabs)
(blog section removed)
components/
code/
CodeOutput.tsx - Code export panel: format switching, syntax highlighting, clipboard copy
ShadowDNA.tsx - Shadow DNA encode/decode panel
controls/
DepthMeter.tsx - Depth-to-multi-layer-shadow generator
FocusRingGenerator.tsx - WCAG-compliant focus-visible ring CSS generator
GradientShadow.tsx - Multi-layer gradient falloff shadow generator
NaturalLanguageInput.tsx - Plain English to shadow layer parser
PresetsGallery.tsx - Preset browser with category navigation and mini-previews
ShadowInspector.tsx - Real-time shadow statistics panel
ShadowLayerControls.tsx - Per-layer property controls (angle, blur, spread, opacity, color, inset)
ShadowLayerList.tsx - Layer list with drag-to-reorder, visibility, duplication, deletion
ShadowMorph.tsx - A to B shadow transition with animation controls
ShadowPalette.tsx - Six harmonized variation generator
preview/
LightSourceOverlay.tsx - Draggable light orb on the preview canvas
ShadowPreview.tsx - Live preview surface with element rendering and canvas controls
scale/
ShadowScale.tsx - Side-by-side elevation visualization page
hooks/
useShadowState.ts - Central state management with undo/redo, URL sync, light source
lib/
depthMeter.ts - Depth-to-multi-layer-shadow algorithm
exportFormats.ts - All export format generators (CSS, TW, SCSS, JS, Flutter)
gradientShadow.ts - Gradient shadow parameter types and generator
lightSource.ts - Light position to shadow offset calculation
materials.ts - Material definitions and color modifiers
naturalLanguage.ts - Tokenizer, parser, and generator for NL input
presets.ts - 40+ curated preset definitions across categories
shadowDna.ts - Base62 encode/decode for compact sharing
shadowPalette.ts - Palette generation (Subtle, Bold, Ethereal, Sharp, Warm, Cool)
shadowUtils.ts - Core utilities: CSS string gen, hex/rgba conversion, URL encode/decode
syntaxHighlight.ts - Custom tokenizer for syntax-highlighted code output
types.ts - TypeScript type definitions
Contributions are welcome. The project follows a standard fork-and-PR workflow.
- Fork the repository
- Create a feature branch:
git checkout -b feat/my-feature - Make your changes following the code style guidelines
- Run the linter:
npm run lint - Build to verify:
npm run build - Commit with a conventional commit message:
git commit -m "feat: add my feature" - Push to your fork:
git push origin feat/my-feature - Open a Pull Request
Use conventional commit prefixes:
feat:- New featurefix:- Bug fixdocs:- Documentation changeschore:- Maintenance, tooling, dependenciesrefactor:- Code restructuring without behavior changestyle:- Code formatting (not CSS styling)
- Keep changes focused - avoid refactoring unrelated code
- Maintain the existing code style: TypeScript, functional components, CSS custom properties for theming
- Test your changes by running
npm run buildand visually verifying in the browser - For bug reports or feature ideas, open a GitHub Issue
Distributed under the MIT License. See LICENSE for more information.