Sizing
All interactive elements: 22px height
One size only — no variants (sm, lg, etc.)
Icon-only buttons: 22×22px square
Border Radius
All elements: 0 (sharp corners)
No rounded corners anywhere
Icons - General
All icons are monochrome (use currentColor)
No colored icons, no emoji
Size: 12-14px depending on context
Effects: single icon stars — no
individual icons per effect
Post-Processors: single icon
sliders — no individual icons per PP
Icons - Colors
Primary #e0e0e0 — active, selected, hovered
Secondary #888888 — default state, inactive
Muted #555555 — decorative, background icons
Accent #4ecdc4 — section headers, active tabs
Icons - When to Use
Primary → icon buttons on hover, active toggles, selected items
Secondary → icon buttons default, inline icons, chevrons
Muted → grip handles, disabled icons, subtle decorations
Accent → section icons (Transform, Fill, Effects), active states
Buttons
Primary → main action (Export, Apply, Save)
Default → secondary action (Cancel, Close)
Ghost → tertiary/inline, no border (Add Stop, Reverse)
Outline → icon buttons with visible border (layers +, dropdowns)
Danger → destructive action (Delete, Remove)
Selects (Dropdowns)
Closed state: same as input — bg: --ui-bg, border:
transparent
Hover: border becomes visible --ui-border-hover
Open: border accent --ui-border-focus, arrow rotates
180°
Dropdown: bg: --ui-bg-popup, appears below trigger
Option hover: bg: --ui-bg-hover
Option selected: bg: --accent-dim, text:
--accent
Keyboard nav: Arrow keys move, Enter selects, Escape closes
Modals
Overlay: rgba(0,0,0,0.7) + backdrop-filter: blur(4px)
Container: bg: --bg-panel, border:
--border-section
Border radius: 0 (sharp corners, same as everything)
Shadow: 0 20px 60px rgba(0,0,0,0.5)
Header: title left, close button (X) right
Close: Escape key, click overlay, click X button
Animation: fade in + translateY(20px) → 0
Max size: 90vw width, 85vh height, scrollable body
Inputs
Default: bg: --ui-bg, border: transparent
Hover: border: --ui-border-hover
Focus: border: --ui-border-focus (accent)
Placeholder: color: --text-muted
Value: color: --text-primary
Number inputs: no spinners (hidden via CSS)
Radio Groups
Container: inline-flex, height 22px, border:
--border-subtle
Options: side by side, separated by 1px border
Default option: bg: --ui-bg, color:
--text-secondary
Hover: bg: --ui-bg-hover, color:
--text-primary
Selected: bg: --accent-dim, color:
--accent
Usage: mutually exclusive options (Fill type, Blend mode)
Colors
Brand Primary:
#00aaff
Danger/Error:
#ff4466
Accent (panels):
#4ecdc4
Typography - Font
Font family: System font
-apple-system, 'Segoe UI', Roboto
Base size: 11px — all UI elements
Sample Text 11px
Small text: 10px — hints, secondary info
Sample Text 10px
Section headers: 11px uppercase
Section Header
Typography - Text Colors
Primary #e0e0e0 — values, active labels
Normal Bold
Secondary #888888 — labels, descriptions
Normal Bold
Muted #555555 — placeholders, hints
Normal Bold
Disabled #444444 — disabled elements
Normal Bold
Never use pure white (#ffffff) — maximum brightness is #e0e0e0
Typography - When to Use
Primary → input values, selected items, headings, button text
Secondary → labels next to inputs, descriptions, inactive tabs
Muted → placeholders, hints, timestamps, tertiary info
Disabled → disabled controls and their labels
Visibility Toggle
Size: 16×16px outer, 6×6px inner dot
Hidden state: transparent bg, hollow circle with
--text-muted border
Visible state: filled with layer color (radial gradient with 3D
highlight)
Hover hidden: border becomes --text-primary
Hover visible: brightness boost (filter: brightness 1.2)
Usage: layers list, effects list, any toggleable visibility
Drag Handle
Icon:
grip-vertical at 12px
Width: 16px container
Default: opacity 0.5, color --text-muted
Hover (row): opacity 1
Cursor: grab → grabbing when dragging
Position: typically between color bar and visibility toggle
Scrubber
Position: right side of number input, inside border
Width: 20px, separated by subtle left border
Thumb: 2×12px vertical bar
Default: thumb --text-muted
Hover: thumb --text-secondary
Active: thumb --accent
Cursor: ew-resize (horizontal drag)
Property Row
Height: 26px (--row-height)
Layout: flex with 8px gap, padding 0 8px
Label: 70px fixed width, --text-secondary, 11px
Control: flex: 1, uses remaining space
Hover: bg: --bg-hover
Slider value: 28px fixed width, right-aligned,
--accent color
Collapsible Section
Header height: 28px (--section-header-height)
Header bg: subtle gradient (bg-section with 4% white tint)
Icon: 12px, --text-secondary, 16px width
Title: 11px, weight 500, --text-primary
Chevron: right when closed, down when open, 12px, muted color
Badge: optional count (bg: --accent-dim, text:
--accent)
Content: hidden by default, padding 2px 0 to 4px 0
Layer Item
Height: 32px
Layout: color bar → drag handle → visibility → icon → name →
badges
Color bar: 4px wide, full height, layer color
Icon: 14px, --text-secondary
Name: 11px, ellipsis overflow
States: hover (bg-hover), selected (bg-selected), hidden (opacity
0.5)
Drag states: box-shadow inset lines (accent) for drop targets
Effect Item
Header: same height as prop-row, clickable to expand
Layout: visibility toggle → name → chevron
Content: bg rgba(0,0,0,0.15), padding 4px 0
Visibility color: uses --accent instead of layer
color
Hidden effect: opacity 0.5 on entire item
Color Picker
Trigger: 20×20px square, current color as bg
Trigger border: --border-section, hover:
--accent
Popup: 220px wide, bg: --bg-panel
Gradient area: 140px tall, saturation/value picker
Hue slider: 14px tall, rainbow gradient
Preview: 32×22px split (new color / old color)
Swatches: 18×18px preset colors, scale on hover
Mini Dial
Size: 20×20px circular
Border: 1px --border-section, hover:
--accent
Marker: 2×7px, rotates from center
Active: accent border + 2px glow ring (--accent-dim)
Cursor: grab → grabbing when dragging
Paired with: 60px wide number input
Sliders
Height: 16px track, takes flex: 1
Track: bg: --ui-bg, border:
--border-subtle
Fill: --accent color, height 100%
Thumb: 3px wide, 100% height, --text-primary
Hover/Active thumb: white
Value display: 28px width, right-aligned,
--accent color
Primary:
Export
Apply
Save
Default:
Cancel
Close
Ghost:
Add Stop
Reverse
Outline:
Add
Danger:
Delete
Remove
Disabled:
Disabled Primary
Disabled Default
With Icons:
Open
Export
File
Icon Only:
Test Modal:
Open Sample Modal
Functional:
Select option...
Option 1
Option 2
Option 3
A longer option text
With icons:
Choose effect...
Fire Effect
Static Glow
Plasma Fill
Selected:
Option 2
Option 1
Option 2
Option 3
Click to open dropdown. Click option to select. Click outside to close.
Visibility Toggle
Circular toggle used to show/hide layers and effects. Uses layer color when visible.
Hidden:
Empty circle, border: muted
Visible:
Filled with layer color gradient
Specs: 16×16px, inner dot: 6×6px, border: 1.5px
Hidden: transparent bg, border --text-muted
Visible: radial gradient from light to dark layer color, subtle 3D
effect
Drag Handle
Grip icon for reordering layers via drag & drop.
Default:
opacity: 0.5, color: muted
Hover (visible):
opacity: 1, cursor: grab
Specs: 16px width, icon: 12px
Behavior: hidden by default, shows on row hover
Cursor: grab → grabbing when dragging
Scrubber
Draggable area inside number inputs for quick value adjustment.
With scrubber:
Drag the right edge ↔
Specs: 20px wide, thumb: 2×12px
Default: thumb color: --text-muted
Hover: thumb: --text-secondary
Active: thumb: --accent
Cursor: ew-resize
Property Row
Standard layout for label + control pairs in panels.
Height: 26px (var(--row-height))
Label: 70px fixed, --text-secondary, 11px
Padding: 0 8px horizontal
Hover: bg: --bg-hover
Collapsible Section
Expandable section with header, icon, title and chevron.
Header: 28px, gradient bg, clickable
Icon: 12px, --text-secondary
Chevron: right when closed, down when open
Badge: optional count (e.g., "3FX")
Layer Item
Row in layers list with color bar, drag handle, visibility, icon, name, badges.
Height: 32px
Color bar: 4px width, full height, layer color
States: default, hover (bg-hover), selected (bg-selected), hidden
(opacity: 0.5)
Drag: drag-over-top/bottom shows accent line
Effect Item
Collapsible effect row inside an element's Effects section.
Header: same as prop-row, clickable to expand
Content: bg: rgba(0,0,0,0.15), padding: 4px 0
Hidden: opacity: 0.5 when effect disabled
Color Picker
Full color picker with gradient area, hue slider, preview, hex input, and swatches.
Trigger:
20×20px, click to open popup
Popup: 220px wide, bg: --bg-panel, padding: 10px
Gradient: 140px tall, SV picker with hue background
Hue slider: 14px tall, rainbow gradient
Preview: 32×22px split (new/old), shows color change
Hex input: 7 chars max, uppercase
Swatches: 12 presets, 18×18px each
Source of truth: createColorPickerHTML() in
UIComponents.ts
Used by PropertiesPanel. Gradient modal has static HTML copy (must be kept in sync).
Mini Dial
Circular dial for rotation and angle values.
Size: 20×20px circular
Border: --border-section, hover: accent
Marker: 2×7px, rotates from center
Active: accent border + glow ring
Angle Dial (Large)
Large circular dial for gradient angle control. Used in Gradient Editor modal.
Size: 40×40px circular
Background: rgba(0,0,0,0.3)
Border: 1px rgba(255,255,255,0.1), hover: accent
Marker: 2×14px, accent color, rotates from center bottom
Center Picker
XY position picker for radial/conic gradient center point.
Size: 60×60px
Background: rgba(0,0,0,0.3)
Border: gradient border (accent)
Crosshairs: 1px, rgba(255,255,255,0.2)
Dot: 8×8px, accent color, draggable
Gradient Presets
Preset gradient swatches for quick selection in Gradient Editor.
Grid: 6 columns, gap: 10px
Swatch: 32×32px, border-radius: 4px
Label: 9px, text-muted, centered
Hover: subtle scale transform
Section Card
Card container with label, used to group related controls in modals.
Selected Stop
Opacity: 100%
Position: 50%
Background: rgba(255,255,255,0.03)
Border: 1px rgba(255,255,255,0.06), radius: 10px
Padding: 12px 14px
Label: 10px uppercase, #666, letter-spacing: 0.08em