From 376020f80cd051f1a38d4f5f8b7a08e82b597ef7 Mon Sep 17 00:00:00 2001 From: AlexZ005 Date: Thu, 8 Oct 2026 05:36:42 +0300 Subject: [PATCH] [feat] item dims on every row: size, box, tris, bytes, animated (core roadmap 39 P4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - tools/kit-build/lib/dims.mjs + `kit-build dims [pack…|--all] [--write] [--remote]`: measures each row's LOD0 (inspectGlb) and writes size [w, h, d] metres, box [minX..maxZ], tris, bytes and animated: true for files with clips. Number arrays stay on one line; the file keeps its own indent and newline style. - the CI: a `dims` check (missing or stale against the measured file, 1.5 mm slack on the bounds) + row-shape rules (dimsShapeProblems); `build` and `pass --write` re-measure, so a decimation can never leave a stale row behind. - one-off backfill of all 252 rows in the 12 model lists, the 21 Khronos rows measured from a --remote download (their bytes stay upstream). - tests: dims.test.mjs (5) + a missing-dims check test; the fixture writes measured dims so every other check test stays focused. 38/38 green; check 0 errors. Core reads these before any download (the drag-to-place ghost's W x D x H and the Explorer's download size). Serving needs the usual `format-1` retag + purge. Co-Authored-By: Claude Opus 5.5 (1M context) --- README.md | 5 + arcane-kit/default.json | 42 ++++- architecture-kit/default.json | 192 +++++++++++++++++---- avatars/default.json | 63 ++++++- cube_diorama/default.json | 72 ++++++-- default/default.json | 18 +- interactive-kit/default.json | 133 ++++++++++++--- interior-kit/default.json | 180 ++++++++++++++++---- khronos-sample-assets/model-index-tp.json | 129 +++++++++++--- nature-kit/default.json | 186 ++++++++++++++++---- props-kit/default.json | 198 ++++++++++++++++++---- scifi-kit/default.json | 168 +++++++++++++++--- tools/kit-build/README.md | 2 + tools/kit-build/kit-build.mjs | 14 ++ tools/kit-build/lib/check.mjs | 6 + tools/kit-build/lib/dims.mjs | 132 +++++++++++++++ tools/kit-build/lib/pass.mjs | 5 + tools/kit-build/lib/rules.mjs | 21 ++- tools/kit-build/test/check.test.mjs | 7 + tools/kit-build/test/dims.test.mjs | 50 ++++++ tools/kit-build/test/fixture.mjs | 11 +- town-kit/default.json | 163 +++++++++++++++--- 22 files changed, 1543 insertions(+), 254 deletions(-) create mode 100644 tools/kit-build/lib/dims.mjs create mode 100644 tools/kit-build/test/dims.test.mjs diff --git a/README.md b/README.md index 6bbd70a..2832340 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,11 @@ tools/avatars/ their build: merge to one skinned mesh + 1 mate runtime/ = what core ships in static/avatars/ ``` +Each item row in a model list also carries its measured **`size`** (`[w, h, d]` metres), **`box`**, +**`tris`**, **`bytes`** (and `animated: true` for a rigged/clipped file) — written by +`node tools/kit-build/kit-build.mjs dims --write`, checked by the CI. The app reads them to +draw an item's size while it is dragged in, before the file downloads. + Each `index.json` row: `{name, title, value | zip, attribution, copyright, license, source}` — `value` points at a model-list JSON (relative to this repo), `zip` at a self-describing installable pack. The formats are documented in the app repo's diff --git a/arcane-kit/default.json b/arcane-kit/default.json index 403bd05..f90be9e 100644 --- a/arcane-kit/default.json +++ b/arcane-kit/default.json @@ -15,7 +15,11 @@ "file": "crystal-ball.lod2.glb", "ratio": 0.53 } - ] + ], + "size": [0.492, 0.55, 0.491], + "box": [-0.246, 0, -0.245, 0.246, 0.55, 0.246], + "tris": 3122, + "bytes": 644660 }, { "name": "AlchemyTable", @@ -33,7 +37,11 @@ "file": "alchemy-table.lod2.glb", "ratio": 0.32 } - ] + ], + "size": [1.6, 1.112, 0.876], + "box": [-0.8, 0, -0.438, 0.8, 1.112, 0.438], + "tris": 6000, + "bytes": 772996 }, { "name": "Lectern", @@ -47,7 +55,11 @@ "file": "lectern.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [0.978, 1.25, 0.612], + "box": [-0.489, 0, -0.306, 0.489, 1.25, 0.306], + "tris": 3499, + "bytes": 758216 }, { "name": "Telescope", @@ -61,7 +73,11 @@ "file": "telescope.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [1.6, 1.6, 0.48], + "box": [-0.8, 0, -0.24, 0.8, 1.6, 0.24], + "tris": 3691, + "bytes": 639320 }, { "name": "Armillary", @@ -75,7 +91,11 @@ "file": "armillary.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [0.845, 0.9, 0.812], + "box": [-0.422, 0, -0.406, 0.423, 0.9, 0.406], + "tris": 4999, + "bytes": 905256 }, { "name": "PotionShelf", @@ -93,7 +113,11 @@ "file": "potion-shelf.lod2.glb", "ratio": 0.21 } - ] + ], + "size": [1.109, 1.8, 0.44], + "box": [-0.554, 0, -0.22, 0.555, 1.8, 0.22], + "tris": 5999, + "bytes": 891424 }, { "name": "RuneRug", @@ -107,6 +131,10 @@ "file": "rune-rug.lod1.glb", "ratio": 0.72 } - ] + ], + "size": [2.4, 0.02, 2.4], + "box": [-1.2, 0, -1.2, 1.2, 0.02, 1.2], + "tris": 601, + "bytes": 894440 } ] diff --git a/architecture-kit/default.json b/architecture-kit/default.json index b572cd0..aefba8f 100644 --- a/architecture-kit/default.json +++ b/architecture-kit/default.json @@ -11,7 +11,11 @@ "file": "wall-stone.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2, 3, 0.25], + "box": [-1, 0, -0.125, 1, 3, 0.125], + "tris": 3067, + "bytes": 845280 }, { "name": "WallStoneDoor", @@ -25,7 +29,11 @@ "file": "wall-stone-door.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2, 3, 0.25], + "box": [-1, 0, -0.125, 1, 3, 0.125], + "tris": 2606, + "bytes": 823632 }, { "name": "WallStoneWindow", @@ -39,7 +47,11 @@ "file": "wall-stone-window.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2, 3, 0.25], + "box": [-1, 0, -0.125, 1, 3, 0.125], + "tris": 3694, + "bytes": 867952 }, { "name": "WallStoneHalf", @@ -53,7 +65,11 @@ "file": "wall-stone-half.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2, 1.5, 0.25], + "box": [-1, 0, -0.125, 1, 1.5, 0.125], + "tris": 1629, + "bytes": 780996 }, { "name": "WallStoneGable", @@ -67,7 +83,11 @@ "file": "wall-stone-gable.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2, 1.5, 0.25], + "box": [-1, 0, -0.125, 1, 1.5, 0.125], + "tris": 982, + "bytes": 752188 }, { "name": "CornerPostStone", @@ -81,7 +101,11 @@ "file": "corner-post-stone.lod1.glb", "ratio": 0.58 } - ] + ], + "size": [0.25, 3, 0.25], + "box": [-0.125, 0, -0.125, 0.125, 3, 0.125], + "tris": 676, + "bytes": 739848 }, { "name": "WallPlaster", @@ -95,7 +119,11 @@ "file": "wall-plaster.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2, 3, 0.25], + "box": [-1, 0, -0.125, 1, 3, 0.125], + "tris": 3067, + "bytes": 561552 }, { "name": "WallPlasterDoor", @@ -109,7 +137,11 @@ "file": "wall-plaster-door.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2, 3, 0.25], + "box": [-1, 0, -0.125, 1, 3, 0.125], + "tris": 2606, + "bytes": 539904 }, { "name": "WallPlasterWindow", @@ -127,7 +159,11 @@ "file": "wall-plaster-window.lod2.glb", "ratio": 0.36 } - ] + ], + "size": [2, 3, 0.25], + "box": [-1, 0, -0.125, 1, 3, 0.125], + "tris": 3694, + "bytes": 584224 }, { "name": "WallPlasterHalf", @@ -141,7 +177,11 @@ "file": "wall-plaster-half.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2, 1.5, 0.25], + "box": [-1, 0, -0.125, 1, 1.5, 0.125], + "tris": 1629, + "bytes": 497276 }, { "name": "WallPlasterGable", @@ -155,7 +195,11 @@ "file": "wall-plaster-gable.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2, 1.5, 0.25], + "box": [-1, 0, -0.125, 1, 1.5, 0.125], + "tris": 982, + "bytes": 468460 }, { "name": "Pillar", @@ -169,7 +213,11 @@ "file": "pillar.lod1.glb", "ratio": 0.59 } - ] + ], + "size": [0.5, 3, 0.5], + "box": [-0.25, 0, -0.25, 0.25, 3, 0.25], + "tris": 1410, + "bytes": 539776 }, { "name": "Column", @@ -187,7 +235,11 @@ "file": "column.lod2.glb", "ratio": 0.32 } - ] + ], + "size": [0.5, 3, 0.5], + "box": [-0.25, 0, -0.25, 0.25, 3, 0.25], + "tris": 1999, + "bytes": 498320 }, { "name": "Arch", @@ -201,7 +253,11 @@ "file": "arch.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2, 3, 0.5], + "box": [-1, 0, -0.25, 1, 3, 0.25], + "tris": 3492, + "bytes": 409620 }, { "name": "FloorStone", @@ -215,7 +271,11 @@ "file": "floor-stone.lod1.glb", "ratio": 0.66 } - ] + ], + "size": [2, 0.1, 2], + "box": [-1, 0, -1, 1, 0.1, 1], + "tris": 1504, + "bytes": 629516 }, { "name": "FloorWood", @@ -229,7 +289,11 @@ "file": "floor-wood.lod1.glb", "ratio": 0.66 } - ] + ], + "size": [2, 0.1, 2], + "box": [-1, 0, -1, 1, 0.1, 1], + "tris": 1504, + "bytes": 495796 }, { "name": "FloorSlate", @@ -243,7 +307,11 @@ "file": "floor-slate.lod1.glb", "ratio": 0.66 } - ] + ], + "size": [2, 0.1, 2], + "box": [-1, 0, -1, 1, 0.1, 1], + "tris": 1504, + "bytes": 535740 }, { "name": "Stairs", @@ -261,7 +329,11 @@ "file": "stairs.lod2.glb", "ratio": 0.35 } - ] + ], + "size": [2, 3, 4], + "box": [-1, 0, -2, 1, 3, 2], + "tris": 2932, + "bytes": 728612 }, { "name": "StairsWood", @@ -279,7 +351,11 @@ "file": "stairs-wood.lod2.glb", "ratio": 0.34 } - ] + ], + "size": [2, 3, 4], + "box": [-1, 0, -2, 1, 3, 2], + "tris": 2940, + "bytes": 418224 }, { "name": "Block", @@ -293,7 +369,11 @@ "file": "block.lod1.glb", "ratio": 0.65 } - ] + ], + "size": [2, 1, 2], + "box": [-1, 0, -1, 1, 1, 1], + "tris": 1404, + "bytes": 675248 }, { "name": "Ramp", @@ -311,7 +391,11 @@ "file": "ramp.lod2.glb", "ratio": 0.61 } - ] + ], + "size": [2, 1, 2], + "box": [-1, 0, -1, 1, 1, 1], + "tris": 1399, + "bytes": 675416 }, { "name": "RoofSlope", @@ -325,7 +409,11 @@ "file": "roof-slope.lod1.glb", "ratio": 0.79 } - ] + ], + "size": [2, 1.5, 2], + "box": [-1, 0, -1, 1, 1.5, 1], + "tris": 1592, + "bytes": 399364 }, { "name": "Battlement", @@ -339,7 +427,11 @@ "file": "battlement.lod1.glb", "ratio": 0.64 } - ] + ], + "size": [2, 1.2, 0.25], + "box": [-1, 0, -0.125, 1, 1.2, 0.125], + "tris": 2466, + "bytes": 695440 }, { "name": "Tower", @@ -353,7 +445,11 @@ "file": "tower.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [4, 3, 4], + "box": [-2, 0, -2, 2, 3, 2], + "tris": 5000, + "bytes": 885548 }, { "name": "Door", @@ -367,7 +463,11 @@ "file": "door.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [1.3, 2.35, 0.33], + "box": [-0.65, 0, -0.165, 0.65, 2.35, 0.165], + "tris": 2512, + "bytes": 473552 }, { "name": "Window", @@ -381,7 +481,11 @@ "file": "window.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [1.1, 1.25, 0.5], + "box": [-0.55, 0.975, -0.25, 0.55, 2.225, 0.25], + "tris": 2500, + "bytes": 571612 }, { "name": "Gate", @@ -399,7 +503,11 @@ "file": "gate.lod2.glb", "ratio": 0.2 } - ] + ], + "size": [2, 3, 0.2], + "box": [-1, 0, -0.1, 1, 3, 0.1], + "tris": 2841, + "bytes": 443080 }, { "name": "Fence", @@ -417,7 +525,11 @@ "file": "fence.lod2.glb", "ratio": 0.21 } - ] + ], + "size": [2, 1, 0.15], + "box": [-1, 0, -0.075, 1, 1, 0.075], + "tris": 1462, + "bytes": 416436 }, { "name": "Railing", @@ -435,7 +547,11 @@ "file": "railing.lod2.glb", "ratio": 0.25 } - ] + ], + "size": [2, 1, 0.15], + "box": [-1, 0, -0.075, 1, 1, 0.075], + "tris": 2500, + "bytes": 497032 }, { "name": "Beam", @@ -449,7 +565,11 @@ "file": "beam.lod1.glb", "ratio": 0.55 } - ] + ], + "size": [2, 0.3, 0.3], + "box": [-1, 0, -0.15, 1, 0.3, 0.15], + "tris": 884, + "bytes": 323196 }, { "name": "Trim", @@ -463,7 +583,11 @@ "file": "trim.lod1.glb", "ratio": 0.58 } - ] + ], + "size": [2, 0.2, 0.45], + "box": [-1, 0, -0.225, 1, 0.2, 0.225], + "tris": 884, + "bytes": 490520 }, { "name": "Chimney", @@ -477,6 +601,10 @@ "file": "chimney.lod1.glb", "ratio": 0.71 } - ] + ], + "size": [0.7, 1.6, 0.7], + "box": [-0.35, 0, -0.35, 0.35, 1.6, 0.35], + "tris": 1410, + "bytes": 539848 } ] diff --git a/avatars/default.json b/avatars/default.json index 0b88a7f..10c0f45 100644 --- a/avatars/default.json +++ b/avatars/default.json @@ -11,7 +11,12 @@ "clip": "Idle", "trigger": "click", "autoplay": true - } + }, + "size": [1.942, 2.467, 1.253], + "box": [-0.971, 0, -0.542, 0.971, 2.467, 0.711], + "tris": 4712, + "bytes": 497264, + "animated": true }, { "name": "Mage", @@ -25,7 +30,12 @@ "clip": "Idle", "trigger": "click", "autoplay": true - } + }, + "size": [2.093, 2.716, 2.04], + "box": [-1.046, 0, -1.017, 1.047, 2.716, 1.023], + "tris": 4509, + "bytes": 477352, + "animated": true }, { "name": "Rogue", @@ -39,7 +49,12 @@ "clip": "Idle", "trigger": "click", "autoplay": true - } + }, + "size": [1.942, 2.187, 1.015], + "box": [-0.971, 0, -0.496, 0.971, 2.187, 0.519], + "tris": 4347, + "bytes": 461980, + "animated": true }, { "name": "HoodedRogue", @@ -53,7 +68,12 @@ "clip": "Idle", "trigger": "click", "autoplay": true - } + }, + "size": [1.942, 2.251, 1.156], + "box": [-0.971, 0, -0.567, 0.971, 2.251, 0.589], + "tris": 4005, + "bytes": 442292, + "animated": true }, { "name": "Barbarian", @@ -67,7 +87,12 @@ "clip": "Idle", "trigger": "click", "autoplay": true - } + }, + "size": [1.942, 2.398, 1.264], + "box": [-0.971, 0, -0.525, 0.971, 2.398, 0.739], + "tris": 4777, + "bytes": 480244, + "animated": true }, { "name": "Skeleton", @@ -81,7 +106,12 @@ "clip": "Idle", "trigger": "click", "autoplay": true - } + }, + "size": [1.938, 2.166, 0.912], + "box": [-0.969, 0, -0.458, 0.969, 2.166, 0.454], + "tris": 5288, + "bytes": 540852, + "animated": true }, { "name": "SkeletonWarrior", @@ -95,7 +125,12 @@ "clip": "Idle", "trigger": "click", "autoplay": true - } + }, + "size": [1.942, 2.59, 1.459], + "box": [-0.971, 0, -0.758, 0.971, 2.59, 0.701], + "tris": 5934, + "bytes": 615228, + "animated": true }, { "name": "SkeletonMage", @@ -109,7 +144,12 @@ "clip": "Idle", "trigger": "click", "autoplay": true - } + }, + "size": [1.938, 2.63, 1.735], + "box": [-0.969, 0, -0.848, 0.969, 2.63, 0.887], + "tris": 4588, + "bytes": 491736, + "animated": true }, { "name": "SkeletonRogue", @@ -123,6 +163,11 @@ "clip": "Idle", "trigger": "click", "autoplay": true - } + }, + "size": [1.942, 2.308, 1.153], + "box": [-0.971, 0, -0.582, 0.971, 2.308, 0.571], + "tris": 5278, + "bytes": 563260, + "animated": true } ] diff --git a/cube_diorama/default.json b/cube_diorama/default.json index 2363bf6..f5067d1 100644 --- a/cube_diorama/default.json +++ b/cube_diorama/default.json @@ -5,7 +5,11 @@ "label": "Picture Frame", "variants": { "glTF-Binary": "cube_diorama-frame.glb" - } + }, + "size": [0.114, 0.951, 0.73], + "box": [-1, -0.251, -0.066, -0.886, 0.7, 0.664], + "tris": 80, + "bytes": 885780 }, { "name": "Shelf", @@ -13,7 +17,11 @@ "label": "Shelf", "variants": { "glTF-Binary": "cube_diorama-shelf.glb" - } + }, + "size": [0.183, 1.418, 0.524], + "box": [-0.912, -1, -0.712, -0.729, 0.418, -0.188], + "tris": 176, + "bytes": 2962600 }, { "name": "Cat", @@ -31,7 +39,11 @@ "file": "cat.lod2.glb", "ratio": 0.2 } - ] + ], + "size": [0.415, 0.094, 0.271], + "box": [0.05, -0.519, -0.716, 0.465, -0.425, -0.445], + "tris": 10054, + "bytes": 953944 }, { "name": "Desk", @@ -39,7 +51,11 @@ "label": "Desk", "variants": { "glTF-Binary": "desk.glb" - } + }, + "size": [1.304, 0.481, 0.589], + "box": [-0.512, -1, -0.936, 0.792, -0.519, -0.347], + "tris": 196, + "bytes": 2969588 }, { "name": "Dresser", @@ -57,7 +73,11 @@ "file": "dresser.lod2.glb", "ratio": 0.31 } - ] + ], + "size": [0.644, 0.528, 0.844], + "box": [-0.946, -1, -0.079, -0.302, -0.472, 0.765], + "tris": 2044, + "bytes": 4101388 }, { "name": "Floor", @@ -75,7 +95,11 @@ "file": "floor.lod2.glb", "ratio": 0.2 } - ] + ], + "size": [2, 0, 2], + "box": [-1, -1, -1, 1, -1, 1], + "tris": 8192, + "bytes": 493108 }, { "name": "Plant1", @@ -89,7 +113,11 @@ "file": "plant1.lod1.glb", "ratio": 0.51 } - ] + ], + "size": [0.16, 0.263, 0.167], + "box": [-0.9, -0.324, -0.551, -0.74, -0.061, -0.384], + "tris": 6368, + "bytes": 467476 }, { "name": "Plant2", @@ -103,7 +131,11 @@ "file": "plant2.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [0.626, 0.417, 0.678], + "box": [-0.998, -0.472, 0.137, -0.372, -0.055, 0.815], + "tris": 23250, + "bytes": 2216380 }, { "name": "Rug", @@ -111,7 +143,11 @@ "label": "Rug", "variants": { "glTF-Binary": "rug.glb" - } + }, + "size": [0.759, 0.017, 0.759], + "box": [-0.089, -1, -0.135, 0.67, -0.983, 0.624], + "tris": 640, + "bytes": 95712 }, { "name": "Wall1", @@ -119,7 +155,11 @@ "label": "Wall 1", "variants": { "glTF-Binary": "wall1.glb" - } + }, + "size": [1.966, 1.908, 0.139], + "box": [-1, -1, -1.139, 0.966, 0.908, -1], + "tris": 92, + "bytes": 384660 }, { "name": "Wall2", @@ -127,7 +167,11 @@ "label": "Wall 2", "variants": { "glTF-Binary": "wall2.glb" - } + }, + "size": [0, 1.9, 1.952], + "box": [-1, -1, -1, -1, 0.9, 0.952], + "tris": 2, + "bytes": 22196 }, { "name": "Window", @@ -135,6 +179,10 @@ "label": "Window", "variants": { "glTF-Binary": "window.glb" - } + }, + "size": [1.132, 0.784, 0.06], + "box": [-0.594, -0.253, -1.147, 0.538, 0.531, -1.087], + "tris": 84, + "bytes": 11820 } ] diff --git a/default/default.json b/default/default.json index a1adcb9..e042b3d 100644 --- a/default/default.json +++ b/default/default.json @@ -5,7 +5,11 @@ "label": "The Prototype Logo", "variants": { "glTF-Binary": "ThePrototype-Logo.glb" - } + }, + "size": [6.046, 7.732, 5.197], + "box": [-5.046, -3.141, -4.197, 1, 4.591, 1], + "tris": 112, + "bytes": 7008 }, { "name": "SvelteRune", @@ -13,7 +17,11 @@ "label": "Svelte Rune", "variants": { "glTF-Binary": "SvelteRune.glb" - } + }, + "size": [1.76, 2.397, 2.086], + "box": [-0.021, -1.143, 0.137, 1.739, 1.254, 2.223], + "tris": 17612, + "bytes": 3704300 }, { "name": "Duck", @@ -31,6 +39,10 @@ "file": "Duck.lod2.glb", "ratio": 0.2 } - ] + ], + "size": [1.655, 1.541, 1.152], + "box": [-0.693, 0.099, -0.613, 0.962, 1.64, 0.539], + "tris": 4212, + "bytes": 120484 } ] diff --git a/interactive-kit/default.json b/interactive-kit/default.json index f6ca80d..d05945d 100644 --- a/interactive-kit/default.json +++ b/interactive-kit/default.json @@ -20,7 +20,12 @@ "file": "door-wood.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [1.3, 2.35, 0.329], + "box": [-0.65, 0, -0.164, 0.65, 2.35, 0.165], + "tris": 2850, + "bytes": 494980, + "animated": true }, { "name": "DoorStudded", @@ -47,7 +52,12 @@ "file": "door-studded.lod2.glb", "ratio": 0.22 } - ] + ], + "size": [1.36, 2.35, 0.35], + "box": [-0.68, 0, -0.175, 0.68, 2.35, 0.175], + "tris": 2493, + "bytes": 675688, + "animated": true }, { "name": "DoorDouble", @@ -74,7 +84,12 @@ "file": "door-double.lod2.glb", "ratio": 0.28 } - ] + ], + "size": [2, 3, 0.25], + "box": [-1, 0, -0.125, 1, 3, 0.125], + "tris": 4716, + "bytes": 1245956, + "animated": true }, { "name": "IronGate", @@ -101,7 +116,12 @@ "file": "iron-gate.lod2.glb", "ratio": 0.42 } - ] + ], + "size": [2.5, 3, 0.5], + "box": [-1.25, 0, -0.25, 1.25, 3, 0.25], + "tris": 5857, + "bytes": 1049016, + "animated": true }, { "name": "Portcullis", @@ -124,7 +144,12 @@ "file": "portcullis.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2, 4.5, 0.25], + "box": [-1, 0, -0.125, 1, 4.5, 0.125], + "tris": 6208, + "bytes": 1414316, + "animated": true }, { "name": "SlidingDoor", @@ -151,7 +176,12 @@ "file": "sliding-door.lod2.glb", "ratio": 0.33 } - ] + ], + "size": [1.5, 2.6, 0.3], + "box": [-0.75, 0, -0.15, 0.75, 2.6, 0.15], + "tris": 3291, + "bytes": 299356, + "animated": true }, { "name": "WallSlidingDoor", @@ -178,7 +208,12 @@ "file": "wall-sliding-door.lod2.glb", "ratio": 0.36 } - ] + ], + "size": [2, 3, 0.3], + "box": [-1, 0, -0.15, 1, 3, 0.15], + "tris": 4618, + "bytes": 507812, + "animated": true }, { "name": "Trapdoor", @@ -205,7 +240,12 @@ "file": "trapdoor.lod2.glb", "ratio": 0.36 } - ] + ], + "size": [1.24, 0.1, 1.24], + "box": [-0.62, 0, -0.62, 0.62, 0.1, 0.62], + "tris": 546, + "bytes": 89660, + "animated": true }, { "name": "Shutters", @@ -228,7 +268,12 @@ "file": "shutters.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [1.549, 1.25, 0.483], + "box": [-0.773, 0.975, -0.25, 0.776, 2.225, 0.233], + "tris": 2564, + "bytes": 579808, + "animated": true }, { "name": "Chest", @@ -255,7 +300,12 @@ "file": "chest.lod2.glb", "ratio": 0.3 } - ] + ], + "size": [0.768, 0.6, 0.686], + "box": [-0.384, 0, -0.343, 0.384, 0.6, 0.343], + "tris": 3112, + "bytes": 819972, + "animated": true }, { "name": "Crate", @@ -278,7 +328,12 @@ "file": "crate.lod1.glb", "ratio": 0.74 } - ] + ], + "size": [0.806, 0.55, 0.546], + "box": [-0.403, 0, -0.273, 0.403, 0.55, 0.273], + "tris": 2744, + "bytes": 719580, + "animated": true }, { "name": "Cabinet", @@ -305,7 +360,12 @@ "file": "cabinet.lod2.glb", "ratio": 0.29 } - ] + ], + "size": [1, 1.5, 0.5], + "box": [-0.5, 0, -0.25, 0.5, 1.5, 0.25], + "tris": 3839, + "bytes": 391476, + "animated": true }, { "name": "Drawers", @@ -332,7 +392,12 @@ "file": "drawers.lod2.glb", "ratio": 0.3 } - ] + ], + "size": [1, 1, 0.5], + "box": [-0.5, 0, -0.25, 0.5, 1, 0.25], + "tris": 4097, + "bytes": 548516, + "animated": true }, { "name": "Lever", @@ -347,7 +412,12 @@ "trigger": "click", "autoplay": false, "sound": "lever" - } + }, + "size": [0.34, 0.582, 0.427], + "box": [-0.17, 0, -0.307, 0.17, 0.582, 0.12], + "tris": 424, + "bytes": 135124, + "animated": true }, { "name": "PressurePlate", @@ -362,7 +432,12 @@ "trigger": "proximity", "autoplay": false, "sound": "click" - } + }, + "size": [1, 0.052, 1], + "box": [-0.5, 0, -0.5, 0.5, 0.052, 0.5], + "tris": 72, + "bytes": 89628, + "animated": true }, { "name": "WallButton", @@ -377,7 +452,12 @@ "trigger": "click", "autoplay": false, "sound": "click" - } + }, + "size": [0.2, 0.2, 0.095], + "box": [-0.1, 0, 0, 0.1, 0.2, 0.095], + "tris": 300, + "bytes": 101712, + "animated": true }, { "name": "Torch", @@ -401,7 +481,12 @@ "file": "torch.lod2.glb", "ratio": 0.41 } - ] + ], + "size": [0.105, 0.685, 0.324], + "box": [-0.052, 0, 0, 0.053, 0.685, 0.324], + "tris": 652, + "bytes": 143000, + "animated": true }, { "name": "Banner", @@ -425,7 +510,12 @@ "file": "banner.lod2.glb", "ratio": 0.28 } - ] + ], + "size": [1.34, 1.66, 0.09], + "box": [-0.67, 0, 0, 0.67, 1.66, 0.09], + "tris": 640, + "bytes": 445732, + "animated": true }, { "name": "CeilingFan", @@ -449,6 +539,11 @@ "file": "ceiling-fan.lod2.glb", "ratio": 0.38 } - ] + ], + "size": [1.3, 0.993, 1.3], + "box": [-0.65, -0.993, -0.65, 0.65, 0, 0.65], + "tris": 2536, + "bytes": 708192, + "animated": true } ] diff --git a/interior-kit/default.json b/interior-kit/default.json index 249392b..e8fb1bf 100644 --- a/interior-kit/default.json +++ b/interior-kit/default.json @@ -15,7 +15,11 @@ "file": "round-table.lod2.glb", "ratio": 0.28 } - ] + ], + "size": [0.95, 0.76, 0.95], + "box": [-0.475, 0, -0.475, 0.475, 0.76, 0.475], + "tris": 3000, + "bytes": 478852 }, { "name": "LongTable", @@ -29,7 +33,11 @@ "file": "long-table.lod1.glb", "ratio": 0.52 } - ] + ], + "size": [2.2, 0.78, 0.9], + "box": [-1.1, 0, -0.45, 1.1, 0.78, 0.45], + "tris": 3000, + "bytes": 703752 }, { "name": "Bench", @@ -43,7 +51,11 @@ "file": "bench.lod1.glb", "ratio": 0.76 } - ] + ], + "size": [1.8, 0.46, 0.36], + "box": [-0.9, 0, -0.18, 0.9, 0.46, 0.18], + "tris": 2000, + "bytes": 666504 }, { "name": "BarStool", @@ -57,7 +69,11 @@ "file": "bar-stool.lod1.glb", "ratio": 0.51 } - ] + ], + "size": [0.388, 0.75, 0.39], + "box": [-0.194, 0, -0.195, 0.194, 0.75, 0.195], + "tris": 1799, + "bytes": 350180 }, { "name": "Stool", @@ -71,7 +87,11 @@ "file": "stool.lod1.glb", "ratio": 0.63 } - ] + ], + "size": [0.38, 0.46, 0.38], + "box": [-0.19, 0, -0.19, 0.19, 0.46, 0.19], + "tris": 1500, + "bytes": 338848 }, { "name": "BarCounter", @@ -85,7 +105,11 @@ "file": "bar-counter.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2, 1.1, 0.7], + "box": [-1, 0, -0.35, 1, 1.1, 0.35], + "tris": 3999, + "bytes": 505548 }, { "name": "BackBar", @@ -103,7 +127,11 @@ "file": "back-bar.lod2.glb", "ratio": 0.37 } - ] + ], + "size": [2, 2, 0.5], + "box": [-1, 0, 0.125, 1, 2, 0.625], + "tris": 4990, + "bytes": 585740 }, { "name": "CrateGoods", @@ -117,7 +145,11 @@ "file": "crate-goods.lod1.glb", "ratio": 0.58 } - ] + ], + "size": [0.456, 0.5, 0.446], + "box": [-0.228, 0, -0.223, 0.228, 0.5, 0.223], + "tris": 3065, + "bytes": 665508 }, { "name": "Armchair", @@ -131,7 +163,11 @@ "file": "armchair.lod1.glb", "ratio": 0.52 } - ] + ], + "size": [0.896, 1.05, 1.002], + "box": [-0.448, 0, -0.501, 0.448, 1.05, 0.501], + "tris": 3897, + "bytes": 547604 }, { "name": "Sofa", @@ -145,7 +181,11 @@ "file": "sofa.lod1.glb", "ratio": 0.51 } - ] + ], + "size": [2.1, 0.85, 0.9], + "box": [-1.05, 0, -0.45, 1.05, 0.85, 0.45], + "tris": 4743, + "bytes": 454252 }, { "name": "DoubleBed", @@ -163,7 +203,11 @@ "file": "double-bed.lod2.glb", "ratio": 0.2 } - ] + ], + "size": [1.6, 1.15, 2.1], + "box": [-0.8, 0, 0.125, 0.8, 1.15, 2.225], + "tris": 4934, + "bytes": 468736 }, { "name": "Wardrobe", @@ -181,7 +225,11 @@ "file": "wardrobe.lod2.glb", "ratio": 0.33 } - ] + ], + "size": [1.2, 2, 0.6], + "box": [-0.6, 0, 0.125, 0.6, 2, 0.725], + "tris": 3961, + "bytes": 557832 }, { "name": "Plant", @@ -189,7 +237,11 @@ "label": "Snake plant in a teal pot", "variants": { "glTF-Binary": "plant.glb" - } + }, + "size": [0.35, 0.95, 0.343], + "box": [-0.175, 0, -0.171, 0.175, 0.95, 0.172], + "tris": 3989, + "bytes": 893364 }, { "name": "Desk", @@ -207,7 +259,11 @@ "file": "desk.lod2.glb", "ratio": 0.32 } - ] + ], + "size": [1.4, 0.76, 0.7], + "box": [-0.7, 0, -0.35, 0.7, 0.76, 0.35], + "tris": 3188, + "bytes": 457272 }, { "name": "KitchenCounter", @@ -225,7 +281,11 @@ "file": "kitchen-counter.lod2.glb", "ratio": 0.36 } - ] + ], + "size": [1, 0.92, 0.62], + "box": [-0.5, 0, 0.125, 0.5, 0.92, 0.745], + "tris": 3000, + "bytes": 428152 }, { "name": "Stove", @@ -243,7 +303,11 @@ "file": "stove.lod2.glb", "ratio": 0.22 } - ] + ], + "size": [0.9, 0.95, 0.65], + "box": [-0.45, 0, 0.125, 0.45, 0.95, 0.775], + "tris": 3873, + "bytes": 622844 }, { "name": "Fireplace", @@ -261,7 +325,11 @@ "file": "fireplace.lod2.glb", "ratio": 0.2 } - ] + ], + "size": [1.8, 1.6, 0.6], + "box": [-0.9, 0, 0.125, 0.9, 1.6, 0.725], + "tris": 4971, + "bytes": 642844 }, { "name": "WallSconce", @@ -269,7 +337,11 @@ "label": "Wall sconce (brass)", "variants": { "glTF-Binary": "wall-sconce.glb" - } + }, + "size": [0.124, 0.44, 0.204], + "box": [-0.062, 0, 0.125, 0.062, 0.44, 0.329], + "tris": 400, + "bytes": 56292 }, { "name": "FloorLamp", @@ -283,7 +355,11 @@ "file": "floor-lamp.lod1.glb", "ratio": 0.52 } - ] + ], + "size": [0.474, 1.655, 0.474], + "box": [-0.237, 0, -0.237, 0.237, 1.655, 0.237], + "tris": 1200, + "bytes": 139504 }, { "name": "Chandelier", @@ -291,7 +367,11 @@ "label": "Iron chandelier (hangs from y = 3)", "variants": { "glTF-Binary": "chandelier.glb" - } + }, + "size": [0.92, 0.92, 0.876], + "box": [-0.46, -0.92, -0.438, 0.46, 0, 0.438], + "tris": 4444, + "bytes": 229172 }, { "name": "RugRound", @@ -299,7 +379,11 @@ "label": "Round rug Ø 2 m (teal)", "variants": { "glTF-Binary": "rug-round.glb" - } + }, + "size": [2, 0.012, 2], + "box": [-1, 0, -1, 1, 0.012, 1], + "tris": 256, + "bytes": 452588 }, { "name": "Picture", @@ -307,7 +391,11 @@ "label": "Framed landscape (wall)", "variants": { "glTF-Binary": "picture.glb" - } + }, + "size": [0.924, 0.684, 0.045], + "box": [-0.462, 0, 0.121, 0.462, 0.684, 0.166], + "tris": 130, + "bytes": 154572 }, { "name": "WallShelfBooks", @@ -315,7 +403,11 @@ "label": "Wall shelf with books", "variants": { "glTF-Binary": "wall-shelf-books.glb" - } + }, + "size": [1.2, 0.833, 0.24], + "box": [-0.6, 0, 0.125, 0.6, 0.833, 0.365], + "tris": 860, + "bytes": 196536 }, { "name": "Skirting", @@ -323,7 +415,11 @@ "label": "Skirting (2 m, on a wall)", "variants": { "glTF-Binary": "skirting.glb" - } + }, + "size": [2, 0.252, 0.042], + "box": [-1, 0, 0.105, 1, 0.252, 0.147], + "tris": 64, + "bytes": 30292 }, { "name": "SkirtingDoorway", @@ -331,7 +427,11 @@ "label": "Skirting, doorway (2 m)", "variants": { "glTF-Binary": "skirting-doorway.glb" - } + }, + "size": [2, 0.252, 0.042], + "box": [-1, 0, 0.105, 1, 0.252, 0.147], + "tris": 56, + "bytes": 30620 }, { "name": "Wainscot", @@ -339,7 +439,11 @@ "label": "Wainscot panelling (2 m, teal)", "variants": { "glTF-Binary": "wainscot.glb" - } + }, + "size": [2, 0.93, 0.057], + "box": [-1, 0, 0.105, 1, 0.93, 0.162], + "tris": 166, + "bytes": 50248 }, { "name": "WainscotDoorway", @@ -347,7 +451,11 @@ "label": "Wainscot, doorway (2 m, teal)", "variants": { "glTF-Binary": "wainscot-doorway.glb" - } + }, + "size": [2, 0.93, 0.057], + "box": [-1, 0, 0.105, 1, 0.93, 0.162], + "tris": 136, + "bytes": 49664 }, { "name": "Cornice", @@ -355,7 +463,11 @@ "label": "Cornice (2 m, at the ceiling)", "variants": { "glTF-Binary": "cornice.glb" - } + }, + "size": [2, 0.21, 0.18], + "box": [-1, 2.79, 0.105, 1, 3, 0.285], + "tris": 100, + "bytes": 37936 }, { "name": "TavernTableSet", @@ -369,7 +481,11 @@ "file": "tavern-table-set.lod1.glb", "ratio": 0.63 } - ] + ], + "size": [1.8, 0.76, 1.8], + "box": [-0.9, 0, -0.9, 0.9, 0.76, 0.9], + "tris": 7498, + "bytes": 1003636 }, { "name": "DiningSet", @@ -383,6 +499,10 @@ "file": "dining-set.lod1.glb", "ratio": 0.65 } - ] + ], + "size": [2.2, 0.78, 1.8], + "box": [-1.1, 0, -0.9, 1.1, 0.78, 0.9], + "tris": 7000, + "bytes": 930688 } ] diff --git a/khronos-sample-assets/model-index-tp.json b/khronos-sample-assets/model-index-tp.json index 075521c..8e00725 100644 --- a/khronos-sample-assets/model-index-tp.json +++ b/khronos-sample-assets/model-index-tp.json @@ -5,7 +5,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/AntiqueCamera/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/AntiqueCamera/glTF-Binary/AntiqueCamera.glb" - } + }, + "size": [2.598, 7.209, 3.395], + "box": [-1.626, -0.001, -1.895, 0.972, 7.208, 1.5], + "tris": 20066, + "bytes": 17540348 }, { "name": "CesiumMilkTruck", @@ -13,7 +17,12 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/CesiumMilkTruck/screenshot/screenshot.gif", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/CesiumMilkTruck/glTF-Binary/CesiumMilkTruck.glb" - } + }, + "size": [2.792, 2.582, 4.869], + "box": [-1.396, 0.002, -2.431, 1.396, 2.584, 2.438], + "tris": 3624, + "bytes": 369980, + "animated": true }, { "name": "ChairDamaskPurplegold", @@ -21,7 +30,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/ChairDamaskPurplegold/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/ChairDamaskPurplegold/glTF-Binary/ChairDamaskPurplegold.glb" - } + }, + "size": [0.829, 0.687, 0.572], + "box": [-0.415, 0, -0.277, 0.414, 0.687, 0.295], + "tris": 9984, + "bytes": 2028924 }, { "name": "ClearCoatCarPaint", @@ -29,7 +42,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/ClearCoatCarPaint/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/ClearCoatCarPaint/glTF-Binary/ClearCoatCarPaint.glb" - } + }, + "size": [1, 0.98, 1], + "box": [-0.5, 0.01, -0.5, 0.5, 0.99, 0.5], + "tris": 3072, + "bytes": 116948 }, { "name": "ClearcoatWicker", @@ -37,7 +54,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/ClearcoatWicker/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/ClearcoatWicker/glTF-Binary/ClearcoatWicker.glb" - } + }, + "size": [1, 0.98, 1], + "box": [-0.5, 0.01, -0.5, 0.5, 0.99, 0.5], + "tris": 3072, + "bytes": 1299752 }, { "name": "DamagedHelmet", @@ -45,7 +66,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/DamagedHelmet/screenshot/screenshot.png", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/DamagedHelmet/glTF-Binary/DamagedHelmet.glb" - } + }, + "size": [1.89, 1.802, 2], + "box": [-0.947, -0.901, -1.187, 0.943, 0.901, 0.813], + "tris": 15452, + "bytes": 3773916 }, { "name": "DragonAttenuation", @@ -53,7 +78,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/DragonAttenuation/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/DragonAttenuation/glTF-Binary/DragonAttenuation.glb" - } + }, + "size": [6.309, 3.572, 6.612], + "box": [-3.03, -0.836, -1.783, 3.279, 2.736, 4.829], + "tris": 134995, + "bytes": 6401616 }, { "name": "DragonDispersion", @@ -61,7 +90,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/DragonDispersion/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/DragonDispersion/glTF-Binary/DragonDispersion.glb" - } + }, + "size": [6.309, 3.572, 6.612], + "box": [-3.03, -0.832, -1.783, 3.279, 2.74, 4.829], + "tris": 134995, + "bytes": 6401724 }, { "name": "Duck", @@ -69,7 +102,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Duck/screenshot/screenshot.png", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Duck/glTF-Binary/Duck.glb" - } + }, + "size": [1.655, 1.541, 1.152], + "box": [-0.693, 0.099, -0.613, 0.962, 1.64, 0.539], + "tris": 4212, + "bytes": 120484 }, { "name": "GlamVelvetSofa", @@ -77,7 +114,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/GlamVelvetSofa/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/GlamVelvetSofa/glTF-Binary/GlamVelvetSofa.glb" - } + }, + "size": [2.189, 0.788, 1.023], + "box": [-1.114, 0, -0.628, 1.075, 0.788, 0.395], + "tris": 4196, + "bytes": 3149844 }, { "name": "IridescenceLamp", @@ -85,7 +126,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/IridescenceLamp/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/IridescenceLamp/glTF-Binary/IridescenceLamp.glb" - } + }, + "size": [0.298, 0.476, 0.302], + "box": [-0.149, 0, -0.151, 0.149, 0.476, 0.151], + "tris": 18866, + "bytes": 4083912 }, { "name": "Lantern", @@ -93,7 +138,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Lantern/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Lantern/glTF-Binary/Lantern.glb" - } + }, + "size": [15.491, 25.664, 4.632], + "box": [-3.922, 0.184, -2.316, 11.569, 25.848, 2.316], + "tris": 5394, + "bytes": 9564264 }, { "name": "LightsPunctualLamp", @@ -101,7 +150,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/LightsPunctualLamp/screenshot/screenshot.png", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/LightsPunctualLamp/glTF-Binary/LightsPunctualLamp.glb" - } + }, + "size": [1.127, 1.864, 0.722], + "box": [-0.312, 0.011, -0.362, 0.815, 1.875, 0.36], + "tris": 6000, + "bytes": 4341320 }, { "name": "MosquitoInAmber", @@ -109,7 +162,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/MosquitoInAmber/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/MosquitoInAmber/glTF-Binary/MosquitoInAmber.glb" - } + }, + "size": [0.098, 0.099, 0.088], + "box": [-0.05, -0.048, -0.051, 0.048, 0.051, 0.037], + "tris": 14349, + "bytes": 24229904 }, { "name": "RiggedFigure", @@ -117,7 +174,12 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/RiggedFigure/screenshot/screenshot.gif", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/RiggedFigure/glTF-Binary/RiggedFigure.glb" - } + }, + "size": [1.179, 1.45, 0.326], + "box": [-0.589, 0, -0.131, 0.59, 1.45, 0.195], + "tris": 256, + "bytes": 50116, + "animated": true }, { "name": "RiggedSimple", @@ -125,7 +187,12 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/RiggedSimple/screenshot/screenshot.gif", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/RiggedSimple/glTF-Binary/RiggedSimple.glb" - } + }, + "size": [2, 9.15, 2], + "box": [-1, -4.575, -1, 1, 4.575, 1], + "tris": 188, + "bytes": 15104, + "animated": true }, { "name": "SheenChair", @@ -133,7 +200,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/SheenChair/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/SheenChair/glTF-Binary/SheenChair.glb" - } + }, + "size": [0.827, 0.686, 0.571], + "box": [-0.414, 0, -0.277, 0.413, 0.686, 0.294], + "tris": 39936, + "bytes": 4125648 }, { "name": "SheenWoodLeatherSofa", @@ -141,7 +212,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/SheenWoodLeatherSofa/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/SheenWoodLeatherSofa/glTF-Binary/SheenWoodLeatherSofa.glb" - } + }, + "size": [2.726, 1.117, 0.924], + "box": [-1.363, 0.001, -0.463, 1.363, 1.118, 0.461], + "tris": 46492, + "bytes": 10107912 }, { "name": "SpecularSilkPouf", @@ -149,7 +224,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/SpecularSilkPouf/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/SpecularSilkPouf/glTF-Binary/SpecularSilkPouf.glb" - } + }, + "size": [0.61, 0.198, 0.61], + "box": [-0.305, 0, -0.305, 0.305, 0.198, 0.305], + "tris": 81280, + "bytes": 4632512 }, { "name": "ToyCar", @@ -157,7 +236,11 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/ToyCar/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/ToyCar/glTF-Binary/ToyCar.glb" - } + }, + "size": [0.073, 0.029, 0.074], + "box": [-0.035, -0.016, -0.037, 0.038, 0.013, 0.037], + "tris": 108936, + "bytes": 5422412 }, { "name": "WaterBottle", @@ -165,6 +248,10 @@ "screenshot": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/WaterBottle/screenshot/screenshot.jpg", "variants": { "glTF-Binary": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/WaterBottle/glTF-Binary/WaterBottle.glb" - } + }, + "size": [0.109, 0.26, 0.109], + "box": [-0.054, -0.13, -0.054, 0.055, 0.13, 0.055], + "tris": 4510, + "bytes": 8966700 } ] diff --git a/nature-kit/default.json b/nature-kit/default.json index 609cf61..e54a045 100644 --- a/nature-kit/default.json +++ b/nature-kit/default.json @@ -11,7 +11,11 @@ "file": "Oak.lod1.glb", "ratio": 0.74 } - ] + ], + "size": [3.754, 6, 3.972], + "box": [-1.877, 0, -1.986, 1.877, 6, 1.986], + "tris": 12518, + "bytes": 1501108 }, { "name": "OakAutumn", @@ -25,7 +29,11 @@ "file": "OakAutumn.lod1.glb", "ratio": 0.74 } - ] + ], + "size": [3.754, 6, 3.972], + "box": [-1.877, 0, -1.986, 1.877, 6, 1.986], + "tris": 12518, + "bytes": 1519028 }, { "name": "Pine", @@ -39,7 +47,11 @@ "file": "Pine.lod1.glb", "ratio": 0.7 } - ] + ], + "size": [2.602, 8, 2.496], + "box": [-1.301, 0, -1.248, 1.301, 8, 1.248], + "tris": 8999, + "bytes": 1281556 }, { "name": "Birch", @@ -47,7 +59,11 @@ "label": "Birch Tree (young)", "variants": { "glTF-Binary": "Birch.glb" - } + }, + "size": [2.506, 7, 2.69], + "box": [-1.253, 0, -1.345, 1.253, 7, 1.345], + "tris": 9188, + "bytes": 1110056 }, { "name": "DeadTree", @@ -61,7 +77,11 @@ "file": "DeadTree.lod1.glb", "ratio": 0.71 } - ] + ], + "size": [2.917, 5, 2.938], + "box": [-1.458, 0, -1.469, 1.459, 5, 1.469], + "tris": 5999, + "bytes": 1115148 }, { "name": "Palm", @@ -69,7 +89,11 @@ "label": "Palm Tree", "variants": { "glTF-Binary": "Palm.glb" - } + }, + "size": [3.94, 7, 4.072], + "box": [-1.97, 0, -2.036, 1.97, 7, 2.036], + "tris": 7999, + "bytes": 1125648 }, { "name": "Bush", @@ -77,7 +101,11 @@ "label": "Bush", "variants": { "glTF-Binary": "Bush.glb" - } + }, + "size": [1.864, 1.1, 1.874], + "box": [-0.932, 0, -0.937, 0.932, 1.1, 0.937], + "tris": 2828, + "bytes": 804412 }, { "name": "BushAutumn", @@ -85,7 +113,11 @@ "label": "Bush (autumn)", "variants": { "glTF-Binary": "BushAutumn.glb" - } + }, + "size": [1.864, 1.1, 1.874], + "box": [-0.932, 0, -0.937, 0.932, 1.1, 0.937], + "tris": 2828, + "bytes": 817900 }, { "name": "Fern", @@ -93,7 +125,11 @@ "label": "Fern", "variants": { "glTF-Binary": "Fern.glb" - } + }, + "size": [1.166, 0.8, 1.164], + "box": [-0.583, 0, -0.582, 0.583, 0.8, 0.582], + "tris": 2126, + "bytes": 887748 }, { "name": "Reeds", @@ -101,7 +137,11 @@ "label": "Reeds (cattails)", "variants": { "glTF-Binary": "Reeds.glb" - } + }, + "size": [0.803, 1.3, 0.848], + "box": [-0.401, 0, -0.424, 0.402, 1.3, 0.424], + "tris": 1453, + "bytes": 789720 }, { "name": "GrassTuft", @@ -109,7 +149,11 @@ "label": "Grass Tuft", "variants": { "glTF-Binary": "GrassTuft.glb" - } + }, + "size": [0.738, 0.375, 0.679], + "box": [-0.345, 0, -0.347, 0.393, 0.375, 0.332], + "tris": 240, + "bytes": 14068 }, { "name": "GrassTuftDry", @@ -117,7 +161,11 @@ "label": "Grass Tuft (dry)", "variants": { "glTF-Binary": "GrassTuftDry.glb" - } + }, + "size": [0.548, 0.306, 0.59], + "box": [-0.258, 0, -0.252, 0.29, 0.306, 0.338], + "tris": 240, + "bytes": 14092 }, { "name": "Flowers", @@ -125,7 +173,11 @@ "label": "Wildflowers (amber)", "variants": { "glTF-Binary": "Flowers.glb" - } + }, + "size": [0.154, 0.5, 0.204], + "box": [-0.077, 0, -0.102, 0.077, 0.5, 0.102], + "tris": 1583, + "bytes": 665392 }, { "name": "FlowersViolet", @@ -133,7 +185,11 @@ "label": "Wildflowers (violet)", "variants": { "glTF-Binary": "FlowersViolet.glb" - } + }, + "size": [0.154, 0.5, 0.204], + "box": [-0.077, 0, -0.102, 0.077, 0.5, 0.102], + "tris": 1583, + "bytes": 691784 }, { "name": "FlowerPatch", @@ -141,7 +197,11 @@ "label": "Flower Patch", "variants": { "glTF-Binary": "FlowerPatch.glb" - } + }, + "size": [0.804, 0.5, 0.761], + "box": [-0.402, 0, -0.38, 0.402, 0.5, 0.381], + "tris": 6572, + "bytes": 956112 }, { "name": "Mushrooms", @@ -155,7 +215,11 @@ "file": "Mushrooms.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [0.862, 0.45, 0.566], + "box": [-0.431, 0, -0.283, 0.431, 0.45, 0.283], + "tris": 2412, + "bytes": 505072 }, { "name": "RockSmall", @@ -169,7 +233,11 @@ "file": "RockSmall.lod1.glb", "ratio": 0.6 } - ] + ], + "size": [0.598, 0.45, 0.581], + "box": [-0.299, 0, -0.29, 0.299, 0.45, 0.291], + "tris": 700, + "bytes": 204520 }, { "name": "RockMedium", @@ -183,7 +251,11 @@ "file": "RockMedium.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [1.316, 1, 1.28], + "box": [-0.658, 0, -0.64, 0.658, 1, 0.64], + "tris": 1500, + "bytes": 228884 }, { "name": "RockLarge", @@ -197,7 +269,11 @@ "file": "RockLarge.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2.896, 2.2, 2.816], + "box": [-1.448, 0, -1.408, 1.448, 2.2, 1.408], + "tris": 1500, + "bytes": 228904 }, { "name": "FlatRock", @@ -211,7 +287,11 @@ "file": "FlatRock.lod1.glb", "ratio": 0.78 } - ] + ], + "size": [1.2, 0.251, 1.158], + "box": [-0.6, 0, -0.579, 0.6, 0.251, 0.579], + "tris": 1200, + "bytes": 442688 }, { "name": "BoulderCluster", @@ -229,7 +309,11 @@ "file": "BoulderCluster.lod2.glb", "ratio": 0.45 } - ] + ], + "size": [3.958, 2.2, 3.484], + "box": [-1.979, 0, -1.742, 1.979, 2.2, 1.742], + "tris": 7100, + "bytes": 742692 }, { "name": "SteppingStones", @@ -243,7 +327,11 @@ "file": "SteppingStones.lod1.glb", "ratio": 0.78 } - ] + ], + "size": [3.502, 0.125, 1.076], + "box": [-1.751, 0, -0.538, 1.751, 0.125, 0.538], + "tris": 6000, + "bytes": 443304 }, { "name": "Cliff", @@ -257,7 +345,11 @@ "file": "Cliff.lod1.glb", "ratio": 0.8 } - ] + ], + "size": [4, 4, 1.5], + "box": [-2, 0, 0, 2, 4, 1.5], + "tris": 4039, + "bytes": 726380 }, { "name": "PathTile", @@ -271,7 +363,11 @@ "file": "PathTile.lod1.glb", "ratio": 0.51 } - ] + ], + "size": [2, 0.15, 2], + "box": [-1, 0, -1, 1, 0.15, 1], + "tris": 1832, + "bytes": 490256 }, { "name": "Log", @@ -285,7 +381,11 @@ "file": "Log.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2.5, 0.686, 0.698], + "box": [-1.25, 0, -0.349, 1.25, 0.686, 0.349], + "tris": 2499, + "bytes": 463936 }, { "name": "Stump", @@ -299,7 +399,11 @@ "file": "Stump.lod1.glb", "ratio": 0.52 } - ] + ], + "size": [1.312, 0.6, 1.311], + "box": [-0.656, 0, -0.655, 0.656, 0.6, 0.656], + "tris": 2585, + "bytes": 647156 }, { "name": "Bridge", @@ -317,7 +421,11 @@ "file": "Bridge.lod2.glb", "ratio": 0.34 } - ] + ], + "size": [4, 2.06, 2], + "box": [-2, 0, -1, 2, 2.06, 1], + "tris": 5000, + "bytes": 660440 }, { "name": "Hill", @@ -335,7 +443,11 @@ "file": "Hill.lod2.glb", "ratio": 0.34 } - ] + ], + "size": [8, 1.2, 8], + "box": [-4, 0, -4, 4, 1.2, 4], + "tris": 1364, + "bytes": 542860 }, { "name": "FallenLeaves", @@ -343,7 +455,11 @@ "label": "Fallen Leaves (decal 2×2 m)", "variants": { "glTF-Binary": "FallenLeaves.glb" - } + }, + "size": [2, 0, 2], + "box": [-1, 0.01, -1, 1, 0.01, 1], + "tris": 2, + "bytes": 66620 }, { "name": "PondWater", @@ -351,7 +467,11 @@ "label": "Pond Water", "variants": { "glTF-Binary": "PondWater.glb" - } + }, + "size": [3.622, 0, 2.21], + "box": [-1.933, 0.02, -1.102, 1.689, 0.02, 1.108], + "tris": 48, + "bytes": 6720 }, { "name": "PondSet", @@ -365,6 +485,10 @@ "file": "PondSet.lod1.glb", "ratio": 0.75 } - ] + ], + "size": [4.316, 1.3, 3.793], + "box": [-2.158, 0, -1.896, 2.158, 1.3, 1.897], + "tris": 11794, + "bytes": 1457524 } ] diff --git a/props-kit/default.json b/props-kit/default.json index ea03a01..4a21acc 100644 --- a/props-kit/default.json +++ b/props-kit/default.json @@ -11,7 +11,11 @@ "file": "table.lod1.glb", "ratio": 0.53 } - ] + ], + "size": [1.8, 0.78, 0.95], + "box": [-0.9, 0, -0.475, 0.9, 0.78, 0.475], + "tris": 2999, + "bytes": 517984 }, { "name": "Bench", @@ -25,7 +29,11 @@ "file": "bench.lod1.glb", "ratio": 0.52 } - ] + ], + "size": [1.5, 0.46, 0.38], + "box": [-0.75, 0, -0.19, 0.75, 0.46, 0.19], + "tris": 2999, + "bytes": 517956 }, { "name": "Chair", @@ -39,7 +47,11 @@ "file": "chair.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [0.506, 0.95, 0.52], + "box": [-0.253, 0, -0.26, 0.253, 0.95, 0.26], + "tris": 2500, + "bytes": 484792 }, { "name": "Bed", @@ -57,7 +69,11 @@ "file": "bed.lod2.glb", "ratio": 0.37 } - ] + ], + "size": [1.1, 1, 2.05], + "box": [-0.55, 0, -1.025, 0.55, 1, 1.025], + "tris": 4000, + "bytes": 684552 }, { "name": "Bookcase", @@ -71,7 +87,11 @@ "file": "bookcase.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [1.316, 2, 0.684], + "box": [-0.658, 0, -0.342, 0.658, 2, 0.342], + "tris": 4928, + "bytes": 708736 }, { "name": "Workbench", @@ -89,7 +109,11 @@ "file": "workbench.lod2.glb", "ratio": 0.22 } - ] + ], + "size": [1.24, 0.92, 0.594], + "box": [-0.62, 0, -0.297, 0.62, 0.92, 0.297], + "tris": 4919, + "bytes": 556360 }, { "name": "Rug", @@ -97,7 +121,11 @@ "label": "Rug 2 × 1.3 m", "variants": { "glTF-Binary": "rug.glb" - } + }, + "size": [2.12, 0.015, 1.3], + "box": [-1.06, 0, -0.65, 1.06, 0.015, 0.65], + "tris": 396, + "bytes": 297956 }, { "name": "Tapestry", @@ -115,7 +143,11 @@ "file": "tapestry.lod2.glb", "ratio": 0.28 } - ] + ], + "size": [1.34, 1.66, 0.09], + "box": [-0.67, 0, 0, 0.67, 1.66, 0.09], + "tris": 640, + "bytes": 415924 }, { "name": "PottedPlant", @@ -123,7 +155,11 @@ "label": "Potted plant", "variants": { "glTF-Binary": "potted-plant.glb" - } + }, + "size": [0.602, 1, 0.632], + "box": [-0.301, 0, -0.316, 0.301, 1, 0.316], + "tris": 5007, + "bytes": 765752 }, { "name": "Crate", @@ -137,7 +173,11 @@ "file": "crate.lod1.glb", "ratio": 0.77 } - ] + ], + "size": [0.806, 0.55, 0.546], + "box": [-0.403, 0, -0.273, 0.403, 0.55, 0.273], + "tris": 2500, + "bytes": 704584 }, { "name": "CrateLarge", @@ -151,7 +191,11 @@ "file": "crate-large.lod1.glb", "ratio": 0.77 } - ] + ], + "size": [1.246, 0.85, 0.844], + "box": [-0.623, 0, -0.422, 0.623, 0.85, 0.422], + "tris": 2500, + "bytes": 704584 }, { "name": "CrateTeal", @@ -165,7 +209,11 @@ "file": "crate-teal.lod1.glb", "ratio": 0.77 } - ] + ], + "size": [0.732, 0.5, 0.496], + "box": [-0.366, 0, -0.248, 0.366, 0.5, 0.248], + "tris": 2500, + "bytes": 677944 }, { "name": "CrateStack", @@ -179,7 +227,11 @@ "file": "crate-stack.lod1.glb", "ratio": 0.77 } - ] + ], + "size": [1.664, 1.05, 0.669], + "box": [-0.816, 0, -0.297, 0.848, 1.05, 0.372], + "tris": 7500, + "bytes": 1333600 }, { "name": "Barrel", @@ -197,7 +249,11 @@ "file": "barrel.lod2.glb", "ratio": 0.37 } - ] + ], + "size": [0.484, 0.9, 0.552], + "box": [-0.242, 0, -0.276, 0.242, 0.9, 0.276], + "tris": 2478, + "bytes": 613800 }, { "name": "BarrelSmall", @@ -215,7 +271,11 @@ "file": "barrel-small.lod2.glb", "ratio": 0.37 } - ] + ], + "size": [0.322, 0.6, 0.368], + "box": [-0.161, 0, -0.184, 0.161, 0.6, 0.184], + "tris": 2478, + "bytes": 613800 }, { "name": "Chest", @@ -233,7 +293,11 @@ "file": "chest.lod2.glb", "ratio": 0.28 } - ] + ], + "size": [0.768, 0.6, 0.686], + "box": [-0.384, 0, -0.343, 0.384, 0.6, 0.343], + "tris": 2910, + "bytes": 806320 }, { "name": "Sacks", @@ -247,7 +311,11 @@ "file": "sacks.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [1.244, 0.75, 1.098], + "box": [-0.622, 0, -0.549, 0.622, 0.75, 0.549], + "tris": 3590, + "bytes": 1233904 }, { "name": "Lantern", @@ -261,7 +329,11 @@ "file": "lantern.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [0.19, 0.38, 0.152], + "box": [-0.095, 0, -0.076, 0.095, 0.38, 0.076], + "tris": 1865, + "bytes": 479824 }, { "name": "WallTorch", @@ -279,7 +351,11 @@ "file": "wall-torch.lod2.glb", "ratio": 0.41 } - ] + ], + "size": [0.105, 0.685, 0.324], + "box": [-0.052, 0, 0, 0.053, 0.685, 0.324], + "tris": 652, + "bytes": 147604 }, { "name": "Candles", @@ -293,7 +369,11 @@ "file": "candles.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [0.17, 0.3, 0.17], + "box": [-0.085, 0, -0.085, 0.085, 0.3, 0.085], + "tris": 2500, + "bytes": 581000 }, { "name": "Cauldron", @@ -311,7 +391,11 @@ "file": "cauldron.lod2.glb", "ratio": 0.4 } - ] + ], + "size": [0.972, 0.6, 0.824], + "box": [-0.486, 0, -0.412, 0.486, 0.6, 0.412], + "tris": 3000, + "bytes": 318260 }, { "name": "Well", @@ -325,7 +409,11 @@ "file": "well.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2.584, 2.6, 2.56], + "box": [-1.292, 0, -1.28, 1.292, 2.6, 1.28], + "tris": 5999, + "bytes": 776244 }, { "name": "MarketStall", @@ -343,7 +431,11 @@ "file": "market-stall.lod2.glb", "ratio": 0.37 } - ] + ], + "size": [2.6, 2.6, 1.848], + "box": [-1.3, 0, -0.924, 1.3, 2.6, 0.924], + "tris": 5660, + "bytes": 740744 }, { "name": "Signpost", @@ -351,7 +443,11 @@ "label": "Signpost", "variants": { "glTF-Binary": "signpost.glb" - } + }, + "size": [1.35, 2.32, 0.7], + "box": [-0.65, 0, -0.55, 0.7, 2.32, 0.15], + "tris": 104, + "bytes": 106532 }, { "name": "Ladder", @@ -359,7 +455,11 @@ "label": "Ladder (3 m, one storey)", "variants": { "glTF-Binary": "ladder.glb" - } + }, + "size": [0.53, 3, 0.06], + "box": [-0.265, 0, -0.03, 0.265, 3, 0.03], + "tris": 336, + "bytes": 81816 }, { "name": "LeverBase", @@ -367,7 +467,11 @@ "label": "Lever base", "variants": { "glTF-Binary": "lever-base.glb" - } + }, + "size": [0.34, 0.2, 0.24], + "box": [-0.17, 0, -0.12, 0.17, 0.2, 0.12], + "tris": 120, + "bytes": 65396 }, { "name": "LeverHandle", @@ -375,7 +479,11 @@ "label": "Lever handle (hinge pivot)", "variants": { "glTF-Binary": "lever-handle.glb" - } + }, + "size": [0.14, 0.536, 0.076], + "box": [-0.07, -0.028, -0.038, 0.07, 0.508, 0.038], + "tris": 304, + "bytes": 100132 }, { "name": "WallButton", @@ -383,7 +491,11 @@ "label": "Wall button", "variants": { "glTF-Binary": "wall-button.glb" - } + }, + "size": [0.2, 0.2, 0.095], + "box": [-0.1, 0, 0, 0.1, 0.2, 0.095], + "tris": 300, + "bytes": 107128 }, { "name": "PressurePlate", @@ -391,7 +503,11 @@ "label": "Pressure plate 1 × 1 m", "variants": { "glTF-Binary": "pressure-plate.glb" - } + }, + "size": [1, 0.052, 1], + "box": [-0.5, 0, -0.5, 0.5, 0.052, 0.5], + "tris": 72, + "bytes": 89392 }, { "name": "Hatch", @@ -399,7 +515,11 @@ "label": "Trapdoor 1 × 1 m (hinge pivot)", "variants": { "glTF-Binary": "hatch.glb" - } + }, + "size": [1, 0.087, 1], + "box": [-0.5, 0, 0, 0.5, 0.087, 1], + "tris": 496, + "bytes": 87148 }, { "name": "DoorKey", @@ -413,7 +533,11 @@ "file": "door-key.lod1.glb", "ratio": 0.79 } - ] + ], + "size": [0.161, 0.022, 0.072], + "box": [-0.086, -0.011, -0.036, 0.075, 0.011, 0.036], + "tris": 556, + "bytes": 81924 }, { "name": "SciFiConsole", @@ -431,7 +555,11 @@ "file": "sci-fi-console.lod2.glb", "ratio": 0.2 } - ] + ], + "size": [0.632, 1.1, 0.528], + "box": [-0.316, 0, -0.264, 0.316, 1.1, 0.264], + "tris": 3811, + "bytes": 506880 }, { "name": "SciFiCrate", @@ -445,6 +573,10 @@ "file": "sci-fi-crate.lod1.glb", "ratio": 0.77 } - ] + ], + "size": [0.88, 0.6, 0.596], + "box": [-0.44, 0, -0.298, 0.44, 0.6, 0.298], + "tris": 2500, + "bytes": 621104 } ] diff --git a/scifi-kit/default.json b/scifi-kit/default.json index cfc7d0b..a76bd85 100644 --- a/scifi-kit/default.json +++ b/scifi-kit/default.json @@ -11,7 +11,11 @@ "file": "wall.lod1.glb", "ratio": 0.51 } - ] + ], + "size": [2, 3, 0.25], + "box": [-1, 0, -0.125, 1, 3, 0.125], + "tris": 996, + "bytes": 193232 }, { "name": "WallDoorway", @@ -25,7 +29,11 @@ "file": "wall-doorway.lod1.glb", "ratio": 0.53 } - ] + ], + "size": [2, 3, 0.32], + "box": [-1, 0, -0.16, 1, 3, 0.16], + "tris": 1426, + "bytes": 252900 }, { "name": "SlidingDoor", @@ -43,7 +51,11 @@ "file": "sliding-door.lod2.glb", "ratio": 0.31 } - ] + ], + "size": [1.5, 2.6, 0.3], + "box": [-0.75, 0, -0.15, 0.75, 2.6, 0.15], + "tris": 3000, + "bytes": 277656 }, { "name": "WallDoor", @@ -61,7 +73,11 @@ "file": "wall-door.lod2.glb", "ratio": 0.35 } - ] + ], + "size": [2, 3, 0.3], + "box": [-1, 0, -0.15, 1, 3, 0.15], + "tris": 4325, + "bytes": 487564 }, { "name": "WallWindow", @@ -75,7 +91,11 @@ "file": "wall-window.lod1.glb", "ratio": 0.53 } - ] + ], + "size": [2, 3, 0.31], + "box": [-1, 0, -0.155, 1, 3, 0.155], + "tris": 1458, + "bytes": 251172 }, { "name": "CornerPost", @@ -89,7 +109,11 @@ "file": "corner-post.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [0.25, 3, 0.25], + "box": [-0.125, 0, -0.125, 0.125, 3, 0.125], + "tris": 630, + "bytes": 173188 }, { "name": "Pillar", @@ -107,7 +131,11 @@ "file": "pillar.lod2.glb", "ratio": 0.35 } - ] + ], + "size": [0.5, 3, 0.5], + "box": [-0.25, 0, -0.25, 0.25, 3, 0.25], + "tris": 2386, + "bytes": 232188 }, { "name": "FloorPlate", @@ -125,7 +153,11 @@ "file": "floor-plate.lod2.glb", "ratio": 0.21 } - ] + ], + "size": [2, 0.1, 2], + "box": [-1, 0, -1, 1, 0.1, 1], + "tris": 2125, + "bytes": 223004 }, { "name": "FloorGrate", @@ -139,7 +171,11 @@ "file": "floor-grate.lod1.glb", "ratio": 0.78 } - ] + ], + "size": [2, 0.1, 2], + "box": [-1, 0, -1, 1, 0.1, 1], + "tris": 716, + "bytes": 103820 }, { "name": "CeilingLight", @@ -147,7 +183,11 @@ "screenshot": "screenshot/screenshot.webp", "variants": { "glTF-Binary": "ceiling-light.glb" - } + }, + "size": [2, 0.115, 2], + "box": [-1, -0.015, -1, 1, 0.1, 1], + "tris": 344, + "bytes": 83984 }, { "name": "Stairs", @@ -165,7 +205,11 @@ "file": "stairs.lod2.glb", "ratio": 0.36 } - ] + ], + "size": [2, 3.455, 4], + "box": [-1, 0, -2, 1, 3.455, 2], + "tris": 3699, + "bytes": 613120 }, { "name": "Ramp", @@ -173,7 +217,11 @@ "screenshot": "screenshot/screenshot.webp", "variants": { "glTF-Binary": "ramp.glb" - } + }, + "size": [2, 1, 2], + "box": [-1, 0, -1, 1, 1, 1], + "tris": 144, + "bytes": 94780 }, { "name": "Railing", @@ -181,7 +229,11 @@ "screenshot": "screenshot/screenshot.webp", "variants": { "glTF-Binary": "railing.glb" - } + }, + "size": [2, 1.085, 0.08], + "box": [-1, 0, -0.04, 1, 1.085, 0.04], + "tris": 160, + "bytes": 82440 }, { "name": "Console", @@ -195,7 +247,11 @@ "file": "console.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [1.822, 1.1, 0.578], + "box": [-0.911, 0, -0.289, 0.911, 1.1, 0.289], + "tris": 3729, + "bytes": 562976 }, { "name": "WallScreen", @@ -203,7 +259,11 @@ "screenshot": "screenshot/screenshot.webp", "variants": { "glTF-Binary": "wall-screen.glb" - } + }, + "size": [1.4, 0.85, 0.061], + "box": [-0.7, 1.15, 0.125, 0.7, 2, 0.186], + "tris": 26, + "bytes": 54616 }, { "name": "ServerRack", @@ -211,7 +271,11 @@ "screenshot": "screenshot/screenshot.webp", "variants": { "glTF-Binary": "server-rack.glb" - } + }, + "size": [0.85, 2, 0.908], + "box": [-0.425, 0, -0.454, 0.425, 2, 0.454], + "tris": 2082, + "bytes": 453068 }, { "name": "Crate", @@ -225,7 +289,11 @@ "file": "crate.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [0.724, 0.7, 0.724], + "box": [-0.362, 0, -0.362, 0.362, 0.7, 0.362], + "tris": 2367, + "bytes": 786980 }, { "name": "CrateLarge", @@ -243,7 +311,11 @@ "file": "crate-large.lod2.glb", "ratio": 0.34 } - ] + ], + "size": [1.158, 1.12, 1.158], + "box": [-0.579, 0, -0.579, 0.579, 1.12, 0.579], + "tris": 2368, + "bytes": 663304 }, { "name": "Canister", @@ -257,7 +329,11 @@ "file": "canister.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [0.596, 1, 0.596], + "box": [-0.298, 0, -0.298, 0.298, 1, 0.298], + "tris": 2499, + "bytes": 577720 }, { "name": "PipeStraight", @@ -265,7 +341,11 @@ "screenshot": "screenshot/screenshot.webp", "variants": { "glTF-Binary": "pipe-straight.glb" - } + }, + "size": [2, 0.33, 0.26], + "box": [-1, 0, -0.13, 1, 0.33, 0.13], + "tris": 464, + "bytes": 105332 }, { "name": "PipeElbow", @@ -283,7 +363,11 @@ "file": "pipe-elbow.lod2.glb", "ratio": 0.31 } - ] + ], + "size": [1.13, 0.33, 1.13], + "box": [-1, 0, -0.13, 0.13, 0.33, 1], + "tris": 1864, + "bytes": 239700 }, { "name": "Vent", @@ -291,7 +375,11 @@ "screenshot": "screenshot/screenshot.webp", "variants": { "glTF-Binary": "vent.glb" - } + }, + "size": [0.8, 0.5, 0.06], + "box": [-0.4, 0.35, 0.125, 0.4, 0.85, 0.185], + "tris": 132, + "bytes": 69192 }, { "name": "Lamp", @@ -299,7 +387,11 @@ "screenshot": "screenshot/screenshot.webp", "variants": { "glTF-Binary": "lamp.glb" - } + }, + "size": [0.44, 1.78, 0.44], + "box": [-0.22, 0, -0.22, 0.22, 1.78, 0.22], + "tris": 484, + "bytes": 110012 }, { "name": "Chair", @@ -313,7 +405,11 @@ "file": "chair.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [0.68, 1.05, 0.648], + "box": [-0.34, 0, -0.324, 0.34, 1.05, 0.324], + "tris": 3000, + "bytes": 697224 }, { "name": "Desk", @@ -331,7 +427,11 @@ "file": "desk.lod2.glb", "ratio": 0.26 } - ] + ], + "size": [1.998, 1.3, 1.012], + "box": [-0.999, 0, -0.506, 0.999, 1.3, 0.506], + "tris": 3500, + "bytes": 527060 }, { "name": "PlantPod", @@ -339,7 +439,11 @@ "screenshot": "screenshot/screenshot.webp", "variants": { "glTF-Binary": "plant-pod.glb" - } + }, + "size": [1.233, 1, 1.306], + "box": [-0.616, 0, -0.653, 0.617, 1, 0.653], + "tris": 3441, + "bytes": 863228 }, { "name": "TeleportPad", @@ -357,7 +461,11 @@ "file": "teleport-pad.lod2.glb", "ratio": 0.28 } - ] + ], + "size": [2.4, 0.215, 2.4], + "box": [-1.2, 0, -1.2, 1.2, 0.215, 1.2], + "tris": 2999, + "bytes": 728692 }, { "name": "Drone", @@ -371,6 +479,10 @@ "file": "drone.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [0.6, 0.175, 0.594], + "box": [-0.3, 0, -0.297, 0.3, 0.175, 0.297], + "tris": 3999, + "bytes": 552368 } ] diff --git a/tools/kit-build/README.md b/tools/kit-build/README.md index 40fe981..3e35bbc 100644 --- a/tools/kit-build/README.md +++ b/tools/kit-build/README.md @@ -20,6 +20,7 @@ node tools/kit-build/kit-build.mjs … | `flicker [--record]` | the static z-fight probe; `--record` RENDERS every file over the limit (headless) and writes `flicker-baseline.json` | | `report [pack…] [--md f] [--json f]` | the **budget report**: per item tris vs budget, MiB, largest texture, LOD triangles, z-fight cm² | | `check [pack…] [--summary f] [--json f]` | **the CI** — exit 1 on any error that `allow.json` does not list | +| `dims [pack…\|--all] [--write] [--remote]` | measures each row's **`size`** `[w, h, d]` (metres), **`box`** (exact bounds), **`tris`**, **`bytes`** and **`animated`** and writes them onto the row — core's drag-to-place ghost (roadmap 39) shows an item's size before it downloads. `build` and `pass --write` run it for you; `--remote` downloads absolute-URL rows (the Khronos index) for a one-off measure | The recipes `build` runs: `tools/architecture-kit/build.mjs`, `tools/scifi-kit/build.mjs`, `tools/town-kit/build.mjs`, `tools/interactive-kit/build.mjs`, `nature-kit/build/finalize.mjs`, @@ -46,6 +47,7 @@ byte-identical. `pass --all` on main changes exactly one file (default/SvelteRun | behavior | the clips a behavior names exist in the GLB and in every LOD file | | flicker | the static z-fight probe (`tools/lod/coplanar.mjs`: coplanar triangle pairs, both facings when double-sided) ≤ 1 cm² — or at most the file's recorded baseline | | thumb | the row's screenshot exists, decodes, ≥ 64 px | +| dims | the row's `size` / `box` / `tris` / `bytes` / `animated` match the file (± 1.5 mm on the bounds) — `kit-build dims --write` fixes it | ### Policy: `packs.json` diff --git a/tools/kit-build/kit-build.mjs b/tools/kit-build/kit-build.mjs index 91a9f29..283244c 100644 --- a/tools/kit-build/kit-build.mjs +++ b/tools/kit-build/kit-build.mjs @@ -15,6 +15,10 @@ // the limit (headless) and writes flicker-baseline.json // report [pack…] [--md file] [--json file] the budget report (tris vs budget, MiB, textures, LODs) // check [pack…] [--json file] [--summary file] the CI: exit 1 on any error not in allow.json +// dims [pack…|--all] [--write] [--remote] measure each row's size/box/tris/bytes/animated and +// write them onto the row (core 39 P4: the app's +// drag-to-place ghost reads them before any download); +// --remote downloads absolute-URL rows (Khronos) import fs from 'node:fs'; import path from 'node:path'; import { execFileSync } from 'node:child_process'; @@ -64,6 +68,14 @@ async function main() { if (opt('--json')) fs.writeFileSync(/** @type {string} */ (opt('--json')), JSON.stringify(r.items, null, 1) + '\n'); return; } + case 'dims': { + const { dimsPacks } = await import('./lib/dims.mjs'); + const packs = flag('--all') ? null : positional(); + const r = await dimsPacks(REPO, packs, { write: flag('--write'), remote: flag('--remote') }); + const changed = r.reduce((n, p) => n + p.changed, 0); + console.log(`${changed} row(s) ${flag('--write') ? 'written' : 'would change (dry run; --write to apply)'}`); + return; + } case 'post': { const [input, output, job] = rest; if (!input || !output) throw new Error("usage: kit-build post ''"); @@ -115,6 +127,8 @@ async function main() { node(['tools/lod/defight-all.mjs', pack]); node(['tools/lod/lod.mjs', pack]); if (!flag('--no-thumbs')) await thumbsPack(REPO, pack, only?.split(',') ?? null); + const { dimsPacks } = await import('./lib/dims.mjs'); + await dimsPacks(REPO, [pack], { write: true }); node(['tools/kit-build/kit-build.mjs', 'check', pack]); return; } diff --git a/tools/kit-build/lib/check.mjs b/tools/kit-build/lib/check.mjs index 930c691..83fd1a3 100644 --- a/tools/kit-build/lib/check.mjs +++ b/tools/kit-build/lib/check.mjs @@ -17,6 +17,8 @@ // when double-sided) ≤ 1 cm² — or no worse than the file's recorded baseline // (flicker-baseline.json, written by `kit-build flicker --record` after a RENDER probe) // thumb the row's screenshot exists and decodes, ≥ 64 px +// dims the row's size/box/tris/bytes/animated match the file (core 39 P4 reads them before any +// download; `kit-build dims --write` writes them) // // A failure is an ERROR unless allow.json lists it (pack, item, check) with a reason; an allow-list // entry that matched nothing is reported so it gets cleaned up. @@ -24,6 +26,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { load } from './deps.mjs'; import { inspectGlb } from './inspect.mjs'; +import { dimsProblem } from './dims.mjs'; import { indexRowProblems, itemRowProblems, behaviorClipProblems, pivotProblem, scaleProblem, safeRel } from './rules.mjs'; import { probeFile } from '../../lod/coplanar.mjs'; @@ -137,6 +140,9 @@ export async function runChecks(repo, o = {}) { if (pv) add('error', pack, item, 'pivot', `${pv}; rule "${pol.pivot}"`); } for (const m of info.materials) if (m.emissiveTexture && !m.emissive) add('warn', pack, item, 'emissive', `material ${m.name || '(unnamed)'} has an emissive map with a black factor (a wasted texture)`); + // dims (core 39 P4): the row says how big the item is before the app downloads it + const dp = dimsProblem(r, info); + if (dp) add('error', pack, item, 'dims', dp.replace('', pack)); // lods const lods = Array.isArray(r.lods) ? r.lods : []; if (!lods.length && info.tris > L.lodRequiredOver) add('error', pack, item, 'lods', `${info.tris} triangles and no LOD files (node tools/kit-build/kit-build.mjs lod ${pack})`); diff --git a/tools/kit-build/lib/dims.mjs b/tools/kit-build/lib/dims.mjs new file mode 100644 index 0000000..b079d8f --- /dev/null +++ b/tools/kit-build/lib/dims.mjs @@ -0,0 +1,132 @@ +// dims: what each pack item IS, written onto its row so the app knows an item's size before it +// downloads it (core roadmap 39 P4 — the drag-to-place ghost draws a not-yet-loaded item as its +// box with W × D × H, and the Explorer shows the download size). +// +// size [x, y, z] extents in metres = width, height, depth (the GLB as shipped) +// box [minX, minY, minZ, maxX, maxY, maxZ] — the exact bounds, so a top-centre or wall +// pivot draws right (the shape core's packRef.box already uses) +// tris LOD0's drawn triangles +// bytes LOD0's file size +// animated true when the GLB carries clips (it places as bytes, not as a kit reference) +// +// `dims --write` measures and writes; `check` reports a row whose dims are missing or stale (a +// `pass --write` that decimated a file changes its tris and bytes). +import fs from 'node:fs'; +import path from 'node:path'; +import os from 'node:os'; +import { inspectGlb } from './inspect.mjs'; + +export const DIM_KEYS = ['size', 'box', 'tris', 'bytes', 'animated']; +const isUrl = (/** @type {any} */ p) => typeof p === 'string' && /^https?:\/\//.test(p); +const r3 = (/** @type {number} */ v) => Math.round(v * 1000) / 1000; + +/** The dims block for an inspected GLB. @param {{bytes: number, tris: number, min: number[], max: number[], animations: string[]}} info */ +export function dimsOf(info) { + const box = [...info.min, ...info.max].map(r3); + return { + size: [0, 1, 2].map((i) => r3(box[i + 3] - box[i])), + box, + tris: info.tris, + bytes: info.bytes, + ...(info.animations.length ? { animated: true } : {}) + }; +} + +/** A row with its dims replaced (other keys keep their order; dims go last). @param {any} row @param {any} dims */ +export function withDims(row, dims) { + const out = {}; + for (const [k, v] of Object.entries(row)) if (!DIM_KEYS.includes(k)) out[k] = v; + return Object.assign(out, dims); +} + +/** + * What is wrong with a row's dims against the measured file, or null. A millimetre of slack on + * the bounds (the file round-trips floats); tris and bytes must match exactly. + * @param {any} row @param {any} info @returns {string | null} + */ +export function dimsProblem(row, info) { + const want = dimsOf(info); + if (!Array.isArray(row.size) || !Array.isArray(row.box) || typeof row.tris !== 'number' || typeof row.bytes !== 'number') + return 'no dims (size/box/tris/bytes) — run `kit-build dims --write`'; + const off = (/** @type {number[]} */ a, /** @type {number[]} */ b) => a.length !== b.length || a.some((v, i) => Math.abs(v - b[i]) > 0.0015); + if (off(row.size, want.size) || off(row.box, want.box)) return `dims are stale: box ${JSON.stringify(row.box)} vs measured ${JSON.stringify(want.box)} — run \`kit-build dims --write\``; + if (row.tris !== want.tris) return `dims are stale: tris ${row.tris} vs measured ${want.tris}`; + if (row.bytes !== want.bytes) return `dims are stale: bytes ${row.bytes} vs measured ${want.bytes}`; + if (!!row.animated !== !!want.animated) return `dims are stale: animated ${!!row.animated} vs ${!!want.animated}`; + return null; +} + +/** Detect a JSON file's indent (its shallowest one) so a rewrite keeps the house style. @param {string} text */ +function indentOf(text) { + let best = null; + for (const m of text.matchAll(/\n([ \t]+)\S/g)) if (best === null || m[1].length < best.length) best = m[1]; + return best ?? ' '; +} + +/** JSON in the house style, with the dims' number arrays kept on one line. @param {any} v @param {string} indent */ +export function stringifyRows(v, indent) { + return JSON.stringify(v, null, indent).replace(/\[\s+(-?[\d.e+-]+(?:,\s+-?[\d.e+-]+)*)\s+\]/g, (_, body) => '[' + body.split(/,\s+/).join(', ') + ']'); +} + +/** + * Measure every row of the given packs and (with `write`) write the dims onto the rows. Remote + * rows (absolute glb URLs, the Khronos index) are downloaded to a temp folder with `remote`. + * @param {string} repo @param {string[] | null} packs + * @param {{write?: boolean, remote?: boolean, log?: (s: string) => void}} [o] + * @returns {Promise<{pack: string, rows: number, changed: number, skipped: string[]}[]>} + */ +export async function dimsPacks(repo, packs, o = {}) { + const log = o.log ?? ((s) => console.log(s)); + const index = JSON.parse(fs.readFileSync(path.join(repo, 'index.json'), 'utf8')); + const out = []; + const tmp = o.remote ? fs.mkdtempSync(path.join(os.tmpdir(), 'kit-dims-')) : ''; + for (const entry of index) { + if (!entry?.value || isUrl(entry.value)) continue; + if (packs && packs.length && !packs.includes(entry.name)) continue; + const listFile = path.join(repo, entry.value); + const text = fs.readFileSync(listFile, 'utf8'); + const rows = JSON.parse(text); + const base = path.dirname(listFile); + let changed = 0; + const skipped = []; + const next = []; + for (const row of rows) { + const ref = row?.variants?.['glTF-Binary']; + let file = ''; + if (typeof ref === 'string' && isUrl(ref)) { + if (!o.remote) { + skipped.push(row.name + ' (remote; --remote downloads it)'); + next.push(row); + continue; + } + file = path.join(tmp, `${entry.name}-${row.name}.glb`); + if (!fs.existsSync(file)) { + const res = await fetch(ref); + if (!res.ok) { + skipped.push(`${row.name} (HTTP ${res.status})`); + next.push(row); + continue; + } + fs.writeFileSync(file, Buffer.from(await res.arrayBuffer())); + } + } else if (typeof ref === 'string') file = path.join(base, row.name, 'glTF-Binary', ref); + if (!file || !fs.existsSync(file)) { + skipped.push(`${row?.name} (no file)`); + next.push(row); + continue; + } + const info = await inspectGlb(file); + const fresh = withDims(row, dimsOf(info)); + if (JSON.stringify(fresh) !== JSON.stringify(row)) changed++; + next.push(fresh); + } + if (o.write && changed) { + const nl = text.includes('\r\n') ? '\r\n' : '\n'; + fs.writeFileSync(listFile, stringifyRows(next, indentOf(text)).replace(/\n/g, nl) + (text.endsWith('\n') ? nl : '')); + } + log(`${entry.name}: ${rows.length} rows, ${changed} ${o.write ? 'written' : 'would change'}${skipped.length ? `, skipped ${skipped.join(', ')}` : ''}`); + out.push({ pack: entry.name, rows: rows.length, changed, skipped }); + } + if (tmp) fs.rmSync(tmp, { recursive: true, force: true }); + return out; +} diff --git a/tools/kit-build/lib/pass.mjs b/tools/kit-build/lib/pass.mjs index c5bf80f..8e98640 100644 --- a/tools/kit-build/lib/pass.mjs +++ b/tools/kit-build/lib/pass.mjs @@ -129,6 +129,11 @@ export async function passPack(repo, pack, o = {}) { } else console.log(`${rel}: would — ${did.join('; ')}`); } if (decimated) console.log(`${pack}: ${decimated} LOD0(s) decimated — run: node tools/kit-build/kit-build.mjs lod ${pack}`); + // core 39 P4: a rewritten file has new tris / bytes (maybe a new box) — its row says so too + if (o.write && changed) { + const { dimsPacks } = await import('./dims.mjs'); + await dimsPacks(repo, [pack], { write: true, log: () => {} }); + } return changed; } diff --git a/tools/kit-build/lib/rules.mjs b/tools/kit-build/lib/rules.mjs index b9b078d..a5d8afe 100644 --- a/tools/kit-build/lib/rules.mjs +++ b/tools/kit-build/lib/rules.mjs @@ -8,7 +8,7 @@ export const BEHAVIOR_TRIGGERS = ['click', 'proximity', 'knock']; const BEHAVIOR_KEYS = ['type', 'clip', 'closeClip', 'trigger', 'autoplay', 'sound', 'collider']; /** core lodGroupCore MAX_LEVELS is 6 (LOD0 + 5 files) */ export const MAX_LOD_FILES = 5; -const ROW_KEYS = ['name', 'label', 'screenshot', 'variants', 'lods', 'behavior']; +const ROW_KEYS = ['name', 'label', 'screenshot', 'variants', 'lods', 'behavior', 'size', 'box', 'tris', 'bytes', 'animated']; const INDEX_KEYS = ['name', 'title', 'value', 'zip', 'attribution', 'copyright', 'license', 'source', 'cover']; export const PIVOTS = ['bottom-center', 'bottom-center-back', 'top-center', 'wall-pivot', 'wall-face', 'foot', 'hinge', 'any']; @@ -49,6 +49,7 @@ export function itemRowProblems(row) { else if (!isUrl(glb) && !/\.glb$/i.test(glb)) out.push('variants["glTF-Binary"] must be a .glb'); if (row.lods !== undefined) out.push(...lodsProblems(row.lods)); if (row.behavior !== undefined) out.push(...behaviorProblems(row.behavior)); + out.push(...dimsShapeProblems(row)); for (const k of Object.keys(row)) if (!ROW_KEYS.includes(k)) out.push(`unknown key "${k}"`); return out; } @@ -162,3 +163,21 @@ export function scaleProblem(size, maxExtent, minExtent) { if (big > maxExtent) return `largest extent ${big.toFixed(2)} m is over the category's ${maxExtent} m — exported in cm?`; return null; } + +/** + * The dims fields' SHAPE (core 39 P4) — core reads them before any download, so a malformed one + * draws a wrong ghost. Whether they are CURRENT is check.mjs's job (it measures the file). + * @param {any} row @returns {string[]} + */ +export function dimsShapeProblems(row) { + const out = []; + const num = (/** @type {any} */ v) => typeof v === 'number' && Number.isFinite(v); + if (row.size !== undefined && !(Array.isArray(row.size) && row.size.length === 3 && row.size.every((/** @type {any} */ v) => num(v) && v >= 0))) + out.push('size must be [width, height, depth] in metres (three numbers >= 0)'); + if (row.box !== undefined && !(Array.isArray(row.box) && row.box.length === 6 && row.box.every(num) && row.box[3] >= row.box[0] && row.box[4] >= row.box[1] && row.box[5] >= row.box[2])) + out.push('box must be [minX, minY, minZ, maxX, maxY, maxZ] with max >= min'); + if (row.tris !== undefined && !(Number.isInteger(row.tris) && row.tris >= 0)) out.push('tris must be a whole number >= 0'); + if (row.bytes !== undefined && !(Number.isInteger(row.bytes) && row.bytes > 0)) out.push('bytes must be a whole number > 0'); + if (row.animated !== undefined && row.animated !== true) out.push('animated is true or absent'); + return out; +} diff --git a/tools/kit-build/test/check.test.mjs b/tools/kit-build/test/check.test.mjs index 8d511fc..56e5b19 100644 --- a/tools/kit-build/test/check.test.mjs +++ b/tools/kit-build/test/check.test.mjs @@ -233,3 +233,10 @@ test('pass: LOD0 over its triangle budget is decimated to it (node names kept)', fs.rmSync(dir, { recursive: true, force: true }); } }); + +test('dims: a row without its size/box/tris/bytes is red (core 39 P4)', async () => { + const errs = await errors((f) => { + f.noDims = true; + }); + assert.ok(errs.some((e) => /^dims: no dims/.test(e)), errs.join('\n')); +}); diff --git a/tools/kit-build/test/dims.test.mjs b/tools/kit-build/test/dims.test.mjs new file mode 100644 index 0000000..5e5c3a0 --- /dev/null +++ b/tools/kit-build/test/dims.test.mjs @@ -0,0 +1,50 @@ +// kit-build dims (core 39 P4): the size/box/tris/bytes a row carries, each rule shown red on the +// input it exists to catch, and the CI's staleness check against a measured file. +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { dimsOf, withDims, dimsProblem, stringifyRows } from '../lib/dims.mjs'; +import { dimsShapeProblems, itemRowProblems } from '../lib/rules.mjs'; + +const info = { bytes: 603416, tris: 320, min: [-1, 0, -1], max: [1, 0.2, 1], animations: [] }; + +test('dimsOf: size is the box extents, animated only when the file has clips', () => { + assert.deepEqual(dimsOf(info), { size: [2, 0.2, 2], box: [-1, 0, -1, 1, 0.2, 1], tris: 320, bytes: 603416 }); + assert.equal(dimsOf({ ...info, animations: ['open'] }).animated, true); + assert.equal('animated' in dimsOf(info), false, 'a static item writes no animated key'); +}); + +test('withDims: replaces old dims, keeps every other key in order, dims last', () => { + const row = { name: 'Road', size: 123, label: 'Road', variants: { 'glTF-Binary': 'road.glb' }, tris: 1 }; + const out = withDims(row, dimsOf(info)); + assert.deepEqual(Object.keys(out), ['name', 'label', 'variants', 'size', 'box', 'tris', 'bytes']); + assert.deepEqual(out.size, [2, 0.2, 2], 'an old numeric size (bytes) is replaced by the dims array'); +}); + +test('dimsProblem: current passes; missing, moved, decimated, resized and re-rigged files fail', () => { + const row = withDims({ name: 'Road' }, dimsOf(info)); + assert.equal(dimsProblem(row, info), null); + assert.match(String(dimsProblem({ name: 'Road' }, info)), /no dims/); + assert.match(String(dimsProblem(row, { ...info, max: [1, 0.3, 1] })), /stale: box/); + assert.match(String(dimsProblem(row, { ...info, tris: 300 })), /stale: tris/, 'a pass --write decimation changes tris'); + assert.match(String(dimsProblem(row, { ...info, bytes: 1 })), /stale: bytes/); + assert.match(String(dimsProblem(row, { ...info, animations: ['x'] })), /stale: animated/); + assert.equal(dimsProblem(row, { ...info, max: [1.0004, 0.2, 1] }), null, 'a float round trip is not stale'); +}); + +test('dims shape: core reads these before any download, so malformed ones are refused', () => { + const ok = { name: 'A', variants: { 'glTF-Binary': 'a.glb' }, ...dimsOf(info) }; + assert.deepEqual(itemRowProblems(ok), []); + assert.match(dimsShapeProblems({ size: [1, 2] }).join(), /size must be/); + assert.match(dimsShapeProblems({ size: [1, -2, 3] }).join(), /size must be/); + assert.match(dimsShapeProblems({ box: [1, 0, 0, 0, 1, 1] }).join(), /box must be/, 'max below min'); + assert.match(dimsShapeProblems({ tris: 1.5 }).join(), /tris must be/); + assert.match(dimsShapeProblems({ bytes: 0 }).join(), /bytes must be/); + assert.match(dimsShapeProblems({ animated: false }).join(), /animated is true or absent/); +}); + +test('stringifyRows: number arrays stay on one line, nothing else changes', () => { + const text = stringifyRows([{ name: 'A', box: [-1, 0, -1.5, 1, 2e-3, 1.5], lods: [{ file: 'a.glb', ratio: 0.5 }] }], ' '); + assert.match(text, /"box": \[-1, 0, -1\.5, 1, 0\.002, 1\.5\]/); + assert.match(text, /"lods": \[\n {6}\{/, 'an array of objects keeps its layout'); + assert.deepEqual(JSON.parse(text), [{ name: 'A', box: [-1, 0, -1.5, 1, 0.002, 1.5], lods: [{ file: 'a.glb', ratio: 0.5 }] }]); +}); diff --git a/tools/kit-build/test/fixture.mjs b/tools/kit-build/test/fixture.mjs index 0308fb6..89ffa2f 100644 --- a/tools/kit-build/test/fixture.mjs +++ b/tools/kit-build/test/fixture.mjs @@ -3,6 +3,8 @@ import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { load, makeIO, REPO } from '../lib/deps.mjs'; +import { inspectGlb } from '../lib/inspect.mjs'; +import { dimsOf, withDims } from '../lib/dims.mjs'; const { Document } = await load('@gltf-transform/core'); const sharp = (await load('sharp')).default; @@ -98,8 +100,15 @@ export async function fixture(edit) { fs.writeFileSync(path.join(dir, rel), data); }; w('index.json', JSON.stringify(f.index)); - w('kit/default.json', JSON.stringify(f.rows)); for (const [rel, data] of Object.entries(f.files)) w(rel, data); + // core 39 P4: a shipped row carries its dims, measured from the file as written (so a test that + // breaks something else is not also red on dims); `f.noDims` leaves them off to test that check + const rows = []; + for (const row of f.rows) { + const glb = path.join(dir, 'kit', String(row?.name), 'glTF-Binary', String(row?.variants?.['glTF-Binary'])); + rows.push(!f.noDims && row && !('size' in row) && fs.existsSync(glb) ? withDims(row, dimsOf(await inspectGlb(glb))) : row); + } + w('kit/default.json', JSON.stringify(rows)); w('tools/kit-build/packs.json', JSON.stringify({ limits: f.limits, categories: f.categories, packs: { kit: f.policy } })); w('tools/kit-build/allow.json', JSON.stringify({ allow: f.allow })); w('tools/kit-build/flicker-baseline.json', JSON.stringify({ files: f.baseline })); diff --git a/town-kit/default.json b/town-kit/default.json index 75f9afe..e7f8e19 100644 --- a/town-kit/default.json +++ b/town-kit/default.json @@ -5,7 +5,11 @@ "screenshot": "thumb.webp", "variants": { "glTF-Binary": "road.glb" - } + }, + "size": [2, 0.2, 2], + "box": [-1, 0, -1, 1, 0.2, 1], + "tris": 320, + "bytes": 603416 }, { "name": "RoadCurb", @@ -13,7 +17,11 @@ "screenshot": "thumb.webp", "variants": { "glTF-Binary": "road-curb.glb" - } + }, + "size": [2, 0.35, 2], + "box": [-1, 0, -1, 1, 0.35, 1], + "tris": 416, + "bytes": 633404 }, { "name": "RoadCorner", @@ -31,7 +39,11 @@ "file": "road-corner.lod2.glb", "ratio": 0.27 } - ] + ], + "size": [2, 0.35, 2], + "box": [-1, 0, -1, 1, 0.35, 1], + "tris": 512, + "bytes": 642636 }, { "name": "RoadCrossing", @@ -49,7 +61,11 @@ "file": "road-crossing.lod2.glb", "ratio": 0.27 } - ] + ], + "size": [2, 0.2, 2], + "box": [-1, 0, -1, 1, 0.2, 1], + "tris": 512, + "bytes": 974912 }, { "name": "Sidewalk", @@ -57,7 +73,11 @@ "screenshot": "thumb.webp", "variants": { "glTF-Binary": "sidewalk.glb" - } + }, + "size": [2, 0.35, 2], + "box": [-1, 0, -1, 1, 0.35, 1], + "tris": 320, + "bytes": 368540 }, { "name": "StoneStairs", @@ -65,7 +85,11 @@ "screenshot": "thumb.webp", "variants": { "glTF-Binary": "stone-stairs.glb" - } + }, + "size": [2, 1, 2], + "box": [-1, 0, -1, 1, 1, 1], + "tris": 1538, + "bytes": 543120 }, { "name": "Well", @@ -79,7 +103,11 @@ "file": "well.lod1.glb", "ratio": 0.7 } - ] + ], + "size": [2.62, 2.5, 2.62], + "box": [-1.31, 0, -1.31, 1.31, 2.5, 1.31], + "tris": 3864, + "bytes": 726972 }, { "name": "Fountain", @@ -97,7 +125,11 @@ "file": "fountain.lod2.glb", "ratio": 0.38 } - ] + ], + "size": [3, 2.055, 3], + "box": [-1.5, 0, -1.5, 1.5, 2.055, 1.5], + "tris": 4998, + "bytes": 772656 }, { "name": "MarketStall", @@ -115,7 +147,11 @@ "file": "market-stall.lod2.glb", "ratio": 0.23 } - ] + ], + "size": [2.4, 1.805, 2.008], + "box": [-1.2, 0, -1.004, 1.2, 1.805, 1.004], + "tris": 4764, + "bytes": 744016 }, { "name": "LampPost", @@ -129,7 +165,11 @@ "file": "lamp-post.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [0.64, 3.4, 0.648], + "box": [-0.32, 0, -0.324, 0.32, 3.4, 0.324], + "tris": 2496, + "bytes": 500584 }, { "name": "ParkBench", @@ -147,7 +187,11 @@ "file": "park-bench.lod2.glb", "ratio": 0.3 } - ] + ], + "size": [1.6, 0.764, 0.696], + "box": [-0.8, 0, -0.348, 0.8, 0.764, 0.348], + "tris": 2500, + "bytes": 558980 }, { "name": "MarketCart", @@ -161,7 +205,11 @@ "file": "market-cart.lod1.glb", "ratio": 0.5 } - ] + ], + "size": [2.2, 0.959, 1.358], + "box": [-1.1, 0, -0.679, 1.1, 0.959, 0.679], + "tris": 3999, + "bytes": 640492 }, { "name": "HayBale", @@ -169,7 +217,11 @@ "screenshot": "thumb.webp", "variants": { "glTF-Binary": "hay-bale.glb" - } + }, + "size": [0.9, 0.45, 0.45], + "box": [-0.45, 0, -0.225, 0.45, 0.45, 0.225], + "tris": 1287, + "bytes": 907488 }, { "name": "FlowerBox", @@ -177,7 +229,11 @@ "screenshot": "thumb.webp", "variants": { "glTF-Binary": "flower-box.glb" - } + }, + "size": [1, 0.5, 0.32], + "box": [-0.5, 0, -0.16, 0.5, 0.5, 0.16], + "tris": 2806, + "bytes": 857232 }, { "name": "NoticeBoard", @@ -195,7 +251,11 @@ "file": "notice-board.lod2.glb", "ratio": 0.28 } - ] + ], + "size": [2.2, 2.2, 0.86], + "box": [-1.1, 0, -0.43, 1.1, 2.2, 0.43], + "tris": 2996, + "bytes": 804556 }, { "name": "ClockTowerTop", @@ -213,7 +273,11 @@ "file": "clock-tower-top.lod2.glb", "ratio": 0.28 } - ] + ], + "size": [4.25, 8.528, 4.204], + "box": [-2.125, 0, -2.102, 2.125, 8.528, 2.102], + "tris": 5365, + "bytes": 777932 }, { "name": "Fence", @@ -221,7 +285,11 @@ "screenshot": "thumb.webp", "variants": { "glTF-Binary": "fence.glb" - } + }, + "size": [2, 1.05, 0.12], + "box": [-1, 0, -0.06, 1, 1.05, 0.06], + "tris": 256, + "bytes": 64328 }, { "name": "FenceGate", @@ -238,7 +306,12 @@ "autoplay": false, "collider": "follow", "sound": "gate" - } + }, + "size": [2.022, 2.1, 0.142], + "box": [-1.011, 0, -0.071, 1.011, 2.1, 0.071], + "tris": 368, + "bytes": 109984, + "animated": true }, { "name": "Bridge", @@ -256,7 +329,11 @@ "file": "bridge.lod2.glb", "ratio": 0.29 } - ] + ], + "size": [1.9, 1.64, 4.444], + "box": [-0.95, 0, -2.222, 0.95, 1.64, 2.222], + "tris": 2328, + "bytes": 263684 }, { "name": "Banner", @@ -264,7 +341,11 @@ "screenshot": "thumb.webp", "variants": { "glTF-Binary": "banner.glb" - } + }, + "size": [1.07, 1.5, 0.153], + "box": [-0.535, 0.4, 0, 0.535, 1.9, 0.153], + "tris": 352, + "bytes": 88912 }, { "name": "BannerPole", @@ -272,7 +353,11 @@ "screenshot": "thumb.webp", "variants": { "glTF-Binary": "banner-pole.glb" - } + }, + "size": [1.04, 3.735, 0.5], + "box": [-0.52, 0, -0.25, 0.52, 3.735, 0.25], + "tris": 316, + "bytes": 107668 }, { "name": "Signpost", @@ -280,7 +365,11 @@ "screenshot": "thumb.webp", "variants": { "glTF-Binary": "signpost.glb" - } + }, + "size": [1.615, 2.46, 1.235], + "box": [-0.755, 0, -0.447, 0.86, 2.46, 0.788], + "tris": 68, + "bytes": 63452 }, { "name": "HayStack", @@ -288,7 +377,11 @@ "screenshot": "thumb.webp", "variants": { "glTF-Binary": "hay-stack.glb" - } + }, + "size": [0.9, 0.9, 0.92], + "box": [-0.45, 0, -0.46, 0.45, 0.9, 0.46], + "tris": 3861, + "bytes": 1000372 }, { "name": "LoadedCart", @@ -302,7 +395,11 @@ "file": "loaded-cart.lod1.glb", "ratio": 0.67 } - ] + ], + "size": [2.2, 1.34, 1.358], + "box": [-1.1, 0, -0.679, 1.1, 1.34, 0.679], + "tris": 7860, + "bytes": 1609596 }, { "name": "BarrelCluster", @@ -320,7 +417,11 @@ "file": "barrel-cluster.lod2.glb", "ratio": 0.26 } - ] + ], + "size": [1.225, 0.9, 0.911], + "box": [-0.522, 0, -0.562, 0.703, 0.9, 0.349], + "tris": 7434, + "bytes": 734120 }, { "name": "SacksBarrel", @@ -338,7 +439,11 @@ "file": "sacks-barrel.lod2.glb", "ratio": 0.38 } - ] + ], + "size": [1.646, 0.75, 1.098], + "box": [-0.822, 0, -0.549, 0.824, 0.75, 0.549], + "tris": 6068, + "bytes": 1847232 }, { "name": "FlowerBoxLong", @@ -346,6 +451,10 @@ "screenshot": "thumb.webp", "variants": { "glTF-Binary": "flower-box-long.glb" - } + }, + "size": [2, 0.5, 0.32], + "box": [-1, 0, -0.16, 1, 0.5, 0.16], + "tris": 5612, + "bytes": 989948 } ]