# tui-pages website Static marketing site for the [`tui-pages`](https://gitlab.com/filipriec/tui-pages) Rust crate. No build step required — open `index.html` in a browser and you're done. ## Stack | Layer | Tech | Source | | --- | --- | --- | | HTML | Hand-written semantic | `*.html` | | CSS framework | Tailwind CSS v3 (Play CDN) | runtime | | Components | DaisyUI v4 (prebuilt CSS) | runtime | | Interactivity | HTMX 2 | runtime | | Light JS | Alpine.js 3 | runtime | | Code highlight | highlight.js 11 (Rust, TOML, Bash) | runtime | | Fonts | Inter + JetBrains Mono (Google Fonts) | runtime | | Icons | Lucide (inline SVG) | hand-written | | Page transitions | View Transitions API (native) | n/a | Everything is loaded from public CDNs. The only thing served from this repo is the HTML, our small `static/css/site.css` layer, and the SVG assets in `static/img/`. ## Local development ```bash # Just open the file xdg-open index.html # Linux open index.html # macOS # Or serve it (recommended — gives you a stable URL for htmx) python3 -m http.server 8000 # then visit http://localhost:8000 ``` The `Makefile` wraps the Python server and a few convenience commands: ```bash make serve # python3 -m http.server 8000 (serves the WORKING TREE — use this while iterating) make size # report file sizes make validate # quick HTML syntax check (search for unclosed tags) make tidy # run html-tidy on every .html (warnings only) make video NAME=foo # regenerate the ASCII background from video/foo.mp4 ``` > **Note:** `make serve` reads from the working tree (so it picks up the latest > `static/js/mountain.js` after a `make video`). For a production build, use > `nix run .#serve` — but note that the Nix build only includes **git-tracked** > files, so you must `git add` your new `mountain.js` (and any other new files) > before `nix run .#serve` will pick them up. ## Animated ASCII video background The page background is an **animated chafa ASCII playback of a video**, running at 12 fps behind the entire page. `ffmpeg` extracts frames from a video you provide; `chafa` converts each frame to an 80 × 24 ASCII grid; a bundler (`tools/build_mountain_js.py`) concatenates all grids into a single JS array (`static/js/mountain.js`). A tiny cycler (`static/js/mountain-bg.js`) swaps `textContent` on a single `
` every ~83 ms.

### Swap the video

1. Drop a `.mp4` in `video/`:

   ```bash
   cp ~/Videos/my-clip.mp4 video/myclip.mp4
   ```

2. Build it into the site (run inside the nix dev shell for ffmpeg + chafa):

   ```bash
   nix develop -c make video NAME=myclip
   ```

   This runs three steps:
   - `make video-frames NAME=myclip` — `ffmpeg` extracts PNGs at 12 fps into `build/myclip/`, then `chafa -s 80x24 --symbols ascii` produces ASCII for each
   - `make video-bundle NAME=myclip` — bundles all `frame-*.txt` into `static/js/mountain.js`
   - the wrapper `make video` does both

3. Serve and view:

   ```bash
   make serve
   # → http://localhost:8000
   ```

### Helper targets

```bash
make video-list              # show available videos in video/
make video-frames NAME=foo   # only extract + chafa, skip the bundle
make video-bundle NAME=foo   # only re-bundle from an existing build/foo/
```

### Tuning

- **Frame rate** — edit `Makefile` `fps=12` in the `video-frames` target. If
  you change it, also update `TP_MOUNTAIN_FPS` at the bottom of
  `static/js/mountain.js` (regenerated automatically each `make video`).
- **ASCII resolution** — `-s 80x24` in the `chafa` call. Wider/higher = larger
  bundle, more detail.
- **Bundle size** — the resulting `static/js/mountain.js` is `~1.7 kB × N_FRAMES`
  (333 kB for a 15 s clip at 12 fps). For long videos, drop `fps` or downscale
  the source video first.
```
       ↓ chafa -s 80x24
build/mountain/frame-*.txt   intermediate ASCII grids
       ↓
static/js/mountain.js        bundled 60-frame array (≈120 kB)
       ↓ requestAnimationFrame
DOM   what you actually see, 12 fps
```

To re-render (you need `chafa` and `python3` on `$PATH`, or use `nix develop`):

```bash
make mountain          # frames + bundle, end-to-end
make mountain-frames   # just the PNG + ASCII frames
make mountain-bundle   # just rebundle the JS array from existing frames
```

### How it's wired

- `static/js/mountain.js` exposes `window.TP_MOUNTAIN_FRAMES` (an array of
  60 template strings) plus `TP_MOUNTAIN_N_FRAMES = 60` and
  `TP_MOUNTAIN_FPS = 12`.
- `static/js/mountain-bg.js` mounts a `