Snip Design Language
May 7, 2026 · View on GitHub
Role: Designer — Color palettes, component patterns, glass effects, and icon specs. This is the source of truth for all visual decisions.
Philosophy
Snip uses a Liquid Glass aesthetic — translucent surfaces with subtle blur, specular highlights, and layered depth. The palette centers on purple as the primary accent, shifting between vibrant purple (dark mode) and softer lavender (light mode) for warmth and personality.
Color Palette
Dark Theme
| Role | Value | Usage |
|---|---|---|
| Accent | #8B5CF6 (Violet 500) | Buttons, active states, focus rings, links |
| Accent hover | #7C3AED (Violet 600) | Button hover, pressed states |
| Accent bg | rgba(139, 92, 246, 0.15) | Active nav items, badges, subtle fills |
| Accent active | rgba(139, 92, 246, 0.7) | Pressed/active toolbar buttons |
| Background primary | rgba(20, 20, 20, 0.75) | Main content area |
| Background secondary | rgba(18, 18, 18, 0.8) | Sidebar |
| Background elevated | rgba(40, 40, 40, 0.7) | Cards, dropdowns, inputs |
| Text primary | #e0e0e0 | Body text |
| Text bright | #ffffff | Headings, active labels |
| Text muted | #555 | Placeholders, secondary info |
| Toast processing | #C4B5FD (Violet 300) | Loading/processing indicators |
Light Theme
| Role | Value | Usage |
|---|---|---|
| Accent | #7C3AED (Violet 600) | Buttons, active states, focus rings |
| Accent hover | #6D28D9 (Violet 700) | Button hover, pressed states |
| Accent bg | rgba(124, 58, 237, 0.08) | Active nav items, badges, subtle fills |
| Background body | rgba(252, 250, 245, 0.9) | Warm cream base |
| Background primary | rgba(255, 253, 250, 0.7) | Main content area (cream-tinted white) |
| Background secondary | rgba(250, 247, 242, 0.8) | Sidebar (warm off-white) |
| Background elevated | rgba(255, 255, 255, 0.75) | Cards, dropdowns |
| Hover | rgba(139, 92, 246, 0.06) | Hover states have a subtle violet tint |
| Text primary | #1a1a1a | Body text |
| Text bright | #000000 | Headings, active labels |
| Toast processing | #7C3AED | Loading/processing indicators |
Shared
| Role | Value |
|---|---|
| Success | #22c55e (dark) / #16a34a (light) |
| Error | #ef4444 (dark) / #dc2626 (light) |
| Error bg | rgba(239, 68, 68, 0.15) (dark) / rgba(220, 38, 38, 0.12) (light) |
| Accent glow | 0 2px 8px rgba(139, 92, 246, 0.3) (dark) / 0 2px 8px rgba(124, 58, 237, 0.3) (light) |
| Font | Plus Jakarta Sans (variable weight 200-800) |
Annotation Shape Palette (SHAPE_COLOR_PALETTE)
Auto-cycled through for new box (rectangle) and arrow annotations so adjacent shapes are visually distinct and individually referenceable. Defined in src/renderer/toolbar.js. Six colors, drawn from the existing tag/segment swatches for consistency:
| Slot | Hex | Name |
|---|---|---|
| 0 | #EF4444 | Red |
| 1 | #3B82F6 | Blue |
| 2 | #22C55E | Green |
| 3 | #EAB308 | Yellow |
| 4 | #7C3AED | Violet |
| 5 | #F97316 | Orange |
Cycles in order, wraps. A manual color picker pick overrides the next shape only, then cycling resumes. Yellow has weak contrast on light/yellow screenshot backgrounds — known palette weakness, accepted because predictable cycling outweighs perfect contrast on every possible source image.
App Icon
| Theme | Background | Scissors | Sparkles |
|---|---|---|---|
| Dark | #0f0a1e → #1a1030 gradient | Blue-indigo gradient (#93c5fd → #6366f1) | Light blue (#93c5fd) |
| Light | Cream → lavender gradient (#FBF5EE → #EDE5F8) | Purple gradient (#A78BFA → #6D28D9) | Violet (#8B5CF6) |
Both icons use a squircle shape (rx="22.5" on a 100x100 viewBox).
Glass Effects (Liquid Glass)
- Blur: 24px
backdrop-filteron all translucent surfaces - Specular highlight: Top edge
inset 0 1px 0 0glow simulates light refraction - Shadows: Multi-layer — outer shadow for depth + inner glow for glass edge
- Borders: Semi-transparent, never fully opaque
Solid Fallback (No Glass)
When the OS or renderer doesn't support backdrop-filter, translucent rgba() backgrounds look broken (washed out, unreadable). A @supports not (backdrop-filter: blur(1px)) block in theme.css swaps all surfaces to opaque equivalents.
| Role | Dark solid | Light solid |
|---|---|---|
| Body | #0a0a0a | #FBF8F2 (cream) |
| Primary | #141414 | #FFFDF9 |
| Secondary | #121212 | #F7F3EC |
| Elevated | #1e1e1e | #FFFFFF |
| Toolbar | #191919 | #FFFDF9 |
The fallback also:
- Sets
--glass-blurto0px - Reduces specular/inner-glow intensity (no blur = no refraction to simulate)
- Slightly increases border opacity for surface separation without blur
- Increases overlay opacity to compensate for missing blur dimming
Design principle: Solid fallback should look intentionally flat and clean, not like a broken glass theme. Think of it as a "matte" variant — same palette, same accent colors, just without translucency.
Component Patterns
Toolbar Buttons (Editor)
All toolbar buttons use a unified color system — no hardcoded colors.
| State | Icon Color | Background | Extra |
|---|---|---|---|
| Default | --text-secondary | transparent | — |
| Hover | --text-primary | --bg-hover-strong | box-shadow: var(--glass-inner-glow) |
| Active tool | white | --accent-active | box-shadow: var(--glass-inner-glow), var(--accent-glow) |
Action buttons (Save, Done, etc.) follow the same default/hover pattern. Tooltips appear below buttons with top: calc(100% + 6px), white text on dark background.
Upscale Button (Editor)
The Upscale button uses .tool-btn styling (same as all other toolbar buttons): transparent background, --text-secondary icon. Single click triggers 2x upscale directly (no dropdown).
Disabled state (.tool-btn.disabled): opacity: 0.4; pointer-events: none. Applied after upscale completes to prevent double-upscale.
Progress overlay (.upscale-progress): same pattern as animation progress — centered fixed panel, 260px wide, glass background, pulsing icon, text label, and accent-colored progress bar (4px track). Stages: "Loading model..." → "Upscaling (2x)..." → "Encoding result...".
Zoom Indicator
Zoom indicator (.zoom-indicator): fixed bottom-right pill (right: 52px to avoid overlapping help button) showing current zoom percentage. Uses --bg-elevated background with glass blur, --text-secondary text, 11px font. Hidden when at default fit-to-viewport zoom with no pan offset; visible otherwise. pointer-events: none so it doesn't interfere with canvas interaction.
Canvas Controls Button
Controls button (.canvas-help-btn): fixed bottom-right pill matching the image-dims / zoom-indicator style — --bg-elevated background, glass blur, --glass-specular border, --text-secondary color, 11px font. Contains a small ? circle SVG icon + "Controls" label. Hover brightens to --text-primary with --glass-specular-strong border.
Clicking opens a Canvas Controls modal (#canvas-guide-backdrop) using the standard .tutorial-backdrop + .tutorial-modal pattern. Contains two sections (Zoom / Pan) with --accent uppercase section headers and .tutorial-kbd + .tutorial-step rows for each shortcut. Dismissed via "Got it" button or backdrop click.
Transcript Panel (Editor)
A slide-in side panel (--bg-elevated background, glass blur, --glass-specular left border) that shows OCR-extracted text. Slides in from the right with a 0.2s ease-out animation.
Header: flex row with "Transcript" title (13px, 700 weight) and close button. Detected languages appear as inline rounded pills (border-radius: 100px) next to the title — --accent text on --accent-bg background, 9px uppercase, max 3 pills. Hidden when empty via :empty { display: none }.
Text area: <pre> with monospace font (SF Mono/Menlo), white-space: pre-wrap, user-selectable. Excessive line breaks (3+) collapsed to double newlines.
Copy button: full-width, --bg-secondary background, --text-primary text, 8px radius. Shows copy icon + "Copy Text" + ⏎ kbd badge. No top border separator.
Fabric.js Selection Controls
Fabric object selection handles (borders, corners) use the theme accent color at canvas init time:
var accent = ToolUtils.getAccentColor(); // reads --accent CSS variable
fabric.FabricObject.ownDefaults.borderColor = accent;
fabric.FabricObject.ownDefaults.cornerColor = accent;
This affects all canvas objects (rectangles, arrows, textboxes, blur images).
Setting Up Your AI Assistant (Inline Overlay)
The setup wizard is an inline overlay (#setup-overlay) inside the home window — position: fixed; inset: 0; z-index: 100. Fully opaque per-theme backgrounds: dark #111113, light #f5f3ef, matching each theme.
Three views (one visible at a time):
-
Steps view — centered header (purple SVG magic wand icon with sparkle accents, title, subtitle) with 3 step cards. Step cards:
--bg-elevatedwith--border-card, 12px radius. Numbered indicators (28px circles): pending (default border), active (--accentborder/bg), done (--successbg with white checkmark). Action areas per step contain buttons, progress bars, or spinner. -
Welcome view — large purple SVG magic wand (64px, filled at 15% opacity,
setup-pop-inanimation: scale 0.5→1 with bounce easing), "Welcome to Snip" title (24px, 700 weight), accent glow button (box-shadow: 0 0 20px rgba(139,92,246,0.4)). -
Failed view — muted SVG magic wand icon (
--text-mutedstroke), "Snip works great without AI too" title, description text, two buttons (primary "Continue without AI" + secondary "Try again").
Sparkle particles (#setup-sparkles): Randomly positioned divs with sparkle-float keyframe (opacity 0 → 0.8 → 0, translateY upward, scale 0.5→1.2). Two shapes: circles (border-radius: 50%) and 4-point stars (clip-path: polygon(...)). Color: var(--accent). Spawned every ~400ms during welcome screen; burst of 30 on transition to welcome.
- Progress bar: 5px track in
--bg-tertiarywith accent gradient fill (linear-gradient(90deg, --accent, --accent-hover)) and subtle purple glow (box-shadow: 0 0 8px rgba(139,92,246,0.3)). - Error state: flex row with
--error-bgbackground, error text in--error, retry button with--errorborder. - Screen transitions:
setup-fade-inkeyframe (opacity 0→1, translateY 10px→0, 0.35s ease).
Settings page (when overlay is not showing):
- Current model card (ready state):
--bg-elevatedwith--border-card, 10px radius. Shows "Active Model" uppercase label, large bold model name, and circular info button. - Info tooltip: Per-theme backgrounds (dark:
rgba(30,30,30,0.95), light:rgba(255,255,255,0.95)). Positioned below card,z-index: 20. Contains a specs table with label column in--text-secondaryand value column in--text-primary.
Buttons
- Primary: Solid accent fill, white text, rounded corners (8px)
- Secondary: Transparent with subtle border, text in dim color
- Icon buttons: 32px square, 6px radius, transparent bg with border
Cards
- Elevated background, 10px radius, 1px border
- Hover: accent-colored border, slight translateY(-2px) lift, card shadow
Tags/Chips
- Pill shape (14px radius), small font (11px), border + transparent bg
- Active state: accent border + accent-bg fill + accent text
Inputs
- Transparent background with subtle border
- Focus: accent-colored border
2GIF Button & Panels
- 2GIF button: Fixed bottom-center, accent background, white bold text, accent glow shadow. Scale(1.05) on hover.
- Preset panel: Fixed bottom-center, 340px wide, glass background with backdrop blur, 14px radius. Contains a 2-column grid of preset buttons + custom prompt section below.
- Preset buttons:
--bg-inputbackground,--border-inputborder, 10px radius. Hover: accent-bg fill with accent border and glow. Each button has an emoji icon + bold label row on top, small description text below. - Custom prompt section: Divider line with "or describe your own" text centered between two lines, then a flex row containing a text input (8px radius,
--bg-inputfill, accent border on focus) + accent-filled go button (34×34px, 8px radius, arrow icon). - Result panel: Same glass panel as preset picker. Contains GIF preview (max 200px, 8px radius) + action buttons row.
- Action buttons: accent-filled for Save GIF/APNG, input-filled for Copy GIF. Standard
--text-secondarycancel link for Done.
Animation Settings (home.css)
The Settings page "Animation" section uses animation-api-key-* CSS classes:
.animation-api-key-row: Flex column layout, 8px gap. Contains the label, input group, status, and help text..animation-api-key-label: 12px font, 500 weight,--text-secondarycolor..animation-api-key-input-group: Flex row with 8px gap for the input field, toggle, and save button..animation-api-key-input: Flex-grow password input,--bg-inputbackground,--border-inputborder, 8px radius. Focus state:--accentborder..animation-api-key-toggle: Eye icon button to show/hide API key..animation-api-key-save: Save button with--accentbackground..animation-api-key-status: 12px status text..savedvariant uses--successcolor..errorvariant uses--errorcolor..animation-api-key-help: 12px help text in--text-dim, contains "Get API Key" link.
MCP Settings Section (home.css)
The Settings page "MCP Server" section (#mcp-section) contains:
- Main toggle row: Status dot (
.status-dot.stopped/.running— colored circle) + label +ai-switchtoggle. When toggled on, the category list and client config expand below. - Category list (
.mcp-category-list, hidden until enabled): Each.mcp-category-rowis a flex row with 8px padding, 8px radius,--bg-hoveron hover. Contains.mcp-category-label(13px, 500 weight,--text-primary, min 120px),.mcp-category-desc(12px,--text-secondary, flex-grows), and a smallai-switch-smtoggle. Four categories: Library Access, Open in Snip, Transcribe, Organize. - Config block (
.mcp-info, shown when enabled): Label text (12px,--text-secondary) above a<pre>code block (.mcp-config-block) using SF Mono 11px,--bg-tertiarybackground,--border-cardborder, 8px radius, padded right 70px to make room for the copy button. An absolute-positioned.mcp-copy-btnin the top-right (8px inset) has--bg-elevatedbackground and changes border to--accenton hover.
Extensions Management Section (home.css)
The Settings page "Extensions" section (#extensions-section) contains:
- Section subtitle: 13px
--text-secondarydescription of sandbox isolation. - Extensions list (
.extensions-list):--bg-elevatedbackground,--border-cardborder, 8px radius. Each installed extension is an.extension-row— flex row, 12px horizontal padding, 10px vertical. Contains.extension-row-name(13px, 500 weight,--text-primary),.extension-row-type(11px pill:--accent-bgbackground,--accenttext, 100px border-radius), a spacer, and.extension-row-remove(remove/trash icon button,opacity: 0until row hover,--error-hovercolor on hover). - Empty state (
.extensions-empty): 13px centered--text-secondarytext ("No user extensions installed.") shown when list is empty. - Actions row (
.extensions-actions): Contains.install-extension-btn— a full-width-ish outlined button with--accentborder,--accenttext, 8px radius. Hover:--accent-bgfill,--accent-glowbox-shadow. Shows a folder icon + "Install Extension from Folder…" label. - Status label (
.extensions-status): 12px text below the install button,opacity: 0normally,opacity: 1when.visible..errorvariant uses--errorcolor.
Shortcut Key Display & Edit Button (home.css)
The Settings page shows keyboard shortcuts with a key display span and, for configurable global shortcuts, a pencil edit button:
Key display (.shortcut-row-key):
| State | Border | Background | Text | Extra |
|---|---|---|---|---|
| Default | --kbd-border | --kbd-bg | --kbd-text | — |
| Recording | --accent | --accent-bg | --accent | Pulsing border animation, text shows "Press key…" (global shortcuts only) |
| Conflict | --error | --error-bg | --error | Error message replaces key text |
| Read-only | --kbd-border | --kbd-bg | --kbd-text | opacity: 0.6, non-interactive (tool + OS shortcuts) |
Edit button (.shortcut-edit-btn):
| State | Border | Background | Color | Extra |
|---|---|---|---|---|
| Default | --border-card | transparent | --text-secondary | Only shown on configurable rows |
| Hover | --accent | --bg-hover | --accent | — |
| Recording | --accent | --accent-bg | --accent | Matches key display recording state |
Search Result Cards (home.css)
Search results use overlay-style cards with hardcoded colors (intentional — overlays sit on top of image content, not app background):
.search-result-card:position: relative,border-radius: 10px,overflow: hidden. Fixed 220px row height..search-result-thumbnail: Fills entire card (width: 100%; height: 100%),object-fit: cover..search-result-info: Absolute-positioned overlay at bottom with gradient (transparent→rgba(0,0,0,0.75))..search-result-name: White text, 12px, 500 weight..search-result-category: Purple pill badge (rgba(139,92,246,0.3)background,#c4b5fdtext)..search-result-score: Match percentage pill (rgba(255,255,255,0.15)background,rgba(255,255,255,0.7)text).
Floating Toast (Main Process)
A small borderless BrowserWindow that appears top-center after copy/save actions and auto-dismisses. Created in ipc-handlers.js via showFloatingToast(), triggered by the show-notification IPC channel.
| Property | Dark | Light |
|---|---|---|
| Background | rgba(20,20,20,0.7) | rgba(255,253,250,0.85) |
| Text | #e0e0e0 | #1a1a1a |
| Checkmark | #8B5CF6 | #7C3AED |
| Border | rgba(255,255,255,0.08) | rgba(124,58,237,0.15) |
| Blur | 24px | 24px |
Animation: fade-in (0.25s ease, translateY -6→0), fade-out (0.3s ease after 1.1s delay). Window is focusable: false, ignoreMouseEvents: true, auto-destroyed after 1.6s. Size: 260×48px.
File Reference
All theme tokens live in src/renderer/theme.css. Component styles reference them via var(--token-name). Never use hardcoded color values in component CSS — always use theme variables.
Shared Utilities (tool-utils.js)
ToolUtils.getAccentColor()— reads--accentfrom computed styles at runtimeToolUtils.hexToRgba(hex, alpha)— converts hex color to rgba string (used by rectangle highlight, segment markers, free-draw eraser)
These replace previously duplicated helper functions across tool files.