Skip to content

Quick Start

Build the property contract once, use it during the Vite build, and derive the exact runtime callback shape from the same record.

src/properties.ts
import {
boolProperty,
colorProperty,
groupProperty,
sliderProperty,
} from 'wallpaper-engine/plugin';
export const properties = {
appearance: groupProperty({ text: 'Appearance' }),
accent: colorProperty({ text: 'Accent', value: 'oklch(70% 0.18 250)' }),
intensity: sliderProperty({
text: 'Intensity',
value: 0.5,
min: 0,
max: 1,
fraction: true,
precision: 2,
}),
showClock: boolProperty({ text: 'Show clock', value: true }),
};

The builders add Wallpaper Engine’s discriminants while preserving your options. The group controls editor layout but produces no runtime value.

vite.config.ts
import { defineConfig } from 'vite';
import { wallpaperEnginePlugin } from 'wallpaper-engine/plugin';
import { properties } from './src/properties';
export default defineConfig({
plugins: [
wallpaperEnginePlugin({
title: 'My Wallpaper',
properties,
}),
],
});

During vite dev, the plugin injects the development simulator by default. It exposes Wallpaper Engine-compatible globals and lets you send property, runtime, audio, and media events to the page.

During vite build, the plugin writes project.json beside the built index.html. It is minified by default; set minify: false to pretty-print it. vite dev injects the simulator and does not write project.json; production output never includes the simulator.

src/wallpaper.ts
import type { WallpaperUserPropertiesOf } from 'wallpaper-engine/plugin';
import type { properties } from './properties';
import { wallpaperColorToHex } from 'wallpaper-engine/helpers';
import 'wallpaper-engine';
type UserProperties = WallpaperUserPropertiesOf<typeof properties>;
window.wallpaperPropertyListener = {
applyUserProperties(values: Partial<UserProperties>) {
if (values.accent) {
document.body.style.backgroundColor = wallpaperColorToHex(
values.accent.value,
);
}
if (values.intensity) {
document.documentElement.style.setProperty(
'--intensity',
String(values.intensity.value),
);
}
if (values.showClock) {
document.body.classList.toggle('clock-hidden', !values.showClock.value);
}
},
};

Register listeners at module scope—not in onMounted, window.onload, or a timer. Wallpaper Engine may deliver startup events before lifecycle hooks, and later property callbacks contain only changed keys. The Partial<UserProperties> annotation and per-key guards encode that behavior.

The inferred values are host-shaped wrappers: accent.value is a Wallpaper Engine color string, intensity.value is a number, and showClock.value is a boolean. The appearance group key is omitted.

The complete working pattern lives in demo/src/wallpaper.ts and demo/src/App.vue.

Define the complete editor contract in Property Schemas, then connect every host callback in Host Listeners.