Trade the tutorial for a screen that counts the dead
The menus were placeholders next to the art. Three screens now: a title over an empty, dimmed, blood-stained court; a MATCH SETUP screen where each court wears meters read straight off its own bounce numbers; and BODY COUNT, which needed the game to start measuring anything at all. stats.js keeps one capped array of per-run records — all time, last match and seven days are three filters over it rather than three counters that can drift apart. Kills file under the body AND the weapon: killZombie only ever knew an index, so every damage loop stamps the cause on its way past. The tutorial is gone. Marvin explained what the in-game modals already teach, and his stage is where the stats live now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
411bff8724
commit
f3b0b791d6
21 files changed
+619
-210
No files matched your search
+211
-100
@@ -63,98 +63,188 @@
|
||||
#hint { position: fixed; top: 6px; right: 10px; text-align: right;
|
||||
font: 400 10px Silkscreen, monospace; color: #6b7688; }
|
||||
@media (pointer: coarse) { #hint { display: none; } }
|
||||
#intro { position: fixed; inset: 0; z-index: 10; touch-action: none; display: grid; place-items: center;
|
||||
background: radial-gradient(circle at 50% 34%, rgba(34,16,20,0.92), rgba(8,10,16,0.96)); }
|
||||
#intro .card { font: 400 11px Silkscreen, monospace; color: #dfe6f2; text-align: center; line-height: 1.9;
|
||||
padding: 18px 26px; max-width: 92vw; animation: drop 0.5s ease-out; }
|
||||
/* ---- THE MENU PALETTE. The canvas HUD keeps its own blue-grey and gold; the menus are
|
||||
deliberately a different room — dark court green, one acid accent, and one crimson reserved for
|
||||
the thing you actually came here to press. Five names so a repaint is five edits, not fifty. */
|
||||
:root { --ink:#0d1408; --panel:rgba(30,45,18,0.55); --line:#3e5a26; --acid:#c8e04a;
|
||||
--cream:#dfe6c9; --dim:#7f9160; --red:#b3201c; --bad:#e0564a;
|
||||
/* the same green as --panel over --ink, but OPAQUE: the pinned header and footer have
|
||||
content scrolling underneath them and a translucent bar shows it through */
|
||||
--solid:#161f0d; }
|
||||
/* touch-action is pan-y, not none: the BODY COUNT list is taller than a phone and has to scroll.
|
||||
align-content is `safe center` rather than place-items — plain centring on a grid whose item
|
||||
overflows pushes the top of the item out of the scrollport, where nothing can reach it. */
|
||||
#intro { position: fixed; inset: 0; z-index: 10; touch-action: pan-y; background: var(--ink);
|
||||
display: grid; grid-template-columns: 1fr; justify-items: center;
|
||||
align-content: safe center; overflow-y: auto; overscroll-behavior: contain; }
|
||||
/* the SPLASH sits on the court; the other stages are lists and want a flat field behind them.
|
||||
The art is dimmed here rather than baked dark, so the same file can be reused at another level. */
|
||||
#intro[data-stage="splash"] {
|
||||
background: linear-gradient(rgba(9,14,7,0.55), rgba(9,14,7,0.88)),
|
||||
url('assets/menu_bg.png?v=85') 50% 46% / cover no-repeat var(--ink);
|
||||
image-rendering: pixelated; }
|
||||
#intro .card { font: 400 11px Silkscreen, monospace; color: var(--cream); text-align: center;
|
||||
line-height: 1.9; padding: 16px 14px 20px; width: min(370px, 94vw);
|
||||
animation: drop 0.5s ease-out; }
|
||||
@keyframes drop { from { transform: translateY(-14px); opacity: 0; } }
|
||||
/* the logo is generated pixel art now (assets/logo.png), not stacked CSS text */
|
||||
#intro .logo { display: block; width: min(320px, 78vw); height: auto; margin: 0 auto 8px;
|
||||
/* EVERY SCREEN FILLS THE VIEWPORT, and every screen is the same three bands: something pinned to
|
||||
the top, something pinned to the bottom, and whatever is between them taking the slack. The
|
||||
card is a full-height flex column, so `margin-top:auto` on the footer drops it to the bottom
|
||||
when the content is short and `position:sticky` keeps it there once the content is long enough
|
||||
to scroll. Centring the card instead left the buttons floating in the middle of a tall phone. */
|
||||
#intro { align-content: stretch; }
|
||||
#intro .card { display: flex; flex-direction: column; min-height: 100dvh; padding: 0 14px; }
|
||||
/* the slack band: the title sits in the middle of whatever is left over */
|
||||
.mid { flex: 1; display: flex; flex-direction: column; justify-content: center; padding: 12px 0; }
|
||||
/* the logo is generated pixel art (assets/logo.png), not stacked CSS text */
|
||||
#intro .logo { display: block; width: min(300px, 74vw); height: auto; margin: 0 auto 6px;
|
||||
image-rendering: pixelated; filter: drop-shadow(0 3px 0 rgba(0,0,0,0.45)); }
|
||||
/* the slogan carries most of the gap between the logo's blood and the first button */
|
||||
#intro .slogan { margin: 10px 0 26px; font-size: 12px; color: #b6a0a4; letter-spacing: 0.5px; }
|
||||
#intro .slogan { margin: 8px 0 20px; font-size: 11px; color: #b6a0a4; letter-spacing: 0.5px; }
|
||||
#intro .slogan b { color: #c9564a; }
|
||||
/* which build is served — filled in by main.js, empty (and invisible) if the header is missing */
|
||||
#build { margin: 10px 0 0; font-size: 9px; color: #5a6270; letter-spacing: 0.5px; }
|
||||
#build { margin: 14px 0 0; font-size: 9px; color: #4d5a3c; letter-spacing: 0.5px; }
|
||||
/* ONE overlay, four panels, swapped by #intro[data-stage]. Keeping the backdrop and the card frame
|
||||
alive across every screen is the point — a screen that unmounts the whole overlay flashes the
|
||||
court through between menus. */
|
||||
#splash, #courts, #tutorial { display: none; }
|
||||
#intro[data-stage="splash"] #splash { display: block; }
|
||||
#intro[data-stage="courts"] #courts { display: block; animation: drop 0.3s ease-out; }
|
||||
#intro[data-stage="tutorial"] #tutorial { display: block; animation: drop 0.3s ease-out; }
|
||||
#splash, #setup, #stats, #ranks { display: none; }
|
||||
#intro[data-stage="splash"] #splash { display: flex; flex-direction: column; flex: 1; }
|
||||
/* flex COLUMN, not block: it is what lets the footer's margin-top:auto reach the bottom of a
|
||||
screen whose content does not fill it */
|
||||
#intro[data-stage="setup"] #setup,
|
||||
#intro[data-stage="stats"] #stats,
|
||||
#intro[data-stage="ranks"] #ranks { display: flex; flex-direction: column; flex: 1;
|
||||
animation: drop 0.3s ease-out; }
|
||||
/* the overlay is HIDDEN during play, not removed: a restart puts it straight back, and the
|
||||
display:grid above would otherwise win over the hidden attribute */
|
||||
#intro[hidden] { display: none; }
|
||||
/* headline: the ANNOUNCEMENT face, the same register the canvas uses for SET and CHAPTER — a
|
||||
screen title is a thing that shouts, not a line of HUD. Bangers carries its own weight, so it
|
||||
wants size and air rather than Silkscreen's letter-spacing. */
|
||||
#intro h2 { margin: 0 0 26px; font: 400 30px Bangers, cursive; color: #e0cc72;
|
||||
letter-spacing: 2px; line-height: 1.2; padding-bottom: 6px; }
|
||||
/* Screen titles and the primary button are BANGERS — the same announcement face the canvas uses
|
||||
for SET and CHAPTER. A screen title is a thing that shouts. Everything that is a NUMBER or a
|
||||
label stays Silkscreen, so the two registers keep meaning what they have always meant. */
|
||||
#intro h2 { margin: 0; font: 400 26px Bangers, cursive; color: var(--acid); letter-spacing: 1.5px; }
|
||||
#intro h3 { display: flex; justify-content: space-between; margin: 18px 0 8px;
|
||||
font: 400 9px Silkscreen, monospace; color: var(--dim); letter-spacing: 2px;
|
||||
text-align: left; }
|
||||
/* header strip: back chevron + title. Every screen but the splash wears one, pinned to the top. */
|
||||
.hdr { position: sticky; top: 0; z-index: 3; display: flex; align-items: center; gap: 10px;
|
||||
padding: 10px 12px; margin: 0 -14px; border-bottom: 2px solid var(--line);
|
||||
background: var(--solid);
|
||||
padding-top: max(10px, env(safe-area-inset-top)); }
|
||||
.hdr h2 { padding-left: 2px; }
|
||||
.chev { width: 34px; height: 34px; flex: none; background: none; border: 2px solid var(--line);
|
||||
color: var(--acid); font: 400 20px Bangers, cursive; line-height: 1; cursor: pointer;
|
||||
-webkit-tap-highlight-color: transparent; }
|
||||
/* the splash stat bar and the BODY COUNT headline row: boxed figures sharing one frame */
|
||||
.bar, .figs { display: flex; border: 2px solid var(--line); background: var(--panel); }
|
||||
/* the bar is the splash's top band — pinned like a header, and the safe-area inset is its job
|
||||
because nothing else on that screen sits above it */
|
||||
.bar { flex: none; margin-top: max(12px, env(safe-area-inset-top)); }
|
||||
.bar .fig { padding: 6px 10px; text-align: left; }
|
||||
.figs .fig { padding: 7px 6px; text-align: center; }
|
||||
.fig { flex: 1; min-width: 0; }
|
||||
.bar .fig + .fig { text-align: right; }
|
||||
.fig + .fig { border-left: 2px solid var(--line); }
|
||||
.fig b { display: block; font: 400 8px Silkscreen, monospace; color: var(--dim); letter-spacing: 1px; }
|
||||
.fig i { display: block; font: 700 15px Silkscreen, monospace; color: var(--acid);
|
||||
font-style: normal; letter-spacing: 1px; }
|
||||
.fig.bad i { color: var(--bad); }
|
||||
/* one button look for every menu screen */
|
||||
.btn { display: block; width: min(340px, 84vw); margin: 0 auto 10px; padding: 12px 10px;
|
||||
background: rgba(255,255,255,0.04); border: 2px solid #3b4354; color: #dfe6f2;
|
||||
.btn { display: block; width: 100%; margin: 0 auto 10px; padding: 12px 10px;
|
||||
background: var(--panel); border: 2px solid var(--line); color: var(--cream);
|
||||
font: 400 12px Silkscreen, monospace; letter-spacing: 1px; cursor: pointer;
|
||||
-webkit-tap-highlight-color: transparent; }
|
||||
.btn.go { border-color: #e0cc72; color: #e0cc72; }
|
||||
/* The two menu buttons wear generated plates. The LETTERING stays live text on top rather than
|
||||
being drawn into the art: generated type is a lottery and would not match the rest of the HUD.
|
||||
A text-shadow is what keeps it readable where a drip runs behind it. The border is CSS, not
|
||||
art — the plate crops are interior-only, so both buttons get the same clean frame. */
|
||||
.btn.plate, .btn.plate2 { padding: 15px 10px; font-size: 15px; letter-spacing: 2px;
|
||||
background-size: 100% 100%; background-repeat: no-repeat;
|
||||
image-rendering: pixelated; text-shadow: 0 2px 0 rgba(0,0,0,0.9); }
|
||||
/* No gold frame on START any more — the sweep below is what draws the eye, and the two buttons
|
||||
now share one border so the pair reads as a pair. */
|
||||
.btn.plate { background-image: url('assets/btn_start.png?v=94'); color: #f7ecb8;
|
||||
border-color: #3b4354; position: relative; overflow: hidden; }
|
||||
/* a light passing over the sign: across in ~0.8s, then still for the rest of the cycle.
|
||||
pointer-events:none so the sweep can never eat the tap. */
|
||||
.btn.plate::after { content: ''; position: absolute; inset: 0; pointer-events: none;
|
||||
background: linear-gradient(105deg, transparent 42%, rgba(255,255,255,0.34) 50%,
|
||||
transparent 58%);
|
||||
transform: translateX(-140%); animation: shine 4.5s ease-in-out infinite; }
|
||||
@keyframes shine { 0% { transform: translateX(-140%); } 18%, 100% { transform: translateX(140%); } }
|
||||
@media (prefers-reduced-motion: reduce) { .btn.plate::after { animation: none; opacity: 0; } }
|
||||
.btn.plate2 { background-image: url('assets/btn_tut.png?v=94'); color: #d6dfec; }
|
||||
.btn.back { font-size: 10px; padding: 9px 10px; color: #8a96ab; }
|
||||
/* The generated button plates are gone with the tutorial. The primary is a flat crimson block
|
||||
now: it survives being resized, which a fixed-size plate crop never did, and the mockup's
|
||||
hierarchy is carried by colour rather than by art. */
|
||||
.btn.big { padding: 13px 10px 11px; background: var(--red); border-color: #6d1310; color: #f6e7dc;
|
||||
font: 400 26px Bangers, cursive; letter-spacing: 2px; line-height: 1.15; }
|
||||
.two { display: flex; gap: 8px; }
|
||||
.two .btn { margin-bottom: 0; }
|
||||
.btn.sec i { display: block; margin-top: 3px; font: 400 8px Silkscreen, monospace;
|
||||
font-style: normal; color: var(--dim); letter-spacing: 0.5px; }
|
||||
/* the tour: two tiles SIDE BY SIDE, not two more full-width rows. The figures face the camera —
|
||||
in play you only ever see your player from behind, so a rear view would show nothing. */
|
||||
#tours { display: flex; gap: 8px; }
|
||||
#tours button { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px;
|
||||
padding: 8px 6px 10px; background: var(--panel); border: 2px solid var(--line);
|
||||
color: inherit; font: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; }
|
||||
#tours button.on { border-color: var(--acid); background: rgba(200,224,74,0.10); }
|
||||
#tours img { height: 88px; width: auto; display: block; image-rendering: pixelated; }
|
||||
#tours b { font: 400 10px Silkscreen, monospace; color: var(--cream); letter-spacing: 0.5px; }
|
||||
/* a row, not a stacked tile: three 3:2 tiles stacked fill a phone twice over, and the art still
|
||||
reads at this size. -webkit-tap-highlight-color kills iOS's blue flash over the pixel art. */
|
||||
#courts button.court { display: flex; align-items: center; gap: 12px; width: min(340px, 84vw);
|
||||
margin: 0 auto 8px; padding: 6px; background: rgba(255,255,255,0.04);
|
||||
border: 2px solid #3b4354; color: inherit; font: inherit; text-align: left;
|
||||
#courtList button.court { display: flex; align-items: center; gap: 11px; width: 100%;
|
||||
margin: 0 0 8px; padding: 7px; background: var(--panel);
|
||||
border: 2px solid var(--line); color: inherit; font: inherit; text-align: left;
|
||||
cursor: pointer; -webkit-tap-highlight-color: transparent; }
|
||||
#courts button.court.on { border-color: #e0cc72; background: rgba(224,204,114,0.10); }
|
||||
/* scoped to #courtList, not #courts: the tour tiles above are portrait figures and must not
|
||||
inherit the 108x72 court-thumbnail box */
|
||||
#courtList img { width: 108px; height: 72px; display: block; image-rendering: pixelated; flex: none; }
|
||||
#courtList b { display: block; font: 400 11px Silkscreen, monospace; color: #dfe6f2; letter-spacing: 0.5px; }
|
||||
#courtList i { display: block; margin-top: 5px; font: 400 9px Silkscreen, monospace; color: #8a96ab; font-style: normal; }
|
||||
#courts .acts { margin-top: 16px; }
|
||||
/* the tour: two tiles SIDE BY SIDE, not two more full-width rows. The court screen already carries
|
||||
three rows and a pair of buttons, and a phone has no room left. The figures face the camera —
|
||||
in play you only ever see your player from behind, so a rear view would show nothing. */
|
||||
#tours { display: flex; gap: 8px; width: min(340px, 84vw); margin: 0 auto 10px; }
|
||||
#tours button { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px;
|
||||
padding: 8px 6px 10px; background: rgba(255,255,255,0.04); border: 2px solid #3b4354;
|
||||
color: inherit; font: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; }
|
||||
#tours button.on { border-color: #e0cc72; background: rgba(224,204,114,0.10); }
|
||||
#tours img { height: 92px; width: auto; display: block; image-rendering: pixelated; }
|
||||
#tours b { font: 400 10px Silkscreen, monospace; color: #dfe6f2; letter-spacing: 0.5px; }
|
||||
/* tutorial: Marvin on the left, his line and the picture on the right */
|
||||
#tutorial .page { display: flex; align-items: flex-end; gap: 14px; width: min(360px, 88vw);
|
||||
margin: 0 auto; text-align: left; min-height: 190px; }
|
||||
#tutorial .marvin { width: 84px; flex: none; image-rendering: pixelated; align-self: flex-end; }
|
||||
#tutorial .say { flex: 1; }
|
||||
#tutorial .say p { margin: 0 0 10px; font: 400 10px Silkscreen, monospace; color: #dfe6f2; line-height: 1.9; }
|
||||
#tutorial .say em { color: #e0cc72; font-style: normal; }
|
||||
/* the panel is 2:1 and it is the point of the page, so it gets the full card width above the
|
||||
Marvin row rather than being squeezed into the text column beside him */
|
||||
#tutorial .shot { display: block; width: min(360px, 88vw); margin: 0 auto 12px;
|
||||
image-rendering: pixelated; border: 2px solid #2a3140; }
|
||||
#tutorial .dots { margin: 14px 0 10px; font: 400 10px Silkscreen, monospace; color: #5a6270; letter-spacing: 3px; }
|
||||
#tutorial .acts { display: flex; gap: 8px; width: min(340px, 84vw); margin: 0 auto; }
|
||||
#tutorial .acts .btn { margin: 0; flex: 1; }
|
||||
#courtList button.court.on { border-color: var(--acid); background: rgba(200,224,74,0.10); }
|
||||
#courtList img { width: 92px; height: 66px; display: block; image-rendering: pixelated; flex: none;
|
||||
object-fit: cover; }
|
||||
#courtList .cb { flex: 1; min-width: 0; }
|
||||
#courtList b { display: block; font: 400 11px Silkscreen, monospace; color: var(--cream); letter-spacing: 0.5px; }
|
||||
#courtList i { display: block; margin: 2px 0 5px; font: 400 8px Silkscreen, monospace; color: var(--dim); font-style: normal; }
|
||||
/* The two meters read straight off the court's own bounce numbers (see main.js), so they cannot
|
||||
drift away from what the ball actually does on it. */
|
||||
.meter { display: flex; align-items: center; gap: 6px; margin-top: 3px;
|
||||
font: 400 7px Silkscreen, monospace; color: var(--dim); letter-spacing: 1px; }
|
||||
.meter u { flex: none; width: 40px; text-decoration: none; }
|
||||
.meter s { flex: 1; height: 5px; background: rgba(0,0,0,0.45); text-decoration: none; display: block; }
|
||||
.meter s > i { display: block; height: 100%; background: var(--acid); }
|
||||
.meter.b s > i { background: #5aa9d0; }
|
||||
/* the commit strip. #intro is the scrollport, so sticky resolves against it and the button stays
|
||||
reachable however long the list above grows. */
|
||||
/* margin-top:auto pins it to the BOTTOM of a short screen; sticky keeps it there on a long one */
|
||||
.foot { position: sticky; bottom: 0; z-index: 2; margin: auto -14px 0; padding: 10px 14px;
|
||||
padding-bottom: max(10px, env(safe-area-inset-bottom));
|
||||
border-top: 2px solid var(--line); background: var(--solid); }
|
||||
.foot .btn { margin-bottom: 0; }
|
||||
/* the splash's bottom band: no bar, no rule — the court art has to keep running under it */
|
||||
.foot.bare { border: 0; background: none; }
|
||||
.foot.bare .btn.big { margin-bottom: 10px; }
|
||||
#sSum { display: flex; justify-content: space-between; gap: 8px; margin: 0 0 8px;
|
||||
font: 400 8px Silkscreen, monospace; color: var(--dim); letter-spacing: 1px; }
|
||||
.tabs { display: flex; gap: 6px; margin: 12px 0 14px; }
|
||||
.tabs button { flex: 1; padding: 9px 2px; background: var(--panel); border: 2px solid var(--line);
|
||||
color: var(--dim); font: 400 8px Silkscreen, monospace; letter-spacing: 1px;
|
||||
cursor: pointer; -webkit-tap-highlight-color: transparent; }
|
||||
.tabs button.on { border-color: var(--acid); color: var(--acid); }
|
||||
/* one opponent. The sprite is the walk frame the game already draws, sat on its own baseline. */
|
||||
.zrow { display: flex; align-items: center; gap: 10px; padding: 7px 9px; margin-bottom: 6px;
|
||||
border: 2px solid var(--line); background: var(--panel); text-align: left; }
|
||||
.zrow.boss { border-color: #7d2420; background: rgba(120,26,22,0.28); }
|
||||
.zrow img { width: 34px; height: 46px; object-fit: contain; object-position: bottom;
|
||||
image-rendering: pixelated; flex: none; }
|
||||
.zb { flex: 1; min-width: 0; display: grid; grid-template-columns: 1fr auto; gap: 0 8px;
|
||||
line-height: 1.4; }
|
||||
.zb b { font: 400 10px Silkscreen, monospace; color: var(--cream); letter-spacing: 0.5px;
|
||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.zb > span { font: 700 12px Silkscreen, monospace; color: var(--acid); text-align: right; }
|
||||
.zrow.boss .zb > span { color: var(--bad); }
|
||||
.pb { grid-column: 1 / -1; height: 5px; margin-top: 4px; background: rgba(0,0,0,0.45); }
|
||||
.pb s { display: block; height: 100%; background: var(--acid); text-decoration: none; }
|
||||
.zrow.boss .pb s { background: var(--bad); }
|
||||
.zb i { grid-column: 1 / -1; margin-top: 3px; font: 400 7px Silkscreen, monospace;
|
||||
font-style: normal; color: var(--dim); letter-spacing: 1px; }
|
||||
#stW { display: flex; flex-wrap: wrap; gap: 6px; }
|
||||
.wtile { flex: 1 1 54px; max-width: 76px; padding: 6px 2px; border: 2px solid var(--line);
|
||||
background: var(--panel); }
|
||||
.wtile img { width: 26px; height: 26px; object-fit: contain; display: block; margin: 0 auto 2px;
|
||||
image-rendering: pixelated; }
|
||||
.wtile b { display: block; font: 400 9px Silkscreen, monospace; color: var(--acid); }
|
||||
.none { margin: 4px 0 0; font: 400 8px Silkscreen, monospace; color: var(--dim); letter-spacing: 1px;
|
||||
text-align: left; }
|
||||
#stFoot { display: flex; justify-content: space-between; align-items: baseline;
|
||||
border-top: 2px solid var(--line); }
|
||||
#stFoot b { font: 400 8px Silkscreen, monospace; color: var(--dim); letter-spacing: 1px; }
|
||||
#stFoot i { font: 700 13px Silkscreen, monospace; color: var(--acid); font-style: normal; }
|
||||
.rkrow { display: flex; align-items: center; gap: 10px; padding: 8px 10px; margin-bottom: 5px;
|
||||
border: 2px solid var(--line); background: var(--panel); text-align: left; }
|
||||
.rkrow.me { border-color: var(--acid); background: rgba(200,224,74,0.12); }
|
||||
.rkrow b { flex: none; width: 60px; font: 700 10px Silkscreen, monospace; color: var(--dim); }
|
||||
.rkrow.me b { color: var(--acid); }
|
||||
.rkrow span { flex: 1; min-width: 0; font: 400 9px Silkscreen, monospace; color: var(--cream);
|
||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.rkrow i { font: 400 9px Silkscreen, monospace; font-style: normal; color: var(--dim); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -164,42 +254,63 @@
|
||||
<div id="intro" data-stage="splash">
|
||||
<div class="card">
|
||||
<!-- The title screen IS the menu. A separate menu stage behind it was the same logo over the
|
||||
same backdrop with two buttons, so it read as the title screen failing to advance. The
|
||||
control list that used to sit here is the tutorial's job now. -->
|
||||
same backdrop with two buttons, so it read as the title screen failing to advance. -->
|
||||
<!-- three bands: the figures at the top, the title floating in the middle, the buttons under
|
||||
your thumb. Same anchoring as every other screen. -->
|
||||
<div id="splash">
|
||||
<img class="logo" src="assets/logo.png" alt="Splatter Tennis">
|
||||
<p class="slogan">Fifteen. Thirty. Forty. <b>Dead.</b></p>
|
||||
<button class="btn plate" id="mStart">START GAME</button>
|
||||
<button class="btn plate2" id="mTut">TUTORIAL</button>
|
||||
<p id="build"></p>
|
||||
<div class="bar">
|
||||
<div class="fig"><b>BEST RUN</b><i id="sBest">—</i></div>
|
||||
<div class="fig"><b>WORLD RANK</b><i id="sRank">—</i></div>
|
||||
</div>
|
||||
<div class="mid">
|
||||
<img class="logo" src="assets/logo.png" alt="Splatter Tennis">
|
||||
<p class="slogan">Fifteen. Thirty. Forty. <b>Dead.</b></p>
|
||||
</div>
|
||||
<div class="foot bare">
|
||||
<button class="btn big" id="mStart">PLAY MATCH</button>
|
||||
<div class="two">
|
||||
<button class="btn sec" id="mStats">STATS<i id="mKills">0 KILLS</i></button>
|
||||
<button class="btn sec" id="mRanks">RANKINGS<i>SEASON 1</i></button>
|
||||
</div>
|
||||
<p id="build"></p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- tour tiles and court rows are both built from tables in main.js (config.TOURS / config.COURTS):
|
||||
adding either is a table row, never markup -->
|
||||
<div id="courts">
|
||||
<h2>CHOOSE YOUR MATCH</h2>
|
||||
<div id="setup">
|
||||
<div class="hdr"><button class="chev" id="sBack">‹</button><h2>MATCH SETUP</h2></div>
|
||||
<h3>01 · PLAYER</h3>
|
||||
<div id="tours"></div>
|
||||
<h3>02 · COURT</h3>
|
||||
<div id="courtList"></div>
|
||||
<div class="acts">
|
||||
<button class="btn go" id="cStart">START GAME</button>
|
||||
<button class="btn back" id="cBack">BACK</button>
|
||||
<div class="foot">
|
||||
<p id="sSum"></p>
|
||||
<button class="btn big" id="cStart">SERVE UP</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- tutorial pages are built from a table in main.js -->
|
||||
<div id="tutorial">
|
||||
<h2>HOW IT WORKS</h2>
|
||||
<img class="shot" id="tShot" alt="">
|
||||
<div class="page">
|
||||
<img class="marvin" id="tMarvin" src="assets/marvin1.png" alt="">
|
||||
<div class="say" id="tSay"></div>
|
||||
</div>
|
||||
<p class="dots" id="tDots"></p>
|
||||
<div class="acts">
|
||||
<button class="btn back" id="tBack">BACK</button>
|
||||
<button class="btn go" id="tNext">NEXT</button>
|
||||
<!-- BODY COUNT. Every row in here is built by stats.js from the run records in localStorage. -->
|
||||
<div id="stats">
|
||||
<div class="hdr"><button class="chev" id="stBack">‹</button><h2>BODY COUNT</h2></div>
|
||||
<div class="tabs" id="stTabs">
|
||||
<button class="on" data-p="all">ALL TIME</button>
|
||||
<button data-p="last">LAST MATCH</button>
|
||||
<button data-p="7d">7 DAYS</button>
|
||||
</div>
|
||||
<div class="figs" id="stFigs"></div>
|
||||
<h3>BY OPPONENT<span id="stPeriod"></span></h3>
|
||||
<div id="stZ"></div>
|
||||
<h3>BY WEAPON</h3>
|
||||
<div id="stW"></div>
|
||||
<div class="foot" id="stFoot"></div>
|
||||
</div>
|
||||
<!-- placeholder ladder until the leaderboard task lands — see stats.drawRanks -->
|
||||
<div id="ranks">
|
||||
<div class="hdr"><button class="chev" id="rkBack">‹</button><h2>RANKINGS</h2></div>
|
||||
<h3>SEASON 1<span>UNRANKED · OFFLINE</span></h3>
|
||||
<div id="rkList"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="main.js?v=121"></script>
|
||||
<script type="module" src="main.js?v=122"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user