Commit recent project changes

This commit is contained in:
balaji
2026-06-16 16:19:50 +05:30
parent 5b8b90c2fb
commit 972b38057a
4 changed files with 661 additions and 139 deletions
+109 -2
View File
@@ -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 => [