feat(hero): campo de particulas WebGL com mergulho guiado pela rolagem e transicao de secoes em CSS
Tres camadas de pontos ligadas por colunas de dados, animadas no vertex shader; o hero fica fixo em telas grandes enquanto a camera atravessa as camadas. Secoes sobem como cartoes via animation-timeline: view() (sem JS). Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
3d47fe9cc7
commit
0ec0194441
7 files changed
+694
-1001
No files matched your search
+157
-10
@@ -255,6 +255,7 @@ textarea {
|
||||
|
||||
.ds-section {
|
||||
padding: clamp(72px, 9vw, 112px) clamp(24px, 6vw, 64px);
|
||||
background: var(--paper);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
@@ -986,30 +987,176 @@ textarea {
|
||||
radial-gradient(40% 50% at 6% 92%, rgba(204, 255, 0, 0.05), transparent 70%);
|
||||
}
|
||||
|
||||
.hero-rise > * {
|
||||
animation: hero-rise 0.8s var(--ease-out) both;
|
||||
/* Hero: palco de 100svh; em telas grandes ele fica fixo enquanto a rolagem conduz o mergulho da cena 3D.
|
||||
--hero-p (0 a 1) vem de cinematic/HeroField.tsx. */
|
||||
.hero {
|
||||
--hero-p: 0;
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
animation-delay: 0.08s;
|
||||
}
|
||||
.hero-stage {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100svh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
animation-delay: 0.16s;
|
||||
/* Sem WebGL (ou antes de a cena carregar): malha de pontos estática no lugar das camadas */
|
||||
.hero-glow::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: radial-gradient(circle, rgba(244, 242, 237, 0.22) 1px, transparent 1.5px) 0 0 / 22px 22px;
|
||||
mask: radial-gradient(38% 46% at 74% 50%, #000, transparent 75%);
|
||||
transition: opacity 1.2s var(--ease-out);
|
||||
}
|
||||
|
||||
.hero:has(.hero-field[data-ready]) .hero-glow::after {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hero-field {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
opacity: 0;
|
||||
transition: opacity 1.6s var(--ease-out);
|
||||
|
||||
&[data-ready] {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes hero-rise {
|
||||
.hero-scrim {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
background:
|
||||
linear-gradient(90deg, rgba(10, 10, 10, 0.86) 0%, rgba(10, 10, 10, 0.55) 36%, transparent 62%),
|
||||
linear-gradient(0deg, rgba(10, 10, 10, 0.9), transparent 28%);
|
||||
|
||||
@media (max-width: 1023px) {
|
||||
background: linear-gradient(0deg, rgba(10, 10, 10, 0.92) 0 30%, rgba(10, 10, 10, 0.5) 65%, rgba(10, 10, 10, 0.7));
|
||||
}
|
||||
}
|
||||
|
||||
/* Entrada: as palavras do título já pintam no primeiro quadro (sem opacity:0, bom para o LCP) e ganham foco em cascata */
|
||||
.hero-word {
|
||||
display: inline-block;
|
||||
animation: hero-word 1.1s var(--ease-out) both;
|
||||
animation-delay: calc(0.12s + var(--i) * 45ms);
|
||||
}
|
||||
|
||||
@keyframes hero-word {
|
||||
from {
|
||||
transform: translateY(16px);
|
||||
transform: translateY(0.42em) rotate(2deg);
|
||||
filter: blur(12px);
|
||||
}
|
||||
}
|
||||
|
||||
.hero-in,
|
||||
.hero-foot > * {
|
||||
animation: hero-in 1s var(--ease-out) both;
|
||||
animation-delay: var(--d, 0.05s);
|
||||
}
|
||||
|
||||
.hero-foot > * {
|
||||
--d: 0.85s;
|
||||
}
|
||||
|
||||
@keyframes hero-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(18px);
|
||||
}
|
||||
}
|
||||
|
||||
.hero-cue-line {
|
||||
width: 56px;
|
||||
height: 1px;
|
||||
background: currentColor;
|
||||
transform-origin: left;
|
||||
animation: hero-cue 2.4s var(--ease-out) infinite;
|
||||
}
|
||||
|
||||
@keyframes hero-cue {
|
||||
0% {
|
||||
transform: scaleX(0);
|
||||
}
|
||||
60% {
|
||||
transform: scaleX(1);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: scaleX(1);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) and (min-height: 700px) and (prefers-reduced-motion: no-preference) {
|
||||
.hero {
|
||||
height: 220svh;
|
||||
}
|
||||
|
||||
.hero-stage {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: 100svh;
|
||||
}
|
||||
|
||||
/* o texto sai de cena enquanto a câmera mergulha: sobe, encolhe e perde o foco */
|
||||
.hero-content {
|
||||
transform: translate3d(0, calc(var(--hero-p) * -16vh), 0) scale(calc(1 - var(--hero-p) * 0.08));
|
||||
transform-origin: 0 50%;
|
||||
opacity: calc(1 - var(--hero-p) * 2.6);
|
||||
filter: blur(calc(var(--hero-p) * 18px));
|
||||
}
|
||||
|
||||
.hero-foot {
|
||||
opacity: calc(1 - var(--hero-p) * 5);
|
||||
}
|
||||
|
||||
.hero-scrim {
|
||||
opacity: calc(1 - var(--hero-p) * 1.4);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.hero-rise > * {
|
||||
.hero-word,
|
||||
.hero-in,
|
||||
.hero-foot > *,
|
||||
.hero-cue-line {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Transição entre seções: cada seção sobe como um cartão e abre até a borda da tela.
|
||||
CSS puro com linha do tempo de rolagem (Chrome, Edge, Safari 26+); sem suporte, a seção só aparece. */
|
||||
.ds-main {
|
||||
background: var(--ink);
|
||||
}
|
||||
|
||||
@keyframes section-rise {
|
||||
from {
|
||||
clip-path: inset(8vh 4vw 0 4vw round 28px);
|
||||
translate: 0 12vh;
|
||||
}
|
||||
to {
|
||||
clip-path: inset(0 0 0 0 round 0);
|
||||
translate: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (animation-timeline: view()) {
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.ds-main > section:not(.hero, .notebook-story) {
|
||||
animation: section-rise linear both;
|
||||
animation-timeline: view();
|
||||
animation-range: entry 0% entry 85vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Capa dos cards de projeto: captura real ou painel gerado em codigo */
|
||||
.ds-cover {
|
||||
position: relative;
|
||||
|
||||
Reference in new issue
Block a user