@plasius/gpu-world-generator 0.0.11 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -81,6 +81,30 @@ console.log(bake.jobs.find((job) => job.key === "assetSerialize"));
81
81
  debug allocation tags for integration with `@plasius/gpu-performance` and
82
82
  `@plasius/gpu-debug`.
83
83
 
84
+ ## Render Representation Plans
85
+
86
+ `@plasius/gpu-world-generator` now also publishes explicit chunk
87
+ representation-tier plans so renderer and worker packages can coordinate near,
88
+ mid, far, and horizon outputs without guessing from distance alone.
89
+
90
+ ```js
91
+ import { createWorldGeneratorRepresentationPlan } from "@plasius/gpu-world-generator";
92
+
93
+ const plan = createWorldGeneratorRepresentationPlan({
94
+ chunkId: "hex-12-9",
95
+ profile: "streaming",
96
+ gameplayImportance: "critical",
97
+ });
98
+
99
+ console.log(plan.bands);
100
+ console.log(plan.representations.find((entry) => entry.output === "rtProxy"));
101
+ ```
102
+
103
+ Each plan exposes raster-facing and RT-facing outputs separately, plus refresh
104
+ cadence, shadow relevance, chunk-identity preservation, and scheduling metadata
105
+ that downstream renderer and worker packages can prioritize by band and
106
+ importance.
107
+
84
108
  ## Demo
85
109
  The WebGPU mixed-forest demo lives in `demo/`. Run it with:
86
110
 
package/dist/index.cjs CHANGED
@@ -57,6 +57,7 @@ __export(index_exports, {
57
57
  createFractalPrepassRunner: () => createFractalPrepassRunner,
58
58
  createMeshBuilder: () => createMeshBuilder,
59
59
  createPerfMonitor: () => createPerfMonitor,
60
+ createWorldGeneratorRepresentationPlan: () => createWorldGeneratorRepresentationPlan,
60
61
  defaultFieldParams: () => defaultFieldParams,
61
62
  defaultFractalMandelSettings: () => defaultFractalMandelSettings,
62
63
  defaultWorldGeneratorWorkerProfile: () => defaultWorldGeneratorWorkerProfile,
@@ -94,6 +95,8 @@ __export(index_exports, {
94
95
  unpackTerrain: () => unpackTerrain,
95
96
  validateTileAssetPayload: () => validateTileAssetPayload,
96
97
  worldGeneratorDebugOwner: () => worldGeneratorDebugOwner,
98
+ worldGeneratorRepresentationBands: () => worldGeneratorRepresentationBands,
99
+ worldGeneratorRepresentationOutputs: () => worldGeneratorRepresentationOutputs,
97
100
  worldGeneratorWorkerManifests: () => worldGeneratorWorkerManifests,
98
101
  worldGeneratorWorkerProfileNames: () => worldGeneratorWorkerProfileNames,
99
102
  worldGeneratorWorkerProfiles: () => worldGeneratorWorkerProfiles,
@@ -1890,6 +1893,64 @@ function createMeshBuilder(sizeOrOptions = 1) {
1890
1893
  var worldGeneratorDebugOwner = "world-generator";
1891
1894
  var worldGeneratorWorkerQueueClass = "voxel";
1892
1895
  var defaultWorldGeneratorWorkerProfile = "streaming";
1896
+ var worldGeneratorRepresentationBands = Object.freeze([
1897
+ "near",
1898
+ "mid",
1899
+ "far",
1900
+ "horizon"
1901
+ ]);
1902
+ var worldGeneratorRepresentationOutputs = Object.freeze([
1903
+ "liveGeometry",
1904
+ "simplifiedGeometry",
1905
+ "rtProxy",
1906
+ "mergedProxy",
1907
+ "horizonShell"
1908
+ ]);
1909
+ var worldGeneratorRepresentationBandPriorityHints = Object.freeze({
1910
+ near: 400,
1911
+ mid: 300,
1912
+ far: 200,
1913
+ horizon: 100
1914
+ });
1915
+ function assertWorldGeneratorIdentifier(name, value) {
1916
+ if (typeof value !== "string" || value.trim().length === 0) {
1917
+ throw new Error(`${name} must be a non-empty string.`);
1918
+ }
1919
+ return value.trim();
1920
+ }
1921
+ function normalizeWorldGeneratorImportance(name, value) {
1922
+ if (value === "medium" || value === "high" || value === "critical") {
1923
+ return value;
1924
+ }
1925
+ throw new Error(`${name} must be one of: medium, high, critical.`);
1926
+ }
1927
+ function buildWorldGeneratorRepresentationDescriptor(options) {
1928
+ return Object.freeze({
1929
+ id: `${options.chunkId}.${options.band}.${options.output}`,
1930
+ chunkId: options.chunkId,
1931
+ profile: options.profile,
1932
+ band: options.band,
1933
+ output: options.output,
1934
+ rasterMode: options.rasterMode,
1935
+ rtParticipation: options.rtParticipation,
1936
+ shadowRelevance: options.shadowRelevance,
1937
+ refreshCadence: Object.freeze({
1938
+ kind: options.refreshCadence.kind,
1939
+ divisor: options.refreshCadence.divisor
1940
+ }),
1941
+ preservesChunkIdentity: options.preservesChunkIdentity,
1942
+ sourceChunkIds: Object.freeze([options.chunkId]),
1943
+ sourceJobKeys: Object.freeze([...options.sourceJobKeys]),
1944
+ suggestedAllocationIds: Object.freeze([...options.suggestedAllocationIds]),
1945
+ scheduling: Object.freeze({
1946
+ owner: "renderer",
1947
+ queueClass: worldGeneratorWorkerQueueClass,
1948
+ priorityHint: worldGeneratorRepresentationBandPriorityHints[options.band],
1949
+ gameplayImportance: options.gameplayImportance,
1950
+ representationBand: options.band
1951
+ })
1952
+ });
1953
+ }
1893
1954
  function buildBudgetLevels(jobType, queueClass, levels) {
1894
1955
  return Object.freeze(
1895
1956
  levels.map(
@@ -2470,6 +2531,108 @@ function getWorldGeneratorWorkerManifest(name = defaultWorldGeneratorWorkerProfi
2470
2531
  }
2471
2532
  return manifest;
2472
2533
  }
2534
+ function createWorldGeneratorRepresentationPlan(options) {
2535
+ const profile = options.profile ?? defaultWorldGeneratorWorkerProfile;
2536
+ const spec = worldGeneratorWorkerProfileSpecs[profile];
2537
+ if (!spec) {
2538
+ const available = worldGeneratorWorkerProfileNames.join(", ");
2539
+ throw new Error(
2540
+ `Unknown world-generator worker profile "${profile}". Available: ${available}.`
2541
+ );
2542
+ }
2543
+ const chunkId = assertWorldGeneratorIdentifier("chunkId", options.chunkId);
2544
+ const gameplayImportance = normalizeWorldGeneratorImportance(
2545
+ "gameplayImportance",
2546
+ options.gameplayImportance ?? "high"
2547
+ );
2548
+ const highValueAllocations = spec.suggestedAllocationIds;
2549
+ const farFieldAllocations = spec.suggestedAllocationIds.filter(
2550
+ (allocationId) => allocationId.includes("mesh") || allocationId.includes("asset") || allocationId.includes("tile")
2551
+ );
2552
+ const bakeSourceJobKeys = profile === "bake" ? ["meshBuild", "tileBake", "assetSerialize"] : ["meshBuild", "tileBake"];
2553
+ const representations = Object.freeze([
2554
+ buildWorldGeneratorRepresentationDescriptor({
2555
+ profile,
2556
+ chunkId,
2557
+ band: "near",
2558
+ output: "liveGeometry",
2559
+ rasterMode: "full-live",
2560
+ rtParticipation: "full",
2561
+ shadowRelevance: "ray-traced-primary",
2562
+ refreshCadence: { kind: "per-frame", divisor: 1 },
2563
+ preservesChunkIdentity: true,
2564
+ sourceJobKeys: ["meshBuild"],
2565
+ gameplayImportance: gameplayImportance === "medium" ? "high" : gameplayImportance,
2566
+ suggestedAllocationIds: highValueAllocations
2567
+ }),
2568
+ buildWorldGeneratorRepresentationDescriptor({
2569
+ profile,
2570
+ chunkId,
2571
+ band: "mid",
2572
+ output: "simplifiedGeometry",
2573
+ rasterMode: "simplified-live",
2574
+ rtParticipation: "selective",
2575
+ shadowRelevance: "selective-raster",
2576
+ refreshCadence: { kind: "interval", divisor: 2 },
2577
+ preservesChunkIdentity: true,
2578
+ sourceJobKeys: ["meshBuild"],
2579
+ gameplayImportance,
2580
+ suggestedAllocationIds: highValueAllocations
2581
+ }),
2582
+ buildWorldGeneratorRepresentationDescriptor({
2583
+ profile,
2584
+ chunkId,
2585
+ band: "mid",
2586
+ output: "rtProxy",
2587
+ rasterMode: "not-rendered",
2588
+ rtParticipation: "proxy",
2589
+ shadowRelevance: "selective-raster",
2590
+ refreshCadence: { kind: "interval", divisor: 2 },
2591
+ preservesChunkIdentity: true,
2592
+ sourceJobKeys: ["meshBuild", "tileBake"],
2593
+ gameplayImportance,
2594
+ suggestedAllocationIds: highValueAllocations
2595
+ }),
2596
+ buildWorldGeneratorRepresentationDescriptor({
2597
+ profile,
2598
+ chunkId,
2599
+ band: "far",
2600
+ output: "mergedProxy",
2601
+ rasterMode: "proxy",
2602
+ rtParticipation: "proxy",
2603
+ shadowRelevance: "proxy-caster",
2604
+ refreshCadence: { kind: "interval", divisor: 8 },
2605
+ preservesChunkIdentity: true,
2606
+ sourceJobKeys: bakeSourceJobKeys,
2607
+ gameplayImportance: "medium",
2608
+ suggestedAllocationIds: farFieldAllocations.length > 0 ? farFieldAllocations : highValueAllocations
2609
+ }),
2610
+ buildWorldGeneratorRepresentationDescriptor({
2611
+ profile,
2612
+ chunkId,
2613
+ band: "horizon",
2614
+ output: "horizonShell",
2615
+ rasterMode: "horizon-shell",
2616
+ rtParticipation: "disabled",
2617
+ shadowRelevance: "baked-impression",
2618
+ refreshCadence: { kind: "interval", divisor: 60 },
2619
+ preservesChunkIdentity: true,
2620
+ sourceJobKeys: profile === "bake" ? ["tileBake", "assetSerialize"] : ["tileBake"],
2621
+ gameplayImportance: "medium",
2622
+ suggestedAllocationIds: farFieldAllocations.length > 0 ? farFieldAllocations : highValueAllocations
2623
+ })
2624
+ ]);
2625
+ return Object.freeze({
2626
+ schemaVersion: 1,
2627
+ owner: worldGeneratorDebugOwner,
2628
+ profile,
2629
+ chunkId,
2630
+ representations,
2631
+ bands: Object.freeze(
2632
+ [...new Set(representations.map((representation) => representation.band))]
2633
+ )
2634
+ });
2635
+ }
2473
2636
  // Annotate the CommonJS export names for ESM import in node:
2474
2637
  0 && (module.exports = {
2475
2638
  DEFAULT_TILE_SIZE_WORLD,
@@ -2498,6 +2661,7 @@ function getWorldGeneratorWorkerManifest(name = defaultWorldGeneratorWorkerProfi
2498
2661
  createFractalPrepassRunner,
2499
2662
  createMeshBuilder,
2500
2663
  createPerfMonitor,
2664
+ createWorldGeneratorRepresentationPlan,
2501
2665
  defaultFieldParams,
2502
2666
  defaultFractalMandelSettings,
2503
2667
  defaultWorldGeneratorWorkerProfile,
@@ -2535,6 +2699,8 @@ function getWorldGeneratorWorkerManifest(name = defaultWorldGeneratorWorkerProfi
2535
2699
  unpackTerrain,
2536
2700
  validateTileAssetPayload,
2537
2701
  worldGeneratorDebugOwner,
2702
+ worldGeneratorRepresentationBands,
2703
+ worldGeneratorRepresentationOutputs,
2538
2704
  worldGeneratorWorkerManifests,
2539
2705
  worldGeneratorWorkerProfileNames,
2540
2706
  worldGeneratorWorkerProfiles,