commit d5b89decce3fee0676dd96522c7867f8eed946fc
parent 001e26b7497c2ad35770e162656bdca46bb96ef5
Author: Kyle Barlow <kb@kylebarlow.com>
Date: Mon, 17 Aug 2026 20:48:30 -0700
Self-host git on NearlyFreeSpeech; drop Codeberg
Point "Open source" at https://www.keyboard.games/code/, a static stagit
code browser served alongside a dumb-HTTP clone source. Nothing runs
server-side: the mirror and HTML are generated locally by deploy.sh and
rsynced up, and a pre-push hook runs the deploy on every push to origin.
tools/stagit-style.css restyles the browser to the site palette.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C3gaidQGTXzcyXKfEaw45a
Diffstat:
4 files changed, 204 insertions(+), 1 deletion(-)
diff --git a/CLAUDE.md b/CLAUDE.md
@@ -136,6 +136,23 @@ unchanged — game logic never references this module.
9. Add browser test cases to `tests/browser/runner.js`
10. Run `npm test` — all must pass before committing
+## Hosting & deploy
+
+The project is self-hosted on NearlyFreeSpeech — there is no Codeberg/GitHub forge.
+
+- `origin` is `ssh://…@ssh.nyc1.nearlyfreespeech.net/home/private/kgames.git`
+ (a bare repo outside the document root).
+- A **`pre-push` hook** runs `deploy.sh` on every push to `origin`, which rsyncs
+ the site, refreshes the restic-backed mirror at
+ `/media/bespin/kyle/backups/gits/kgames.git`, and publishes a static
+ [stagit](https://codemadness.org/stagit.html) code browser + dumb-HTTP clone
+ source to `https://www.keyboard.games/code/`. Skip with `KG_SKIP_DEPLOY=1`.
+- `deploy.sh` and the hook are **untracked**, so a fresh clone does not reproduce
+ this setup — copies plus restore notes live in
+ `/media/bespin/kyle/backups/gits/kgames-untracked/`.
+- The mirror is deliberately **never repacked** so restic dedups its objects.
+- `tools/stagit-style.css` is the code browser's stylesheet (site palette).
+
## Color palette
`#E63946` red · `#1D7CF2` blue · `#FFD23F` yellow · `#2EC4B6` teal
diff --git a/README.md b/README.md
@@ -58,6 +58,17 @@ Standard static file hosting. No `.htaccess` tricks needed.
4. Add unit tests in `tests/unit/` and browser test cases in `tests/browser/runner.js`
5. Run `npm test` — must pass before committing
+## Source
+
+Browse the code at <https://www.keyboard.games/code/>, or clone it:
+
+```
+git clone https://www.keyboard.games/code/kgames.git
+```
+
+The browser and the clone URL are static files generated by
+[stagit](https://codemadness.org/stagit.html) — no forge, no server-side code.
+
## License
GPL-3.0 — see [LICENSE](LICENSE)
diff --git a/index.html b/index.html
@@ -22,7 +22,7 @@
</main>
<footer>
- <p><a href="https://codeberg.org/ursidaureus/keyboard_games">Open source</a></p>
+ <p><a href="https://www.keyboard.games/code/">Open source</a></p>
</footer>
<script src="js/main.js"></script>
diff --git a/tools/stagit-style.css b/tools/stagit-style.css
@@ -0,0 +1,175 @@
+/* KGames stylesheet for the stagit-generated code browser.
+ Based on stagit's default style.css, recoloured to the site palette:
+ #E63946 red · #1D7CF2 blue · #FFD23F yellow · #2EC4B6 teal */
+
+body {
+ color: #2b2b2b;
+ background-color: #FFF5F5;
+ font-family: 'Fredoka', system-ui, sans-serif;
+ margin: 1.2em;
+}
+
+pre, td.num, #blob, .code, pre a {
+ font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
+}
+
+a {
+ color: #1D7CF2;
+}
+
+a:hover {
+ color: #E63946;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-size: 1em;
+ margin: 0;
+}
+
+h1 {
+ font-size: 1.4em;
+ font-weight: 600;
+}
+
+img, h1, h2 {
+ vertical-align: middle;
+}
+
+img {
+ border: 0;
+}
+
+a:target {
+ background-color: #FFD23F;
+}
+
+a.d,
+a.h,
+a.i,
+a.line {
+ text-decoration: none;
+}
+
+#blob a {
+ color: #9a9a9a;
+}
+
+#blob a:hover {
+ color: #1D7CF2;
+ text-decoration: none;
+}
+
+table thead td {
+ font-weight: 600;
+}
+
+table td {
+ padding: 0.1em 0.5em;
+}
+
+#content table td {
+ vertical-align: top;
+ white-space: nowrap;
+}
+
+#branches tr:hover td,
+#tags tr:hover td,
+#index tr:hover td,
+#log tr:hover td,
+#files tr:hover td {
+ background-color: #FFE8E8;
+}
+
+#index tr td:nth-child(2),
+#tags tr td:nth-child(3),
+#branches tr td:nth-child(3),
+#log tr td:nth-child(2) {
+ white-space: normal;
+}
+
+td.num {
+ text-align: right;
+}
+
+.desc {
+ color: #6b6b6b;
+}
+
+hr {
+ border: 0;
+ border-top: 2px solid #2EC4B6;
+ height: 2px;
+}
+
+pre a.h {
+ color: #1D7CF2;
+}
+
+.A,
+span.i,
+pre a.i {
+ color: #17836f;
+}
+
+.D,
+span.d,
+pre a.d {
+ color: #E63946;
+}
+
+pre a.h:hover,
+pre a.i:hover,
+pre a.d:hover {
+ text-decoration: none;
+}
+
+@media (prefers-color-scheme: dark) {
+ body {
+ background-color: #141418;
+ color: #d8d8d8;
+ }
+ hr {
+ border-color: #2EC4B6;
+ }
+ a {
+ color: #5FA8FF;
+ }
+ a:hover {
+ color: #FF6B76;
+ }
+ a:target {
+ background-color: #5c4a00;
+ }
+ .desc {
+ color: #a0a0a0;
+ }
+ #blob a {
+ color: #5a5a5a;
+ }
+ #blob a:target {
+ color: #eee;
+ }
+ #blob a:hover {
+ color: #5FA8FF;
+ }
+ pre a.h {
+ color: #2EC4B6;
+ }
+ .A,
+ span.i,
+ pre a.i {
+ color: #4fd6a0;
+ }
+ .D,
+ span.d,
+ pre a.d {
+ color: #FF6B76;
+ }
+ #branches tr:hover td,
+ #tags tr:hover td,
+ #index tr:hover td,
+ #log tr:hover td,
+ #files tr:hover td {
+ background-color: #22222a;
+ }
+}