mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
docs(street-level): shorten comments and docs, drop audit references
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
d59b4d05bb
commit
48b889590d
12 files changed
+41
-76
No files matched your search
+6
-8
@@ -71,16 +71,14 @@
|
|||||||
proposed diagnosis in #927, and [kvnloo](https://github.com/kvnloo) for identifying
|
proposed diagnosis in #927, and [kvnloo](https://github.com/kvnloo) for identifying
|
||||||
the repair race. Windows/Claude Desktop Cowork confirmation remains outstanding.
|
the repair race. Windows/Claude Desktop Cowork confirmation remains outstanding.
|
||||||
|
|
||||||
- Street Level: Mapillary street-level imagery modelled on the iD editor's
|
- Street Level: Mapillary street-level imagery (free client token, CC BY-SA
|
||||||
photo overlay (free client token, CC BY-SA 4.0 imagery). A docked right-rail
|
4.0). A right-rail panel holds an ON/OFF pill, 360°/flat and captured-since
|
||||||
panel holds an ON/OFF pill, 360°/flat and captured-since filters, a legend
|
filters, a legend and an embedded viewer with EXPAND and FIT/FILL. Coverage
|
||||||
and an embedded viewer with full-screen EXPAND and FIT/FILL. Coverage lines
|
lines (below 60 km) and image cones drape on terrain and Google 3D tiles;
|
||||||
(below 60 km) and image cones drape on the terrain and Google 3D tiles;
|
|
||||||
opening a photo frames it with one camera flight. Share links carry the
|
opening a photo frames it with one camera flight. Share links carry the
|
||||||
switch, the filters and the panel's collapsed state. A server proxy adds the
|
switch, the filters and the panel's collapsed state. A server proxy adds the
|
||||||
token to coverage-tile requests, trims the tiles and caches them in memory
|
token to coverage tiles, trims and caches them for 24 h, refuses cross-site
|
||||||
for 24 h; it refuses cross-site requests and upstream redirects, rate-limits
|
requests and redirects, and limits load per IP and upstream. The panel reads
|
||||||
per IP and runs at most six Mapillary fetches at once. The panel reads
|
|
||||||
KEY REQUIRED without a token and KEY REJECTED when Mapillary refuses it.
|
KEY REQUIRED without a token and KEY REJECTED when Mapillary refuses it.
|
||||||
|
|
||||||
- Add Norway's road cameras from Statens vegvesen as a CCTV pack. The camera
|
- Add Norway's road cameras from Statens vegvesen as a CCTV pack. The camera
|
||||||
|
|||||||
+3
-4
@@ -66,10 +66,9 @@ gate for the feature you changed.
|
|||||||
> **CI does not cover this for you.** The workflow runs the setup policy
|
> **CI does not cover this for you.** The workflow runs the setup policy
|
||||||
> checks, the formatting and package-boundary checks, the unit suite and the
|
> checks, the formatting and package-boundary checks, the unit suite and the
|
||||||
> production build, plus a Windows onboarding job. It runs neither
|
> production build, plus a Windows onboarding job. It runs neither
|
||||||
> `npm run test:track` nor any other `qa-*.mjs` gate — both need a live dev
|
> `npm run test:track` nor any `qa-*.mjs` gate except the Street Level fixture
|
||||||
> server and a browser. The one exception is the hermetic Street Level fixture
|
> gate (`street-level-browser` job) — they need a live dev server and a
|
||||||
> gate (`street-level-browser` job). Include the applicable local run in your PR's validation
|
> browser. Include the applicable local run in your PR's validation evidence.
|
||||||
> evidence.
|
|
||||||
|
|
||||||
## Share-link layer tokens
|
## Share-link layer tokens
|
||||||
|
|
||||||
|
|||||||
+8
-12
@@ -3028,9 +3028,8 @@ Street Level is a docked, collapsible right-rail panel (`#street-level-panel`,
|
|||||||
layer token `0`, option owner `street-level`, panel `ui` token `t`) that starts
|
layer token `0`, option owner `street-level`, panel `ui` token `t`) that starts
|
||||||
collapsed. It opens itself only when the user, voice or a tool switches the
|
collapsed. It opens itself only when the user, voice or a tool switches the
|
||||||
layer on or a photo opens, never on a restore, and those opens are not stored.
|
layer on or a photo opens, never on a restore, and those opens are not stored.
|
||||||
Like the iD editor's photo overlay it shows Mapillary only: 360°/flat and
|
It has 360°/flat and captured-since filters (relative days, so a link keeps
|
||||||
captured-since filters (relative days, so a link keeps its meaning), one
|
its meaning), one embedded viewer and an on-globe credit while the layer is on. Share options:
|
||||||
embedded viewer and an on-globe credit while the layer is on. Share options:
|
|
||||||
`m` (Mapillary on/off; off draws nothing), `p` (`a`/`p`/`f` panoramas), `s`
|
`m` (Mapillary on/off; off draws nothing), `p` (`a`/`p`/`f` panoramas), `s`
|
||||||
(since, days). The header pill is the only layer switch.
|
(since, days). The header pill is the only layer switch.
|
||||||
|
|
||||||
@@ -3047,9 +3046,8 @@ pauses them for its Retry-After.
|
|||||||
The server proxy (`server/providers/mapillary.js`) adds the token to
|
The server proxy (`server/providers/mapillary.js`) adds the token to
|
||||||
coverage-tile requests (the browser holds it too, for MapillaryJS and the Graph
|
coverage-tile requests (the browser holds it too, for MapillaryJS and the Graph
|
||||||
API), serves only z11–14 coverage, refuses upstream redirects, strips the
|
API), serves only z11–14 coverage, refuses upstream redirects, strips the
|
||||||
unused `image` layer, coalesces concurrent requests, runs at most six Mapillary
|
unused `image` layer, shares one fetch per tile, runs at most six at once
|
||||||
fetches at once (a fetch every client has left is cancelled, or never started)
|
(cancelling those every client has left) and keeps tiles in memory for 24 h.
|
||||||
and keeps tiles in a 24 h memory cache.
|
|
||||||
|
|
||||||
MapillaryJS loads on the first photo. Opening one frames it with a single
|
MapillaryJS loads on the first photo. Opening one frames it with a single
|
||||||
camera flight through the application's deferred navigation (`begin` /
|
camera flight through the application's deferred navigation (`begin` /
|
||||||
@@ -3064,12 +3062,10 @@ Mapillary back on. At phone width the viewer height comes from the rail band
|
|||||||
so the whole photo fits.
|
so the whole photo fits.
|
||||||
|
|
||||||
Browser gates: `npm run qa:street-level -- --url <server>` runs against real
|
Browser gates: `npm run qa:street-level -- --url <server>` runs against real
|
||||||
Mapillary with a token; `npm run qa:street-level:fixtures` answers every
|
Mapillary; `npm run qa:street-level:fixtures` answers every Mapillary request
|
||||||
Mapillary request from fixtures (`providers/mapillary/coverageFixture.mjs`,
|
from fixtures (`providers/mapillary/coverageFixture.mjs`,
|
||||||
`scripts/fixtures/street-level/`); its server (default `:4173`) still needs a
|
`scripts/fixtures/street-level/`), but its server (default `:4173`) still needs
|
||||||
`MAPILLARY_CLIENT_TOKEN`, and any value will do. CI runs the fixture gate with
|
some `MAPILLARY_CLIENT_TOKEN`. CI runs it `--strict` against `vite preview`.
|
||||||
`--strict` against a production build served by `vite preview` with a dummy
|
|
||||||
token.
|
|
||||||
|
|
||||||
Directions is a keyless front end to the routing the voice agent already
|
Directions is a keyless front end to the routing the voice agent already
|
||||||
uses. Its row chips are the whole interface: DRIVE / WALK / BIKE pick the
|
uses. Its row chips are the whole interface: DRIVE / WALK / BIKE pick the
|
||||||
|
|||||||
@@ -57,9 +57,8 @@ Related keys (current versions):
|
|||||||
- Panel collapsed state: `godsEyeView.v6.panelCollapsed.<panel-id>` — `'0'` open,
|
- Panel collapsed state: `godsEyeView.v6.panelCollapsed.<panel-id>` — `'0'` open,
|
||||||
`'1'` closed, absent means the panel's own default. A view opened from a share
|
`'1'` closed, absent means the panel's own default. A view opened from a share
|
||||||
link ignores the stored value entirely.
|
link ignores the stored value entirely.
|
||||||
- Panel positions: `godsEyeView.v8.panelPos.<panel-id>` — the versioned name for a
|
- Panel positions: `godsEyeView.v8.panelPos.<panel-id>` — the current layout
|
||||||
stored position. The current layout writes none, so deleting one changes
|
writes none.
|
||||||
nothing.
|
|
||||||
- CCTV calibration: `godsEyeView.cctv.calibration.v2`
|
- CCTV calibration: `godsEyeView.cctv.calibration.v2`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -14,10 +14,7 @@ const DROP_LAYERS = ['image'];
|
|||||||
/** A z14 tile with its image layer is ~11 MB; anything past this is wrong. */
|
/** A z14 tile with its image layer is ~11 MB; anything past this is wrong. */
|
||||||
export const TILE_MAX_BYTES = 48 * 1024 * 1024;
|
export const TILE_MAX_BYTES = 48 * 1024 * 1024;
|
||||||
const FETCH_TIMEOUT_MS = 60_000;
|
const FETCH_TIMEOUT_MS = 60_000;
|
||||||
/**
|
/** Upstream fetches at once; more wait their turn. */
|
||||||
* Upstream fetches at once; more wait their turn. A fetch every client has
|
|
||||||
* left is cancelled, or never started, so the queue holds live tiles only.
|
|
||||||
*/
|
|
||||||
export const TILE_UPSTREAM_CONCURRENCY = 6;
|
export const TILE_UPSTREAM_CONCURRENCY = 6;
|
||||||
/** Tiles change only when new imagery is processed. */
|
/** Tiles change only when new imagery is processed. */
|
||||||
export const TILE_TTL_MS = 24 * 60 * 60 * 1000;
|
export const TILE_TTL_MS = 24 * 60 * 60 * 1000;
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ import { plausibleSurfaceHeight, sampledSurfaceHeight } from './view.js';
|
|||||||
/** Fly the globe camera once to frame a photo after it opens. */
|
/** Fly the globe camera once to frame a photo after it opens. */
|
||||||
export function createCameraFraming({ state }) {
|
export function createCameraFraming({ state }) {
|
||||||
/**
|
/**
|
||||||
* The application's camera authority (`attachNavigation`): `begin(noun)`
|
* The application's camera authority: `reassert(begin())` succeeds only if
|
||||||
* takes a deferred ticket (a generation, or false when refused) that
|
* nothing newer took the camera. Without it, framing flies directly.
|
||||||
* `reassert(generation)` honours, releasing tracking, only if nothing newer
|
|
||||||
* took the camera. Without it, framing flies directly.
|
|
||||||
*/
|
*/
|
||||||
let navigation = null;
|
let navigation = null;
|
||||||
/** Our framing flight while it is current; Cesium calls `cancel` when another flight starts. */
|
/** Our framing flight while it is current; Cesium calls `cancel` when another flight starts. */
|
||||||
|
|||||||
@@ -218,11 +218,7 @@ export function createStreetLevelLayer({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/** A photo frames itself only if it still owns the camera once loaded. */
|
||||||
* The application's camera authority, the deferred `begin(noun)` /
|
|
||||||
* `reassert(generation)` pair: a photo claims the camera when opening
|
|
||||||
* starts and frames only if it still owns it once loaded.
|
|
||||||
*/
|
|
||||||
attachNavigation(navigation) {
|
attachNavigation(navigation) {
|
||||||
parts.framing.attachNavigation(navigation);
|
parts.framing.attachNavigation(navigation);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -31,10 +31,9 @@ export function sampledSurfaceHeight(scene, carto) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ellipsoidal height (m) of the ground under the camera, or null. The globe
|
* Ellipsoidal height (m) of the ground under the camera, or null. Under
|
||||||
* answers where shown; Google 3D hides it, so the rendered surface does
|
* Google 3D (globe hidden) the rendered surface counts, minus any roof above
|
||||||
* (roofs count: a building's height at most). A sample above the camera is
|
* the camera.
|
||||||
* ignored: a raised ground would put the camera underground.
|
|
||||||
*/
|
*/
|
||||||
export function groundUnderCamera(viewer) {
|
export function groundUnderCamera(viewer) {
|
||||||
const carto = viewer?.camera?.positionCartographic;
|
const carto = viewer?.camera?.positionCartographic;
|
||||||
@@ -81,11 +80,9 @@ function groundHit(camera, point, ellipsoid, maxRange) {
|
|||||||
const BBOX_GRID = 5;
|
const BBOX_GRID = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visible [west, south, east, north] degrees, or null when fewer than four
|
* Visible [west, south, east, north] degrees from the rays that hit the
|
||||||
* rays hit. Only hits count, so a horizon cannot inflate the box to the world.
|
* ground, or null when fewer than four do. `groundHeight` raises the ellipsoid
|
||||||
* `groundHeight` raises the ellipsoid to the ground (rays to the bare
|
* to the ground (Denver is 1,600 m up); `maxRange` (m) drops far hits.
|
||||||
* ellipsoid under Denver land kilometres too far out) and `maxRange` (m)
|
|
||||||
* drops near-horizon hits.
|
|
||||||
*/
|
*/
|
||||||
export function visibleBbox(
|
export function visibleBbox(
|
||||||
viewer,
|
viewer,
|
||||||
@@ -158,10 +155,8 @@ export function cameraNadir(viewer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Where coverage tiles are ranked from: halfway between the ground under the
|
* Where coverage tiles are ranked from: halfway between the nadir and the
|
||||||
* camera and the ground at the centre of the screen, so a tilted view loads
|
* screen centre's ground, or the nadir when that is out of `maxRange`.
|
||||||
* what it looks at as well as what is near. The nadir when the centre ray
|
|
||||||
* misses the ground within `maxRange`. Options as `visibleBbox`.
|
|
||||||
*/
|
*/
|
||||||
export function viewFocus(
|
export function viewFocus(
|
||||||
viewer,
|
viewer,
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
import { freshStreet } from './state.js';
|
import { freshStreet } from './state.js';
|
||||||
|
|
||||||
/**
|
/** The panel's photo viewer: its poses update `state.street` and the marker. */
|
||||||
* Owns the panel's viewer element and the photo viewer mounted in it (the
|
|
||||||
* MapillaryJS adapter, or a stand-in). Its poses update `state.street` and
|
|
||||||
* the marker; MapillaryJS loads on the first open.
|
|
||||||
*/
|
|
||||||
export function createViewerHost({ state, parts, adapter }) {
|
export function createViewerHost({ state, parts, adapter }) {
|
||||||
/** Set once mounted, until `unmount`. */
|
/** Set once mounted, until `unmount`. */
|
||||||
let unsubscribe = null;
|
let unsubscribe = null;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const UNTRIMMED = tile([
|
|||||||
{ name: 'image', payload: Buffer.alloc(4000, 1) },
|
{ name: 'image', payload: Buffer.alloc(4000, 1) },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/** Mount the plugin and return `call(route, url, method, headers)`. */
|
/** Mount the plugin and return `call(route, url, method, headers, onResponse)`. */
|
||||||
function install(mode = 'configureServer') {
|
function install(mode = 'configureServer') {
|
||||||
const routes = new Map();
|
const routes = new Map();
|
||||||
mapillaryProxy()[mode]({
|
mapillaryProxy()[mode]({
|
||||||
|
|||||||
@@ -79,9 +79,8 @@ export class PanelPositionControls {
|
|||||||
this._restorePanelPosition(spec.id, spec.panel);
|
this._restorePanelPosition(spec.id, spec.panel);
|
||||||
this._makePanelDraggable(spec.id, spec.panel, spec.handle);
|
this._makePanelDraggable(spec.id, spec.panel, spec.handle);
|
||||||
}
|
}
|
||||||
// Keep a positioned panel on-screen when its HEIGHT changes after restore — it expands to its
|
// A restored panel grows a frame or two later, so the restore-time clamp
|
||||||
// full row set a frame or two later, so the restore-time clamp used a stale (shorter) height and
|
// is stale: re-clamp on every size change.
|
||||||
// the panel could still hang off the bottom (audit U2). Re-clamp on every size change.
|
|
||||||
if (this._ppToggles && typeof ResizeObserver !== 'undefined') {
|
if (this._ppToggles && typeof ResizeObserver !== 'undefined') {
|
||||||
this._draggableResizeObserver = new ResizeObserver(() =>
|
this._draggableResizeObserver = new ResizeObserver(() =>
|
||||||
this._reclampDraggablePanels(),
|
this._reclampDraggablePanels(),
|
||||||
@@ -159,8 +158,7 @@ export class PanelPositionControls {
|
|||||||
const pos = JSON.parse(raw);
|
const pos = JSON.parse(raw);
|
||||||
if (!pos || typeof pos.left !== 'number' || typeof pos.top !== 'number')
|
if (!pos || typeof pos.left !== 'number' || typeof pos.top !== 'number')
|
||||||
return;
|
return;
|
||||||
// Clamp to the viewport: a position saved at one window size would otherwise land off-screen at
|
// A position saved at another window size can land off-screen.
|
||||||
// another (audit U2 — observed a panel at x:-192). The drag handler clamps; restore must too.
|
|
||||||
const { left, top } = this._clampToViewport(
|
const { left, top } = this._clampToViewport(
|
||||||
Math.round(pos.left),
|
Math.round(pos.left),
|
||||||
Math.round(pos.top),
|
Math.round(pos.top),
|
||||||
|
|||||||
@@ -105,10 +105,8 @@ export class StreetLevelControls {
|
|||||||
this._setParams({ sinceDays: sinceDays() }),
|
this._setParams({ sinceDays: sinceDays() }),
|
||||||
);
|
);
|
||||||
this.listen(el.viewerClose, 'click', () => this.layer.closeViewer?.());
|
this.listen(el.viewerClose, 'click', () => this.layer.closeViewer?.());
|
||||||
// EXPAND is the browser's own fullscreen: it handles Esc, focus and the
|
// EXPAND is the browser's fullscreen. iPhone Safari has no element
|
||||||
// rest of the page. iPhone Safari has no element fullscreen, so there the
|
// fullscreen, so there it is a top-layer popover; with neither, no button.
|
||||||
// viewer opens as a top-layer popover over the page instead (Esc and the
|
|
||||||
// button close it). With neither, the button is not offered.
|
|
||||||
this._expandMode =
|
this._expandMode =
|
||||||
typeof el.viewerWrap?.requestFullscreen === 'function'
|
typeof el.viewerWrap?.requestFullscreen === 'function'
|
||||||
? 'fullscreen'
|
? 'fullscreen'
|
||||||
@@ -195,9 +193,8 @@ export class StreetLevelControls {
|
|||||||
|
|
||||||
async _toggleEnabled() {
|
async _toggleEnabled() {
|
||||||
const enabled = this.actions.isEnabled?.() === true;
|
const enabled = this.actions.isEnabled?.() === true;
|
||||||
// The pill is the only switch. A share link or tool can switch Mapillary
|
// The pill is the only switch: it also brings back Mapillary that a link
|
||||||
// off under a layer that is on; the pill then reads OFF, and switching on
|
// or tool switched off under a layer that is on.
|
||||||
// brings Mapillary back (and the layer, if it is off too).
|
|
||||||
if (this._state?.providerOn === false) {
|
if (this._state?.providerOn === false) {
|
||||||
this._setParams({ mapillary: true });
|
this._setParams({ mapillary: true });
|
||||||
if (enabled) return;
|
if (enabled) return;
|
||||||
@@ -252,11 +249,7 @@ export class StreetLevelControls {
|
|||||||
this._syncExpanded();
|
this._syncExpanded();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Clean View, recording and the cockpit hide every panel, so they end EXPAND too. */
|
||||||
* While expanded, leave when Clean View, recording or the cockpit starts:
|
|
||||||
* they hide every panel, and the photo would stay over the globe (and in a
|
|
||||||
* recording).
|
|
||||||
*/
|
|
||||||
_watchPanelHidingModes(on) {
|
_watchPanelHidingModes(on) {
|
||||||
const body = document.body;
|
const body = document.body;
|
||||||
if (!on || !body) {
|
if (!on || !body) {
|
||||||
|
|||||||
Reference in new issue
Block a user