- JavaScript 98%
- HTML 0.9%
- Shell 0.6%
- Dockerfile 0.5%
| docs/superpowers/plans | ||
| public | ||
| src | ||
| tests | ||
| .containerignore | ||
| .gitignore | ||
| Dockerfile | ||
| index.html | ||
| nginx-site.conf | ||
| nginx.conf | ||
| pulserun.container | ||
| README.md | ||
| SPEC.md | ||
PULSE RUN — dev setup
This environment has no Node.js/npm (no root access to apk add nodejs npm, Nix daemon
unavailable). The project is plain ES module JavaScript with no build step, as a deliberate
deviation from SPEC.md §3 (TypeScript + Vite + Vitest), agreed with the project owner.
Run it
python3 -m http.server 8000
Then open http://localhost:8000/ in a browser (landscape / mobile-width devtools emulation
recommended).
Run tests
bash tests/run.sh
This launches headless Chromium against tests/run.html, which imports every tests/*.test.js
file and runs it through the harness in tests/harness.js. Exits non-zero if any test fails.
Why no TypeScript / bundler / lint
- No compiler is run; public functions carry JSDoc
@param/@returnscomments instead of compiler-checked types. - No bundler:
index.htmlloadssrc/main.jsas a native ES module; browsers resolve theimportgraph directly. Bundle-size budgets from SPEC.md §17 are approximated by summing raw file sizes rather than measured with a gzip-bundle report. - No ESLint/Prettier: formatting is kept consistent by hand.
If Node/npm become available later, migrating to Vite + TypeScript + Vitest per the original SPEC.md §3 is straightforward since module boundaries already match that structure.
Deploy with plain nginx (no containers)
The app is just static files, so if you already have nginx running on the host, the simplest deploy is to copy the files into place and point a site config at them — no image, no Podman.
sudo mkdir -p /var/www/pulserun
sudo cp -r index.html src public /var/www/pulserun/
sudo cp nginx-site.conf /etc/nginx/sites-available/pulserun
sudo ln -s /etc/nginx/sites-available/pulserun /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Edit server_name in /etc/nginx/sites-available/pulserun first if you're not using the
default catch-all. To pick up a new build after changing the source, just re-run the cp -r
step — no nginx reload needed, since it's static files with no config change.
Deploy with Podman
If you'd rather not touch the host's nginx (e.g. it's shared with other sites, or you want the
app process-isolated and independently restartable/updatable), the same app also ships as a
container. The container is just nginx pointed at index.html/src/public
(Dockerfile, nginx.conf). Build it locally:
podman build -t localhost/pulserun:latest .
Then either run it directly:
podman run -d --name pulserun -p 8000:8080 localhost/pulserun:latest
...or, on a systemd host, install the included Quadlet unit so systemd manages it:
sudo cp pulserun.container /etc/containers/systemd/pulserun.container
sudo systemctl daemon-reload
sudo systemctl start pulserun.service
pulserun.container requires Podman ≥ 4.4 for native Quadlet support (its own header comment
has version notes for Debian 12 vs 13). Open http://<host>:8000/ either way. The service
worker only enables offline/installable-PWA behavior over a secure context (HTTPS or
localhost) — served plain over HTTP on a LAN hostname, the game still works, it just won't
offer install/offline; put a TLS-terminating reverse proxy in front if you want that.
To pick up a new build after changing the source: rebuild the image, then
systemctl restart pulserun.service (or podman auto-update, since the unit sets
AutoUpdate=local).