fix(rsplat): resize images client-side before 3D generation, pass through fal.ai errors

Mobile photos (12MP+) were causing generation failures due to large base64 payloads.
Now resizes to max 1024px before sending. Server now returns actual fal.ai error
messages instead of generic "3D generation failed".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-03-15 16:56:35 -07:00
parent e5b5c551b1
commit c5f757d050
2 changed files with 40 additions and 9 deletions

View File

@ -521,15 +521,13 @@ export class FolkSplatViewer extends HTMLElement {
submitBtn.disabled = true;
actions.style.display = "none";
progress.style.display = "block";
status.textContent = "";
status.textContent = "Preparing image...";
try {
const reader = new FileReader();
const dataUrl = await new Promise<string>((resolve) => {
reader.onload = () => resolve(reader.result as string);
reader.readAsDataURL(selectedFile!);
});
// Resize image to max 1024px to reduce payload and improve API success
const dataUrl = await this.resizeImage(selectedFile!, 1024);
status.textContent = "Generating 3D model...";
const res = await fetch("/api/3d-gen", {
method: "POST",
headers: { "Content-Type": "application/json" },
@ -572,6 +570,30 @@ export class FolkSplatViewer extends HTMLElement {
});
}
// ── Image helpers ──
private resizeImage(file: File, maxSize: number): Promise<string> {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => {
let { width, height } = img;
if (width > maxSize || height > maxSize) {
const scale = maxSize / Math.max(width, height);
width = Math.round(width * scale);
height = Math.round(height * scale);
}
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d")!;
ctx.drawImage(img, 0, 0, width, height);
resolve(canvas.toDataURL("image/jpeg", 0.9));
};
img.onerror = () => reject(new Error("Failed to load image"));
img.src = URL.createObjectURL(file);
});
}
// ── Viewer ──
private renderViewer() {

View File

@ -998,9 +998,18 @@ app.post("/api/3d-gen", async (c) => {
});
if (!res.ok) {
const err = await res.text();
console.error("[3d-gen] fal.ai error:", err);
return c.json({ error: "3D generation failed" }, 502);
const errText = await res.text();
console.error("[3d-gen] fal.ai error:", res.status, errText);
let detail = "3D generation failed";
try {
const parsed = JSON.parse(errText);
if (parsed.detail) {
detail = typeof parsed.detail === "string" ? parsed.detail
: Array.isArray(parsed.detail) ? parsed.detail[0]?.msg || detail
: detail;
}
} catch {}
return c.json({ error: detail }, 502);
}
const data = await res.json();