Feat: semi-transparent mode with animated webp

This commit is contained in:
2026-03-21 00:36:15 -07:00
parent 23ee7642ae
commit 4de18f3825

View File

@@ -2,6 +2,8 @@ import { getApiKey, setApiKey, hasApiKey } from './core/storage.js';
import { buildFirstMessage, buildNextMessage } from './core/messages.js'; import { buildFirstMessage, buildNextMessage } from './core/messages.js';
import { generateFrame } from './services/openrouter.js'; import { generateFrame } from './services/openrouter.js';
import { assembleGif } from './services/gif.js'; import { assembleGif } from './services/gif.js';
import { removeBackgroundFrames } from './services/background.js';
import { assembleAnimatedWebp } from './services/webp.js';
import { import {
ELEMENT_IDS, ELEMENT_IDS,
grabElements, grabElements,
@@ -62,6 +64,9 @@ async function handleGenerate() {
const maxSize = Math.max(32, Math.min(1024, Number.parseInt(el.inpMaxSize?.value || '256', 10) || 256)); const maxSize = Math.max(32, Math.min(1024, Number.parseInt(el.inpMaxSize?.value || '256', 10) || 256));
const imageSize = '1K'; const imageSize = '1K';
const aspectRatio = el.selRatio?.value || '1:1'; const aspectRatio = el.selRatio?.value || '1:1';
const semiTransparent = !!el.chkSemiTransparent?.checked;
const generationMaxPct = semiTransparent ? 55 : 100;
setGenerating(el, true); setGenerating(el, true);
resetProgress(el); resetProgress(el);
@@ -86,10 +91,10 @@ async function handleGenerate() {
allFrames.push(first.base64); allFrames.push(first.base64);
history.push(firstMsg, first.assistantMsg); history.push(firstMsg, first.assistantMsg);
addFramePreview(el, first.base64, 0); addFramePreview(el, first.base64, 0);
setProgress(el, Math.round(100 / frameCount), `frame 1 of ${frameCount} done`); setProgress(el, Math.round((1 / frameCount) * generationMaxPct), `frame 1 of ${frameCount} done`);
for (let i = 2; i <= frameCount; i++) { for (let i = 2; i <= frameCount; i++) {
setProgress(el, Math.round(((i - 1) / frameCount) * 100), `generating frame ${i} of ${frameCount}...`); setProgress(el, Math.round(((i - 1) / frameCount) * generationMaxPct), `generating frame ${i} of ${frameCount}...`);
const nextUserMsg = buildNextMessage(i, frameCount); const nextUserMsg = buildNextMessage(i, frameCount);
const startIdx = Math.max(1, history.length - WINDOW * 2); const startIdx = Math.max(1, history.length - WINDOW * 2);
@@ -106,14 +111,35 @@ async function handleGenerate() {
allFrames.push(next.base64); allFrames.push(next.base64);
history.push(nextUserMsg, next.assistantMsg); history.push(nextUserMsg, next.assistantMsg);
addFramePreview(el, next.base64, i - 1); addFramePreview(el, next.base64, i - 1);
setProgress(el, Math.round((i / frameCount) * 100), `frame ${i} of ${frameCount} done`); setProgress(el, Math.round((i / frameCount) * generationMaxPct), `frame ${i} of ${frameCount} done`);
} }
setProgress(el, 100, 'assembling gif...'); if (!semiTransparent) {
const blob = await assembleGif(allFrames, fps, maxSize); setProgress(el, 100, 'assembling gif...');
currentGifUrl = URL.createObjectURL(blob); const blob = await assembleGif(allFrames, fps, maxSize);
showResult(el, currentGifUrl); currentGifUrl = URL.createObjectURL(blob);
setProgress(el, 100, 'done! 🎉'); showResult(el, currentGifUrl, 'vibegif.gif');
setProgress(el, 100, 'done! 🎉');
return;
}
setProgress(el, 56, 'starting background removal...');
const transparentFrames = await removeBackgroundFrames(allFrames, {
onProgress: ({ pct, text }) => {
const mapped = Math.round(55 + (Math.max(0, Math.min(100, pct)) * 0.30));
setProgress(el, mapped, text || 'removing backgrounds...');
}
});
setProgress(el, 86, 'assembling animated webp...');
const webpBlob = await assembleAnimatedWebp(transparentFrames, fps, maxSize, (pct, text) => {
const mapped = Math.round(85 + (Math.max(0, Math.min(100, pct)) * 0.15));
setProgress(el, mapped, text || 'assembling animated webp...');
});
currentGifUrl = URL.createObjectURL(webpBlob);
showResult(el, currentGifUrl, 'vibegif.webp');
setProgress(el, 100, 'done! transparent animated webp ready ✨');
} catch (err) { } catch (err) {
const msg = err?.message || String(err); const msg = err?.message || String(err);
setProgress(el, 0, `error: ${msg}`); setProgress(el, 0, `error: ${msg}`);