Files
Elias Journal 30f9148adb Initial commit: KiddOs v3 React kiosk
- React 18 + Vite 5 hot-reload OS (800x480 Nord theme)
- 7 apps: Journal, Calculator, Drawing, CodeLab, Clock, Files, Scratch
- Cage + Cog Wayland kiosk, offline localStorage
- Scripts: dev.sh, run-kiosk.sh, run-prod.sh
2026-08-24 21:53:02 -04:00

5.2 KiB

KiddOs v3 — Plan: Browser Kiosk + React Hot Reload, No Backend

Goal

From-scratch v3, just webapp React with hot refresh, no server, no LVGL, no backend. Use the proven kiosk command that shows web on DSI:

cage -s -- \
cog --platform=wl file:///home/elias/KiddOsV2/browser/hello.html --bg-color=#2E3440

That command is Method 2a that you confirmed works: cage (tiny Wayland kiosk compositor, 82KB) owns DRM/KMS on /dev/dri/card1 (DSI 800x480 connector id 49), creates Wayland socket in $XDG_RUNTIME_DIR, cog --platform=wl (WPE WebKit, ~10MB) connects as Wayland client and renders HTML. No X11, no black flicker from fork/exec.

For v3 we keep that exact command, but point it to a React dev server for hot refresh instead of static file://

Why No Backend?

  • v2 had server/server.py local-first + central sync. Good architecture but adds complexity.
  • v3 requirement: just webapp react with hot refresh on code changes so we can quickly iterate.
  • So: Vite dev server on Pi itself http://localhost:5173 serves React, Cog loads that URL, and Vite HMR pushes changes instantly to DSI — you edit src/App.jsx on laptop via SSH, DSI updates in <1s.

Stack

  • Compositor: cage -s (kiosk Wayland, handles DRM, libinput touch via seat0)
  • Browser: cog --platform=wl (WPE WebKit, lighter than Chromium 150MB and Electron 265MB). Fallback: chromium --ozone-platform=wayland if WPE touch fails.
  • Webapp: React 18 UMD or Vite + React (we use Vite for HMR). No backend, uses localStorage for journal/todos. All offline, file:// or http://localhost works.
  • Icons: Reuse PNG 128x128 from v1/v2 browser/icons/.

Folder v3

KiddOsV3/
├── plan.md (this file)
├── README.md
├── public/ (static icons, will be served by Vite)
├── webapp/
│   ├── package.json (vite + react)
│   ├── vite.config.js (host 0.0.0.0, port 5173, HMR overlay)
│   ├── index.html (Vite entry)
│   └── src/
│       ├── main.jsx (ReactDOM.createRoot)
│       ├── App.jsx (OS shell: header, favorites, categories, grid, settings drawer)
│       └── apps/
│           ├── Journal.jsx (localStorage journal)
│           ├── Calculator.jsx
│           ├── Drawing.jsx (canvas)
│           └── CodeLab.jsx
└── scripts/
    ├── dev.sh (run vite dev server)
    └── run-kiosk.sh (the proven cage command)

How to run (prove without services)

On Pi, no services needed — manual, like you asked:

# 1. Stop any old kiosks, leave terminal on DSI
sudo systemctl stop kiddos.service kiddos-browser.service journal-kiosk.service
sudo systemctl start getty@tty1.service

# 2. Start React dev server in one SSH session:
cd ~/KiddOsV3/webapp
npm install
npm run dev -- --host 0.0.0.0 --port 5173
# Vite says: Local: http://localhost:5173/

# 3. In another SSH session, put it on DSI (exact command you proved):
sudo openvt -f -c 1 -s -- env XDG_RUNTIME_DIR=/run/user/1000 cage -s -- \
cog --platform=wl http://localhost:5173 --bg-color=#2E3440 --doc-viewer

# You should see React launcher on DSI, and editing src/App.jsx updates instantly.

If touch cursor stuck middle (your last report):

  • Cage needs input devices. Check libinput list-devices shows 10-0038 generic ft5x06 (79) at event7.
  • Try without WLR_NO_HARDWARE_CURSORS, and ensure /run/user/1000/wayland-* cleaned.
  • Fallback: cage -s -- chromium --ozone-platform=wayland instead of cog — you saw webpage with that too.
  • Last resort heavier: labwc --startup "cog ..." or Xorg+openbox, but we avoid until proven.

React Hot Refresh Details

  • Vite HMR uses WebSocket on same host:port. Cog supports WebSocket, so HMR works file://? No, needs http:// — hence dev server at localhost:5173.
  • In vite.config.js:
export default {
  server: { host: '0.0.0.0', port: 5173, hmr: { clientPort: 5173 } },
  clearScreen: false
}
  • Edit src/App.jsx, save, DSI refreshes.

Next Steps After Prove

Once hello world React works reliably on DSI with touch:

  1. Add more React apps (Scratch via iframe?).
  2. Optionally re-add local server later for central sync (v2's server.py) — but keep v3 frontend-only for fast iteration.
  3. Only then create systemd service using same working command (openvt -f -c 1 -s ...).

Commands Reference (the one you asked to keep)

Base proven command (no backend, just file:// hello world):

cage -s -- \
cog --platform=wl file:///home/elias/KiddOsV2/browser/hello.html --bg-color=#2E3440

For v3 React with HMR:

cage -s -- \
cog --platform=wl http://localhost:5173 --bg-color=#2E3440

If Cog touch fails, try Chromium:

cage -s -- \
chromium --kiosk --no-sandbox --ozone-platform=wayland --disable-gpu \
http://localhost:5173

Electron alternative (heavier, same as Chromium + Node, you asked about):

cage -s -- \
./node_modules/.bin/electron --no-sandbox --ozone-platform=wayland --disable-gpu .

Why not LVGL anymore?

  • v1 LVGL had to fork/exec + DRM master handover for each app → “any app I try to open freeze and restarts the OS” (your report). Non-DRM apps (gnome-calculator) crashed.
  • Browser OS: one process owns DRM forever, apps are just React components / pages, no fork, no black screen.