feat: Add HQ image preview modal in SparkPlug and improve Meshy 3D model quality via topology parameters
Build and Deploy / build-and-push (push) Successful in 57s
Build and Deploy / build-and-push (push) Successful in 57s
This commit is contained in:
+3
-1
@@ -516,7 +516,9 @@ app.post('/api/sparkplug/generate-3d', authenticate, async (req, res) => {
|
|||||||
|
|
||||||
const response = await axios.post('https://api.meshy.ai/openapi/v1/multi-image-to-3d', {
|
const response = await axios.post('https://api.meshy.ai/openapi/v1/multi-image-to-3d', {
|
||||||
image_urls: base64Images,
|
image_urls: base64Images,
|
||||||
enable_pbr: true
|
enable_pbr: true,
|
||||||
|
topology: 'quad',
|
||||||
|
target_polycount: 50000
|
||||||
}, {
|
}, {
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Bearer ${meshyKey}`,
|
'Authorization': `Bearer ${meshyKey}`,
|
||||||
|
|||||||
+37
-7
@@ -36,6 +36,9 @@ export default function SparkPlug() {
|
|||||||
const [modelProgress, setModelProgress] = useState(0);
|
const [modelProgress, setModelProgress] = useState(0);
|
||||||
const [generatedGlbUrl, setGeneratedGlbUrl] = useState<string | null>(null);
|
const [generatedGlbUrl, setGeneratedGlbUrl] = useState<string | null>(null);
|
||||||
|
|
||||||
|
// HQ Image Preview
|
||||||
|
const [previewImage, setPreviewImage] = useState<string | null>(null);
|
||||||
|
|
||||||
const handleFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
if (e.target.files && e.target.files[0]) {
|
if (e.target.files && e.target.files[0]) {
|
||||||
setPdfFile(e.target.files[0]);
|
setPdfFile(e.target.files[0]);
|
||||||
@@ -338,14 +341,17 @@ export default function SparkPlug() {
|
|||||||
<div className="flex-1 bg-zinc-950 border border-zinc-800 rounded-xl p-4">
|
<div className="flex-1 bg-zinc-950 border border-zinc-800 rounded-xl p-4">
|
||||||
{generatedImages.length > 0 ? (
|
{generatedImages.length > 0 ? (
|
||||||
<div className="grid grid-cols-2 gap-4 h-full">
|
<div className="grid grid-cols-2 gap-4 h-full">
|
||||||
{generatedImages.map((img, idx) => (
|
{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">
|
<div key={idx} className="relative bg-zinc-900 rounded-lg overflow-hidden border border-zinc-800 flex items-center justify-center group cursor-pointer" onClick={() => setPreviewImage(img)}>
|
||||||
<img src={img} alt={`View ${idx + 1}`} className="max-w-full max-h-[150px] object-contain" />
|
<img src={img} alt={`View ${idx + 1}`} className="max-w-full max-h-[150px] object-contain transition-transform duration-300 group-hover:scale-110" />
|
||||||
<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 uppercase">
|
<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 uppercase">
|
||||||
{idx === 0 ? 'FRONT' : idx === 1 ? 'BACK' : idx === 2 ? 'LEFT' : 'RIGHT'}
|
{idx === 0 ? 'FRONT' : idx === 1 ? 'BACK' : idx === 2 ? 'LEFT' : 'RIGHT'}
|
||||||
|
</div>
|
||||||
|
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/20 transition-colors flex items-center justify-center">
|
||||||
|
<span className="opacity-0 group-hover:opacity-100 text-white font-bold bg-black/50 px-3 py-1 rounded backdrop-blur-sm transition-opacity">Preview HQ</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
))}
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex h-full items-center justify-center">
|
<div className="flex h-full items-center justify-center">
|
||||||
@@ -428,6 +434,30 @@ export default function SparkPlug() {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
{/* HQ Image Preview Modal */}
|
||||||
|
{previewImage && (
|
||||||
|
<div
|
||||||
|
className="fixed inset-0 z-50 flex items-center justify-center bg-black/90 p-8 cursor-zoom-out"
|
||||||
|
onClick={() => setPreviewImage(null)}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className="absolute top-6 right-6 text-white hover:text-red-500 transition-colors z-50"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setPreviewImage(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
||||||
|
</button>
|
||||||
|
<img
|
||||||
|
src={previewImage}
|
||||||
|
alt="HQ Preview"
|
||||||
|
className="max-w-full max-h-full object-contain rounded-lg shadow-2xl cursor-default"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user