Skip to main content

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:

  1. Writes shellui.config.json (with $schema) - port 4000, layout, theme "shellui", Home nav, Settings modal
  2. Adds placeholder files under static/ (favicon.svg, logo.svg, icons)
  3. For JS frameworks: copies a companion starter, sets dev.run / dev.url, and runs your package manager install unless --no-install
  4. Points Home url at 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:

  1. Wait for shellui.ready
  2. Call shellui.applyTheme() and subscribe with shellui.on('theme', …)
  3. Read shellui.language, subscribe with shellui.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.

FrameworkInit idCompanion dev.url
React / Vue / SvelteKit / Alpinereact, vue, svelte, alpinehttp://localhost:5173
Angularangularhttp://localhost:4200
Next.js / Nuxtnext, nuxthttp://localhost:3000
Emptyemptynone (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.js calls shellui.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.js updates vue-i18n locale from shellui.on('language', …)
  • Stack note: main.js registers 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 with t() over inline en / fr maps in src/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.js dynamic-imports @shellui/sdk/tiny (SSR-safe); app/i18n.js holds a plain t(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.ts writes shared state; app/composables/useShellui.ts reads useState('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.js starts listeners from +layout.svelte onMount; src/lib/i18n.js uses 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.js registers Alpine.data('shelluiHome', …) with ready / theme / language handlers; src/i18n.js exports t()
  • 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:

  1. Open http://localhost:4000/ - the shell loads the companion in Home
  2. Open Shell Settings and switch theme - the iframe page should restyle
  3. 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.