Skip to content

Latest commit

 

History

History
225 lines (166 loc) · 10.2 KB

File metadata and controls

225 lines (166 loc) · 10.2 KB

Getting started

This is a guide, not the contract. What the platform guarantees is specified under openspec/specs/. For this page: scaffolding · platform-composition. Where this page and a specification disagree, the specification is right, and that is a defect in this page: change the behaviour there, then explain it here.

Scaffold a running product in about five minutes: the LoomWeaver chrome, branded, with one plugin of your own already contributing to it. Every command below was run against a fresh Angular app to produce exactly what the last step shows. The live demo runs the same shell, built the same way.

If you would rather understand each file instead of generating it, set it up by hand. Same result, roughly fifteen minutes, and it explains what the generators write.

Prerequisites: Node 24 and an Angular 22 workspace. Both flavours work and nothing below is specific to either: the Angular CLI (ng new) and Nx (nx g @nx/angular:application) generate the same application shape. Where they differ, in one file name or one path, it is called out. See also LoomWeaver and Nx.

1 · An application to put it in

ng new my-studio --style=css --ssr=false
cd my-studio

Already have an application (Angular CLI or Nx)? Skip this step and run the rest inside it.

--ssr=false because the shell is a client-rendered application chrome. If your workspace has SSR switched on, as the Nx Angular template does, see SSR; it is one line, not a blocker.

2 · Install the platform

npm install @loomweaver/shell @loomweaver/plugin-sdk @angular/cdk @jsverse/transloco @ng-icons/heroicons \
  @angular/service-worker@$(node -p "require('@angular/core/package.json').version")
npm install -D tailwindcss @tailwindcss/postcss @tailwindcss/typography

These are runtime dependencies of your application, not dev tooling: @angular/cdk powers drag-drop reorder and accessibility, Transloco the translations, @ng-icons/heroicons the first-party icon set. Tailwind is build-time only.

The last argument pins @angular/service-worker, a peer dependency of the shell, to the Angular version you already have; leave it off and the install fails with ERESOLVE. Manual setup → Install explains why, and why the version is read from node_modules rather than package.json.

3 · Scaffold the distribution

A distribution is your product: the composition root that assembles the platform into something shippable.

npx @loomweaver/cli distribution --name my-studio --title "My Studio" --out . --force

It writes eleven files and deletes nothing:

src/main.ts              bootstraps App with appConfig  (Angular's own shape)
src/app/app.config.ts    ← everything your product is made of lives here
src/app/app.config.spec.ts
src/app/app.ts           renders <lw-shell /> inside <app-root>
src/app/app.html
src/index.html           title, CSP, manifest link
src/styles.css           Tailwind + the LoomWeaver theme
ngsw-config.json
public/logo.svg          placeholder mark, so the top bar has something to show
public/manifest.webmanifest
LOOMWEAVER.md            what was written, and the little that is still yours

--force lets it replace the six of those that ng new just produced; all six are bootstrap wiring. Your README.md stays yours, because the scaffold keeps its own notes in LOOMWEAVER.md. If you want the list first, run it without --force: the CLI names each file it would replace and writes nothing.

It also wires your workspace; the run names every file it touched and every line it added.

What the scaffold wired

Nothing to do here; the wiring is worth knowing about, not waiting for you.

.postcssrc.json, beside your package.json, so Tailwind runs at all. Without it the chrome renders unstyled while the build reports success (Styles).

Your build target, in angular.json (or project.json under Nx), gains four things:

"styles": ["src/styles.css"],
"assets": [
  { "glob": "**/*", "input": "public" },
  { "glob": "**/*", "input": "node_modules/@loomweaver/shell/i18n", "output": "i18n" },
  { "glob": "**/*", "input": "node_modules/@loomweaver/frame-kit/dist", "output": "frame-kit" }
],

and, in the production configuration:

"serviceWorker": "ngsw-config.json",
"optimization": { "styles": { "inlineCritical": false } }

Each has a reason, told where the manual setup makes the same edit. The i18n glob serves the shell's own strings (Serve the host translations). The frame-kit glob matters only once you host sandboxed plugins (Frame plugins). serviceWorker and inlineCritical: false are the PWA side (PWA and delivery). One trap belongs here: inlineCritical: false is not optional. The generated index.html ships a strict script-src 'self' that blocks Angular's inline critical-CSS handler, and the app then renders unstyled, only in production builds.

The scaffold only adds. A setting you had already made is left exactly as you made it, so re-running a scaffold over a workspace you have configured changes nothing.

Don't want Tailwind? Re-run this step with --styles precompiled and skip the Tailwind packages from step 2; src/styles.css becomes one import of the stylesheet @loomweaver/shell ships pre-compiled. Bringing your own CSS framework says what you give up and how a Bootstrap theme fits.

When a scaffold cannot do something, the run says so and says what it costs to leave undone. Scaffolding lists those cases.

4 · Scaffold a weaver

A weaver is a plugin: where all your own UI and logic live.

npx @loomweaver/cli weaver --id notes --command --shortcut 'mod+shift+n' --out src/notes

Write the chord with the mod token rather than cmd or ctrl; the host binds and displays it per platform. You get a manifest, a routable surface, a rail item, a command, both translation bundles and a starter test, with the capabilities it needs already declared.

What the weaver scaffold wired

Also nothing to do. The weaver scaffold registered the plugin for you, in src/app/app.config.ts: one import at the top of the file,

import { notesPlugin } from '../notes/src';

and three lines in the providers array.

provideTranslationNamespaces('notes'),
provideCapabilityGrants({ notes: ['contributions', 'ui', 'navigation'] }),
...providePlugins(notesPlugin),

The grants are exactly what the weaver's own manifest declares, because the broker is default-deny: an ungranted plugin throws CapabilityError rather than quietly doing less. It also added the assets glob that serves the weaver's translations and the @source entry that emits the utilities its templates use.

It does this only while the composition root still presents the shape the distribution scaffold generated, since that is the shape it knows how to edit. Once you have reshaped it, the scaffold does not guess: it leaves the file untouched, prints the lines above, and says the plugin was not registered.

5 · Run

ng serve

You get the branded chrome: a top bar with your name, logo and the theme and language controls, a rail on the left with your weaver's icon in it, and a collapsible sidebar on each side. Click that icon and the app navigates to /notes, where your surface fills the content area.

The scaffolded product after the first run: the top bar with the product name, the notes weaver open in a tab, the shell's version in the status bar.

That icon in the rail is the whole point: the platform drew every piece of chrome around it, and your plugin only declared what it wanted to contribute.

Navigating there opens a tab, so the pane draws a tab strip above your surface, as it does for every routable surface (The content area).

One thing is deliberately empty, and it names the next thing to build: the home route renders nothing, because no surface claims / yet.

The status bar along the bottom shows the running version, which the shell contributes itself. To put something of your own there, scaffold with --bar-item or copy one behaviour, many triggers.

mod+shift+n fires the command the scaffold registered, which raises a toast: a placeholder action on a real shortcut, there to be replaced.

Two shortcuts are the shell's own and work from this first run: mod+k opens the command search, mod+p the search over everything you have open. The scaffold put both on screen as badges that print their own chord, two lines in your app.config.ts and yours to move or delete; LOOMWEAVER.md says how.

Your first production build warns bundle initial exceeded maximum budget; raise the budgets in your build target as Manual setup → Run describes.

Tidy up

Two files from ng new are now unreferenced: src/app/app.routes.ts and src/app/app.css. The shell owns content routing, and Routing shows that the router itself is unchanged. The starter test src/app/app.spec.ts was replaced by one that boots the shell with your composition root's providers. Beside it, app.config.spec.ts tests something worth testing without mounting anything: that the layout still declares the region ids your contributions target. ng test is green as generated.

The logo at public/logo.svg is the LoomWeaver mark, there so the top bar renders something from the first run; replace it with your own square image whenever you like. It is the app icon too. Until you add a 192 and a 512 raster icon, the browser does not offer installation: see PWA and delivery.


Next:

  • Samples: complete, copyable recipes for the things you will build next.
  • Authoring a weaver: the full contract behind what you just scaffolded.
  • Manual setup: the same app wired by hand, if you want to see every seam.