Decisions SW-362 and later
Decisions, newest first
Section titled “Decisions, newest first”SW-385 — Design site v2.0: grouped sections, long pages split, wide layout
Section titled “SW-385 — Design site v2.0: grouped sections, long pages split, wide layout”- Date: 13 November
- Decision: The site is organised like an established design system: Start here, Brand, Foundations, Motion,
Components and patterns, Content, Rules and Reference, each group collapsed until you open it. Long docs are
published as an overview (the doc’s introduction plus an “On this topic” list) and one page per part; the
Markdown sources stay single files, the split is defined in
site/scripts/split-docs.mjs, and links to an anchor that moved are rewritten. The content column is wide (76rem) so tables, swatches, demos and matrices use the room, while running text keeps a ~72-character line; between 72rem and 90rem the right-hand contents column folds into the “On this page” bar so the content is not squeezed; wide matrices pin their first column and scroll sideways only when they cannot fit. No content was removed: a content inventory of every heading, paragraph, table row, image and link before and after the change matched. - Why: The owner said: “break long pages into splits, proper grouping, and some pages, even though the screen has room, look squished; fix that in the design system. A proper v2 update”, and “make it a proper design system: don’t remove any content, but well placed”. The rules, decisions and UX spec pages were single walls of 20,000 to 50,000 pixels, and the reading column was about 690 px wide on a 1280 px laptop.
- Status: current.
- Implemented in:
site/astro.config.mjs(sidebar),site/scripts/split-docs.mjs,site/scripts/sync-split.mjs,site/src/styles/custom.css(layout),site/src/content/docs/index.mdx(home),site/src/content/docs/foundations.mdx.
SW-383 — Pipelines, versions and releases page
Section titled “SW-383 — Pipelines, versions and releases page”- Date: 13 November
- Decision:
docs/delivery.mdrecords how every SpaceWorks-Labs repository checks, versions and releases its work: the general rules (dev, then PR, then main; required checks; nothing merges red; semver inVERSION; releases built by CI only when a newVERSIONreaches main; secrets only in GitHub), the pipeline of each of the five stacks, a table of where each repository stands today, and the gaps to close. It is published on the site next to the product rules. - Why: The owner said: “in the design system also mention the pipeline — GitHub Actions and workflows, version, release and all — per stack”. The product rules said what to do in one line; nobody could see which repository actually did it, so gaps (no version-bump check on the Next.js apps, no signed Android or iOS releases, no CI on the website) stayed invisible.
- Status: current.
- Implemented in:
docs/delivery.md,docs/product-rules.md(section 12 pointer),site/scripts/sync-extra.mjs,site/astro.config.mjs(sidebar entry).
SW-382 — This release is “Space Works Design System v2.0”
Section titled “SW-382 — This release is “Space Works Design System v2.0””- Date: 13 November
- Decision: The design system has its own version: this release is Space Works Design System v2.0
(
VERSION=2.0.0), which ships alongside SpaceWorks 0.12.0. The app’s version is named only when describing the app. “What changed in 0.12.0” becomes “What’s new in v2.0”:docs/whats-new-v2.0.md(the olddocs/design-changes-0.12.0.mdstays as a pointer) and the site page/whats-new-v2/(the old/whats-new/redirects). The site header shows the version. - Why: The design system ships on its own schedule and is used by several products, so tying its name to one app’s release number confused which version of the kit a product followed. Reason beyond that not recorded.
- Status: current.
- Implemented in:
VERSION,docs/whats-new-v2.0.md,README.md(changelog heading),site/astro.config.mjs(redirect),site/src/components/SiteTitle.astro(badge).
SW-381 — Logo box animation: one orange face when shut, no holes in dark, frame-checked
Section titled “SW-381 — Logo box animation: one orange face when shut, no holes in dark, frame-checked”- Date: 13 November
- Decision: The box animation (logo hover
hov, loaderloop, splashonce,mono, the forced grounds) has defined states and a frame check. Rest is the static logo exactly; shut is one solid cube whose lid is the outer pair (top-right over bottom-left), so in light it shows exactly one orange face; a flap changes colour only edge-on, showing its outer face past it; the reversed (dark) artwork shows a cream cap behind the front flaps from the first moving frame; moving flaps are outlined in the ground colour; flaps are painted in depth order (top-right drawn in two layers); the fold is staggered so no flap passes through another. Timings are unchanged except the fold’s stagger inside the same 600 ms (hover) and 968 ms (loader). - Why: The owner reported two bugs: in dark, “blank black areas” (holes in the box) appeared while the flaps moved; in light, “when the box is closed there are two orange faces; closed should show one orange, open shows two”. Root causes: the reversed master cuts its side faces short under the front flaps and the cap that fills them only appeared when the box was nearly shut; the bottom-left flap swapped to teal at 105 degrees instead of at edge-on (56), so its orange showed while the lid was still closed, and it was painted under the lid it rises in front of; the shut flaps did not reach each other, leaving a slot; and folding all four flaps together made neighbours pass through each other. The owner asked to make it “accurate” and checked frame by frame.
- Status: current.
- Implemented in:
motion/box-open/(generatedbox-open.cssand markup,react/boxOpen/, README “Known-good states”),scripts/check-box-frames.mjs,docs/motion.md,docs/lessons-learned.md(lesson 39). App:frontend/src/components/boxOpen/(generator andboxOpen.frames.test.ts),components/brand/, theindex.htmlsplash.
SW-380 — One bright chart palette in light and dark; contrast from edges
Section titled “SW-380 — One bright chart palette in light and dark; contrast from edges”- Date: 13 November
- Decision: Chart series use the five bright brand colours (teal, orange, citron, sky, yellow), the same hex
in light and dark (
--chart-1to--chart-5). The 3:1 contrast for graphics comes from--chart-edge: a 1px edge on every filled mark and a 4px casing under every 2px line (Deep Ink in light, Warm Cream in dark), with the dash patterns kept so colour is never the only cue. Danger red is not a series colour. - Why: The owner said: “use the same bright colours in light and dark too, the bright colours SpaceWorks uses, like in charts”. One brand palette should look the same everywhere; the old chart set dulled the colours (ink shades in light, a mix in dark) to pass contrast. Contrast is solved with edges, not by dulling colours.
- Status: current. Changes the chart rule of lesson 13 (history kept there).
- Implemented in:
tokens/tokens.css,tokens/tokens.json(chart),docs/theming.md,docs/lessons-learned.md,docs/ui-brand-spec.md,site/src/components/ThemeDemo.astro; appfrontend/src/styles/chrome.cssand the report chart components.
SW-379 — Push to main now; every change ships with tests; this decisions file
Section titled “SW-379 — Push to main now; every change ships with tests; this decisions file”- Date: 13 November
- Decision: Push what is finished in this repo to
mainnow (dev, then PR, then merge); work still in progress follows in later PRs. The product rules state that every change ships with its tests, by change type. This file records every design decision with its reason. - Why: The owner wanted the finished work published without waiting for the unfinished lanes, and wanted the reasoning kept (“so that the reason is not lost”). Reasons are the first thing lost in a fast build.
- Status: current.
- Implemented in:
docs/decisions.md(this file); the testing rule is indocs/product-rules.md.
SW-378 — Search field animation
Section titled “SW-378 — Search field animation”- Date: 13 November
- Decision: One shared search field with a focus ring and icon nudge, a shortcut chip that fades on focus, the magnifier becoming the small box spinner while loading, a clear button that fades in (Escape also clears), and results that fade in with a 4 px rise and at most six staggered items. Reduced motion means colour change only.
- Why: About 46 search inputs in the app each behaved a little differently. One component removes the differences and gives the design system one reference template. Reason beyond that not recorded.
- Status: current. In progress:
motion/search/is not in this repo yet. - Implemented in: app: shared
SearchField(all search inputs migrated, with a guard test). Design repo (planned):motion/search/, a preview, a site page and a row indocs/motion.md.
SW-377 — Every animation becomes a reusable template
Section titled “SW-377 — Every animation becomes a reusable template”- Date: 13 November
- Decision:
docs/motion.mdis checked against the app, and every animation family (route change, page enter, scroll reveal, overlays, toast, sidebar, skeleton, hover and press, feedback, kiosk and TV display) gets its ownmotion/<family>/folder with token-based CSS and JS, React copies, a light and dark demo, a README, animated previews covered by the freshness check, and a site page. - Why: Other apps (Android, iOS, sibling web apps) must be able to copy an animation and get exactly the same feel; a description alone drifts. Reason in the ledger is brief; this is the intent of the template folders.
- Status: current. In progress: only
motion/box-open/andmotion/theme-reveal/exist so far. - Implemented in:
motion/,docs/motion.md,scripts/check-previews.mjs.
SW-376 — Theme-switch animation as a template
Section titled “SW-376 — Theme-switch animation as a template”- Date: 13 November
- Decision: The light/dark switch animation (a circle growing from the toggle, 720 ms, plain cross-fade where unsupported, instant under reduced motion) ships as a copy-paste template, and the design site’s own toggle uses it.
- Why: It is the app’s signature theme moment; shipping it as a template lets every product switch theme
the same way, and using it on the site keeps the template honest. The held final frame exists so the old
theme never flashes (lesson 29 in
docs/lessons-learned.md). - Status: current.
- Implemented in:
motion/theme-reveal/(CSS, plain JS, React, demo, preview),docs/theming.md,docs/motion.md. App: the theme toggle component.
SW-375 — Org-wide rules: hybrid per part, mobile analytics SDKs
Section titled “SW-375 — Org-wide rules: hybrid per part, mobile analytics SDKs”- Date: 13 November
- Decision: For every product, “hybrid” hosting means a choice per part (database, Redis, storage, email, website each local or outside), and the installer asks about and checks each. Android and iOS must support the same optional analytics providers as the web where an official mobile SDK exists: off by default, set per deployment, no personal data, with a client tag. Every gap found becomes a required rule plus a per-product “bring up to the rules” checklist; products are updated after 0.12.0.
- Why: The products had drifted: the web offered analytics providers the phone apps did not, and “hybrid” meant different things in different places. Reason beyond that not recorded.
- Status: current.
- Implemented in:
docs/product-rules.md(rules and per-product status matrix).
SW-374 — Rename to SpaceWorks-Design-System; dev, then PR, then main; owner-only commits
Section titled “SW-374 — Rename to SpaceWorks-Design-System; dev, then PR, then main; owner-only commits”- Date: 13 November
- Decision: The repository is
SpaceWorks-Labs/SpaceWorks-Design-System(site atspaceworks-labs.github.io/SpaceWorks-Design-System/). Work is committed ondevby the owner with no AI co-author trailers, pushed, a pull request is opened tomain, and for this repository the owner has authorised merging it. The site base path and every link move to the new name. - Why: The new name says what the repo is (a system, not just a “design” folder) and matches the org’s
other repos. The pull-request step means the site build and checks run before anything reaches
main. The no-trailer rule (also stated in SW-235 and SW-299) is the owner’s choice for this repo; reason not recorded. Older commits that already carry trailers are left as they are, history is not rewritten. - Status: current.
- Implemented in:
.github/workflows/deploy-site.yml(builds on pull requests, publishes on push tomain),site/astro.config.mjs,README.md.
SW-373 — Brand guidelines v2
Section titled “SW-373 — Brand guidelines v2”- Date: 13 November
- Decision: A second guidelines PDF, same visual family as v1, updated for release 0.12.0: the solid black dark palette and the shift, logo in motion, colour with real contrast ratios, free fonts only, theming, motion, Patch on dark, UX and product-rule summaries, accessibility. v1 is kept, not replaced.
- Why: v1 predates the black dark theme, the loader and the font change, so it would mislead anyone using it alone. Keeping v1 preserves the original approved record. The v2 source is HTML so it can be rebuilt.
- Status: current. Files exist in the working tree but were not yet committed when this was written.
- Implemented in:
brand/space-works-brand-guidelines-v2.pdf,brand/guidelines-v2/;brand/space-works-brand-guidelines-v1.pdfstays.
SW-372 — README banner with rounded corners and the logo
Section titled “SW-372 — README banner with rounded corners and the logo”- Date: 13 November
- Decision: The design repo README gets a rounded-corner banner with the logo (light version on Warm
Cream, dark version on solid black, switched with a
<picture>element), a tidied intro and a complete Contents table. - Why: The README is the first thing people see on GitHub; the owner asked for a professional first impression. Light and dark versions follow the reader’s colour scheme.
- Status: current.
- Implemented in:
brand/readme/banner-light.svg,banner-dark.svg,make-banner.py,README.md.
DS-1 — Banner text is outlined, not live fonts
Section titled “DS-1 — Banner text is outlined, not live fonts”- Date: 12 to 13 November
- Decision: The banner generator converts the Gilroy and Outfit text into outlined paths instead of relying on installed fonts.
- Why: GitHub displays SVGs without custom fonts, so live text would fall back to a system font and lose
the brand type. Outlines show the brand fonts with no font dependency (stated in
make-banner.py). The README changelog’s mention of a “system-font fallback stack” describes an earlier approach. - Status: current.
- Implemented in:
brand/readme/make-banner.py(needsfonttools), the two banner SVGs.
SW-371 — Preview freshness check
Section titled “SW-371 — Preview freshness check”- Date: 13 November
- Decision: A lock file holds hashes of
tokens/tokens.jsonandmotion/box-open/box-open.css(and the other sources). A check fails if a preview image no longer matches its source. It runs in the deploy workflow, next to the site’s token-drift check and link validator. - Why: Preview images (palette cards, animated loaders) are generated files; without a check they quietly go stale after a token change and the site shows colours the product no longer uses.
- Status: current.
- Implemented in:
scripts/make-previews.mjs,scripts/check-previews.mjs,scripts/lib-previews.mjs,scripts/previews.lock.json,.github/workflows/deploy-site.yml.
SW-370 — Design images follow the new palette
Section titled “SW-370 — Design images follow the new palette”- Date: 13 November
- Decision: Palette previews (light, dark, side by side) are generated from
tokens.json; the box loader and the fold-then-open logo hover get animated previews rendered from the real CSS; the 24-plus Space Works UX screenshots are recaptured from 0.12.0 under the same file names. Brand guidelines v1 page images stay as the original. - Why: Images that are drawn by hand or captured once drift from the real palette. Generating them from the tokens and the real CSS means they cannot disagree with the product.
- Status: current. Palette and animation previews exist; the screenshot recapture was still in progress.
- Implemented in:
tokens/previews/,motion/**/preview*,screenshots/ux/(list inscreenshots/ux/RECAPTURE.md).
SW-369 — Product rules apply to every SpaceWorks-Labs product
Section titled “SW-369 — Product rules apply to every SpaceWorks-Labs product”- Date: 13 November
- Decision:
docs/product-rules.mdis widened from one product to all of them (SpaceWorks, Workspace, Events, Machines, Inventory, Bookings, Organization, Android, iOS, website, docs): stack, one-line install and VPS default, self-host, managed and hybrid, areas and modules, role-based views, file size, money, audit trails, analytics, API and mobile parity, tenancy, languages, accessibility, themes, motion, testing and release, with a per-product status table checked against the org repos. - Why: The rules were being re-learned product by product. One shared set, with an honest status per product, shows where each one still falls short.
- Status: current.
- Implemented in:
docs/product-rules.md; site page “Rules”.
SW-368 — Product and engineering rules page
Section titled “SW-368 — Product and engineering rules page”- Date: 13 November
- Decision:
docs/product-rules.mdrecords the rules every Space Works product follows (file size about 200 lines with a 300 ceiling, areas switched off are hidden everywhere, role-based views, tenancy and privacy, audit and evidence, API rules, money, languages, accessibility, themes, motion, tokens, testing and release). Each rule says why it exists, how to apply it and how SpaceWorks enforces it. - Why: So a new app or contributor can follow the same rules without reading the whole codebase, and so each rule carries its reason.
- Status: current (widened by SW-369).
- Implemented in:
docs/product-rules.md.
SW-367 — Logo hover: fold shut, then open
Section titled “SW-367 — Logo hover: fold shut, then open”- Date: 13 November
- Decision: On hover, starting from the resting open logo, the box folds shut and then opens (no hold at the end). Leaving mid-way lets the cycle finish, so nothing snaps. The mark’s box-open is the one hover-motion exception named in the UI spec.
- Why: Reason not recorded in the ledger beyond “softened”; the point of the rule is no jump or snap in either direction.
- Status: current.
- Implemented in:
motion/box-open/,docs/motion.md,docs/ui-brand-spec.mdsection E.
SW-366 — “What changed in 0.12.0” page
Section titled “SW-366 — “What changed in 0.12.0” page”- Date: 13 November
- Decision: A page for designers and the other app teams: the dark-mode shift with before and after per token, logo animation, every animation and where it is used, and the UX improvements to copy.
- Why: The Android, iOS and sibling web teams need to know exactly what to change to match 0.12.0.
- Status: current.
- Implemented in:
docs/whats-new-v2.0.md(first published asdocs/design-changes-0.12.0.md); site page “What’s new in v2.0”.
SW-365 — Lessons-learned page
Section titled “SW-365 — Lessons-learned page”- Date: 13 November
- Decision: Every design lesson from the build, written as a rule with the problem, rule, values, how it is enforced and its source, plus a light and dark pairing table with contrast ratios. Colour matching in light and dark is the main subject.
- Why: Dark mode was redone three times in a month and several contrast mistakes were repeated; writing the lesson next to the rule stops the next app repeating them.
- Status: current.
- Implemented in:
docs/lessons-learned.md; site page.
SW-364 — Motion guide and theming guide
Section titled “SW-364 — Motion guide and theming guide”- Date: 13 November
- Decision:
docs/motion.mdsays which animation to use where (sensible defaults, and what not to animate);docs/theming.mdsays how to build the light, dark and system switch with these palettes (tokens,html.dark, a script that runs before first paint so there is no flash,theme-color, logo, chart and loader variants, HTML, JS and React examples). The site gets a Theming page with a live switch and light and dark side by side on the colour page. - Why: Having tokens without guidance on using them leads to inconsistent motion and flash-of-wrong-theme bugs in other apps.
- Status: current.
- Implemented in:
docs/motion.md,docs/theming.md, site Theming and Motion pages.
SW-363 — Design site shows the real palette, generated from tokens
Section titled “SW-363 — Design site shows the real palette, generated from tokens”- Date: 13 November
- Decision: The site shows the solid black dark family and the current light set on every page, generated from the tokens so it cannot drift, and shows the motion (header logo opens on hover and focus, a Motion section with the catalogue, live loader demos and motion tokens).
- Why: The site had been showing the old green-tinted dark palette after the app moved on. Colours typed
by hand into a site are the usual source of this; generating them from the tokens, plus a build check that
tokens.cssandtokens.jsonagree value for value, makes drift fail the build. - Status: current.
- Implemented in:
site/scripts/sync-kit.mjs,site/scripts/check-tokens.mjs,site/src/,tokens/.
SW-362 — The logo opens on hover and focus, everywhere
Section titled “SW-362 — The logo opens on hover and focus, everywhere”- Date: 13 November
- Decision: The Space Works mark plays a one-shot box opening (1600 ms) on pointer hover and keyboard focus wherever it appears, through one shared component. It never loops except as the loader. Tenant logos never animate. No hover animation on touch devices. Reduced motion shows the still mark.
- Why: A small brand moment that is the same everywhere. Touch is excluded because hover effects stick after a tap; tenant logos are excluded because they belong to the makerspace, not to us; reduced motion is a designed state, not an afterthought.
- Status: current (softened by SW-367).
- Implemented in:
motion/box-open/,docs/motion.md. App:AnimatedLogoMark.
Part of Design decisions, with the reason for each, published from docs/decisions.md. Edit it there.