Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Shell scripts must keep LF endings so their shebang works after checkout
# on machines with core.autocrlf enabled.
*.sh text eol=lf

# Landing site: normalize to LF and exclude from language stats; index.html is
# generated by site/build.js.
site/** text eol=lf linguist-documentation
site/index.html linguist-generated
96 changes: 96 additions & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Pages

on:
push:
branches:
- main
paths:
- 'site/**'
- '.github/workflows/pages.yml'

pull_request:
branches:
- main
paths:
- 'site/**'
- '.github/workflows/pages.yml'

workflow_dispatch:

permissions:
contents: read

concurrency:
group: pages-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
pages-build:
name: pages-build
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
with:
persist-credentials: false

- name: Stage site
shell: bash
run: |
set -euo pipefail
mkdir -p _site/licenses
cp site/index.html _site/index.html
cp site/licenses/OFL-ChakraPetch.txt _site/licenses/
cp site/licenses/OFL-IBMPlexMono.txt _site/licenses/

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '24'
package-manager-cache: false

- name: Install site dependencies
working-directory: site
shell: bash
run: npm ci --ignore-scripts --no-audit --no-fund

- name: Verify committed index.html matches build output
working-directory: site
shell: bash
run: |
set -euo pipefail
node build.js
if ! cmp -s ../_site/index.html index.html; then
echo "::error file=site/index.html::Committed index.html does not match build.js output. Run npm ci and node build.js in site/, then commit index.html."
git diff --stat -- index.html
exit 1
fi
changes="$(git status --porcelain --untracked-files=all -- .)"
if [ -n "$changes" ]; then
echo "::error::Building the site left uncommitted changes under site/."
printf '%s\n' "$changes"
exit 1
fi

- name: Upload Pages artifact
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: _site/

pages-deploy:
name: pages-deploy
needs: pages-build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}

steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ link.LinkObjects.Add(new LinkObject("/orders/1"));

## Additional Resources

- **Project Site:** [brenpike.github.io/Chatter.Rest.Hal](https://brenpike.github.io/Chatter.Rest.Hal/)
- **Source Code:** [GitHub Repository](https://github.com/brenpike/Chatter.Rest.Hal)
- **Core Library:** [Resource.cs](https://github.com/brenpike/Chatter.Rest.Hal/blob/main/src/Chatter.Rest.Hal/Resource.cs)
- **Code Generators:** [Source Generator Project](https://github.com/brenpike/Chatter.Rest.Hal/tree/main/src/Chatter.Rest.Hal.CodeGenerators)
Expand Down
80 changes: 80 additions & 0 deletions site/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Chatter.Rest.Hal landing site

This directory holds the source for the project landing page, published at
https://brenpike.github.io/Chatter.Rest.Hal/.

## Files

- `index.src.html` is the hand-edited page source.
- `build.js` inlines the web fonts into `index.src.html` and writes `index.html`.
- `index.html` is committed build output. Never edit it by hand.
- `licenses/` contains the font license texts.

## Rebuilding

```sh
cd site
npm ci
node build.js
```

Commit the changed source and the regenerated `index.html` together.

## Deployment

The GitHub Pages source for this repository is set to GitHub Actions.
`.github/workflows/pages.yml` publishes the committed `index.html` and the
`licenses/` texts. Before publishing it reinstalls the pinned font packages
(`npm ci`), runs `build.js`, and fails if the output differs from the committed
`index.html`, so rebuild and commit `index.html` before merging.

- A push to `main` that touches `site/**` or the workflow file runs `pages-build`
and then `pages-deploy`.
- A pull request against `main` that touches the same paths runs only
`pages-build`. It never deploys.
- A manual workflow dispatch deploys only when run from `main`. From any other
branch or tag, `pages-deploy` is skipped and the published site does not change.
- Runs are serialized per ref, so at most one run per ref is in progress.
GitHub does not guarantee the order in which queued runs start, so an older
commit can occasionally deploy after a newer one.
- Each run publishes the commit it was started for, and the last deploy to
finish wins. The workflow does not check that this commit is still the tip
of `main`.
- Re-running an older `main` run redeploys that run's commit. This is the
intended rollback path.
- If the published site looks stale, re-run the newest `main` run or push to
`main`.
- A new push to a pull request cancels that pull request's in-progress run.

## Fonts

The page embeds Chakra Petch and IBM Plex Mono, both licensed under the SIL Open
Font License 1.1. The license texts are in `licenses/OFL-ChakraPetch.txt` and
`licenses/OFL-IBMPlexMono.txt`.

## Capture hooks

The page intentionally keeps the `window.seek(t)` hook and its related globals
(`__seam`, `__ready`, `render`). They allow deterministic frame-by-frame capture
of the page animation for screenshots and recordings. Do not remove them.

## Review checklist

- **Accessibility:** the landing copy is in the accessibility tree at every width.
`.mcopy` is the text source and is never `display:none`. The animated stages stay `aria-hidden`.
- **Motion:** rendering is demand-driven. `requestRender()` is the only scheduler and the page
calls `requestAnimationFrame` nowhere else. A frame requests another frame only while
`animating()` is true, and every timeline is clamped to its settle time, so an idle page runs
no frames and makes no DOM writes.
- `sample()` is the only live writer of render state. Every input it reads (clock, scroll position,
viewport height, mode, reduced motion, Act-2 start) must have a subscription that calls `requestRender()`.
- Event handlers never write render state. They only update anchors (such as the Act-2 start time)
and call `requestRender()`.
- Every environment input (width, reduced motion, resize) goes through `applyPresentation()`, the
only reader of `.matches`. Never decide presentation once at load.
- Reduced motion shows the end-state frame and schedules no animation frames.
- After `seek()`, frames never continue on their own. Environment changes re-layout and re-render only.
- The capture hooks (`seek()`, `render`) render synchronously and bypass the scheduler.
- **HAL fidelity:** the Act-2 JSON pane must be token-identical to real serializer output (whitespace aside)
for the Act-2 builder code. Verify against real Chatter.Rest.Hal output when either changes.
- **Render parity:** unrelated edits change no pixels.
11 changes: 11 additions & 0 deletions site/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const fs=require('fs'),path=require('path');
const d=__dirname;
const f=(p)=>fs.readFileSync(path.join(d,'node_modules/@fontsource',p)).toString('base64');
const face=(fam,w,file)=>`@font-face{font-family:"${fam}";font-weight:${w};font-style:normal;font-display:block;src:url(data:font/woff2;base64,${f(file)}) format("woff2")}`;
const css=[
...[400,500,600,700].map(w=>face('Chakra Petch',w,`chakra-petch/files/chakra-petch-latin-${w}-normal.woff2`)),
...[400,500,600].map(w=>face('IBM Plex Mono',w,`ibm-plex-mono/files/ibm-plex-mono-latin-${w}-normal.woff2`)),
].join('\n');
let h=fs.readFileSync(path.join(d,'index.src.html'),'utf8').replace('/*FONTS*/',css);
fs.writeFileSync(path.join(d,'index.html'),h);
console.log('index.html',(h.length/1024).toFixed(0)+'KB');
Loading
Loading