import { generateImageFrame } from "./openrouter.js"; import { buildGifFromFrames } from "./gif.js"; import { firstPrompt, nextFramePrompt, clampForm } from "./ui.js"; window.vibeGifApp = function () { return { settingsOpen: false, loading: false, error: "", apiKeyInput: "", apiKey: "", progressLabel: "", progressPct: 0, frames: [], gifUrl: "", form: { model: "google/gemini-3.1-flash-image-preview", userPrompt: "", frameCount: 4, fps: 6, imageSize: "1K", aspectRatio: "1:1" }, refreshIcons() { if (!window.lucide?.createIcons) return; window.lucide.createIcons(); }, init() { this.apiKey = localStorage.getItem("openrouter_api_key") || ""; this.apiKeyInput = this.apiKey || ""; this.$nextTick(() => this.refreshIcons()); setTimeout(() => this.refreshIcons(), 0); setTimeout(() => this.refreshIcons(), 120); this.$watch("settingsOpen", () => this.$nextTick(() => this.refreshIcons())); this.$watch("form.model", () => { if (this.form.model !== "google/gemini-3.1-flash-image-preview" && this.form.imageSize === "0.5K") { this.form.imageSize = "1K"; } }); }, saveApiKey() { this.apiKey = this.apiKeyInput.trim(); localStorage.setItem("openrouter_api_key", this.apiKey); this.settingsOpen = false; }, clearApiKey() { this.apiKey = ""; this.apiKeyInput = ""; localStorage.removeItem("openrouter_api_key"); }, async generate() { this.error = ""; this.gifUrl = ""; this.frames = []; this.progressLabel = ""; this.progressPct = 0; clampForm(this.form); if (!this.apiKey) { this.error = "Add your OpenRouter API key first (panel-left icon)."; this.settingsOpen = true; return; } if (!this.form.userPrompt) { this.error = "Please enter a simple prompt (e.g. rolling cat)."; return; } this.loading = true; try { const total = this.form.frameCount; const p1 = firstPrompt(this.form.userPrompt); this.progressLabel = `Generating frame 1/${total}...`; const frame1 = await generateImageFrame({ apiKey: this.apiKey, model: this.form.model, textPrompt: p1, previousFrames: [], imageSize: this.form.imageSize, aspectRatio: this.form.aspectRatio }); this.frames.push(frame1); this.progressPct = Math.round((1 / total) * 100); for (let i = 2; i <= total; i++) { this.progressLabel = `Generating frame ${i}/${total}...`; const next = await generateImageFrame({ apiKey: this.apiKey, model: this.form.model, textPrompt: nextFramePrompt(total), previousFrames: this.frames.slice(-2), imageSize: this.form.imageSize, aspectRatio: this.form.aspectRatio }); this.frames.push(next); this.progressPct = Math.round((i / total) * 100); } this.progressLabel = "Building GIF..."; this.gifUrl = await buildGifFromFrames(this.frames, this.form.fps); this.progressLabel = "Done."; this.progressPct = 100; } catch (e) { this.error = e?.message || "Failed to generate."; } finally { this.loading = false; } } }; };