SHINOBI EARTH — A Procedural 3D Geospatial Testbed for Spatial Analysis with CesiumJS

Hi everyone,

I wanted to share a technical follow-up to my previous SHINOBI EARTH project showcase.

The original post introduced the project as a fictional 3D WebGIS environment built with CesiumJS. In this post, I would like to go deeper into the actual structure of the environment, the spatial-analysis workflow, and how the generated geospatial data is connected to the Cesium visualization.

Previous project showcase:

SHINOBI EARTH is a fictional geospatial environment inspired by a ninja-world setting.

The fictional setting is mainly a convenient way to create a controlled spatial dataset. I can control the terrain, buildings, roads, rivers, vegetation and analytical attributes instead of depending entirely on an existing real-world dataset.

The current prototype contains:

  • approximately 1,200 spatial analysis cells

  • 882 buildings

  • a 200 m analysis grid

  • procedural 3D buildings

  • mountainous terrain

  • roads

  • rivers

  • vegetation

  • village districts and landmarks

  • building-density analysis

  • river-proximity analysis

  • a flood-risk heuristic

  • mountain / forest classification

  • development-suitability analysis

  • feature-level spatial information

The main question I am exploring is:

How can a procedural 3D environment become a structured geospatial testbed rather than simply a 3D visualization?


1. The 3D geospatial environment

The environment represents a fictional mountain valley containing a hidden village.

The scene contains terrain, forests, roads, a river network, buildings, districts and landmarks.

The important part is that the objects are not treated only as visual geometry.

They are associated with spatial information that can also be used by the analysis layer.

For example, a building can have:

  • a geographic position

  • a building identifier

  • a building type

  • a district

  • a village

  • an associated analysis cell

This makes it possible to move between the 3D representation and the underlying spatial information.

Figure 1. SHINOBI EARTH 3D exploration view showing the procedural mountain-valley environment, village districts, buildings, roads, river and surrounding vegetation.


2. Why use a fictional world?

The fictional environment is intentional.

Instead of starting with a real city and trying to modify an existing dataset, I can generate the spatial relationships that I want to investigate.

For example, I can control:

  • where buildings are generated

  • how dense different districts are

  • where roads are located

  • how the river passes through the village

  • how terrain and vegetation are distributed

  • which spatial cells contain particular features

This makes the environment useful as a repeatable testbed.

If the underlying parameters change, the environment can be regenerated and the analytical results can be recalculated.

The goal is therefore not to reproduce a real geographic location.

The goal is to create a controlled 3D spatial environment in which visualization and analysis can be developed together.


3. Technology stack

The current application is built with:

  • React

  • TypeScript

  • Vite

  • CesiumJS

  • custom geospatial datasets

  • procedural 3D geometry

  • client-side spatial analysis

At a high level, the application can be thought of as four layers:

Procedural Data
      │
      ▼
Spatial Dataset
      │
      ├── Buildings
      ├── Roads
      ├── Rivers
      ├── Vegetation
      └── Analysis Cells
      │
      ▼
Spatial Analysis
      │
      ├── Density
      ├── Proximity
      ├── Flood Heuristic
      ├── Classification
      └── Suitability
      │
      ▼
CesiumJS Visualization

The application layer manages the generated data and analysis results, while CesiumJS provides the interactive 3D geospatial visualization.


4. A 200 m spatial analysis grid

One of the main structural elements of the prototype is a spatial analysis grid.

The current environment uses a 200 m analysis grid containing approximately 1,200 cells.

The grid provides a common spatial reference for several analytical operations.

Instead of calculating every analytical result independently for every rendered object, the environment can associate objects and derived attributes with spatial cells.

This creates a bridge between the procedural 3D scene and the analytical dataset.

Figure 2. Konoha Analysis workspace showing the 200 m spatial grid and the analytical environment.

The grid can be used to associate information such as:

  • building counts

  • building-density categories

  • river proximity

  • flood-risk heuristic values

  • terrain / environmental classifications

  • development-suitability values

This is one of the main reasons I treat the environment as a geospatial testbed rather than only a 3D model.


5. Building-density analysis

The prototype currently contains 882 buildings.

The analysis layer associates buildings with the spatial environment and calculates relative building-density information.

The current interface also provides a summary of the analyzed building population.

The basic workflow is:

Generated Buildings
        │
        ▼
Spatial Cell Assignment
        │
        ▼
Building Count
        │
        ▼
Density Classification
        │
        ▼
3D Visualization

The current interface distinguishes high, medium and low density areas.

This makes it possible to inspect the relationship between the visible distribution of buildings and the corresponding analytical classification.

Figure 3. Spatial-analysis dashboard showing building-density results together with river-proximity, flood-risk and environmental analysis.

The important point is that the density visualization is derived from the spatial dataset rather than being only a decorative color overlay.


6. River-proximity analysis

The river is another important spatial feature in the environment.

The analysis layer evaluates the relationship between spatial cells and the river network.

The current interface divides cells into proximity categories such as:

  • within 100 m

  • 100–250 m

  • outside 250 m

The conceptual workflow is:

Analysis Cell
      │
      ▼
Distance to River
      │
      ▼
Proximity Category
      │
      ▼
Visualization

This provides a simple example of proximity-based spatial analysis in a 3D environment.

The same pattern could potentially be extended to:

  • roads

  • facilities

  • administrative boundaries

  • points of interest

  • other environmental features


7. Flood-risk heuristic

The prototype also includes an experimental flood-risk layer.

This is deliberately described as a heuristic, not a hydrological simulation or scientific flood-prediction model.

The purpose is to investigate how several spatial characteristics can be combined into a derived analytical attribute.

For example, the analysis can consider relationships involving:

  • river proximity

  • terrain

  • surrounding spatial conditions

The result is then associated with the spatial grid and visualized in the 3D environment.

The interface explicitly treats this as a heuristic rather than a real flood prediction model.

This distinction is important because the goal of this layer is to test the visualization and data workflow, not to claim hydrological accuracy.


8. Mountain and forest classification

Terrain and vegetation are also part of the analytical environment.

The prototype includes a mountain / forest classification layer that allows the generated landscape to participate in spatial analysis rather than remaining purely visual.

This creates another connection between procedural world generation and analytical data.

Conceptually:

Terrain / Vegetation
        │
        ▼
Spatial Classification
        │
        ▼
Analysis Cells
        │
        ▼
Cesium Visualization

This approach makes it possible to use the same generated environment for both visual exploration and analytical experiments.


9. Development-suitability analysis

Another experimental layer is development or expansion suitability.

The idea is to combine several spatial characteristics into a derived suitability value.

For example:

Terrain
   +
River Proximity
   +
Existing Buildings
   +
Environmental Classification
        │
        ▼
Suitability Heuristic
        │
        ▼
Spatial Grid
        │
        ▼
3D Visualization

Again, this is not intended to represent a real urban-planning model.

It is a controlled experiment for studying how multiple spatial variables can be combined and visualized in a CesiumJS environment.


10. Inspecting individual spatial features

One feature I particularly wanted in the prototype was the ability to inspect an individual object and connect it back to its geographic information.

For example, selecting a building exposes information including:

  • name

  • feature type

  • building identifier

  • building type

  • district

  • district ID

  • village

  • longitude

  • latitude

  • description

Figure 4. Selected building feature showing its spatial attributes, district information and geographic coordinates.

This is useful because it demonstrates the connection between the rendered 3D object and the underlying geospatial record.

The scene is therefore not just:

3D Building

but rather:

3D Building
     │
     ├── Feature ID
     ├── Building Type
     ├── District
     ├── Village
     ├── Longitude
     ├── Latitude
     └── Spatial Attributes

This relationship is important for a WebGIS application because the user should be able to move from visual context to structured geographic information.


11. Data and renderer consistency

This led to another technical problem: keeping the generated dataset and the rendered scene consistent.

If a building is generated at one location but assigned to the wrong spatial cell, the scene may look correct while the analysis is incorrect.

Similarly, the analytical dataset may contain a correct attribute while the rendered object displays an inconsistent state.

The general relationship is:

Generated Feature
        │
        ├── Geometry
        ├── Position
        ├── Attributes
        └── Spatial Cell
               │
               ▼
       Analytical Dataset
               │
               ▼
         Cesium Feature

For this reason, the application includes reconciliation and validation steps intended to keep the generated spatial data and the rendered representation aligned.

The goal is to maintain consistency between:

  • generated objects

  • spatial-cell assignments

  • analytical attributes

  • rendered Cesium features

This is one of the more interesting engineering aspects of the project for me, because the challenge is not only rendering a convincing scene but also ensuring that the scene remains a meaningful representation of the underlying data.


12. Procedural generation

The environment is generated procedurally rather than manually modeling every building and geographic feature.

A simplified generation pipeline looks like:

Generation Parameters
        │
        ▼
Terrain
        │
        ├─────────────┐
        ▼             ▼
      Rivers       Vegetation
        │             │
        └──────┬──────┘
               ▼
             Roads
               │
               ▼
          Buildings
               │
               ▼
       Analysis Grid
               │
               ▼
      Derived Attributes
               │
               ▼
          Cesium Scene

This approach gives me control over the relationships between the different components.

It also means that the dataset can be regenerated when parameters change.

That makes the environment more useful as a development and experimentation platform.


13. CesiumJS as the visualization layer

CesiumJS provides the interactive 3D geospatial environment in which the generated data can be explored.

The application layer is responsible for the generated data, analytical calculations and interface state, while CesiumJS handles the geographic 3D scene.

This separation raises several questions that I would like to investigate further.

For example:

  • When should a generated object be represented as an Entity?

  • When should lower-level Primitives be preferred?

  • When should geometry be batched?

  • When does a procedural environment become large enough to benefit from 3D Tiles?

  • How should analytical overlays be separated from base visualization?

  • How should analytical updates be propagated efficiently to the rendered scene?

The current prototype gives me a practical environment in which to explore these questions.


14. Performance considerations

The current environment contains hundreds of buildings and approximately 1,200 analysis cells.

As the environment grows, I expect rendering and update strategies to become increasingly important.

Areas I would like to investigate include:

  • geometry batching

  • reducing unnecessary geometry

  • reducing repeated calculations

  • minimizing unnecessary scene updates

  • separating analysis computation from rendering

  • Entity vs. Primitive approaches

  • 3D Tiles for larger generated datasets

At this stage, the project is primarily a testbed rather than a large-scale production system.

The goal is to use the current environment to identify which architectural decisions become important as the dataset grows.


15. Why this is useful as a geospatial testbed

The fictional setting provides one practical advantage: I control the dataset.

I can deliberately change:

  • building density

  • terrain

  • river location

  • vegetation

  • road layout

  • district boundaries

  • analysis parameters

and then regenerate or recalculate the environment.

This makes it possible to create controlled scenarios for testing.

For example, I can ask:

What happens to the analytical visualization when the building distribution changes?

Or:

How should the visualization change when a district moves closer to a river?

These questions are easier to investigate when the underlying dataset is under direct control.


16. Digital-twin perspective

I use the term “digital twin” in an experimental sense.

SHINOBI EARTH is not intended to be a digital twin of a real city or physical infrastructure system.

Instead, I am exploring some of the workflow concepts associated with digital-twin applications:

Spatial Data
     │
     ▼
3D Representation
     │
     ▼
Spatial Analysis
     │
     ▼
Derived Information
     │
     ▼
3D Visualization
     │
     ▼
Feature Inspection
     │
     ▼
Validation / Synchronization

The interesting part is the relationship between the underlying spatial data and the interactive 3D representation.


17. What I would like to explore next

There are several areas where I would appreciate feedback from the CesiumJS community.

Larger procedural environments

I would like to understand how other developers approach procedural environments when the number of generated objects becomes much larger.

Entity vs. Primitive

I would like to better understand where developers typically draw the line between convenient Entity-based representations and lower-level rendering approaches.

3D Tiles

I am also interested in understanding when it makes sense to move a procedurally generated environment toward 3D Tiles.

Analytical visualization

Another area I would like to improve is the visualization of spatial-analysis results without making the underlying 3D environment difficult to read.

Terrain-derived analysis

I would like to explore more sophisticated terrain-derived attributes and their relationship with analytical layers.

Data synchronization

Finally, I would like to develop stronger validation mechanisms between generated spatial data, analytical attributes and the rendered Cesium scene.


18. Conclusion

SHINOBI EARTH started as an experiment in building a fictional 3D environment with CesiumJS.

It has gradually become a controlled geospatial testbed for exploring the relationship between:

procedural generation → spatial data → spatial analysis → 3D visualization → feature inspection

The fictional setting gives me control over the dataset, while CesiumJS provides the 3D geospatial environment in which the data can be explored.

The current prototype is still experimental, but it provides a useful environment for investigating procedural geometry, spatial-analysis visualization, feature-level information, data/renderer consistency and future rendering strategies.

Live Demo:

Source Code:

I would especially appreciate feedback from other CesiumJS developers on:

  • Entity vs. Primitive architecture

  • Procedural geometry strategies

  • When to introduce 3D Tiles

  • Spatial-analysis visualization

  • Terrain-derived analysis

  • Data/renderer synchronization

  • Performance optimization for larger procedural datasets

Thanks for reading.

I would be very interested to hear how other CesiumJS developers would approach these problems.

There’s a lot to unpack here. The screenshots look pretty cool, but I’ll have to allocate much more time to read all that more thoroughly, and have a closer look. What caught my attention for now is … only a small, maybe shallow aspect, namely that of the procedural generation. I’ve been playing with approaches for generating ~“artificial test data” in various ways, including some 3D Tiles data. Again, I’ll have to read much more to properly understand the context here, but the specific point here is…

I am also interested in understanding when it makes sense to move a procedurally generated environment toward 3D Tiles.

… that these don’t have to be mutually exclusive. If it was possible to write out the generated data (and even if it’s just a “flat” tileset with a single LOD and some buildings), then this could be used to create some interesting test/demo data.

Thanks for taking the time to look at it — and that’s a really interesting point.

I was initially thinking about procedural generation and 3D Tiles more as two different stages/approaches, but your suggestion of using the procedural generator itself as a way to produce reusable 3D Tiles test/demo data makes a lot of sense.

A flat tileset with a single LOD and procedurally generated buildings sounds like a particularly interesting starting point. It could also make it easier to experiment with larger synthetic environments while keeping the generation process reproducible.

I’ll definitely explore this direction. I’d also be very interested to hear more about the approaches you’ve used for generating artificial 3D Tiles test data.

I have not yet looked at your post and repo in all depth - I’ll have to allocate (much) more time for that (maybe ~“next week”). Everything that I’m doing here is happening only as a “side track” for me, purely in my spare time. But given that this is exactly what your question refers to…

I’ll definitely explore this direction. I’d also be very interested to hear more about the approaches you’ve used for generating artificial 3D Tiles test data.

… an attempt of a short summary, starting with a disclaimer: It may look boring :slightly_smiling_face:

My focus was on creating test data that varies along certain “dimensions” of the data set characteristics. Roughly, to create test tilesets that have 2/3/4… levels of detail, with 2/4/8… children each, and each content has 10/100/1000KB of geometry and 10/100/1000KB of textures.

Yes, all that does look boring :slightly_smiling_face: . The focus was on the infrastructure for creating all this. I also did some experiments for building tilesets that look “nice” - something like this:

but… this is using pre-baked glTF models, and not generating them procedurally.


I’ll take a closer look at your repo, and have a look at where exactly e.g. the buildings are generated. I could imagine that there is some sort of
gltf = createBuilding(buildingConfig)
function hidden somewhere. And if this exists, then it should be doable to write this out as a GLB file. And for the first shot, a function like
tilesetJson = createFlat(listOfBuildingGlbUris);
could be enough to create something like what is shown in the last screenshot - but looking nice, like the things in your screenshots :slightly_smiling_face:

This is really interesting — thank you for taking the time to explain it.

The idea of treating the procedural generator as the source for both the interactive Cesium environment and reusable 3D Tiles test data makes a lot of sense to me.

And yes, there is indeed a procedural building-generation path in the project. I’m very interested to see what you think once you’ve had a chance to look through that part of the repo.

Your createBuilding(...) → GLB → createFlat(...) idea is also a very useful way for me to think about the next step.

No rush at all — I’ll be looking forward to your thoughts when you get some time next week. :slightly_smiling_face: