Add compression ratios and animation support to 3D viewer
This commit is contained in:
File diff suppressed because one or more lines are too long
1
dist/assets/index-0Vn4RLxh.js.map
vendored
Normal file
1
dist/assets/index-0Vn4RLxh.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/assets/index-2z9TbcuZ.js.map
vendored
1
dist/assets/index-2z9TbcuZ.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/index.html
vendored
2
dist/index.html
vendored
@@ -9,7 +9,7 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<script type="module" crossorigin src="./assets/index-2z9TbcuZ.js"></script>
|
||||
<script type="module" crossorigin src="./assets/index-0Vn4RLxh.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-DplxtjX9.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Suspense, useState } from 'react';
|
||||
import { Suspense, useState, useEffect } from 'react';
|
||||
import { Canvas } from '@react-three/fiber';
|
||||
import { OrbitControls, useGLTF, Environment, ContactShadows, Center } from '@react-three/drei';
|
||||
import { OrbitControls, useGLTF, useAnimations, Environment, ContactShadows, Center } from '@react-three/drei';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { Box, AlertCircle, RotateCw, ZoomIn, Move, X } from 'lucide-react';
|
||||
|
||||
@@ -37,12 +37,21 @@ function ViewerError({ message, onClose }: { message: string; onClose: () => voi
|
||||
}
|
||||
|
||||
// The actual 3D model component
|
||||
function Model({ url }: { url: string }) {
|
||||
const { scene } = useGLTF(url);
|
||||
function Model({ url, animated = false }: { url: string; animated?: boolean }) {
|
||||
const { scene, animations } = useGLTF(url);
|
||||
const { actions } = useAnimations(animations, scene);
|
||||
|
||||
// Auto-play animation if available and model is flagged as animated
|
||||
useEffect(() => {
|
||||
if (animated && actions && Object.keys(actions).length > 0) {
|
||||
const firstAction = Object.values(actions)[0];
|
||||
firstAction?.play();
|
||||
}
|
||||
}, [animated, actions]);
|
||||
|
||||
return (
|
||||
<Center>
|
||||
<primitive object={scene} scale={1.5} />
|
||||
<primitive object={scene} scale={animated ? 1.2 : 1.5} />
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
@@ -72,12 +81,12 @@ function Loader() {
|
||||
|
||||
// Available models with correct paths
|
||||
const availableModels = [
|
||||
{ name: 'T-Pose Character', file: 'models/T-pose_web.glb', size: '428 KB' },
|
||||
{ name: 'Jogging Character', file: 'models/Jogging_web.glb', size: '235 KB' },
|
||||
{ name: 'Old Man Idle', file: 'models/Old Man Idle_web.glb', size: '282 KB' },
|
||||
{ name: 'Doless Model', file: 'models/Doless_web.glb', size: '65 KB' },
|
||||
{ name: 'AI Character', file: 'models/ComfyUI_00003__web.glb', size: '752 KB' },
|
||||
{ name: 'David Bust (OBJ+MTL)', file: 'models/bust_of_David_web.glb', size: '6 MB' },
|
||||
{ name: 'T-Pose Character', file: 'models/T-pose_web.glb', size: '418 KB', original: '2.1 MB', compression: '80%' },
|
||||
{ name: 'Jogging Character', file: 'models/Jogging_web.glb', size: '235 KB', original: '1.8 MB FBX', compression: '87%', animated: true },
|
||||
{ name: 'Old Man Idle', file: 'models/Old Man Idle_web.glb', size: '282 KB', original: '2.1 MB FBX', compression: '87%', animated: true },
|
||||
{ name: 'Doless Model', file: 'models/Doless_web.glb', size: '66 KB', original: '6.6 MB OBJ', compression: '99%' },
|
||||
{ name: 'AI Character', file: 'models/ComfyUI_00003__web.glb', size: '753 KB', original: '4.9 MB', compression: '85%' },
|
||||
{ name: 'David Bust (OBJ+MTL)', file: 'models/bust_of_David_web.glb', size: '6 MB', original: '29 MB OBJ', compression: '79%' },
|
||||
];
|
||||
|
||||
export default function Model3DViewer() {
|
||||
@@ -133,8 +142,33 @@ export default function Model3DViewer() {
|
||||
</div>
|
||||
<h3>{model.name}</h3>
|
||||
<p style={{ color: 'var(--text-muted)', fontSize: '0.9rem' }}>
|
||||
Web-optimized GLB • {model.size}
|
||||
{model.original} → {model.size}
|
||||
</p>
|
||||
{model.animated && (
|
||||
<span style={{
|
||||
background: 'rgba(6, 182, 212, 0.2)',
|
||||
color: '#06b6d4',
|
||||
padding: '0.25rem 0.5rem',
|
||||
borderRadius: '4px',
|
||||
fontSize: '0.75rem',
|
||||
fontWeight: 600,
|
||||
marginTop: '0.5rem',
|
||||
display: 'inline-block'
|
||||
}}>
|
||||
▶ Animated
|
||||
</span>
|
||||
)}
|
||||
<div style={{
|
||||
marginTop: '0.75rem',
|
||||
padding: '0.4rem 0.75rem',
|
||||
background: 'rgba(139, 92, 246, 0.1)',
|
||||
borderRadius: '6px',
|
||||
display: 'inline-block'
|
||||
}}>
|
||||
<span style={{ color: '#8b5cf6', fontSize: '0.8rem', fontWeight: 600 }}>
|
||||
Draco: -{model.compression} smaller
|
||||
</span>
|
||||
</div>
|
||||
<div style={{
|
||||
marginTop: '1rem',
|
||||
padding: '0.5rem 1rem',
|
||||
@@ -212,7 +246,7 @@ export default function Model3DViewer() {
|
||||
<ambientLight intensity={0.5} />
|
||||
<directionalLight position={[10, 10, 5]} intensity={1} />
|
||||
<Environment preset="city" />
|
||||
<Model url={selectedModel} />
|
||||
<Model url={selectedModel} animated={availableModels.find(m => m.file === selectedModel)?.animated} />
|
||||
<ContactShadows
|
||||
position={[0, -1.5, 0]}
|
||||
opacity={0.4}
|
||||
|
||||
Reference in New Issue
Block a user