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 - Edit
skin.jsonwith your info - Edit
theme.css— set your palette in:root, style elements withvar() - Drop art in
assets/, reference asurl('./assets/file.ext') - 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)
| Variable | Purpose | Default |
|---|---|---|
--t-foreground | Main text | #e0e0e8 |
--t-background | Terminal background | #0a0a0f |
--t-cursor | Cursor color | #d4a036 |
--t-cursor-accent | Cursor text when selected | #0a0a0f |
--t-selection | Selection highlight | rgba(212,160,54,0.25) |
--t-black | ANSI 0 | #1a1a2e |
--t-red | ANSI 1 | #d43636 |
--t-green | ANSI 2 | #36d480 |
--t-yellow | ANSI 3 | #d4a036 |
--t-blue | ANSI 4 | #3678d4 |
--t-magenta | ANSI 5 | #a036d4 |
--t-cyan | ANSI 6 | #36b5d4 |
--t-white | ANSI 7 | #e0e0e8 |
--t-bright-black | ANSI 8 | #3a3a52 |
--t-bright-red | ANSI 9 | #ff5555 |
--t-bright-green | ANSI 10 | #50fa7b |
--t-bright-yellow | ANSI 11 | #f1c232 |
--t-bright-blue | ANSI 12 | #6299e6 |
--t-bright-magenta | ANSI 13 | #c678dd |
--t-bright-cyan | ANSI 14 | #56d4ef |
--t-bright-white | ANSI 15 | #ffffff |
Chrome Colors (6 vars)
| Variable | Purpose | Default |
|---|---|---|
--c-chrome-bg | Panel backgrounds | #0a0a0f |
--c-chrome-text | UI text | #9898a8 |
--c-chrome-border | Borders, dividers | #1a1a2e |
--c-chrome-accent | Highlights, active | #d4a036 |
--c-chrome-dim | Muted text | #606070 |
--c-chrome-hover | Hover backgrounds | #1e1e32 |
Effects (6 vars)
| Variable | Type | Purpose | Default |
|---|---|---|---|
--effect-scanlines | 0 or 1 | Scanline overlay | 0 |
--effect-glow | 0 or 1 | Inner glow | 0 |
--effect-crt | 0 or 1 | CRT curvature | 0 |
--scanline-opacity | 0-1 | Scanline intensity | 0.04 |
--glow-intensity | pixels | Glow blur | 12px |
--c-glow | color | Glow color | rgba(212,160,54,0.15) |
Typography & Layout
| Variable | Default |
|---|---|
--font-terminal | 'SF Mono', monospace |
--font-chrome | 'Inter', sans-serif |
--font-size | 14px |
--radius | 4px |
Targetable Elements
Layout
| Class | What |
|---|---|
.moltamp-shell | Root container |
.moltamp-titlebar | Top title bar |
.moltamp-vibes | Top banner — your canvas |
.moltamp-panel-left | Left panel (Intel) |
.moltamp-panel-right | Right panel (Signal) |
.moltamp-panel-bottom | Bottom bar (Telemetry) |
.moltamp-statusbar | Status bar |
Terminal
| Class | What |
|---|---|
.moltamp-terminal | Terminal container |
.moltamp-message-user | User messages |
.moltamp-message-assistant | Assistant messages |
.moltamp-tool-call | Tool call blocks |
.moltamp-thinking | Thinking blocks |
.moltamp-code-block | Code 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
| Value | Meaning | Use for |
|---|---|---|
data-activity="idle" | No output | Dim, calm |
data-activity="low" | Some output | Moderate |
data-activity="high" | Streaming | Bright, intense |
Shell State
| Value | Meaning |
|---|---|
idle | Waiting for input |
thinking | Claude is reasoning |
streaming | Outputting text |
tool-use | Calling a tool |
permission | Waiting for permission |
error | Something broke |
Live CSS Properties
Set on .moltamp-shell for data-driven visuals:
| Property | Description |
|---|---|
--data-context-pct | Context window used % |
--data-cost-cents | Session cost in cents |
--data-tokens-in | Input tokens (thousands) |
--data-tokens-out | Output tokens (thousands) |
--data-rate-5h | 5-hour rate limit % |
--data-agents | Active subagent count |
--data-git-changed | Changed 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.
Preflight (Auto-Fixes)
MOLTamp applies these overrides after your skin CSS loads. They protect users from common mistakes — especially in AI-generated skins.
| What | Override | Why |
|---|---|---|
.moltamp-vibes background | background: transparent !important | Vibes visuals come from GIF widget slots |
All ::before / ::after | pointer-events: none !important | Pseudo-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
backgroundorbackground-imageon.moltamp-vibes(use GIF widget slots) - Every
::before/::afterhaspointer-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