Skip to content

Commit 3f9e07e

Browse files
committed
Make the repo production-ready: contract tests, CI, docs, release
src/lib/effects/contract.test.ts adds 195 cases pinning the effect system's invariants: registry length and order match GLOW_VARIANTS, every module parses, every selector is gated on its own [data-glow], every keyframe and @Property name carries its module's namespace (prefix map recorded in the test), and a measured performance cap bounds infinite animations per state. CI gains a reusable checks workflow (svelte-check, vitest, both builds, packaging with publint, pack-smoke) called from a new ci.yml on pushes and PRs, a manual release.yml publishing to npm with provenance, and the Pages deploy now depends on the same gate. README is rewritten as the package story — install, quick start, per-effect imports with the measured 24 KB single-effect footprint, the customization seams, the custom effect authoring path, and the full 39-effect table. Release hygiene: CONTRACT.md ships in the tarball, repository/homepage/keywords metadata added, npm publish --dry-run audited clean at 0.1.0, and the prefers-reduced-motion parity decision is recorded as a labeled follow-up in CONTRACT.md.
1 parent e86ab22 commit 3f9e07e

8 files changed

Lines changed: 696 additions & 87 deletions

File tree

‎.github/workflows/checks.yml‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Reusable check suite for @ui4ai/light-input. Every entry point (CI on push/PR, the Pages deploy,
2+
# and the manual npm release) calls this so the exact same gate guards all of them — no drift
3+
# between "what CI runs" and "what actually ships".
4+
name: Checks
5+
6+
on:
7+
workflow_call:
8+
9+
jobs:
10+
verify:
11+
name: svelte-check · tests · build · package · pack-smoke
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v6
17+
18+
- name: Setup Node
19+
uses: actions/setup-node@v6
20+
with:
21+
node-version: 24
22+
cache: npm
23+
24+
- name: Install dependencies
25+
run: npm ci
26+
27+
- name: Type-check (svelte-check)
28+
run: npm run check
29+
30+
- name: Unit + contract tests
31+
run: npm test
32+
33+
- name: Build demo (client)
34+
run: npm run build
35+
36+
- name: Build GitHub Pages demo
37+
run: npm run build:pages
38+
39+
- name: Package the library (svelte-package + publint)
40+
run: npm run package
41+
42+
- name: Packaging smoke test (tarball + isolation + SSR)
43+
run: npm run pack-smoke

‎.github/workflows/ci.yml‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Continuous integration: run the full check suite on every push to main and every PR targeting
2+
# main. This is the gate that must be green before the Pages deploy runs and before a release can
3+
# be cut. See checks.yml for the actual steps.
4+
name: CI
5+
6+
on:
7+
push:
8+
branches:
9+
- main
10+
pull_request:
11+
branches:
12+
- main
13+
14+
# Cancel superseded runs on the same ref (a new push to a branch/PR obsoletes the previous one).
15+
concurrency:
16+
group: ci-${{ github.workflow }}-${{ github.ref }}
17+
cancel-in-progress: true
18+
19+
jobs:
20+
checks:
21+
name: Checks
22+
uses: ./.github/workflows/checks.yml

‎.github/workflows/pages.yml‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,15 @@ concurrency:
1616
cancel-in-progress: true
1717

1818
jobs:
19+
# Gate the deploy on the same suite CI runs (svelte-check, tests, build, package, pack-smoke).
20+
# A red gate blocks the site update instead of shipping a broken demo.
21+
checks:
22+
name: Checks
23+
uses: ./.github/workflows/checks.yml
24+
1925
build:
2026
name: Build static demo
27+
needs: checks
2128
runs-on: ubuntu-latest
2229

2330
steps:
@@ -33,12 +40,6 @@ jobs:
3340
- name: Install dependencies
3441
run: npm ci
3542

36-
- name: Check
37-
run: npm run check
38-
39-
- name: Test
40-
run: npm test -- --run
41-
4243
- name: Build GitHub Pages demo
4344
run: npm run build:pages
4445

‎.github/workflows/release.yml‎

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Manual npm release for @ui4ai/light-input.
2+
#
3+
# Trigger from the Actions tab (workflow_dispatch). It runs the FULL check suite first and only
4+
# publishes if every check passes, so a broken tree can never ship.
5+
#
6+
# One-time setup required in the repo settings:
7+
# • Secret NPM_TOKEN — an npm automation/granular token with publish rights to the
8+
# @ui4ai scope (Settings → Secrets and variables → Actions → New repository secret).
9+
# • The workflow publishes with --provenance, which needs the `id-token: write` permission
10+
# granted below and a runner on npm ≥ 9.5 (Node 24 ships a newer npm — fine).
11+
#
12+
# Versioning is manual: bump `version` in package.json (e.g. `npm version minor`) and push before
13+
# running this. The publish step is idempotent-safe — npm refuses to republish an existing version,
14+
# so a re-run after a partial failure will not double-publish.
15+
name: Release
16+
17+
on:
18+
workflow_dispatch:
19+
inputs:
20+
dry-run:
21+
description: 'Run npm publish with --dry-run only (no upload)'
22+
type: boolean
23+
default: false
24+
25+
concurrency:
26+
group: release
27+
cancel-in-progress: false
28+
29+
jobs:
30+
# Reuse the exact CI gate. Publishing is blocked unless this succeeds.
31+
checks:
32+
name: Checks
33+
uses: ./.github/workflows/checks.yml
34+
35+
publish:
36+
name: Publish to npm
37+
needs: checks
38+
runs-on: ubuntu-latest
39+
permissions:
40+
contents: read
41+
id-token: write # required for npm provenance
42+
43+
steps:
44+
- name: Checkout
45+
uses: actions/checkout@v6
46+
47+
- name: Setup Node
48+
uses: actions/setup-node@v6
49+
with:
50+
node-version: 24
51+
registry-url: https://registry.npmjs.org
52+
cache: npm
53+
54+
- name: Install dependencies
55+
run: npm ci
56+
57+
# `prepublishOnly` (check + test + package) runs automatically as part of `npm publish`,
58+
# building dist/ and re-validating before anything is uploaded.
59+
- name: Publish (dry run)
60+
if: ${{ inputs.dry-run }}
61+
run: npm publish --provenance --access public --dry-run
62+
env:
63+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
64+
65+
- name: Publish
66+
if: ${{ !inputs.dry-run }}
67+
run: npm publish --provenance --access public
68+
env:
69+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

‎CONTRACT.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,30 @@ its entrance pose. If your effect adds infinite motion on other layers, add a ma
281281
`.stage[data-glow='my-effect'][data-light-flow='off'] … { animation: none }` so "flow off" is
282282
honored.
283283

284+
### `prefers-reduced-motion` — current parity (FOLLOW-UP)
285+
286+
Known limitation for `0.1.0`, recorded here so it is not mistaken for a bug. `core.css` carries a
287+
`@media (prefers-reduced-motion: reduce)` block that sets `animation: none` on the base anatomy
288+
(`.field::before`, `.caret`, `.torch-beam`, `.beam`, `.next-word`, `.tail`). Those rules are (0,2,0),
289+
so a per-effect module's own animation — set at `.stage[data-glow='x'] .field[data-glow] .beam-veil`
290+
(0,5,0) — **overrides** the reduced-motion kill. Net effect today: the default torch layers quiet
291+
down under reduced-motion, but each effect's signature animations keep running (a deliberate
292+
visual-identity choice, not real support).
293+
294+
**If your effect must honor reduced-motion**, add your own scoped kill:
295+
296+
```css
297+
@media (prefers-reduced-motion: reduce) {
298+
.stage[data-glow='my-effect'] .field[data-glow] .beam-veil,
299+
.stage[data-glow='my-effect'] .field[data-glow] .beam-hot {
300+
animation: none;
301+
}
302+
}
303+
```
304+
305+
Making this the package default for all 39 effects (emitting the scoped `animation: none` at (0,5,0)
306+
under the media query in every module) is a tracked follow-up.
307+
284308
---
285309

286310
## 7. The var()-in-custom-property pitfall (read this)

0 commit comments

Comments
 (0)