feat(@projects): ✨ add wasm grid utility hook
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
0e92eec0b4
commit
b5a9a218b1
6 changed files with 136 additions and 3 deletions
|
|
@ -23,6 +23,7 @@
|
|||
"@types/styled-components": "^5.1.34",
|
||||
"@vitejs/plugin-react": "^4.4.1",
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "^6.3.3"
|
||||
"vite": "^6.3.3",
|
||||
"vite-plugin-wasm": "^3.6.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
31
.project/designs/app/src/utils/wasm/useWasmGrid.ts
Normal file
31
.project/designs/app/src/utils/wasm/useWasmGrid.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { useState, useEffect, useRef } from "react";
|
||||
import type { WasmGrid } from "../../../../../../.local/build/wasm/magic_civ_physics";
|
||||
|
||||
type GridState =
|
||||
| { status: "idle" }
|
||||
| { status: "loading" }
|
||||
| { status: "ready"; grid: WasmGrid }
|
||||
| { status: "error"; message: string };
|
||||
|
||||
export function useWasmGrid(seed: number, mapSize: string = "tiny"): GridState {
|
||||
const [state, setState] = useState<GridState>({ status: "idle" });
|
||||
const genRef = useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
const gen = ++genRef.current;
|
||||
setState({ status: "loading" });
|
||||
|
||||
import("../../../../../../.local/build/wasm/magic_civ_physics")
|
||||
.then(({ WasmGrid }) => {
|
||||
if (gen !== genRef.current) return;
|
||||
const grid = WasmGrid.generateForLab(BigInt(seed), mapSize);
|
||||
setState({ status: "ready", grid });
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
if (gen !== genRef.current) return;
|
||||
setState({ status: "error", message: String(err) });
|
||||
});
|
||||
}, [seed, mapSize]);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
import path from "path";
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import wasm from "vite-plugin-wasm";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
plugins: [wasm(), react()],
|
||||
build: { target: "esnext" },
|
||||
resolve: {
|
||||
alias: {
|
||||
"@game-data": path.resolve(__dirname, "../../../public/games/age-of-dwarves/data"),
|
||||
|
|
@ -26,6 +28,7 @@ export default defineConfig({
|
|||
path.resolve(__dirname, "../../../public"),
|
||||
path.resolve(__dirname, "../../../.local/audio-alternatives"),
|
||||
path.resolve(__dirname, "../../../.local/audio-staging"),
|
||||
path.resolve(__dirname, "../../../.local/build/wasm"),
|
||||
path.resolve(__dirname, "../../reports"),
|
||||
],
|
||||
},
|
||||
|
|
|
|||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
|
|
@ -50,6 +50,9 @@ importers:
|
|||
vite:
|
||||
specifier: ^6.3.3
|
||||
version: 6.4.2(@types/node@25.6.0)(tsx@4.21.0)
|
||||
vite-plugin-wasm:
|
||||
specifier: ^3.6.0
|
||||
version: 3.6.0(vite@6.4.2(@types/node@25.6.0)(tsx@4.21.0))
|
||||
|
||||
public/games/age-of-dwarves/guide:
|
||||
dependencies:
|
||||
|
|
|
|||
62
public/games/age-of-dwarves/data/world_shapes/manifest.json
Normal file
62
public/games/age-of-dwarves/data/world_shapes/manifest.json
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
{
|
||||
"schema_version": "1",
|
||||
"default": "earthlike",
|
||||
"earthlike": {
|
||||
"id": "earthlike",
|
||||
"name": "Earthlike",
|
||||
"description": "Familiar continents, moderate climate, balanced rainfall.",
|
||||
"axes": {
|
||||
"landmass": "continents",
|
||||
"climate": "temperate",
|
||||
"moisture": "balanced",
|
||||
"age": "mature",
|
||||
"sea_level": "standard"
|
||||
},
|
||||
"param_overrides": {
|
||||
"plate_count": 10,
|
||||
"convergent_bias": 0.40,
|
||||
"divergent_bias": -0.25,
|
||||
"sea_level": 0.28,
|
||||
"ocean_percentage": { "target": 0.40 },
|
||||
"temp_offset": 0.0,
|
||||
"latitude_gradient": 0.7,
|
||||
"base_precip_offset": 0.0,
|
||||
"windward_boost": 1.5,
|
||||
"leeward_factor": 0.4,
|
||||
"erosion_iterations": 5,
|
||||
"seasonality_scale": 0.8,
|
||||
"rain_shadow_factor": 1.0
|
||||
},
|
||||
"thumbnail": "world_shapes/previews/earthlike.png",
|
||||
"is_default": true
|
||||
},
|
||||
"axes": {
|
||||
"landmass": ["pangaea", "continents", "archipelago", "islands", "shattered"],
|
||||
"climate": ["cold", "temperate", "hot", "extreme"],
|
||||
"moisture": ["arid", "dry", "balanced", "wet", "lush"],
|
||||
"age": ["young", "mature", "ancient"],
|
||||
"sea_level": ["low", "standard", "high"]
|
||||
},
|
||||
"presets": [
|
||||
"landmass/pangaea.json",
|
||||
"landmass/continents.json",
|
||||
"landmass/archipelago.json",
|
||||
"landmass/islands.json",
|
||||
"landmass/shattered.json",
|
||||
"climate/cold.json",
|
||||
"climate/temperate.json",
|
||||
"climate/hot.json",
|
||||
"climate/extreme.json",
|
||||
"moisture/arid.json",
|
||||
"moisture/dry.json",
|
||||
"moisture/balanced.json",
|
||||
"moisture/wet.json",
|
||||
"moisture/lush.json",
|
||||
"age/young.json",
|
||||
"age/mature.json",
|
||||
"age/ancient.json",
|
||||
"sea_level/low.json",
|
||||
"sea_level/standard.json",
|
||||
"sea_level/high.json"
|
||||
]
|
||||
}
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
//! WASM API surface — exposes Rust simulation to the web guide via wasm-bindgen.
|
||||
//! All public functions match the signatures specified in Task #2.
|
||||
//! See: public/games/age-of-dwarves/docs/terrain/WORLDGEN_PIPELINE.md
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use mc_core::grid::{GridState, biome_registry::{has_tag, BiomeTag}};
|
||||
use mc_climate::{ClimatePhysics, EcologyPhysics, step_atmospheric_chemistry};
|
||||
use mc_mapgen::MapGenerator;
|
||||
use mc_mapgen::{MapGenerator, seed::{derive as derive_seed, SeedDomain}};
|
||||
|
||||
/// WASM-exposed grid handle wrapping GridState.
|
||||
#[wasm_bindgen]
|
||||
|
|
@ -36,6 +37,19 @@ impl WasmGrid {
|
|||
Ok(Self { inner })
|
||||
}
|
||||
|
||||
/// Run the full worldgen pipeline (tectonics → climate → erosion → hydrology)
|
||||
/// and return a populated WasmGrid ready for tile_*_json queries.
|
||||
/// `map_size` accepts "duel" | "tiny" | "small" | "standard" | "large" | "huge".
|
||||
/// Used by the design lab's per-layer playground pages (p1-53).
|
||||
/// See: public/games/age-of-dwarves/docs/terrain/WORLDGEN_PIPELINE.md
|
||||
#[wasm_bindgen(js_name = "generateForLab")]
|
||||
pub fn generate_for_lab(seed: u64, map_size: &str) -> WasmGrid {
|
||||
let gen = MapGenerator::new("{}");
|
||||
WasmGrid {
|
||||
inner: gen.generate(seed, map_size),
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn width(&self) -> i32 {
|
||||
self.inner.width
|
||||
|
|
@ -329,6 +343,25 @@ impl WasmEcologyPhysics {
|
|||
}
|
||||
}
|
||||
|
||||
/// Derive a deterministic sub-seed for the given domain from a map seed.
|
||||
/// `domain` matches SeedDomain discriminants: 0=Tectonics, 1=Erosion,
|
||||
/// 2=Hydrology, 3=Climate, 4=FloraSelect, 5=FaunaSelect.
|
||||
/// Used by the RNG playground page (p1-53).
|
||||
/// See: public/games/age-of-dwarves/docs/terrain/WORLDGEN_PIPELINE.md
|
||||
#[wasm_bindgen(js_name = "seedDerive")]
|
||||
pub fn wasm_seed_derive(map_seed: u64, domain: u8) -> u64 {
|
||||
let d = match domain {
|
||||
0 => SeedDomain::Tectonics,
|
||||
1 => SeedDomain::Erosion,
|
||||
2 => SeedDomain::Hydrology,
|
||||
3 => SeedDomain::Climate,
|
||||
4 => SeedDomain::FloraSelect,
|
||||
5 => SeedDomain::FaunaSelect,
|
||||
_ => SeedDomain::Tectonics,
|
||||
};
|
||||
derive_seed(map_seed, d)
|
||||
}
|
||||
|
||||
/// WASM-exposed atmospheric chemistry step.
|
||||
#[wasm_bindgen(js_name = "stepAtmosphericChemistry")]
|
||||
pub fn wasm_step_atmospheric_chemistry(grid: &mut WasmGrid, spec_json: &str) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue