Skinning Guide v2.0

Everything you need to build a MOLTamp skin. A skin is a folder with a JSON manifest and a CSS theme. No JavaScript, no build tools.

Quick Start

cp -r ~/Moltamp/skins/_template ~/Moltamp/skins/my-skin
  1. Edit skin.json with your info
  2. Edit theme.css — set your palette in :root, style elements with var()
  3. Drop art in assets/, reference as url('./assets/file.ext')
  4. Open MOLTamp Settings → Skins, select your skin

The Rules

Non-negotiable. The validator enforces them.

1. All colors live in :root

Every color value must be a CSS variable in :root. Never hardcode a color in a selector.

/* WRONG */
.moltamp-panel-left { background: #070b07; }

/* RIGHT */
:root { --skin-panel-bg: #070b07; }
.moltamp-panel-left { background: var(--skin-panel-bg); }

Why: Color overrides inject a :root block on top of your skin. Hardcoded colors can't be reached.

2. Contract variables come first

The 6 chrome and 21 terminal variables are the contract. Override them in :root. Extend with --skin-* prefixed variables.

3. Never hide panels

No display: none on panels. Users toggle visibility in Settings. Style them freely — visibility is the user's choice.

4. No executable content

  • No external URLs (https:, http:)
  • No @import
  • No expression(), javascript:
  • CSS only. Zero JS.

5. Don't hide the permission dialog

These trigger validator warnings: visibility: hidden, opacity: 0, pointer-events: none

6. No backgrounds on .moltamp-vibes

The vibes panel is always transparent. Visual content must come from GIF widget slots in skin.json, not CSS background. MOLTamp strips vibes backgrounds at load time.

7. Pseudo-elements need pointer-events: none

Every ::before and ::after must include pointer-events: none. Without it, they block right-click menus, drag handles, and widget interaction. Auto-fixed at load time, but declare it explicitly.

.moltamp-panel-right::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--skin-overlay);
  pointer-events: none;  /* always include this */
}

8. Assets stay in assets/

  • Reference with url('./assets/filename.ext')
  • Supported: PNG, JPG, WebP, GIF, SVG, AVIF
  • Max 5MB per file, 20MB per skin
  • No nested directories, no path traversal

Skin Format

skins/my-skin/
  skin.json          ← Required: manifest
  theme.css          ← Required: all styles
  assets/            ← Optional: images, GIFs, SVGs

skin.json

{
  "id": "my-skin",
  "name": "My Skin",
  "version": "1.0.0",
  "author": "Your Name",
  "description": "A short description.",
  "engine": "1.0"
}

All fields required. id must match ^[a-zA-Z0-9_-]+$.

Variable Contract

Override these in :root. This is the API between MOLTamp and your skin.

Terminal Colors (21 vars)

VariablePurposeDefault
--t-foregroundMain text#e0e0e8
--t-backgroundTerminal background#0a0a0f
--t-cursorCursor color#d4a036
--t-cursor-accentCursor text when selected#0a0a0f
--t-selectionSelection highlightrgba(212,160,54,0.25)
--t-blackANSI 0#1a1a2e
--t-redANSI 1#d43636
--t-greenANSI 2#36d480
--t-yellowANSI 3#d4a036
--t-blueANSI 4#3678d4
--t-magentaANSI 5#a036d4
--t-cyanANSI 6#36b5d4
--t-whiteANSI 7#e0e0e8
--t-bright-blackANSI 8#3a3a52
--t-bright-redANSI 9#ff5555
--t-bright-greenANSI 10#50fa7b
--t-bright-yellowANSI 11#f1c232
--t-bright-blueANSI 12#6299e6
--t-bright-magentaANSI 13#c678dd
--t-bright-cyanANSI 14#56d4ef
--t-bright-whiteANSI 15#ffffff

Chrome Colors (6 vars)

VariablePurposeDefault
--c-chrome-bgPanel backgrounds#0a0a0f
--c-chrome-textUI text#9898a8
--c-chrome-borderBorders, dividers#1a1a2e
--c-chrome-accentHighlights, active#d4a036
--c-chrome-dimMuted text#606070
--c-chrome-hoverHover backgrounds#1e1e32

Effects (6 vars)

VariableTypePurposeDefault
--effect-scanlines0 or 1Scanline overlay0
--effect-glow0 or 1Inner glow0
--effect-crt0 or 1CRT curvature0
--scanline-opacity0-1Scanline intensity0.04
--glow-intensitypixelsGlow blur12px
--c-glowcolorGlow colorrgba(212,160,54,0.15)

Typography & Layout

VariableDefault
--font-terminal'SF Mono', monospace
--font-chrome'Inter', sans-serif
--font-size14px
--radius4px

Targetable Elements

Layout

ClassWhat
.moltamp-shellRoot container
.moltamp-titlebarTop title bar
.moltamp-vibesTop banner — your canvas
.moltamp-panel-leftLeft panel (Intel)
.moltamp-panel-rightRight panel (Signal)
.moltamp-panel-bottomBottom bar (Telemetry)
.moltamp-statusbarStatus bar

Terminal

ClassWhat
.moltamp-terminalTerminal container
.moltamp-message-userUser messages
.moltamp-message-assistantAssistant messages
.moltamp-tool-callTool call blocks
.moltamp-thinkingThinking blocks
.moltamp-code-blockCode blocks

The Vibes Panel

The .moltamp-vibes div is your hero canvas.

Backgrounds are not allowed on .moltamp-vibes. The vibes panel is always transparent — all visual content (GIFs, images) must come from GIF widget slots defined in skin.json, not from CSS background or background-image. MOLTamp enforces this with an !important override at load time.

// skin.json
{
  "vibes": {
    "slots": [
      { "widgetId": "gif", "gifSrc": "assets/vibes.gif", "gifFit": "cover" }
    ]
  }
}

Use ::before and ::after for overlay effects — these are still allowed:

.moltamp-vibes::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--skin-overlay);
  mix-blend-mode: multiply;
  pointer-events: none;
}

Reactive Data Attributes

Set on .moltamp-shell — changes with Claude's state.

Activity Level

ValueMeaningUse for
data-activity="idle"No outputDim, calm
data-activity="low"Some outputModerate
data-activity="high"StreamingBright, intense

Shell State

ValueMeaning
idleWaiting for input
thinkingClaude is reasoning
streamingOutputting text
tool-useCalling a tool
permissionWaiting for permission
errorSomething broke

Live CSS Properties

Set on .moltamp-shell for data-driven visuals:

PropertyDescription
--data-context-pctContext window used %
--data-cost-centsSession cost in cents
--data-tokens-inInput tokens (thousands)
--data-tokens-outOutput tokens (thousands)
--data-rate-5h5-hour rate limit %
--data-agentsActive subagent count
--data-git-changedChanged file count

Example: Context gauge as pie chart:

.moltamp-context-gauge {
  width: 80px; height: 80px;
  border-radius: 50%;
  background: conic-gradient(
    var(--c-chrome-accent) calc(var(--data-context-pct) * 1%),
    var(--c-chrome-border) 0
  );
}

Reactive Animations

Bind animations to data attributes:

[data-activity="high"] .moltamp-vibes {
  filter: brightness(1.2) saturate(1.1);
  animation: skin-glow 2s ease-in-out infinite;
}

[data-shell-state="thinking"] .moltamp-vibes {
  animation: skin-pulse 1.5s ease-in-out infinite;
}

[data-shell-state="error"] .moltamp-vibes {
  box-shadow: inset 0 0 20px var(--skin-error-color);
}

Prefer transform and opacity for performance. Keep durations under 5s.

Sharing

Export: Settings → Skins → Export — saves as .zip

Import: Settings → Skins → Import — select .zip

Preflight (Auto-Fixes)

MOLTamp applies these overrides after your skin CSS loads. They protect users from common mistakes — especially in AI-generated skins.

WhatOverrideWhy
.moltamp-vibes backgroundbackground: transparent !importantVibes visuals come from GIF widget slots
All ::before / ::afterpointer-events: none !importantPseudo-elements must never block clicks

For AI-generated skins

If using ChatGPT, Claude, or another AI to generate a skin, paste this with your prompt:

Rules: All colors must be CSS variables in :root.
Use --skin-* prefix for custom vars.
Never set background on .moltamp-vibes — use skin.json vibes slots for images.
Every ::before/::after MUST have pointer-events: none.
No external URLs, no @import, no JS.

Pre-Share Checklist

  • All colors defined as variables in :root
  • Zero hardcoded hex/rgb outside :root
  • Contract variables (--c-*, --t-*) overridden
  • Custom variables use --skin-* prefix
  • No background or background-image on .moltamp-vibes (use GIF widget slots)
  • Every ::before/::after has pointer-events: none
  • No external URLs or @import
  • Assets under 5MB each, 20MB total
  • Tested at different panel sizes
  • Right-click context menus work on all panels
  • Permission dialog still visible