An @xcwds app is a static site that installs like an app, works offline and keeps what people save on their own device. You describe it in one config file: its name, icon and colours, and a list of plugins. This page takes you from nothing to an app on your phone.
Not on npm yet. The packages will be published with the first release (#26). Until then, try it from a clone of xcwds/xcwds:
pnpm install && pnpm build node packages/create/dist/create.js examples/my-app --workspace pnpm install
--workspacemakes the new app use the packages in the clone. Everything below works the same, fromexamples/my-app.
Make an app
npm create @xcwds my-app
# or
pnpm create @xcwds my-app
It asks for a name, a one-line tagline, a square SVG icon (or uses a neutral one) and which
plugins to use, with the recommended ones ticked: the shell (header, tab bar and Home), light
and dark mode, offline support, updates that wait for a tap, an Install button and a settings
page. --template tools adds a list of small tools and timers. Then it installs everything.
cd my-app
pnpm dev # http://localhost:5173
What you get
| File | What it is |
|---|---|
xcwds.config.ts |
The app's brand and plugins. Most changes start here. |
src/routes/ |
Pages. A plugin's page is a small file that renders its component. |
src/xcwds.css |
Each plugin's styles, kept in sync by xcwds add. |
src/lib/Notices.svelte |
The notices plugins show (offline, update), also kept in sync. |
e2e/app.test.ts |
Playwright tests: every page, tap targets, offline, no tracking. |
.github/workflows/deploy.yml |
Tests every push and deploys main to GitHub Pages. |
It is an ordinary SvelteKit project, built with
@sveltejs/adapter-static: you add pages the usual way.
The config file
// xcwds.config.ts
import { defineConfig } from '@xcwds/core';
import settings from '@xcwds/plugin-settings';
import shell from '@xcwds/plugin-shell';
import theme from '@xcwds/plugin-theme';
export default defineConfig({
brand: {
name: 'Pocketbox',
tagline: 'Everyday tools.',
icon: 'icon.svg',
themeColor: { light: '#ffffff', dark: '#0f172a' }
},
plugins: [
shell({
sections: [
{ path: '/', label: 'Home', emoji: '๐ ' },
{ path: '/settings', label: 'Settings', emoji: 'โ๏ธ' }
]
}),
theme(),
settings()
]
});
brandnames the app everywhere it shows: the page title, the home-screen label, the manifest.iconis rendered into every icon size browsers and phones ask for.pluginsis the list of features, in order. Calling a plugin returns a small, plain description of it (its package name and options), so options must be plain data: strings, numbers, booleans, arrays and objects. The build checks them and names the plugin when one is wrong.privacy.allowOriginslists any server the app may contact that no plugin declares. It is empty by default, and the build fails if it finds a call to any other server. See Privacy.manifestadds fields to the generated web app manifest.storage.prefixchanges theapp:prefix of saved keys, andstorage.appNamethe name backups carry (and must carry to import), which defaults tobrand.name: set it to keep importing backups an app made under another name.
Add a plugin
pnpm xcwds add timers
xcwds add installs the package, adds it to xcwds.config.ts (and its tab before Settings),
writes the pages it needs and updates src/xcwds.css and src/lib/Notices.svelte. Run
pnpm xcwds add on its own to see every plugin, with the ones you have ticked. The
ecosystem page lists them all, and Writing a plugin shows how
to make your own.
Deploy to GitHub Pages
- Push the app to a GitHub repository.
- In the repository's Settings โ Pages, set Source to GitHub Actions.
- Push to
main. The workflow runs the tests, builds and deploys.
A repository named <user>.github.io is served from the root. Any other repository is a
project site under /<repo>, so the workflow sets BASE_PATH for the build and every link,
the manifest and the service worker follow it. Other static hosts work too: deploy the build/
folder and serve 404.html for unknown paths.
Check that it works
- Install it. Open the deployed site on your phone. On Android, tap Install in Settings (or the browser's menu); on iPhone, Settings shows the Share โ Add to Home Screen steps.
- Go offline. Turn on airplane mode and open the app: every page still loads.
- Update it. Push a change. The open app offers Update and only reloads when you tap it, so nobody loses what they were doing.
Next: Concepts explains how the pieces fit together.