← Biblioteca Promptfly
Snippet: objeto que gira com o scroll
Componente React com GSAP que desenha uma sequência de frames num canvas. É o scroll que gira o objeto. Já vem com os frames do anel do VYTAL pra testar.
ScrollSequence.tsx
"use client";
// Objeto que gira com o scroll: uma sequência de frames desenhada num <canvas>.
// É o scroll que escolhe qual frame aparece, não um vídeo tocando sozinho.
// Instale: npm i gsap
// Os 102 frames abaixo são do anel do VYTAL, já hospedados. Troque pelos seus.
import { useEffect, useRef } from "react";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
const FRAME_COUNT = 102;
const frameUrl = (i: number) =>
`https://www.promptfly.com.br/templates/vytal-anel-inteligente/ring-frames/ring-${String(i + 1).padStart(3, "0")}.webp`;
export default function ScrollSequence() {
const sectionRef = useRef<HTMLElement>(null);
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = canvasRef.current;
const ctx = canvas?.getContext("2d");
if (!canvas || !ctx) return;
let cancelled = false;
const state = { frame: 0 };
const images = Array.from({ length: FRAME_COUNT }, (_, i) => {
const img = new Image();
img.src = frameUrl(i);
return img;
});
// Desenha o frame atual centralizado, sem distorcer (igual object-fit: contain).
function draw() {
const img = images[Math.round(state.frame)];
if (!canvas || !ctx || !img.naturalWidth) return;
const dpr = window.devicePixelRatio || 1;
const w = Math.round(canvas.clientWidth * dpr);
const h = Math.round(canvas.clientHeight * dpr);
if (canvas.width !== w || canvas.height !== h) {
canvas.width = w;
canvas.height = h;
}
const scale = Math.min(w / img.naturalWidth, h / img.naturalHeight);
const dw = img.naturalWidth * scale;
const dh = img.naturalHeight * scale;
ctx.clearRect(0, 0, w, h);
ctx.drawImage(img, (w - dw) / 2, (h - dh) / 2, dw, dh);
}
const gsapCtx = gsap.context(() => {}, sectionRef);
// Pré-carrega e decodifica TODOS os frames antes de ligar o scroll.
// Sem isso a animação engasga nos primeiros giros.
Promise.all(images.map((img) => img.decode().catch(() => undefined))).then(() => {
if (cancelled) return;
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
state.frame = FRAME_COUNT - 1;
draw();
return;
}
gsapCtx.add(() => {
gsap.to(state, {
frame: FRAME_COUNT - 1,
ease: "none",
onUpdate: draw,
scrollTrigger: {
trigger: sectionRef.current,
start: "top top",
end: "+=300%", // quanto maior, mais devagar o objeto gira
pin: true,
scrub: 0.2,
},
});
});
draw();
});
window.addEventListener("resize", draw);
return () => {
cancelled = true;
window.removeEventListener("resize", draw);
gsapCtx.revert();
};
}, []);
return (
<section ref={sectionRef} style={{ height: "100vh", background: "#0a0a0a" }}>
<canvas ref={canvasRef} style={{ display: "block", width: "100%", height: "100%" }} />
</section>
);
}Como usar
- 01Roda npm i gsap no seu projeto Next.js.
- 02Cria o arquivo ScrollSequence.tsx e cola o código.
- 03Coloca o componente na página com conteúdo antes e depois, pra ter por onde rolar.
Promptfly PremiumAcesso vitalício
Esse é 1 recurso. A biblioteca tem 51.
de R$ 129,90por R$ 47,90-63% Pagamento único e acesso vitalício.
- Mentoria pronta: o método do primeiro site ao primeiro cliente
- Os 15 templates de sites cinematográficos, com o prompt completo
- As 10 animações de scroll Premium, com prompt e código
- As skills cinematográficas pro Claude Code
- Grupo VIP no Discord
- Todo template novo incluído, sem pagar de novo
- Pagamento via Hotmart, garantia de 7 dias