Skip to content

Commit 4c48d4c

Browse files
committed
save pmtiles debug
1 parent 7a74228 commit 4c48d4c

15 files changed

Lines changed: 308 additions & 19 deletions

CLAUDE.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# 3DTilesRendererJS - Claude Code Guide
2+
3+
## Project Overview
4+
5+
**3DTilesRendererJS** is a Three.js renderer implementation for the [3D Tiles specification](https://github.com/CesiumGS/3d-tiles), an OGC standard for streaming massive geospatial 3D datasets. This NASA-AMMOS project supports rendering geographic and geometric tile data including Mars terrain, Google Photorealistic Tiles, and various map tile formats.
6+
7+
- **Package**: `3d-tiles-renderer` (npm)
8+
- **License**: Apache-2.0
9+
10+
## Build Commands
11+
12+
```bash
13+
npm install # Install dependencies
14+
npm start # Dev server at http://localhost:5173
15+
npm run build-lib # Build library to /build
16+
npm test # TypeScript check + Vitest
17+
npm run lint # ESLint + TypeScript
18+
```
19+
20+
## Directory Structure
21+
22+
```
23+
src/
24+
├── core/ # Framework-agnostic implementations
25+
│ ├── plugins/ # Base plugin classes
26+
│ └── renderer/
27+
│ ├── loaders/ # Format loaders: B3DM, I3DM, PNTS, CMPT, MVT
28+
│ ├── tiles/ # Tile traversal algorithms
29+
│ └── utilities/ # BatchTable, PriorityQueue, LRUCache
30+
├── three/ # Three.js-specific implementations
31+
│ ├── plugins/ # Three.js plugins
32+
│ │ ├── images/ # Image overlay plugins (TMS, XYZ, WMTS, WMS, MVT, PMTiles)
33+
│ │ │ └── sources/ # Image source implementations
34+
│ │ ├── gltf/ # GLTF extensions & metadata
35+
│ │ └── batched/ # Batched rendering optimization
36+
│ └── renderer/
37+
│ ├── loaders/ # Three.js tile format loaders
38+
│ ├── tiles/ # TilesRenderer & TilesGroup
39+
│ ├── controls/ # GlobeControls, EnvironmentControls
40+
│ └── math/ # Ellipsoid, OBB, GeoUtils
41+
├── r3f/ # React Three Fiber components
42+
└── plugins.js # Plugin re-exports
43+
44+
example/ # Three.js and R3F examples
45+
test/ # Vitest unit tests
46+
```
47+
48+
## Architecture
49+
50+
### Main Classes
51+
52+
- **TilesRenderer** (`src/three/renderer/tiles/TilesRenderer.js`) - Main Three.js rendering class
53+
- **TilesRendererBase** (`src/core/renderer/tiles/TilesRendererBase.js`) - Framework-agnostic core
54+
55+
### Plugin System
56+
57+
Plugins extend functionality through lifecycle hooks:
58+
59+
```javascript
60+
class MyPlugin extends TilesPlugin {
61+
constructor() {
62+
super();
63+
this.name = 'MY_PLUGIN';
64+
}
65+
preprocessURL( url ) { }
66+
postProcess( tile ) { }
67+
onLoadModel( { scene, tile } ) { }
68+
onDisposeModel( { scene, tile } ) { }
69+
}
70+
```
71+
72+
### Tile Formats Supported
73+
74+
- **B3DM** - Batched 3D Model
75+
- **I3DM** - Instanced 3D Model
76+
- **PNTS** - Point Cloud
77+
- **CMPT** - Composite
78+
- **MVT** - Mapbox Vector Tiles (in development)
79+
- **Quantized Mesh** - Terrain mesh
80+
81+
## Code Style
82+
83+
- **Indentation**: Tabs
84+
- **Quotes**: Single quotes
85+
- **Semicolons**: Always
86+
- **Naming**: Long descriptive names preferred (`isHierarchicallyVisible` not `isVis`)
87+
- **Private members**: Underscore prefix (`this._internalState`)
88+
- **Comments**: Explain WHY, not WHAT
89+
90+
## Key Technologies
91+
92+
- **three**: ^0.170.0 (required peer dependency)
93+
- **vite**: Build tool
94+
- **vitest**: Test runner
95+
- **typescript**: Type checking (JSDoc-based)
96+
97+
## Module Exports
98+
99+
- `3d-tiles-renderer` - Full library
100+
- `3d-tiles-renderer/core` - Core only
101+
- `3d-tiles-renderer/three` - Three.js implementation
102+
- `3d-tiles-renderer/r3f` - React Three Fiber
103+
- `3d-tiles-renderer/three/plugins` - Three.js plugins

example/three/geojson.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/three/mvt_globe.js

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@ import {
1212
import {
1313
UpdateOnChangePlugin,
1414
MVTTilesPlugin,
15-
MVTTilesMeshPlugin
15+
MVTTilesMeshPlugin,
16+
PMTilesPlugin
1617
} from '3d-tiles-renderer/plugins';
1718

1819
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
1920

2021
let scene, renderer, camera, controls, tiles, gui;
2122

22-
const apiKey = localStorage.getItem( 'mapbox_key' ) || prompt( 'Enter Mapbox API Key' );
23-
if ( apiKey ) localStorage.setItem( 'mapbox_key', apiKey );
23+
// const apiKey = localStorage.getItem( 'mapbox_key' ) || prompt( 'Enter Mapbox API Key' );
24+
// if ( apiKey ) localStorage.setItem( 'mapbox_key', apiKey );
2425

2526
// --- Dynamic Filter State ---
2627
const state = {
@@ -41,13 +42,13 @@ const state = {
4142
landuse: '#caedc1',
4243
building: '#eeeeee',
4344
road: '#444444',
44-
admin: '#ff0000',
45+
boundaries: '#ff0000',
4546
poi: '#ffcc00',
4647
default: '#222222'
4748
}
4849
};
4950

50-
const MVT_URL = `https://api.mapbox.com/v4/mapbox.mapbox-streets-v8/{z}/{x}/{y}.vector.pbf?access_token=${apiKey}`;
51+
// const MVT_URL = `https://api.mapbox.com/v4/mapbox.mapbox-streets-v8/{z}/{x}/{y}.vector.pbf?access_token=${apiKey}`;
5152

5253
init();
5354
setupGUI();
@@ -90,10 +91,10 @@ function mvtFilter( feature, layerName ) {
9091
if ( layerName === 'landuse' && ! state.showLanduse ) return false;
9192

9293
// 2. Advanced Admin Filtering
93-
if ( layerName === 'admin' ) {
94+
if ( layerName === 'boundaries' ) {
9495

9596
if ( ! state.showAdmin ) return false;
96-
return props.admin_level <= state.maxAdminLevel;
97+
return true;
9798

9899
}
99100

@@ -120,6 +121,8 @@ function recreateTiles() {
120121

121122
}
122123

124+
const PMTILES_URL = 'https://demo-bucket.protomaps.com/v4.pmtiles';
125+
123126
tiles = new TilesRenderer();
124127
tiles.registerPlugin( new UpdateOnChangePlugin() );
125128

@@ -128,20 +131,22 @@ function recreateTiles() {
128131
shape: 'ellipsoid',
129132
levels: 15,
130133
tileDimension: 512,
131-
url: MVT_URL,
134+
url: PMTILES_URL,
132135
styles: state.colors,
133136
filter: mvtFilter
134137
};
135138

136-
if ( state.pluginType === 'Mesh' ) {
139+
tiles.registerPlugin( new PMTilesPlugin( pluginOptions ) );
137140

138-
tiles.registerPlugin( new MVTTilesMeshPlugin( pluginOptions ) );
141+
// if ( state.pluginType === 'Mesh' ) {
139142

140-
} else {
143+
// tiles.registerPlugin( new MVTTilesMeshPlugin( pluginOptions ) );
141144

142-
tiles.registerPlugin( new MVTTilesPlugin( pluginOptions ) );
145+
// } else {
143146

144-
}
147+
// tiles.registerPlugin( new MVTTilesPlugin( pluginOptions ) );
148+
149+
// }
145150

146151
tiles.group.rotation.x = - Math.PI / 2;
147152
tiles.setCamera( camera );

package-lock.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,21 @@
9898
"globals": "^16.5.0",
9999
"leva": "^0.10.0",
100100
"postprocessing": "^6.36.4",
101+
"pmtiles": "^4.3.2",
101102
"three": "^0.170.0",
102103
"typescript": "^5.6.0",
103104
"typescript-eslint": "^8.48.1",
104105
"vite": "^6.2.2",
105106
"vitest": "^4.0.15"
106107
},
107108
"peerDependencies": {
109+
"@mapbox/vector-tile": "^2.0.3",
108110
"@react-three/fiber": "^8.17.9 || ^9.0.0",
111+
"earcut": "^3.0.2",
109112
"react": "^18.3.1 || ^19.0.0",
110113
"react-dom": "^18.3.1 || ^19.0.0",
111114
"three": ">=0.167.0",
112-
"@mapbox/vector-tile": "^2.0.3",
113-
"earcut": "^3.0.2"
115+
"pmtiles": "^4.3.2"
114116
},
115117
"peerDependenciesMeta": {
116118
"@react-three/fiber": {
@@ -127,6 +129,9 @@
127129
},
128130
"earcut": {
129131
"optional": true
132+
},
133+
"pmtiles": {
134+
"optional": true
130135
}
131136
}
132137
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { ColorRepresentation } from 'three';
2+
3+
export class PMTilesPlugin {
4+
5+
constructor( options: {
6+
url: string,
7+
tileDimension?: number,
8+
filter?: ( feature: any, layerName: string ) => boolean,
9+
styles?: { [ layerName: string ]: ColorRepresentation },
10+
11+
center?: boolean,
12+
shape?: 'ellipsoid' | 'planar',
13+
endCaps?: boolean,
14+
useRecommendedSettings?: boolean,
15+
} );
16+
17+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { EllipsoidProjectionTilesPlugin } from './EllipsoidProjectionTilesPlugin.js';
2+
import { PMTilesImageSource } from './sources/PMTilesImageSource.js';
3+
4+
export class PMTilesPlugin extends EllipsoidProjectionTilesPlugin {
5+
6+
constructor( options = {} ) {
7+
8+
const { ...rest } = options;
9+
super( rest );
10+
11+
this.name = 'PMTILES_PLUGIN';
12+
this.imageSource = new PMTilesImageSource( options );
13+
14+
}
15+
16+
fetchData( url, options ) {
17+
18+
if ( url.startsWith( 'pmtiles://' ) ) {
19+
20+
return this.imageSource.fetchInternal( url, options );
21+
22+
}
23+
24+
return null;
25+
26+
}
27+
28+
}

src/three/plugins/images/sources/MVTImageSource.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export class MVTImageSource extends XYZImageSource {
5656
const layerOrder = [
5757
'landuse', 'park', 'water', 'waterway',
5858
'transportation', 'road', 'building',
59-
'admin', 'poi', 'place_label'
59+
'boundaries', 'poi', 'place_label'
6060
];
6161

6262
const layersToDraw = Object.keys( vectorTile.layers ).sort( ( a, b ) => {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { ColorRepresentation, Texture } from 'three';
2+
import { PMTiles } from 'pmtiles';
3+
4+
export class PMTilesImageSource {
5+
6+
readonly pmtilesUrl: string;
7+
readonly instance: PMTiles;
8+
9+
constructor( options: {
10+
url: string,
11+
tileDimension?: number,
12+
filter?: ( feature: any, layerName: string ) => boolean,
13+
styles?: { [ layerName: string ]: ColorRepresentation },
14+
fetchOptions?: RequestInit,
15+
} );
16+
17+
init(): Promise<void>;
18+
getUrl( x: number, y: number, level: number ): string;
19+
fetchInternal( url: string, options: { signal?: AbortSignal } ): Promise<ArrayBuffer | null>;
20+
processBufferToTexture( buffer: ArrayBuffer ): Promise<Texture>;
21+
22+
}

0 commit comments

Comments
 (0)