<title>Cinematic Concept: Stone Giant</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
.aspect-9-16 {
aspect-ratio: 9 / 16;
}
/* Simulates the camera slowly moving backward while looking up */
@keyframes cameraMoveBackward {
0% {
transform: scale(1.15) translateY(-2%);
filter: brightness(1.1);
}
100% {
transform: scale(1) translateY(0%);
filter: brightness(1);
}
}
.cinematic-zoom {
animation: cameraMoveBackward 5s ease-out forwards;
}
/* Loading spinner */
.loader {
border-top-color: #f97316; /* Orange for glowing eyes vibe */
-webkit-animation: spinner 1.5s linear infinite;
animation: spinner 1.5s linear infinite;
}
@keyframes spinner {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
<div class="max-w-sm w-full bg-gray-900 rounded-2xl overflow-hidden shadow-2xl border border-gray-800 flex flex-col">
<div class="p-4 border-b border-gray-800 bg-gray-900/80 backdrop-blur z-10">
<h1 class="text-lg font-bold text-center tracking-wide text-gray-100">Shot 01: The Morning Commute</h1>
<p class="text-xs text-gray-400 text-center mt-1">5-Second Cinematic Camera Pull-Back</p>
</div>
<!-- Video/Scene Container -->
<div id="media-container" class="relative w-full aspect-9-16 bg-black overflow-hidden flex items-center justify-center">
<!-- Loading State -->
<div id="loading-state" class="flex flex-col items-center justify-center space-y-4 absolute inset-0 bg-gray-900 z-10">
<div class="loader ease-linear rounded-full border-4 border-t-4 border-gray-700 h-10 w-10 mb-2"></div>
<p class="text-xs font-medium animate-pulse text-gray-400 tracking-wider uppercase">Rendering Frame...</p>
</div>
</div>
<!-- Controls -->
<div class="p-4 bg-gray-900 flex justify-center border-t border-gray-800 hidden relative z-10" id="controls">
<button onclick="replayAnimation()" class="bg-orange-600 hover:bg-orange-500 text-white p-3 rounded-full transition-all focus:outline-none focus:ring-4 focus:ring-orange-500/50 shadow-lg shadow-orange-900/50 flex items-center justify-center group" title="Replay 5s Scene">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" class="translate-x-[2px] group-hover:scale-110 transition-transform"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>
</button>
</div>
</div>
<script>
const apiKey = "";
// Condensed prompt per instructions
const promptText = "Vertical 9:16. Low angle backward track. Giant muscular dark-gray stone warrior walks through morning SE Asian traffic. Glowing orange eyes, serious. Realistic cars, morning sun, cinematic depth. No text/watermarks.";
// Exponential backoff retry logic for API calls
async function fetchWithRetry(url, options, retries = 5) {
const delays = [1000, 2000, 4000, 8000, 16000];
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.error) {
throw new Error(data.error.message);
}
return data;
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(res => setTimeout(res, delays[i]));
}
}
}
async function generateScene() {
const container = document.getElementById('media-container');
const loading = document.getElementById('loading-state');
const controls = document.getElementById('controls');
try {
const data = await fetchWithRetry(`https://generativelanguage.googleapis.com/v1beta/models/imagen-4.0-generate-001:predict?key=${apiKey}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
instances: { prompt: promptText },
parameters: { sampleCount: 1 }
})
});
if (data.predictions && data.predictions[0]) {
const imageUrl = `data:image/png;base64,${data.predictions[0].bytesBase64Encoded}`;
// Fade out loading, insert image, and start animation
loading.classList.add('hidden');
// The origin-bottom ensures the camera looks up from the street level while zooming out
const imgElement = document.createElement('img');
imgElement.id = 'scene-image';
imgElement.src = imageUrl;
imgElement.alt = "Stone Giant in Traffic";
imgElement.className = "w-full h-full object-cover cinematic-zoom origin-bottom";
container.appendChild(imgElement);
controls.classList.remove('hidden');
} else {
throw new Error('No image generated.');
}
} catch (error) {
loading.innerHTML = `
<div class="text-red-500 mb-2">
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mx-auto"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>
</div>
<p class="text-sm text-red-400 text-center px-4 font-semibold">Failed to render scene.</p>
<p class="text-xs text-red-400/80 text-center px-4 mt-1">Please try again later.</p>
`;
}
}
function replayAnimation() {
const img = document.getElementById('scene-image');
if (img) {
// Trigger reflow to restart the 5-second CSS animation
img.classList.remove('cinematic-zoom');
void img.offsetWidth; // magic reflow trick
img.classList.add('cinematic-zoom');
}
}
// Start generation immediately upon load
window.onload = generateScene;
</script>
!DOCTYPE html>
<title>Cinematic Concept: Stone Giant</title> <script src="https://cdn.tailwindcss.com"></script> <style> .aspect-9-16 { aspect-ratio: 9 / 16; }