Commit recent project changes
This commit is contained in:
+109
-2
@@ -40,15 +40,19 @@ import {
|
||||
Clipboard,
|
||||
RotateCw,
|
||||
Save,
|
||||
FolderOpen
|
||||
FolderOpen,
|
||||
Sparkles
|
||||
} from "lucide-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { ErrorBoundary } from "./components/ErrorBoundary";
|
||||
import { ModelViewer } from "./components/ModelViewer";
|
||||
import { JuiceBox } from "./components/JuiceBox";
|
||||
import { RenderModal, RenderSettings } from "./components/RenderModal";
|
||||
import { UnifiedMappingMaterial } from './components/UnifiedMappingMaterial';
|
||||
import { ImageTo3DModal } from "./components/ImageTo3DModal";
|
||||
import { UVEditor } from "./components/UVEditor";
|
||||
import { VizAiModal } from "./components/VizAiModal";
|
||||
import { ApiSettingsModal } from "./components/ApiSettingsModal";
|
||||
import { EffectComposer, DepthOfField, Bloom, Vignette, BrightnessContrast, HueSaturation } from "@react-three/postprocessing";
|
||||
import { cn } from "./lib/utils";
|
||||
import * as THREE from "three";
|
||||
@@ -412,6 +416,9 @@ export default function App() {
|
||||
const [backgroundType, setBackgroundType] = useState<"color" | "hdri" | "image">("color");
|
||||
const [showGrid, setShowGrid] = useState(true);
|
||||
const [showRenderModal, setShowRenderModal] = useState(false);
|
||||
const [showVizAi, setShowVizAi] = useState(false);
|
||||
const [showApiSettings, setShowApiSettings] = useState(false);
|
||||
const [vizAiBaseImage, setVizAiBaseImage] = useState<string | null>(null);
|
||||
const [renderRequest, setRenderRequest] = useState<RenderSettings | null>(null);
|
||||
const [exportRequest, setExportRequest] = useState(false);
|
||||
const [exportFormat, setExportFormat] = useState<'glb' | 'usdz'>('glb');
|
||||
@@ -1716,7 +1723,28 @@ export default function App() {
|
||||
<span className="hover:text-white cursor-pointer">Camera</span>
|
||||
<span className="hover:text-white cursor-pointer">Image</span>
|
||||
<span className="hover:text-white cursor-pointer">Render</span>
|
||||
<span className="hover:text-white cursor-pointer">Tools</span>
|
||||
<div className="relative">
|
||||
<span
|
||||
className="hover:text-primary cursor-pointer px-1 py-0.5 rounded hover:bg-white/40 dark:hover:bg-white/5 transition-colors"
|
||||
onClick={() => setOpenMenu(openMenu === 'tools' ? null : 'tools')}
|
||||
>
|
||||
Tools
|
||||
</span>
|
||||
{openMenu === 'tools' && (
|
||||
<div className="absolute top-full left-0 mt-1 w-48 bg-zinc-900 border border-zinc-800 rounded-lg shadow-xl py-1 z-50">
|
||||
<button
|
||||
className="w-full flex items-center gap-2 px-4 py-2 text-xs text-zinc-300 hover:bg-zinc-800 hover:text-white"
|
||||
onClick={() => {
|
||||
setShowApiSettings(true);
|
||||
setOpenMenu(null);
|
||||
}}
|
||||
>
|
||||
<Settings size={14} />
|
||||
<span>API Settings</span>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="relative">
|
||||
<span
|
||||
className="hover:text-primary cursor-pointer px-1 py-0.5 rounded hover:bg-white/40 dark:hover:bg-white/5 transition-colors"
|
||||
@@ -2372,6 +2400,17 @@ export default function App() {
|
||||
onRender={(settings) => setRenderRequest(settings)}
|
||||
/>
|
||||
|
||||
<VizAiModal
|
||||
isOpen={showVizAi}
|
||||
onClose={() => setShowVizAi(false)}
|
||||
baseImage={vizAiBaseImage}
|
||||
/>
|
||||
|
||||
<ApiSettingsModal
|
||||
isOpen={showApiSettings}
|
||||
onClose={() => setShowApiSettings(false)}
|
||||
/>
|
||||
|
||||
{/* Export / Save Dialog */}
|
||||
{exportDialog && (
|
||||
<div className="fixed inset-0 z-[200] flex items-center justify-center bg-black/60 backdrop-blur-sm"
|
||||
@@ -4560,6 +4599,19 @@ export default function App() {
|
||||
<ImageIcon size={18} />
|
||||
<span className="text-[9px]">Render</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
const canvas = document.querySelector('canvas');
|
||||
if (canvas) {
|
||||
setVizAiBaseImage(canvas.toDataURL("image/png"));
|
||||
setShowVizAi(true);
|
||||
}
|
||||
}}
|
||||
className="flex flex-col items-center gap-0.5 text-blue-500 hover:text-blue-400 transition-colors"
|
||||
>
|
||||
<Sparkles size={18} />
|
||||
<span className="text-[9px]">Viz AI</span>
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="text-[10px] text-zinc-500 mr-4">
|
||||
@@ -4749,6 +4801,61 @@ export default function App() {
|
||||
}
|
||||
});
|
||||
|
||||
// Save model data for scene persistence
|
||||
const modelBlob = await fetch(modelUrl).then(r => r.blob());
|
||||
const modelBase64 = await new Promise<string>((resolve) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => resolve(reader.result as string);
|
||||
reader.readAsDataURL(modelBlob);
|
||||
});
|
||||
setModelData({ name: "Generated_Model.glb", data: modelBase64, extension: 'glb' });
|
||||
|
||||
const boundingBox = new THREE.Box3().setFromObject(object);
|
||||
const center = new THREE.Vector3();
|
||||
boundingBox.getCenter(center);
|
||||
const size = new THREE.Vector3();
|
||||
boundingBox.getSize(size);
|
||||
const maxDim = Math.max(size.x || 0, size.y || 0, size.z || 0) || 1;
|
||||
const radius = maxDim / 2;
|
||||
const minY = boundingBox.min.y;
|
||||
|
||||
setModelBounds({ center, size, maxDim, minY, radius });
|
||||
|
||||
if (directionalLightRef.current) {
|
||||
const light = directionalLightRef.current;
|
||||
light.shadow.camera.left = -maxDim;
|
||||
light.shadow.camera.right = maxDim;
|
||||
light.shadow.camera.top = maxDim;
|
||||
light.shadow.camera.bottom = -maxDim;
|
||||
light.shadow.camera.near = 0.1;
|
||||
light.shadow.camera.far = maxDim * 5;
|
||||
light.shadow.camera.updateProjectionMatrix();
|
||||
light.shadow.mapSize.width = 2048;
|
||||
light.shadow.mapSize.height = 2048;
|
||||
}
|
||||
|
||||
let cameraZDistance = 0;
|
||||
if (cameraRef.current) {
|
||||
const camera = cameraRef.current;
|
||||
const fovRadians = camera.fov * (Math.PI / 180);
|
||||
cameraZDistance = radius / Math.sin(fovRadians / 2);
|
||||
cameraZDistance *= 1.5;
|
||||
|
||||
camera.position.set(center.x, center.y + (maxDim / 4), center.z + cameraZDistance);
|
||||
camera.near = radius / 100;
|
||||
camera.far = radius * 100;
|
||||
camera.updateProjectionMatrix();
|
||||
camera.lookAt(center);
|
||||
}
|
||||
|
||||
if (orbitControlsRef.current) {
|
||||
const controls = orbitControlsRef.current;
|
||||
if (center) controls.target.copy(center);
|
||||
controls.minDistance = radius / 2;
|
||||
controls.maxDistance = (cameraZDistance || radius * 10) * 5;
|
||||
controls.update();
|
||||
}
|
||||
|
||||
setLoadedModel(object);
|
||||
setBlobURLs(prev => [...prev, modelUrl]);
|
||||
setSceneObjects(prev => [
|
||||
|
||||
Reference in New Issue
Block a user