From 4bc9691d772ea074f3c3ee75dc503aaaa5d0397a Mon Sep 17 00:00:00 2001 From: Cameron Date: Fri, 25 Sep 2026 21:19:57 -0700 Subject: [PATCH] Give the tide pool's specimen sheet a close button in its top corner that releases the machine just as Release and Escape do, and keep the sheet above the pool and zoom buttons in short mid-width windows. --- public/tide-pool.css | 9 +++++++++ public/tide-pool.js | 5 ++++- src/components/tide-pool.tsx | 3 ++- src/index.tsx | 2 +- src/tide-pool.test.tsx | 1 + 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/public/tide-pool.css b/public/tide-pool.css index 8c3b28e..844cd20 100644 --- a/public/tide-pool.css +++ b/public/tide-pool.css @@ -84,6 +84,11 @@ body:has(.tide-pool) .theme-toggle, body:has(.tide-pool) .theme-preferences { di .tide-inspect { position: absolute; z-index: 3; right: clamp(16px, 3.4vw, 56px); bottom: 150px; width: 244px; padding: .9rem 1rem 1rem; background: var(--panel); border: 1px solid var(--line); } .tide-inspect[hidden] { display: none; } .tide-inspect h2 { margin: .25rem 0 .7rem; font: 400 1.9rem/1 var(--site-font-display); letter-spacing: .02em; } +/* A quiet cross in the corner, with a full-size touch target; the heading keeps clear of it. */ +.tide-inspect header { padding-right: 2rem; } +#tide-inspect-close { position: absolute; top: 0; right: 0; width: 44px; height: 44px; padding: 0; color: var(--muted); background: none; border: 0; font-size: 1.15rem; line-height: 1; } +#tide-inspect-close:hover { color: #e5e0e8; } +#tide-inspect-close:focus-visible { outline-offset: -4px; } .tide-facts { display: grid; grid-template-columns: 1fr 1fr; gap: .55rem .8rem; margin: 0 0 .8rem; } .tide-facts dd { margin: .15rem 0 0; font-size: .82rem; font-variant-numeric: tabular-nums; } .tide-meter { height: 6px; background: #1e1c20; } @@ -216,3 +221,7 @@ body:has(.tide-pool) .theme-toggle, body:has(.tide-pool) .theme-preferences { di .tide-log { display: none; } .tide-status { bottom: 84px; } } +/* Short windows at mid widths: the sheet stays above the raised corner strips too, where there is room for it. */ +@media (max-height: 620px) and (min-height: 540px) and (max-width: 1080px) and (min-width: 721px) { + .tide-inspect { bottom: 136px; } +} diff --git a/public/tide-pool.js b/public/tide-pool.js index ae4f668..d592f65 100644 --- a/public/tide-pool.js +++ b/public/tide-pool.js @@ -1809,7 +1809,10 @@ async function initialize() { if (following) { goal.x = c.x; goal.z = c.z; clampGoal(); } wake(); }); - $('#tide-release').addEventListener('click', () => { release(); status.textContent = 'Released. Tap any machine to follow it.'; canvas.focus(); }); + // The close button in the sheet's corner lets go just as Release does. + root.querySelectorAll('#tide-release, #tide-inspect-close').forEach(b => b.addEventListener('click', () => { + release(); status.textContent = 'Released. Tap any machine to follow it.'; canvas.focus(); + })); // A quiet ticker of notable events near the view. const ticker = $('#tide-ticker'); diff --git a/src/components/tide-pool.tsx b/src/components/tide-pool.tsx index 70fde96..e44784b 100644 --- a/src/components/tide-pool.tsx +++ b/src/components/tide-pool.tsx @@ -82,6 +82,7 @@ export function TidePoolContent() {

Specimen

—

+
Generation
—
@@ -141,7 +142,7 @@ export function TidePoolContent() { {/* Lets the three.js add-ons resolve the same pinned module the page already uses. */} + ); } diff --git a/src/index.tsx b/src/index.tsx index 964eee1..a67c991 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -187,7 +187,7 @@ app.get("/other", async (c) => { // Commissioned public artwork, listed under Other. Unlike the artifacts, it is indexable. app.get("/tide-pool", async (c) => { const stream = renderToReadableStream( - + ); diff --git a/src/tide-pool.test.tsx b/src/tide-pool.test.tsx index 534b066..6213438 100644 --- a/src/tide-pool.test.tsx +++ b/src/tide-pool.test.tsx @@ -20,6 +20,7 @@ test("public tide pool keeps the shell and progressive enhancement with an immer assert.ok(!html.includes("tide-still")); assert.ok(html.includes('id="tide-canvas" hidden')); assert.ok(html.includes('id="tide-sound" aria-pressed="false" disabled')); + assert.ok(html.split('id="tide-inspect"')[1].split("")[0].includes('