release: bump version to 0.58.0
Some checks failed
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / delivery (push) Has been cancelled
release / images (push) Has been cancelled

Release 0.58.0 includes the Earth high-precision boundary PMTiles/MVT pipeline, standardized Earth boundary source collectors, China POV boundary configuration templates, and removal of the legacy low-precision GeoJSON fallback. It also adds Earth news target-location queueing/archive support, fixes datasource task status visibility, documents the Earth surface depth-spacing rules that prevent far-zoom z-fighting snow/black blocks, and updates bilingual operations/developer docs.
This commit is contained in:
linkong
2026-05-15 17:40:07 +08:00
parent dd176a6ae6
commit 93eb41a9f7
75 changed files with 5217 additions and 716 deletions

View File

@@ -86,9 +86,17 @@ async def run(self, db):
| TeleGeography | submarine_cable | Submarine cable information | 7 days |
| BarentsWatch AIS | vessel | AIS vessel positions, speed, heading, MMSI, and related fields | Collector settings |
| AISStream Vessels | vessel_ais | AIS WebSocket realtime stream, written to the raw observation layer and displayed through aggregation | Collector settings |
| Earth Admin-0 Boundaries | earth_admin0_boundaries | Downloads the configured country-boundary source, saves an artifact, and writes an `earth_boundary_source` manifest record | Collector settings |
| Earth Coastline | earth_coastline | Downloads the configured coastline source, saves an artifact, and writes an `earth_boundary_source` manifest record | Collector settings |
| Earth Claim Lines | earth_claim_lines | Downloads the configured claim-line source, saves an artifact, and writes an `earth_boundary_source` manifest record | Collector settings |
| Earth PMTiles Builder | earth_boundary_tiles | Reads the three Earth boundary source records and builds / registers the PMTiles artifact | Collector settings |
AIS vessel collectors use a different persistence path from regular `CollectedData` collectors. BarentsWatch, AISStream, and custom `vessel_ais` sources write into the AIS raw observation layer first, then the aggregation service merges those observations into the GeoJSON and detail payloads used by the Earth vessel layer. This preserves source, transport, field conflicts, and observation time instead of letting one realtime source overwrite the final display table.
Earth boundaries are now split into three real source collectors plus one downstream builder. `earth_admin0_boundaries`, `earth_coastline`, and `earth_claim_lines` read endpoint, headers, auth, and `config.target_schema=earth_boundary_source` from Collector Settings. Triggering them requests the configured endpoint, writes the full response to `data/earth-boundary-sources/<collector>/<sha256>.*`, and stores sha256, feature count, license, artifact path, sample properties, and mapping metadata in `CollectedData`.
`earth_boundary_tiles` no longer means source-data collection. It reads the latest successful records from those three source collectors; if any source is missing, the task fails as "not ready" and does not register "4 high-precision tile" records. Once all sources exist, it uses `tippecanoe` / `pmtiles` to build `frontend/public/earth/data/boundaries/earth-boundaries-china-pov-v1.pmtiles`; if those tools are missing, the task fails with the missing-tool message. There is no legacy low-precision fallback for country boundaries.
TOP500 and Epoch AI compute sources do not always provide usable coordinates. The unified Earth compute-center endpoint uses only valid source-provided coordinates or `compute_center_locations` dimension-table coordinates during the main map startup path; records without coordinates are returned as `unresolved` instead of being rendered from a local registry, country centroid, or guessed city. When users manually collect candidates, the backend queries ROR and Nominatim/OpenStreetMap from source fields; accepted candidates are saved into `compute_center_locations` and rendered from that table on the next layer refresh.
## IV. Data Format (stored in CollectedData table)
@@ -219,7 +227,8 @@ backend/app/services/collectors/
├── peeringdb.py # PeeringDB collector
├── telegeraphy.py # TeleGeography submarine cable collector
├── vessel_ais.py # BarentsWatch AIS vessel collector
── aisstream.py # AISStream WebSocket vessel collector
── aisstream.py # AISStream WebSocket vessel collector
└── earth_boundaries.py # Earth boundary source verification and static tile artifact collector
backend/app/services/
├── custom_datasource_runtime.py # Custom REST / WebSocket mapping runtime

View File

@@ -307,6 +307,8 @@ Files:
Custom sources are supplemental inputs for existing target schemas, not isolated data islands. The most complete target today is `vessel_ais`: a custom REST or WebSocket source is mapped deterministically, written into AIS raw observations, and then pushed to Earth through the `vessels` WebSocket channel.
Earth high-precision boundaries use the same target-schema mechanism. `earth_boundary_source` receives mapped records for `earth_admin0_boundaries`, `earth_coastline`, and `earth_claim_lines`; full GeoJSON / JSON payloads are stored as artifacts, while the database only keeps source kind, sha256, feature count, license, artifact path, and sample properties so large geometries do not land in a single row.
### Configuration Semantics
Important fields:
@@ -316,7 +318,7 @@ Important fields:
- `auth_type`: `none`, `bearer`, `api_key`, or `basic`.
- `headers`: static request headers.
- `auth_config`: token, API key, or basic username/password; API keys can be sent by header or query.
- `config.target_schema`: for example `vessel_ais`.
- `config.target_schema`: for example `vessel_ais` or `earth_boundary_source`.
- `config.delivery_mode`: REST defaults to `polling`; WebSocket defaults to `realtime_stream`.
- `config.merge_target_source`: records which built-in source this custom source supplements, such as `barentswatch_vessels`.

View File

@@ -122,6 +122,9 @@ Responsibilities:
- Globe sphere, cloud layer, atmosphere
- Real terrain mesh
- Terrain tile fetch, decode, displacement, and shading
- Whole-globe land/ocean and border base overlays
The Earth surface is a stack of near-concentric shells, not a single mesh. The base sphere and HD texture overlay in `earth.js`, plus the land/ocean base in `country-boundaries.js`, need explicit radius separation. At far zoom, GPU depth precision drops; neighboring shells that are too close can z-fight and show black flicker blocks or snow. The current stable spacing is `landAltitudeOffset = 0.32` and `textureOverlayAltitudeOffset = 0.48`. When adding or adjusting whole-globe surface overlays, update [Earth Render Layer Order](/home/ray/dev/linkong/planet/docs/technical/en/earth-render-layer-order.md) and verify at 50% zoom.
### 7. Layer Modules

View File

@@ -23,7 +23,7 @@ This document records the material, color, opacity, line width, radius offset, a
| Earth base specular | `EARTH_MATERIAL_CONFIG.specular` | `0x1a2d45` | `MeshPhongMaterial.specular` |
| Earth base shininess | `EARTH_MATERIAL_CONFIG.shininess` | `12` | `MeshPhongMaterial.shininess` |
| Earth base opacity | `EARTH_MATERIAL_CONFIG.opacity` | `1` | `MeshPhongMaterial.opacity` |
| HD texture radius offset | `EARTH_MATERIAL_CONFIG.textureOverlayAltitudeOffset` | `0.1` | Standalone HD texture sphere radius |
| HD texture radius offset | `EARTH_MATERIAL_CONFIG.textureOverlayAltitudeOffset` | `0.48` | Standalone HD texture sphere radius; must keep enough depth separation from the land/ocean base and Earth base sphere to avoid far-zoom z-fighting |
| HD texture opacity | `EARTH_MATERIAL_CONFIG.textureOverlayOpacity` | `0.88` | HD texture `MeshPhongMaterial.opacity` |
| HD texture renderOrder | `EARTH_MATERIAL_CONFIG.textureOverlayRenderOrder` | `0.96` | `_earthTextureOverlay.renderOrder` |
| HD texture specular | `EARTH_MATERIAL_CONFIG.textureOverlaySpecular` | `0x05080d` | Reduces specular highlight in direct-light areas to avoid blown-out texture |
@@ -78,11 +78,18 @@ The land/ocean base is an Earth base-map asset and preloads at startup; the "Bor
| Name | Variable | Current Value | Location / Notes |
| --- | --- | --- | --- |
| Country border data path | `COUNTRY_BOUNDARY_CONFIG.dataPath` | `"/earth/data/countries-admin0.min.geojson"` | GeoJSON input |
| Boundary tile manifest | `COUNTRY_BOUNDARY_CONFIG.tileManifestPath` | `"/earth/data/boundaries/v1/manifest.json"` | Required production PMTiles manifest; missing manifest is an error |
| Boundary tile provider | `COUNTRY_BOUNDARY_CONFIG.tileProvider` | `"pmtiles-mvt"` | Only PMTiles/MVT is accepted for country boundaries |
| PMTiles artifact path | `COUNTRY_BOUNDARY_CONFIG.pmtilesPath` | `"/earth/data/boundaries/earth-boundaries-china-pov-v1.pmtiles"` | Production single-file PMTiles/MVT artifact |
| MVT layer names | `COUNTRY_BOUNDARY_CONFIG.mvtLayerNames` | `boundary_admin0 / boundary_disputed_internal / coastline / claim_line` | Fixed layer names decoded by the PMTiles provider |
| Boundary tile base path | `COUNTRY_BOUNDARY_CONFIG.tileBasePath` | `"/earth/data/boundaries/v1/"` | PMTiles manifest base path |
| Boundary tile zoom thresholds | `COUNTRY_BOUNDARY_CONFIG.tileZoomThresholds` | `1.6 -> z5`, `2.8 -> z6`, `3.4 -> z7`, `4.0 -> z8`, `4.6 -> z9`, `5.2 -> z10` | Production PMTiles zoom selection |
| Boundary tile cache limit | `COUNTRY_BOUNDARY_CONFIG.tileCacheLimit` | `150` | Frontend LRU cache entries for loaded tile geometries |
| Boundary tile debounce | `COUNTRY_BOUNDARY_CONFIG.tileDebounceMs` | `180` | View-change debounce before requesting visible tiles |
| Ocean fill color | local `OCEAN_HEX` | `0x010609` | Land/ocean base canvas background |
| Land fill color | `COUNTRY_BOUNDARY_CONFIG.landColor` | `0x080f1b` | Land/ocean base canvas land |
| Land/ocean base opacity | `COUNTRY_BOUNDARY_CONFIG.landOpacity` | `1.0` | `MeshBasicMaterial.opacity` |
| Land/ocean base radius offset | `COUNTRY_BOUNDARY_CONFIG.landAltitudeOffset` | `0.08` | `country-land-ocean` radius |
| Land/ocean base radius offset | `COUNTRY_BOUNDARY_CONFIG.landAltitudeOffset` | `0.32` | `country-land-ocean` radius; separated from the Earth base sphere to avoid snow / black block flicker at 50% zoom |
| Land/ocean base renderOrder | `COUNTRY_BOUNDARY_CONFIG.landRenderOrder` | `0.86` | `country-land-ocean.renderOrder` |
| Land/ocean mask size | `landMaskWidth / landMaskHeight` | `2048 / 1024` | Canvas / DataTexture size |
| Country tint color | `COUNTRY_BOUNDARY_CONFIG.tintColor` | `0x0b1830` | Tint when HD texture is off |
@@ -91,16 +98,16 @@ The land/ocean base is an Earth base-map asset and preloads at startup; the "Bor
| Border line color | `COUNTRY_BOUNDARY_CONFIG.lineColor` | `0x7fc7ff` | Normal border line |
| Border line opacity | `COUNTRY_BOUNDARY_CONFIG.lineOpacity` | `0.58` | Normal border line opacity |
| Border dimmed opacity on hover | `COUNTRY_BOUNDARY_CONFIG.dimmedLineOpacity` | `0.18` | Normal border opacity during hover |
| Border line radius offset | `COUNTRY_BOUNDARY_CONFIG.lineAltitudeOffset` | `0.115` | Normal border line radius; slightly above HD texture `0.10` and below terrain base `0.16` to reduce floating |
| Border line radius offset | `COUNTRY_BOUNDARY_CONFIG.lineAltitudeOffset` | `0.115` | Normal border line radius; line layers rely on renderOrder and independent geometry, not whole-globe shell depth spacing |
| Border line renderOrder | `COUNTRY_BOUNDARY_CONFIG.lineRenderOrder` | `2.2` | Normal border line level |
| Border hover color | `COUNTRY_BOUNDARY_CONFIG.hoverLineColor` | `0xff3b1f` | Neon red-orange |
| Border hover opacity | `COUNTRY_BOUNDARY_CONFIG.hoverLineOpacity` | `1.0` | Hover line opacity |
| Border hover radius offset | `COUNTRY_BOUNDARY_CONFIG.hoverAltitudeOffset` | `0.14` | Hover line radius; close to the surface but above normal border lines |
| Border hover radius offset | `COUNTRY_BOUNDARY_CONFIG.hoverAltitudeOffset` | `0.115` | Hover line radius; matches the normal border geometry to avoid double-edge ghosting during highlight changes |
| Border hover renderOrder | `COUNTRY_BOUNDARY_CONFIG.hoverLineRenderOrder` | `2.3` | Hover line level |
| Border hover glow opacity | `COUNTRY_BOUNDARY_CONFIG.hoverGlowOpacity` | `0.38` | Glow line opacity |
| Border hover glow line width | `COUNTRY_BOUNDARY_CONFIG.hoverGlowLineWidth` | `3` | Glow `LineBasicMaterial.linewidth` |
| Border hover glow level offset | `COUNTRY_BOUNDARY_CONFIG.hoverGlowRenderOrderOffset` | `0.01` | Glow renderOrder = `2.29` |
| Border hover glow radius offset | `COUNTRY_BOUNDARY_CONFIG.hoverGlowRadiusOffset` | `0.04` | Glow radius = hover radius + 0.04 |
| Border hover glow radius offset | `COUNTRY_BOUNDARY_CONFIG.hoverGlowRadiusOffset` | `0` | Glow uses the same radius as the hover line to avoid coastline detail misalignment |
## Real Terrain

View File

@@ -17,8 +17,8 @@ Note: the layer control panel order and the registration / startup load order ar
| -1 | Earth occluder sphere | `earth.js` | Invisible inner sphere | Writes depth buffer | Occludes objects behind the Earth. |
| 0 | Earth base sphere | `earth.js` | `CONFIG.earthRadius` | Surface picking fallback target | Dark base; still visible when all optional map layers are off. |
| 0.2 | Country dark tint | `country-boundaries.js` | `tintAltitudeOffset` | Raycast disabled | Used when HD texture is off. |
| 0.86 | Land/ocean base fill | `country-boundaries.js` | `landAltitudeOffset`; ocean `#010609`, land `#080f1b` | Raycast disabled | Base map remains usable even when country borders are off. |
| 0.96 | HD Earth texture | `earth.js` | `textureOverlayAltitudeOffset` | Surface picking target when visible | HD texture always overlays the land/ocean base fill. |
| 0.86 | Land/ocean base fill | `country-boundaries.js` | `landAltitudeOffset = 0.32`; ocean `#010609`, land `#080f1b` | Raycast disabled | Base map remains usable even when country borders are off; radius is separated from the base sphere to avoid far-zoom z-fighting. |
| 0.96 | HD Earth texture | `earth.js` | `textureOverlayAltitudeOffset = 0.48` | Surface picking target when visible | HD texture always overlays the land/ocean base fill; radius must stay above the land/ocean base and far enough from the base sphere. |
| 1 | Atmospheric glow and clouds | `earth.js` | Atmosphere / cloud spheres | Not in normal object selection path | Cloud layer controlled by the "Cloud Layer" toggle. |
| 1 | Submarine cables | `cables.js` | `CABLE_CONFIG.line.renderOrder` | Cable picking path | Preserves existing cable layer level. |
| 1.2 | Real terrain | `earth.js`, `terrain.js` | `TERRAIN_CONFIG.baseRadiusOffset` plus terrain displacement | Raycast disabled | Terrain overlays HD texture; temporarily hidden when HD texture is off, restores to prior state when re-enabled. |
@@ -45,6 +45,17 @@ Note: the layer control panel order and the registration / startup load order ar
| Border Lines off | Hides only interactive border lines and hover, clearing hover state; the land/ocean base fill remains as the Earth base map. |
| Real Satellite Altitude off | Satellite dots, trails, and predicted orbits use the legacy same-sphere height; satellites with missing TLE data or failed propagation also use this fallback height. |
## Depth Spacing Rules
The Earth surface is not a single mesh. It is a stack of near-concentric shells: base sphere, land/ocean base, HD texture, terrain, clouds, atmosphere, and the occluder. Radius offsets that look harmless at close zoom can collapse into the same depth-buffer pixels at zoomed-out views such as 50%, causing z-fighting that appears as black blocks, snow, or flicker.
Maintenance rules:
- Do not reach first for hiding layers at far zoom. Check neighboring shell `altitudeOffset`, `renderOrder`, `depthTest`, and `depthWrite` first.
- Whole-globe overlays such as the land/ocean base and HD texture must keep explicit separation from `CONFIG.earthRadius`; the current stable values are `landAltitudeOffset = 0.32` and `textureOverlayAltitudeOffset = 0.48`.
- Any new whole-globe or near-whole-globe surface overlay must be screenshot-verified at 50% zoom and at common close zooms, with no black blocks, snow, flicker, or obvious floating.
- If these radii change, update this document and the intent around the constants in `frontend/public/earth/js/constants.js`.
## Interaction Rules
| Interaction | Current Rule |

View File

@@ -58,9 +58,9 @@ For temporary troubleshooting, you can stop IP Helper from Administrator PowerSh
Stop-Service iphlpsvc -Force
```
This may affect networking, proxying, or forwarding features. Do not disable it long-term unless you know why it is safe. New `--allow-lan` runs a temporary Windows relay for `3000` / `8000`, so persistent portproxy is no longer required.
This may affect networking, proxying, or forwarding features. Do not disable it long-term unless you know why it is safe. `--allow-lan` now binds `3000` / `8000` / `8010` directly, so persistent portproxy is no longer required.
If the script prints `failed-stop-service`, `failed-stop-process`, or Vite reports `Port 3000 is already in use` followed by `Windows listener ... services=iphlpsvc`, an old Windows listener still owns the port. Startup stops immediately and prints the recovery order: use Administrator PowerShell to inspect `netsh interface portproxy show all`, delete the matching `listenport` rule, confirm the PID and services with `netstat` / `tasklist` if no portproxy rule exists, and temporarily run `Stop-Service iphlpsvc -Force` when appropriate. After old rules are gone, rerun `./planet.sh restart --allow-lan`; the script starts temporary relays while LAN devices still use `3000` / `8000`.
If the script prints `Windows 侧端口 ... 存在监听者`, or Vite reports `Port 3000 is already in use` followed by `Windows listener ... services=iphlpsvc`, an old Windows listener still owns the port. The script requests Administrator PowerShell cleanup for that port. If the automatic cleanup is canceled, inspect `netsh interface portproxy show all`, delete the matching `listenport` rule, confirm the PID and services with `netstat` / `tasklist` if no portproxy rule exists, and temporarily run `Stop-Service iphlpsvc -Force` when appropriate. After old rules are gone, rerun `./planet.sh restart --allow-lan`; LAN devices still use `3000` / `8000` / `8010`.
### Which startup flags change default ports?
@@ -87,6 +87,7 @@ Check in this order before changing firewall rules:
# In WSL or the shell running Planet
curl http://localhost:3000
curl http://localhost:8000/health
curl http://localhost:8010/health
```
Then verify from Windows PowerShell:
@@ -94,6 +95,7 @@ Then verify from Windows PowerShell:
```powershell
curl http://localhost:3000
curl http://localhost:8000/health
curl http://localhost:8010/health
```
If both localhost checks pass but a phone or another computer cannot connect, start with LAN enabled:
@@ -108,16 +110,18 @@ The flag must be written as `--allow-lan`. `allowlan` or `--allowlan` is not rec
./planet.sh restart -f 3000 --allow-lan
```
If `ss -ltnp` shows the frontend listening on `0.0.0.0:3000`, but `Test-NetConnection <Windows LAN IP> -Port 3000` still fails from Windows PowerShell, the problem is usually Windows-side forwarding or firewall policy rather than Vite or `.zshrc`.
If `ss -ltnp` shows the frontend listening on `0.0.0.0:3000`, but `Test-NetConnection <Windows LAN IP> -Port 3000` still fails from Windows PowerShell, the problem is usually Windows-side port ownership, stale `portproxy`, or firewall policy rather than Vite or `.zshrc`.
For traditional WSL NAT networking, `./planet.sh start --allow-lan` starts temporary Windows relays so Windows still exposes `3000` / `8000`. Before startup, the script checks for stale `portproxy` rules and requests Administrator PowerShell to delete them. It also checks Windows Firewall and, when inbound allow rules for `3000` / `8000` are missing, triggers a UAC Administrator PowerShell request to create them. If the automatic request is canceled, clean up manually:
`./planet.sh start --allow-lan` directly exposes `3000` / `8000` / `8010` and checks port availability, stale `portproxy`, and Windows Firewall before startup. If a Windows-side listener owns a port, the script requests Administrator PowerShell cleanup. When inbound allow rules are missing, it also triggers a UAC Administrator PowerShell request to create them. If the automatic request is canceled, clean up manually:
```powershell
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=3000
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=8000
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=8010
New-NetFirewallRule -DisplayName "WSL Planet 3000" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 3000
New-NetFirewallRule -DisplayName "WSL Planet 8000" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8000
New-NetFirewallRule -DisplayName "WSL Planet 8010" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8010
```
LAN devices should use the Windows external port, for example `http://<Windows LAN IP>:3000/earth`.
@@ -127,6 +131,7 @@ If `wslinfo --networking-mode` prints `mirrored`, also check Hyper-V firewall. E
```powershell
New-NetFirewallHyperVRule -Name "Planet-Frontend-3000" -DisplayName "Planet Frontend 3000" -Direction Inbound -VMCreatorId "{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}" -Protocol TCP -LocalPorts 3000 -Action Allow
New-NetFirewallHyperVRule -Name "Planet-Backend-8000" -DisplayName "Planet Backend 8000" -Direction Inbound -VMCreatorId "{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}" -Protocol TCP -LocalPorts 8000 -Action Allow
New-NetFirewallHyperVRule -Name "Planet-AIProvider-8010" -DisplayName "Planet AI Provider 8010" -Direction Inbound -VMCreatorId "{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}" -Protocol TCP -LocalPorts 8010 -Action Allow
```
Use these commands to inspect the current Hyper-V firewall state:

View File

@@ -177,7 +177,7 @@ Frontend startup now has an additional pre-start cleanup retry layer:
- `PORT_PRESTART_RETRIES`: defaults to 3 attempts.
- `PORT_PRESTART_RETRY_INTERVAL`: defaults to 2 seconds.
`kill_port_if_requested()` first cleans listener PIDs visible in the current environment. It only checks for Windows-side listeners when the script detects WSL, no local listener PID is visible, and the port still cannot bind. In that WSL-only path it tries to stop the owning Windows service or force-stop the owning process through PowerShell. If permissions are missing, or a system service such as `iphlpsvc` refuses to stop, the script prints the Windows listener details and Administrator PowerShell recovery commands, then stops startup immediately instead of launching the service into the same port error. If the frontend Vite process only discovers `Port 3000 is already in use` after launch, the script prints the same Windows listener recovery commands. Non-WSL environments do not run the Windows cleanup path. On WSL, `--allow-lan` uses temporary Windows relays to expose `3000` / `8000`, so old persistent portproxy rules should be removed.
`kill_port_if_requested()` first cleans listener PIDs visible in the current environment. It only checks for Windows-side listeners when the script detects WSL, no local listener PID is visible, and the port still cannot bind. In that WSL-only path it requests Administrator PowerShell to delete stale `portproxy` rules, stop services that own the port, or force-stop the owning process. If the administrator request is canceled, or a system service such as `iphlpsvc` refuses to stop, the script prints the Windows listener details and Administrator PowerShell recovery commands, then stops startup immediately instead of launching the service into the same port error. If the frontend Vite process only discovers `Port 3000 is already in use` after launch, the script prints the same Windows listener recovery commands. Non-WSL environments do not run the Windows cleanup path. `--allow-lan` now exposes `3000` / `8000` / `8010` directly and no longer starts an extra Windows forwarding process; old persistent portproxy rules should be removed.
## Issue 4: `restart` Behavior

View File

@@ -120,7 +120,7 @@ Useful for:
- Demoing Earth from a phone or tablet
- Other LAN machines reaching the same dev instance
`--allow-lan` only makes the frontend and backend listen on `0.0.0.0`. When Planet runs in WSL, Windows can usually reach it through `localhost`, but other LAN machines reaching the Windows LAN IP still need Windows port forwarding and firewall rules.
`--allow-lan` directly exposes the frontend, backend, and AI Provider from the development machine: frontend `3000`, backend `8000`, and AI Provider `8010`. Before startup, the script checks all three ports. If WSL/Linux cannot release a port and a Windows-side listener or stale `portproxy` rule owns it, the script requests Administrator PowerShell cleanup. When Planet runs in WSL, Windows can usually reach it through `localhost`; other LAN machines reaching the Windows LAN IP still need Windows Firewall allow rules.
Diagnose in this order:
@@ -128,20 +128,23 @@ Diagnose in this order:
# From the shell running Planet
curl http://localhost:3000
curl http://localhost:8000/health
ss -ltnp | grep -E ':3000|:8000'
curl http://localhost:8010/health
ss -ltnp | grep -E ':3000|:8000|:8010'
```
If WSL services are running but the LAN IP still fails, let `./planet.sh start --allow-lan` launch temporary Windows relays. The relays keep Windows exposed on `3000` / `8000` and exit automatically when the WSL target port goes away. The script checks stale `portproxy` rules and requests Administrator PowerShell to delete them, then checks Windows Firewall and triggers a UAC Administrator PowerShell request when inbound allow rules are missing. Manual fallback commands:
If the services are running but the LAN IP still fails, first remove stale `portproxy` rules and confirm Windows Firewall allows the ports. The script checks this automatically and requests Administrator PowerShell when needed. Manual fallback commands:
```powershell
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=3000
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=8000
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=8010
New-NetFirewallRule -DisplayName "WSL Planet 3000" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 3000
New-NetFirewallRule -DisplayName "WSL Planet 8000" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8000
New-NetFirewallRule -DisplayName "WSL Planet 8010" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8010
```
LAN devices should use the Windows external port, for example `http://<Windows LAN IP>:3000/earth`.
LAN devices should use the Windows external ports, for example `http://<Windows LAN IP>:3000/earth`, `http://<Windows LAN IP>:8000/health`, and `http://<Windows LAN IP>:8010/health`.
## AI Provider Environment and Builds
@@ -238,6 +241,16 @@ uv sync
uv run pytest backend/tests/test_otp_service.py
```
## Earth Boundary PMTiles Operations
1. In Collector Settings, configure endpoints, headers/auth, `config.target_schema=earth_boundary_source`, license, and mapping for `Earth Admin-0 Boundaries`, `Earth Coastline`, and `Earth Claim Lines`.
2. In the data-source console, collect those three sources first. Each successful source writes the full artifact to `data/earth-boundary-sources/<collector>/<sha256>.*` and stores sha256, feature count, artifact path, and sample properties.
3. After all three sources succeed, collect `Earth PMTiles Builder`. If any source is missing, it fails as "not ready" and does not update Earth boundaries.
4. The builder requires `tippecanoe` and `pmtiles` on PATH. Missing tools fail the task with a clear message.
5. A successful production build outputs `frontend/public/earth/data/boundaries/earth-boundaries-china-pov-v1.pmtiles` and its manifest.
6. After deployment, open Earth, enable "Border Lines", and inspect China's southeast coast, Taiwan, Hainan, the South China Sea, Zangnan, Kosovo, and Gaza for hover behavior and boundary policy.
7. If PMTiles loading fails, Earth reports a boundary-layer error and does not draw legacy low-precision borders. Troubleshoot in this order: browser Network range requests for PMTiles, manifest `tileProvider: "pmtiles-mvt"`, Nginx static serving for `.pmtiles`, and artifact path / sha256 consistency with the manifest.
## Related Docs
- [planet.sh Startup Mechanism](/home/ray/dev/linkong/planet/docs/technical/en/ops-planet-sh-startup.md)

View File

@@ -87,9 +87,17 @@ async def run(self, db):
| Space-Track TLE | satellite_tle | 卫星轨道 TLE 数据 | 依采集器配置 |
| BarentsWatch AIS | vessel | 船只位置、航速、航向、MMSI 等 AIS 数据 | 依采集器配置 |
| AISStream Vessels | vessel_ais | AIS WebSocket 实时流,写入原始观测层并由聚合接口展示 | 依采集器配置 |
| Earth Admin-0 Boundaries | earth_admin0_boundaries | 从配置 endpoint 下载国家级边界源,保存 artifact 并写入 `earth_boundary_source` manifest 记录 | 依采集器配置 |
| Earth Coastline | earth_coastline | 从配置 endpoint 下载海岸线源,保存 artifact 并写入 `earth_boundary_source` manifest 记录 | 依采集器配置 |
| Earth Claim Lines | earth_claim_lines | 从配置 endpoint 下载主张线源,保存 artifact 并写入 `earth_boundary_source` manifest 记录 | 依采集器配置 |
| Earth PMTiles Builder | earth_boundary_tiles | 读取三类 Earth 边界源采集结果并构建 / 登记 PMTiles 产物 | 依采集器配置 |
AIS 船只类采集器和其它 `CollectedData` 采集器的落库路径不同。BarentsWatch、AISStream 和自定义 `vessel_ais` 源都会进入 AIS 原始观测层,随后由聚合服务合并成 Earth 船只图层使用的 GeoJSON 和详情数据。这样做可以保留来源、传输方式、字段冲突和观测时间,避免某个实时源直接覆盖最终展示表。
Earth 边界现在拆成三个真实源采集器和一个下游构建器。`earth_admin0_boundaries``earth_coastline``earth_claim_lines` 都读取后台 Collector Settings 里的 endpoint、headers、auth 和 `config.target_schema=earth_boundary_source`,点击采集时会真实请求 endpoint保存完整响应到 `data/earth-boundary-sources/<collector>/<sha256>.*`,并在 `CollectedData` 中写入 sha256、feature count、license、artifact path、sample properties 和 mapping 信息。
`earth_boundary_tiles` 不再代表源数据采集。它只读取上述三类源的最新成功记录缺任一源时任务失败并显示“未就绪”不会登记“4 条高精度瓦片”。三类源齐全后,它会调用 `tippecanoe` / `pmtiles` 生成 `frontend/public/earth/data/boundaries/earth-boundaries-china-pov-v1.pmtiles`;本机缺少这些工具时任务失败并说明缺失工具。国界不再有旧低精度兜底。
TOP500 和 Epoch AI 算力数据的公开源不总是提供可用经纬度。Earth 统一算力中心接口在主地图启动链路中只使用源数据自带坐标或 `compute_center_locations` 维表坐标;缺少坐标的记录会进入 `unresolved`,不会通过本地注册表、国家质心或猜测城市自动渲染。用户手动采集候选时,后端会用源字段调用 ROR 组织注册 API 和 Nominatim/OpenStreetMap 在线搜索;候选经前端保存后写入 `compute_center_locations`,后续地图刷新再从维表渲染。
## 四、数据格式 (统一存储到 CollectedData 表)
@@ -244,7 +252,8 @@ backend/app/services/collectors/
├── peeringdb.py # PeeringDB采集器
├── telegeraphy.py # TeleGeography海底光缆采集器
├── vessel_ais.py # BarentsWatch AIS 船只采集器
── aisstream.py # AISStream WebSocket 船只采集器
── aisstream.py # AISStream WebSocket 船只采集器
└── earth_boundaries.py # Earth 国界源校验和静态瓦片 artifact 采集器
backend/app/services/
├── custom_datasource_runtime.py # 自定义 REST / WebSocket 映射运行时

View File

@@ -309,6 +309,8 @@ GET /api/v1/vessels/snapshot?bbox=lon_min,lat_min,lon_max,lat_max&zoom=12&limit=
自定义源现在不是独立的新数据孤岛,而是作为内置数据源的补充源写入目标 schema。当前最完整的目标是 `vessel_ais`:自定义 REST 或 WebSocket 源经过确定性 mapping 后写入 AIS raw observations再通过 `vessels` WebSocket channel 推送给 Earth。
Earth 高精度边界使用同一套目标 schema 机制。`earth_boundary_source` 承接 `earth_admin0_boundaries``earth_coastline``earth_claim_lines` 三类源的映射结果;完整 GeoJSON / JSON 原文保存为 artifact数据库只保存 source kind、sha256、feature count、license、artifact path 和 sample properties避免把大型几何塞进单行记录。
### 配置语义
关键字段:
@@ -318,7 +320,7 @@ GET /api/v1/vessels/snapshot?bbox=lon_min,lat_min,lon_max,lat_max&zoom=12&limit=
- `auth_type``none``bearer``api_key``basic`
- `headers`:静态请求头。
- `auth_config`token、API key、basic 用户名密码API key 支持 header 或 query。
- `config.target_schema`:例如 `vessel_ais`
- `config.target_schema`:例如 `vessel_ais``earth_boundary_source`
- `config.delivery_mode`REST 默认 `polling`WebSocket 默认 `realtime_stream`
- `config.merge_target_source`:记录该自定义源补充哪个内置数据,例如 `barentswatch_vessels`

View File

@@ -123,12 +123,16 @@ Browser Camera provider 的手势识别管线在 [motion-browser-provider.js](/h
- [earth.js](/home/ray/dev/linkong/planet/frontend/public/earth/js/earth.js)
- [terrain.js](/home/ray/dev/linkong/planet/frontend/public/earth/js/terrain.js)
- [country-boundaries.js](/home/ray/dev/linkong/planet/frontend/public/earth/js/country-boundaries.js)
职责:
- 地球球体、云层、大气
- 真实地形 mesh
- terrain tile 拉取、解码、位移、着色
- 海陆基座与国界底图的整球 overlay
Earth 地表是多层近似同心球,不是单一 mesh。`earth.js` 的基座球、高清材质 overlay、云层/大气,以及 `country-boundaries.js` 的海陆基座都需要明确半径间距。远距视图下 GPU 深度精度会下降,相邻 shell 过近会 z-fighting表现为黑色闪烁块或雪花。当前稳定策略是让海陆基座使用 `landAltitudeOffset = 0.32`,高清材质使用 `textureOverlayAltitudeOffset = 0.48`;后续新增或调整整球地表 overlay 时,必须同步检查 [Earth 渲染图层顺序](/home/ray/dev/linkong/planet/docs/technical/zh/earth-render-layer-order.md),并在 50% 缩放视图验证。
### 7. 图层模块

View File

@@ -26,7 +26,7 @@
| Earth 基座 specular | `EARTH_MATERIAL_CONFIG.specular` | `0x1a2d45` | `MeshPhongMaterial.specular` |
| Earth 基座 shininess | `EARTH_MATERIAL_CONFIG.shininess` | `12` | `MeshPhongMaterial.shininess` |
| Earth 基座 opacity | `EARTH_MATERIAL_CONFIG.opacity` | `1` | `MeshPhongMaterial.opacity` |
| 高清材质半径偏移 | `EARTH_MATERIAL_CONFIG.textureOverlayAltitudeOffset` | `0.1` | 独立高清材质球半径 |
| 高清材质半径偏移 | `EARTH_MATERIAL_CONFIG.textureOverlayAltitudeOffset` | `0.48` | 独立高清材质球半径;必须与海陆基座和地球基座保持足够深度间距,避免远距 z-fighting |
| 高清材质透明度 | `EARTH_MATERIAL_CONFIG.textureOverlayOpacity` | `0.88` | 高清材质 `MeshPhongMaterial.opacity` |
| 高清材质 renderOrder | `EARTH_MATERIAL_CONFIG.textureOverlayRenderOrder` | `0.96` | `_earthTextureOverlay.renderOrder` |
| 高清材质 specular | `EARTH_MATERIAL_CONFIG.textureOverlaySpecular` | `0x05080d` | 降低直射区域镜面高光,避免贴图死白 |
@@ -84,11 +84,18 @@
| 正式名称 | 变量名 | 当前值 | 使用位置 / 说明 |
| --- | --- | --- | --- |
| 国界数据路径 | `COUNTRY_BOUNDARY_CONFIG.dataPath` | `"/earth/data/countries-admin0.min.geojson"` | GeoJSON 输入 |
| 国界瓦片 manifest | `COUNTRY_BOUNDARY_CONFIG.tileManifestPath` | `"/earth/data/boundaries/v1/manifest.json"` | 必需的生产 PMTiles manifest缺失即报错 |
| 国界瓦片 provider | `COUNTRY_BOUNDARY_CONFIG.tileProvider` | `"pmtiles-mvt"` | 国界只接受 PMTiles/MVT |
| PMTiles 产物路径 | `COUNTRY_BOUNDARY_CONFIG.pmtilesPath` | `"/earth/data/boundaries/earth-boundaries-china-pov-v1.pmtiles"` | 生产单文件 PMTiles/MVT artifact |
| MVT 图层名 | `COUNTRY_BOUNDARY_CONFIG.mvtLayerNames` | `boundary_admin0 / boundary_disputed_internal / coastline / claim_line` | PMTiles provider 解码时读取的固定 layer 名 |
| 国界瓦片基础路径 | `COUNTRY_BOUNDARY_CONFIG.tileBasePath` | `"/earth/data/boundaries/v1/"` | PMTiles manifest 基础路径 |
| 国界瓦片缩放阈值 | `COUNTRY_BOUNDARY_CONFIG.tileZoomThresholds` | `1.6 -> z5`, `2.8 -> z6`, `3.4 -> z7`, `4.0 -> z8`, `4.6 -> z9`, `5.2 -> z10` | 生产 PMTiles zoom 选择 |
| 国界瓦片缓存上限 | `COUNTRY_BOUNDARY_CONFIG.tileCacheLimit` | `150` | 前端已加载瓦片几何的 LRU 缓存条目数 |
| 国界瓦片 debounce | `COUNTRY_BOUNDARY_CONFIG.tileDebounceMs` | `180` | 视野变化后请求可见瓦片前的防抖时间 |
| 海洋填充色 | local `OCEAN_HEX` | `0x010609` | 海陆基座 canvas 背景 |
| 陆地填充色 | `COUNTRY_BOUNDARY_CONFIG.landColor` | `0x080f1b` | 海陆基座 canvas 陆地 |
| 海陆基座透明度 | `COUNTRY_BOUNDARY_CONFIG.landOpacity` | `1.0` | `MeshBasicMaterial.opacity` |
| 海陆基座半径偏移 | `COUNTRY_BOUNDARY_CONFIG.landAltitudeOffset` | `0.08` | `country-land-ocean` 半径 |
| 海陆基座半径偏移 | `COUNTRY_BOUNDARY_CONFIG.landAltitudeOffset` | `0.32` | `country-land-ocean` 半径;与地球基座拉开以避免 50% 缩放时雪花/黑块闪烁 |
| 海陆基座 renderOrder | `COUNTRY_BOUNDARY_CONFIG.landRenderOrder` | `0.86` | `country-land-ocean.renderOrder` |
| 海陆 mask 尺寸 | `landMaskWidth / landMaskHeight` | `2048 / 1024` | canvas / DataTexture 尺寸 |
| 国界 tint 颜色 | `COUNTRY_BOUNDARY_CONFIG.tintColor` | `0x0b1830` | 高清材质关闭时 tint |
@@ -97,16 +104,16 @@
| 国界线颜色 | `COUNTRY_BOUNDARY_CONFIG.lineColor` | `0x7fc7ff` | 普通国界线 |
| 国界线透明度 | `COUNTRY_BOUNDARY_CONFIG.lineOpacity` | `0.58` | 普通国界线 opacity |
| 国界线 hover 时压暗透明度 | `COUNTRY_BOUNDARY_CONFIG.dimmedLineOpacity` | `0.18` | hover 时普通国界线 opacity |
| 国界线半径偏移 | `COUNTRY_BOUNDARY_CONFIG.lineAltitudeOffset` | `0.115` | 普通国界线半径;略高于高清材质 `0.10`,低于地形基准 `0.16`,减少悬浮感 |
| 国界线半径偏移 | `COUNTRY_BOUNDARY_CONFIG.lineAltitudeOffset` | `0.115` | 普通国界线半径;线层靠 renderOrder 和独立 geometry 叠加,不作为整球基座深度间距参考 |
| 国界线 renderOrder | `COUNTRY_BOUNDARY_CONFIG.lineRenderOrder` | `2.2` | 普通国界线层级 |
| 国界 hover 颜色 | `COUNTRY_BOUNDARY_CONFIG.hoverLineColor` | `0xff3b1f` | 霓虹红橘 |
| 国界 hover 透明度 | `COUNTRY_BOUNDARY_CONFIG.hoverLineOpacity` | `1.0` | hover 实线 opacity |
| 国界 hover 半径偏移 | `COUNTRY_BOUNDARY_CONFIG.hoverAltitudeOffset` | `0.14` | hover 实线半径;贴近地表但高于普通国界线 |
| 国界 hover 半径偏移 | `COUNTRY_BOUNDARY_CONFIG.hoverAltitudeOffset` | `0.115` | hover 实线半径;与普通国界线同源几何对齐,避免高亮切换时出现重影 |
| 国界 hover renderOrder | `COUNTRY_BOUNDARY_CONFIG.hoverLineRenderOrder` | `2.3` | hover 实线层级 |
| 国界 hover glow 透明度 | `COUNTRY_BOUNDARY_CONFIG.hoverGlowOpacity` | `0.38` | glow 线 opacity |
| 国界 hover glow 线宽 | `COUNTRY_BOUNDARY_CONFIG.hoverGlowLineWidth` | `3` | glow `LineBasicMaterial.linewidth` |
| 国界 hover glow 层级偏移 | `COUNTRY_BOUNDARY_CONFIG.hoverGlowRenderOrderOffset` | `0.01` | glow renderOrder = `2.29` |
| 国界 hover glow 半径偏移 | `COUNTRY_BOUNDARY_CONFIG.hoverGlowRadiusOffset` | `0.04` | glow 半径 = hover 半径 + 0.04 |
| 国界 hover glow 半径偏移 | `COUNTRY_BOUNDARY_CONFIG.hoverGlowRadiusOffset` | `0` | glow hover 实线共用半径,避免海岸细节处双线错位 |
## 真实地形

View File

@@ -18,15 +18,15 @@
| -1 | Earth 遮挡球 | `earth.js` | 地球内侧不可见球 | 写入深度 | 遮挡地球背面的对象。 |
| 0 | Earth 基座球 | `earth.js` | `CONFIG.earthRadius` | 地表拾取兜底目标 | 深色基座,所有可选地图层关闭时仍可见。 |
| 0.2 | 国界暗色 tint | `country-boundaries.js` | `tintAltitudeOffset` | 禁用 raycast | 高清材质关闭时使用。 |
| 0.86 | 海陆基座填充 | `country-boundaries.js` | `landAltitudeOffset`; 海洋 `#010609`,陆地 `#080f1b` | 禁用 raycast | 即使国界线关闭,基座地图仍保持可用。 |
| 0.96 | 高清 Earth 材质 | `earth.js` | `textureOverlayAltitudeOffset` | 可见时作为地表拾取目标 | 高清材质始终压过海陆基座填充。 |
| 0.86 | 海陆基座填充 | `country-boundaries.js` | `landAltitudeOffset = 0.32`; 海洋 `#010609`,陆地 `#080f1b` | 禁用 raycast | 即使国界线关闭,基座地图仍保持可用;半径与基座球拉开以避免远距 z-fighting。 |
| 0.96 | 高清 Earth 材质 | `earth.js` | `textureOverlayAltitudeOffset = 0.48` | 可见时作为地表拾取目标 | 高清材质始终压过海陆基座填充;半径必须高于海陆基座并与基座球保持足够间距。 |
| 1 | 大气辉光和云图 | `earth.js` | 大气 / 云层球 | 不走普通对象选择路径 | 云图由“大气云图”图层开关控制。 |
| 1 | 海缆 / 登陆点 | `cables.js` | 海缆线和登陆点都使用 `renderOrder = 1`;半径偏移都为 `0.2`;登陆点是专用 `THREE.Sprite` 黄色扁平球 | 海缆走海缆拾取路径;登陆点 `depthTest: false` 保持球体完整,并用相机到球心的球体遮挡判断避免背面穿透 | 登陆点和海缆同层贴地,避免地表设施层的凌空感。 |
| 1.2 | 真实地形 | `earth.js`, `terrain.js` | `TERRAIN_CONFIG.baseRadiusOffset` 加地形位移 | 禁用 raycast | 地形压过高清材质;高清材质关闭时临时隐藏,重新开启后恢复原状态。 |
| 2.05 | 经纬线 | `earth.js` | `CONFIG.earthRadius + 0.14` | 禁用 raycast | 低透明度显示在高清材质上。 |
| 2.2 | 国界线 | `country-boundaries.js` | `lineAltitudeOffset = 0.115` | `depthTest: true`,禁用 raycast | 略高于高清材质 `0.10`,低于地形基准 `0.16`,减少悬浮感;地形 `depthWrite: false`,所以地形开启时仍可见。 |
| 2.2 | 国界线 | `country-boundaries.js` | `lineAltitudeOffset = 0.115` | `depthTest: true`,禁用 raycast | 线层使用独立 line geometry 与 `renderOrder` 控制;地形 `depthWrite: false`,所以地形开启时仍可见。 |
| 2.29 | 国界 hover 光晕 | `country-boundaries.js` | hover 半径加 glow 偏移 | `depthTest: false`,禁用 raycast | 用 additive 光晕增强交界边和地形开启时的 hover 可见性。 |
| 2.3 | 国界 hover 实线 | `country-boundaries.js` | `hoverAltitudeOffset = 0.14` | `depthTest: false`,禁用 raycast | 霓虹红橘 hover 线;中国和中国(台湾)共享高亮组。 |
| 2.3 | 国界 hover 实线 | `country-boundaries.js` | `hoverAltitudeOffset = 0.115` | `depthTest: false`,禁用 raycast | 霓虹红橘 hover 线;与普通国界线同源半径对齐,避免重影;中国和中国(台湾)共享高亮组。 |
| 3 | 卫星 footprint 填充 / Iridium coverage ring | `satellites.js`, `iridium-footprint-adapter.js` | `GROUND_FOOTPRINT_RENDER_ORDER` | depth-testedIridium adapter 的 fill / ring 也使用同一 renderOrder | Footprint 在 land / texture / terrain 和国界线之上,但在算力中心和卫星之下。 |
| 3-4.5 | BGP 观测站、事件扩散圈和事件 marker | `bgp.js`, `interactable.js` | BGP 观测站和事件 marker 均使用 `Interactable` 批量 `THREE.Points`;事件 marker 使用 `BGP_EVENT_RENDER_ORDER = 4.5`;观测站主图标使用 `BGP_COLLECTOR_RENDER_ORDER = 4.4``BGP_CONFIG.collectorAltitudeOffset = 0.2`;事件 overlay 进入 `bgp-event-overlay-layer`;观测站 halo 和覆盖扇形进入 `bgp-collector-radar-layer` | BGP 事件和观测站都通过 `Interactable` 屏幕空间 picking并参与同坐标避让 | BGP 观测站主图标与船只同层BGP 事件与算力中心同层;向外扩散圈、观测站雷达/覆盖动画继续由 BGP 业务逻辑驱动。 |
| 4.3 | AIS 船只轨迹线 | `vessels.js` | `VESSEL_RENDER_ORDER - 0.1``CONFIG.earthRadius + VESSEL_CONFIG.track.altitudeOffset` | 跟随船只显隐,不单独参与拾取 | 选中船只后显示最近轨迹,低于船只 marker。 |
@@ -48,6 +48,17 @@
| 国界线 off | 只隐藏可交互国界线和 hover高亮状态会清除海陆基座填充仍作为 Earth 底图保留。 |
| 真实卫星高度 off | 卫星点、轨迹和预测轨道都使用旧版同层球面;缺失 TLE 或传播失败的卫星也使用同一 fallback 高度。 |
## 深度间距规则
Earth 的地表不是单一 mesh而是多层近似同心球基座球、海陆基座、高清材质、地形、云层、大气和遮挡球。近距看起来只差几个小数的半径偏移在 50% 这类远距视图下会被深度缓冲压到同一批像素,导致 z-fighting表现为黑块、雪花或闪烁。
维护规则:
- 不要用“远距隐藏图层”作为第一反应;先检查相邻 shell 的 `altitudeOffset``renderOrder``depthTest``depthWrite`
- 海陆基座和高清材质这类整球 overlay 必须与 `CONFIG.earthRadius` 保持明确间距;当前稳定值为 `landAltitudeOffset = 0.32``textureOverlayAltitudeOffset = 0.48`
- 新增整球或近整球地表 overlay 时,必须在 50% 缩放和常用近距视图各截一次图,确认没有黑块、雪花、闪烁,也没有明显漂浮感。
- 如果必须调整这些半径,需同步更新本文和 `frontend/public/earth/js/constants.js` 的注释/常量意图。
## 交互规则
| 交互 | 当前规则 |

View File

@@ -58,9 +58,9 @@ tasklist /svc /fi "PID eq 4700"
Stop-Service iphlpsvc -Force
```
这可能影响部分网络、代理或转发能力。长期不推荐禁用该服务;新版本 `--allow-lan`用临时 Windows relay 暴露 `3000` / `8000`,不再需要保留持久 portproxy。
这可能影响部分网络、代理或转发能力。长期不推荐禁用该服务;`--allow-lan`直接绑定 `3000` / `8000` / `8010`,不再需要保留持久 portproxy。
如果脚本输出 `failed-stop-service``failed-stop-process`,或 Vite 报 `Port 3000 is already in use` 后显示 `Windows listener ... services=iphlpsvc`,说明旧的 Windows listener 仍在占用端口。脚本会停止启动,并提示用管理员 PowerShell 检查 `netsh interface portproxy show all`,删除对应 `listenport` 规则如果没有 portproxy 规则,再用 `netstat` / `tasklist` 确认服务,必要时临时 `Stop-Service iphlpsvc -Force`。清理旧规则后重新运行 `./planet.sh restart --allow-lan`脚本会启动临时 relay局域网仍访问 `3000` / `8000`
如果脚本输出 `Windows 侧端口 ... 存在监听者`,或 Vite 报 `Port 3000 is already in use` 后显示 `Windows listener ... services=iphlpsvc`,说明旧的 Windows listener 仍在占用端口。脚本会请求管理员 PowerShell 清理对应端口;如果自动清理被取消,再手动检查 `netsh interface portproxy show all`,删除对应 `listenport` 规则如果没有 portproxy 规则,再用 `netstat` / `tasklist` 确认服务,必要时临时 `Stop-Service iphlpsvc -Force`。清理旧规则后重新运行 `./planet.sh restart --allow-lan`,局域网仍访问 `3000` / `8000` / `8010`
### 默认端口冲突时应该改哪些参数?
@@ -89,6 +89,7 @@ Stop-Service iphlpsvc -Force
# 在 WSL 或运行 Planet 的 shell 中
curl http://localhost:3000
curl http://localhost:8000/health
curl http://localhost:8010/health
```
再到 Windows PowerShell 验证:
@@ -96,6 +97,7 @@ curl http://localhost:8000/health
```powershell
curl http://localhost:3000
curl http://localhost:8000/health
curl http://localhost:8010/health
```
如果 WSL 和 Windows localhost 都通,但手机或其他电脑访问不通,再考虑局域网开放:
@@ -110,16 +112,18 @@ curl http://localhost:8000/health
./planet.sh restart -f 3000 --allow-lan
```
如果 `ss -ltnp` 显示前端已经监听 `0.0.0.0:3000`,但 Windows PowerShell 中 `Test-NetConnection <Windows局域网IP> -Port 3000` 仍失败,问题通常不在 Vite 或 `.zshrc`,而是在 Windows 侧转发或防火墙。
如果 `ss -ltnp` 显示前端已经监听 `0.0.0.0:3000`,但 Windows PowerShell 中 `Test-NetConnection <Windows局域网IP> -Port 3000` 仍失败,问题通常不在 Vite 或 `.zshrc`,而是在 Windows 侧端口占用、旧 `portproxy` 或防火墙。
传统 WSL NAT 场景下,`./planet.sh start --allow-lan`启动临时 Windows relay让 Windows 对外仍使用 `3000` / `8000`。脚本会在启动前检测并请求管理员 PowerShell 删除`portproxy`,也会检测 Windows 防火墙规则;如果缺少 `3000` / `8000` 入站放行会触发一次 UAC 管理员 PowerShell 请求来自动创建。若自动请求被取消,可以手动清理:
`./planet.sh start --allow-lan`直接开放 `3000` / `8000` / `8010`,并在启动前检测端口、`portproxy` Windows 防火墙规则。端口被 Windows 侧 listener 占用时,脚本会请求管理员 PowerShell 清理;缺少入站放行时,也会触发一次 UAC 管理员 PowerShell 请求来自动创建。若自动请求被取消,可以手动清理:
```powershell
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=3000
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=8000
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=8010
New-NetFirewallRule -DisplayName "WSL Planet 3000" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 3000
New-NetFirewallRule -DisplayName "WSL Planet 8000" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8000
New-NetFirewallRule -DisplayName "WSL Planet 8010" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8010
```
局域网设备访问 Windows 对外端口,例如 `http://<Windows局域网IP>:3000/earth`
@@ -129,6 +133,7 @@ New-NetFirewallRule -DisplayName "WSL Planet 8000" -Direction Inbound -Action Al
```powershell
New-NetFirewallHyperVRule -Name "Planet-Frontend-3000" -DisplayName "Planet Frontend 3000" -Direction Inbound -VMCreatorId "{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}" -Protocol TCP -LocalPorts 3000 -Action Allow
New-NetFirewallHyperVRule -Name "Planet-Backend-8000" -DisplayName "Planet Backend 8000" -Direction Inbound -VMCreatorId "{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}" -Protocol TCP -LocalPorts 8000 -Action Allow
New-NetFirewallHyperVRule -Name "Planet-AIProvider-8010" -DisplayName "Planet AI Provider 8010" -Direction Inbound -VMCreatorId "{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}" -Protocol TCP -LocalPorts 8010 -Action Allow
```
也可以用下面命令确认当前 Hyper-V firewall 状态:

View File

@@ -155,7 +155,7 @@ wait_for_port_release() {
- `PORT_PRESTART_RETRIES`:默认 3 次。
- `PORT_PRESTART_RETRY_INTERVAL`:默认 2 秒。
`kill_port_if_requested()` 优先清理当前环境能找到的监听 PID只有检测到当前运行在 WSL 且没有可杀 PID、但端口仍不可绑定时才会检查 Windows 侧 listener尝试通过 PowerShell 停止对应服务或强制结束对应进程。若没有权限,或 `iphlpsvc` 这类系统服务拒绝停止,脚本会打印 Windows listener 详情和管理员 PowerShell 处理命令,然后立即停止启动,不再继续拉起服务碰同一个端口错误。前端 Vite 启动后才发现 `Port 3000 is already in use` 时,也会打印同一套 Windows listener 处理命令。非 WSL 环境不会尝试 Windows 清理路径。`--allow-lan` 在 WSL 下会使用临时 Windows relay 暴露 `3000` / `8000`所以旧的持久 portproxy 规则应清理掉。
`kill_port_if_requested()` 优先清理当前环境能找到的监听 PID只有检测到当前运行在 WSL 且没有可杀 PID、但端口仍不可绑定时才会检查 Windows 侧 listener请求管理员 PowerShell 删除旧 `portproxy`、停止占用端口的服务或强制结束对应进程。若管理员请求被取消,或 `iphlpsvc` 这类系统服务拒绝停止,脚本会打印 Windows listener 详情和管理员 PowerShell 处理命令,然后立即停止启动,不再继续拉起服务碰同一个端口错误。前端 Vite 启动后才发现 `Port 3000 is already in use` 时,也会打印同一套 Windows listener 处理命令。非 WSL 环境不会尝试 Windows 清理路径。`--allow-lan` 直接开放 `3000` / `8000` / `8010`不再启动额外的 Windows 端口转发进程;旧的持久 portproxy 规则应清理掉。
## 问题三:端口检测用 Python

View File

@@ -120,7 +120,7 @@
- 手机或平板演示 Earth
- 局域网其他机器访问同一开发实例
`--allow-lan` 只负责让前端和后端监听 `0.0.0.0`。WSL 中运行时Windows 本机一般可以通过 `localhost` 访问,局域网其他机器访问 Windows 局域网 IP 时还需要 Windows 端口转发和防火墙放行。
`--allow-lan` 会让前端、后端和 AI Provider 直接对开发机开放:前端 `3000`、后端 `8000`、AI Provider `8010`。脚本启动前会检查这三个端口;如果 WSL/Linux 侧无法释放端口,并检测到 Windows 侧 listener 或旧 `portproxy`,会请求管理员 PowerShell 清理。WSL 中运行时Windows 本机一般可以通过 `localhost` 访问,局域网其他机器访问 Windows 局域网 IP 时还需要 Windows 防火墙放行。
建议按顺序排查:
@@ -128,20 +128,23 @@
# 在运行 Planet 的 shell 中
curl http://localhost:3000
curl http://localhost:8000/health
ss -ltnp | grep -E ':3000|:8000'
curl http://localhost:8010/health
ss -ltnp | grep -E ':3000|:8000|:8010'
```
如果看到 WSL 内部服务已经启动但局域网 IP 仍访问失败,`./planet.sh start --allow-lan` 启动临时 Windows relay。relay 会让 Windows 对外继续使用 `3000` / `8000`,并在 WSL 目标端口断开后自动退出。脚本会检测并请求管理员 PowerShell 删除`portproxy`,也会检测 Windows 防火墙规则;缺少入站放行时会触发一次 UAC 管理员 PowerShell 请求自动创建。手动兜底命令如下:
如果服务已经启动但局域网 IP 仍访问失败,优先清理`portproxy` 并确认 Windows 防火墙放行。脚本会自动检测并请求管理员 PowerShell 处理;自动请求被取消时,手动兜底命令如下:
```powershell
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=3000
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=8000
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=8010
New-NetFirewallRule -DisplayName "WSL Planet 3000" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 3000
New-NetFirewallRule -DisplayName "WSL Planet 8000" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8000
New-NetFirewallRule -DisplayName "WSL Planet 8010" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8010
```
局域网设备访问 Windows 对外端口,例如 `http://<Windows局域网IP>:3000/earth`
局域网设备访问 Windows 对外端口,例如 `http://<Windows局域网IP>:3000/earth``http://<Windows局域网IP>:8000/health``http://<Windows局域网IP>:8010/health`
## AI Provider 环境变量与构建
@@ -238,6 +241,16 @@ uv sync
uv run pytest backend/tests/test_otp_service.py
```
## Earth 国界 PMTiles 操作步骤
1. 在后台 Collector Settings 中分别配置 `Earth Admin-0 国界源``Earth 海岸线源``Earth 主张线源` 的 endpoint、headers/auth、`config.target_schema=earth_boundary_source`、license 和 mapping。
2. 在数据源页依次采集这三个源。每个源成功后会保存完整 artifact 到 `data/earth-boundary-sources/<collector>/<sha256>.*`,并写入 sha256、feature count、artifact path、sample properties。
3. 三个源都成功后,再采集 `Earth PMTiles 构建器`。缺任一源时它会失败为“未就绪”,不会更新 Earth 国界。
4. 构建器需要本机 PATH 里有 `tippecanoe``pmtiles`。缺工具时任务失败并显示缺失工具。
5. 生产构建成功后应输出 `frontend/public/earth/data/boundaries/earth-boundaries-china-pov-v1.pmtiles` 和对应 manifest。
6. 部署后打开 Earth开启“国界线”放大中国东南海岸、台湾、海南、南海、藏南、科索沃、加沙等区域验证 hover 和边界口径。
7. 如果 PMTiles 加载失败Earth 会报国界图层错误并且不绘制旧低精度国界。排查顺序是:浏览器 Network 是否有 PMTiles range 请求、manifest 的 `tileProvider` 是否为 `pmtiles-mvt`、Nginx 是否能静态返回 `.pmtiles`、artifact 路径和 sha256 是否与 manifest 一致。
## 相关文档
- [planet.sh 启动机制](/home/ray/dev/linkong/planet/docs/technical/zh/ops-planet-sh-startup.md)