JK
>読み込み中 // 読み込み中
ビューを初期化中大気散乱シェーダーと位置マーカーを搭載したWebGLベースの高性能3D地球儀。
エントリークラスの端末でもフレームレートを落とさず、リアルな惑星の光と影をブラウザ上で描画すること。
| 技術 | バージョン | 目的 | 採用理由 |
|---|---|---|---|
| React | ^19.0.1 | UI runtime for both entries | Component model; canvas work stays outside React and is driven through a ref |
| TypeScript | ^7.0.2 | Types for the whole project | Only static gate in CI (lint = tsc --noEmit) with strict mode on |
| Vite | ^8.3.0 | Build tool and dev server | Fast builds with dual entry via rollupOptions.input |
| Tailwind CSS | ^4.3.3 | Utility styling | No config file; @theme tokens in index.css |
| d3-geo | ^3.1.1 | Projection maths only | geoOrthographic/geoPath/graticule without committing to a renderer |
| topojson-client + world-atlas | ^3.1.0 / ^2.0.2 | Country polygons | Free, offline, no API key; India's entry is replaced by official vectors |
| lucide-react | ^0.546.0 | Icons | Tree-shakeable icon set |
| @vercel/analytics | ^2.0.1 | Pageview analytics | Zero-config on Vercel |
| Vitest | ^5.0.4 | Unit tests | Fast, node environment - everything under test is pure logic |
| pnpm | 10.33.2 (pinned) | Package manager | Deterministic lockfile in CI |
| GitHub Actions | ubuntu-latest, Node 22 | CI | Native to the repo host; lint -> test -> build gates |
| Vercel | — | Static hosting and CDN | Static assets + headers + rewrites with no server |
| OSM Nominatim | public API | Geocoding search | Free and keyless |
| メソッド | ルート | 目的 |
|---|---|---|
| GET | / | Main app SPA - customizer, search, embed generator (rewritten to /index.html) |
| GET | /embed | Chrome-free iframe target; rewritten to /embed.html and served with CSP frame-ancestors * |
| GET | /embed.html | Same embed entry, served directly; configured by URL query params |
| メソッド | ルート | 目的 |
|---|---|---|
| GET | /search | Resolve a place name to lat/lng for the search pin; debounced, abortable, ~1 req/s budget with a 30 s cooldown on 429 |
判断: index.html and embed.html are built from one config and both render the same EarthGlobe component
理由: The embed must never diverge visually or behaviourally from the app; a second renderer would double the surface area of every fix
利点: One renderer, every fix reaches both surfaces
トレードオフ: The embed downloads saved-settings branches it never runs (~3.5 kB, ~0.3 kB gzipped)
判断: Hand-written Canvas 2D painter with d3-geo used only for projection maths
理由: Zero backend, zero keys, static-only hosting - a hand-painted orthographic globe at 110m resolution does not need a GPU stack
利点: Negligible library weight, no shader or context-loss failure modes, full control of the drawing passes
トレードオフ: Per-frame CPU scales with geometry (177 country + 37 state polygons every frame); no LOD, culling or instancing
判断: Filter ISO 356 out of world-atlas and draw India from india-official.json (37 features incl. J&K and Ladakh)
理由: Natural Earth's India does not match official boundaries, and cartographic accuracy should not require a tile server
利点: Authoritative borders, fully offline, no map service at runtime
トレードオフ: ~+210 KB payload; TopoJSON quantisation was rejected because it changes cartographic fidelity
判断: Fixed parameter order in buildEmbedUrl, plus a round-trip test that parses generated URLs back through parseGlobeConfig
理由: A pasted embed snippet is a public API surface that cannot change
利点: A silent behavioural break becomes a red build; the CI workflow flags the round-trip test as load-bearing
トレードオフ: Genuine awkwardness is preserved to keep the byte format stable (e.g. DEFAULT_APP_ZOOM exists only to make a non-behaviour visible)
判断: Coerce-then-clamp instead of strict typing; id optional, numeric strings accepted, longitude wraps, zoom clamps
理由: Hosts send string coordinates, out-of-range zoom or a marker without id - a typeof check would reject those and silently stop the globe moving
利点: Existing embeds keep working; only genuinely unusable payloads are rejected, with a commandRejected event
トレードオフ: Hand-written and only partly uniform; 3 of 20 commands still fail silently
判断: Require event.source === window.parent, with EMBED_ALLOWED_PARENT_ORIGINS shipping empty and outbound events targeting the referrer origin
理由: Embedding is a public, unauthenticated capability - the realistic threat is a third party messaging an embed already on screen
利点: Blocks pop-up/opener/sibling-frame attacks at zero cost to embedders
トレードオフ: Any site that iframes the globe has full script control; acceptable because nothing secret is transmitted
判断: Diff writes field-by-field against a last-known ref, merge them over a fresh disk read, skip unchanged writes, and reconcile on the storage event
理由: Whole-blob last-write-wins destroyed a sibling tab's unrelated fields and fired spurious events
利点: Correct multi-tab behaviour; a slider drag collapses into a single serialisation
トレードオフ: A ~45-value hook return, three parallel write effects, no schema version for forward migration
判断: background=false substitutes pure white/black instead of clearing to transparent; every frame is fully painted
理由: Removes clearRect, avoids compositing cost and letterboxing, and makes the theme halo legible
利点: Simpler and cheaper frames, predictable look across hosts
トレードオフ: The globe cannot be composited over a host page background - a real limitation for embeds
判断: Inertia 0.93^(dt*60), auto-rotation speed*dt*10, wheel zoom 1.08 in / 1/1.08 out
理由: Flat velocity decay behaves differently at 60 vs 120 Hz and asymmetric zoom steps are not reversible
利点: Identical feel on 60 Hz, 120 Hz and ProMotion displays
トレードオフ: Constants are scattered across three sites rather than shared