tower / commit
fix(ci): move Vite's static dir off the GitLab Pages collision
.gitlab-ci.yml | 3 +++
README.md | 10 +++++-----
decisions.md | 2 +-
design.md | 2 +-
index.html | 2 +-
src/ui/app.ts | 2 +-
{public => static}/terrain-color.png | Bin
{public => static}/terrain-corridor.png | Bin
{public => static}/terrain-height.png | Bin
{public => static}/world.json | 0
test/world.test.ts | 2 +-
tools/terrain.mjs | 10 +++++-----
vite.config.ts | 10 +++++++++-
13 files changed, 27 insertions(+), 16 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8c1d701..cd728c4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -15,6 +15,9 @@ pages:
- npm ci
- npm run build
- mv dist public
+ # Fail loudly rather than publishing a 404. `mv` silently nests when the
+ # destination exists, which is exactly how this broke the first time.
+ - test -f public/index.html || (echo "no index.html at artifact root" && exit 1)
artifacts:
paths: [public]
rules:
diff --git a/README.md b/README.md
index 8cb6ca1..fc9cc94 100644
--- a/README.md
+++ b/README.md
@@ -56,10 +56,10 @@ shell. `npm run terrain` renders it, with no dependencies beyond Node:
| | |
|---|---|
-| `public/terrain-height.png` | 16-bit greyscale, 0–5,000 m |
-| `public/terrain-color.png` | the whole world, 264 m/px |
-| `public/terrain-corridor.png` | the developed corridor, 122 m/px |
-| `public/world.json` | seed places for the app |
+| `static/terrain-height.png` | 16-bit greyscale, 0–5,000 m |
+| `static/terrain-color.png` | the whole world, 264 m/px |
+| `static/terrain-corridor.png` | the developed corridor, 122 m/px |
+| `static/world.json` | seed places for the app |
It reports each stage as it goes — every relief op, colourisation, and PNG encode —
and takes about 6 seconds. Flags:
@@ -104,4 +104,4 @@ Everything autosaves to this browser's localStorage. Two exports:
| | |
|---|---|
| **Export backup** | everything, private notes included. Keep out of the public repo — `.gitignore` already excludes `tower-backup-*.json`. |
-| **Export static map content** | public places only, `notes` stripped. This is `public/world.json`, the world readers see, and the seed for a browser with no local draft. |
+| **Export static map content** | public places only, `notes` stripped. This is `static/world.json`, the world readers see, and the seed for a browser with no local draft. |
diff --git a/decisions.md b/decisions.md
index 24a0105..d1a9359 100644
--- a/decisions.md
+++ b/decisions.md
@@ -671,7 +671,7 @@ polyline only needs two to go somewhere — and the kind list grows from six to
thirteen (`mountain`, `river`, `canyon`, `forest`, `desert`, `tower`, `town`), with
`AREA_KINDS` / `LINE_KINDS` deciding whether a traced shape closes. Before this the
seed silently dropped The Long Water and The Narrows. A test now loads
-`public/world.json` and asserts nothing is lost, so the two files cannot drift apart
+`static/world.json` and asserts nothing is lost, so the two files cannot drift apart
again unnoticed.
**The rendered terrain is drawn under the map**, which is what the whole tool was
diff --git a/design.md b/design.md
index aee40ed..99430ee 100644
--- a/design.md
+++ b/design.md
@@ -488,7 +488,7 @@ Hollow Station — around 2,100 m, with the runs above them.
a control panel, and a framework would not earn its weight.
- **Three.js** for the exterior and interior 3D views.
- **Canvas 2D** for the map view.
-- **GitLab CI → GitLab Pages**, publishing `dist/` as `public/`.
+- **GitLab CI → GitLab Pages**, publishing `dist/` as `static/`.
### 2.2 Module layout
diff --git a/index.html b/index.html
index baeab99..ffbb7ac 100644
--- a/index.html
+++ b/index.html
@@ -84,7 +84,7 @@
<input id="import-file" type="file" accept="application/json" hidden />
<p class="hint">
Backups carry your private notes; keep them out of a public repo.
- The static export is <code>public/world.json</code> — the default readers see.
+ The static export is <code>static/world.json</code> — the default readers see.
</p>
</section>
</aside>
diff --git a/src/ui/app.ts b/src/ui/app.ts
index 4093618..3bf5ffa 100644
--- a/src/ui/app.ts
+++ b/src/ui/app.ts
@@ -3,7 +3,7 @@
*
* The loop this serves: place and name things on the map, autosaved to localStorage
* continuously; export a full backup whenever; export the static public content
- * once to seed `public/world.json` in the repo.
+ * once to seed `static/world.json` in the repo.
*/
import { SLAT_COUNT_MAX, SLAT_COUNT_MIN } from '../canon/constants.js'
import { landStripWidth, slatCount, setSlatCount, slatWidth } from '../canon/slats.js'
diff --git a/public/terrain-color.png b/static/terrain-color.png
similarity index 100%
rename from public/terrain-color.png
rename to static/terrain-color.png
diff --git a/public/terrain-corridor.png b/static/terrain-corridor.png
similarity index 100%
rename from public/terrain-corridor.png
rename to static/terrain-corridor.png
diff --git a/public/terrain-height.png b/static/terrain-height.png
similarity index 100%
rename from public/terrain-height.png
rename to static/terrain-height.png
diff --git a/public/world.json b/static/world.json
similarity index 100%
rename from public/world.json
rename to static/world.json
diff --git a/test/world.test.ts b/test/world.test.ts
index 671971f..c1a55e8 100644
--- a/test/world.test.ts
+++ b/test/world.test.ts
@@ -90,7 +90,7 @@ describe('geometry kinds', () => {
})
describe('the seeded world loads without losing anything', () => {
- const seed = JSON.parse(readFileSync('public/world.json', 'utf8'))
+ const seed = JSON.parse(readFileSync('static/world.json', 'utf8'))
it('keeps every place the terrain tool emits', () => {
expect(parseWorld(seed).places).toHaveLength(seed.places.length)
diff --git a/tools/terrain.mjs b/tools/terrain.mjs
index b63e391..267a93b 100644
--- a/tools/terrain.mjs
+++ b/tools/terrain.mjs
@@ -2,9 +2,9 @@
* Terrain generator. `npm run terrain`
*
* Reads content/geography.json — the authored source of truth — and writes:
- * public/terrain-height.png 16-bit greyscale, 0..maxElevationM
- * public/terrain-color.png 8-bit RGB, hypsometric tint + hillshade
- * public/world.json seed places for the app
+ * static/terrain-height.png 16-bit greyscale, 0..maxElevationM
+ * static/terrain-color.png 8-bit RGB, hypsometric tint + hillshade
+ * static/world.json seed places for the app
*
* The map is the cylinder unrolled: x is z (sun cap at the left), y is theta.
* y wraps; x does not. Every distance below is in metres, converted to pixels only
@@ -608,7 +608,7 @@ line(1, 'encode')
const write = (name, make) =>
step(2, name, () => {
const buf = make()
- writeFileSync(`public/${name}`, buf)
+ writeFileSync(`static/${name}`, buf)
return buf
}, (b) => `${mb(b.length).padEnd(10)}`)
@@ -655,7 +655,7 @@ const places = geo.features
geometry: toPlaceGeometry(f.geometry), blurb: '',
}))
-const target = 'public/world.json'
+const target = 'static/world.json'
const existing = existsSync(target) ? JSON.parse(readFileSync(target, 'utf8')) : { places: [] }
const authored = existing.places?.filter((p) => !places.some((q) => q.id === p.id)) ?? []
if (authored.length && !process.argv.includes('--force')) {
diff --git a/vite.config.ts b/vite.config.ts
index 53fdc40..852945a 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -14,4 +14,12 @@ import { defineConfig } from 'vite'
*/
const base = process.env.BASE || './'
-export default defineConfig({ base, build: { target: 'es2022' } })
+export default defineConfig({
+ base,
+ // Vite's static directory is `static/`, not the default `public/`, because
+ // GitLab Pages requires its artifact to be a directory named `public` — and
+ // `mv dist public` does not rename when `public/` already exists, it moves dist
+ // *inside* it. The collision is silent and produces a 404 at the site root.
+ publicDir: 'static',
+ build: { target: 'es2022' },
+})