feat: update Spark Plug UI to handle 4 multi-view images and save generated GLB URL
Build and Deploy / build-and-push (push) Successful in 51s
Build and Deploy / build-and-push (push) Successful in 51s
This commit is contained in:
+45
-13
@@ -21,8 +21,8 @@ export default function SparkPlug() {
|
|||||||
// Step 2: Extracted Text
|
// Step 2: Extracted Text
|
||||||
const [extractedPrompt, setExtractedPrompt] = useState<string>('');
|
const [extractedPrompt, setExtractedPrompt] = useState<string>('');
|
||||||
|
|
||||||
// Step 3: Generated Image
|
// Step 3: Generated Images (Multi-view)
|
||||||
const [generatedImage, setGeneratedImage] = useState<string | null>(null);
|
const [generatedImages, setGeneratedImages] = useState<string[]>([]);
|
||||||
|
|
||||||
// Step 4: 3D Model
|
// Step 4: 3D Model
|
||||||
const [modelProgress, setModelProgress] = useState(0);
|
const [modelProgress, setModelProgress] = useState(0);
|
||||||
@@ -76,8 +76,13 @@ export default function SparkPlug() {
|
|||||||
// Mocking the image generation with Nano Banana
|
// Mocking the image generation with Nano Banana
|
||||||
await new Promise(r => setTimeout(r, 3000));
|
await new Promise(r => setTimeout(r, 3000));
|
||||||
|
|
||||||
// Placeholder image for the shampoo sachet
|
// Placeholder images for the 4 views (front, back, left, right)
|
||||||
setGeneratedImage("https://images.unsplash.com/photo-1629198688000-71f23e745b6e?w=800&q=80"); // Generic beauty product placeholder
|
setGeneratedImages([
|
||||||
|
"https://images.unsplash.com/photo-1629198688000-71f23e745b6e?w=400&q=80", // front
|
||||||
|
"https://images.unsplash.com/photo-1629198725848-18e55e975cc3?w=400&q=80", // back
|
||||||
|
"https://images.unsplash.com/photo-1629198725838-511bb7405234?w=400&q=80", // left
|
||||||
|
"https://images.unsplash.com/photo-1629198688000-71f23e745b6e?w=400&q=80", // right
|
||||||
|
]);
|
||||||
|
|
||||||
setCurrentStep(3);
|
setCurrentStep(3);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -89,7 +94,7 @@ export default function SparkPlug() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const processStep3 = async () => {
|
const processStep3 = async () => {
|
||||||
if (!generatedImage) return;
|
if (generatedImages.length === 0) return;
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -118,10 +123,26 @@ export default function SparkPlug() {
|
|||||||
const processStep4 = async () => {
|
const processStep4 = async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
// Create project and save
|
// Mock generated GLB URL from Meshy
|
||||||
|
const mockGlbUrl = "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/BoxTextured/glTF-Binary/BoxTextured.glb";
|
||||||
|
|
||||||
|
// Create project and save with model injected into scene_data
|
||||||
const res = await api.saveProject({
|
const res = await api.saveProject({
|
||||||
name: "Spark Plug Output - Sachet",
|
name: "Spark Plug Output",
|
||||||
scene_data: {} // We would normally attach the generated GLB URL here
|
scene_data: {
|
||||||
|
objects: [
|
||||||
|
{
|
||||||
|
id: "model_" + Date.now(),
|
||||||
|
type: "model",
|
||||||
|
name: "Generated Product Model",
|
||||||
|
visible: true,
|
||||||
|
position: [0, 0, 0],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
scale: [1, 1, 1],
|
||||||
|
url: mockGlbUrl
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if (res.id) {
|
if (res.id) {
|
||||||
navigate(`/editor/${res.id}`);
|
navigate(`/editor/${res.id}`);
|
||||||
@@ -257,14 +278,25 @@ export default function SparkPlug() {
|
|||||||
<div className="flex-1 flex flex-col gap-4 animate-in fade-in slide-in-from-right-8 duration-300">
|
<div className="flex-1 flex flex-col gap-4 animate-in fade-in slide-in-from-right-8 duration-300">
|
||||||
<h2 className="text-xl font-bold">Concept Art generated by Nano Banana</h2>
|
<h2 className="text-xl font-bold">Concept Art generated by Nano Banana</h2>
|
||||||
<p className="text-sm text-zinc-400">
|
<p className="text-sm text-zinc-400">
|
||||||
Review the generated product imagery. These images will be used by Meshy to construct the final 3D model.
|
Review the 4-sided product imagery (front, back, left, right). These images will be used by Meshy's Multi-Image API to construct the final 3D model.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="flex-1 bg-zinc-950 border border-zinc-800 rounded-xl flex items-center justify-center overflow-hidden p-4 relative">
|
<div className="flex-1 bg-zinc-950 border border-zinc-800 rounded-xl p-4">
|
||||||
{generatedImage ? (
|
{generatedImages.length > 0 ? (
|
||||||
<img src={generatedImage} alt="Generated Concept" className="max-w-full max-h-[300px] object-contain rounded-lg shadow-xl" />
|
<div className="grid grid-cols-2 gap-4 h-full">
|
||||||
|
{generatedImages.map((img, idx) => (
|
||||||
|
<div key={idx} className="relative bg-zinc-900 rounded-lg overflow-hidden border border-zinc-800 flex items-center justify-center">
|
||||||
|
<img src={img} alt={`View ${idx + 1}`} className="max-w-full max-h-[150px] object-contain" />
|
||||||
|
<div className="absolute top-2 left-2 bg-black/50 backdrop-blur-sm px-2 py-1 rounded text-[10px] font-bold text-zinc-300">
|
||||||
|
{['FRONT', 'BACK', 'LEFT', 'RIGHT'][idx]}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<ImageIcon size={48} className="text-zinc-800" />
|
<div className="flex h-full items-center justify-center">
|
||||||
|
<ImageIcon size={48} className="text-zinc-800" />
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user