Skip to content

Plan: shard-vector + output-grid globe viewer, packaged for JupyterHub (cryocloud) #1

Description

@espg

🤖 from Claude

Plan: shard-vector + output-grid globe viewer on gridlook, packaged for JupyterHub (cryocloud)

The Phase-B viewer from englacial/zagg#74 (globe-view shardmap viewer, one extension also serving the output-zarr-grid view). Decisions ratified on that thread and in-session (2026-07-17):

  • Build on gridlook (this fork; upstream d70-t/gridlook, MIT, three.js + Vue 3 + Vite — not deck.gl).
  • One shell, two layer families: zagg's shard/granule vector polygons + gridlook's existing zarr datacube globe.
  • Landing target: cryocloud (2i2c) as an installable extension. NASA policy: no public buckets — output stores are reachable from cryocloud, not from the public internet, which forces the data path through a hub-side proxy (Phase 4).
  • Upstream policy (ratified): offer generic pieces (filled-polygon layer, vector layer kind, jupyter packaging) to d70-t/gridlook per-piece, opportunistically — never gating our timeline.
  • Pip wrapper name (ratified): gridlook-jupyter. Proxy shape (ratified): one custom jupyter-server extension serving both the static app and the S3 byte-range proxy (fewer moving parts than jupyter-server-proxy + a second handler).

Architecture facts this plan builds on (verified against this fork at 1.4.1):

  • The overlay system is now a first-class, user-manipulable layer stack (store.layerStack, LAYER_KINDS: grid/coastlines/graticules/mask/texture) with add/remove/reorder/visibility/opacity and a LayerPanel.vue UI. TEXTURE layers are already dynamically user-injected (id-keyed, syncTextureLayers in useGridOverlays.ts) — the injection risk flagged on zagg#74 is retired; a vector kind follows this exact pattern.
  • The vector gap is unchanged: geojson.ts renders LineString/MultiLineString only (GPU-projected line segments); Polygon/MultiPolygon are rejected; three-conic-polygon-geometry / three-geojson-geometry are declared in package.json but unimported.
  • House style for anything on the globe: geometry built in lat/lon, projection applied in-shader via ProjectionHelper (gpuProjectedLines, gridShaders) so layers track gridlook's globe↔flat projection switching. The polygon layer should follow this (triangulate rings, project in shader), not bake globe-space geometry.
  • vite.config.ts has base: "./" — the built app serves under any path prefix (a Jupyter URL) without rebuild.
  • Input surface: zagg already emits the vector data (shard_outlines / granule_footprints WGS84 GeoJSON FeatureCollections, antimeridian-split). GeoJSON is the only interchange — same surface as zagg's Phase-C ipyleaflet viewer, no second tessellation (the zagg#74 constraint).

Phases

  • Phase 1 — filled-polygon rendering primitive. Extend the geojson layer path with Polygon/MultiPolygon support: triangulate rings in lat/lon (three's Earcut / ShapeUtils, or wire the already-declared three-conic-polygon-geometry — implementer decides with a note on projection-switching behavior), GPU-projected fill material following the line-layer house style, plus polygon outlines through the existing line builder. A LAYER_KINDS.VECTOR entry rendered from a store-held FeatureCollection. Acceptance: zagg shard_outlines GeoJSON renders filled+stroked on globe and flat projections; vitest unit tests for the triangulation/geometry builder; lint-ci + typecheck green.
  • Phase 2 — user injection + layer UI. Load vector layers from URL or file upload (mirroring texture-layer injection), multiple id-keyed vector layers, LayerPanel entries with fill/stroke/opacity styling controls, hover/picking with a feature-properties readout (shard id, granule id). Acceptance: drag in / point at a zagg GeoJSON with zero code.
  • Phase 3 — shardmap presentation. Default styling for shard_outlines / granule_footprints (property-driven choropleth, e.g. granule count per shard), a legend, and URL-param wiring so a hub launcher can deep-link a specific shardmap + catalog view.
  • Phase 4 — gridlook-jupyter (in-repo jupyter/ dir). Python package (own pyproject; wheel built from this repo) containing one custom jupyter-server extension: (a) serves the built Vite app on a hub URL, (b) proxies byte-range GETs to S3 hub-side (obstore/boto3; bucket allowlist via config/env) so the browser reads non-public buckets through the hub — the NASA-policy data path. Acceptance: pip install . on a plain JupyterLab, app opens, zarr loads from an allowlisted private bucket through the proxy.
  • Phase 5 — cryocloud/2i2c integration + launcher polish. Launcher card (minimal prebuilt Lab extension or jupyter-app-launcher entry) opening the app in a Lab tab; deployment recipe for the 2i2c image (docs); creds/allowlist configuration documented.
  • Phase 6 — morton-hive store awareness ("moczarr-lite" TS). v1: open a single hive leaf zarr (vanilla v3 — works with gridlook today). v2: parse morton_hive.json + root coverage.moc ranges, compute leaf paths arithmetically (BigInt for u64 words; box tier only — no zstd bitmap in the browser), and enumerate/open leaves from the UI. Golden vectors ported from moczarr (-5112333, its hive path, the ranges envelope) pin TS↔Python convention parity. Refs Design: sparse coverage convention + cross-resolution read path (MOC domain, hive stores, xdggs extension) englacial/zagg#198 §5/§6.

Phases 1–3 are pure frontend (testable with npm run dev + zagg-emitted GeoJSON, no hub). Phase 4 unblocks cryocloud; 6 can interleave after 3.

Upstream tracking

Candidates to offer d70-t/gridlook once stable, per-piece: the polygon rendering primitive + VECTOR layer kind (phases 1–2, most generic), the jupyter packaging (phase 4, if upstream wants it). zagg-specific presentation (phase 3 styling defaults) and morton-hive awareness (phase 6) likely stay fork-side unless upstream asks.

Open questions (non-blocking for phase 1)

  1. Picking tech (phase 2): three.js raycaster against triangulated meshes vs GPU id-picking — decide when hover lands; raycaster is likely fine at shard counts (10²–10⁴ features).
  2. Proxy auth model (phase 4): bucket allowlist only, or also per-user scoping via hub auth state? Start allowlist-only.
  3. Node floor: repo engines wants node ≥24.16; local dev currently has 23.5 (npm warns, doesn't fail). Align dev env when convenient.

Working conventions: branches claude/<issue#>-<topic>, draft PRs with phased checklists, one commit per phase, adversarial review + fold per phase push — same workflow as moczarr/zagg. Keep the fork synced with upstream main regularly to keep upstream PRs cheap.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions