diff --git a/index.html b/index.html
index 758eff7..1ef4782 100644
--- a/index.html
+++ b/index.html
@@ -46,12 +46,12 @@
-
+
-
+ :class="rarityBg(store.selectedFish?.genetics.rarity)"
+ x-text="store.selectedFish?.genetics.rarity.toUpperCase()">
+
@@ -59,20 +59,20 @@
Gender
-
+
Size
-
+
Speed
-
+
Pattern
-
+
Age
-
+
Sell value:
-
+
@@ -82,7 +82,7 @@
diff --git a/src/main.ts b/src/main.ts
index f3008ba..40e9461 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -59,27 +59,10 @@ function getSpeciesUrl(sp: FishSpecies): string {
};
return urls[sp];
}
-// Per-species true longest rendered extent (model units), measured
-// offline with scripts/measure-models.mjs (stride-safe rest-pose +
-// swim-clip evaluation of the actual GLB data). Fish are scaled by
-// targetLength / modelLength. This replaces the old
-// Box3.setFromObject auto-measure, which under-reports armature-scaled
-const SPECIES_LENGTH: Record
= {
- angelfish: 4.2139,
- goldfish: 1.7386,
- guppy: 2.8070,
- betta: 1.0228,
- blue_tang: 1.0192,
- flower_horn: 1.0516,
- neon_tetra: 3.6548,
- oscar: 8.8411,
- knifefish: 23.0140,
-};
function fishToSpec(f: FishData): FishSpec {
return {
url: getSpeciesUrl(f.species),
targetLength: f.genetics.sizeMult * 0.5,
- modelLength: SPECIES_LENGTH[f.species],
speed: [0.3 * f.genetics.speedMult, 0.7 * f.genetics.speedMult],
orient: isQuaternius(f.species) ? { y: Math.PI / 2 } : undefined,
genetics: f.genetics,
diff --git a/src/scene/GLTFish.ts b/src/scene/GLTFish.ts
index 5aff6e6..64e82a9 100644
--- a/src/scene/GLTFish.ts
+++ b/src/scene/GLTFish.ts
@@ -17,28 +17,6 @@ const FOOD_EAT = 0.15;
export interface FishSpec {
url: string;
targetLength: number;
- /**
- * The model's true longest rendered extent in model units, measured
- * offline with `scripts/measure-models.mjs` (stride-safe evaluation of
- * rest pose + swim-clip extremes). The fish is scaled by
- * `targetLength / modelLength`.
- *
- * This replaces the old `Box3.setFromObject` auto-measure, which is
- * unreliable: it measures skinned geometry in skeleton space (an
- * armature's scale/rotation is not in the mesh's matrixWorld and a
- * stale cached bounding box may be used), so it under-reports
- * armature-scaled models (e.g. knifefish 8.89 vs true 22.91, oscar
- * 6.49 vs true 8.84), and for the clownfish GLB it is dominated by
- * the model's 45.3-unit water plane instead of the 8.28-unit fish.
- */
- modelLength: number;
- /**
- * Node names to hide after loading. The clownfish GLB is a whole
- * aquarium scene: a 45.3-unit untextured white "Surface" water plane,
- * a "TopLight" slab, a "Bubbles" prop, and a mirrored duplicate of the
- * body ("Original-Mirrored") — only "ClownFish" is the fish itself.
- */
- hideNodes?: string[];
orient?: { x?: number; y?: number; z?: number };
speed?: Range;
genetics?: Genetics;
@@ -145,31 +123,27 @@ interface Fish {
function buildFish(gltf: GLTF, spec: FishSpec): Fish {
const model = gltf.scene ?? gltf.scenes[0];
- // Hide non-fish scene props before anything else (clownfish GLB bundles
- // a full scene around the fish body).
- if (spec.hideNodes) {
- for (const name of spec.hideNodes) {
- const node = model.getObjectByName(name);
- if (node) node.visible = false;
- }
- }
-
const orient = new THREE.Group();
if (spec.orient) {
orient.rotation.set(spec.orient.x ?? 0, spec.orient.y ?? 0, spec.orient.z ?? 0);
}
- const scale = (spec.targetLength / spec.modelLength) * rand(0.92, 1.08);
- orient.scale.setScalar(scale);
- console.log("[Fish]", spec.url, "target:", spec.targetLength.toFixed(3), "modelLen:", spec.modelLength, "scale:", scale.toFixed(4), "expected rendered:", (scale * spec.modelLength).toFixed(3));
+ // Add the model to orient BEFORE measuring, so the full node hierarchy
+ // (including armature scales) is reflected in the world matrices
orient.add(model);
+ orient.updateMatrixWorld(true);
+
+ // Measure the actual world-space extent of the model
+ const box = new THREE.Box3().setFromObject(model);
+ const size = box.getSize(new THREE.Vector3());
+ const longest = Math.max(size.x, size.y, size.z);
+
+ // Scale so the longest dimension equals targetLength
+ const scale = (spec.targetLength / longest) * rand(0.92, 1.08);
+ orient.scale.setScalar(scale);
const group = new THREE.Group();
group.add(orient);
- group.updateMatrixWorld(true);
- const dbgBox = new THREE.Box3().setFromObject(group);
- const dbgSize = dbgBox.getSize(new THREE.Vector3());
- console.log("[Fish Box3]", spec.url, "x:", dbgSize.x.toFixed(3), "y:", dbgSize.y.toFixed(3), "z:", dbgSize.z.toFixed(3), "max:", Math.max(dbgSize.x, dbgSize.y, dbgSize.z).toFixed(3));
// Apply genetics (color shift, rarity glow)
if (spec.genetics) {