Scaffold a framework starter
shellui init scaffolds a Shellui project and, for each JS framework, a companion iframe app already wired for theme and language. This page covers what init writes, the shared SDK pattern, and how each starter runs.
What shellui init writes
Run the wizard or pass a framework id:
shellui init
shellui init react
shellui init --framework next --backend none
Init does the following:
- Writes
shellui.config.json(with$schema) - port 4000, layout, theme"shellui", Home nav, Settings modal - Adds placeholder files under
static/(favicon.svg,logo.svg, icons) - For JS frameworks: copies a companion starter, sets
dev.run/dev.url, and runs your package manager install unless--no-install - Points Home
urlat the companion origin so the shell loads the iframe app
Templates come from the GitHub tag that matches the CLI version (or a local monorepo copy). They are not bundled in the npm tarball. Overwrite an existing config with --force.
Supported positional ids: empty, react, vue, angular, next, nuxt, svelte, alpine. The wizard also offers Other (coming soon), which writes a shell-only config with static/ stubs and no framework template (same companion shape as empty). Command flags and backends are on CLI init. First-run flow is on Create a project.
Theme and i18n out of the box
Every JS starter uses @shellui/sdk/tiny the same way you would wire it by hand:
- Wait for
shellui.ready - Call
shellui.applyTheme()and subscribe withshellui.on('theme', …) - Read
shellui.language, subscribe withshellui.on('language', …), and drive a local i18n library (or a small message map)
import { shellui } from '@shellui/sdk/tiny';
void shellui.ready.then(() => {
shellui.applyTheme();
applyLanguage(shellui.language);
});
shellui.on('theme', () => shellui.applyTheme());
shellui.on('language', applyLanguage);
Sample catalogs ship as en / fr. Change theme or language in Shell Settings and the companion home page updates. Framework-specific wiring (hooks, composables, services, plugins) is under each starter below. Related: Themes, Internationalization, SDK.
Choose a framework
Pick a starter, then jump to its section for ports and stack notes:
After init, from the project root:
shellui start
That starts the shell on 4000 and the companion on the port in the table below. Init sets dev.run to {pm} run dev for every JS starter. Run the companion alone with that script if you need it without the host.
| Framework | Init id | Companion dev.url |
|---|---|---|
| React / Vue / SvelteKit / Alpine | react, vue, svelte, alpine | http://localhost:5173 |
| Angular | angular | http://localhost:4200 |
| Next.js / Nuxt | next, nuxt | http://localhost:3000 |
| Empty | empty | none (Home at /) |
React
Vite + React starter; init id react, companion port 5173.
shellui init react
shellui start
Theme and i18n in this starter:
- Theme / i18n:
src/useShellui.jscallsshellui.applyTheme()and syncs language into i18next (src/i18n.js, react-i18next) - Stack note: the hook returns
{ theme, language, shellui }for the home UI
Vue
Vite + Vue starter; init id vue, companion port 5173.
shellui init vue
shellui start
Theme and i18n in this starter:
- Theme / i18n:
src/composables/useShellui.jsupdates vue-i18nlocalefromshellui.on('language', …) - Stack note:
main.jsregisters the i18n plugin; the composable owns the SDK listeners
Angular
Angular starter; init id angular, companion port 4200. Init sets dev.run to {pm} run dev (the package dev script runs ng serve --port 4200).
shellui init angular
shellui start
Theme and i18n in this starter:
- Theme / i18n:
ShelluiService(src/app/shellui.service.ts) applies theme and resolves strings witht()over inlineen/frmaps insrc/app/i18n.ts - Stack note: the root component starts the service on init; signals hold theme and language
Next.js
Next.js App Router starter; init id next, companion port 3000 (pinned via scripts/ensure-port.mjs).
shellui init next
shellui start
Theme and i18n in this starter:
- Theme / i18n: client component
app/home.jsdynamic-imports@shellui/sdk/tiny(SSR-safe);app/i18n.jsholds a plaint(lang, key)helper - Stack note: keep SDK work in client components; do not import the tiny SDK at the top level of a Server Component
Nuxt
Nuxt starter; init id nuxt, companion port 3000 (nuxt.config.ts devServer.port).
shellui init nuxt
shellui start
Theme and i18n in this starter:
- Theme / i18n: client plugin
app/plugins/shellui.client.tswrites shared state;app/composables/useShellui.tsreadsuseState('shellui-theme' | 'shellui-language') - Stack note: Nuxt 4 expects a recent Node 22.x / 24.x
SvelteKit
SvelteKit starter; init id svelte, companion port 5173.
shellui init svelte
shellui start
Theme and i18n in this starter:
- Theme / i18n:
src/lib/shellui.jsstarts listeners from+layout.svelteonMount;src/lib/i18n.jsuses writable / derived stores - Stack note: dynamic import keeps the SDK off the server render path
Alpine.js
Vite + Alpine.js starter; init id alpine, companion port 5173.
shellui init alpine
shellui start
Theme and i18n in this starter:
- Theme / i18n:
src/main.jsregistersAlpine.data('shelluiHome', …)with ready / theme / language handlers;src/i18n.jsexportst() - Stack note: init also sets
language: ["en", "fr"]in config so Settings lists both locales. No Tailwind in this starter
Empty shell
Shell-only project; init id empty. No companion, no dev block. Home stays at /.
shellui init empty
shellui start
Add your own iframe app later and set dev.run / dev.url - see companion process.
Companion checklist
After shellui start:
- Open
http://localhost:4000/- the shell loads the companion in Home - Open Shell Settings and switch theme - the iframe page should restyle
- Switch language to French - sample strings should update
If the companion port is busy, free it or change both the framework config and dev.url together. Picked Other in the wizard? You get a shell-only config like empty; wire your own companion the same way. Details: Create a project, CLI.