From 7a8073e22eb554ec5dbabd33a82235de204a0892 Mon Sep 17 00:00:00 2001
From: Bissbert <43237892+Bissbert@users.noreply.github.com>
Date: Fri, 17 Jul 2026 10:55:12 +0200
Subject: [PATCH] fix(hero): aim the hero camera at the crystal so it renders
centred in the canvas
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
R3F treats the Canvas `camera` prop as construction-only and never calls lookAt, so the custom-positioned hero camera faced world -Z instead of the crystal — leaving it off-centre (low) in its plate even after the earlier geometry.center() fix. Added onCreated camera.lookAt(0,0,0) so the optical axis runs through the crystal's centroid (already at the origin), and removed the now-redundant drei
wrapper (which offsets by the axis-aligned bbox and is imperfect around a rotating child). Browser-verified with pixel analysis: crystal centroid within ~0.3% of plate centre, stays centred through rotation, static+centred under reduced motion, both themes + mobile OK, no console errors. Build clean.
---
src/components/crystal/HeroCrystal3D.tsx | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/src/components/crystal/HeroCrystal3D.tsx b/src/components/crystal/HeroCrystal3D.tsx
index 3eeb7c0..9eacc0f 100644
--- a/src/components/crystal/HeroCrystal3D.tsx
+++ b/src/components/crystal/HeroCrystal3D.tsx
@@ -7,7 +7,7 @@
*/
import { Canvas, useFrame } from '@react-three/fiber';
-import { Center, Edges } from '@react-three/drei';
+import { Edges } from '@react-three/drei';
import { Suspense, useRef, useState, useEffect } from 'react';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
@@ -231,19 +231,22 @@ export function HeroCrystal3D({
gl={{ antialias: true, alpha: true }}
dpr={[1, 2]}
style={{ background: 'transparent' }}
+ // R3F treats `camera` as construction-only and never orients it, so a
+ // custom position leaves the camera facing world -Z instead of the
+ // crystal. Aim it at the origin (where geometry.center() puts the
+ // crystal's centroid) so it renders centred in the canvas.
+ onCreated={({ camera }) => camera.lookAt(0, 0, 0)}
>
}>
-
- {geometry ? (
-
- ) : (
-
- )}
-
+ {geometry ? (
+
+ ) : (
+
+ )}