On kiosk, chromium runs software-composited (--in-process-gpu or
--disable-gpu, one raster thread). The dashboard's 3D-transformed
will-change background layers and the infinite mix-blend-mode:multiply
fixed overlays routinely fail to repaint there after the first
interaction/route change, leaving the container's black fill (or a stuck
multiply layer) covering the screen.
A kiosk-mode class is now set on <html> (localStorage kiosk flag, ?kiosk
param, or the /kiosk boot path) and gates CSS overrides: background
layers become plain 2D opacity crossfades (no preserve-3d/translateZ/
will-change) and the animated multiply overlays are disabled.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two causes of the fresh-install 'loads, refreshes, loads again' jank:
- The PWA autoUpdate service worker claims the page right after the very
first load, firing controllerchange, which unconditionally reloaded the
page. Now only a *replaced* controller (a real update) triggers reload.
- A single 2s RPC echo decided server-down on first boot, flashing the
BootScreen and then hard-reloading seconds later. A second, 6s attempt
now runs before concluding the backend is down.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The remote-companion popup fired on a blind 5s timer while the
first-visit dashboard entrance cinematic runs for 8s, so on a fresh
install it appeared mid-reveal and broke the intro. The cinematic now
publishes an introCinematicPlaying flag via the loginTransition store,
and the popup waits for it to clear (plus a 2s grace) before showing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three first-visit-experience bugs, all caught by the new e2e suite
(e2e/intro-experience.spec.ts — 5 tests against the demo stack on real
Chrome, instrumenting HTMLMediaElement/WebAudio/MutationObserver since
headless can't hear or see the cinematic):
- playDashboardLoadOomph was always silent: the login→dashboard route
change closes the AudioContext (stopAllAudio), and the oomph only
fetched the dead context. It now recreates one, riding the login
click's sticky user activation.
- A direct /login load in the demo hijacked into the splash: App.vue
read route.path before the router resolved the initial navigation, so
every deep-route boot looked like a root boot. The splash decision now
reads window.location.pathname.
- Replayed intros ran mute (enableCinematicSounds override) and the
intro's shortcut exits skipped the dashboard finale (flag now armed on
both demo and login exits).
Verified: 5/5 e2e, 673/673 unit, vue-tsc clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- SplashScreen no longer re-checks neode_intro_seen itself: it silently
skipped the whole logo-tap/typing sequence for any browser that had
seen the intro before, even when App.vue explicitly requested it (demo
fresh visits, Replay Intro). App.vue is the single decision point.
- Intro video re-encoded 12.7MB/12.6Mbps → 4.3MB/4.2Mbps (1920x1080 CRF23
faststart, muted track dropped) — visually identical on this
illustrated content; cache-buster bumped to v=8.
- Video is <link rel=preload>ed the moment the splash is scheduled (the
<video> element only mounts ~20s in, so cold caches used to start the
download mid-sequence and stutter).
- nginx demo cache regex now covers mp4/webm/mp3/webp/woff2 so repeat
visits play from browser cache.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Login video continuity, cloud bottom-bar music player, demo intro on
every visit — regenerated the What's New block to match.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The login page sometimes swapped to a random bg-intro-N still on load,
breaking the seamless handoff from the intro video. Now: until anyone
has logged in / set a password (neode_first_login_done, stamped by every
Login success path incl. TOTP and setup), /login keeps the VIDEO
background — one continuous shot from the splash. From the second login
onward the lock screen rotates through the static backgrounds as
designed, and if the static path is ever hit pre-first-login it pins to
bg-intro.jpg (the video's end frame) instead of rotating.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
FileCard audio clicks now emit play (global GlobalAudioPlayer bar) —
wired through the FileGrid list view, the Cloud My Files list and own
search results. Peer Files already used the bottom bar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Demo boots at '/' (first visit or a browser refresh) always start with
the typing splash into the onboarding intro — the per-calendar-day
gate is gone. In-session SPA navigation never replays it, and
deep-route refreshes keep the visitor's place.
- Cloud top-level tabs return to the standard mode-switcher style on
desktop; the orange full-width switcher stays mobile-only.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The cloud tabs rework added useCloudStore() to Cloud.vue's setup; this
older test mounted without a Pinia instance and failed the release gate.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
'Add Service' only worked for the 19 apps in the hardcoded
known_service_port map — everything else failed with 'Unknown app'.
tor.create-service and tor.toggle-app now fall back to the app's live
launch address from the scanner state, so any manifest-driven app gets
a .onion without a per-app entry (the static map still wins for
protocol services like bitcoin, which must expose 8333, not a UI port).
toggle-app also no longer writes a broken port-0 HiddenServicePort for
unknown apps.
Every successful package.install now auto-creates the app's hidden
service (detached, best-effort, retries while the scanner derives the
port; skips protocol services and existing entries).
The demo mock gains stateful tor.create-service/tor.delete-service so
the demo round-trips instead of erroring.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- playDashboardLoadOomph gated itself silent on the one entry that
should be loud: onboarding is already flagged complete by the time the
post-wizard dashboard mounts. force flag restores the full oomph there
while keeping ordinary re-logins quiet (the intentional limit).
- OnboardingDone now hands Login a one-shot finale flag, so the login
right after the wizard gets the full zoom + oomph even as a regular
password login — which is exactly the demo flow (and TOTP logins).
- 'Replay intro' on the login screen actually replays: App.vue was
instantly re-marking the intro as seen on onboarded nodes; an explicit
one-shot replay flag now overrides every suppression rule (unit
tested).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
24-item catalog across films/series/books/music/photography/documents/
software with full metadata; deterministic per-peer subsets so every
node shares a different mix. Posters/covers/photos are committed JPEGs
(demo/peer-media, sourced via picsum.photos); previews always serve real
image bytes, and free music/photos/documents stream the actual committed
files so playback genuinely works.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Top-level Cloud tabs get their own orange-tinted switcher (clearly
distinct from the category pills); full-width thirds on mobile
- 'All Files' tab renamed Folders; categories only show on the file-list
tabs (My Files / Peer Files / search)
- My Files is now a flat list of every own file rendered with FileCard —
real actions (share/download/delete) and clicking opens the FILE
(media lightbox incl. audio, downloads for documents), never a folder;
own search results get the same treatment
- Folder list rows get card backgrounds (readable over the wallpaper),
same info as before
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cloud gets the same header layout as Apps: All Files / My Files / Peer
Files tabs, Photos & Video / Music / Documents category filter, and a
search bar that queries your own FileBrowser sections (depth-limited
walk) plus every federation peer's shared catalog (content.browse-peer
fan-out, cached), with a loader while it runs. Peer Files lists the
actual files from all peers with attribution. Mobile uses the Apps
category-pill strips (which already opt out of the page-switch swipe)
with search below — no fixed top tabs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Send modal gains an Ark tab (address/invoice/lightning-address via
wallet.ark-send), Receive gains an Ark address + QR tab, and the peer
file purchase confirm offers Ark alongside Cashu/Fedimint. Demo mock
exposes ark_sats in wallet.ecash-balance and deducts the chosen rail on
paid downloads.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
nginx regex locations outrank prefix locations, so app-shell assets like
/app/bitcoin-core/tailwind.css and /app/lnd/qrcode.js hit the .css/.js
cache block and 404'd from the web root instead of proxying to the mock
backend — the actual cause of the unstyled Bitcoin UI (and the shabby
lnd-ui) on the demo. ^~ on the /app/ prefixes disables regex matching
for those paths. Config validated with nginx -t.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The official shell reads poorly inside the demo iframe; serve a
demoAppShell dashboard (balances, channels, node URI) consistent with
the /proxy/lnd/v1/* mocks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Applying DNS assigned the RPC response's fields into networkData without
guarding the shape; the demo mock answered {success:true} with no
servers array, dnsServers became undefined, and the dnsDisplayLabel
computed crashed the whole page render on .length. Guard the assignment,
teach the mock to round-trip DNS state per session, and Teleport the
WiFi + DNS modals to body so they overlay the full app instead of just
the right panel (position:fixed is containing-block-relative inside the
dashboard).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ark tab in Wallet Settings (status, balances, receive address,
board/offboard, server config via wallet.ark-*), teal Ark badge in the
transactions modal, Ark row on the home wallet card (hidden until barkd
reports a balance), official bark icon, and wallet.ark-* mocks so the
public demo renders the tab.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The v1.8.00-alpha changelog section never shipped as an OTA (no tag, live
manifest stayed 1.7.99-alpha); its content ships now as v1.7.100-alpha.
First 10 bullets are the OTA manifest changelog.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The mempool placeholder page (777d54ea) is served by the mock backend, but
the demo web nginx still had a location block reverse-proxying /app/mempool/
to mempool.guide, so it always won and the placeholder was unreachable.
Drop the block so mempool falls through to the generic /app/ backend proxy.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Companion QR overlay: demo builds encode the demo's own origin
(/packages/archipelago-companion.apk ships in the web image) instead of
the vps2 raw URL.
- Dockerfile.web/.backend: build-time scrub replaces every remaining
occurrence of the release-server address with registry.demo.internal and
fails the build if any survives.
- Mock backend update-mirror list, sideload help text, and changelog prose
no longer name the server address.
- Copy demo-images workflow into .gitea/workflows/ — Gitea ignores
.github/workflows when .gitea/workflows exists, so the CI never ran.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The public demo has no synced chain/electrs, so opening Mempool 502'd.
Serve a self-contained branded placeholder from the mock instead.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Open/Close Channel modals sat at z-[60], BEHIND the wallet settings
BaseModal (z-3000) — clicking 'Open Channel' looked like nothing
happened while the form changed in the background. Raised to z-3100.
- TransactionsModal gains rail filter chips (All / On-chain / Lightning
/ Ecash with counts): instant ecash micro-payments were burying the
standard transactions.
- Global LND seed-backup banner: once the wallet exists and the seed is
un-acknowledged, a dismissible glass banner (24h snooze) prompts and
routes to the LND backup card; polls only when authenticated, stops
permanently once acked.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Request-to-Peer (Federation Discover modal + Web5 Node Visibility list)
no longer fires instantly: a BaseModal confirm shows the target, an
optional 280-char message (handshake.connect already carried it), and
Send/Cancel with the standard orange CTA.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The global mesh-detection poll (added for the device-detected modal)
fired on the login page, 401'd, and the session-expired handler
redirected to /login — reloading the page we were already on, forever.
Background polls now run only when authenticated, and a 401 never
redirects when the path is already /login.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Parity with the backend's invite trust threading so the demo's Invite a
Peer / Link Your Nodes flows show the right level end-to-end.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Native select arrows rendered with inconsistent right padding across
views and long labels could overflow into the icon. Global select rule:
appearance-none + a single SVG chevron at a fixed inset, uniform
padding-right (overrides ad-hoc pr-* utilities), ellipsis truncation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Plugging in a LoRa radio now pops a global two-step setup modal on any
page: step 1 shows the ACTUAL detected board (25 board SVGs vendored
from the Meshtastic web-flasher, GPL-3.0; matched by USB product string
on native-USB boards, vid:pid heuristics for bridge chips, animated
fallback otherwise); step 2 configures with Archipelago presets — the
LoRa region pre-selected from the node's location (new lat/lon→region
mapping), channel 'archipelago', node name, and an advanced firmware
pin. Options adapt per protocol: region+channel program Meshtastic;
MeshCore shows its community frequency plan (firmware owns RF); RNode
defers to the Reticulum daemon config.
Backend: mesh.configure now accepts lora_region (validated against the
driver's region table) and device_kind (probe pin); mesh.status returns
the persisted values plus per-port USB identity (sysfs vid/pid/product)
for board identification. The Mesh Device tab gains a full settings
form (region with duty-cycle/legality hints, firmware pin, channel,
name, identity broadcast) replacing the read-only panel; the old
Mesh-page-only onboarding modal is superseded by the global flow.
Mock backend: stateful mesh config so the dev UI demos the full
detect→configure round-trip (disable mesh → modal fires with Heltec V3).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
484.kitchen, Arch Presentation, Call the Operator, Next Web News
Network, Syntropy Institute, and T-0 were hardcoded web-only bookmark
apps (no manifests/containers). Removed across the frontend app grid /
curated / marketplace / session / launcher data, the backend
AppMetadata table, their icons, and the nginx /ext/ proxy blocks
(external-app-proxies.conf deleted — nothing installed it anymore).
botfights/nostrudel/gitea keep the shared external-app code paths.
Frontend: vue-tsc clean, 672 tests pass, production build verified
clean of the removed slugs. Backend: cargo check clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The old tri-state (hidden/discoverable/public) was confusing — its
'discoverable' level implied discovery by already-connected federated
peers, which is meaningless. The card is now a single Enable switch
(global ToggleSwitch style) that drives nostr presence publishing:
ON = public — anyone can find the node and request a connection
(requests join as Peer/observer on approval, never trusted).
The card also lists nostr-discoverable nodes inline with Request-to-Peer
buttons (same handshake.connect flow as the Federation Discover modal,
which stays available in Federation & Peers).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Federation List/Map tabs now use the Home mode-switcher tablist
(full-width on mobile, shrink-wrapped on desktop, proper tablist a11y)
- Network Interfaces WLAN adapter toggle replaced with the shared
ToggleSwitch used by AI data access in Settings; ToggleSwitch gains
optional disabled/ariaLabel props (non-breaking)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- openwrt.get-status/scan/scan-wifi/provision-tollgate/configure-wan
mocked: 19-day-uptime GL-MT3000 TollGate gateway, two open TollGate
SSIDs + private SSID, live upstream WAN, 21 sat/min pricing (edits
via the reconfigure form persist in mock state)
- handshake.discover returns 4 discoverable nodes; nostr.set-discovery/
discovery-status stateful; handshake.connect + pending-request
approve/reject round-trip against mock state (incl. one inbound
request for the demo)
- node-nostr-discover (Web5) list grown to 5 nodes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The app-details credentials/version sidebar and the container-app Launch
button used solid bg-blue-600 CTAs and blue links/focus rings instead of
the global glass style; InstallVersionModal used an off-token solid
orange. All primary CTAs now use glass-button glass-button-warning (the
Create Identity orange) and links/focus accents use the orange tokens.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The invite type chosen in QuickActions was only used for the modal
title — the RPC never carried it, so every invite was minted Trusted.
Pass it through so 'Invite a Peer' mints observer invites and 'Link
Your Nodes' keeps trusted ones.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Jul 10 asset swap (75ed3041) replaced the progressive JPEG with a
baseline re-encode that trips the known Chromium compositor black-layer
bug in the 3D perspective background stack — the image paints for a
second, then the layer drops and the #000 container fill shows through.
Restore the pre-swap progressive encoding.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>