feat: improve AI layer editing UI, enforce aspect ratio matching through system prompt constraints
Build and Deploy / build-and-push (push) Successful in 57s

This commit is contained in:
AI Bot
2026-10-05 12:48:43 +05:30
parent cf3c114172
commit e8b88fcead
+28 -22
View File
@@ -69,7 +69,11 @@ export function UVEditor({ onClose, onSave, targetObject, loadedModel, sceneObje
ctx.drawImage(layer.img, 0, 0);
const base64 = tempCanvas.toDataURL('image/png');
const newUrl = await editUVLayer(aiPrompt, base64, token || '');
const fullPrompt = `The user has provided an image layer. Please apply the following edit exactly as requested, while strictly maintaining the EXACT same aspect ratio, resolution, and general structure of the original image.
User Prompt: "${aiPrompt}"
Negative constraints: Do NOT change the aspect ratio. Do NOT add completely unrelated elements. Do NOT crop the image boundaries.`;
const newUrl = await editUVLayer(fullPrompt, base64, token || '');
if (!originalLayerUrl && !regenerate) {
setOriginalLayerUrl(layer.url);
@@ -485,43 +489,45 @@ export function UVEditor({ onClose, onSave, targetObject, loadedModel, sceneObje
{/* AI Layer Edit */}
<div className="h-px bg-zinc-700 my-1" />
<p className="text-[10px] font-bold text-zinc-500 uppercase tracking-widest flex items-center justify-between">
AI Texture Edit
<span className="flex items-center gap-1.5"><span className="text-blue-400">✨</span> Edit with AI</span>
</p>
<div className="flex flex-col gap-2 relative">
{isEditingLayer && (
<div className="absolute inset-0 z-10 flex flex-col items-center justify-center bg-zinc-900/80 backdrop-blur-sm rounded border border-zinc-700 p-2 text-center text-xs text-blue-400">
<Loader2 size={18} className="animate-spin mb-1" />
Generating...
</div>
)}
<textarea
placeholder="e.g. Change the color to red, add a vintage filter..."
value={aiPrompt}
onChange={e => setAiPrompt(e.target.value)}
className="w-full h-16 bg-zinc-900 border border-zinc-700 rounded p-2 text-xs text-zinc-300 placeholder:text-zinc-600 resize-none outline-none focus:border-blue-500"
/>
{aiPreviewUrl ? (
<div className="flex flex-col gap-2">
<p className="text-[10px] text-zinc-400">Review AI Generation:</p>
<div className="flex gap-2">
<button onClick={handleApproveEdit} className="flex-1 bg-green-500 hover:bg-green-600 text-white py-1.5 rounded text-xs font-semibold">
<button onClick={handleApproveEdit} className="flex-1 py-1.5 bg-green-500/20 text-green-400 hover:bg-green-500/30 rounded text-[11px] font-semibold border border-green-500/30 transition-colors">
Approve
</button>
<button onClick={handleRejectEdit} className="flex-1 bg-zinc-700 hover:bg-zinc-600 text-white py-1.5 rounded text-xs font-semibold">
Reject
<button onClick={() => handleAiEdit(true)} className="flex-1 py-1.5 bg-blue-500/20 text-blue-400 hover:bg-blue-500/30 rounded text-[11px] font-semibold border border-blue-500/30 transition-colors">
Regenerate
</button>
</div>
<button onClick={() => handleAiEdit(true)} disabled={isEditingLayer} className="w-full bg-blue-500/20 hover:bg-blue-500/30 text-blue-400 py-1.5 rounded text-xs font-semibold flex items-center justify-center gap-2">
{isEditingLayer ? <Loader2 size={12} className="animate-spin" /> : null} Regenerate
<button onClick={handleRejectEdit} className="flex-1 py-1.5 bg-red-500/20 text-red-400 hover:bg-red-500/30 rounded text-[11px] font-semibold border border-red-500/30 transition-colors">
Revert
</button>
</div>
) : (
<div className="flex flex-col gap-2">
<textarea
value={aiPrompt}
onChange={e => setAiPrompt(e.target.value)}
placeholder="e.g. Turn into a rusty metal texture"
className="w-full bg-zinc-900 border border-zinc-700 rounded p-2 text-xs text-zinc-200 placeholder-zinc-600 resize-none h-16 outline-none focus:border-blue-500"
/>
<button
onClick={() => handleAiEdit(false)}
disabled={isEditingLayer || !aiPrompt.trim()}
className="w-full bg-blue-500 hover:bg-blue-600 disabled:opacity-50 text-white py-1.5 rounded text-xs font-semibold flex items-center justify-center gap-2 transition-colors"
disabled={!aiPrompt.trim()}
className="w-full py-1.5 bg-blue-500/10 hover:bg-blue-500/20 disabled:opacity-50 disabled:cursor-not-allowed rounded text-[11px] font-semibold text-blue-400 border border-blue-500/30 transition-colors flex items-center justify-center gap-1.5"
>
{isEditingLayer ? <Loader2 size={14} className="animate-spin" /> : null}
Generate Edit
<span className="text-[14px] leading-none">✨</span> Generate Edit
</button>
</div>
)}
</div>
</div>
)}
</div>
</div>