Loading playground
Input
Additional Settings
Customize your input with more control.
Result
Idle
Customize your input with more control.
Customize your input with more control.
Hint: Drag and drop video files from your computer, video from web pages, paste from clipboard (Ctrl/Cmd+V), or provide a URL. Accepted file types: mp4, mov, webm, m4v, gif
Hint: Drag and drop image files from your computer, images from web pages, paste from clipboard (Ctrl/Cmd+V), or provide a URL. Accepted file types: jpg, jpeg, png, webp, gif, avif, heic, heif
Hint: Drag and drop audio files from your computer, audio from web pages, paste from clipboard (Ctrl/Cmd+V), or provide a URL. Accepted file types: mp3, ogg, wav, m4a, aac
Customize your input with more control.
{
"code": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>FAST</title>\n<!--\nSHOT LIST (6.00 s loop, 1920x1080)\n0.00-0.17 hold: nine stacked rows \"FAST FAST FAST\", heavy white type on black, filling the frame.\n0.17-1.33 rows whip sideways in alternating directions and come back to rest in one\n continuous move (power2.inOut).\n1.33-1.88 hold on the grid.\n1.88-2.30 rows collapse vertically toward the centre (expo.in, 0.02 s stagger) and fade.\n2.04-2.54 one giant FAST slams in, scaling up from the centre (expo.out).\n2.54-3.12 hold on the giant FAST.\n3.12-3.42 acid green underline wipes in from the left (power2.out, fast start, slow settle).\n3.42-3.79 hold.\n3.79-4.54 underline retracts toward the right edge (slow start, quick finish).\n4.54-4.96 hold on the giant FAST.\n4.96-5.21 giant FAST shrinks out (power2.in).\n5.10-5.96 rows spread back out from the centre with alternating offsets (expo.out)\n and reach the exact opening frame by 5.96.\n5.96-6.00 hold, which equals frame 0.\nAll visuals are drawn by a pure draw(t) called from the timeline's onUpdate.\n-->\n<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n<link href=\"https://fonts.googleapis.com/css2?family=Archivo+Black&display=block\" rel=\"stylesheet\">\n<style>\n html, body { margin: 0; height: 100%; background: #000000; overflow: hidden; }\n svg { display: block; width: 100vw; height: 100vh; }\n text { font-family: 'Archivo Black', 'Arial Black', sans-serif; fill: #FEFEFE; }\n</style>\n</head>\n<body>\n<svg id=\"stage\" viewBox=\"0 0 1920 1080\" preserveAspectRatio=\"xMidYMid meet\">\n <rect id=\"background\" width=\"1920\" height=\"1080\" fill=\"#000000\"/>\n <g id=\"rowGrid\"></g>\n <g id=\"giantFast\" opacity=\"0\">\n <text id=\"giantWord\" x=\"20\" y=\"880\" font-size=\"830\" textLength=\"1880\" lengthAdjust=\"spacingAndGlyphs\">FAST</text>\n </g>\n <rect id=\"underline\" x=\"1910\" y=\"925\" width=\"0\" height=\"72\" fill=\"#6CFF12\"/>\n</svg>\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js\"></script>\n<script>\n// Palette\nconst BG = \"#000000\", WHITE = \"#FEFEFE\", ACID = \"#6CFF12\";\n\nconst DURATION = 6;\nconst ROWS = 9, PITCH = 120, FONT = 146, CAP = 0.72 * FONT, ROW_W = 1360;\nconst NS = \"http://www.w3.org/2000/svg\";\nconst grid = document.getElementById(\"rowGrid\");\n\n// Build the nine stacked rows\nconst rows = [];\nfor (let i = 0; i < ROWS; i++) {\n const t = document.createElementNS(NS, \"text\");\n t.setAttribute(\"id\", \"row\" + (i + 1));\n t.setAttribute(\"x\", 960 - ROW_W / 2);\n t.setAttribute(\"y\", 540 + (i - 4) * PITCH + CAP / 2);\n t.setAttribute(\"font-size\", FONT);\n t.setAttribute(\"textLength\", ROW_W);\n t.setAttribute(\"lengthAdjust\", \"spacingAndGlyphs\");\n t.textContent = \"FAST FAST FAST\";\n grid.appendChild(t);\n rows.push(t);\n}\nconst dir = i => (i % 2 === 0 ? 1 : -1); // alternating directions\n\nconst giant = document.getElementById(\"giantFast\");\nconst underline = document.getElementById(\"underline\");\n\n// Helpers\nconst E = n => gsap.parseEase(n);\nconst clamp = v => Math.max(0, Math.min(1, v));\nconst seg = (t, a, b, ease) => (ease || (x => x))(clamp((t - a) / (b - a)));\nconst EASE = {\n whip: E(\"power2.inOut\"), collapse: E(\"expo.in\"), slam: E(\"expo.out\"),\n wipe: E(\"power2.out\"), retract: E(\"power4.in\"), out: E(\"power2.in\"), spread: E(\"expo.out\")\n};\n\n// Pure frame renderer\nfunction draw(t) {\n // 0.17-1.33 alternating whip, one continuous out-and-back\n const wp = seg(t, 0.17, 1.33, EASE.whip);\n const whipX = Math.sin(Math.PI * wp) * 70;\n\n rows.forEach((r, i) => {\n const off = (i - 4) * PITCH * 0.85;\n let x, y, op;\n if (t < 4) {\n // 1.88-2.30 collapse to centre\n const c = seg(t, 1.88 + i * 0.02, 2.14 + i * 0.02, EASE.collapse);\n x = dir(i) * whipX;\n y = -off * c;\n op = 1 - seg(t, 2.14, 2.32);\n } else {\n // 5.10-5.96 spread back out\n const s = seg(t, 5.10 + i * 0.02, 5.80 + i * 0.02, EASE.spread);\n x = dir(i) * 90 * (1 - s);\n y = -off * (1 - s);\n op = seg(t, 5.10, 5.25);\n }\n r.setAttribute(\"transform\", `translate(${x.toFixed(2)},${y.toFixed(2)})`);\n r.setAttribute(\"opacity\", op.toFixed(3));\n });\n\n // Giant FAST: 2.04-2.54 in, 4.96-5.21 out\n let s, gop;\n if (t < 4) {\n s = 0.3 + 0.7 * seg(t, 2.04, 2.54, EASE.slam);\n gop = seg(t, 2.04, 2.18);\n } else {\n const o = seg(t, 4.96, 5.21, EASE.out);\n s = 1 - 0.7 * o;\n gop = 1 - o;\n }\n giant.setAttribute(\"transform\", `translate(960,580) scale(${s.toFixed(4)}) translate(-960,-580)`);\n giant.setAttribute(\"opacity\", gop.toFixed(3));\n\n // Underline: 3.12-3.42 wipe in, 3.79-4.54 retract right\n const right = 10 + 1900 * seg(t, 3.12, 3.42, EASE.wipe);\n const left = 10 + 1900 * seg(t, 3.79, 4.54, EASE.retract);\n const w = Math.max(0, right - left);\n underline.setAttribute(\"x\", (w > 0 ? left : 1910).toFixed(2));\n underline.setAttribute(\"width\", w.toFixed(2));\n}\n\nconst external = new URLSearchParams(location.search).get(\"external\") === \"1\";\nconst tl = gsap.timeline({ paused: true, repeat: external ? 0 : -1 });\nconst clock = { t: 0 };\n// 0.00-6.00 single clock driving draw(t)\ntl.to(clock, { t: DURATION, duration: DURATION, ease: \"none\", onUpdate: () => draw(clock.t) }, 0);\n\nwindow.anim = {\n tl,\n duration: DURATION,\n seek(t) {\n const tt = Math.max(0, Math.min(DURATION, t));\n tl.pause();\n tl.totalTime(tt, false);\n draw(tt);\n },\n play(from) { tl.play(from || 0); },\n pause() { tl.pause(); }\n};\n\ndraw(0);\ndocument.fonts.ready.then(() => {\n window.anim.seek(0);\n document.documentElement.dataset.ready = \"1\";\n if (!external) tl.play(0);\n});\n</script>\n</body>\n</html>",
"html": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>FAST</title>\n<!--\nSHOT LIST (6.00 s loop, 1920x1080)\n0.00-0.17 hold: nine stacked rows \"FAST FAST FAST\", heavy white type on black, filling the frame.\n0.17-1.33 rows whip sideways in alternating directions and come back to rest in one\n continuous move (power2.inOut).\n1.33-1.88 hold on the grid.\n1.88-2.30 rows collapse vertically toward the centre (expo.in, 0.02 s stagger) and fade.\n2.04-2.54 one giant FAST slams in, scaling up from the centre (expo.out).\n2.54-3.12 hold on the giant FAST.\n3.12-3.42 acid green underline wipes in from the left (power2.out, fast start, slow settle).\n3.42-3.79 hold.\n3.79-4.54 underline retracts toward the right edge (slow start, quick finish).\n4.54-4.96 hold on the giant FAST.\n4.96-5.21 giant FAST shrinks out (power2.in).\n5.10-5.96 rows spread back out from the centre with alternating offsets (expo.out)\n and reach the exact opening frame by 5.96.\n5.96-6.00 hold, which equals frame 0.\nAll visuals are drawn by a pure draw(t) called from the timeline's onUpdate.\n-->\n<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n<link href=\"https://fonts.googleapis.com/css2?family=Archivo+Black&display=block\" rel=\"stylesheet\">\n<style>\n html, body { margin: 0; height: 100%; background: #000000; overflow: hidden; }\n svg { display: block; width: 100vw; height: 100vh; }\n text { font-family: 'Archivo Black', 'Arial Black', sans-serif; fill: #FEFEFE; }\n</style>\n</head>\n<body>\n<svg id=\"stage\" viewBox=\"0 0 1920 1080\" preserveAspectRatio=\"xMidYMid meet\">\n <rect id=\"background\" width=\"1920\" height=\"1080\" fill=\"#000000\"/>\n <g id=\"rowGrid\"></g>\n <g id=\"giantFast\" opacity=\"0\">\n <text id=\"giantWord\" x=\"20\" y=\"880\" font-size=\"830\" textLength=\"1880\" lengthAdjust=\"spacingAndGlyphs\">FAST</text>\n </g>\n <rect id=\"underline\" x=\"1910\" y=\"925\" width=\"0\" height=\"72\" fill=\"#6CFF12\"/>\n</svg>\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js\"></script>\n<script>\n// Palette\nconst BG = \"#000000\", WHITE = \"#FEFEFE\", ACID = \"#6CFF12\";\n\nconst DURATION = 6;\nconst ROWS = 9, PITCH = 120, FONT = 146, CAP = 0.72 * FONT, ROW_W = 1360;\nconst NS = \"http://www.w3.org/2000/svg\";\nconst grid = document.getElementById(\"rowGrid\");\n\n// Build the nine stacked rows\nconst rows = [];\nfor (let i = 0; i < ROWS; i++) {\n const t = document.createElementNS(NS, \"text\");\n t.setAttribute(\"id\", \"row\" + (i + 1));\n t.setAttribute(\"x\", 960 - ROW_W / 2);\n t.setAttribute(\"y\", 540 + (i - 4) * PITCH + CAP / 2);\n t.setAttribute(\"font-size\", FONT);\n t.setAttribute(\"textLength\", ROW_W);\n t.setAttribute(\"lengthAdjust\", \"spacingAndGlyphs\");\n t.textContent = \"FAST FAST FAST\";\n grid.appendChild(t);\n rows.push(t);\n}\nconst dir = i => (i % 2 === 0 ? 1 : -1); // alternating directions\n\nconst giant = document.getElementById(\"giantFast\");\nconst underline = document.getElementById(\"underline\");\n\n// Helpers\nconst E = n => gsap.parseEase(n);\nconst clamp = v => Math.max(0, Math.min(1, v));\nconst seg = (t, a, b, ease) => (ease || (x => x))(clamp((t - a) / (b - a)));\nconst EASE = {\n whip: E(\"power2.inOut\"), collapse: E(\"expo.in\"), slam: E(\"expo.out\"),\n wipe: E(\"power2.out\"), retract: E(\"power4.in\"), out: E(\"power2.in\"), spread: E(\"expo.out\")\n};\n\n// Pure frame renderer\nfunction draw(t) {\n // 0.17-1.33 alternating whip, one continuous out-and-back\n const wp = seg(t, 0.17, 1.33, EASE.whip);\n const whipX = Math.sin(Math.PI * wp) * 70;\n\n rows.forEach((r, i) => {\n const off = (i - 4) * PITCH * 0.85;\n let x, y, op;\n if (t < 4) {\n // 1.88-2.30 collapse to centre\n const c = seg(t, 1.88 + i * 0.02, 2.14 + i * 0.02, EASE.collapse);\n x = dir(i) * whipX;\n y = -off * c;\n op = 1 - seg(t, 2.14, 2.32);\n } else {\n // 5.10-5.96 spread back out\n const s = seg(t, 5.10 + i * 0.02, 5.80 + i * 0.02, EASE.spread);\n x = dir(i) * 90 * (1 - s);\n y = -off * (1 - s);\n op = seg(t, 5.10, 5.25);\n }\n r.setAttribute(\"transform\", `translate(${x.toFixed(2)},${y.toFixed(2)})`);\n r.setAttribute(\"opacity\", op.toFixed(3));\n });\n\n // Giant FAST: 2.04-2.54 in, 4.96-5.21 out\n let s, gop;\n if (t < 4) {\n s = 0.3 + 0.7 * seg(t, 2.04, 2.54, EASE.slam);\n gop = seg(t, 2.04, 2.18);\n } else {\n const o = seg(t, 4.96, 5.21, EASE.out);\n s = 1 - 0.7 * o;\n gop = 1 - o;\n }\n giant.setAttribute(\"transform\", `translate(960,580) scale(${s.toFixed(4)}) translate(-960,-580)`);\n giant.setAttribute(\"opacity\", gop.toFixed(3));\n\n // Underline: 3.12-3.42 wipe in, 3.79-4.54 retract right\n const right = 10 + 1900 * seg(t, 3.12, 3.42, EASE.wipe);\n const left = 10 + 1900 * seg(t, 3.79, 4.54, EASE.retract);\n const w = Math.max(0, right - left);\n underline.setAttribute(\"x\", (w > 0 ? left : 1910).toFixed(2));\n underline.setAttribute(\"width\", w.toFixed(2));\n}\n\nconst external = new URLSearchParams(location.search).get(\"external\") === \"1\";\nconst tl = gsap.timeline({ paused: true, repeat: external ? 0 : -1 });\nconst clock = { t: 0 };\n// 0.00-6.00 single clock driving draw(t)\ntl.to(clock, { t: DURATION, duration: DURATION, ease: \"none\", onUpdate: () => draw(clock.t) }, 0);\n\nwindow.anim = {\n tl,\n duration: DURATION,\n seek(t) {\n const tt = Math.max(0, Math.min(DURATION, t));\n tl.pause();\n tl.totalTime(tt, false);\n draw(tt);\n },\n play(from) { tl.play(from || 0); },\n pause() { tl.pause(); }\n};\n\ndraw(0);\ndocument.fonts.ready.then(() => {\n window.anim.seek(0);\n document.documentElement.dataset.ready = \"1\";\n if (!external) tl.play(0);\n});\n</script>\n</body>\n</html>",
"video": {
"url": "https://v3b.fal.media/files/b/0ab01c47/__VfQUa2cr7Pq15cRNml7_JteWZlTo.mp4",
"content_type": "video/mp4",
"file_name": "__VfQUa2cr7Pq15cRNml7_JteWZlTo.mp4",
"file_size": 617426,
"width": 1280,
"height": 720,
"fps": 24,
"duration": 6,
"num_frames": 144
},
"contact_sheet": {
"url": "https://v3b.fal.media/files/b/0ab01c47/noDkwtEXKbGKH5ZpenxEc_rvgqBzjC.png",
"content_type": "image/png",
"file_name": "noDkwtEXKbGKH5ZpenxEc_rvgqBzjC.png",
"file_size": null,
"width": null,
"height": null
},
"reference_video": {
"url": "https://v3b.fal.media/files/b/0ab01c36/SXcu6yJUMQaqa0oY2Rgvc_minimax-h3.mp4",
"content_type": "video/mp4",
"file_name": null,
"file_size": null,
"width": null,
"height": null,
"fps": null,
"duration": null,
"num_frames": null
},
"duration": 6,
"rounds": 2,
"timings": {
"source": 12.72,
"study": 16.52,
"generate": 48.02,
"render": 16.7,
"refine": 87.99,
"encode": 4.88
}
}Your request will cost $0.30 per second of animation when MiniMax H3 Max animates your prompt or image first, or $0.20 per second from your own video, with a 5-second minimum: a 6-second loop from a prompt costs $1.80, a 10-second clip rebuilt from your video $2.00.