StoryLark
← All guides

Getting Started

StoryLark runs on Cloudflare or Azure — pick either, or don't pick yet. Where you end up depends on what you're trying to do:

Deploying your own site

There are two starting points, and two ways to drive each one — four paths, same result:

Manual Wizard-driven
Clone the repo git clone the engine, fill in an env file yourself, run the platform installer git clone, then node platforms/wizard.mjs asks the questions and runs the installer for you
npm create storylark Scaffolds a standalone site folder, fill in an env file yourself, run the installer npm create storylark my-site -- --deploy — one command, a few prompts, ends at a live URL

Every path asks you to pick a platform (Cloudflare or Azure) as part of it — nothing above assumes Cloudflare. Prerequisites differ by platform:

Full detail on all four paths, what each one produces, and what's shared across every path (your brand folder, CI wiring, self-update) is in install.md.

Running the engine locally

If you just want to see the app boot and poke at the code — no deployment, no platform account needed beyond what local dev requires — clone the engine repo directly and run it against the neutral StoryLark base brand.

This path always runs on Cloudflare tooling (wrangler dev) regardless of which platform you'd eventually deploy to — it's the engine's own local dev loop, not a platform choice. Standing up a real site (Cloudflare or Azure) is covered above.

Prerequisites

Clone and install

git clone <your-fork-or-clone-url> storylark
cd storylark
npm install

This is an npm workspaces repo. A single npm install at the root installs the app site and the packages/* (storylark-core, storylark-worker, storylark-pipeline) workspaces together, linking the site against the local packages.

The commands (from the root package.json)

Command What it runs Notes
npm run dev npm run build -w app -- --mode storylark && wrangler dev --env storylark Builds the PWA for the storylark brand, then serves it (static assets + /api/*) through the Worker on a local port.
npm run build npm run build -w app -- --mode storylark Production build of the app into app/dist.
npm run deploy npm run build && wrangler deploy --env storylark Build, then deploy the Worker + assets to Cloudflare directly (bypasses the installer — see Deploying your own site for the supported path).
npm run publish node packages/pipeline/publish.mjs --brand storylark Publish content to R2. This script needs extra flags — see the note below and content-pipeline.md.
npm run typecheck tsc over the site, core, and worker tsconfigs Type-checks the site, the engine, and the Worker.

Note on npm run publish: the root script passes only --brand storylark, but packages/pipeline/publish.mjs requires --source <path> as well and will exit with a usage message otherwise. Treat the npm script as a shorthand and pass the remaining flags after --, e.g. npm run publish -- --source examples/demo --no-audio --local app/dist. Stories are plain markdown — see authoring-stories.md for the format and content-pipeline.md for the full pipeline reference (including --parser for non-markdown sources).

After npm run dev, open the URL Wrangler prints. The app boots as a branded but empty shelf — there is no bundled content. To see stories, publish some (the bundled examples/demo public-domain stories are the quickest way; see content-pipeline.md).

Testing secret-gated routes locally (ADMIN_KEY etc.): confirmed on this project's Workers+Assets setup, .dev.vars / .dev.vars.<env> / --var do not actually reach env in wrangler dev — the startup banner claims the binding exists, but the Worker never sees it (verified by dumping every key on env at runtime: only what's declared in wrangler.jsonc's vars shows up). To test an admin route locally, temporarily add the value under that env's vars block in wrangler.jsonc and remove it before committing — never commit a real secret this way.

How the brand "mode" works

The Vite build mode is the brand id. The defineStorylarkConfig preset (from storylark-core/vite, used by app/vite.config.ts) reads --mode <brandId>, loads brands/<brandId>/brand.json + brands/<brandId>/theme.css, and bakes them into the bundle:

The built-in Vite modes (development, production, test) fall back to the storylark brand. Any other --mode value is treated as a brand id, so --mode acme builds brands/acme/. The root scripts all pin --mode storylark.

Project layout

brands/             per-brand config: brand.json, theme.css, assets/icons/ (and optional assets/covers/)
app/                the base SITE — a thin consumer of storylark-core (index.html, entry.ts, vite.config.ts)
packages/core/      storylark-core — the PWA engine (library / reader / player / settings + service worker)
                    plus the defineStorylarkConfig Vite preset that builds a site from a brand folder
packages/worker/    storylark-worker — Hono API (/api/*) over a database adapter (D1 or Postgres); SQL migrations
packages/pipeline/  storylark-pipeline — publish pipeline (markdown -> chapter JSON + TTS audio + word timings -> storage) + generators
platforms/          per-platform deploy tooling (cloudflare/, azure/) — installers, IaC, the shared wizard
docs/               these docs
examples/           demo content + a sample parser (public-domain stories) for trying the pipeline

Inside packages/core/src/:

Next steps


Found a gap? StoryLark is open source — improve these docs on GitHub.