Files
EZPPLauncher/THEME_API_V2.md
T
HorizonCode c02b26e8ae feat: polish theme tooling, diagnostics and launcher workflows
Expand the theme editor with multi-select, snapping, context menus, draft
recovery and export validation; add theme backups and trust prompts. Add
in-app diagnostics and rotating log bundle viewing, hardware-accelerated
theme video playback on macOS, and refresh the settings, setup wizard and
theme gallery layouts.
2026-10-29 15:41:33 +01:00

14 KiB
Raw Blame History

EZPPLauncher Theme API 2.0

API 2.0 is a declarative theme format. Instead of shipping a JavaScript bundle that mounts its own UI, a theme describes its background, effects, audio, fonts and freeform layers in theme.json. The launcher renders it, and the built-in advanced editor can create and edit these themes without writing code.

API 1.0 themes continue to work unchanged. Pick the API that fits the theme:

API 1.0 API 2.0
Rendering Svelte bundle (entry) Launcher-rendered
Files theme.json, bundle.js, style.css, assets/ theme.json, assets/
Created with create-ezpplauncher-theme Launcher editor or create-ezpplauncher-theme
Scripts / arbitrary DOM Yes No (data only, optional CSS)
Cross-platform Depends on the bundle Yes

Package layout

A packaged .ezpplauncher-theme file is a zip with this structure:

theme.json
assets/
  background.webm
  layer.png
  music.mp3
  font.woff2
  preview.png        # optional thumbnail

An installed theme lives in:

# Windows
C:\Users\<user>\.ezpplauncher\themes\<folder>\

# macOS / Linux
~/.ezpplauncher/themes/<folder>/

theme.json

{
  "name": "Midnight",
  "version": "1.0.0",
  "apiVersion": "2.0",
  "author": "Your Name",
  "description": "A dark gradient with drifting stars.",
  "preview": "preview.png",
  "background": {
    "type": "gradient",
    "from": "#181825",
    "to": "#3b1d4f",
    "angle": 135,
    "opacity": 1
  },
  "overlay": {
    "color": "#000000",
    "opacity": 0.2,
    "vignette": 0.35
  },
  "effects": {
    "type": "stars",
    "density": 40,
    "speed": 1,
    "color": "#ffd6f2"
  },
  "typography": {
    "body": "Sora Variable",
    "heading": "Bebas Neue"
  },
  "fonts": [
    {
      "family": "My Display Font",
      "src": "display.woff2",
      "weight": "400",
      "style": "normal"
    }
  ],
  "elements": [
    {
      "id": "tagline",
      "type": "text",
      "text": "MIDNIGHT",
      "x": 640,
      "y": 84,
      "width": 300,
      "height": 72,
      "fontFamily": "Bebas Neue",
      "fontSize": 46,
      "fontWeight": 400,
      "color": "#ffffff",
      "align": "right",
      "verticalAlign": "center",
      "letterSpacing": 2
    }
  ],
  "audio": {
    "src": "music.mp3",
    "loop": true
  },
  "accentColor": "#ff006e",
  "css": ""
}

Metadata

Field Type Required Notes
name string yes Display name; also used for the install folder
version string yes Semver, used for update checks
apiVersion string yes Must start with 2 (use "2.0")
author string yes Shown in the theme manager
description string no Shown on the theme card
nsfw bool no Marks the theme as adult content (18+ badge)
preview string no Card thumbnail; the editor generates preview.png
accentColor string no Hex color used for focus rings and active UI states
css string no Extra CSS injected while the theme is active

Background

background.type selects the layer:

{ "type": "color", "color": "#181825", "opacity": 1 }
{ "type": "gradient", "from": "#181825", "to": "#3b1d4f", "angle": 135, "opacity": 1 }
{ "type": "image", "src": "background.png", "fit": "cover", "opacity": 1, "blur": 0 }
{
  "type": "video",
  "src": "background.webm",
  "fit": "cover",
  "opacity": 1,
  "blur": 0,
  "muted": true
}
  • src is relative to the theme's assets/ folder.
  • fit is cover (default) or contain.
  • opacity is clamped to 0–1, blur to 0–40 pixels.
  • Background videos autoplay and loop. They are muted by default; set muted to false to play their audio.
  • Prefer WebM for video backgrounds and video layers. It is supported by the launcher and keeps theme packages much smaller than MP4. MP4, MOV and M4V also work.

Overlay

{ "color": "#000000", "opacity": 0.2, "vignette": 0.35 }

opacity controls the flat dim layer and vignette darkens the edges. Both are clamped to 0–1.

Effects

{ "type": "stars", "density": 40, "speed": 1, "color": "#ffd6f2" }

Supported types: none, stars, snow, petals, bubbles.

  • density is clamped to 0–120 particles.
  • speed is clamped to 0.2–3.
  • Effects are disabled when the user turns on Reduce animations.

Audio

{ "src": "music.mp3", "loop": true }

src is relative to assets/. Music uses the launcher's volume control and is silent in the theme editor preview.

Typography

typography.body changes the font used by the launcher UI. typography.heading changes headings such as the launcher title.

"typography": {
  "body": "Montserrat Variable",
  "heading": "Playfair Display Variable"
}

These families ship with the launcher through @fontsource and can be used without adding any files:

Family Style
Sora Variable Sans
Montserrat Variable Sans
Bebas Neue Display
Playfair Display Variable Serif
Space Mono Mono
JetBrains Mono Variable Mono

Custom fonts can be packaged with the theme. The launcher generates the @font-face rules from fonts:

"fonts": [
  { "family": "My Display Font", "src": "display.woff2", "weight": "400", "style": "normal" }
]
  • src is relative to assets/.
  • Supported formats: WOFF2 (recommended), WOFF, TTF and OTF.
  • weight defaults to 400; style defaults to normal.
  • Use the family value in typography and in text layers.

The editor's Fonts tab browses the full Fontsource catalog (2,000+ families) and downloads the selected family, weight, style and subset as a WOFF2 into the theme's assets/ folder. It adds the matching fonts entry automatically, so saved and exported themes stay self-contained.

Freeform layers

elements are rendered above the launcher UI, but only on the Home screen. The launcher canvas is a fixed 1000 × 650 coordinate space. Elements can extend the home screen with text, images, videos and shapes, and they are pointer-transparent in the running launcher so they never block buttons.

The order of the elements array controls stacking: the last element is drawn on top. Themes can contain up to 100 layers.

Every layer supports:

Field Type Notes
id string Unique within the theme
name string? Optional editor label; does not affect rendering
type string text, image, video or shape
x, y number Position in the 1000 × 650 stage
width number 24–1000
height number 24–650
rotation number Degrees, -360–360
opacity number 0–1
hidden boolean Keep the layer in the file but do not render it
locked boolean Prevent moving/resizing the layer in the editor

Text

{
  "id": "greeting",
  "type": "text",
  "text": "Welcome back!",
  "x": 360,
  "y": 220,
  "width": 420,
  "height": 90,
  "fontFamily": "Bebas Neue",
  "fontSize": 42,
  "fontWeight": 600,
  "color": "#ffffff",
  "align": "center",
  "verticalAlign": "center",
  "lineHeight": 1.2,
  "letterSpacing": 0
}

align is left, center or right; verticalAlign is top, center or bottom. Font size is clamped to 6–240.

Image and video

{
  "id": "logo",
  "type": "image",
  "src": "logo.png",
  "x": 700,
  "y": 420,
  "width": 220,
  "height": 140,
  "fit": "contain",
  "radius": 18,
  "opacity": 1
}
{
  "id": "ambient",
  "type": "video",
  "src": "ambient.webm",
  "x": 0,
  "y": 0,
  "width": 1000,
  "height": 650,
  "fit": "cover",
  "opacity": 0.35
}

Video layers autoplay and loop. They are muted by default; set muted to false to play their audio. WebM is recommended for size. Use an opacity below 1 if the video should blend into the launcher UI.

Shape

{
  "id": "glow",
  "type": "shape",
  "shape": "ellipse",
  "x": 680,
  "y": 60,
  "width": 260,
  "height": 260,
  "fill": "#ff006e",
  "opacity": 0.18,
  "borderWidth": 0,
  "borderColor": "#ffffff"
}

shape is rectangle, ellipse or line. radius rounds rectangle corners. borderWidth is clamped to 0–40.

Custom CSS

The css field is appended while the theme is active. Theme authors can use it for small tweaks, but it is not required. Example:

:root {
  --radius: 1rem;
}

Using the advanced editor

  1. Open Themes in the launcher.
  2. Select Create theme, or the pencil button on an installed API 2.0 theme.
  3. The editor opens in its own resizable window, not a modal. The center is a full launcher home canvas at 1000 × 650.
  4. Use the left toolbar to add text, image, video and shape layers. Drag layers on the canvas, resize with the corner handles, or edit exact values in the right inspector. Shift/Cmd-click a layer or drag a marquee over empty canvas to select several layers. Multi-selections can be dragged together and aligned or distributed from the right panel. Layers snap to canvas edges, the canvas center, and other layers while dragging; hold Alt to disable snapping. Right-click a layer for quick duplicate, ordering, hide/lock and delete actions, or right-click empty canvas to add a new layer.
  5. The layer list supports double-click rename, hide/show, lock/unlock and drag-to-reorder. Hidden layers remain in the package, while locked layers cannot be moved or resized on the canvas.
  6. Use the Theme tab for metadata, background, effects, typography and custom CSS. Open the Fonts tab to search and download from every Fontsource family, or import WOFF2, WOFF, TTF and OTF files. Downloaded fonts are copied into the theme's assets/ folder when you save.
  7. Select Save theme to write theme.json and copy new assets into ~/.ezpplauncher/themes. A fresh assets/preview.png thumbnail is rendered from the theme and the launcher applies the saved theme immediately. Unsaved edits are autosaved as a local draft and offered for recovery after a crash.
  8. Select Export to create a shareable .ezpplauncher-theme package. A theme check runs first and reports missing assets, oversized media, missing fonts and unused imports. Export saves and refreshes the preview, then reports the final package size.

Keyboard shortcuts:

  • Cmd/Ctrl+Z undoes the last change.
  • Cmd/Ctrl+Shift+Z or Ctrl+Y redoes it.
  • Cmd/Ctrl+S saves.
  • Cmd/Ctrl+D duplicates the selected layer or multi-selection.
  • Cmd/Ctrl+A selects every visible layer.
  • Shift/Cmd-click toggles a layer in the current selection.
  • Arrow keys nudge the selected layer(s) by 1 px; hold Shift for 10 px.
  • Delete removes the selected layer(s).
  • Hold Alt while dragging to skip snapping.
  • Esc clears the selection or closes an open editor dialog.

Creating API 2.0 themes with the CLI

The create-ezpplauncher-theme CLI includes a declarative (API 2.0) template:

npx git+https://git.ez-pp.farm/EZPPFarm/create-ezpplauncher-theme.git my-theme

Choose declarative (API 2.0), edit theme.json, add files to assets/, then run:

npm run build

This produces dist/my_theme.ezpplauncher-theme. The template also includes preview.html for a standalone browser preview:

npx serve .

Compatibility and limits

  • API 2.0 packages must include theme.json; entry and style are not used.
  • Asset paths are resolved inside assets/; path traversal is rejected by the import commands.
  • Exports include only assets/ files referenced by theme.json (background, audio, fonts, layers and preview). Orphaned files left in the folder are omitted, which keeps packages small. API 1.0 themes are exported whole because their bundles can load files dynamically.
  • The editor writes preview.png whenever you save or export. The generated thumbnail renders the background, effects, launcher UI, theme fonts and freeform layers; custom CSS is not applied to the thumbnail.
  • The theme editor only writes inside ~/.ezpplauncher/themes.
  • API 1.0 themes are still loaded through their existing mountTheme bundle API.
  • API 2.0 themes cannot run JavaScript. Use custom CSS for small visual tweaks, or use API 1.0 when a theme needs a fully custom UI.
  • Freeform layers are decorative, home-screen-only and pointer-transparent; they cannot add interactive controls.