@lumen-mirror/cli
v0.0.8
Published
CLI for scaffolding and developing Lumen Mirror smart mirror apps.
Readme
@lumen-mirror/cli
Create and run Lumen Mirror smart mirror apps from the terminal.
Lumen Mirror is a TypeScript framework for building mirror widgets as modules with HTML templates and reactive signals. This CLI scaffolds projects, generates modules, and runs dev/build tooling — Vite, SCSS, and decorator support are built in, so you never touch a vite.config.ts.
Install
npm install -g @lumen-mirror/cliOr use it once without installing:
npx @lumen-mirror/cli new my-mirrorCreate a project
lumen new my-mirror
cd my-mirror
npm install
npm run devOpen the URL printed in the terminal (default http://localhost:5173). You get a working mirror with four starter widgets on a CSS grid — the clock is the main reference example (alarms, routine profiles, voices, focus mode, and localStorage persistence).
Starter modules
| Widget | What it demonstrates |
| --- | --- |
| clock | Full-featured reference module: (click) template bindings, @if / @for, <dialog> alarm editor, Popover API for new profiles, Web Speech voices, minute-by-minute alarm firing, focus mode. State under dashboard.modules.clock in localStorage. |
| weather | Signals, host onClick, cross-module events (weather:selected) |
| welcome | Event bus listener (envelope with source), onboarding copy |
| news-feed | @for list rendering |
Open the clock gear first — add a routine profile, create an alarm, and pick a voice.
Electron (optional)
Run the same app inside an Electron shell — useful for kiosk-style mirrors:
npm run dev:electronWindow size and display options live in lumen.json under electron.
Day-to-day scripts
| Script | What it does |
| --- | --- |
| npm run dev | Start the dev server with hot reload |
| npm run dev:electron | Dev server + Electron window |
| npm run build | Production build to dist/ |
All three delegate to the lumen CLI (serve / build).
Project layout
After lumen new, your app looks like this:
my-mirror/
lumen.json # platform config (serve, build, electron)
index.html
src/
main.ts # bootstraps the mirror
lumen.config.ts # typed CSS grid layout
global.scss # base styles
modules/ # one folder per widget
clock/
weather/
welcome/
news-feed/src/main.ts
Entry point — loads your layout and modules, then starts the runtime:
import lumenProject from '../lumen.json';
import { bootstrap } from '@lumen-mirror/core';
import appConfig from './lumen.config.js';
import { ClockModule, WeatherModule } from './modules/index.js';
await bootstrap({
root: lumenProject.root,
modules: [ClockModule, WeatherModule /* … */],
config: appConfig,
});src/lumen.config.ts
Define where widgets sit on the mirror grid. Rows, columns, and cell names are type-checked:
import { defineLayout, defineLumenConfig } from '@lumen-mirror/core';
export default defineLumenConfig({
layout: defineLayout(3, 4, [
['clock', 'clock', '.', 'weather'],
['welcome', 'welcome', 'welcome', 'welcome'],
['news-feed', 'news-feed', '.', '.'],
] as const),
});Use . for empty cells. Each name must match a module's host.classes entry (e.g. host: { classes: ['clock'] }).
lumen.json
Platform config the CLI reads — like angular.json / project.json. Layout and modules live in TypeScript, not here:
{
"name": "my-mirror",
"root": "#app",
"entry": "src/main.ts",
"index": "index.html",
"serve": { "port": 5173, "host": "localhost" },
"build": { "target": "esnext", "minify": true, "sourcemap": false },
"electron": { "width": 1080, "height": 1920, "fullscreen": false }
}Add a module
From your project root:
lumen generate quotesThis creates src/modules/quotes/ with a module class, template, and styles, and adds a barrel export in src/modules/index.ts.
By default it does not add the module to src/main.ts or the grid — use that when the widget is nested inside another module:
<QuotesModule />If you confirm the prompt, it will also register the module in src/main.ts and src/lumen.config.ts for top-level grid placement.
Inside a module:
import { LumenModule, Module, signal } from '@lumen-mirror/core';
@Module({
templateUrl: './quotes.template.html',
styleUrls: ['./quotes.template.scss'],
host: { classes: ['quotes'] },
})
export class QuotesModule extends LumenModule {
text = signal('Hello, mirror');
onClick() {
this.text.set('Tapped!');
}
}Put layout and panel styles on the module host via host.classes — do not repeat that class on a wrapper inside the template (the renderer already applies it to the host element).
Templates use {{ signalName }}, @if, and @for. See @lumen-mirror/core for the full template and signals API.
Commands
| Command | Description |
| --- | --- |
| lumen new <name> | Scaffold a new mirror app |
| lumen generate [name] | Add a module (alias: lumen g) |
| lumen serve | Dev server with hot reload |
| lumen serve --electron | Dev server + Electron shell |
| lumen build | Production build |
Requirements
- Node.js 20+
- npm, pnpm, or yarn (for installing scaffolded app dependencies)
Learn more
- Runtime & templates: @lumen-mirror/core on npm
