Skip to content

SlowGuardian V10 — ground-up LTS recode (Scramjet-only, Astro frontend) - #19

Open
zgr2575 wants to merge 40 commits into
mainfrom
claude/slowguardian-v10-recode-ji8x55
Open

SlowGuardian V10 — ground-up LTS recode (Scramjet-only, Astro frontend)#19
zgr2575 wants to merge 40 commits into
mainfrom
claude/slowguardian-v10-recode-ji8x55

Conversation

@zgr2575

@zgr2575 zgr2575 commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Ground-up, LTS-focused rebuild of SlowGuardian, developed under v10/ so this PR is purely additive — V9 at the repo root is untouched. The V8 and V9 code is preserved on the legacy/v8 (a91599b, Version8.9a) and legacy/v9 (current main) branches before any future cutover.

Version 10.0.0-rc.1. This lands the app + tests + CI + Docker; the 1.0 flip, GHCR publish, and the actual root cutover are deliberately left as a follow-up.

What's inside

  • Proxy coreScramjet over Wisp (wisp-js), a single service worker, bare-mux + epoxy-transport, COOP/COEP cross-origin isolation. Express on a raw node:http server, crash-only, envalid config, pino logging. Bundles are served straight from node_modules so the bytes always match the installed version.
  • Frontend — Astro 5 static MPA, Apple-style Liquid Glass (dark-first), a Dynamic Island nav, tuned for 2016–2019 Chromebooks (blur → solid glass under a perf dial).
    • Home — Google-style search lander.
    • Games / Apps — Netflix-style library over the real 284-game / 55-app catalog: billboard → shelves → a dense full-width "All" grid.
    • Proxy (/go) — Chrome-style multi-tab in-app browser (tab strip, pill omnibox, fullscreen, open-in-new-window, always-there Quick Exit, Chrome-style new-tab page).
    • Privacy — tab disguise (12 school-app presets + custom, live preview), one-key Quick Exit (decoy + rebindable key; global double-Esc), the opt-in about:blank cloak (a faithful port of V8's createAboutBlank, minus the V9 auto-run bug), and clear-traces.
    • Settings — theme, 4 accents, performance dial, and a search-engine picker.
    • Onboarding — one-time first-run flow.

Phases (all verified)

  • P1 Proxy core — SW + wisp + Scramjet + bare-mux/epoxy, COOP/COEP; proxied a live site end-to-end.
  • P2 Frontend — Astro MPA, Liquid Glass, catalog + multi-tab proxy UI.
  • P3 Privacy — tab disguise, quick exit, about:blank cloak, clear-traces.
  • P4 Stability/healthz + /readyz, Playwright smoke test, CI, Docker.
  • Parity — audited V9; added onboarding, search-engine choice, expanded cloak presets, proxy fullscreen/pop-out.

Testing / CI / Docker

  • npm run test:e2e — Playwright, 6/6: lander, library, health, COOP/COEP, first-run onboarding, and a full proxy round-trip against a local fixture (SW → bare-mux → epoxy → wisp → Scramjet), so it never depends on live internet.
  • npm run test:wisp — zero-dep /wisp/ upgrade handshake.
  • .github/workflows/v10-ci.yml — build frontend → Chromium → wisp handshake → Playwright e2e, plus a parallel docker-build job. Scoped to v10/**, independent of the legacy test-sw.yml.
  • v10/Dockerfile — multi-stage, non-root, /readyz HEALTHCHECK. Build from the repo root: docker build -f v10/Dockerfile -t slowguardian:10 .

Intentionally not carried over from V9

Full transparency map in v10/README.md. In short (all previously agreed): one proxy engine only (dropped UV / Dynamic / Rammerhead / failover), no accounts / premium / ads / KeyAuth (public proxy + single env-password admin gate; ZADMIN is a separate future project), no MongoDB (embedded SQLite), no monitoring-evasion (privacy defends against a shoulder-glance, not network/device monitoring — and the UI says so), music/Spotify reserved for a future integration, and the theme-zoo / particles / plugins / movable-buttons / 100-feature-manager / home widgets superseded by the approved Liquid-Glass design.

Deploy

Split: static frontend on Vercel, persistent Wisp backend on Render; one Docker image is the canonical artifact. Re-confirm HTTPS proxying on the first real deploy (a TLS-intercepting dev egress correctly fails epoxy's cert validation).

🤖 Generated with Claude Code


Generated by Claude Code

claude added 27 commits July 4, 2026 01:31
Adds V10_RECODE_PLAN.md — a stability-first, ground-up recode plan
derived from a full V9 code audit and research into modern web-unblocker
architecture, stealth/cloaking, frontend, and backend/LTS practices.

Core decisions proposed:
- Collapse 5 proxy engines to one (Scramjet) over a single Wisp transport
- One service worker, one auth path; cut Spotify/KeyAuth/AdSense/Replit DB
- Astro MPA frontend; Express backend kept; better-sqlite3/memory storage
- Real test pyramid incl. Playwright proxy smoke test; LTS branch + release-please
- Honest stealth: default tab-cloak + fixed panic key, opt-in about:blank/blob

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Revise the deploy plan to keep Vercel support (per maintainer): static
Astro frontend on Vercel, persistent Wisp proxy backend on Render/Railway/
Fly/self-host. Adds section 6.1 documenting the split-deploy topology and
why running Wisp as Vercel serverless functions is not viable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
- DESIGN_V10.md: judged design-system spec (NEON DECK arcade-console
  direction chosen for surviving the Chromebook perf budget; absorbs
  command palette + film-grain from the runner-up directions). Full
  token set, theming architecture, component inventory, motion set,
  performance-mode strategy, and CI-enforced budgets.
- docs/design/v10-neon-deck-mockup.html: self-contained clickable
  mockup — live theme (Arcade/Midnight/Carbon/Paper) + accent switching,
  catalog search/filter over real titles, command palette, tab-cloak
  and panic demos. All effects static CSS or compositor-only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Scrap the arcade/neon mockup per maintainer direction. New UI is
Apple Liquid Glass, dark-mode-first: translucent frosted material,
specular edges, ambient light field, floating panels, one restrained
accent. Real backdrop-filter on capable devices with a solid-glass
fallback (@supports + data-perf) so old Chromebooks stay smooth.
Light Liquid Glass available via toggle. Includes live accent
switching, catalog search, and a Cmd-K command palette.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Start the ground-up recode under v10/ (alongside V9 until cutover so
main stays shippable). Adds the design-token stylesheet extracted from
the approved Liquid Glass direction, and a BUILD_STATUS tracker with
the locked decisions and phase checklist.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Replace the flat filter-grid (felt cluttered) with a featured billboard
hero + side-scrolling category rows of landscape tiles (title overlaid
on the art, scroll-snap, bleeds off the edge). Search collapses rows
into a results grid. Fixes a .row class collision with the command
palette that broke row-header layout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Maximize screen usage per feedback: widen container to 1440, cut excess
vertical padding, shrink the featured billboard, and densify library
tiles (6/row on a 1366 Chromebook, 2-up on phone with the next peeking).
Drop the redundant monogram from tiles (collided with the title on short
tiles); title now sits on a bottom bar with ellipsis for long names.
Add scroll-margin so anchored sections clear the sticky nav.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Ditch the generic nav bar for an iOS Dynamic Island: a compact centered
glass pill (brand + live status) that morphs open on hover/tap to reveal
the links, search, and theme toggle (springy width transition, ambient
status collapses as controls expand). Merge the two search boxes into
one — the island search / Cmd-K palette, which now also searches game
titles. Tuned to fit on phones. Removes the duplicate library search.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Each nav tab gets an icon (Games=controller, Apps=grid, Proxy=globe,
Privacy=lock); active tab icon tints with the accent. The island now
collapses label text away below 900px so the pill reduces to icon-only
on small laptops and phones, keeping it compact on small screens.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Per maintainer: remove Replit (nix + dead Replit DB dep); keep Vercel
(split-deploy, already set); keep the about:blank cloak (opt-in, gesture-
triggered, never auto-on) and the multi-tab in-app browser in 1.0 scope.
Update BUILD_STATUS locked decisions + phase checklist accordingly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Per maintainer: ship a single engine (Scramjet) over Wisp for maximum
LTS stability and bisectable bug reports. Ultraviolet stays a documented
post-1.0 escape hatch, added only if the nightly live-site test proves a
real compatibility gap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Resolved with maintainer:
- Accounts: public proxy + single admin gate (no user sign-ups)
- Admin auth: pluggable adapter; will use forthcoming ZADMIN Auth system,
  env-password placeholder for 1.0
- Storage: better-sqlite3 (no MongoDB)
- Deploy backend: Render (frontend stays on Vercel)
- Music/Spotify slot: reserved for a future project integration (TBD)
- Mirror/reachability: post-1.0
- LTS window: 6 months active + 6 security-only
- Git history: leave intact, stop tracking big files going forward

All Section 9 decisions now closed; BUILD_STATUS is the source of truth.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Per maintainer: do not do any ZADMIN work yet (not even an adapter).
1.0 ships a simple env-password admin gate; ZADMIN is a separate future
project to be picked up only on the maintainer's go-ahead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
The working single-engine proxy pipeline:
- Express serves the app + scramjet/bare-mux/epoxy browser bundles straight
  from node_modules (no guessed paths); raw node:http owns the 'upgrade'
  event so wisp-js routes /wisp/ tunnels, non-wisp upgrades dropped.
- COOP same-origin + COEP require-corp on every response (cross-origin
  isolation for Scramjet WASM + epoxy).
- One service worker (public/sw.js) via $scramjetLoadWorker.
- Client (public/boot.js) registers the SW + sets the epoxy transport at
  /wisp/ eagerly on load, then navigates via the Scramjet controller.
- envalid fail-fast config, pino logging, crash-only handlers that LOG
  (no process.exit mid-request), graceful shutdown.

Pinned co-released set: scramjet 1.1.0, wisp-js 0.4.1, bare-mux 2.1.9,
epoxy-transport 2.1.28 (2.x keeps the node epoxyPath helper).

Verified locally: /healthz, COOP/COEP headers, all bundles 200, wisp
handshake (101 / dropped), and a live HTTP site rendered fully-styled
inside the Scramjet frame end-to-end. HTTPS blocked only by this dev
sandbox's TLS MITM (epoxy correctly rejects the private CA) — confirm on
first Render deploy. Includes zero-dep test/wisp-handshake.mjs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
…y UI

Ports the approved design to an Astro 5 static MPA under v10/web/,
served by the Phase 1 Express server (now serves web/dist/, falling back
to public/ when unbuilt):
- Liquid Glass, dark-first, with the Dynamic Island nav (per-tab icons,
  icon-only collapse), theme/accent/perf controls, command palette.
- Netflix-style library over the REAL catalog: content collections
  (Astro 5 file() loader + Zod) built from V9's 284 games / 55 apps,
  featured billboard + side-scrolling shelves, real icons.
- Proxy-integrated /go page: Liquid Glass multi-tab browser (tabs,
  address bar, always-visible Exit/quick-exit) reusing the verified
  Phase 1 Scramjet/Wisp wiring.
- Settings/privacy pages with honest 'quiet on a shared screen' copy.

Verified: astro build green (5 pages); home/apps/settings render; the
new multi-tab go page proxied a live site (httpforever.com) end-to-end.
Icons synced from committed static/ at build (prebuild) — not duplicated
in git; dist/.astro/node_modules gitignored.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
…e.html)

The showcase is a self-contained single-file build of the V10 UI with
real catalog icons embedded as data URIs (~1.4MB) for the clickable
Artifact. It's reproducible from the mockup + catalog, so keep it out of
git rather than committing the heavy generated file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
The Dynamic Island nav now switches between distinct pages — Games,
Apps, Proxy, Privacy, Settings — instead of one long scroll, matching
the real Astro MPA. Adds: a client-side router (showView) wired to the
island links + brand + omnibox + palette; an Apps page (its own catalog
+ shelves); a Proxy page with a multi-tab browser mock (tab strip,
address bar, always-there Exit); tiles now support real icon images
(falling back to gradient). Settings gets its own nav entry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
- Home is now a clean, search-first page (centered logo + omnibox +
  Games/Apps/Surprise-me quick links), not a marketing lander; it's the
  default view. The Netflix library moves to its own Games page.
- Proxy page rebuilt as a real browser: dropped the marketing heading,
  the tab strip + address bar + frame now fill the viewport edge-to-edge
  (no wasted space).
- Content views get top padding so they clear the floating island.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Every view now fills the viewport with the footer anchored to the bottom
instead of floating up mid-screen. Content-rich views (games/apps/settings)
sit below the Dynamic Island and scroll; sparse views (home/privacy) center
their content in a sticky-footer flex column.

Settings was the emptiest screen — replaced the lone appearance bar with a
three-card grid (Performance toggles, Privacy & exit, About/version) so it
reads as a genuine settings page and has no dead space.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
… space

Proxy view now reads like Google Chrome: real tab strip (rounded connected
tabs, hover states, close affordances), a Chrome toolbar with circular
nav buttons, a pill omnibox with a lock glyph, and a bookmark / menu /
profile-avatar cluster. The empty content frame is replaced by a Chrome-style
new-tab page — wordmark, search pill, and a grid of shortcut tiles — so the
workspace fills the viewport instead of showing a lone centered note.

Apps now mirrors Games: a featured billboard sits above the Netflix-style
shelves so the page opens with the same weight as the game library.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Adds a packed, edge-to-edge grid of the entire catalog below the Netflix
shelves on both library views (auto-fill columns, 6 on a 1280 screen / 9 on
1920), and widens the library column to 1780px so wide monitors aren't
half-empty. Search hides the games grid so results stay clean.

Work in progress under review — not final.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Home is no longer a lone centered search box: below the search hero it now
carries real content shelves (Jump back in / Popular games / Top apps) that
fill the page top to bottom.

Proxy new-tab page top-aligns like real Chrome and gains a "Recently visited"
card row, so the workspace fills instead of centering a small block in an
empty frame.

With the earlier dense All grids on games/apps and the three-card settings
page, no view leaves a large empty band.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Revert the home content shelves — the Google-style centered lander (logo +
search + quicklinks) was the intended design. Games/apps keep their dense
grids and the proxy keeps its filled new-tab page; only home goes back to
the minimal search-first landing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Bring the real app in line with the approved mockup (docs/design):

- Home "/" is now the Google-style search lander (logo + omnibox + quick
  links); the games library moved to /games. Nav + ⌘K routes updated.
- Games/Apps gain a dense full-width "All" grid below the Netflix shelves
  so wide screens fill edge to edge; dropped the in-library search field
  (search is unified into the ⌘K palette). Library column widened to 1780px.
- /go proxy reskinned to look like Google Chrome — Chrome tab strip, pill
  omnibox with lock/globe, menu + profile avatar, and a Chrome-style
  new-tab page with shortcut tiles. The verified multi-tab Scramjet wiring
  (IDs, JS) is untouched; this is purely the skin + the full-height shell.
- /settings rebuilt as the three-card grid (Performance / Privacy & exit /
  About); performance mode, tab disguise, and clear-traces stay wired.
- Sticky-footer full-height layout across every page.

Build green (6 routes); every page verified against src/server.js with no
console errors and the proxy engine reaching "ready".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Complete the opt-in about:blank cloak on /privacy as a clean port of V8's
proven createAboutBlank (static/assets/scripts/h.js), minus the V9 auto-run
bug. The prior Phase-2 launcher only opened a blank window; this restores the
three parts of the working V8 flow that make it an actual cloak:

- redirect the ORIGIN tab to the decoy (sg:panicUrl) after launch, so nothing
  left on screen points back at SlowGuardian;
- a beforeunload guard in the blank document so an accidental close asks first;
- a Firefox guard (Firefox blocks scripting an about:blank popup) with an
  honest fallback message.

Still gesture-triggered and opt-in (sg:aboutblank); the blank window loads
SlowGuardian in a full-page iframe wearing the sg:cloak title/favicon. Copy
updated to state plainly that this tab switches to the decoy and that it does
not bypass network filtering or device monitoring.

Verified end-to-end in headless Chromium: popup opens with the disguise title,
iframe src = origin, beforeunload set, origin tab redirects to the decoy, no
console errors. Mirror rotation stays post-1.0 per the locked decisions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Health & readiness:
- /healthz now returns {ok, version, uptime}; new /readyz returns 200/503
  with a per-asset check list (proxy bundles + built frontend must actually
  resolve). Load balancers gate on /readyz.

Proxy smoke test (Playwright, test/e2e.spec.mjs):
- Boots the real server (webServer waits on /readyz), asserts the lander and
  games grid render, health + COOP/COEP headers, and — the key case — proxies
  a LOCAL fixture end-to-end (SW → bare-mux → epoxy → wisp TCP → Scramjet),
  so it never depends on live internet. 5/5 pass in headless Chromium.
- wisp-js blocks loopback/private IPs by default (SSRF hygiene); enabled
  allow_loopback_ips ONLY under NODE_ENV=test so the fixture is reachable —
  dev/prod stay locked (allow_private_ips stays false everywhere).

CI (.github/workflows/v10-ci.yml, scoped to v10/**, independent of the legacy
test-sw.yml): build frontend → install Chromium → wisp handshake → Playwright
e2e; plus a parallel docker-build job that builds the image (no push) so the
Dockerfile is validated on every change.

Docker (v10/Dockerfile): multi-stage — build Astro frontend, resolve prod-only
server deps (drops the test browser), slim runtime with a /readyz HEALTHCHECK
running as the node user. Builds from the repo root (the web build sources the
catalog icons from repo-root static/); .dockerignore added at the root.

Tooling: swap the unused puppeteer-core devDep for @playwright/test; add
build:web / test:wisp / test:e2e scripts; version 10.0.0-phase1 → 10.0.0-rc.1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Audited V9 against V10 and closed the real gaps (clean rebuilds, no bloat):

- Onboarding: a one-time first-run modal (web/src/components/Onboarding.astro,
  rendered from Base) — welcome → appearance (theme+accent, applied live) →
  privacy (tab disguise / about:blank opt-in) → done; guard sg:onboarded.
  Uses the shared window.SG API so choices persist. Playwright-tested.
- Search-engine choice: Settings picker (Google/Bing/DuckDuckGo/Startpage/
  Brave/Ecosia/custom) → sg:engine template; both the lander and the proxy
  omniboxes honor it instead of hardcoding Google.
- Tab-cloak presets expanded 4 → 12 (adds Slides, Gmail, Meet, Canvas,
  Schoology, Khan, Wikipedia, PowerSchool) alongside custom title/favicon.
- Proxy utilities: Fullscreen + Open-in-new-window (Ctrl+T/W/L intentionally
  skipped — they collide with the host browser's own bindings).

README rewritten with a transparent carried-over / intentionally-dropped /
deferred map so nothing is silently lost. Legacy code preserved on the
legacy/v8 and legacy/v9 branches.

Build green (6 routes); Playwright 6/6 (adds a first-run onboarding test).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
@vercel

vercel Bot commented Jul 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
algebra Ready Ready Preview Jul 30, 2026 4:03pm

Request Review

https://slowguardian-v10.onrender.com is up and working: /healthz + /readyz
all green, lander + onboarding render, and the proxy loaded a live HTTPS
site (example.com) end-to-end through Wisp/Scramjet on a real network —
closing the Phase 1 "re-confirm HTTPS on a real egress" caveat.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
- Settings: drop the marketing headings/jargon; present a plain labeled
  list (Appearance/Accent/Performance/Search/Tab disguise/Privacy/Clear/
  Version) closer to V8/V9 — no "straight talk" copy, no section headers.
- Remove the jargon footer globally (Base.astro).
- Proxy (/go): make the in-app browser fullscreen — full-bleed edge to edge,
  fills the viewport top to bottom (thin gap for the floating island), no
  footer, no rounded box. Verified: shell spans full width, footer gone.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
…-style settings

- Dynamic Island now docks to the top-left and shows icons only until
  hovered/focused/tapped, then morphs open to reveal labels (icon-only on phones).
- Launching a game/app from the library opens the proxy in an immersive mode
  (?app=1): the tab strip, toolbar, status bar, and global nav island are all
  stripped, leaving a full-viewport view of just the content with a small
  floating control cluster (reload / fullscreen / quick-exit / close).
- Settings rewritten as a plain card grid resembling V8/V9: one clear title +
  one-line description + control per card, no marketing copy or page heading.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
The previous change rewrote the shared Dynamic Island for every page. Restore
the original centered island everywhere and move the left-docked, shield-
collapsed (expands on hover/focus/tap) variant behind a .sg-proxy class that
only go.astro sets — set synchronously in <head> so the pill never flashes
centered first. Every non-proxy page keeps the original centered pill.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
The root vercel.json routed every request to index.js (V9's server), so the
connected Vercel project only ever served V9 — V10 lives under v10/web and was
never built. Replace the legacy builds/routes with a static build of the V10
Astro app (v10/web → dist); its prebuild syncs the catalog icons from the
repo-root static/ tree, which Vercel has in the full clone.

Note: the proxy still requires the persistent Wisp backend (Render); Vercel
serves the static frontend only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
The privacy narrative read like a warning label. Removed it everywhere it
appeared and replaced it with plain descriptions of what each control does:

- privacy: delete the "Straight talk." callout; "Quiet on a shared screen." →
  "Privacy controls."; "Hide the address, honestly." → "Hide the address bar.";
  drop the about:blank caveat note and the clear-traces "can't touch records"
  sentence; rewrite the page meta description.
- onboarding: "Quiet on a shared screen" → "Privacy", drop the "Straight talk:"
  fine print (and its now-dead .ob-fine rule).
- proxy new-tab: delete the "not a way past network filtering" fine print.
- docs: stop mandating the copy in README/BUILD_STATUS; the scope decision
  itself (no monitoring-evasion features) is unchanged.

No replacement claims the product defeats filtering or monitoring — each line
just says what the feature does. Verified: 0 matches for the removed phrasing
across all 6 built pages; e2e 6/6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
claude added 2 commits July 29, 2026 18:19
- go: the immersive Close pill inherited display:grid from .gg-immbtn, which
  stacked the X icon on top of the "Close" label so they overlapped inside a
  32px box. Switch it to inline-flex with explicit sizing. Verified: icon and
  label now sit on one row (no overlap, label inside the pill), and it still
  collapses to a 32px round button at 390px wide.
- Base: catalog icons that 404 rendered the browser's broken-image glyph.
  Add a capture-phase error handler that degrades a failed tile/billboard
  image to a lettered placeholder over the existing gradient. Covers tiles
  injected later by search and the palette.
- apps: repoint 4 icons at the files that actually exist on disk
  (gemini.png, instagram.webp, ng.webp, snapchat.webp).
- games: fix a malformed URL, "https:/moomoo.io" -> "https://moomoo.io".

Found by a full catalog audit (339 entries HTTP-checked). e2e 6/6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
CATALOG (full HTTP audit of all 339 entries, then re-verified independently):
Root cause of most rot: github.com/3kh0/3kh0-assets was gutted and moved to
GitLab, killing every raw.githack.com/3kh0/... link; f.silvergames.com and
static.arcadespot.com stopped resolving; now.gg retired its iframe embed API.
- 55 entries repointed at verified-200 replacements (glcdn.githack GitLab CDN,
  gamesfrog, coolmath /play embeds, archive.org /embed, author-renamed Pages).
- 10 entries removed as genuinely unavailable (now.gg cloud-Android titles:
  Fortnite, Toca Boca x3, Stumble Guys, Bloons TD Battles, Cookie Run, Aptoide,
  Roblox NowGG.me, a deleted Replit).
- 7 local games pointed at /y/... and /f/... assets that were never in the repo;
  all now have hosted URLs.
- All 10 missing app icons resolved (4 repointed, 6 fetched).
Result: 0 dead paths and 0 missing icons, from 86 hard-broken. The remaining
503s were confirmed to be this sandbox being rate-limited, not dead hosts
(slither.io/kiomet.com return 200 after a pause), so those were left alone.

UI (3 broken, 5 major — each reproduced and re-verified after the fix):
- reveal animation: threshold 0.12 can never fire for an element taller than
  viewport/0.12, so the ~6000px "All" grid stayed at opacity 0 forever — 90% of
  /games was blank on a Chromebook viewport. Now threshold 0 + rootMargin.
- onboarding: modal was taller than a short viewport with no scroll and no
  dismiss path, hiding Skip/Next. Now scrolls, with sticky actions.
- palette: Library self-wired #cmdList and its focus handler overwrote Base's
  render, so Cmd-K always showed "No matches". Library now registers a source
  and Base owns the list; "mine" returns the Minecraft entries.
- home omnibox: input lacked min-width:0, pushing the Open button out of the
  pill and off-screen at 390px.
- tiles: square logo art was cover-cropped and decapitated; near-square art is
  now letterboxed onto the tile plate.
- nav pill overlapped the library heading on phones; light-theme secondary text
  (2.6:1) and accent links (2.56:1) were under AA; palette had no surface and
  the toast was capped at 50vw and near-invisible.

e2e 6/6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
…fixes

GAMES — the earlier pass only borrowed Interstellar's asset hosts to repair
dead links; this actually adds their catalog. Interstellar doesn't store games,
it proxies 3kh0-assets at request time, so I enumerated that tree directly
(GitLab project 54213496, 412 dirs), diffed it against ours, and HTTP-verified
every candidate:
  412 slugs -> 65 already covered -> 347 candidates -> 306 verified playable
  -> 289 added after dropping dupes and 9 non-games (a Flash runtime, a
  prank "virus" page, utility folders).
Names come from each game's own <title>, cleaned and length-capped. Games: 276 -> 565.

Only 6% of those folders ship artwork, so rather than 273 broken-image tiles,
an entry with no image now renders a deterministic gradient plate carrying its
wordmark (catalog.ts artPlate + .art.noart) — no wasted 404 request per tile,
and the grid reads as designed rather than failed.

UI (continued from the previous commit):
- billboard: it reused the small square catalog icon as a 5.5:1 hero, giving a
  ~9x upscaled blur. Now a blurred backdrop copy plus a crisp contained copy
  held clear of the text (hidden under 760px where there's no room).
- verified in-browser: square logos are contained not decapitated, the All
  grid reveals (opacity 1), no horizontal overflow.

e2e 6/6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
/go UI — it was a browser with a floating nav pill parked on top of its own tab
strip, and 54px of the viewport reserved for that pill:
- hide the pill on /go entirely; the SlowGuardian logo now lives in the browser's
  own toolbar as the way back to the site, and leads the immersive control
  cluster too (logo · reload · fullscreen · quick-exit · Close) so both modes
  read the same way.
- genuinely fullscreen: page starts at y=0, 100dvh. Chrome trimmed 100px -> 83px
  (tab strip 46->39, toolbar 54->44), content viewport 641 -> 684px at 768p.
- the "+" sat ~1100px right of the last tab on a wide screen; it now docks beside
  them. Tabs get cursor:pointer.
- drop the permanent full-width "ready" status bar for a transient corner bubble
  (idle now sets "", so :empty actually fires), stop stealing focus into the
  address bar on arrival (it painted a full-width blue ring), and raise the
  immersive cluster from 45% to 82% opacity since :hover never fires on touch.
- mobile: hide forward/popout/fullscreen so the address bar gets the room.
- remove dead .gg-menu/.gg-avatar rules and the stale .sg-proxy island offsets.

PROXY ON A STATIC HOST — I previously said this was impossible; that was wrong,
and the split was verified end-to-end before making the change. A static host
cannot run /wisp/, but it can drive a remote one:
- web/scripts/copy-proxy-assets.mjs (postbuild) ships scramjet/bare-mux/epoxy
  into dist so /scram /baremux /epoxy resolve same-origin off a static host.
- PUBLIC_WISP_URL selects the wisp backend at build time, falling back to this
  origin so the single-service Render deploy is byte-identical. An https page
  with a ws:// value is upgraded to wss:// (mixed content is the easy mistake).
- vercel.json now sets COOP/COEP (required, Vercel sets neither by default) and
  installs v10's deps so the copy step can resolve the packages.

e2e 6/6 including the proxy round-trip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
epoxy's transport is loaded with a dynamic import(), so a non-JavaScript MIME
on /epoxy/index.mjs would hard-fail the proxy. Vercel's mime-db maps .mjs to
text/javascript and .wasm was observed correct on a live deploy, but the live
check here was intercepted by Deployment Protection (assets 302 to the SSO
login), so this pins both rather than relying on the default.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Set PUBLIC_WISP_URL in the Vercel buildCommand, defaulting to the Render
service and still deferring to a dashboard env var if one is set
(${PUBLIC_WISP_URL:-...}). Verified both build paths:
  vercel buildCommand   -> "wss://slowguardian-v10.onrender.com/wisp/" inlined,
                           same-origin fallback constant-folded away
  npm run build:web     -> no Render host present, same-origin fallback intact
so the single-service Render deploy is unchanged. Render's /wisp/ was confirmed
to accept a wss upgrade carrying the Vercel Origin (HTTP 101, valid accept hash).

e2e 6/6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
…hing

Reported symptom: the address bar showed the requested site but the frame
rendered SlowGuardian's own home page.

Cause: sw.js had no install/activate handlers, and registerSW() only awaited
navigator.serviceWorker.ready. .ready means a worker is ACTIVE, not that this
page is CONTROLLED — a freshly installed worker does not control the page that
registered it until that page reloads or the worker claims its clients. So on a
first visit navigator.serviceWorker.controller was null, the first
/scramjet/<url> request bypassed the SW and went to the network, and a static
host answered it with index.html — i.e. our own lander inside the proxy frame.
On Express the same request 404s, which is why this only showed up on Vercel.

Fix:
- sw.js: skipWaiting() on install, clients.claim() on activate. Also lets a new
  deploy displace a stale cached worker instead of waiting for every tab to
  close (which is why the reported page mixed old and new chrome).
- go.astro: after .ready, wait for controllerchange when controller is still
  null, capped at 5s so a browser that never claims cannot hang the UI.
- both copies of sw.js updated: web/public/sw.js is the one that ships to
  dist/; v10/public/sw.js is the server's Phase-1 fallback. Only the latter was
  edited first and the built output was unchanged — caught by testing the
  SERVED file rather than the source.

Verified on a fresh browser profile against the built output:
  before -> FIRST VISIT controlled: false, frame showed our own page
  after  -> FIRST VISIT controlled: true,  frame title "FIXTURE PROXIED OK"
e2e 6/6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants