Creator guide · 3 of 3

Design a VibeFuse styling pack — theme.json, orb.json, and shell effects

A styling pack reskins the whole VibeFuse desktop shell without touching agent logic: background layers, panels, accent, text, strokes, the terminal palette, canvas particles, border and overlay effects, and the voice-dock orb. It is three JSON files in a folder under C:\vibefuse\styling. This guide builds a complete pack called Midnight Ember, renders it live below with the same engine the marketplace uses, and takes it through publish.

3 JSON files CSS custom properties 15 particle presets Orb style + motion Free or paid

What a pack controls

theme.json
Color tokens, terminal ANSI palette, shell particles, border / overlay effects, optional CSS
orb.json
Voice-dock orb colors (style) and motion (animation)
manifest.json
Identity, swatches for the catalog card, default accent
Applies to
Menubar, sidebar, canvas, session tabs, settings, widget chrome, voice dock

Users pick a pack in Settings → Appearance → Styling packs, next to the nine built-in themes. Choosing a built-in theme turns the pack off; choosing the pack turns it back on. Marketplace saves sync into the styling folder on next launch.

Settings → Appearance: built-in themes, styling packs, accent

Dark Snow — a shipped pack, tokens from its theme.json

Prerequisites

  • VibeFuse for Windows signed in with your VF- key.
  • A text editor and a color tool you like. Hex and rgba() are all you need.
  • A direction in one sentence (“deep navy, ember accents, warm orb”). Packs with a point of view sell; “default but blue” does not.
  • To sell (optional): seller profile + Stripe Connect.
Fastest start: save Dark Snow or Jarvis-Pro from the marketplace, copy its folder from C:\vibefuse\styling, rename it, change the id, and edit colors from there.

Package anatomy

All three files are required at publish time. The folder name becomes the local package slug (the marketplace prefixes it with style-).

RuleDetail
Allowed file typesjson, css, svg, md, txt (html/js are accepted by the uploader but the shell reads JSON only)
Size limits750 KB per file · ~2.5 MB per package
ImagesNot part of the package. Card / banner / screenshots are uploaded on the listing page.

Step 1 — manifest.json

manifest.json json
{
  "id": "com.yourname.styling.midnight-ember",
  "name": "Midnight Ember",
  "version": "1.0.0",
  "description": "Deep navy workspace with ember-orange accents, drifting embers on the canvas, a soft glow border, and a warm frosted orb.",
  "author": "Your Name",
  "license": "MIT",
  "icon": "palette",
  "category": "styling",
  "kind": "marketplace",
  "entry": "theme.json",
  "tags": ["appearance", "orb", "dark", "warm"],
  "swatches": ["#070a12", "#111827", "#ff7a3d"],
  "defaultAccent": "#ff7a3d",
  "light": false
}
FieldRequiredWhat it does
idYesUnique, reverse-DNS. Convention: com.yourname.styling.<slug>. 3–128 chars of letters, numbers, . _ -. Never change after launch.
nameYesShown on the Appearance card, catalog, and listing.
versionNoSemver, default 1.0.0. Bump per release.
descriptionNoOne or two sentences. Appears on the Appearance card and catalog.
iconNoDefault palette.
entryNoDefault theme.json; the file must exist.
swatchesNo3–5 hex colors shown on cards and the listing hero. Pick background, surface, accent.
defaultAccentNoFallback accent when --accent is missing from tokens.
lightNotrue for light-background packs. Flags the pack as a light theme in the catalog.
category / kindNoNormalized to styling / marketplace on publish.

Step 2 — theme.json: tokens

Tokens are CSS custom properties applied to the shell root while the pack is active. Every built-in surface reads from these names, so a consistent set here restyles everything at once. The full example:

theme.json json
{
  "defaultAccent": "#ff7a3d",
  "light": false,
  "tokens": {
    "--bg-0": "#070a12",
    "--bg-1": "#0b1020",
    "--bg-2": "#111827",
    "--surface": "rgba(14, 20, 36, 0.72)",
    "--surface-strong": "rgba(9, 13, 24, 0.94)",
    "--panel": "rgba(14, 20, 36, 0.7)",
    "--panel-strong": "rgba(8, 11, 20, 0.9)",
    "--chrome-bg": "rgba(8, 11, 20, 0.88)",
    "--overlay-bg": "rgba(5, 7, 14, 0.68)",
    "--input-bg": "rgba(255, 122, 61, 0.05)",

    "--accent": "#ff7a3d",
    "--accent-2": "#ffa46b",
    "--accent-deep": "#b8451a",
    "--accent-rgb": "255, 122, 61",
    "--gold": "#f2b866",
    "--gold-rgb": "242, 184, 102",
    "--purple": "#6b7bd6",
    "--violet": "#8b7bd6",

    "--text": "#f4f1ec",
    "--text-dim": "#a8a49c",
    "--text-faint": "#6b6862",

    "--stroke": "rgba(255, 122, 61, 0.14)",
    "--stroke-strong": "rgba(255, 122, 61, 0.32)",
    "--glow": "rgba(255, 122, 61, 0.22)",
    "--shadow": "0 22px 60px rgba(0, 0, 0, 0.6)",

    "--ambient-a": "#2a1a12",
    "--ambient-b": "#070a12",
    "--ambient-opacity": "0.18",
    "--ambient-vignette": "rgba(0, 0, 0, 0.7)",

    "--ok": "#7fe2a2",
    "--warn": "#f2b866",
    "--danger": "#ff6b7a",
    "--danger-rgb": "255, 107, 122",

    "--orb-spin": "1.05",
    "--orb-breathe": "2.6",
    "--orb-ring-ms": "2.6s"
  },
  "terminal": {
    "background": "#0b1020",
    "foreground": "#f4f1ec",
    "cursor": "#ff7a3d",
    "cursorAccent": "#070a12",
    "selectionBackground": "rgba(255, 122, 61, 0.3)",
    "black": "#070a12",
    "red": "#ff6b7a",
    "green": "#7fe2a2",
    "yellow": "#f2b866",
    "blue": "#6b9bd6",
    "magenta": "#c58bd6",
    "cyan": "#7ad0d6",
    "white": "#f4f1ec"
  },
  "shell": {
    "particles": {
      "canvas": { "preset": "embers", "count": 26, "speed": 0.8, "size": 1.3, "opacity": 0.55, "direction": "up", "color": "#ff9a5c" },
      "sidebar": "none",
      "stage": "none"
    },
    "effects": {
      "border": "glow",
      "overlay": "film-grain"
    },
    "customCss": ".widget-window { box-shadow: 0 0 0 1px rgba(255,122,61,0.18), 0 18px 48px rgba(0,0,0,0.55); }"
  }
}

Token reference

TokenControlsTip
--bg-0 --bg-1 --bg-2Background layers: window base, canvas, elevated regionsThree steps of the same hue, each 4–8% lighter
--surface --surface-strongWidget bodies, cards (translucent → opaque)Use rgba() at 0.7 / 0.94 so particles show through
--panel --panel-strong --chrome-bgSidebar, menubar, settings panels, widget title barsSlightly darker than surface
--overlay-bg --input-bgModal backdrops, text inputsInput tinted with accent at 5% alpha reads as “themed”
--accent --accent-2 --accent-deep --accent-rgbButtons, focus rings, active tabs, links; lighter and darker variants; r, g, b for alpha mathKeep --accent-rgb in sync with --accent
--gold --gold-rgb --purple --violetSecondary highlights used by badges, ranks, and some widgetsCan equal the accent for a monochrome pack
--text --text-dim --text-faintPrimary, secondary, disabled textCheck contrast on --surface: aim ≥ 7:1 for --text
--stroke --stroke-strongBorders and dividersAccent-tinted at 14% / 32% alpha is the house style
--glow --shadowFocus glow, elevated shadowsAccent at ~22% alpha for glow
--ambient-a --ambient-b --ambient-opacity --ambient-vignetteSlow ambient gradient behind the canvas and its edge vignetteOpacity 0.12–0.2; more is distracting
--ok --warn --danger --danger-rgbStatus colorsKeep green/amber/red recognizable
--orb-spin --orb-breathe --orb-ring-msOrb motion defaults when orb.json omits themUsually mirrored in orb.json → animation

Unknown tokens are passed through, so you may add your own (--my-pack-stripe) and reference them from shell.customCss. The marketplace preview reads --bg-*, --surface*, --accent*, --text*, --stroke*, --gold, and --panel to paint its stages.

Step 3 — Terminal palette

The terminal object themes every PTY widget (Terminal, Claude, Codex, Gemini, Cursor, Qwen). Keys follow the xterm.js theme convention.

theme.json → terminal json
"terminal": {
  "background": "#0b1020",
  "foreground": "#f4f1ec",
  "cursor": "#ff7a3d",
  "cursorAccent": "#070a12",
  "selectionBackground": "rgba(255, 122, 61, 0.3)",
  "black": "#070a12",   "red": "#ff6b7a",     "green": "#7fe2a2",  "yellow": "#f2b866",
  "blue": "#6b9bd6",    "magenta": "#c58bd6", "cyan": "#7ad0d6",   "white": "#f4f1ec"
}
  • Match background to --bg-1 so terminals sit flush with the canvas.
  • Keep the eight ANSI colors distinguishable — agents print a lot of green/yellow/red diffs.
  • brightBlackbrightWhite are optional; omit them to derive from the base eight.

Step 4 — Shell effects & particles

The shell object adds motion and atmosphere. Everything here is optional — a pack can be tokens only.

theme.json → shell json
"shell": {
  "particles": {
    "canvas":  { "preset": "embers", "count": 26, "speed": 0.8, "size": 1.3, "opacity": 0.55, "direction": "up", "color": "#ff9a5c" },
    "sidebar": "none",
    "stage":   "snow"
  },
  "effects": {
    "border":  "glow",
    "overlay": "film-grain"
  },
  "customCss": ".widget-window { box-shadow: 0 0 0 1px rgba(255,122,61,0.18), 0 18px 48px rgba(0,0,0,0.55); }",
  "customJs": ""
}

Particles

Three regions — canvas (behind widgets), sidebar (left rail), stage (full window). Each takes a preset name string or an object:

KeyDefaultMeaning
presetsnow · rain · embers · fireflies · dust · stars · bubbles · confetti · petals · matrix · aurora · mist · spark · geometric · lightning · none
count28Number of particles. 16–40 is the comfortable range.
speed1Multiplier. 0.6 is calm, 1.5 is lively.
size1.2Multiplier on the preset's base size.
opacity0.50–1.
directiondowndown, up, left, right.
colorpreset defaultAny CSS color. Leave blank to use the preset's own tint.
enabledtrueSet false to ship a region switched off but configured.

Effects

KeyValuesWhere it shows
borderglow · neon · pulse · rainbow · scan · shimmer · noneAnimated edge on widget windows and the shell frame
overlayfilm-grain · scanlines · crt · vignette-pulse · aurora-veil · noneFull-window atmosphere layer above the canvas

Custom CSS / JS

  • customCss is injected while the pack is active. Target shell classes such as .widget-window; prefer adjusting shadows, radii, and borders over layout.
  • customJs runs in the shell while active. Keep it tiny and idempotent (it may run more than once). Anything that reaches the network or the file system is grounds for removal.
  • Both are listed on the marketplace page as “Custom shell CSS / JS” so buyers know they exist.

Reduce-motion users: VibeFuse's Reduce motion switch slows or stops particles and effects. Your pack should still look complete with them off — that is why tokens do the heavy lifting.

Step 5 — orb.json

The orb is the voice-dock indicator (idle, listening, speaking) and shows in the status bar. style paints it; animation moves it.

orb.json json
{
  "style": {
    "id": "ember-core",
    "label": "Ember Core",
    "preset": "frost",
    "coreTop": "#fff1e6",
    "coreMid": "#ff7a3d",
    "coreDeep": "#5a2410",
    "rim": "#ffa46b",
    "frost": "rgba(255, 200, 160, 0.5)",
    "glyph": "#1a0c06",
    "chrome": "#ffa46b"
  },
  "animation": {
    "id": "ember-drift",
    "label": "Ember Drift",
    "preset": "particles",
    "particleRgb": "255, 154, 92",
    "particleCount": 22,
    "particleSize": 1.4,
    "spin": 1.05,
    "breathe": 2.6,
    "ringMs": 2.6
  }
}
KeyMeaning
style.presetclassic (solid gradient core) or frost (translucent frosted core with a visible rim).
style.coreTop / coreMid / coreDeepThree-stop radial gradient from highlight to depth.
style.rimEdge ring color; usually your accent or accent-2.
style.frostSemi-transparent haze over the core (frost preset).
style.glyphColor of the center glyph / microphone mark — dark on light cores, light on dark cores.
style.chromeTint for the pill and ring chrome around the orb.
animation.presetclassic (breathe + rings) or particles (adds orbiting particles).
animation.particleRgb / particleCount / particleSizeParticle tint as r, g, b, count (8–28), size multiplier.
animation.spin / breathe / ringMsRotation speed multiplier, breathe period in seconds, ring pulse period in seconds.
id / labelFree text shown on the listing (“Ember Core”, “Ember Drift”).

Orb activity pill in the shell status bar

Rendered preview — Midnight Ember, from the JSON above

This block is generated from the three example files on this page by the same code that renders marketplace styling pages. Change a token, republish, and this is what buyers see.

Midnight Ember

Deep navy workspace with ember-orange accents, drifting embers on the canvas, a soft glow border, and a warm frosted orb.

Desktop shell

Workspace preview

Menubar, sidebar, canvas, and voice dock tinted with this pack's tokens.

Terminal
$ vibe pack sync ready
Browser
Synced Ember Core

Live pack demos

See the styling in motion

Auto-playing showcase of orb, particles, shell chrome, widgets, and terminal colors from this pack.

Ember Drift

Particles orb motion

Desktop shell

Menubar, sidebar, canvas, dock

Embers / Canvas

Shell particle field

Glow borders

Edge / focus treatment

Widget style

Canvas chrome using pack tokens

Session tabs

Active / idle session chrome

Controls

Buttons, toggles, inputs

Terminal palette

Agent / terminal colors

Film Grain overlay

Full-shell atmosphere

Compare with live packs: Jarvis-Pro (violet, frost orb, particles) · Dark Snow (monochrome, snow particles) · LSU Death Valley (two-color brand pack).

Design guidance

Color

  • One hue family for backgrounds, one accent, one secondary. That is the whole palette.
  • Derive strokes, glow, input tints from --accent-rgb at low alpha — cohesive for free.
  • Test --text-dim on --panel: it is the most-read color in the app.
  • Light packs: set "light": true, invert the bg ladder (bg-0 lightest), and darken the accent for contrast.

Motion

  • One particle region is plenty. Canvas particles behind translucent widgets is the classic look.
  • Slow beats fast: speed 0.6–0.9, opacity ≤ 0.6, count ≤ 30 for an all-day workspace.
  • Pick either a border effect or an overlay for subtle packs; both for showpieces.
  • Match orb breathe to your ambient feel — 2.4s energetic, 3.2s calm.

Built-in theme cards your pack sits beside in Settings → Appearance

Step 6 — Test locally

  1. 01
    Create the folder

    C:\vibefuse\styling\Midnight-Ember\ with manifest.json, theme.json, orb.json. The folder is listed in Settings → Marketplace → Local styling packs (use Reveal folder).

  2. 02
    Apply it

    Open Settings → Appearance. The pack appears under Styling packs with your swatches. Click it — the shell recolors immediately.

  3. 03
    Load a busy canvas

    Open a Terminal, a Claude or Codex widget, a Browser, and the Vibe Agent. Run a command with colored output. Open Settings and a modal. This is what buyers will stare at for hours.

  4. 04
    Check the orb

    Hold to talk or trigger Jarvis — watch idle, listening, and speaking states. Adjust rim / frost if the glyph disappears.

  5. 05
    Iterate

    Edit the JSON, then re-select the pack (or toggle to a built-in theme and back) to reload tokens. Fix contrast before you touch particles.

  6. 06
    Test Reduce motion

    Toggle it in Appearance. Tokens alone should still read as a finished theme.

Step 7 — Publish from Settings → Marketplace

  1. 01
    Confirm your license is linked

    The tab header shows your seller profile with an active VF- key. Otherwise copy one from Account → Product Keys.

  2. 02
    Find the pack under Local styling packs

    Each folder in C:\vibefuse\styling shows as a card with Not on marketplace, Uploaded · unpublished, or Live on marketplace.

  3. 03
    List on marketplace

    VibeFuse validates id + name, requires theme.json and orb.json, checks file types and sizes, then uploads. Your profile name is stamped as author and the package slug gets a style- prefix.

  4. 04
    Publish

    Click Publish on the card (or Publish all). The listing goes live at /marketplace/styling/style-<slug> and appears under Styling on the marketplace.

Settings → Marketplace → Local styling packs

Styling packs are currently listed free. Pricing for packs follows the same Stripe Connect flow as widgets and skills (80% to you) as the paid rollout expands — see the Sell & earn section for current status.

Step 8 — The listing page

Your pack page is generated from the JSON, so most of the work is already done. It shows:

  • Hero — name, description, version, saves, swatches, orb preview, and a widget window painted with your tokens
  • Pack breakdown — token count, particle regions, effects, orb style / motion, custom CSS / JS flags
  • Workspace preview — menubar, sidebar, canvas with your particles, two widgets, status bar with the mini orb
  • Showcase stages — terminal palette, orb, particles, border effect, overlay, background ladder
  • About + creator card — your description, avatar, follower count

Add a card image and banner in Account → Marketplace if you want a photo-real screenshot on the catalog card; otherwise the swatches carry it.

Step 9 — Ship an update

  • Edit tokens, bump version in manifest.json, then Update listing on the card. Same id → same listing; saves carry over.
  • Users pick up the new files on their next launch sync and see them the next time the pack is applied.
  • Unpublish hides the page; installed copies keep working.

Pre-publish checklist

  • manifest.json has a unique com.yourname.styling.* id, name, description, 3–5 swatches, defaultAccent
  • theme.json defines the full bg / surface / panel ladder, accent set with --accent-rgb, text trio, strokes, status colors
  • terminal.background matches --bg-1; ANSI colors distinguishable
  • orb.json has both style and animation; glyph visible on the core
  • Particles ≤ 30 count, opacity ≤ 0.6; at most one overlay
  • Contrast checked on a busy canvas and with Reduce motion on
  • customJs empty or reviewed line by line; no network, no storage
  • All three files are valid JSON (no trailing commas, no comments)

Troubleshooting

SymptomFix
Pack not in Settings → AppearanceFolder must be directly inside C:\vibefuse\styling with a valid manifest.json. Validate the JSON — a trailing comma silently drops the pack.
“Pack must include theme.json / orb.json”Both files are required at publish. Names are exact and lowercase.
Colors apply but look like the default themeTokens must start with -- and live under "tokens". Check for typos such as --acccent.
Orb is a grey ballorb.json is missing or style keys are misspelled. coreMid falls back to the accent; coreDeep to #222.
Particles do not showRegion key must be canvas, sidebar, or stage; preset must be one of the listed names; enabled not false; Reduce motion off.
Terminal text unreadableSet terminal.foreground and background explicitly; do not rely on defaults when your bg ladder is unusual.
“already listed by another creator”Change your id to your own namespace.

FAQ

Can I ship a light theme?

Yes. Set "light": true in both manifest and theme, make --bg-0 the lightest layer, use dark text tokens, and darken the accent to keep button text readable.

Do packs change my widgets' content?

No. A pack themes the shell chrome around widgets. Marketplace iframe widgets keep their own interior styling; built-in widgets (terminal, settings) follow the tokens.

Can one pack contain multiple themes?

One pack = one theme today. Publish variants as separate packs (Midnight Ember, Midnight Ember Light) and cross-link them in the descriptions.

Can I include a wallpaper image?

Binary files are not packaged. Use CSS gradients via tokens (--ambient-a/b) or a data-URI SVG in customCss.

Will my pack break on VibeFuse updates?

Token names are stable; new surfaces read existing tokens. Only customCss that targets internal class names may need a touch-up — keep it minimal.

Next guides

Related: Settings → Appearance · Styling catalog · Styling pack creator overview