@holoscript/core 8.0.13 → 8.0.15
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 +20 -13
- package/bin/holo-decision.mjs +133 -0
- package/bin/holoscript.cjs +0 -0
- package/dist/{GLTFPipeline-L76YTXKA.js → GLTFPipeline-FRBZIATS.js} +7 -7
- package/dist/{GLTFPipeline-ZWJN7GI6.cjs → GLTFPipeline-MTPP444P.cjs} +11 -11
- package/dist/{HoloCompositionParser-P4Y3CXKQ.js → HoloCompositionParser-2GVQAZ2X.js} +7 -7
- package/dist/HoloCompositionParser-3NDF6BMX.cjs +45 -0
- package/dist/HoloScriptPlusParser-URSIBEAW.cjs +30 -0
- package/dist/HoloScriptPlusParser-YCV6L7GI.js +13 -0
- package/dist/{HoloScriptRuntime-YBYXJHJN.cjs → HoloScriptRuntime-CRWI6C3P.cjs} +5 -5
- package/dist/{HoloScriptRuntime-UTRLJI5L.js → HoloScriptRuntime-IAZGHPFP.js} +4 -4
- package/dist/{SceneIRCompiler-63KA3M2F.js → SceneIRCompiler-BJQMKLWL.js} +7 -7
- package/dist/{SceneIRCompiler-KWUFHZ4O.cjs → SceneIRCompiler-RTPPDQAV.cjs} +12 -12
- package/dist/{chunk-FWCHPCD4.js → chunk-22AULOAL.js} +5 -5
- package/dist/{chunk-G35CAQ7I.cjs → chunk-2DJIS7TH.cjs} +5 -5
- package/dist/{chunk-LHUDAJQT.cjs → chunk-2PVEXEOL.cjs} +5 -5
- package/dist/{chunk-WWNCM473.js → chunk-2UP2J3OK.js} +4 -4
- package/dist/{chunk-HVX7QQYK.js → chunk-3AUYBQ5I.js} +3 -3
- package/dist/{chunk-TSTFYGGX.js → chunk-3MQAOMKD.js} +3 -3
- package/dist/{chunk-FWKEY4LD.js → chunk-4AGNARX6.js} +3 -3
- package/dist/{chunk-WNYXT4TE.cjs → chunk-4CQ7ULXZ.cjs} +3 -3
- package/dist/{chunk-U3D4SYQ5.js → chunk-5LCJDX5A.js} +3 -3
- package/dist/{chunk-IK6Z2HNC.js → chunk-6OQHLNTT.js} +2 -2
- package/dist/{chunk-EI3J6LTW.cjs → chunk-6RDHWSZM.cjs} +217 -217
- package/dist/{chunk-77QI552M.js → chunk-7AY66PZP.js} +3 -3
- package/dist/{chunk-7IDJDMPU.cjs → chunk-7FYSSI3C.cjs} +27 -2
- package/dist/{chunk-BP4KTMLY.js → chunk-7HDRN5BW.js} +4 -4
- package/dist/{chunk-SQAAWO4V.cjs → chunk-7YKNV2BE.cjs} +5 -5
- package/dist/{chunk-WTH23ISI.js → chunk-AAUQTR7I.js} +4 -4
- package/dist/{chunk-OC6GV5QH.cjs → chunk-AN3ZH7M7.cjs} +38 -38
- package/dist/{chunk-YW3I2FQL.js → chunk-ANMME7XT.js} +4 -2
- package/dist/{chunk-A4OOLBZD.js → chunk-ATRAK4RC.js} +5 -5
- package/dist/{chunk-BQJ3YBF3.js → chunk-AUF7HFOO.js} +724 -647
- package/dist/{chunk-2X3IPCBK.cjs → chunk-AUMTQV64.cjs} +7 -7
- package/dist/chunk-AUU4ACJP.cjs +1605 -0
- package/dist/{chunk-QQFB4RT2.cjs → chunk-BTVHY3UB.cjs} +2 -2
- package/dist/{chunk-ZK7KX5CD.cjs → chunk-CMEINO5I.cjs} +190 -74
- package/dist/{chunk-BCP4E7MD.cjs → chunk-CRUIGXF7.cjs} +26 -10
- package/dist/{chunk-2E6PP5UE.cjs → chunk-E2SNPMBO.cjs} +11 -11
- package/dist/{chunk-2BYAUHBO.js → chunk-E4YS5SIZ.js} +90 -25
- package/dist/{chunk-KFVNCW4Q.js → chunk-EKNWUSGW.js} +3 -3
- package/dist/{chunk-JEJ7TT54.js → chunk-ETIJOUIO.js} +4 -4
- package/dist/{chunk-FRSKLX6I.js → chunk-F33KLYOS.js} +12 -9
- package/dist/{chunk-GGR7QUKK.cjs → chunk-F47FEV4X.cjs} +40 -40
- package/dist/{chunk-J3UHV5T4.cjs → chunk-FCGTI7FO.cjs} +4 -4
- package/dist/{chunk-RRQIAJLQ.cjs → chunk-FGTXAVKG.cjs} +5 -5
- package/dist/{chunk-2KKOYZYI.cjs → chunk-FPGYWNNA.cjs} +5 -5
- package/dist/{chunk-65S62L4D.cjs → chunk-FQ4MYZYU.cjs} +20 -20
- package/dist/{chunk-UGQ3QNV6.js → chunk-FT4FGTR6.js} +24 -8
- package/dist/{chunk-Q4K2GEMW.cjs → chunk-FVNV4WHQ.cjs} +20 -17
- package/dist/{chunk-SJIRCTIS.cjs → chunk-HSGJFCVJ.cjs} +2 -2
- package/dist/{chunk-B3CWTCK2.js → chunk-IA7FCSRY.js} +27 -2
- package/dist/{chunk-OIBRWLPY.cjs → chunk-ILO2KMER.cjs} +55 -4
- package/dist/{chunk-ZRPALBQB.cjs → chunk-IPBSNGAN.cjs} +92 -27
- package/dist/{chunk-FHVPN7BN.js → chunk-IX2U3RQT.js} +3 -3
- package/dist/{chunk-QEDMOGF3.cjs → chunk-IYK6LMQ7.cjs} +7 -7
- package/dist/{chunk-G6EKZHXY.js → chunk-J3VVM6GV.js} +4 -4
- package/dist/{chunk-LMB555QB.cjs → chunk-J74S4ZMF.cjs} +18 -18
- package/dist/{chunk-36NPLOI4.cjs → chunk-JERWCCEJ.cjs} +4 -2
- package/dist/{chunk-RVNXBF2M.js → chunk-JTDDLCSP.js} +4 -4
- package/dist/{chunk-VTEXJOSD.cjs → chunk-K53L47NH.cjs} +30 -30
- package/dist/{chunk-IJU6AS67.cjs → chunk-LJTM5ONX.cjs} +23 -23
- package/dist/{chunk-G6KACNMO.js → chunk-LJVVOVA6.js} +4 -4
- package/dist/{chunk-PDXX5UI4.cjs → chunk-LNJKBQ2B.cjs} +38 -38
- package/dist/{chunk-EM2OGPYE.js → chunk-M2GDE3NV.js} +3 -3
- package/dist/{chunk-CP7V3ATL.js → chunk-MSZNGI5P.js} +52 -5
- package/dist/{chunk-P7JEKJTZ.cjs → chunk-N2BOTBPG.cjs} +27 -16
- package/dist/{chunk-LB3ZZMKT.cjs → chunk-NFALJJCH.cjs} +12 -12
- package/dist/{chunk-XF63CZ7E.cjs → chunk-NRZRBK25.cjs} +6 -6
- package/dist/{chunk-GZPUA2TL.cjs → chunk-NTSLNIY7.cjs} +10 -10
- package/dist/{chunk-Y57AVOM2.cjs → chunk-NZJOAWJM.cjs} +4 -4
- package/dist/{chunk-RXQNRZ5F.js → chunk-OG7RKWWX.js} +3 -3
- package/dist/{chunk-VVAAZITA.cjs → chunk-OQVHCYY4.cjs} +5 -5
- package/dist/{chunk-PJFTTSKE.js → chunk-PFZ5WLIP.js} +4 -4
- package/dist/{chunk-PXVAPGTR.cjs → chunk-PHLNABJD.cjs} +3788 -1138
- package/dist/{chunk-SQXAZHDG.js → chunk-PLK3DLTF.js} +3 -3
- package/dist/{chunk-QBY7LRN2.js → chunk-PMACVMHL.js} +3 -3
- package/dist/{chunk-DJ5BNRIS.js → chunk-PV2OXNP5.js} +3684 -1041
- package/dist/{chunk-F3YT6GUF.cjs → chunk-Q6VW7MGX.cjs} +14 -14
- package/dist/{chunk-DUG3OQAS.js → chunk-QC3CAVFN.js} +187 -70
- package/dist/{chunk-NQN5LFN4.cjs → chunk-QKLEDRHN.cjs} +19 -19
- package/dist/{chunk-2EGGAZT3.js → chunk-QS27OYBU.js} +3 -3
- package/dist/{chunk-4376VHNJ.js → chunk-RUB7WL6C.js} +3 -3
- package/dist/{chunk-5LVFTGKH.js → chunk-TW2AH2ZS.js} +3 -3
- package/dist/{chunk-AATYYLYK.js → chunk-TZM6DKSJ.js} +18 -7
- package/dist/{chunk-ESSEF6U2.js → chunk-U227RWXB.js} +3 -3
- package/dist/{chunk-TC7JEO6R.cjs → chunk-U6CQOM5Q.cjs} +711 -52
- package/dist/{chunk-Z557DVYN.js → chunk-ULT2QAV5.js} +4 -4
- package/dist/{chunk-S4O7CFHQ.cjs → chunk-VSO6HPDZ.cjs} +7 -7
- package/dist/{chunk-ONPVM4IV.js → chunk-WQJMSSJT.js} +698 -45
- package/dist/{chunk-GILYQ5VH.cjs → chunk-WXSDBWGM.cjs} +4 -4
- package/dist/{chunk-UTUD6GJI.js → chunk-X5PMMK7H.js} +3 -3
- package/dist/{chunk-IFW5IW4L.cjs → chunk-X5ZLSPU2.cjs} +742 -657
- package/dist/{chunk-QM7FJB5W.js → chunk-X727CQ7X.js} +5 -5
- package/dist/{chunk-566ZB4LZ.cjs → chunk-XHZYS4QO.cjs} +5 -5
- package/dist/{chunk-RZ2EPXO3.cjs → chunk-XRQCTTDC.cjs} +8 -8
- package/dist/{chunk-5FYMCVBY.js → chunk-YBIHSN55.js} +4 -4
- package/dist/{chunk-FG6PYGIZ.js → chunk-Z574GVI3.js} +4 -4
- package/dist/{chunk-ZVQMKUGJ.js → chunk-Z5V3KA7L.js} +2 -2
- package/dist/chunk-ZGDEOXGU.js +1571 -0
- package/dist/{chunk-IS7NTKY5.cjs → chunk-ZHW6TDZ6.cjs} +14 -14
- package/dist/{chunk-CKV5NYAE.js → chunk-ZPHCTPR6.js} +4 -4
- package/dist/{chunk-3IUHTGDD.cjs → chunk-ZXXC2GXB.cjs} +38 -38
- package/dist/cli/holoscript-runner.cjs +169 -20
- package/dist/cli/holoscript-runner.js +163 -14
- package/dist/compiler/agent-inference.cjs +8 -8
- package/dist/compiler/agent-inference.js +4 -4
- package/dist/compiler/android-xr.cjs +7 -7
- package/dist/compiler/android-xr.js +5 -5
- package/dist/compiler/android.cjs +6 -6
- package/dist/compiler/android.js +4 -4
- package/dist/compiler/context.cjs +6 -6
- package/dist/compiler/context.js +3 -3
- package/dist/compiler/daimon-seed.cjs +9 -9
- package/dist/compiler/daimon-seed.js +4 -4
- package/dist/compiler/domain-block-utils.cjs +165 -165
- package/dist/compiler/domain-block-utils.js +4 -4
- package/dist/compiler/dtdl.cjs +7 -7
- package/dist/compiler/dtdl.js +4 -4
- package/dist/compiler/gltf-pipeline.cjs +8 -8
- package/dist/compiler/gltf-pipeline.js +1 -1
- package/dist/compiler/godot.cjs +6 -6
- package/dist/compiler/godot.js +5 -5
- package/dist/compiler/incremental.cjs +8 -8
- package/dist/compiler/incremental.js +3 -3
- package/dist/compiler/index.cjs +2275 -212
- package/dist/compiler/index.d.ts +29 -1
- package/dist/compiler/index.js +2078 -66
- package/dist/compiler/ios.cjs +6 -6
- package/dist/compiler/ios.js +4 -4
- package/dist/compiler/llm-provider-capabilities.cjs +6 -6
- package/dist/compiler/llm-provider-capabilities.js +3 -3
- package/dist/compiler/openxr.cjs +6 -6
- package/dist/compiler/openxr.js +5 -5
- package/dist/compiler/sdf.cjs +7 -7
- package/dist/compiler/sdf.js +5 -5
- package/dist/compiler/state.cjs +6 -6
- package/dist/compiler/state.js +4 -4
- package/dist/compiler/trait-composition.cjs +7 -7
- package/dist/compiler/trait-composition.js +3 -3
- package/dist/compiler/unity.cjs +6 -6
- package/dist/compiler/unity.js +5 -5
- package/dist/compiler/unreal.cjs +7 -7
- package/dist/compiler/unreal.js +5 -5
- package/dist/compiler/urdf.cjs +14 -14
- package/dist/compiler/urdf.js +5 -5
- package/dist/compiler/usd-physics.cjs +7 -7
- package/dist/compiler/usd-physics.js +4 -4
- package/dist/compiler/visionos.cjs +6 -6
- package/dist/compiler/visionos.js +5 -5
- package/dist/compiler/vrchat.cjs +7 -7
- package/dist/compiler/vrchat.js +5 -5
- package/dist/compiler/wasm.cjs +10 -10
- package/dist/compiler/wasm.js +5 -5
- package/dist/compiler/webgpu.cjs +6 -6
- package/dist/compiler/webgpu.js +5 -5
- package/dist/constants.cjs +99 -99
- package/dist/constants.js +3 -3
- package/dist/debugger.cjs +5 -5
- package/dist/debugger.js +3 -3
- package/dist/{dist-GRMOP2UL.cjs → dist-YGATNURH.cjs} +705 -9
- package/dist/{dist-ZBUKU2JG.js → dist-ZEZXRCBG.js} +701 -10
- package/dist/entries/scripting.cjs +8 -8
- package/dist/entries/scripting.js +4 -4
- package/dist/evolution/index.cjs +20 -20
- package/dist/evolution/index.js +8 -8
- package/dist/index.cjs +1099 -826
- package/dist/index.d.ts +78 -5
- package/dist/index.js +265 -120
- package/dist/parser/HoloCompositionTypes.d.ts +1 -1
- package/dist/parser.cjs +21 -21
- package/dist/parser.js +7 -7
- package/dist/reconstruction/index.cjs +127 -38
- package/dist/reconstruction/index.d.ts +159 -0
- package/dist/reconstruction/index.js +11 -2
- package/dist/runtime.cjs +9 -9
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.js +3 -3
- package/dist/traitDocs/traitDocs.cjs +8 -8
- package/dist/traitDocs/traitDocs.js +2 -2
- package/dist/traits/botanical-lotus.d.ts +61 -0
- package/dist/traits/index.cjs +761 -673
- package/dist/traits/index.d.ts +65 -0
- package/dist/traits/index.js +102 -27
- package/dist/types/HoloScriptPlus.d.ts +1 -1
- package/package.json +71 -65
- package/dist/HoloCompositionParser-6GW2BZID.cjs +0 -45
- package/dist/HoloScriptPlusParser-HQV6IJAH.js +0 -13
- package/dist/HoloScriptPlusParser-RFNHRMPE.cjs +0 -30
- package/dist/chunk-DVHZD5HV.cjs +0 -639
- package/dist/chunk-G72754QB.js +0 -625
|
@@ -1,10 +1,202 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkIYK6LMQ7_cjs = require('./chunk-IYK6LMQ7.cjs');
|
|
4
|
+
var chunkCMEINO5I_cjs = require('./chunk-CMEINO5I.cjs');
|
|
5
5
|
var chunkZHPMP447_cjs = require('./chunk-ZHPMP447.cjs');
|
|
6
6
|
var ans = require('@holoscript/core-types/ans');
|
|
7
7
|
|
|
8
|
+
// src/compiler/render-modules/geometry-registry.ts
|
|
9
|
+
function resolveGeometry(meshType) {
|
|
10
|
+
const key = String(meshType ?? "").trim().toLowerCase();
|
|
11
|
+
const kind = ALIAS[key] ?? "box";
|
|
12
|
+
return PRIMITIVE[kind];
|
|
13
|
+
}
|
|
14
|
+
var PRIMITIVE, ALIAS;
|
|
15
|
+
var init_geometry_registry = chunkZHPMP447_cjs.__esm({
|
|
16
|
+
"src/compiler/render-modules/geometry-registry.ts"() {
|
|
17
|
+
PRIMITIVE = {
|
|
18
|
+
box: { kind: "box", webgpuVertexFn: "generateCubeVertices(1.0)" },
|
|
19
|
+
sphere: { kind: "sphere", webgpuVertexFn: "generateSphereVertices(0.5, 16, 16)" },
|
|
20
|
+
plane: { kind: "plane", webgpuVertexFn: "generatePlaneVertices(1.0, 1.0)" },
|
|
21
|
+
cylinder: { kind: "cylinder", webgpuVertexFn: "generateCylinderVertices(0.5, 1.0, 16)" },
|
|
22
|
+
cone: { kind: "cone", webgpuVertexFn: "generateConeVertices(0.5, 1.0, 16)" },
|
|
23
|
+
torus: { kind: "torus", webgpuVertexFn: "generateTorusVertices(0.5, 0.15, 16, 32)" }
|
|
24
|
+
};
|
|
25
|
+
ALIAS = {
|
|
26
|
+
// box family (panels, rounded boxes read as boxes)
|
|
27
|
+
cube: "box",
|
|
28
|
+
box: "box",
|
|
29
|
+
rounded_panel: "box",
|
|
30
|
+
rounded_box: "box",
|
|
31
|
+
panel: "box",
|
|
32
|
+
card: "box",
|
|
33
|
+
// sphere family
|
|
34
|
+
sphere: "sphere",
|
|
35
|
+
orb: "sphere",
|
|
36
|
+
ball: "sphere",
|
|
37
|
+
bubble: "sphere",
|
|
38
|
+
procedural_upper_body: "sphere",
|
|
39
|
+
avatar: "sphere",
|
|
40
|
+
// plane / surface family
|
|
41
|
+
plane: "plane",
|
|
42
|
+
quad: "plane",
|
|
43
|
+
surface: "plane",
|
|
44
|
+
full_screen_fluid_plane: "plane",
|
|
45
|
+
fluid_plane: "plane",
|
|
46
|
+
water: "plane",
|
|
47
|
+
// cylinder family
|
|
48
|
+
cylinder: "cylinder",
|
|
49
|
+
tube: "cylinder",
|
|
50
|
+
pillar: "cylinder",
|
|
51
|
+
capsule: "cylinder",
|
|
52
|
+
// cone family
|
|
53
|
+
cone: "cone",
|
|
54
|
+
pyramid: "cone",
|
|
55
|
+
spike: "cone",
|
|
56
|
+
crystal: "cone",
|
|
57
|
+
diamond: "cone",
|
|
58
|
+
gem: "cone",
|
|
59
|
+
// torus family
|
|
60
|
+
torus: "torus",
|
|
61
|
+
ring: "torus",
|
|
62
|
+
donut: "torus"
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// src/compiler/render-modules/skybox-registry.ts
|
|
68
|
+
function hexToRgb(hex) {
|
|
69
|
+
const h = hex.replace("#", "");
|
|
70
|
+
return [
|
|
71
|
+
Number((parseInt(h.substring(0, 2), 16) / 255).toFixed(4)),
|
|
72
|
+
Number((parseInt(h.substring(2, 4), 16) / 255).toFixed(4)),
|
|
73
|
+
Number((parseInt(h.substring(4, 6), 16) / 255).toFixed(4))
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
function resolveSkyboxColor(name) {
|
|
77
|
+
const key = String(name ?? "").trim().toLowerCase();
|
|
78
|
+
const hex = SKYBOX_HEX[key];
|
|
79
|
+
return hex ? hexToRgb(hex) : FALLBACK;
|
|
80
|
+
}
|
|
81
|
+
var SKYBOX_HEX, FALLBACK;
|
|
82
|
+
var init_skybox_registry = chunkZHPMP447_cjs.__esm({
|
|
83
|
+
"src/compiler/render-modules/skybox-registry.ts"() {
|
|
84
|
+
SKYBOX_HEX = {
|
|
85
|
+
// ── deep / space / void ─────────────────────────────────────────────
|
|
86
|
+
deep_machine_ocean: "#052430",
|
|
87
|
+
deep_space: "#05060d",
|
|
88
|
+
space: "#05060d",
|
|
89
|
+
nebula: "#0b0618",
|
|
90
|
+
night_sky: "#0b1020",
|
|
91
|
+
night_overcast: "#14161c",
|
|
92
|
+
void: "#050507",
|
|
93
|
+
midnight: "#070a12",
|
|
94
|
+
// ── water / underwater ──────────────────────────────────────────────
|
|
95
|
+
ocean: "#063240",
|
|
96
|
+
underwater: "#062a3a",
|
|
97
|
+
// ── studio / neutral (light backdrops kept light, just not pure white) ─
|
|
98
|
+
studio: "#c4c8cf",
|
|
99
|
+
neutral_studio: "#c4c8cf",
|
|
100
|
+
studio_soft: "#d2d5da",
|
|
101
|
+
hdr_studio: "#c9ccd2",
|
|
102
|
+
gallery: "#20222a",
|
|
103
|
+
indoor_museum: "#1c1e24",
|
|
104
|
+
interior_dark: "#14151a",
|
|
105
|
+
classroom: "#d2cfc6",
|
|
106
|
+
warehouse: "#3a3c40",
|
|
107
|
+
asset_pipeline_warehouse: "#3a3c40",
|
|
108
|
+
// ── sky / daylight ──────────────────────────────────────────────────
|
|
109
|
+
procedural_sky: "#8fbce6",
|
|
110
|
+
clear_sky: "#8fbce6",
|
|
111
|
+
daylight: "#9ec6ea",
|
|
112
|
+
fantasy_sky: "#2a3a6a",
|
|
113
|
+
sunset: "#46283a",
|
|
114
|
+
dusk: "#2e2740",
|
|
115
|
+
desert_dawn: "#caa079",
|
|
116
|
+
// ── tech / abstract ─────────────────────────────────────────────────
|
|
117
|
+
digital_grid: "#0a0f1e",
|
|
118
|
+
gradient: "#1a2030",
|
|
119
|
+
// ── environments / scenes ───────────────────────────────────────────
|
|
120
|
+
industrial: "#2a2d30",
|
|
121
|
+
urban_courtyard: "#3a3d42",
|
|
122
|
+
ancient_ruins: "#3a3428",
|
|
123
|
+
concert_venue: "#0e0a14",
|
|
124
|
+
lounge: "#1a1220",
|
|
125
|
+
farm: "#7fae5a",
|
|
126
|
+
vault_archive: "#1a140a",
|
|
127
|
+
passthrough: "#0c0c0e",
|
|
128
|
+
default: "#0a0e14"
|
|
129
|
+
};
|
|
130
|
+
FALLBACK = hexToRgb("#0a0e14");
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// src/compiler/render-modules/geometry-purpose.ts
|
|
135
|
+
function coerceBool(v) {
|
|
136
|
+
if (v === true || v === "true") return true;
|
|
137
|
+
if (v === false || v === "false") return false;
|
|
138
|
+
return void 0;
|
|
139
|
+
}
|
|
140
|
+
function resolveGeometryRole(opts) {
|
|
141
|
+
let purpose = "render";
|
|
142
|
+
const p = String(opts.purpose ?? "").trim().toLowerCase();
|
|
143
|
+
if (p && ALL_PURPOSES.has(p)) {
|
|
144
|
+
purpose = p;
|
|
145
|
+
} else {
|
|
146
|
+
for (const t of opts.traitNames ?? []) {
|
|
147
|
+
const mapped = PURPOSE_TRAITS[String(t).trim().toLowerCase()];
|
|
148
|
+
if (mapped) {
|
|
149
|
+
purpose = mapped;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const explicit = coerceBool(opts.visible);
|
|
155
|
+
const visible = explicit !== void 0 ? explicit : purpose === "render";
|
|
156
|
+
return { purpose, visible };
|
|
157
|
+
}
|
|
158
|
+
var INVISIBLE_PURPOSES, PURPOSE_TRAITS, ALL_PURPOSES;
|
|
159
|
+
var init_geometry_purpose = chunkZHPMP447_cjs.__esm({
|
|
160
|
+
"src/compiler/render-modules/geometry-purpose.ts"() {
|
|
161
|
+
INVISIBLE_PURPOSES = /* @__PURE__ */ new Set([
|
|
162
|
+
"collision",
|
|
163
|
+
"trigger",
|
|
164
|
+
"vfx_emitter",
|
|
165
|
+
"sim_domain",
|
|
166
|
+
"navmesh",
|
|
167
|
+
"occluder",
|
|
168
|
+
"audio_zone"
|
|
169
|
+
]);
|
|
170
|
+
PURPOSE_TRAITS = {
|
|
171
|
+
collider: "collision",
|
|
172
|
+
collision: "collision",
|
|
173
|
+
physics_collider: "collision",
|
|
174
|
+
rigidbody_collider: "collision",
|
|
175
|
+
trigger: "trigger",
|
|
176
|
+
trigger_volume: "trigger",
|
|
177
|
+
interaction_volume: "trigger",
|
|
178
|
+
emitter: "vfx_emitter",
|
|
179
|
+
vfx_emitter: "vfx_emitter",
|
|
180
|
+
particle_emitter: "vfx_emitter",
|
|
181
|
+
spawn_volume: "vfx_emitter",
|
|
182
|
+
sim_domain: "sim_domain",
|
|
183
|
+
sim_volume: "sim_domain",
|
|
184
|
+
fluid_domain: "sim_domain",
|
|
185
|
+
field_region: "sim_domain",
|
|
186
|
+
navmesh: "navmesh",
|
|
187
|
+
nav_mesh: "navmesh",
|
|
188
|
+
occluder: "occluder",
|
|
189
|
+
occlusion: "occluder",
|
|
190
|
+
audio_zone: "audio_zone",
|
|
191
|
+
audio_volume: "audio_zone"
|
|
192
|
+
};
|
|
193
|
+
ALL_PURPOSES = /* @__PURE__ */ new Set([
|
|
194
|
+
"render",
|
|
195
|
+
...Array.from(INVISIBLE_PURPOSES)
|
|
196
|
+
]);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
8
200
|
// src/compiler/WebGPUCompiler.ts
|
|
9
201
|
var WebGPUCompiler_exports = {};
|
|
10
202
|
chunkZHPMP447_cjs.__export(WebGPUCompiler_exports, {
|
|
@@ -19,15 +211,35 @@ function findGpuParticleTrait(traits) {
|
|
|
19
211
|
exports.WebGPUCompiler = void 0;
|
|
20
212
|
var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
21
213
|
"src/compiler/WebGPUCompiler.ts"() {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
214
|
+
chunkCMEINO5I_cjs.init_CompilerBase();
|
|
215
|
+
init_geometry_registry();
|
|
216
|
+
init_skybox_registry();
|
|
217
|
+
init_geometry_purpose();
|
|
218
|
+
chunkIYK6LMQ7_cjs.init_DomainBlockCompilerMixin();
|
|
219
|
+
exports.WebGPUCompiler = class extends chunkCMEINO5I_cjs.CompilerBase {
|
|
25
220
|
constructor(options = {}) {
|
|
26
221
|
super();
|
|
27
222
|
this.compilerName = "WebGPUCompiler";
|
|
28
223
|
this.lines = [];
|
|
29
224
|
this.indentLevel = 0;
|
|
30
225
|
this.objectIndex = 0;
|
|
226
|
+
// Resolved once per compile() so findObjProp can fall back to template defaults.
|
|
227
|
+
this.templatesByName = /* @__PURE__ */ new Map();
|
|
228
|
+
// True when any object is a water/fluid surface — gates the animated water
|
|
229
|
+
// pipeline, its WGSL, the tessellated-plane helper, and the shared time uniform.
|
|
230
|
+
this.hasWater = false;
|
|
231
|
+
/** World facts collected at emission time, serialized as the HoloScene Manifest. */
|
|
232
|
+
this.manifestObjects = [];
|
|
233
|
+
/** Accumulated spatial-group translation for the objects currently being
|
|
234
|
+
* emitted — manifest positions are WORLD-space (render applies the same
|
|
235
|
+
* offsets via GroupXform; local coords would be a false fact for grouped
|
|
236
|
+
* scenes). */
|
|
237
|
+
this.manifestGroupOffset = [0, 0, 0];
|
|
238
|
+
// The named channels the water surface's clarity/ripple are bound to (from the
|
|
239
|
+
// .holo's water_clarity_binding / ripple_intensity_binding props). Host state
|
|
240
|
+
// (e.g. Brittney receipts) drives these BY NAME via hsSetChannel.
|
|
241
|
+
this.waterClarityChannel = "environmentWaterClarity";
|
|
242
|
+
this.waterRippleChannel = "environmentRippleIntensity";
|
|
31
243
|
this.options = {
|
|
32
244
|
entryPoint: options.entryPoint || "main",
|
|
33
245
|
enableCompute: options.enableCompute ?? true,
|
|
@@ -44,6 +256,13 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
44
256
|
this.lines = [];
|
|
45
257
|
this.indentLevel = 0;
|
|
46
258
|
this.objectIndex = 0;
|
|
259
|
+
this.manifestObjects = [];
|
|
260
|
+
this.manifestGroupOffset = [0, 0, 0];
|
|
261
|
+
this.templatesByName = new Map(
|
|
262
|
+
(composition.templates ?? []).map((t) => [t.name, t])
|
|
263
|
+
);
|
|
264
|
+
this.hasWater = this.compositionHasWater(composition);
|
|
265
|
+
if (this.hasWater) this.resolveWaterChannels(composition);
|
|
47
266
|
this.emit("// Auto-generated by HoloScript WebGPUCompiler");
|
|
48
267
|
this.emit(
|
|
49
268
|
`// Source: composition "${this.escapeStringValue(composition.name, "TypeScript")}"`
|
|
@@ -57,7 +276,27 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
57
276
|
this.emitGeometryHelpers();
|
|
58
277
|
this.emitShaderSources();
|
|
59
278
|
this.emitEnvironment(composition.environment ?? { type: "Environment", properties: [] });
|
|
60
|
-
this.emitCamera(composition
|
|
279
|
+
this.emitCamera(composition);
|
|
280
|
+
this.emitSceneLights(composition);
|
|
281
|
+
if (this.hasWater) {
|
|
282
|
+
const cc = JSON.stringify(this.waterClarityChannel);
|
|
283
|
+
const rc = JSON.stringify(this.waterRippleChannel);
|
|
284
|
+
this.emit(`const hsChannels = { [${cc}]: 1.0, [${rc}]: 0.0 };`);
|
|
285
|
+
this.emit("let hsWaterAmp = 1.0;");
|
|
286
|
+
this.emit(
|
|
287
|
+
"function hsSetChannel(name, value) { if (name in hsChannels) hsChannels[name] = Math.max(0, Math.min(1, value)); return hsChannels[name]; }"
|
|
288
|
+
);
|
|
289
|
+
this.emit(
|
|
290
|
+
`function hsSetWater(o) { if (o) { if (o.clarity !== undefined) hsSetChannel(${cc}, o.clarity); if (o.ripple !== undefined) hsSetChannel(${rc}, o.ripple); if (o.amplitude !== undefined) hsWaterAmp = Math.max(0, o.amplitude); } return { clarity: hsChannels[${cc}], ripple: hsChannels[${rc}], amplitude: hsWaterAmp }; }`
|
|
291
|
+
);
|
|
292
|
+
this.emit(
|
|
293
|
+
'if (typeof window !== "undefined") { window.hsSetChannel = hsSetChannel; window.hsSetWater = hsSetWater; }'
|
|
294
|
+
);
|
|
295
|
+
this.emit(
|
|
296
|
+
`const waterFrameU = createBuffer(device, new Float32Array([0,0,0,0, hsChannels[${cc}], hsChannels[${rc}], hsWaterAmp, 0]), GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST);`
|
|
297
|
+
);
|
|
298
|
+
this.emit("");
|
|
299
|
+
}
|
|
61
300
|
this.emit("const holoGraphObjects = [];");
|
|
62
301
|
this.emit("");
|
|
63
302
|
if (composition.objects) {
|
|
@@ -66,9 +305,7 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
66
305
|
if (composition.spatialGroups) {
|
|
67
306
|
for (const group of composition.spatialGroups) this.emitGroup(group);
|
|
68
307
|
}
|
|
69
|
-
|
|
70
|
-
for (const light of composition.lights) this.emitLight(light);
|
|
71
|
-
}
|
|
308
|
+
this.emitSceneManifest(composition);
|
|
72
309
|
if (this.options.enableCompute) this.emitComputeShaders(composition);
|
|
73
310
|
this.emitWebGPUDomainBlocks(composition);
|
|
74
311
|
this.emitViewportRuntime();
|
|
@@ -88,7 +325,7 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
88
325
|
this.emitMaterialDomainBlock(block, prefix);
|
|
89
326
|
break;
|
|
90
327
|
case "dataviz":
|
|
91
|
-
this.emitMultiline(
|
|
328
|
+
this.emitMultiline(chunkIYK6LMQ7_cjs.datavizToWebGPU(chunkIYK6LMQ7_cjs.compileDataVizBlock(block), prefix));
|
|
92
329
|
break;
|
|
93
330
|
case "vfx":
|
|
94
331
|
this.emitParticleDomainBlock(block, prefix);
|
|
@@ -107,8 +344,8 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
107
344
|
}
|
|
108
345
|
}
|
|
109
346
|
emitMaterialDomainBlock(block, prefix) {
|
|
110
|
-
const mat =
|
|
111
|
-
this.emitMultiline(
|
|
347
|
+
const mat = chunkIYK6LMQ7_cjs.compileMaterialBlock(block);
|
|
348
|
+
this.emitMultiline(chunkIYK6LMQ7_cjs.materialToWebGPU(mat, prefix));
|
|
112
349
|
if (Object.keys(mat.textureMaps).length > 0) {
|
|
113
350
|
this.emit(`const ${prefix}TextureMaps = ${this.json(mat.textureMaps)};`);
|
|
114
351
|
this.emit(`const ${prefix}Textures = await loadMaterialTextureSet(${prefix}TextureMaps);`);
|
|
@@ -118,7 +355,7 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
118
355
|
}
|
|
119
356
|
}
|
|
120
357
|
emitParticleDomainBlock(block, prefix) {
|
|
121
|
-
const ps =
|
|
358
|
+
const ps = chunkIYK6LMQ7_cjs.compileParticleBlock(block);
|
|
122
359
|
const count = Math.max(
|
|
123
360
|
1,
|
|
124
361
|
Math.floor(
|
|
@@ -161,7 +398,7 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
161
398
|
this.emit("});");
|
|
162
399
|
}
|
|
163
400
|
emitPostFXDomainBlock(block, prefix) {
|
|
164
|
-
const pp =
|
|
401
|
+
const pp = chunkIYK6LMQ7_cjs.compilePostProcessingBlock(block);
|
|
165
402
|
this.emit(`// Domain post-processing: ${this.escapeStringValue(pp.name ?? block.name, "TypeScript")}`);
|
|
166
403
|
this.emit(`const ${prefix}PostFXConfig = ${this.json({
|
|
167
404
|
name: pp.name,
|
|
@@ -182,7 +419,7 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
182
419
|
this.emit("});");
|
|
183
420
|
}
|
|
184
421
|
emitProceduralDomainBlock(block, prefix) {
|
|
185
|
-
const proc =
|
|
422
|
+
const proc = chunkIYK6LMQ7_cjs.compileProceduralBlock(block);
|
|
186
423
|
this.emit(`// Domain procedural: ${this.escapeStringValue(proc.name, "TypeScript")}`);
|
|
187
424
|
this.emit(`const ${prefix}ProceduralConfig = ${this.json({
|
|
188
425
|
name: proc.name,
|
|
@@ -352,6 +589,18 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
352
589
|
this.emit("return new Float32Array([-x,0,-z,0,1,0, x,0,-z,0,1,0, x,0,z,0,1,0, -x,0,-z,0,1,0, x,0,z,0,1,0, -x,0,z,0,1,0]);");
|
|
353
590
|
this.dedent();
|
|
354
591
|
this.emit("}");
|
|
592
|
+
if (this.hasWater) {
|
|
593
|
+
this.emit("function generateWaterPlaneVertices(w, h, n) {");
|
|
594
|
+
this.indent();
|
|
595
|
+
this.emit("const out = [], hw = w/2, hh = h/2, N = Math.max(2, n|0);");
|
|
596
|
+
this.emit("for (let iy=0; iy<N; iy++) { for (let ix=0; ix<N; ix++) {");
|
|
597
|
+
this.emit(" const x0=-hw+w*ix/N, x1=-hw+w*(ix+1)/N, y0=-hh+h*iy/N, y1=-hh+h*(iy+1)/N;");
|
|
598
|
+
this.emit(" const a=[x0,y0,0,0,0,1], b=[x1,y0,0,0,0,1], c=[x1,y1,0,0,0,1], d=[x0,y1,0,0,0,1];");
|
|
599
|
+
this.emit(" out.push(...a,...b,...c, ...a,...c,...d);");
|
|
600
|
+
this.emit("} } return new Float32Array(out);");
|
|
601
|
+
this.dedent();
|
|
602
|
+
this.emit("}");
|
|
603
|
+
}
|
|
355
604
|
this.emit("function generateSphereVertices(radius, lat, lon) {");
|
|
356
605
|
this.indent();
|
|
357
606
|
this.emit("const rings = Math.max(3, lat | 0), segs = Math.max(3, lon | 0); const out = [];");
|
|
@@ -417,7 +666,7 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
417
666
|
const envData = {};
|
|
418
667
|
for (const prop of env.properties) envData[prop.key] = prop.value;
|
|
419
668
|
const bg = envData.background || envData.skybox || "#000000";
|
|
420
|
-
const bgColor = this.parseColor(bg);
|
|
669
|
+
const bgColor = typeof bg === "string" && bg.startsWith("#") || Array.isArray(bg) ? this.parseColor(bg) : resolveSkyboxColor(bg);
|
|
421
670
|
this.emit(
|
|
422
671
|
`const clearColor: GPUColor = { r: ${bgColor[0]}, g: ${bgColor[1]}, b: ${bgColor[2]}, a: 1.0 };`
|
|
423
672
|
);
|
|
@@ -444,6 +693,41 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
444
693
|
const isModel = meshType === "model" || !!modelSrc;
|
|
445
694
|
const traits = obj.traits || [];
|
|
446
695
|
this.emit(`// Object: ${this.escapeStringValue(obj.name, "TypeScript")}`);
|
|
696
|
+
const role = resolveGeometryRole({
|
|
697
|
+
purpose: this.findObjProp(obj, "purpose"),
|
|
698
|
+
visible: this.findObjProp(obj, "visible"),
|
|
699
|
+
traitNames: traits.map((t) => t.name)
|
|
700
|
+
});
|
|
701
|
+
if (!role.visible) {
|
|
702
|
+
const prim = resolveGeometry(meshType).kind;
|
|
703
|
+
const pos = this.findObjProp(obj, "position");
|
|
704
|
+
const [px, py, pz] = Array.isArray(pos) ? pos : [0, 0, 0];
|
|
705
|
+
this.emit(
|
|
706
|
+
`// Functional geometry \u2014 purpose="${role.purpose}", not rendered; primitive="${prim}" is shared with physics/vfx/sim consumers.`
|
|
707
|
+
);
|
|
708
|
+
this.emit(
|
|
709
|
+
`holoGraphObjects.push({ id: "${this.escapeStringValue(obj.name, "TypeScript")}", name: "${this.escapeStringValue(obj.name, "TypeScript")}", geometry: "${this.escapeStringValue(meshType, "TypeScript")}", primitive: "${prim}", purpose: "${role.purpose}", visible: false, traits: ${this.json(traits.map((t) => t.name))}, basePosition: [${px},${py},${pz}], position: [${px},${py},${pz}] });`
|
|
710
|
+
);
|
|
711
|
+
this.manifestObjects.push({
|
|
712
|
+
id: String(obj.name ?? ""),
|
|
713
|
+
geometry: meshType,
|
|
714
|
+
primitive: prim,
|
|
715
|
+
purpose: role.purpose,
|
|
716
|
+
visible: false,
|
|
717
|
+
traits: traits.map((t) => t.name),
|
|
718
|
+
affordances: this.extractAffordanceNames(obj),
|
|
719
|
+
position: [
|
|
720
|
+
px + this.manifestGroupOffset[0],
|
|
721
|
+
py + this.manifestGroupOffset[1],
|
|
722
|
+
pz + this.manifestGroupOffset[2]
|
|
723
|
+
]
|
|
724
|
+
});
|
|
725
|
+
this.emit("");
|
|
726
|
+
if (obj.children) {
|
|
727
|
+
for (const child of obj.children) this.emitObject(child);
|
|
728
|
+
}
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
447
731
|
const isGaussianSplat = traits.some((t) => t.name === "gaussian_splat");
|
|
448
732
|
const isPointCloud = traits.some((t) => t.name === "point_cloud");
|
|
449
733
|
const isGpuParticle = traits.some((t) => isGpuParticleTraitName(t.name));
|
|
@@ -462,6 +746,8 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
462
746
|
this.emitPointCloudObject(v, obj);
|
|
463
747
|
} else if (isGpuParticle) {
|
|
464
748
|
this.emitGpuParticleObject(v, obj);
|
|
749
|
+
} else if (this.isWaterObject(obj)) {
|
|
750
|
+
this.emitWaterObject(v, obj);
|
|
465
751
|
} else {
|
|
466
752
|
this.emitMeshObject(v, obj, meshType);
|
|
467
753
|
}
|
|
@@ -479,6 +765,203 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
479
765
|
for (const child of obj.children) this.emitObject(child);
|
|
480
766
|
}
|
|
481
767
|
}
|
|
768
|
+
// ─── Water / fluid surfaces ────────────────────────────────────────────────
|
|
769
|
+
/**
|
|
770
|
+
* Resolve which named channels the water surface's clarity/ripple are bound to,
|
|
771
|
+
* from the first water object's `water_clarity_binding` / `ripple_intensity_binding`
|
|
772
|
+
* props. These names match the .holo's environment state fields, so host state
|
|
773
|
+
* (Brittney receipts) driving those fields drives the water by name.
|
|
774
|
+
*/
|
|
775
|
+
resolveWaterChannels(composition) {
|
|
776
|
+
const all = [...composition.objects ?? []];
|
|
777
|
+
for (const g of composition.spatialGroups ?? []) all.push(...g.objects ?? []);
|
|
778
|
+
const water = all.find((o) => this.isWaterObject(o));
|
|
779
|
+
if (!water) return;
|
|
780
|
+
const clarity = this.findObjProp(water, "water_clarity_binding");
|
|
781
|
+
const ripple = this.findObjProp(water, "ripple_intensity_binding");
|
|
782
|
+
if (typeof clarity === "string" && clarity.trim()) this.waterClarityChannel = clarity.trim();
|
|
783
|
+
if (typeof ripple === "string" && ripple.trim()) this.waterRippleChannel = ripple.trim();
|
|
784
|
+
}
|
|
785
|
+
/** True if any object (incl. nested groups/children) is a water/fluid surface. */
|
|
786
|
+
compositionHasWater(composition) {
|
|
787
|
+
const scan = (objs) => (objs ?? []).some((o) => this.isWaterObject(o) || scan(o.children));
|
|
788
|
+
if (scan(composition.objects)) return true;
|
|
789
|
+
const walk = (g) => scan(g.objects) || (g.groups ?? []).some(walk);
|
|
790
|
+
return (composition.spatialGroups ?? []).some(walk);
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* A water surface is a fluid-plane mesh (full_screen_fluid_plane / water / ...),
|
|
794
|
+
* or a water-ish MATERIAL on a plane-like geometry. It is NOT a water material on
|
|
795
|
+
* a sphere — emitWaterObject always renders a tessellated plane.
|
|
796
|
+
*/
|
|
797
|
+
isWaterObject(obj) {
|
|
798
|
+
const mesh = String(this.findObjProp(obj, "mesh") ?? this.findObjProp(obj, "geometry") ?? "").trim().toLowerCase();
|
|
799
|
+
const material = String(this.findObjProp(obj, "material") ?? "").trim().toLowerCase();
|
|
800
|
+
const WATER_MESH = ["full_screen_fluid_plane", "fluid_plane", "water", "water_plane", "ocean"];
|
|
801
|
+
const WATER_MAT = ["liquid_glass", "water", "liquid", "fluid"];
|
|
802
|
+
if (WATER_MESH.includes(mesh)) return true;
|
|
803
|
+
return WATER_MAT.includes(material) && resolveGeometry(mesh).kind === "plane";
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Emit an animated water surface: a tessellated plane driven by the shared
|
|
807
|
+
* per-frame time uniform through the WGSL_WATER shader (Gerstner-lite height
|
|
808
|
+
* waves + analytic normals + texture-free caustics + fresnel). Binding layout
|
|
809
|
+
* mirrors the mesh path (0=Model, 2=vpUniform) plus 1=WaterStatic, 3=waterFrameU.
|
|
810
|
+
*/
|
|
811
|
+
emitWaterObject(v, obj) {
|
|
812
|
+
const pos = this.findObjProp(obj, "position");
|
|
813
|
+
const scale = this.findObjProp(obj, "scale") || this.findObjProp(obj, "size");
|
|
814
|
+
const [px, py, pz] = Array.isArray(pos) ? pos : [0, 0, 0];
|
|
815
|
+
const [sx, sy, sz] = Array.isArray(scale) ? scale : typeof scale === "number" ? [scale, scale, scale] : [1, 1, 1];
|
|
816
|
+
const deep = this.parseColor(this.findObjProp(obj, "color") ?? "#06131f");
|
|
817
|
+
const shallow = [
|
|
818
|
+
Math.min(1, deep[0] * 2.2 + 0.05),
|
|
819
|
+
Math.min(1, deep[1] * 2.2 + 0.2),
|
|
820
|
+
Math.min(1, deep[2] * 2 + 0.24)
|
|
821
|
+
];
|
|
822
|
+
const amplitude = 0.18, choppiness = 0.4, clarity = 1, ripple = 0;
|
|
823
|
+
const L = [0.3714, 0.7428, 0.5571];
|
|
824
|
+
this.emit(`// Water surface: ${this.escapeStringValue(obj.name, "TypeScript")}`);
|
|
825
|
+
this.emit(`const ${v}Vertices = generateWaterPlaneVertices(1.0, 1.0, 48);`);
|
|
826
|
+
this.emit(`const ${v}VBO = createBuffer(device, ${v}Vertices, GPUBufferUsage.VERTEX);`);
|
|
827
|
+
this.emit(`const ${v}VertexCount = ${v}Vertices.length / 6;`);
|
|
828
|
+
this.emit(
|
|
829
|
+
`const ${v}Model = createBuffer(device, new Float32Array([${sx},0,0,0, 0,${sy},0,0, 0,0,${sz},0, ${px},${py},${pz},1]), GPUBufferUsage.UNIFORM);`
|
|
830
|
+
);
|
|
831
|
+
this.emit(
|
|
832
|
+
`const ${v}WaterStatic = createBuffer(device, new Float32Array([${amplitude},${choppiness},${clarity},${ripple}, ${deep[0]},${deep[1]},${deep[2]},0, ${shallow[0]},${shallow[1]},${shallow[2]},0, ${L[0]},${L[1]},${L[2]},0]), GPUBufferUsage.UNIFORM);`
|
|
833
|
+
);
|
|
834
|
+
this.emit(`const ${v}WaterPipeline = device.createRenderPipeline({`);
|
|
835
|
+
this.indent();
|
|
836
|
+
this.emit('layout: "auto",');
|
|
837
|
+
this.emit(
|
|
838
|
+
'vertex: { module: device.createShaderModule({ code: WGSL_WATER }), entryPoint: "vs_water",'
|
|
839
|
+
);
|
|
840
|
+
this.emit(
|
|
841
|
+
' buffers: [{ arrayStride: 24, attributes: [{ shaderLocation: 0, offset: 0, format: "float32x3" }, { shaderLocation: 1, offset: 12, format: "float32x3" }] }] },'
|
|
842
|
+
);
|
|
843
|
+
this.emit(
|
|
844
|
+
'fragment: { module: device.createShaderModule({ code: WGSL_WATER }), entryPoint: "fs_water", targets: [{ format }] },'
|
|
845
|
+
);
|
|
846
|
+
this.emit('primitive: { topology: "triangle-list", cullMode: "none" },');
|
|
847
|
+
this.emit(
|
|
848
|
+
`depthStencil: { format: "depth24plus", depthWriteEnabled: true, depthCompare: "less" }, multisample: { count: MSAA_COUNT },`
|
|
849
|
+
);
|
|
850
|
+
this.dedent();
|
|
851
|
+
this.emit("});");
|
|
852
|
+
this.emit(
|
|
853
|
+
`const ${v}WaterBind = device.createBindGroup({ layout: ${v}WaterPipeline.getBindGroupLayout(0), entries: [`
|
|
854
|
+
);
|
|
855
|
+
this.emit(
|
|
856
|
+
` { binding: 0, resource: { buffer: ${v}Model } }, { binding: 1, resource: { buffer: ${v}WaterStatic } }, { binding: 2, resource: { buffer: vpUniform } }, { binding: 3, resource: { buffer: waterFrameU } }] });`
|
|
857
|
+
);
|
|
858
|
+
}
|
|
859
|
+
/** Emit the shared WGSL_WATER module (vs_water + fs_water + noise helpers). */
|
|
860
|
+
emitWaterShaderSource() {
|
|
861
|
+
this.emit("const WGSL_WATER = /* wgsl */`");
|
|
862
|
+
this.emit("struct Model { m: mat4x4<f32> };");
|
|
863
|
+
this.emit("struct WStatic { p: vec4<f32>, deep: vec4<f32>, shallow: vec4<f32>, lightDir: vec4<f32> };");
|
|
864
|
+
this.emit("struct Cam { viewProj: mat4x4<f32> };");
|
|
865
|
+
this.emit("struct WFrame { tc: vec4<f32>, dyn: vec4<f32> };");
|
|
866
|
+
this.emit("@group(0) @binding(0) var<uniform> model: Model;");
|
|
867
|
+
this.emit("@group(0) @binding(1) var<uniform> ws: WStatic;");
|
|
868
|
+
this.emit("@group(0) @binding(2) var<uniform> cam: Cam;");
|
|
869
|
+
this.emit("@group(0) @binding(3) var<uniform> wf: WFrame;");
|
|
870
|
+
this.emit("struct VIn { @location(0) pos: vec3<f32>, @location(1) norm: vec3<f32> };");
|
|
871
|
+
this.emit("struct VOut { @builtin(position) clip: vec4<f32>, @location(0) wNorm: vec3<f32>, @location(1) wPos: vec3<f32> };");
|
|
872
|
+
this.emit("@vertex fn vs_water(in: VIn) -> VOut {");
|
|
873
|
+
this.emit(" var o: VOut;");
|
|
874
|
+
this.emit(" let sx = length(model.m[0].xyz); let sy = length(model.m[1].xyz); let sz = max(length(model.m[2].xyz), 1e-4);");
|
|
875
|
+
this.emit(" let wp = in.pos.xy * vec2<f32>(sx, sy);");
|
|
876
|
+
this.emit(" let t = wf.tc.x; let amp = ws.p.x * wf.dyn.z * (0.4 + wf.dyn.y);");
|
|
877
|
+
this.emit(" var h = 0.0; var dhdx = 0.0; var dhdy = 0.0;");
|
|
878
|
+
this.emit(" var dx = 0.0; var dy = 0.0; var k = 0.0; var spd = 0.0; var a = 0.0;");
|
|
879
|
+
this.emit(" for (var i = 0; i < 4; i = i + 1) {");
|
|
880
|
+
this.emit(" if (i == 0) { dx = 1.0; dy = 0.0; k = 0.7; spd = 0.6; a = 1.0; }");
|
|
881
|
+
this.emit(" else if (i == 1) { dx = 0.5; dy = 0.86; k = 1.2; spd = 0.9; a = 0.55; }");
|
|
882
|
+
this.emit(" else if (i == 2) { dx = -0.8; dy = 0.6; k = 1.9; spd = 1.15; a = 0.3; }");
|
|
883
|
+
this.emit(" else { dx = 0.2; dy = -0.98; k = 2.7; spd = 1.4; a = 0.18; }");
|
|
884
|
+
this.emit(" let d = normalize(vec2<f32>(dx, dy));");
|
|
885
|
+
this.emit(" let ph = k * dot(d, wp) + spd * t;");
|
|
886
|
+
this.emit(" h = h + a * amp * sin(ph);");
|
|
887
|
+
this.emit(" dhdx = dhdx + a * amp * k * d.x * cos(ph);");
|
|
888
|
+
this.emit(" dhdy = dhdy + a * amp * k * d.y * cos(ph);");
|
|
889
|
+
this.emit(" }");
|
|
890
|
+
this.emit(" var lp = in.pos; lp.z = lp.z + h / sz;");
|
|
891
|
+
this.emit(" let world = model.m * vec4<f32>(lp, 1.0);");
|
|
892
|
+
this.emit(" o.wPos = world.xyz;");
|
|
893
|
+
this.emit(" o.wNorm = normalize(vec3<f32>(-dhdx, -dhdy, 1.0));");
|
|
894
|
+
this.emit(" o.clip = cam.viewProj * world;");
|
|
895
|
+
this.emit(" return o;");
|
|
896
|
+
this.emit("}");
|
|
897
|
+
this.emit("fn hash21(p: vec2<f32>) -> f32 { let h = dot(p, vec2<f32>(127.1, 311.7)); return fract(sin(h) * 43758.5453); }");
|
|
898
|
+
this.emit("fn vnoise(p: vec2<f32>) -> f32 {");
|
|
899
|
+
this.emit(" let i = floor(p); let f = fract(p); let u = f * f * (3.0 - 2.0 * f);");
|
|
900
|
+
this.emit(" let a = hash21(i); let b = hash21(i + vec2<f32>(1.0, 0.0));");
|
|
901
|
+
this.emit(" let c = hash21(i + vec2<f32>(0.0, 1.0)); let dd = hash21(i + vec2<f32>(1.0, 1.0));");
|
|
902
|
+
this.emit(" return mix(mix(a, b, u.x), mix(c, dd, u.x), u.y);");
|
|
903
|
+
this.emit("}");
|
|
904
|
+
this.emit("struct FIn { @location(0) wNorm: vec3<f32>, @location(1) wPos: vec3<f32> };");
|
|
905
|
+
this.emit("@fragment fn fs_water(in: FIn) -> @location(0) vec4<f32> {");
|
|
906
|
+
this.emit(" let N = normalize(in.wNorm);");
|
|
907
|
+
this.emit(" let V = normalize(wf.tc.yzw - in.wPos);");
|
|
908
|
+
this.emit(" let L = normalize(ws.lightDir.xyz);");
|
|
909
|
+
this.emit(" let t = wf.tc.x;");
|
|
910
|
+
this.emit(" let ndv = max(dot(N, V), 0.0);");
|
|
911
|
+
this.emit(" let fres = 0.02 + 0.98 * pow(1.0 - ndv, 5.0);");
|
|
912
|
+
this.emit(" let tilt = clamp(1.0 - ndv, 0.0, 1.0);");
|
|
913
|
+
this.emit(" var col = mix(ws.deep.rgb, ws.shallow.rgb, clamp(tilt * 1.3, 0.0, 1.0));");
|
|
914
|
+
this.emit(" let p = in.wPos.xy;");
|
|
915
|
+
this.emit(" let n1 = vnoise(p * 0.9 + vec2<f32>(t * 0.15, t * 0.08));");
|
|
916
|
+
this.emit(" let n2 = vnoise(p * 1.7 - vec2<f32>(t * 0.11, t * 0.19));");
|
|
917
|
+
this.emit(" let caustic = pow(n1 * n2, 3.0);");
|
|
918
|
+
this.emit(" col = col + vec3<f32>(0.10, 0.18, 0.20) * caustic * wf.dyn.x;");
|
|
919
|
+
this.emit(" let H = normalize(L + V);");
|
|
920
|
+
this.emit(" let spec = pow(max(dot(N, H), 0.0), 200.0);");
|
|
921
|
+
this.emit(" col = col + vec3<f32>(0.85, 0.92, 1.0) * spec;");
|
|
922
|
+
this.emit(" let sky = vec3<f32>(0.10, 0.26, 0.36);");
|
|
923
|
+
this.emit(" col = mix(col, sky, fres * 0.3);");
|
|
924
|
+
this.emit(" return vec4<f32>(col, 1.0);");
|
|
925
|
+
this.emit("}`;");
|
|
926
|
+
this.emit("");
|
|
927
|
+
}
|
|
928
|
+
/** Tool-affordance names declared on an object's @tool traits (both trait
|
|
929
|
+
* config formats), for the scene manifest — the artifact-level answer to
|
|
930
|
+
* "which named actions does this entity offer" that the numeric registry
|
|
931
|
+
* cannot express. */
|
|
932
|
+
extractAffordanceNames(obj) {
|
|
933
|
+
const names = [];
|
|
934
|
+
for (const trait of obj.traits ?? []) {
|
|
935
|
+
const t = trait;
|
|
936
|
+
if (t.name !== "tool") continue;
|
|
937
|
+
const config = "config" in t && typeof t.config === "object" && t.config !== null ? t.config : t;
|
|
938
|
+
if (typeof config["name"] === "string" && config["name"] !== "tool") {
|
|
939
|
+
names.push(config["name"]);
|
|
940
|
+
} else {
|
|
941
|
+
names.push("unnamed_tool");
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
return names;
|
|
945
|
+
}
|
|
946
|
+
/**
|
|
947
|
+
* HoloScene Manifest — a machine-readable world-facts block INSIDE the
|
|
948
|
+
* delivered artifact (g9tk). Collected at EMISSION time (each emitObject/
|
|
949
|
+
* emitMeshObject records what it actually emitted), so the manifest describes
|
|
950
|
+
* the artifact, not the input. Strict JSON payload: independent consumers
|
|
951
|
+
* (perceiver derivations, tooling) JSON.parse it instead of regexing the
|
|
952
|
+
* imperative holoGraphObjects push literals.
|
|
953
|
+
*/
|
|
954
|
+
emitSceneManifest(composition) {
|
|
955
|
+
const manifest = {
|
|
956
|
+
version: "holo-scene-manifest-v1",
|
|
957
|
+
source: String(composition.name ?? ""),
|
|
958
|
+
objects: this.manifestObjects
|
|
959
|
+
};
|
|
960
|
+
this.emit("// === HoloScene Manifest (machine-readable world facts; part of the delivered artifact) ===");
|
|
961
|
+
this.emit(`const holoSceneManifest = ${this.json(manifest)};`);
|
|
962
|
+
this.emit('if (typeof globalThis !== "undefined") { globalThis.holoSceneManifest = holoSceneManifest; }');
|
|
963
|
+
this.emit("");
|
|
964
|
+
}
|
|
482
965
|
emitMeshObject(v, obj, meshType) {
|
|
483
966
|
this.emit(`const ${v}Vertices = ${this.geometryVertexDataFn(meshType)};`);
|
|
484
967
|
this.emit(`const ${v}VBO = createBuffer(device, ${v}Vertices, GPUBufferUsage.VERTEX);`);
|
|
@@ -495,14 +978,35 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
495
978
|
const [cr, cg, cb] = this.extractMaterialColor(material, color);
|
|
496
979
|
const rough = this.extractMaterialProp(material, "roughness", 0.5);
|
|
497
980
|
const metal = this.extractMaterialProp(material, "metalness", 0);
|
|
498
|
-
|
|
499
|
-
|
|
981
|
+
let [er, eg, eb] = this.extractEmissive(material, obj);
|
|
982
|
+
let emissiveStrength = this.extractMaterialProp(material, "emissive_intensity", 1);
|
|
983
|
+
const glow = this.materialGlow(material);
|
|
984
|
+
if (glow > 0 && er === 0 && eg === 0 && eb === 0) {
|
|
985
|
+
er = cr;
|
|
986
|
+
eg = cg;
|
|
987
|
+
eb = cb;
|
|
988
|
+
emissiveStrength = glow;
|
|
989
|
+
}
|
|
500
990
|
this.emit(
|
|
501
991
|
`const ${v}Mat = createBuffer(device, new Float32Array([${cr},${cg},${cb},1.0, ${rough},${metal},${emissiveStrength},0, ${er},${eg},${eb},0]), GPUBufferUsage.UNIFORM);`
|
|
502
992
|
);
|
|
503
993
|
this.emit(
|
|
504
994
|
`holoGraphObjects.push({ id: "${this.escapeStringValue(obj.name, "TypeScript")}", name: "${this.escapeStringValue(obj.name, "TypeScript")}", geometry: "${this.escapeStringValue(meshType, "TypeScript")}", traits: ${this.json((obj.traits || []).map((t) => t.name))}, properties: ${this.json(this.extractObjectProperties(obj))}, basePosition: [${px},${py},${pz}], position: [${px},${py},${pz}], baseScale: [${sx},${sy},${sz}], scale: [${sx},${sy},${sz}], baseColor: [${cr},${cg},${cb}], color: [${cr},${cg},${cb}], material: { roughness: ${rough}, metalness: ${metal}, emissiveStrength: ${emissiveStrength}, emissive: [${er},${eg},${eb}] }, modelBuffer: ${v}Model, matBuffer: ${v}Mat, visible: true });`
|
|
505
995
|
);
|
|
996
|
+
this.manifestObjects.push({
|
|
997
|
+
id: String(obj.name ?? ""),
|
|
998
|
+
geometry: meshType,
|
|
999
|
+
visible: true,
|
|
1000
|
+
traits: (obj.traits || []).map((t) => t.name),
|
|
1001
|
+
affordances: this.extractAffordanceNames(obj),
|
|
1002
|
+
position: [
|
|
1003
|
+
px + this.manifestGroupOffset[0],
|
|
1004
|
+
py + this.manifestGroupOffset[1],
|
|
1005
|
+
pz + this.manifestGroupOffset[2]
|
|
1006
|
+
],
|
|
1007
|
+
scale: [sx, sy, sz],
|
|
1008
|
+
color: [cr, cg, cb]
|
|
1009
|
+
});
|
|
506
1010
|
this.emit(`const ${v}Pipeline = device.createRenderPipeline({`);
|
|
507
1011
|
this.indent();
|
|
508
1012
|
this.emit('layout: "auto",');
|
|
@@ -525,7 +1029,7 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
525
1029
|
`const ${v}Bind = device.createBindGroup({ layout: ${v}Pipeline.getBindGroupLayout(0), entries: [`
|
|
526
1030
|
);
|
|
527
1031
|
this.emit(
|
|
528
|
-
` { binding: 0, resource: { buffer: ${v}Model } }, { binding: 1, resource: { buffer: ${v}Mat } }, { binding: 2, resource: { buffer: vpUniform } }] });`
|
|
1032
|
+
` { binding: 0, resource: { buffer: ${v}Model } }, { binding: 1, resource: { buffer: ${v}Mat } }, { binding: 2, resource: { buffer: vpUniform } }, { binding: 3, resource: { buffer: sceneLights } }] });`
|
|
529
1033
|
);
|
|
530
1034
|
}
|
|
531
1035
|
emitGaussianSplatObject(v, obj) {
|
|
@@ -632,43 +1136,140 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
632
1136
|
this.emit(
|
|
633
1137
|
`const ${v}GroupXform = createBuffer(device, new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, ${px},${py},${pz},1]), GPUBufferUsage.UNIFORM);`
|
|
634
1138
|
);
|
|
1139
|
+
const saved = this.manifestGroupOffset;
|
|
1140
|
+
this.manifestGroupOffset = [saved[0] + px, saved[1] + py, saved[2] + pz];
|
|
635
1141
|
for (const obj of group.objects) this.emitObject(obj);
|
|
636
1142
|
if (group.groups) {
|
|
637
1143
|
for (const sub of group.groups) this.emitGroup(sub);
|
|
638
1144
|
}
|
|
1145
|
+
this.manifestGroupOffset = saved;
|
|
639
1146
|
this.emit("");
|
|
640
1147
|
}
|
|
641
1148
|
// ─── Light ────────────────────────────────────────────────────────────────
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
1149
|
+
// Aggregate the scene's declared lights into ONE shared uniform buffer that every
|
|
1150
|
+
// mesh binds (binding 3). Shape math — color*intensity, type tag, world position,
|
|
1151
|
+
// travel direction — is resolved here; the fragment shader consumes up to
|
|
1152
|
+
// MAX_LIGHTS. A light-less scene gets a synthesized key light so it stays lit.
|
|
1153
|
+
emitSceneLights(composition) {
|
|
1154
|
+
const MAX_LIGHTS = 4;
|
|
1155
|
+
const typeIndex = {
|
|
1156
|
+
directional: 0,
|
|
1157
|
+
point: 1,
|
|
1158
|
+
spot: 2,
|
|
1159
|
+
hemisphere: 3,
|
|
1160
|
+
ambient: 4,
|
|
1161
|
+
area: 5
|
|
1162
|
+
};
|
|
1163
|
+
const lights = (composition.lights ?? []).slice(0, MAX_LIGHTS).map((light) => {
|
|
1164
|
+
let color = [1, 1, 1], intensity = 1, pos = [0, 10, 0], dir = [0, -1, 0], hasDir = false;
|
|
1165
|
+
for (const prop of light.properties) {
|
|
1166
|
+
if (prop.key === "color") color = this.parseColor(prop.value);
|
|
1167
|
+
else if (prop.key === "intensity") intensity = prop.value;
|
|
1168
|
+
else if (prop.key === "position" && Array.isArray(prop.value)) pos = prop.value;
|
|
1169
|
+
else if (prop.key === "direction" && Array.isArray(prop.value)) {
|
|
1170
|
+
dir = prop.value;
|
|
1171
|
+
hasDir = true;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
const ti = typeIndex[light.lightType] ?? 0;
|
|
1175
|
+
if (ti === 0 && !hasDir && Array.isArray(pos)) dir = [-pos[0], -pos[1], -pos[2]];
|
|
1176
|
+
return { name: String(light.name ?? ""), kind: String(light.lightType ?? ""), color, intensity, pos, dir, ti };
|
|
1177
|
+
});
|
|
1178
|
+
if (lights.length === 0) {
|
|
1179
|
+
lights.push({ name: "(synthesized key light)", kind: "directional", color: [1, 1, 1], intensity: 1, pos: [1, 2, 1.5], dir: [-1, -2, -1.5], ti: 0 });
|
|
1180
|
+
}
|
|
1181
|
+
const segs = [`${lights.length},0,0,0`];
|
|
1182
|
+
for (let i = 0; i < MAX_LIGHTS; i++) {
|
|
1183
|
+
const l = lights[i];
|
|
1184
|
+
if (l) {
|
|
1185
|
+
segs.push(`${l.color[0] * l.intensity},${l.color[1] * l.intensity},${l.color[2] * l.intensity},${l.ti}`);
|
|
1186
|
+
segs.push(`${l.pos[0]},${l.pos[1]},${l.pos[2]},0`);
|
|
1187
|
+
segs.push(`${l.dir[0]},${l.dir[1]},${l.dir[2]},0`);
|
|
1188
|
+
} else {
|
|
1189
|
+
segs.push("0,0,0,0", "0,0,0,0", "0,0,0,0");
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
this.emit("// === Scene Lights (shared uniform, bound by every mesh at binding 3) ===");
|
|
1193
|
+
for (let i = 0; i < lights.length; i++) {
|
|
1194
|
+
const safeName = lights[i].name.replace(/[\r\n*]+/g, " ");
|
|
1195
|
+
this.emit(`// Light[${i}]: "${safeName}" (${lights[i].kind}, intensity ${lights[i].intensity})`);
|
|
650
1196
|
}
|
|
651
|
-
const ti = { directional: 0, point: 1, spot: 2, hemisphere: 3, ambient: 4, area: 5 }[light.lightType] ?? 0;
|
|
652
|
-
this.emit(
|
|
653
|
-
`// Light: ${this.escapeStringValue(light.name, "TypeScript")} (${light.lightType})`
|
|
654
|
-
);
|
|
655
1197
|
this.emit(
|
|
656
|
-
`const
|
|
1198
|
+
`const sceneLights = createBuffer(device, new Float32Array([${segs.join(", ")}]), GPUBufferUsage.UNIFORM);`
|
|
657
1199
|
);
|
|
658
1200
|
this.emit("");
|
|
659
1201
|
}
|
|
660
1202
|
// ─── Camera ───────────────────────────────────────────────────────────────
|
|
661
|
-
|
|
1203
|
+
// Compute a bounding sphere (center + radius) over every object's world position,
|
|
1204
|
+
// including spatial-group offsets and per-object scale. Used to auto-frame the
|
|
1205
|
+
// camera when the author declared no explicit position. Returns null for an
|
|
1206
|
+
// object-less scene (nothing to frame → keep the neutral default).
|
|
1207
|
+
sceneBoundsForCamera(composition) {
|
|
1208
|
+
const pts = [];
|
|
1209
|
+
const R_CAP = 3;
|
|
1210
|
+
const addObj = (obj, offset) => {
|
|
1211
|
+
const pos = this.findObjProp(obj, "position");
|
|
1212
|
+
const scale = this.findObjProp(obj, "scale") || this.findObjProp(obj, "size");
|
|
1213
|
+
const [px, py, pz] = Array.isArray(pos) ? pos : [0, 0, 0];
|
|
1214
|
+
const rawR = Array.isArray(scale) ? Math.max(...scale.map((n) => Math.abs(n))) : typeof scale === "number" ? Math.abs(scale) : 1;
|
|
1215
|
+
pts.push({ p: [px + offset[0], py + offset[1], pz + offset[2]], r: Math.min(rawR, R_CAP) });
|
|
1216
|
+
};
|
|
1217
|
+
for (const obj of composition.objects ?? []) addObj(obj, [0, 0, 0]);
|
|
1218
|
+
const walkGroup = (g, parent) => {
|
|
1219
|
+
const gp = g.properties?.find((p) => p.key === "position")?.value;
|
|
1220
|
+
const [gx, gy, gz] = Array.isArray(gp) ? gp : [0, 0, 0];
|
|
1221
|
+
const off = [parent[0] + gx, parent[1] + gy, parent[2] + gz];
|
|
1222
|
+
for (const obj of g.objects ?? []) addObj(obj, off);
|
|
1223
|
+
for (const sub of g.groups ?? []) walkGroup(sub, off);
|
|
1224
|
+
};
|
|
1225
|
+
for (const g of composition.spatialGroups ?? []) walkGroup(g, [0, 0, 0]);
|
|
1226
|
+
if (pts.length === 0) return null;
|
|
1227
|
+
const min = [Infinity, Infinity, Infinity];
|
|
1228
|
+
const max = [-Infinity, -Infinity, -Infinity];
|
|
1229
|
+
for (const { p, r } of pts) {
|
|
1230
|
+
for (let i = 0; i < 3; i++) {
|
|
1231
|
+
min[i] = Math.min(min[i], p[i] - r);
|
|
1232
|
+
max[i] = Math.max(max[i], p[i] + r);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
const center = [(min[0] + max[0]) / 2, (min[1] + max[1]) / 2, (min[2] + max[2]) / 2];
|
|
1236
|
+
let radius = 0;
|
|
1237
|
+
for (const { p, r } of pts) {
|
|
1238
|
+
radius = Math.max(radius, Math.hypot(p[0] - center[0], p[1] - center[1], p[2] - center[2]) + r);
|
|
1239
|
+
}
|
|
1240
|
+
return { center, radius: radius || 1 };
|
|
1241
|
+
}
|
|
1242
|
+
emitCamera(composition) {
|
|
1243
|
+
const cam = composition.camera;
|
|
662
1244
|
this.emit("// === Camera ===");
|
|
663
|
-
let fov = 60, near = 0.1, far = 1e3, pos = [4, 3, 6], lookAt = [0, 0, 0];
|
|
1245
|
+
let fov = 60, near = 0.1, far = 1e3, pos = [4, 3, 6], lookAt = [0, 0, 0], hasPos = false;
|
|
664
1246
|
for (const prop of cam?.properties ?? []) {
|
|
665
1247
|
if (prop.key === "fov" || prop.key === "field_of_view") fov = prop.value;
|
|
666
1248
|
else if (prop.key === "near") near = prop.value;
|
|
667
1249
|
else if (prop.key === "far") far = prop.value;
|
|
668
|
-
else if (prop.key === "position" && Array.isArray(prop.value))
|
|
669
|
-
|
|
1250
|
+
else if (prop.key === "position" && Array.isArray(prop.value)) {
|
|
1251
|
+
pos = prop.value;
|
|
1252
|
+
hasPos = true;
|
|
1253
|
+
} else if ((prop.key === "look_at" || prop.key === "lookAt") && Array.isArray(prop.value))
|
|
670
1254
|
lookAt = prop.value;
|
|
671
1255
|
}
|
|
1256
|
+
if (!hasPos) {
|
|
1257
|
+
const b = this.sceneBoundsForCamera(composition);
|
|
1258
|
+
if (b) {
|
|
1259
|
+
const r4 = (n) => Number(n.toFixed(4));
|
|
1260
|
+
const fovRad = fov * Math.PI / 180;
|
|
1261
|
+
const dist = b.radius / Math.sin(fovRad / 2) * 1.1;
|
|
1262
|
+
const dl = Math.hypot(0.35, 0.45, 1);
|
|
1263
|
+
const dir = [0.35 / dl, 0.45 / dl, 1 / dl];
|
|
1264
|
+
pos = [
|
|
1265
|
+
r4(b.center[0] + dir[0] * dist),
|
|
1266
|
+
r4(b.center[1] + dir[1] * dist),
|
|
1267
|
+
r4(b.center[2] + dir[2] * dist)
|
|
1268
|
+
];
|
|
1269
|
+
lookAt = [r4(b.center[0]), r4(b.center[1]), r4(b.center[2])];
|
|
1270
|
+
far = Math.max(far, r4(dist + b.radius * 2 + 10));
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
672
1273
|
this.emit(`const cameraFov = ${fov} * Math.PI / 180;`);
|
|
673
1274
|
this.emit(`const cameraNear = ${near}, cameraFar = ${far};`);
|
|
674
1275
|
this.emit(`const cameraPos = new Float32Array([${pos.join(",")}]);`);
|
|
@@ -768,15 +1369,27 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
768
1369
|
this.emit("");
|
|
769
1370
|
this.emit("const WGSL_FRAGMENT = /* wgsl */`");
|
|
770
1371
|
this.emit("struct Mat { color: vec4<f32>, rm: vec4<f32>, emissive: vec4<f32> };");
|
|
1372
|
+
this.emit("struct Light { ct: vec4<f32>, posW: vec4<f32>, dirW: vec4<f32> };");
|
|
1373
|
+
this.emit("struct Lights { count: vec4<f32>, items: array<Light, 4> };");
|
|
771
1374
|
this.emit("@group(0) @binding(1) var<uniform> mat: Mat;");
|
|
1375
|
+
this.emit("@group(0) @binding(3) var<uniform> lights: Lights;");
|
|
772
1376
|
this.emit("struct FIn { @location(0) wNorm: vec3<f32>, @location(1) wPos: vec3<f32> };");
|
|
773
1377
|
this.emit("@fragment fn fs_main(i: FIn) -> @location(0) vec4<f32> {");
|
|
774
|
-
this.emit(" let N = normalize(i.wNorm);
|
|
775
|
-
this.emit("
|
|
776
|
-
this.emit(" let
|
|
1378
|
+
this.emit(" let N = normalize(i.wNorm);");
|
|
1379
|
+
this.emit(" var acc = vec3<f32>(0.0, 0.0, 0.0);");
|
|
1380
|
+
this.emit(" let n = i32(lights.count.x);");
|
|
1381
|
+
this.emit(" for (var k = 0; k < n; k = k + 1) {");
|
|
1382
|
+
this.emit(" let lt = lights.items[k];");
|
|
1383
|
+
this.emit(" var L = normalize(-lt.dirW.xyz);");
|
|
1384
|
+
this.emit(" if (lt.ct.w > 0.5) { L = normalize(lt.posW.xyz - i.wPos); }");
|
|
1385
|
+
this.emit(" let d = max(dot(N, L), 0.0) * (1.0 - mat.rm[0] * 0.5);");
|
|
1386
|
+
this.emit(" acc = acc + lt.ct.rgb * d;");
|
|
1387
|
+
this.emit(" }");
|
|
1388
|
+
this.emit(" let lit = mat.color.rgb * (0.15 + acc);");
|
|
777
1389
|
this.emit(" let emit = mat.emissive.rgb * mat.rm[2];");
|
|
778
1390
|
this.emit(" return vec4<f32>(lit + emit, mat.color.a); }`;");
|
|
779
1391
|
this.emit("");
|
|
1392
|
+
if (this.hasWater) this.emitWaterShaderSource();
|
|
780
1393
|
this.emit("const WGSL_SPLAT = /* wgsl */`");
|
|
781
1394
|
this.emit(
|
|
782
1395
|
"struct Splat { center: vec3<f32>, opacity: f32, cov: array<f32,6>, sh: vec3<f32> };"
|
|
@@ -1011,6 +1624,11 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
1011
1624
|
this.emit("frameCount++;");
|
|
1012
1625
|
this.emit("const time = (performance.now() - t0) / 1000.0;");
|
|
1013
1626
|
this.emit("device.queue.writeBuffer(vpUniform, 0, buildViewProjection());");
|
|
1627
|
+
if (this.hasWater) {
|
|
1628
|
+
this.emit(
|
|
1629
|
+
`device.queue.writeBuffer(waterFrameU, 0, new Float32Array([time, cameraPos[0], cameraPos[1], cameraPos[2], hsChannels[${JSON.stringify(this.waterClarityChannel)}], hsChannels[${JSON.stringify(this.waterRippleChannel)}], hsWaterAmp, 0]));`
|
|
1630
|
+
);
|
|
1631
|
+
}
|
|
1014
1632
|
this.emit("hsRenderLabels();");
|
|
1015
1633
|
this.emit("const enc = device.createCommandEncoder();");
|
|
1016
1634
|
const gpuObjs = (composition.objects || []).filter(
|
|
@@ -1067,6 +1685,17 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
1067
1685
|
emitDrawCall(obj) {
|
|
1068
1686
|
const v = this.sanitizeName(obj.name);
|
|
1069
1687
|
const traits = obj.traits || [];
|
|
1688
|
+
const role = resolveGeometryRole({
|
|
1689
|
+
purpose: this.findObjProp(obj, "purpose"),
|
|
1690
|
+
visible: this.findObjProp(obj, "visible"),
|
|
1691
|
+
traitNames: traits.map((t) => t.name)
|
|
1692
|
+
});
|
|
1693
|
+
if (!role.visible) {
|
|
1694
|
+
if (obj.children) {
|
|
1695
|
+
for (const child of obj.children) this.emitDrawCall(child);
|
|
1696
|
+
}
|
|
1697
|
+
return;
|
|
1698
|
+
}
|
|
1070
1699
|
if (traits.some((t) => t.name === "gaussian_splat")) {
|
|
1071
1700
|
this.emit(`rp.setPipeline(${v}SplatPipeline); rp.draw(4, ${v}SplatCount.value);`);
|
|
1072
1701
|
} else if (traits.some((t) => t.name === "point_cloud")) {
|
|
@@ -1075,6 +1704,10 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
1075
1704
|
this.emit(
|
|
1076
1705
|
`rp.setPipeline(${v}ParticlePipeline); rp.setVertexBuffer(0, ${v}ParticleBufA); rp.draw(${v}ParticleCount);`
|
|
1077
1706
|
);
|
|
1707
|
+
} else if (this.isWaterObject(obj)) {
|
|
1708
|
+
this.emit(
|
|
1709
|
+
`rp.setPipeline(${v}WaterPipeline); rp.setBindGroup(0, ${v}WaterBind); rp.setVertexBuffer(0, ${v}VBO); rp.draw(${v}VertexCount);`
|
|
1710
|
+
);
|
|
1078
1711
|
} else {
|
|
1079
1712
|
this.emit(
|
|
1080
1713
|
`rp.setPipeline(${v}Pipeline); rp.setBindGroup(0, ${v}Bind); rp.setVertexBuffer(0, ${v}VBO); rp.draw(${v}VertexCount);`
|
|
@@ -1152,7 +1785,14 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
1152
1785
|
return h >>> 0;
|
|
1153
1786
|
}
|
|
1154
1787
|
findObjProp(obj, key) {
|
|
1155
|
-
|
|
1788
|
+
const own = obj.properties?.find((p) => p.key === key)?.value;
|
|
1789
|
+
if (own !== void 0) return own;
|
|
1790
|
+
if (obj.template) {
|
|
1791
|
+
const tpl = this.templatesByName.get(obj.template);
|
|
1792
|
+
const fromTemplate = tpl?.properties?.find((p) => p.key === key)?.value;
|
|
1793
|
+
if (fromTemplate !== void 0) return fromTemplate;
|
|
1794
|
+
}
|
|
1795
|
+
return void 0;
|
|
1156
1796
|
}
|
|
1157
1797
|
extractObjectProperties(obj) {
|
|
1158
1798
|
const properties = {};
|
|
@@ -1204,16 +1844,29 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
1204
1844
|
return [0, 0, 0];
|
|
1205
1845
|
}
|
|
1206
1846
|
geometryVertexDataFn(meshType) {
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
}
|
|
1216
|
-
return
|
|
1847
|
+
return resolveGeometry(meshType).webgpuVertexFn;
|
|
1848
|
+
}
|
|
1849
|
+
materialName(material) {
|
|
1850
|
+
if (typeof material === "string") return material;
|
|
1851
|
+
if (material && typeof material === "object") {
|
|
1852
|
+
const m = material;
|
|
1853
|
+
if (typeof m.type === "string") return m.type;
|
|
1854
|
+
if (typeof m.name === "string") return m.name;
|
|
1855
|
+
}
|
|
1856
|
+
return void 0;
|
|
1857
|
+
}
|
|
1858
|
+
// Self-illumination strength for a named material when no explicit emissive is
|
|
1859
|
+
// authored. Holographic/neon/emissive surfaces glow in their own color; glass/gel
|
|
1860
|
+
// gets a soft sheen; everything else stays purely lit (0).
|
|
1861
|
+
materialGlow(material) {
|
|
1862
|
+
const name = this.materialName(material);
|
|
1863
|
+
if (!name) return 0;
|
|
1864
|
+
const n = name.toLowerCase();
|
|
1865
|
+
if (/hologram|holo|liquid_glass|liquid_hologram|neon|glow|emissive|aura|plasma|energy/.test(n)) {
|
|
1866
|
+
return 0.65;
|
|
1867
|
+
}
|
|
1868
|
+
if (/glass|crystal|gel|water/.test(n)) return 0.28;
|
|
1869
|
+
return 0;
|
|
1217
1870
|
}
|
|
1218
1871
|
};
|
|
1219
1872
|
}
|
|
@@ -1221,5 +1874,11 @@ var init_WebGPUCompiler = chunkZHPMP447_cjs.__esm({
|
|
|
1221
1874
|
|
|
1222
1875
|
exports.WebGPUCompiler_exports = WebGPUCompiler_exports;
|
|
1223
1876
|
exports.init_WebGPUCompiler = init_WebGPUCompiler;
|
|
1224
|
-
|
|
1225
|
-
|
|
1877
|
+
exports.init_geometry_purpose = init_geometry_purpose;
|
|
1878
|
+
exports.init_geometry_registry = init_geometry_registry;
|
|
1879
|
+
exports.init_skybox_registry = init_skybox_registry;
|
|
1880
|
+
exports.resolveGeometry = resolveGeometry;
|
|
1881
|
+
exports.resolveGeometryRole = resolveGeometryRole;
|
|
1882
|
+
exports.resolveSkyboxColor = resolveSkyboxColor;
|
|
1883
|
+
//# sourceMappingURL=chunk-U6CQOM5Q.cjs.map
|
|
1884
|
+
//# sourceMappingURL=chunk-U6CQOM5Q.cjs.map
|