Polish home CTAs, panel rounding, and 404 label; fix dev-mode SW crash

- Shorten CTA labels to "Play Demo" / "Load Table"
- Fix mismatched corner radii on the hero and table-staging panels
- Add horizontal padding to the in-game "insert coin" hint on mobile
- Match the 404 page's "TILT" eyebrow label size to the rest of the site
- Only register the service worker in production — it precaches
  /404.html, which doesn't exist as a static file under `next dev` and
  was failing cache.addAll() on every load

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-24 08:35:18 +02:00
co-authored by Claude Sonnet 5
parent 35fb68c916
commit 958f091c56
5 changed files with 10 additions and 6 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ import { buttonClassName } from "@/components/ui/Button";
export default function NotFound() { export default function NotFound() {
return ( return (
<main className="flex flex-1 flex-col items-center justify-center gap-6 px-4 py-24 text-center"> <main className="flex flex-1 flex-col items-center justify-center gap-6 px-4 py-24 text-center">
<p className="font-mono text-sm tracking-[0.3em] text-arc">TILT</p> <p className="font-mono text-xs tracking-[0.3em] text-arc">TILT</p>
<h1 className="font-display text-5xl font-black tracking-wide text-marquee sm:text-7xl"> <h1 className="font-display text-5xl font-black tracking-wide text-marquee sm:text-7xl">
TABLE NOT FOUND TABLE NOT FOUND
</h1> </h1>
+4
View File
@@ -4,6 +4,10 @@ import { useEffect } from "react";
export default function RegisterServiceWorker() { export default function RegisterServiceWorker() {
useEffect(() => { useEffect(() => {
// sw.js precaches /404.html, which only exists as a static file after
// `next build`'s static export — under `next dev` it 404s and fails the
// whole cache.addAll(), so only register outside of development.
if (process.env.NODE_ENV !== "production") return;
if (!("serviceWorker" in navigator)) return; if (!("serviceWorker" in navigator)) return;
navigator.serviceWorker.register("/sw.js").catch((err) => { navigator.serviceWorker.register("/sw.js").catch((err) => {
console.error("Service worker registration failed:", err); console.error("Service worker registration failed:", err);
+3 -3
View File
@@ -33,7 +33,7 @@ export default function AttractHero() {
return ( return (
<FileDropZone onFile={handleFile} onError={setError} className="w-full max-w-4xl"> <FileDropZone onFile={handleFile} onError={setError} className="w-full max-w-4xl">
<div className="relative overflow-hidden rounded-t-3xl rounded-b-lg border-2 border-chrome/40 bg-ash shadow-2xl"> <div className="relative overflow-hidden rounded-lg border-2 border-chrome/40 bg-ash shadow-2xl">
{/* Backglass glow — stands in for real playfield art; GI-lamp amber + a cyan tube accent. */} {/* Backglass glow — stands in for real playfield art; GI-lamp amber + a cyan tube accent. */}
<div <div
aria-hidden aria-hidden
@@ -64,10 +64,10 @@ export default function AttractHero() {
<div className="mt-4 flex flex-col items-center gap-3 sm:flex-row"> <div className="mt-4 flex flex-col items-center gap-3 sm:flex-row">
<Button type="button" variant="primary" onClick={() => router.push("/play")}> <Button type="button" variant="primary" onClick={() => router.push("/play")}>
Insert Coin Play Demo Play Demo
</Button> </Button>
<label htmlFor={VPX_FILE_INPUT_ID} className={buttonClassName("outline", "cursor-pointer")}> <label htmlFor={VPX_FILE_INPUT_ID} className={buttonClassName("outline", "cursor-pointer")}>
Load Your Table Load Table
</label> </label>
</div> </div>
+1 -1
View File
@@ -30,7 +30,7 @@ export default function TableStaging({ vpxFile, onPlay, onCancel }: TableStaging
}; };
return ( return (
<div className="relative overflow-hidden rounded-t-3xl rounded-b-lg border-2 border-chrome/40 bg-ash shadow-2xl"> <div className="relative overflow-hidden rounded-lg border-2 border-chrome/40 bg-ash shadow-2xl">
<div className="relative flex flex-col items-center gap-5 px-4 py-14 text-center sm:px-8"> <div className="relative flex flex-col items-center gap-5 px-4 py-14 text-center sm:px-8">
<p className="font-mono text-xs tracking-[0.3em] text-arc">TABLE SELECTED</p> <p className="font-mono text-xs tracking-[0.3em] text-arc">TABLE SELECTED</p>
<h2 className="max-w-lg truncate font-display text-3xl font-black tracking-wide text-paper sm:text-4xl"> <h2 className="max-w-lg truncate font-display text-3xl font-black tracking-wide text-paper sm:text-4xl">
+1 -1
View File
@@ -68,7 +68,7 @@ export default function PinballCanvasImpl({ tableData, rom, tableInfo }: Pinball
real coin-op cabinet — pressing 1 alone does nothing until a real coin-op cabinet — pressing 1 alone does nothing until a
credit is added. Surfaced here since it's the first thing credit is added. Surfaced here since it's the first thing
anyone hits and easy to mistake for the app not responding. */} anyone hits and easy to mistake for the app not responding. */}
<p className="font-mono text-xs text-chrome"> <p className="max-w-md px-4 text-center font-mono text-xs text-chrome">
If Start doesn&apos;t respond: press <span className="text-arc">4</span> to insert a coin, then{" "} If Start doesn&apos;t respond: press <span className="text-arc">4</span> to insert a coin, then{" "}
<span className="text-arc">1</span> to start. <span className="text-arc">1</span> to start.
</p> </p>