v0.4.9a — box art opens full size, a third splash card, and a scoped footer claim

Splash page only: the box art thumbnail opens a full-size lightbox on click, a
new "Play multiplayer" (coming soon) card balances the bottom row to three
cards, and the footer's "runs entirely in your browser" claim is now scoped
to solitaire.
This commit is contained in:
Jesse
2026-08-20 07:40:58 -04:00
parent 859817d173
commit 3a5a909ec0
4 changed files with 89 additions and 28 deletions
+24
View File
@@ -19,6 +19,30 @@ page as `v0.1.0 · <sha> · <date>`, so what is deployed can always be identifie
---
## 0.4.9a — 2026-08-20
Four small tweaks to the splash page (`index.html`, `splash.ts`), no engine changes.
### Box art opens full size on click
The thumbnail beside the title was too small to read. Clicking (or Enter/Space on keyboard focus)
now opens it in a full-size lightbox overlay; click the overlay or press Escape to close.
### A third card balances the bottom row
The doors row was nested beside the box art, two cards wide, leaving the width under the box art
unused. Moved to a full-width row below the hero (three columns at roughly the same card width as
before) and added **Play multiplayer**, modeled on the Play Solitaire card but describing the
not-yet-built feature, with "Coming soon" in place of a link. Its text is shorter than Play
Solitaire's so the row height — and the page's vertical size — doesn't change.
### Footer's "runs in your browser" claim scoped to solitaire
Now reads "solitaire runs entirely in your browser" rather than an unqualified claim that would no
longer hold once multiplayer needs a server.
---
## 0.4.9 — 2026-08-19
A playtest review of seed 58228926 (day 6), plus one long-standing display complaint and the first
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "station-master",
"version": "0.4.9",
"version": "0.4.9a",
"private": true,
"type": "module",
"description": "Station Master — a railroad operations game",
+45 -27
View File
@@ -12,22 +12,27 @@ body{margin:0;background:var(--bg);color:var(--fg);
min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:28px}
main{width:100%;max-width:760px}
.hero{display:flex;gap:24px;align-items:flex-start}
.hero-image{width:230px;flex:none;border-radius:9px;overflow:hidden;border:1px solid var(--line)}
.hero-image{width:230px;flex:none;border-radius:9px;overflow:hidden;border:1px solid var(--line);cursor:zoom-in}
.hero-image img{display:block;width:100%;height:auto}
.hero-content{flex:1;min-width:0}
@media(max-width:640px){.hero{flex-direction:column}.hero-image{width:100%;max-width:280px}}
h1{font-size:32px;margin:0 0 2px;letter-spacing:.02em}
.tag{color:var(--dim);margin:0;font-size:14px}
.blurb{color:#c6ccd6;margin:16px 0 26px;max-width:66ch}
.blurb{color:#c6ccd6;margin:16px 0 0;max-width:66ch}
.rule{height:1px;background:var(--line);margin:22px 0}
.doors{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.doors{display:grid;grid-template-columns:1fr 1fr 1fr;gap:14px;margin-top:26px}
@media(max-width:640px){.doors{grid-template-columns:1fr}}
a.door{display:block;text-decoration:none;color:inherit;background:var(--panel);
.door{display:block;text-decoration:none;color:inherit;background:var(--panel);
border:1px solid var(--line);border-radius:9px;padding:18px 18px 16px;transition:.12s}
a.door:hover{border-color:#4d6fa8;background:#1f2733;transform:translateY(-1px)}
a.door h2{font-size:17px;margin:0 0 5px;color:#9fb6d8}
a.door p{margin:0;color:var(--dim);font-size:13px;line-height:1.5}
a.door .go{display:inline-block;margin-top:11px;font-size:12px;color:#5aa9e6}
.door h2{font-size:17px;margin:0 0 5px;color:#9fb6d8}
.door p{margin:0;color:var(--dim);font-size:13px;line-height:1.5}
.door .go{display:inline-block;margin-top:11px;font-size:12px;color:#5aa9e6}
.door.disabled .go{color:var(--dim)}
.lightbox{position:fixed;inset:0;background:rgba(8,10,13,.92);display:flex;
align-items:center;justify-content:center;padding:32px;z-index:10;cursor:zoom-out}
.lightbox[hidden]{display:none}
.lightbox img{display:block;max-width:90vw;max-height:90vh;border-radius:6px;box-shadow:0 12px 40px rgba(0,0,0,.5)}
/* the rule between title and blurb is drawn as rail, not decorated */
svg.trackline{width:100%;height:24px;display:block;margin:10px 0 0}
.rail{stroke:#4a5361;stroke-width:1.6}
@@ -38,7 +43,7 @@ footer{margin-top:26px;color:var(--dim);font-size:11px;display:flex;gap:18px;fle
<body>
<main>
<div class="hero">
<div class="hero-image">
<div class="hero-image" id="hero-image" tabindex="0" role="button" aria-label="View full-size box art">
<img src="./images/station-master-splash.jpg"
alt="Station Master — TimeTable &amp; Train Order Railroading, 1840&ndash;1950. Box art: two trains meet at a junction beside a train order office."
width="560" height="700">
@@ -60,35 +65,48 @@ footer{margin-top:26px;color:var(--dim);font-size:11px;display:flex;gap:18px;fle
and get every train away again &mdash; a train with nowhere to stand is a collision, and a
collision costs more than the freight was worth.
</p>
<div class="doors">
<a class="door" href="./play.html">
<h2>Play solitaire</h2>
<p>Play by yourself and run the entire division for five full days. Your goal is 20 Revenue.
Your game data is saved in your browser &mdash; if you close the tab and reopen this site
without clearing your cache, your game is preserved and you can continue automatically.
During the game you can also explicitly save your progress for later replay.</p>
<span class="go">Start a game &rarr;</span>
</a>
<a class="door" href="./replays.html">
<h2>Replays</h2>
<p>Replay a saved game, step by step or advancing automatically through phases, Stages and
Days. Open one saved on the site, or a saved file that someone has sent you.</p>
<span class="go">Browse replays &rarr;</span>
</a>
</div>
</div>
</div>
<div class="doors">
<div class="door disabled">
<h2>Play multiplayer</h2>
<p>Play with your friends across the internet. You each run your own office area within the
entire division. You can play a normal game, or choose co-op or cutthroat. This requires
a Station Master server to be running.</p>
<span class="go">Coming soon</span>
</div>
<a class="door" href="./play.html">
<h2>Play solitaire</h2>
<p>Play by yourself and run the entire division for five full days. Your goal is 20 Revenue.
Your game data is saved in your browser &mdash; if you close the tab and reopen this site
without clearing your cache, your game is preserved and you can continue automatically.
During the game you can also explicitly save your progress for later replay.</p>
<span class="go">Start a game &rarr;</span>
</a>
<a class="door" href="./replays.html">
<h2>Replays</h2>
<p>Replay a saved game, step by step or advancing automatically through phases, Stages and
Days. Open one saved on the site, or a saved file that someone has sent you.</p>
<span class="go">Browse replays &rarr;</span>
</a>
</div>
<div class="rule"></div>
<footer>
<span>build <span id="build">__BUILD__</span></span>
<span>runs entirely in your browser &mdash; no server code required</span>
<span>solitaire runs entirely in your browser &mdash; no server code required</span>
</footer>
</main>
<div class="lightbox" id="lightbox" hidden>
<img src="./images/station-master-splash.jpg"
alt="Station Master — TimeTable &amp; Train Order Railroading, 1840&ndash;1950. Box art: two trains meet at a junction beside a train order office.">
</div>
<script type="module" src="./web/splash.js"></script>
</body>
</html>
+19
View File
@@ -7,3 +7,22 @@ if (ties) {
}
ties.innerHTML = out;
}
/** Clicking the box art opens it full size, since the thumbnail is too small to read. */
const heroImage = document.getElementById('hero-image');
const lightbox = document.getElementById('lightbox');
if (heroImage && lightbox) {
const open = () => { lightbox.hidden = false; };
const close = () => { lightbox.hidden = true; };
heroImage.addEventListener('click', open);
heroImage.addEventListener('keydown', (e) => {
if (e instanceof KeyboardEvent && (e.key === 'Enter' || e.key === ' ')) {
e.preventDefault();
open();
}
});
lightbox.addEventListener('click', close);
document.addEventListener('keydown', (e) => {
if (e instanceof KeyboardEvent && e.key === 'Escape') close();
});
}