#Contributing

#Commands

bun install
bun test                       # the full suite
bun run typecheck
bun run docs                   # rebuild this site into site/
bun run playground             # rebuild preview/playground.html
bun run preview                # rebuild preview/contact-sheet.png
bun run convert-assets         # regenerate src/data/*.json from vendor/
bun run sync-backend-snapshot  # refresh the backend catalogue snapshot (monorepo only)

#Layout

src/
  body/       geometry loading, types, and intensity resolution
  color/      OKLCH conversion and the intensity scale
  core/       the platform-agnostic renderer and its primitives contract
  data/       GENERATED body maps - never hand-edit
  muscles/    the 49-code catalogue
  index.ts    pure exports (no React)
  native.tsx  react-native-svg entry
  web.tsx     DOM SVG entry
docs/         this documentation, as Markdown
playground/   the interactive playground app
scripts/      converters and site builders
vendor/       upstream artwork, kept for re-conversion

#What is generated

Four things, all rebuilt from a source of truth rather than maintained by hand:

Output Built from By
src/data/*.json vendor/ artwork convert-assets
site/ docs/*.md + the live catalogue docs
preview/playground.html playground/ + the real package playground
tests/fixtures/backend-muscle-catalogue.json core-service constants sync-backend-snapshot

The documentation tables for the catalogue, coverage matrix and intensity ramp are generated from the actual exports at build time. A hand-written table drifts; a generated one cannot.

#Invariants the tests protect

These are the things that would break quietly, so they each have a test:

  • Backend parity. All 49 codes, names and statuses match the backend catalogue. Inside the monorepo this checks the live Python file and that the committed snapshot still agrees with it; standalone, it checks the snapshot alone and skips the comparison.
  • One-hop aliases. No alias points at another alias. Every code resolves to a drawn region.
  • Every extended code states a reason. aliasOf and aliasNote are both required.
  • The resolution breakdown. 23 drawn, 18 splittable, 5 deep, 3 side-view - so the documented counts cannot go stale.
  • Coverage. All 23 drawn regions appear on at least one diagram, and no code is unrenderable across all four.
  • The female back omits exactly ANK and HEA. Keeps the artwork and the backend's "Both (Front only for female)" annotation in agreement.
  • Merge semantics. Collisions take the maximum, and order does not matter.
  • Colour. Anchors return exactly; out-of-range clamps; OKLCH beats sRGB blending on chroma at the midpoint.
  • The playground actually runs. The built HTML is loaded into a DOM and executed. It also asserts the file contains exactly one </script> - React DOM embeds the literal string "<script></script>", and an unescaped copy closes the tag early, leaving the browser to render the rest of the bundle as visible text.

#Publishing the docs

bun run docs writes a fully static site to site/ - plain HTML with relative links, so you can open site/index.html straight from disk with no server.

The GitHub Actions workflow at .github/workflows/docs.yml builds and deploys the same output to GitHub Pages on every push to the default branch. Pages needs to be enabled once, under Settings → Pages → Source: GitHub Actions. On a private repository this requires a paid GitHub plan; on a public repository it is free.

#Before open-sourcing

  • Remove "private": true from package.json.
  • Claim the @gravn npm scope, or rename the package.
  • Confirm NOTICE and LICENSE both ship - the upstream MIT attribution is a licence obligation, not a courtesy.