Release v0.1.6 2026-07-12
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import { Canvas } from "@react-three/fiber";
|
||||
import { useGLTF } from "@react-three/drei";
|
||||
import { Suspense, useMemo } from "react";
|
||||
import * as THREE from "three";
|
||||
import { clone as cloneSkeleton } from "three/examples/jsm/utils/SkeletonUtils.js";
|
||||
import { BOSS_DEFINITIONS } from "../game/bossCatalog";
|
||||
import { ALTERNATE_BOSS_CONFIG, bossVisualUrl } from "../game/bossVisuals";
|
||||
import type { BossId } from "../game/types";
|
||||
|
||||
function PortraitModel({ bossId }: { bossId: BossId }) {
|
||||
const gltf = useGLTF(bossVisualUrl(bossId), false, true);
|
||||
const model = useMemo(() => {
|
||||
const clone = cloneSkeleton(gltf.scene);
|
||||
clone.updateMatrixWorld(true);
|
||||
const bounds = new THREE.Box3().setFromObject(clone);
|
||||
const center = bounds.getCenter(new THREE.Vector3());
|
||||
const size = bounds.getSize(new THREE.Vector3());
|
||||
const scale = 2.35 / Math.max(size.x, size.y, size.z, 0.001);
|
||||
clone.traverse((object) => {
|
||||
if (object instanceof THREE.Mesh) {
|
||||
object.castShadow = false;
|
||||
object.receiveShadow = false;
|
||||
}
|
||||
});
|
||||
return { clone, center, scale };
|
||||
}, [gltf.scene]);
|
||||
|
||||
return (
|
||||
<primitive
|
||||
object={model.clone}
|
||||
position={[-model.center.x * model.scale, -model.center.y * model.scale, -model.center.z * model.scale]}
|
||||
rotation={[0, bossId === "bulldrome" ? 0.35 : ALTERNATE_BOSS_CONFIG[bossId].rotationOffset + 0.35, 0]}
|
||||
scale={model.scale}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function BossTrophyPortrait({ bossId }: { bossId: BossId }) {
|
||||
const boss = BOSS_DEFINITIONS[bossId];
|
||||
return (
|
||||
<div className="trophy-portrait" aria-label={`${boss.name} portrait`} role="img">
|
||||
<Canvas
|
||||
camera={{ position: [3.4, 2.35, 4.8], zoom: 70, near: 0.1, far: 30 }}
|
||||
dpr={1}
|
||||
frameloop="demand"
|
||||
gl={{ alpha: true, antialias: true, powerPreference: "low-power" }}
|
||||
orthographic
|
||||
>
|
||||
<ambientLight intensity={1.9} />
|
||||
<directionalLight color="#fff3cf" intensity={3.2} position={[3, 5, 4]} />
|
||||
<directionalLight color={boss.accent} intensity={2.1} position={[-4, 2, -2]} />
|
||||
<Suspense fallback={null}><PortraitModel bossId={bossId} /></Suspense>
|
||||
</Canvas>
|
||||
<span aria-hidden="true">{boss.icon}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user