Each window is a folder with 3 files:
my-window/
config.js ← metadata, position, drag, resize, exports
template.html ← the window's HTML
style.css ← styles (auto-scoped, no conflicts)
This guide dialog is part of the main settings UI, not a runtime window module. Use it as authoring reference only.
config.js + version subfolders in the ZIP and choose a version in the pickerNote: registry.json is only for built-in windows that ship with the project.
GitHub import supports optional hash params: #window=inventory&version=v2.
export default {
id: 'my-window', // unique ID (matches folder name)
title: 'My Window', // display title
defaultPosition: { x: 100, y: 100, width: 400, height: 300 },
defaultOpen: true,
dragHandle: '.my-header', // CSS selector for drag zone
resizable: {
enabled: true,
handles: ['se'], // n,s,e,w,ne,nw,se,sw
minWidth: 200, minHeight: 150,
},
exports: [
{ selector: '[data-export="my-full"]', name: 'full', label: 'Full Window' }, // minimal export baseline
// add fine-grained slices only when explicitly needed (prefer cells/elements, not text-only selectors)
// optional interactive states:
// {
// selector: '[data-export="my-btn"]', name: 'btn', label: 'Button',
// variants: [
// { state: 'hover', className: 'ui-export-hover' },
// { state: 'click', className: 'ui-export-click' },
// ],
// },
],
init(container) {
// wire interactive logic here
// container.querySelector('.my-btn').addEventListener('click', ...);
},
captureState(container) {
return null; // optional, implement only for editable tab/value/filter state
},
applyState(container, state) {
// optional
},
};
<div class="my-container" data-export="my-full">
<div class="my-header">
<span>MY WINDOW</span>
<button class="my-close">✕</button>
</div>
<div class="my-body">
<!-- your content -->
</div>
</div>
Write plain CSS — selectors are automatically scoped to your window. No IDs needed, class names won't conflict with other windows. Animations (@keyframes) pass through unmodified.
For granular export lists, prefer element/cell selectors (buttons, slots, bars, cards). Avoid text-only export slices.
You can include any HTML/CSS animations in template.html. Use @keyframes in style.css and wire interactive logic in config.init(). Click handlers, state toggles, SVG animations — everything works.
If you use export variants, provide matching CSS state classes (for example .ui-export-hover / .ui-export-click) so cloned export renders the target state correctly.
Copy this prompt to Claude, ChatGPT, or any AI model:
I need you to create a window for the UI Emulator.
The emulator uses plain HTML/CSS/JS (no frameworks).
Each window = 3 files: config.js, template.html, style.css.
## How the emulator works
- Windows live inside a 1920×1080 virtual viewport that scales to fit the browser
- Each window is a draggable, resizable container — the emulator handles drag & resize via config options
- template.html provides the window's HTML content — it's injected into a container div
- style.css is auto-scoped: all your selectors are prefixed with `[data-window-id="your-id"]` so class names never conflict with other windows
- config.js is an ES module (`export default {}`) that declares metadata and an optional `init()` function for interactivity
- Users can import windows client-side (ZIP or 3 files) without touching any server
## config.js fields
- `id` (string): unique window ID, must match folder name
- `title` (string): display name shown in the panel
- `defaultPosition` (object): `{ x, y, width, height }` — initial position in the 1920×1080 viewport
- `defaultOpen` (boolean): whether the window is visible on first load
- `dragHandle` (string): CSS selector for the draggable area (e.g. '.my-header')
- `resizable` (object): `{ enabled: true, handles: ['se'], minWidth, minHeight }` — which edges/corners can resize
- `exports` (array): `[{ selector, name, label, variants? }]` — export targets (minimal `full` export is enough unless granular slicing is requested)
- `init(container)` (function): called after the window is mounted. Use `container.querySelector()` to access your elements.
- `captureState(container)` + `applyState(container, state)` (optional): persist editable tabs/values/filters for defaults
## Rules
- template.html: pure HTML, include a drag handle element matching config.dragHandle
- export slicing: default to one `data-export` for full window; add granular markers only when requested
- export slicing detail: prefer cells/elements; avoid text-only export selectors
- export variants (optional): only when requested, add `variants` entries and matching CSS state selectors/classes for hover/click outputs
- style.css: plain CSS (auto-scoped, no need to prefix selectors), @keyframes work, avoid IDs
- init(container): use container.querySelector() to wire events, animations, state changes
- To close the window: import('../../js/core/window-manager.js').then(m => m.windowManager.close('my-id'))
- All animation via CSS @keyframes or JS in init()
- No React, no Tailwind, no build tools, no external deps
Create a window that: [DESCRIBE YOUR WINDOW HERE]
Return only the 3 files, nothing else.
GitHub Repository — full source, existing windows, and detailed windows_guide/WINDOW.md guide.