diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 9562dc9f5..8fec824e9 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -59,6 +59,24 @@ provider registration rejects compositions that cannot fit rather than truncatin identities. A malformed or duplicate entry invalidates the complete custom-switch field. Existing whole-link size limits still apply. +## Mobile app prototype — October 18, 2026 + +`/mobile/` is a phone and foldable shell over the same engine, specified in +[`mobile/DESIGN.md`](../mobile/DESIGN.md). It has five tabs: a situation feed, +the globe, capture, reconstruction threads and the user's own captures. +`mobile/globe/` is a phone-tuned Cesium engine. It blends Esri day imagery +with NASA Black Marble night lights across the terminator, uses Google 3D +tiles below 25 km when keyed, and builds its layers on the existing `/api` +routes and source parsers. Capture signs each bundle on the device with a +non-extractable ECDSA P-256 WebCrypto key held in IndexedDB. A bundle carries +a SHA-256 media hash, a per-device hash chain, and the IMU and GPS trace. +These signatures are browser equivalents of hardware attestation; they are +not hardware attestation. Hypotheses and authors in the reconstruction +threads are labelled example content. `npm run build` now emits +`dist/mobile/index.html` beside the app, while `npm run build:panel` still +builds the app page alone. `mobile/vision/index.html` is a self-contained +concept mockup with illustrative data and no production code. + ## God's Eye View in conversations — October 2, 2026 Tool answers that can be shown in God's Eye View include a view: camera, layers, diff --git a/mobile/DESIGN.md b/mobile/DESIGN.md index 98e1b6e04..5c8d51679 100644 --- a/mobile/DESIGN.md +++ b/mobile/DESIGN.md @@ -7,7 +7,7 @@ This folder holds two things: | Path | What it is | Tethered to production? | | --- | --- | --- | | [`mobile/index.html`](index.html) → `/mobile/` | **Prototype.** A working phone/foldable app that sets the design language on top of the real engine: CesiumJS, Esri cloudless imagery, NASA Black Marble night lights, Google Photorealistic 3D Tiles (when keyed), and the app's own live `/api` feeds (ADS-B, military, AIS, TLEs, quakes, FIRMS fires, cyclones, launches, CCTV) plus the bundled Bhote Koshi event pack. Capture is real: camera, IMU, GPS and a WebCrypto signature. | Yes. Runs on the existing dev server (`npm run dev`, open `http://localhost:4173/mobile/`). | -| [`mobile/vision/index.html`](vision/index.html) | **Vision.** A single self-contained file with no server, no keys and no production code. It shows where the product goes: the full feed, 4D reconstructions with collaborative hypotheses, the provenance ledger, holograms left in places, a hand-written WebGL globe with a cinematic post chain. | No. Open the file in any browser. | +| [`mobile/vision/index.html`](vision/index.html) | **Vision.** A single self-contained file with no server, no keys and no production code. It shows where the product goes: the full feed, 4D reconstructions with collaborative hypotheses, the provenance ledger, holograms left in places, a hand-written WebGL globe with a cinematic post chain. | No. Open the file straight from disk in any browser (the dev server's CSP blocks its inline script). Rebuild it with `node mobile/vision/build.mjs`. | --- diff --git a/mobile/vision/assets/day.webp b/mobile/vision/assets/day.webp index 82d693251..607ebd3a8 100644 Binary files a/mobile/vision/assets/day.webp and b/mobile/vision/assets/day.webp differ diff --git a/mobile/vision/assets/night.webp b/mobile/vision/assets/night.webp index b2c5f2590..d9178c1a2 100644 Binary files a/mobile/vision/assets/night.webp and b/mobile/vision/assets/night.webp differ diff --git a/mobile/vision/index.html b/mobile/vision/index.html index e45c79f63..f80ac0f64 100644 --- a/mobile/vision/index.html +++ b/mobile/vision/index.html @@ -294,7 +294,7 @@ input, textarea { font: inherit; color: inherit; } .hud svg { position: absolute; inset: 0; width: 100%; height: 100%; } .hud .tape { position: absolute; top: 50%; transform: translateY(-50%); font-size: 15px; font-weight: 600; padding: 6px 9px; border: 1px solid rgba(190,255,200,.55); border-radius: 6px; background: rgba(0,20,8,.25); } .hud .tape small { display: block; font-size: 9.5px; opacity: .7; font-weight: 500; } -.chat { position: absolute; left: 12px; right: 12px; bottom: calc(var(--sab) + 72px); height: 46%; display: flex; flex-direction: column; justify-content: flex-end; gap: 8px; pointer-events: none !important; mask-image: linear-gradient(to top, #000 70%, transparent); -webkit-mask-image: linear-gradient(to top, #000 70%, transparent); } +.chat { position: absolute; left: 12px; right: 12px; bottom: calc(var(--sab) + 72px); height: 34%; display: flex; flex-direction: column; justify-content: flex-end; gap: 8px; pointer-events: none !important; mask-image: linear-gradient(to top, #000 70%, transparent); -webkit-mask-image: linear-gradient(to top, #000 70%, transparent); } .bub { align-self: flex-start; max-width: 84%; display: flex; gap: 8px; align-items: flex-end; animation: bubIn .5s var(--spring); } .bub .bx { padding: 8px 12px; border-radius: 18px 18px 18px 6px; font-size: 13.5px; line-height: 1.35; } .bub .bx b { display: block; font-size: 11.5px; color: var(--text2); font-weight: 600; margin-bottom: 1px; } @@ -377,7 +377,7 @@ input, textarea { font: inherit; color: inherit; } .ws .wsh > * { pointer-events: auto; } .ws .wsh .tt { flex: 1; min-width: 0; height: 44px; border-radius: 22px; display: flex; align-items: center; gap: 10px; padding: 0 8px 0 14px; } .ws .wsh .tt b { font-size: 14.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; } -.ws .wsh .tt span { font-size: 11.5px; color: var(--text2); display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.ws .wsh .tt span.sub { font-size: 11.5px; color: var(--text2); display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .ws .body { position: absolute; left: 0; right: 0; bottom: 0; top: 40%; border-radius: 28px 28px 0 0; display: flex; flex-direction: column; overflow: hidden; } .ws .seg { display: flex; margin: 12px 14px 8px; padding: 3px; border-radius: 12px; background: rgba(255,255,255,.07); flex: none; } .ws .seg button { flex: 1; height: 34px; border-radius: 9px; font-size: 13px; font-weight: 600; color: var(--text2); transition: all .25s; } @@ -524,7 +524,10 @@ input, textarea { font: inherit; color: inherit; } @media (min-width: 600px) { :root { --paneW: clamp(360px, 40vw, 440px); } .pane { width: var(--paneW); background: var(--bg); border-right: .5px solid var(--sep); z-index: 22; } - .tabwrap { --tabW: var(--paneW); } + .tabwrap { --tabW: var(--paneW); padding-left: 8px; padding-right: 8px; gap: 8px; } + .tab, .tablens { width: 54px; } + .searchbtn { width: 54px; height: 54px; } + .tabbar { height: 58px; } .tablens { height: 50px; } .tab { height: 50px; } .acc-host { right: auto; width: calc(var(--paneW) - 24px); } .app[data-tab="globe"] .acc-host { display: flex; } .wide-only { display: block !important; } @@ -548,10 +551,12 @@ input, textarea { font: inherit; color: inherit; } #v-capture { z-index: 45; } .ride { left: var(--paneW); } .concept-tag, .app[data-tab] .concept-tag { top: calc(var(--sat) + 14px); bottom: auto; left: auto; right: 70px; } + .app[data-mode="situation"] .concept-tag { right: 124px; } .composer { left: 10px; right: 10px; } } @media (min-width: 1100px) { :root { --paneW: 440px; } + .tab, .tablens { width: 66px; } .searchbtn { width: 62px; height: 62px; } .tabbar { height: 62px; } .tablens { height: 54px; } .tab { height: 54px; } .masonry { grid-template-columns: 1fr 1fr; } } /* hinge-aware: vertical fold — panes split exactly at the hinge */ @@ -732,7 +737,7 @@ input, textarea { font: inherit; color: inherit; }