chore(themes): add new themes api v2, add in-app theme editor/creator, macos compatibility, fix asset loading, rework settings and setup wizard
This commit is contained in:
1 parent
417f54a94a
commit
87202de656
97 files changed
+10968
-1422
No files matched your search
+424
@@ -0,0 +1,424 @@
|
||||
# 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`
|
||||
|
||||
```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:
|
||||
|
||||
```json
|
||||
{ "type": "color", "color": "#181825", "opacity": 1 }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "type": "gradient", "from": "#181825", "to": "#3b1d4f", "angle": 135, "opacity": 1 }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "type": "image", "src": "background.png", "fit": "cover", "opacity": 1, "blur": 0 }
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```json
|
||||
{ "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
|
||||
|
||||
```json
|
||||
{ "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
|
||||
|
||||
```json
|
||||
{ "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.
|
||||
|
||||
```json
|
||||
"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`:
|
||||
|
||||
```json
|
||||
"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 |
|
||||
| `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` |
|
||||
|
||||
#### Text
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "logo",
|
||||
"type": "image",
|
||||
"src": "logo.png",
|
||||
"x": 700,
|
||||
"y": 420,
|
||||
"width": 220,
|
||||
"height": 140,
|
||||
"fit": "contain",
|
||||
"radius": 18,
|
||||
"opacity": 1
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
|
||||
```css
|
||||
: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.
|
||||
5. 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.
|
||||
6. 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.
|
||||
7. Select **Export** to create a shareable `.ezpplauncher-theme` package. Export
|
||||
saves and refreshes the preview first, so the package always includes the
|
||||
current thumbnail.
|
||||
|
||||
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.
|
||||
- Arrow keys nudge the selected layer by 1 px; hold Shift for 10 px.
|
||||
- `Delete` removes the selected layer.
|
||||
- `Esc` deselects the layer.
|
||||
|
||||
---
|
||||
|
||||
## Creating API 2.0 themes with the CLI
|
||||
|
||||
The `create-ezpplauncher-theme` CLI includes a **declarative (API 2.0)** template:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
This produces `dist/my_theme.ezpplauncher-theme`. The template also includes
|
||||
`preview.html` for a standalone browser preview:
|
||||
|
||||
```bash
|
||||
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.
|
||||
Reference in new issue
Block a user