Contributing
Alabaster takes issues, translations, theme packs, and code.
Getting set up
Development setup covers Node.js versions, the dev server, the Docker service, and this documentation site.
The short version:
npm install && npm run devnpm run checknpm run check is the gate: formatting, linting, type-checking, every test, and the production build. A change is not finished until it passes.
Work happens on develop. main carries releases and this site.
The cheapest ways to help
Translate it. English is the source locale. To add a language, copy src/locales/en.json, keep the same keys, and skip code changes entirely. A test fails the build if a locale is missing a key or has an empty message, so partial translations cannot ship.
Write a theme pack. A theme pack needs one CSS file, one registry line, and a label in each locale. See Theming for the steps and the constraints.
File a good bug. The console's Show Klipper's own prefixes option keeps the raw !! and // markers in place. This lets you copy a line into an issue verbatim.
Rules that are enforced by tests
These fail the build. They are not review preferences.
| Rule | |
|---|---|
| Every control variant clears 4.5:1 contrast over every surface, at rest, hovered, and pressed | Composited, not eyeballed |
| Chromatic color comes only from the Okabe-Ito palette, and no component carries a color literal | |
| Every animation has a reduced-motion fallback | |
| Every clickable control uses a documented button variant and size, and none move on hover or press | |
| Every routed page uses one of two documented page shells | |
| Every locale matches the English schema, with no empty messages | |
| Every theme pack implements the full token contract in light and dark |
Rules that reviewers enforce
- No literal user-facing text in a component. Add an English key, mirror it in every locale, render it through Vue I18n. This includes
aria-label,title, placeholders, validation, and notification text. - No color literals. Components use semantic tokens. Palette primitives live only in the theme sources.
- Color is never the only carrier of status. Pair it with text or a distinct shape.
- No
window.confirm,window.prompt, orwindow.alert. Every confirmation is a real dialog that names what it will touch. The Confirmations list also tracks it. - Never reload the application or replace the route during a Moonraker, Klipper, or firmware restart. Keep last-known data mounted and mark it stale.
- Never replay a mutating command after reconnecting. Surface the failure and require an explicit retry.
- Any field showing remote data must subscribe to the notification that reports its change. A one-time snapshot that goes stale until the next page load violates this rule. If no notification exists, add explicit polling instead of freezing the value.
- Verify at desktop width and at 390 px. Neither the page nor a toolbar may scroll sideways.
Where the standards live
Alabaster keeps internal design and architecture documents. Each of these areas has its own document: page layout and shared UI, navigation, buttons, dialogs, module settings, the dashboard module contract, motion, availability and reconnection, the Moonraker transport, the frontend stack, and deployment. These documents are not part of this repository's public checkout, so you cannot open them directly. They are binding on every change: code and documents must agree.
If your change touches one of these areas, say so in the issue or pull request before you design a solution. A reviewer can tell you what the document already settled, so you don't reinvent a decision that already exists.
Editing this site
The published documentation lives in website/, built with VitePress:
npm run docs:devTwo rules for what goes in it:
- Lead with what a reader can accomplish. Never narrate what the screen already shows.
- Never copy developer-facing phrasing from the repository's own contributor documents into user-facing text. They constrain implementation. They do not describe the product.
Every page has an Edit this page on GitHub link at the bottom.
Prior art
Alabaster's design draws on Mainsail and Fluidd. Both interfaces have years of production use, and they already settled much of what a Moonraker client needs to get right. Alabaster's own design documents came from a survey of both. Referencing what either does, for Moonraker behavior or for UI patterns worth carrying over, is welcome. Copying their Vue 2 / Vuex / Vuetify implementation is not.