primocode 10.15.2 → 10.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSES/edit-ia-pro.txt +32 -0
- package/LICENSES/fontes-OFL.txt +476 -0
- package/LICENSES/hyperframes-Apache-2.0.txt +205 -0
- package/LICENSES/permanent-marker-Apache-2.0.txt +204 -0
- package/LICENSES/selfie-multiclass-Apache-2.0.txt +227 -0
- package/LICENSES/three-MIT.txt +23 -0
- package/LICENSES/video-use-MIT.txt +24 -0
- package/LICENSES/woven-sfx-CC0.txt +16 -0
- package/LICENSES/yunet-MIT.txt +21 -0
- package/README.md +2 -2
- package/bin/primocode.js +74 -9
- package/editor/LICENSE.md +11 -0
- package/editor/README.md +321 -0
- package/editor/SKILL.md +307 -0
- package/editor/THIRD_PARTY_NOTICES.md +228 -0
- package/editor/assets/baixar.json +591 -0
- package/editor/assets/fonts/anton/OFL.txt +93 -0
- package/editor/assets/fonts/caveat/OFL.txt +93 -0
- package/editor/assets/fonts/figtree/OFL.txt +93 -0
- package/editor/assets/fonts/fonts.json +10 -0
- package/editor/assets/fonts/montserrat/OFL.txt +93 -0
- package/editor/assets/fonts/permanentmarker/LICENSE.txt +202 -0
- package/editor/assets/models/SELFIE_MULTICLASS_LICENSE.txt +227 -0
- package/editor/assets/models/YUNET_LICENSE.txt +21 -0
- package/editor/assets/sfx/licencas/bass_drop.txt +32 -0
- package/editor/assets/sfx/licencas/cash.txt +76 -0
- package/editor/assets/sfx/licencas/charge.txt +31 -0
- package/editor/assets/sfx/licencas/click.txt +46 -0
- package/editor/assets/sfx/licencas/coin.txt +50 -0
- package/editor/assets/sfx/licencas/count.txt +47 -0
- package/editor/assets/sfx/licencas/data.txt +31 -0
- package/editor/assets/sfx/licencas/error.txt +32 -0
- package/editor/assets/sfx/licencas/flash.txt +31 -0
- package/editor/assets/sfx/licencas/gears.txt +82 -0
- package/editor/assets/sfx/licencas/keyboard.txt +48 -0
- package/editor/assets/sfx/licencas/metal_hit.txt +62 -0
- package/editor/assets/sfx/licencas/metal_riser.txt +61 -0
- package/editor/assets/sfx/licencas/mouse_click.txt +50 -0
- package/editor/assets/sfx/licencas/notification.txt +54 -0
- package/editor/assets/sfx/licencas/pop.txt +38 -0
- package/editor/assets/sfx/licencas/rewind.txt +32 -0
- package/editor/assets/sfx/licencas/rise.txt +46 -0
- package/editor/assets/sfx/licencas/sinteticos.txt +21 -0
- package/editor/assets/sfx/licencas/snap.txt +50 -0
- package/editor/assets/sfx/licencas/success.txt +40 -0
- package/editor/assets/sfx/licencas/synth_hit.txt +32 -0
- package/editor/assets/sfx/licencas/tick.txt +14 -0
- package/editor/assets/sfx/licencas/whoosh.txt +47 -0
- package/editor/assets/sfx/licencas/wind.txt +31 -0
- package/editor/assets/sfx/sfx.json +832 -0
- package/editor/assets/sfx/sfx_sinteticos.json +317 -0
- package/editor/assets/sfx/sfx_woven.json +387 -0
- package/editor/assets/sfx/woven/LICENCA.md +16 -0
- package/editor/fichas/briefing-do-video.md +45 -0
- package/editor/fichas/conferencia-da-amostra.md +56 -0
- package/editor/fichas/matriz-de-ganchos.csv +3 -0
- package/editor/fichas/padrao.json +16 -0
- package/editor/fichas/planilha-de-cenas.csv +4 -0
- package/editor/fichas/planilha-de-versoes.csv +4 -0
- package/editor/fichas/plano-em-blocos.md +32 -0
- package/editor/fichas/registro-de-materiais.json +27 -0
- package/editor/helpers/assets_ocr/ocr_vision.swift +41 -0
- package/editor/helpers/bordas_precisas.py +272 -0
- package/editor/helpers/camera_viva.py +426 -0
- package/editor/helpers/captions.py +601 -0
- package/editor/helpers/common.py +308 -0
- package/editor/helpers/compose_final.py +3555 -0
- package/editor/helpers/conferir_corte.py +234 -0
- package/editor/helpers/conferir_dados.py +405 -0
- package/editor/helpers/contact_sheet.py +282 -0
- package/editor/helpers/corte_por_onda.py +433 -0
- package/editor/helpers/corte_seco.py +595 -0
- package/editor/helpers/denoise.py +971 -0
- package/editor/helpers/efeitos.py +408 -0
- package/editor/helpers/efeitos_gerar.py +159 -0
- package/editor/helpers/elevenlabs_api.py +442 -0
- package/editor/helpers/face_layout.py +570 -0
- package/editor/helpers/fetch_images.py +423 -0
- package/editor/helpers/ganho_por_trecho.py +214 -0
- package/editor/helpers/gen_image.py +312 -0
- package/editor/helpers/gen_music.py +316 -0
- package/editor/helpers/gen_sfx.py +148 -0
- package/editor/helpers/grade.py +307 -0
- package/editor/helpers/icloud.py +119 -0
- package/editor/helpers/make_sfx.py +940 -0
- package/editor/helpers/matte.py +1342 -0
- package/editor/helpers/medir_referencia.py +2232 -0
- package/editor/helpers/mixar_trilha.py +354 -0
- package/editor/helpers/montar_corte.py +295 -0
- package/editor/helpers/motion/__init__.py +13 -0
- package/editor/helpers/motion/engine.py +1915 -0
- package/editor/helpers/motion/registry.py +510 -0
- package/editor/helpers/motion/render.py +665 -0
- package/editor/helpers/motion/templates/barra_progresso.py +370 -0
- package/editor/helpers/motion/templates/carimbo.py +132 -0
- package/editor/helpers/motion/templates/checklist.py +271 -0
- package/editor/helpers/motion/templates/comentario_cta.py +380 -0
- package/editor/helpers/motion/templates/contador.py +222 -0
- package/editor/helpers/motion/templates/destaque.py +263 -0
- package/editor/helpers/motion/templates/etiqueta_preco.py +461 -0
- package/editor/helpers/motion/templates/grafico_barras.py +510 -0
- package/editor/helpers/motion/templates/grafico_linha.py +462 -0
- package/editor/helpers/motion/templates/notificacao.py +266 -0
- package/editor/helpers/motion/templates/palavra_impacto.py +410 -0
- package/editor/helpers/motion/templates/passos.py +321 -0
- package/editor/helpers/motion/templates/riscado.py +298 -0
- package/editor/helpers/motion/templates/selo_garantia.py +150 -0
- package/editor/helpers/motion_render.py +241 -0
- package/editor/helpers/motion_sugerir.py +961 -0
- package/editor/helpers/noise_check.py +134 -0
- package/editor/helpers/pack_transcripts.py +223 -0
- package/editor/helpers/palavras_na_onda.py +176 -0
- package/editor/helpers/plano_sfx.py +839 -0
- package/editor/helpers/portao.py +427 -0
- package/editor/helpers/preview_server.py +1177 -0
- package/editor/helpers/rastrear_rosto.py +298 -0
- package/editor/helpers/render_cut.py +1256 -0
- package/editor/helpers/respiros.py +89 -0
- package/editor/helpers/sincronizar_cameras.py +571 -0
- package/editor/helpers/speech_regions.py +423 -0
- package/editor/helpers/style_catalog.json +231 -0
- package/editor/helpers/style_samples.py +246 -0
- package/editor/helpers/tela_verde.py +2113 -0
- package/editor/helpers/text_render.py +2059 -0
- package/editor/helpers/texto_na_tela.py +366 -0
- package/editor/helpers/timeline_view.py +292 -0
- package/editor/helpers/tira_de_quadros.py +113 -0
- package/editor/helpers/transcribe.py +734 -0
- package/editor/helpers/transcribe_batch.py +129 -0
- package/editor/helpers/trilhas.py +1146 -0
- package/editor/helpers/trilhas_humores.json +66 -0
- package/editor/helpers/valores.py +187 -0
- package/editor/helpers/verify_cut.py +820 -0
- package/editor/helpers/voice_levels.py +233 -0
- package/editor/helpers/voz_check.py +386 -0
- package/editor/helpers/voz_limpa.py +81 -0
- package/editor/helpers/watch_preview.py +372 -0
- package/editor/modelo-projeto/LEIA.md +402 -0
- package/editor/modelo-projeto/assets/fontes/OFL-Caveat.txt +93 -0
- package/editor/modelo-projeto/assets/fontes/OFL-JetBrainsMono.txt +93 -0
- package/editor/modelo-projeto/assets/fontes/OFL-Montserrat.txt +93 -0
- package/editor/modelo-projeto/assets/fontes/larguras.json +1 -0
- package/editor/modelo-projeto/assets/three/BufferGeometryUtils.js +1438 -0
- package/editor/modelo-projeto/assets/three/GLTFLoader.js +4895 -0
- package/editor/modelo-projeto/assets/three/LICENSE +21 -0
- package/editor/modelo-projeto/assets/three/ORIGEM.txt +17 -0
- package/editor/modelo-projeto/assets/three/RoomEnvironment.js +185 -0
- package/editor/modelo-projeto/assets/three/three.core.min.js +6 -0
- package/editor/modelo-projeto/assets/three/three.module.min.js +6 -0
- package/editor/modelo-projeto/build.py +4828 -0
- package/editor/modelo-projeto/compositions/cenas/2d/k2d_antes_depois.html +199 -0
- package/editor/modelo-projeto/compositions/cenas/2d/k2d_arquivo.html +232 -0
- package/editor/modelo-projeto/compositions/cenas/2d/k2d_busca.html +315 -0
- package/editor/modelo-projeto/compositions/cenas/2d/k2d_comando.html +304 -0
- package/editor/modelo-projeto/compositions/cenas/2d/k2d_conversa.html +217 -0
- package/editor/modelo-projeto/compositions/cenas/2d/k2d_esquema.html +289 -0
- package/editor/modelo-projeto/compositions/cenas/2d/k2d_medidor.html +249 -0
- package/editor/modelo-projeto/compositions/cenas/2d/k2d_notas.html +233 -0
- package/editor/modelo-projeto/compositions/cenas/3d/k3d_caminho.html +197 -0
- package/editor/modelo-projeto/compositions/cenas/3d/k3d_explodida.html +152 -0
- package/editor/modelo-projeto/compositions/cenas/3d/k3d_tela.html +167 -0
- package/editor/modelo-projeto/compositions/cenas/3d/k3d_volume.html +124 -0
- package/editor/modelo-projeto/compositions/cenas/3d/motor-three.js +728 -0
- package/editor/modelo-projeto/compositions/cenas/LEIA.md +177 -0
- package/editor/modelo-projeto/ferramentas/medir_fontes.py +65 -0
- package/editor/modelo-projeto/ferramentas/pessoa_recortada.py +176 -0
- package/editor/modelo-projeto/ferramentas/rastrear_maos.py +189 -0
- package/editor/modelo-projeto/hyperframes.json +12 -0
- package/editor/modelo-projeto/package.json +11 -0
- package/editor/modelo-projeto/projeto.json +16 -0
- package/editor/preview/app.css +1009 -0
- package/editor/preview/app.js +2122 -0
- package/editor/preview/index.html +307 -0
- package/editor/pyproject.toml +23 -0
- package/editor/references/3d.md +236 -0
- package/editor/references/animacao-catalogo.md +672 -0
- package/editor/references/animacao.md +498 -0
- package/editor/references/comandos.md +92 -0
- package/editor/references/corte-seco-como-funciona.md +50 -0
- package/editor/references/corte-seco.md +88 -0
- package/editor/references/corte.md +290 -0
- package/editor/references/direcao-por-blocos.md +218 -0
- package/editor/references/enquadramento.md +654 -0
- package/editor/references/estilos-prontos.md +355 -0
- package/editor/references/estudio.md +100 -0
- package/editor/references/exemplo-eventos.json +67 -0
- package/editor/references/lettering.md +252 -0
- package/editor/references/modelos.md +494 -0
- package/editor/references/phase2.md +1007 -0
- package/editor/references/referencia-aplicar.md +203 -0
- package/editor/references/referencia-medir.md +375 -0
- package/editor/references/revisao.md +335 -0
- package/editor/references/som-e-trilha.md +146 -0
- package/editor/references/tabela-de-sons.md +130 -0
- package/editor/references/variacoes.md +234 -0
- package/editor/uv.lock +1141 -0
- package/lib/act.js +38 -8
- package/lib/app-chat.js +97 -0
- package/lib/catalogo.js +7 -1
- package/lib/chamada-torta.js +81 -0
- package/lib/editor-pro.js +786 -0
- package/lib/entrega.js +58 -0
- package/lib/estudio/conferencia-visual.js +76 -0
- package/lib/estudio/diretor.js +6 -1
- package/lib/estudio/exportar.js +3 -1
- package/lib/estudio/gosto/tela.html +1349 -0
- package/lib/estudio/gosto.js +305 -0
- package/lib/estudio/index.js +12 -1
- package/lib/estudio/kit-ae/base.jsx +119 -13
- package/lib/estudio/kit-ae/cenas.jsx +47 -15
- package/lib/estudio/kit-ae/guarda.jsx +274 -0
- package/lib/estudio/kit-ae/primitivas.jsx +180 -24
- package/lib/estudio/maquina-diretor.js +70 -12
- package/lib/estudio/maquina-foto.js +177 -0
- package/lib/estudio/maquina-guarda.js +207 -0
- package/lib/estudio/maquina-layout.js +22 -1
- package/lib/estudio/maquina.js +64 -11
- package/lib/estudio/referencias.js +1 -1
- package/lib/estudio/visao/visao.swift +97 -0
- package/lib/estudio/visao.js +60 -0
- package/lib/headless.js +15 -3
- package/lib/local/cerebro.json +285 -7
- package/lib/local/motor.js +5 -2
- package/lib/memoria-usuario.js +164 -0
- package/lib/nuvem.js +33 -2
- package/lib/passagem.js +50 -0
- package/lib/perigo.js +19 -11
- package/lib/protecao.js +134 -0
- package/lib/repeticao.js +1 -1
- package/lib/sandbox.js +57 -9
- package/lib/titulo-conversa.js +46 -0
- package/lib/tools.js +23 -4
- package/lib/ui.js +2 -2
- package/package.json +3 -2
- package/skills/editar-meu-video/SKILL.md +6 -2
- package/skills/editar-video/SKILL.md +113 -0
- package/studio/pessoa.py +52 -0
- package/voz/primo_voz/__main__.py +55 -40
- package/voz/primo_voz/app.py +500 -4
- package/voz/primo_voz/chat.html +1773 -0
- package/voz/primo_voz/conversa.py +0 -26
- package/voz/primo_voz/hud.html +8 -2
- package/voz/primo_voz/hud.py +129 -5
- package/voz/primo_voz/identidade.py +1 -1
- package/voz/primo_voz/painel_dados.py +134 -0
|
@@ -0,0 +1,1349 @@
|
|
|
1
|
+
<!doctype html><html><head><meta charset=utf8><meta name=viewport content="width=device-width,initial-scale=1,viewport-fit=cover"><style>:root{color-scheme:light;box-sizing:border-box;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)}html{scroll-padding-top:env(safe-area-inset-top,0px)}body{margin:0;padding:0;font:14px -apple-system,BlinkMacSystemFont,sans-serif;background:#fff;color:#000}img{max-width:100%}[hidden]:not([hidden=until-found i]){display:none!important}</style></head><body>
|
|
2
|
+
<title>Seu gosto de motion · PrimoCode</title>
|
|
3
|
+
<style>
|
|
4
|
+
/* Layout: página de produto da Apple — título centrado, muito respiro, telinhas cinza claras, um azul só pra ação. */
|
|
5
|
+
:root {
|
|
6
|
+
--bg: #ffffff;
|
|
7
|
+
--palco: #ffffff;
|
|
8
|
+
--linha: #d2d2d7;
|
|
9
|
+
--giz: #1d1d1f;
|
|
10
|
+
--apagado: #6e6e73;
|
|
11
|
+
--ambar: #0071e3;
|
|
12
|
+
--ambar-hover: #0077ed;
|
|
13
|
+
--sobre: #ffffff;
|
|
14
|
+
--vermelho: #ff3b30;
|
|
15
|
+
--onda-ceu: #ffffff; --onda-clara: #f2fbff; --onda-media: #9fdcff; --onda-funda: #5ab4ff;
|
|
16
|
+
--sombra-card: 0 2px 6px rgba(0, 40, 90, .06), 0 12px 32px rgba(0, 40, 90, .08);
|
|
17
|
+
--c-brincalhao: var(--giz); --c-premium: var(--giz); --c-corporativo: var(--giz);
|
|
18
|
+
--c-energico: var(--giz); --c-cinema3d: var(--giz); --c-cinetico: var(--giz);
|
|
19
|
+
--f-display: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
20
|
+
--f-poster: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue", Arial, sans-serif;
|
|
21
|
+
--f-serifa: "New York", ui-serif, "Iowan Old Style", Georgia, serif;
|
|
22
|
+
--f-mono: ui-monospace, "SF Mono", Menlo, monospace;
|
|
23
|
+
}
|
|
24
|
+
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) {
|
|
25
|
+
--bg: #000000; --palco: #1c1c1e; --linha: #38383a; --giz: #f5f5f7; --apagado: #98989d;
|
|
26
|
+
--ambar: #2997ff; --ambar-hover: #47a6ff; --sobre: #ffffff; --vermelho: #ff453a; color-scheme: dark;
|
|
27
|
+
--onda-ceu: #03070f; --onda-clara: #b9ecff; --onda-media: #2f8fe8; --onda-funda: #5fd0ff;
|
|
28
|
+
--sombra-card: 0 2px 6px rgba(0, 0, 0, .4), 0 12px 32px rgba(0, 0, 0, .35); } }
|
|
29
|
+
:root[data-theme="dark"] {
|
|
30
|
+
--bg: #000000; --palco: #1c1c1e; --linha: #38383a; --giz: #f5f5f7; --apagado: #98989d;
|
|
31
|
+
--ambar: #2997ff; --ambar-hover: #47a6ff; --sobre: #ffffff; --vermelho: #ff453a; color-scheme: dark;
|
|
32
|
+
--onda-ceu: #03070f; --onda-clara: #b9ecff; --onda-media: #2f8fe8; --onda-funda: #5fd0ff;
|
|
33
|
+
--sombra-card: 0 2px 6px rgba(0, 0, 0, .4), 0 12px 32px rgba(0, 0, 0, .35); }
|
|
34
|
+
* { box-sizing: border-box; }
|
|
35
|
+
body {
|
|
36
|
+
background: var(--bg); color: var(--giz); font-family: var(--f-display); font-size: 17px; line-height: 1.47; letter-spacing: -.022em;
|
|
37
|
+
-webkit-font-smoothing: antialiased;
|
|
38
|
+
padding-left: max(16px, env(safe-area-inset-left, 0px)); padding-right: max(16px, env(safe-area-inset-right, 0px));
|
|
39
|
+
padding-block: 56px 96px;
|
|
40
|
+
}
|
|
41
|
+
#ondas { position: fixed; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none;
|
|
42
|
+
background: linear-gradient(180deg, var(--onda-ceu) 35%, var(--onda-clara) 60%, var(--onda-media)); }
|
|
43
|
+
.palco { box-shadow: var(--sombra-card); }
|
|
44
|
+
.item, .tabela, pre, .passos span.ativo { box-shadow: var(--sombra-card); }
|
|
45
|
+
/* seleção: o círculo vazado aparece no hover; escolhido, fica azul com ✓ */
|
|
46
|
+
.selo { background: var(--bg); box-shadow: inset 0 0 0 1.5px var(--linha), 0 1px 3px rgba(0, 0, 0, .12); }
|
|
47
|
+
.selo::before { content: ""; }
|
|
48
|
+
.card:hover .selo, .card:focus-visible .selo { opacity: 1; transform: scale(1); }
|
|
49
|
+
.card[aria-pressed="true"] .selo { background: var(--ambar); box-shadow: none; }
|
|
50
|
+
.card[aria-pressed="true"] .selo::before { content: "✓"; }
|
|
51
|
+
@media (hover: none) { .selo { opacity: 1; transform: scale(1); } }
|
|
52
|
+
/* catálogo completo */
|
|
53
|
+
.catalogo { margin-top: 40px; display: grid; gap: 24px; }
|
|
54
|
+
.cat-topo { display: grid; gap: 6px; justify-items: center; text-align: center; }
|
|
55
|
+
.cat-topo h2 { margin: 0; font-size: clamp(26px, 3.4vw, 36px); font-weight: 600; letter-spacing: -.025em; }
|
|
56
|
+
.cat-grade { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 20px; align-items: start; }
|
|
57
|
+
.cat-grupo { background: var(--palco); border-radius: 18px; padding: 18px 20px; box-shadow: var(--sombra-card); }
|
|
58
|
+
.cat-grupo h3 { margin: 0 0 8px; font-size: 17px; font-weight: 600; display: flex; justify-content: space-between; align-items: baseline; }
|
|
59
|
+
.cat-grupo ul { list-style: none; margin: 0; padding: 0; }
|
|
60
|
+
.cat-grupo li { display: flex; justify-content: space-between; gap: 12px; padding: 9px 0; border-top: 1px solid var(--linha); font-size: 15px; }
|
|
61
|
+
.cat-grupo li small { color: var(--apagado); font-size: 13px; text-align: right; }
|
|
62
|
+
/* passo 2 e 3: prévia maior, campo no topo, sugestões com + */
|
|
63
|
+
.lista .item { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); }
|
|
64
|
+
@media (max-width: 700px) { .lista .item { grid-template-columns: minmax(0, 1fr); } }
|
|
65
|
+
.sug { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 18px; }
|
|
66
|
+
.sug button { all: unset; cursor: pointer; font-size: 14px; padding: 7px 14px; border-radius: 980px; color: var(--ambar); background: color-mix(in srgb, var(--ambar) 10%, var(--bg)); transition: background .15s ease, color .15s ease; }
|
|
67
|
+
.sug button::before { content: "+ "; font-weight: 600; }
|
|
68
|
+
.sug button:hover { background: color-mix(in srgb, var(--ambar) 18%, var(--bg)); }
|
|
69
|
+
.sug button:focus-visible { outline: 2px solid var(--ambar); outline-offset: 2px; }
|
|
70
|
+
.sug button[aria-pressed="true"] { background: var(--ambar); color: var(--sobre); }
|
|
71
|
+
.sug button[aria-pressed="true"]::before { content: "✓ "; }
|
|
72
|
+
.rot-chips { margin: 0 0 8px; font-size: 13px; color: var(--apagado); }
|
|
73
|
+
.mini-fila { display: flex; gap: 18px; justify-content: safe center; overflow-x: auto; padding: 8px 4px 18px; margin: -8px -4px -6px; scrollbar-width: thin; }
|
|
74
|
+
.mini-fila .palco { flex: none; width: min(280px, 78vw); border-radius: 18px; }
|
|
75
|
+
#passo2 .carrossel { padding-block: 10px; }
|
|
76
|
+
#passo2 .trilho { width: min(880px, calc(100vw - 32px)); }
|
|
77
|
+
#passo2 .acoes { margin-top: 18px !important; }
|
|
78
|
+
#passo2 .lista { gap: 16px; }
|
|
79
|
+
.lista .item-ops { grid-template-columns: minmax(0, 1fr); gap: 16px; padding: 22px 26px; width: 100%; max-width: 860px; margin: 0 auto; border-radius: 20px; }
|
|
80
|
+
/* compacto: cada linha é o rótulo + quatro pílulas com um ícone pequeno animado */
|
|
81
|
+
.item-ops .grupo { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
|
|
82
|
+
.lista .item-ops h3 { flex: none; width: 128px; margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -.01em; color: var(--giz); }
|
|
83
|
+
.ops { flex: 1; display: flex; flex-wrap: wrap; gap: 10px; }
|
|
84
|
+
.op { all: unset; box-sizing: border-box; cursor: pointer; display: inline-flex; align-items: center; gap: 10px; padding: 11px 22px 11px 15px; border-radius: 980px;
|
|
85
|
+
background: var(--bg); color: var(--giz); box-shadow: inset 0 0 0 1.5px var(--linha); font-size: 16px; font-weight: 500; white-space: nowrap;
|
|
86
|
+
transition: transform .3s cubic-bezier(.34, 1.56, .64, 1), background .2s ease, box-shadow .2s ease, color .2s ease; }
|
|
87
|
+
.op:hover { transform: translateY(-2px); box-shadow: inset 0 0 0 1.5px var(--ambar); }
|
|
88
|
+
.op:focus-visible { outline: 2px solid var(--ambar); outline-offset: 3px; }
|
|
89
|
+
.op[aria-pressed="true"] { background: var(--ambar); color: var(--sobre); box-shadow: none; }
|
|
90
|
+
.menos .op:hover { box-shadow: inset 0 0 0 1.5px var(--vermelho); }
|
|
91
|
+
.menos .op[aria-pressed="true"] { background: var(--vermelho); box-shadow: none; }
|
|
92
|
+
.op .ic { transform: scale(.74); transform-origin: center; margin: -4px -6px; }
|
|
93
|
+
@media (max-width: 560px) { .lista .item-ops h3 { width: 100%; } }
|
|
94
|
+
/* os ícones: cada um faz o movimento que nomeia */
|
|
95
|
+
.ic { position: relative; width: 46px; height: 34px; color: var(--ambar); perspective: 120px; }
|
|
96
|
+
.menos .ic { color: var(--vermelho); }
|
|
97
|
+
.op[aria-pressed="true"] .ic { color: var(--sobre); }
|
|
98
|
+
.ic i { position: absolute; display: block; background: currentColor; }
|
|
99
|
+
.ic-rapido i { left: 6px; height: 4px; border-radius: 2px; animation: icRapido .7s cubic-bezier(.6, 0, .4, 1) infinite; }
|
|
100
|
+
.ic-rapido i:nth-child(1) { top: 5px; width: 30px; } .ic-rapido i:nth-child(2) { top: 15px; width: 22px; animation-delay: .12s; } .ic-rapido i:nth-child(3) { top: 25px; width: 27px; animation-delay: .24s; }
|
|
101
|
+
@keyframes icRapido { 0% { transform: translateX(-10px) scaleX(.4); opacity: 0; } 40% { opacity: 1; } 100% { transform: translateX(12px) scaleX(1); opacity: 0; } }
|
|
102
|
+
.ic-tres_d i { left: 11px; top: 5px; width: 24px; height: 24px; background: none; border: 3px solid currentColor; border-radius: 5px; box-sizing: border-box; animation: ic3d 2.6s linear infinite; }
|
|
103
|
+
@keyframes ic3d { from { transform: rotateX(25deg) rotateY(0deg); } to { transform: rotateX(25deg) rotateY(360deg); } }
|
|
104
|
+
.ic-quique i { left: 17px; top: 0; width: 12px; height: 12px; border-radius: 50%; animation: icQuique .8s infinite; }
|
|
105
|
+
@keyframes icQuique { 0% { transform: translateY(0); animation-timing-function: cubic-bezier(.55, 0, 1, .45); } 45% { transform: translateY(20px) scale(1.3, .7); animation-timing-function: cubic-bezier(0, .55, .45, 1); } 55% { transform: translateY(18px) scale(.9, 1.1); } 100% { transform: translateY(0); } }
|
|
106
|
+
.ic-calmo i { left: 13px; top: 7px; width: 20px; height: 20px; border-radius: 50%; animation: icCalmo 3.2s ease-in-out infinite; }
|
|
107
|
+
@keyframes icCalmo { 0%, 100% { transform: scale(.6); opacity: .45; } 50% { transform: scale(1.1); opacity: 1; } }
|
|
108
|
+
.ic-lento i:nth-child(1) { left: 4px; top: 21px; width: 38px; height: 3px; border-radius: 2px; opacity: .3; }
|
|
109
|
+
.ic-lento i:nth-child(2) { left: 4px; top: 16px; width: 12px; height: 12px; border-radius: 50%; animation: icLento 4s linear infinite; }
|
|
110
|
+
@keyframes icLento { from { transform: translateX(0); } to { transform: translateX(26px); } }
|
|
111
|
+
.ic-exagero i { left: 11px; top: 5px; width: 24px; height: 24px; clip-path: polygon(50% 0, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%); animation: icExagero 1s cubic-bezier(.34, 1.56, .64, 1) infinite; }
|
|
112
|
+
@keyframes icExagero { 0%, 100% { transform: scale(.6) rotate(0deg); } 30% { transform: scale(1.45) rotate(-25deg); } 55% { transform: scale(.85) rotate(20deg); } }
|
|
113
|
+
.ic-flash i { left: 9px; top: 3px; width: 28px; height: 28px; border-radius: 6px; animation: icFlash .5s steps(1) infinite; }
|
|
114
|
+
@keyframes icFlash { 0% { opacity: 1; } 50% { opacity: .1; } }
|
|
115
|
+
.ic-tremido i { left: 8px; top: 14px; width: 30px; height: 6px; border-radius: 3px; animation: icTremido .25s steps(4) infinite; }
|
|
116
|
+
@keyframes icTremido { 0% { transform: translate(0, 0); } 25% { transform: translate(-3px, 2px); } 50% { transform: translate(3px, -2px); } 75% { transform: translate(-2px, -1px); } }
|
|
117
|
+
@media (prefers-reduced-motion: reduce) { .ic i { animation: none !important; } }
|
|
118
|
+
/* salvo no PrimoCode */
|
|
119
|
+
.salvo { margin: 0; display: inline-flex; gap: 10px; align-items: center; font-weight: 600; font-size: 17px; }
|
|
120
|
+
.mundo { position: absolute; left: 50%; top: 50%; width: 320px; height: 200px; margin: -100px 0 0 -160px; transform-style: preserve-3d; transform-origin: center; }
|
|
121
|
+
#catGrade { display: grid; grid-template-columns: minmax(0, 1fr); gap: 40px; }
|
|
122
|
+
.cat-sec { display: grid; gap: 16px; }
|
|
123
|
+
.cat-cab { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding-bottom: 10px; border-bottom: 1px solid var(--linha); }
|
|
124
|
+
.cat-cab h3 { margin: 0; font-size: 22px; font-weight: 600; letter-spacing: -.02em; }
|
|
125
|
+
.cat-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 18px; }
|
|
126
|
+
.tile .rotulo b { font-size: 15px; font-weight: 500; }
|
|
127
|
+
.salvo span { width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center; background: var(--ambar); color: var(--sobre); font-size: 13px; }
|
|
128
|
+
/* carrossel infinito: colunas de dois motions deslizam por transform; o carrossel vaza até a borda da janela
|
|
129
|
+
e esmaece nas pontas, então o motion que sai vai sumindo em vez de ser cortado pelo bloco */
|
|
130
|
+
body { overflow-x: clip; }
|
|
131
|
+
.carrossel { position: relative; width: 100vw; margin-left: calc(50% - 50vw); padding-block: 18px; overflow: hidden;
|
|
132
|
+
-webkit-mask-image: linear-gradient(90deg, transparent, #000 16%, #000 84%, transparent); mask-image: linear-gradient(90deg, transparent, #000 16%, #000 84%, transparent); }
|
|
133
|
+
.trilho { position: relative; width: min(1040px, calc(100vw - 32px)); margin: 0 auto; touch-action: pan-y; }
|
|
134
|
+
.trilho:focus-visible { outline: none; }
|
|
135
|
+
.trilho:focus-visible .coluna.vis { outline: 2px solid var(--ambar); outline-offset: 6px; border-radius: 22px; }
|
|
136
|
+
.coluna { position: absolute; left: 0; top: 0; display: grid; gap: 20px; will-change: transform, opacity;
|
|
137
|
+
transition: transform .9s cubic-bezier(.65, 0, .25, 1), opacity .9s cubic-bezier(.65, 0, .25, 1), filter .9s ease; }
|
|
138
|
+
.coluna.salta { transition: none; }
|
|
139
|
+
.coluna.longe { pointer-events: none; }
|
|
140
|
+
@media (prefers-reduced-motion: reduce) { .coluna { transition: opacity .2s linear; } }
|
|
141
|
+
.seta { all: unset; box-sizing: border-box; position: absolute; top: calc(50% - 24px); z-index: 4; width: 48px; height: 48px; border-radius: 50%; cursor: pointer;
|
|
142
|
+
display: grid; place-items: center; color: var(--giz); background: color-mix(in srgb, var(--palco) 80%, transparent);
|
|
143
|
+
-webkit-backdrop-filter: blur(14px) saturate(1.5); backdrop-filter: blur(14px) saturate(1.5);
|
|
144
|
+
box-shadow: var(--sombra-card), inset 0 0 0 1px var(--linha); transition: opacity .2s ease, transform .2s ease; }
|
|
145
|
+
.seta svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
|
|
146
|
+
.seta:hover { transform: scale(1.08); }
|
|
147
|
+
.seta:focus-visible { outline: 2px solid var(--ambar); outline-offset: 3px; }
|
|
148
|
+
.seta-volta { left: max(16px, calc(50% - 560px)); } .seta-vai { right: max(16px, calc(50% - 560px)); }
|
|
149
|
+
.rotulo .tipo { font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--ambar); }
|
|
150
|
+
.wrap { max-width: 1040px; margin: 0 auto; display: grid; gap: 48px; }
|
|
151
|
+
header { display: grid; gap: 12px; justify-items: center; text-align: center; }
|
|
152
|
+
.passos { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; font-size: 12px; color: var(--apagado); letter-spacing: 0; }
|
|
153
|
+
.passos span { padding: 4px 12px; border-radius: 999px; }
|
|
154
|
+
.passos span.ativo { color: var(--giz); background: var(--palco); font-weight: 600; }
|
|
155
|
+
h1 { font-size: clamp(32px, 5.4vw, 56px); line-height: 1.07; font-weight: 600; letter-spacing: -.028em; margin: 8px 0 0; text-wrap: balance; max-width: 18ch; }
|
|
156
|
+
.sub { color: var(--apagado); margin: 0; max-width: 46ch; font-size: clamp(17px, 2vw, 21px); line-height: 1.38; }
|
|
157
|
+
|
|
158
|
+
.grade { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
|
|
159
|
+
@media (max-width: 900px) { .grade { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
|
|
160
|
+
@media (max-width: 600px) { .grade { grid-template-columns: minmax(0, 1fr); } }
|
|
161
|
+
|
|
162
|
+
.card { all: unset; box-sizing: border-box; display: grid; gap: 14px; cursor: pointer; border-radius: 22px; position: relative; transition: transform .3s ease; }
|
|
163
|
+
.card:hover { transform: scale(1.012); }
|
|
164
|
+
.card:focus-visible { outline: 2px solid var(--ambar); outline-offset: 4px; }
|
|
165
|
+
.card[aria-pressed="true"] .palco { box-shadow: 0 0 0 2px var(--ambar); }
|
|
166
|
+
.selo { position: absolute; top: 12px; right: 12px; z-index: 3; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
|
|
167
|
+
font-size: 0; color: var(--sobre); background: var(--ambar); opacity: 0; transform: scale(.6); transition: opacity .2s ease, transform .25s ease; }
|
|
168
|
+
.selo::before { content: "✓"; font-size: 14px; font-weight: 600; }
|
|
169
|
+
.card[aria-pressed="true"] .selo { opacity: 1; transform: scale(1); }
|
|
170
|
+
.palco { position: relative; aspect-ratio: 16 / 10; max-width: 100%; background: var(--palco); border-radius: 18px; overflow: hidden; perspective: 900px; display: grid; place-items: center; transition: box-shadow .2s ease; }
|
|
171
|
+
.cena { position: relative; width: 100%; height: 100%; display: grid; place-items: center; transform-style: preserve-3d; }
|
|
172
|
+
.rotulo { display: grid; gap: 2px; padding: 0 4px; text-align: center; }
|
|
173
|
+
.rotulo b { font-size: 19px; font-weight: 600; color: var(--giz); }
|
|
174
|
+
.rotulo small { color: var(--apagado); font-size: 14px; letter-spacing: -.01em; }
|
|
175
|
+
|
|
176
|
+
/* peças das cenas */
|
|
177
|
+
.palavra { font-weight: 700; font-size: clamp(30px, 4.2vw, 44px); letter-spacing: -.03em; color: var(--cor); will-change: transform, opacity, filter; }
|
|
178
|
+
.bola { position: absolute; width: 30px; height: 30px; border-radius: 50%; background: var(--cor); bottom: 16%; left: 20%; }
|
|
179
|
+
.cartao { position: absolute; width: 30%; aspect-ratio: 3 / 2; border: 2px solid var(--cor); border-radius: 12px; }
|
|
180
|
+
.letras { display: flex; gap: .02em; font-family: var(--f-poster); font-weight: 800; letter-spacing: -.04em; font-size: clamp(38px, 5.4vw, 58px); color: var(--cor); }
|
|
181
|
+
.letras span { display: inline-block; will-change: transform; }
|
|
182
|
+
.faisca { position: absolute; width: 18px; height: 2px; background: var(--cor); border-radius: 1px; opacity: 0; }
|
|
183
|
+
|
|
184
|
+
.acoes { display: flex; gap: 20px; align-items: center; justify-content: center; flex-wrap: wrap; }
|
|
185
|
+
.btn { all: unset; cursor: pointer; font-size: 17px; font-weight: 400; padding: 12px 24px; border-radius: 980px; background: var(--ambar); color: var(--sobre); transition: background .2s ease, opacity .2s ease; }
|
|
186
|
+
.btn:hover { background: var(--ambar-hover); }
|
|
187
|
+
.btn:focus-visible { outline: 2px solid var(--ambar); outline-offset: 3px; }
|
|
188
|
+
.btn[disabled] { opacity: .3; cursor: not-allowed; }
|
|
189
|
+
/* botão grande, sem brilho; o Continuar do passo 1 só aparece depois da primeira escolha */
|
|
190
|
+
.btn-grande { font-size: 19px; font-weight: 600; padding: 17px 42px; transition: background .2s ease, transform .2s ease, opacity .35s ease; }
|
|
191
|
+
.btn-grande:hover { transform: translateY(-1px); }
|
|
192
|
+
#ir2 { transition: background .2s ease, opacity .4s ease, transform .4s cubic-bezier(.34, 1.56, .64, 1); }
|
|
193
|
+
#ir2[disabled] { opacity: 0; transform: translateY(10px) scale(.96); pointer-events: none; }
|
|
194
|
+
.link { all: unset; cursor: pointer; color: var(--ambar); font-size: 17px; }
|
|
195
|
+
.link:hover { text-decoration: underline; }
|
|
196
|
+
/* botão secundário de vidro: legível em cima da onda nos dois temas */
|
|
197
|
+
.btn-vidro { all: unset; cursor: pointer; font-size: 17px; padding: 16px 30px; border-radius: 980px; color: var(--giz);
|
|
198
|
+
background: color-mix(in srgb, var(--palco) 72%, transparent); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
|
|
199
|
+
box-shadow: inset 0 0 0 1px var(--linha); transition: background .2s ease; }
|
|
200
|
+
.btn-vidro:hover { background: var(--palco); }
|
|
201
|
+
.btn-vidro:focus-visible { outline: 2px solid var(--ambar); outline-offset: 3px; }
|
|
202
|
+
.link:focus-visible { outline: 2px solid var(--ambar); outline-offset: 2px; }
|
|
203
|
+
.conta { font-size: 14px; color: var(--apagado); font-variant-numeric: tabular-nums; }
|
|
204
|
+
|
|
205
|
+
/* passo 2 e 3 */
|
|
206
|
+
.lista { display: grid; gap: 20px; }
|
|
207
|
+
.item { display: grid; grid-template-columns: minmax(0, 300px) minmax(0, 1fr); gap: 32px; align-items: center; padding: 24px; background: var(--palco); border-radius: 22px; }
|
|
208
|
+
.item .palco { background: var(--bg); }
|
|
209
|
+
@media (max-width: 700px) { .item { grid-template-columns: minmax(0, 1fr); gap: 20px; } }
|
|
210
|
+
.item h3 { margin: 0 0 14px; font-size: 24px; font-weight: 600; letter-spacing: -.02em; color: var(--giz); }
|
|
211
|
+
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
|
|
212
|
+
.chip { all: unset; cursor: pointer; font-size: 14px; padding: 8px 16px; border-radius: 980px; background: var(--bg); color: var(--giz); box-shadow: inset 0 0 0 1px var(--linha); transition: background .15s ease, box-shadow .15s ease, color .15s ease; }
|
|
213
|
+
.chip:hover { box-shadow: inset 0 0 0 1px var(--apagado); }
|
|
214
|
+
.chip:focus-visible { outline: 2px solid var(--ambar); outline-offset: 2px; }
|
|
215
|
+
.chip[aria-pressed="true"] { background: var(--ambar); color: var(--sobre); box-shadow: none; }
|
|
216
|
+
.nao .chip[aria-pressed="true"] { background: var(--vermelho); }
|
|
217
|
+
.nao h3 { color: var(--giz) !important; }
|
|
218
|
+
textarea { width: 100%; min-height: 72px; resize: vertical; background: var(--bg); color: var(--giz); border: 1px solid var(--linha); border-radius: 12px; padding: 12px 14px; font: inherit; font-size: 15px; }
|
|
219
|
+
textarea:focus-visible { outline: none; border-color: var(--ambar); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ambar) 25%, transparent); }
|
|
220
|
+
|
|
221
|
+
/* ficha final */
|
|
222
|
+
.ficha { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 32px; }
|
|
223
|
+
@media (max-width: 800px) { .ficha { grid-template-columns: minmax(0, 1fr); } }
|
|
224
|
+
.ficha .acoes { justify-content: flex-start; }
|
|
225
|
+
.resumo { font-size: clamp(21px, 2.6vw, 28px); line-height: 1.3; font-weight: 600; letter-spacing: -.02em; margin: 0; max-width: 32ch; }
|
|
226
|
+
.tabela { font-size: 15px; background: var(--palco); border-radius: 18px; padding: 8px 20px; margin: 0; }
|
|
227
|
+
.tabela div { display: flex; justify-content: space-between; gap: 16px; padding: 13px 0; border-bottom: 1px solid var(--linha); }
|
|
228
|
+
.tabela div:last-child { border-bottom: 0; }
|
|
229
|
+
.tabela dt { color: var(--apagado); }
|
|
230
|
+
.tabela dd { margin: 0; text-align: right; color: var(--giz); font-weight: 500; font-variant-numeric: tabular-nums; }
|
|
231
|
+
.barra { height: 4px; background: var(--linha); border-radius: 2px; overflow: hidden; margin-top: 8px; }
|
|
232
|
+
.barra i { display: block; height: 100%; background: var(--ambar); border-radius: 2px; transition: width .9s cubic-bezier(.4,0,.2,1); }
|
|
233
|
+
pre { margin: 0; overflow-x: auto; background: var(--palco); border-radius: 18px; padding: 16px 20px; font-family: var(--f-mono); font-size: 12px; color: var(--apagado); max-height: 240px; letter-spacing: 0; }
|
|
234
|
+
/* tela final: só a frase, o check e o botão */
|
|
235
|
+
.fim { display: grid; justify-items: center; gap: 22px; text-align: center; margin-top: -8px; }
|
|
236
|
+
.fim-check svg { width: 96px; height: 96px; fill: none; stroke: var(--ambar); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; overflow: visible; }
|
|
237
|
+
.fim-check circle { stroke-dasharray: 145; stroke-dashoffset: 145; }
|
|
238
|
+
.fim-check path { stroke-width: 4; stroke-dasharray: 34; stroke-dashoffset: 34; }
|
|
239
|
+
#passo4:not([hidden]) .fim-check { animation: fimPula .7s cubic-bezier(.34, 1.56, .64, 1) .55s both; }
|
|
240
|
+
#passo4:not([hidden]) .fim-check circle { animation: fimTraco .6s cubic-bezier(.65, 0, .35, 1) forwards; }
|
|
241
|
+
#passo4:not([hidden]) .fim-check path { animation: fimTraco .35s cubic-bezier(.65, 0, .35, 1) .5s forwards; }
|
|
242
|
+
@keyframes fimTraco { to { stroke-dashoffset: 0; } }
|
|
243
|
+
@keyframes fimPula { 0% { transform: scale(1); } 40% { transform: scale(1.16); } 100% { transform: scale(1); } }
|
|
244
|
+
@media (prefers-reduced-motion: reduce) { .fim-check circle, .fim-check path { stroke-dashoffset: 0; animation: none !important; } .fim-check { animation: none !important; } }
|
|
245
|
+
.fim-sub { margin: 0; color: var(--apagado); font-size: clamp(17px, 2vw, 21px); }
|
|
246
|
+
.pular { font-size: 14px; color: var(--apagado); }
|
|
247
|
+
.erro { margin: 14px auto 0; max-width: 46ch; text-align: center; color: var(--vermelho); font-size: 15px; }
|
|
248
|
+
.nota { color: var(--apagado); font-size: 14px; margin: 0; max-width: 60ch; }
|
|
249
|
+
code { font-family: var(--f-mono); font-size: .92em; }
|
|
250
|
+
</style>
|
|
251
|
+
|
|
252
|
+
<canvas id="ondas" aria-hidden="true"></canvas>
|
|
253
|
+
<div class="wrap">
|
|
254
|
+
<header>
|
|
255
|
+
<h1 id="titulo">Qual movimento tem a sua cara?</h1>
|
|
256
|
+
</header>
|
|
257
|
+
|
|
258
|
+
<section id="passo1">
|
|
259
|
+
<div class="carrossel" id="carrossel">
|
|
260
|
+
<button class="seta seta-volta" id="setaVolta" aria-label="Voltar" aria-controls="grade"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M15 5l-7 7 7 7"/></svg></button>
|
|
261
|
+
<div class="trilho" id="grade" tabindex="0" aria-label="Todos os motions"></div>
|
|
262
|
+
<button class="seta seta-vai" id="setaVai" aria-label="Avançar" aria-controls="grade"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9 5l7 7-7 7"/></svg></button>
|
|
263
|
+
</div>
|
|
264
|
+
<div class="acoes" style="margin-top:36px"><button class="btn btn-grande" id="ir2" disabled>Continuar</button></div>
|
|
265
|
+
<div class="acoes" style="margin-top:14px"><button class="link pular" id="pular">pular por agora</button></div>
|
|
266
|
+
</section>
|
|
267
|
+
|
|
268
|
+
<section id="passo2" hidden>
|
|
269
|
+
<div class="lista" id="lista2"></div>
|
|
270
|
+
<div class="acoes" style="margin-top:28px"><button class="btn btn-grande" id="ir3">Continuar</button><button class="btn-vidro" id="volta1">Voltar</button></div>
|
|
271
|
+
<p class="erro" id="erro" role="alert" hidden></p>
|
|
272
|
+
</section>
|
|
273
|
+
|
|
274
|
+
<section id="passo3" hidden>
|
|
275
|
+
<div class="lista">
|
|
276
|
+
<div class="item nao" style="--cor:var(--giz)">
|
|
277
|
+
<div class="palco" id="palcoNao"></div>
|
|
278
|
+
<div>
|
|
279
|
+
<h3>O que você NÃO quer ver?</h3>
|
|
280
|
+
<textarea id="naoTexto" placeholder="algo que te incomoda em motion? (opcional)"></textarea>
|
|
281
|
+
<div class="sug" id="sugNao"></div>
|
|
282
|
+
<p class="rot-chips">Marque o que você não quer</p>
|
|
283
|
+
<div class="chips" id="chipsNao"></div>
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
<div class="acoes" style="margin-top:22px"><button class="btn" id="salvar">Salvar meu gosto</button><button class="link" id="volta2">voltar</button></div>
|
|
288
|
+
</section>
|
|
289
|
+
|
|
290
|
+
<section id="passo4" hidden>
|
|
291
|
+
<div class="fim">
|
|
292
|
+
<div class="fim-check" aria-hidden="true"><svg viewBox="0 0 52 52"><circle cx="26" cy="26" r="23"/><path d="M15.5 27l7 7 14-15"/></svg></div>
|
|
293
|
+
<p class="fim-sub" id="fimSub" aria-live="polite">Tudo salvo no seu PrimoCode.</p>
|
|
294
|
+
<button class="btn btn-grande" id="finalizar">Voltar pro PrimoCode</button>
|
|
295
|
+
</div>
|
|
296
|
+
</section>
|
|
297
|
+
</div>
|
|
298
|
+
|
|
299
|
+
<script>
|
|
300
|
+
const TOKEN = '__TOKEN__';
|
|
301
|
+
window.GOSTO = __DADOS__; // o servidor manda os estilos que ele conhece; a tela só mostra esses
|
|
302
|
+
const ESTILOS = [
|
|
303
|
+
{ id: 'brincalhao', nome: 'Brincalhão', frase: 'quica e passa do ponto', ritmo: 'rapido', cameras: ['pulso','orbita'], trocas: ['giro','encolhe','abre'], tipografias: ['arredondada','manuscrita'], overshoot: .18 },
|
|
304
|
+
{ id: 'premium', nome: 'Premium', frase: 'lento, liso, elegante', ritmo: 'lento', cameras: ['cinema','deriva'], trocas: ['desfoque','dissolve','cortina'], tipografias: ['serifa_fina','editorial'], overshoot: 0 },
|
|
305
|
+
{ id: 'corporativo', nome: 'Direto', frase: 'empurra e corta seco', ritmo: 'medio', cameras: ['trilho','push'], trocas: ['empurra','persiana','corte'], tipografias: ['geometrica','tecnica'], overshoot: .04 },
|
|
306
|
+
{ id: 'energico', nome: 'Enérgico', frase: 'chicote, punch no beat', ritmo: 'rapido', cameras: ['chicote','pulso'], trocas: ['chicote','tremor','zoom','corte'], tipografias: ['pesada','poster'], overshoot: .25 },
|
|
307
|
+
{ id: 'cinema3d', nome: 'Cinema 3D', frase: 'gira em profundidade', ritmo: 'medio', cameras: ['orbita','cinema','push'], trocas: ['giro','zoom','empurra'], tipografias: ['poster','editorial'], overshoot: .1 },
|
|
308
|
+
{ id: 'cinetico', nome: 'Letra que dança', frase: 'cada letra entra sozinha', ritmo: 'rapido', cameras: ['pulso','push'], trocas: ['corte','chicote','encolhe'], tipografias: ['poster','pesada','tecnica'], overshoot: .15 },
|
|
309
|
+
];
|
|
310
|
+
const GOSTEI = [['rapido','rápido'],['tres_d','3D'],['quique','com quique'],['calmo','calmo']];
|
|
311
|
+
const NAO_QUERO = [['lento','devagar'],['exagero','exagerado'],['flash','flash'],['tremido','tremido']];
|
|
312
|
+
const RITMO_NOME = { rapido: 'rápido', medio: 'médio', lento: 'lento' };
|
|
313
|
+
const SUGESTOES = {
|
|
314
|
+
brincalhao: ['o quique no fim', 'a bolinha amassando', 'parece desenho animado', 'leve e divertido'],
|
|
315
|
+
premium: ['a entrada lenta', 'o desfoque saindo', 'parece marca de luxo', 'a letra com serifa'],
|
|
316
|
+
direto: ['sem enrolação', 'o corte seco', 'tudo alinhado', 'parece apresentação de empresa'],
|
|
317
|
+
energico: ['o soco na batida', 'a letra inclinada', 'muita energia', 'parece trailer'],
|
|
318
|
+
cinema3d: ['a profundidade', 'o giro do cartão', 'parece filme', 'a palavra vindo do fundo'],
|
|
319
|
+
cinetico: ['cada letra sozinha', 'o giro do O', 'ritmo de música', 'letra grande e pesada'],
|
|
320
|
+
};
|
|
321
|
+
const SUG_NAO = ['elemento colado na borda', 'música fraca', 'efeito demais', 'texto difícil de ler', 'todo vídeo igual'];
|
|
322
|
+
|
|
323
|
+
/* pílulas "+": um toque põe a frase no campo, outro tira; o texto continua editável */
|
|
324
|
+
function sugestoes(frases, ta, aoMudar) {
|
|
325
|
+
return el('div', { class: 'sug' }, frases.map((f) => {
|
|
326
|
+
const b = el('button', { 'aria-pressed': 'false', text: f });
|
|
327
|
+
b.addEventListener('click', () => {
|
|
328
|
+
const on = b.getAttribute('aria-pressed') !== 'true';
|
|
329
|
+
b.setAttribute('aria-pressed', String(on));
|
|
330
|
+
const partes = ta.value.split(',').map((s) => s.trim()).filter((s) => s && s !== f);
|
|
331
|
+
if (on) partes.push(f);
|
|
332
|
+
ta.value = partes.join(', ').slice(0, 280);
|
|
333
|
+
aoMudar(ta.value);
|
|
334
|
+
});
|
|
335
|
+
return b;
|
|
336
|
+
}));
|
|
337
|
+
}
|
|
338
|
+
const parar = matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
339
|
+
|
|
340
|
+
const estado = { escolhidos: new Map(), nao: new Set(), naoTexto: '', extras: new Set() };
|
|
341
|
+
const $ = (s) => document.querySelector(s);
|
|
342
|
+
const el = (tag, attrs = {}, kids = []) => { const e = document.createElement(tag); for (const [k, v] of Object.entries(attrs)) { if (k === 'text') e.textContent = v; else if (k === 'style') e.style.cssText = v; else e.setAttribute(k, v); } kids.forEach((k) => e.appendChild(k)); return e; };
|
|
343
|
+
|
|
344
|
+
/* ── as cenas ─────────────────────────────────────────────────────────────
|
|
345
|
+
Cada telinha é um "mundo" de 320×200 px escalado pro tamanho do card, então as
|
|
346
|
+
distâncias valem igual no celular e no desktop. Easing vai em cada keyframe
|
|
347
|
+
(o easing geral da animação distorceria a linha do tempo inteira). */
|
|
348
|
+
const OVER = 'cubic-bezier(.34,1.56,.64,1)', LISO = 'cubic-bezier(.4,0,.2,1)', MD3 = 'cubic-bezier(.2,0,0,1)',
|
|
349
|
+
CAI = 'cubic-bezier(.55,0,1,.45)', SOBE = 'cubic-bezier(0,.55,.45,1)', CHICOTE = 'cubic-bezier(.75,0,.15,1)';
|
|
350
|
+
const loop = (n, kf, opt) => n.animate(kf, { iterations: Infinity, ...opt });
|
|
351
|
+
const TINTA = 'var(--cor)', VEU = 'color-mix(in srgb, var(--cor) 9%, transparent)';
|
|
352
|
+
const T = (x = 0, y = 0, r = 0, sx = 1, sy = sx) => `translate(${x}px,${y}px) rotate(${r}deg) scale(${sx},${sy})`;
|
|
353
|
+
|
|
354
|
+
function mundo(palco) {
|
|
355
|
+
const m = el('div', { class: 'mundo' });
|
|
356
|
+
palco.appendChild(m);
|
|
357
|
+
const ajustar = () => { m.style.scale = String((palco.clientWidth || 320) / 320); };
|
|
358
|
+
ajustar();
|
|
359
|
+
try { new ResizeObserver(ajustar).observe(palco); } catch { /* sem ResizeObserver: fica no tamanho inicial */ }
|
|
360
|
+
return m;
|
|
361
|
+
}
|
|
362
|
+
const peca = (pai, estilo, texto) => {
|
|
363
|
+
const e = el('div', texto == null ? { style: 'position:absolute;' + estilo } : { style: 'position:absolute;' + estilo, text: texto });
|
|
364
|
+
pai.appendChild(e); return e;
|
|
365
|
+
};
|
|
366
|
+
const palavra = (pai, estilo, texto = 'PRIMO') => peca(pai, `font-family:var(--f-display);font-weight:800;letter-spacing:-.04em;color:${TINTA};white-space:nowrap;line-height:1;` + estilo, texto);
|
|
367
|
+
function letras(pai, estilo, texto = 'PRIMO') {
|
|
368
|
+
const w = peca(pai, `display:flex;font-family:var(--f-display);font-weight:800;letter-spacing:-.04em;color:${TINTA};line-height:1;white-space:pre;` + estilo);
|
|
369
|
+
return texto.split('').map((ch) => { const s = el('span', { text: ch, style: 'display:inline-block;will-change:transform' }); w.appendChild(s); return s; });
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function montarCena(id, palco) {
|
|
373
|
+
const m = mundo(palco), A = [];
|
|
374
|
+
if (parar) {
|
|
375
|
+
const p = palavra(m, 'left:0;right:0;top:78px;text-align:center;font-size:44px');
|
|
376
|
+
A.push(loop(p, [{ opacity: .35 }, { opacity: 1 }], { duration: 2400, direction: 'alternate' }));
|
|
377
|
+
return A;
|
|
378
|
+
}
|
|
379
|
+
const CENAS = { ...NOVAS_CENAS, brincalhao: cenaBrincalhao, premium: cenaPremium, corporativo: cenaDireto, energico: cenaEnergico, cinema3d: cenaCinema3d, cinetico: cenaCinetico, nao: cenaNao };
|
|
380
|
+
(CENAS[id] || cenaPremium)(m, A);
|
|
381
|
+
return A;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/* Brincalhão: a bolinha cai, quica três vezes, estoura em confete e vira a palavra. */
|
|
385
|
+
function cenaBrincalhao(m, A) {
|
|
386
|
+
const D = 3200;
|
|
387
|
+
const bola = peca(m, `left:146px;top:-34px;width:28px;height:28px;border-radius:50%;background:${TINTA}`);
|
|
388
|
+
A.push(loop(bola, [
|
|
389
|
+
{ transform: T(0, 0), opacity: 1, easing: CAI },
|
|
390
|
+
{ transform: T(0, 150, 0, 1.3, .65), offset: .14, easing: SOBE },
|
|
391
|
+
{ transform: T(0, 80, 0, .85, 1.15), offset: .24, easing: CAI },
|
|
392
|
+
{ transform: T(0, 150, 0, 1.2, .75), offset: .33, easing: SOBE },
|
|
393
|
+
{ transform: T(0, 118, 0, .95, 1.05), offset: .4, easing: CAI },
|
|
394
|
+
{ transform: T(0, 150, 0, 1.1, .85), offset: .46 },
|
|
395
|
+
{ transform: T(0, 140, 0, 1.6), opacity: 1, offset: .5 },
|
|
396
|
+
{ transform: T(0, 140, 0, 0), opacity: 0, offset: .53 },
|
|
397
|
+
{ transform: T(0, 0, 0, 0), opacity: 0 }], { duration: D }));
|
|
398
|
+
for (let i = 0; i < 10; i++) {
|
|
399
|
+
const a = (i / 10) * Math.PI * 2, r = 70 + (i % 3) * 18, t = i % 2 ? 6 : 9;
|
|
400
|
+
const c = peca(m, `left:156px;top:118px;width:${t}px;height:${t}px;border-radius:${i % 3 ? '50%' : '2px'};background:${TINTA};opacity:0`);
|
|
401
|
+
A.push(loop(c, [
|
|
402
|
+
{ transform: T(0, 0, 0, 0), opacity: 0 },
|
|
403
|
+
{ transform: T(0, 0, 0, 0), opacity: 0, offset: .5 },
|
|
404
|
+
{ transform: T(0, 0, 0, 1), opacity: 1, offset: .51, easing: 'cubic-bezier(.1,.8,.3,1)' },
|
|
405
|
+
{ transform: T(Math.cos(a) * r, Math.sin(a) * r * .7 + 20, i * 50, .6), opacity: 0, offset: .74 },
|
|
406
|
+
{ transform: T(0, 0, 0, 0), opacity: 0 }], { duration: D }));
|
|
407
|
+
}
|
|
408
|
+
letras(m, 'left:0;right:0;top:66px;justify-content:center;font-size:52px').forEach((s, i) => {
|
|
409
|
+
const t = .5 + i * .028, rot = [-14, 10, -6, 12, -10][i];
|
|
410
|
+
A.push(loop(s, [
|
|
411
|
+
{ transform: T(0, 40, 0, 0) },
|
|
412
|
+
{ transform: T(0, 40, 0, 0), offset: t, easing: OVER },
|
|
413
|
+
{ transform: T(0, -18, rot, 1.3), offset: t + .07 },
|
|
414
|
+
{ transform: T(0, 4, -rot / 3, .94), offset: t + .12 },
|
|
415
|
+
{ transform: T(0, 0, 0, 1), offset: t + .17 },
|
|
416
|
+
{ transform: T(0, 0, 0, 1), offset: .86, easing: 'ease-out' },
|
|
417
|
+
{ transform: T(0, -6, 0, 1.1), offset: .9, easing: 'ease-in' },
|
|
418
|
+
{ transform: T(0, 30, 0, 0), offset: .97 },
|
|
419
|
+
{ transform: T(0, 30, 0, 0) }], { duration: D }));
|
|
420
|
+
});
|
|
421
|
+
const card = peca(m, `left:238px;top:22px;width:46px;height:32px;border-radius:9px;border:2.5px solid ${TINTA}`);
|
|
422
|
+
A.push(loop(card, [
|
|
423
|
+
{ transform: T(0, 0, -30, 0) }, { transform: T(0, 0, -30, 0), offset: .62, easing: OVER },
|
|
424
|
+
{ transform: T(0, 0, 14, 1.25), offset: .7 }, { transform: T(0, 0, -6, 1), offset: .76 },
|
|
425
|
+
{ transform: T(0, 0, 3, 1), offset: .82 }, { transform: T(0, 0, 0, 1), offset: .88, easing: 'ease-in' },
|
|
426
|
+
{ transform: T(0, 0, 30, 0), offset: .96 }, { transform: T(0, 0, 30, 0) }], { duration: D }));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/* Premium: a câmera recua devagar, a palavra sai do desfoque apertando o espaçamento e um brilho corre por ela. */
|
|
430
|
+
function cenaPremium(m, A) {
|
|
431
|
+
const D = 4400;
|
|
432
|
+
A.push(loop(m, [{ transform: 'scale(1.14)' }, { transform: 'scale(1)' }], { duration: D, easing: LISO }));
|
|
433
|
+
const fonte = 'left:0;right:0;top:56px;text-align:center;font-family:var(--f-serifa);font-style:italic;font-weight:400;font-size:60px;letter-spacing:-.01em;';
|
|
434
|
+
const p = palavra(m, fonte, 'Primo');
|
|
435
|
+
A.push(loop(p, [
|
|
436
|
+
{ opacity: 0, filter: 'blur(16px)', letterSpacing: '.35em', transform: 'translateY(10px)', easing: LISO },
|
|
437
|
+
{ opacity: 1, filter: 'blur(0px)', letterSpacing: '-.01em', transform: 'translateY(0)', offset: .42 },
|
|
438
|
+
{ opacity: 1, filter: 'blur(0px)', letterSpacing: '-.01em', transform: 'translateY(0)', offset: .84, easing: LISO },
|
|
439
|
+
{ opacity: 0, filter: 'blur(12px)', letterSpacing: '.1em', transform: 'translateY(-6px)' }], { duration: D }));
|
|
440
|
+
const brilho = palavra(m, fonte + 'color:transparent;background:linear-gradient(105deg,transparent 42%,rgba(255,255,255,.95) 50%,transparent 58%);background-size:300% 100%;-webkit-background-clip:text;background-clip:text', 'Primo');
|
|
441
|
+
A.push(loop(brilho, [
|
|
442
|
+
{ backgroundPosition: '100% 0', opacity: 0 }, { backgroundPosition: '100% 0', opacity: 1, offset: .46, easing: LISO },
|
|
443
|
+
{ backgroundPosition: '0% 0', opacity: 1, offset: .74 }, { backgroundPosition: '0% 0', opacity: 0, offset: .8 }, { backgroundPosition: '0% 0', opacity: 0 }], { duration: D }));
|
|
444
|
+
const linha = peca(m, `left:110px;top:134px;width:100px;height:1px;background:${TINTA}`);
|
|
445
|
+
A.push(loop(linha, [
|
|
446
|
+
{ transform: 'scaleX(0)' }, { transform: 'scaleX(0)', offset: .3, easing: LISO }, { transform: 'scaleX(1)', offset: .56 },
|
|
447
|
+
{ transform: 'scaleX(1)', offset: .84, easing: LISO }, { transform: 'scaleX(0)', opacity: 0 }], { duration: D }));
|
|
448
|
+
const tag = peca(m, `left:0;right:0;top:148px;text-align:center;font-family:var(--f-mono);font-size:9px;letter-spacing:.6em;color:${TINTA}`, 'ESTÚDIO · MMXXVI');
|
|
449
|
+
A.push(loop(tag, [
|
|
450
|
+
{ opacity: 0, letterSpacing: '1em' }, { opacity: 0, letterSpacing: '1em', offset: .46, easing: LISO },
|
|
451
|
+
{ opacity: .7, letterSpacing: '.6em', offset: .66 }, { opacity: .7, letterSpacing: '.6em', offset: .84 }, { opacity: 0, letterSpacing: '.6em' }], { duration: D }));
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/* Direto: o título sobe por máscara, as barras entram empurrando, o anel enche e tudo sai numa cortina seca. */
|
|
455
|
+
function cenaDireto(m, A) {
|
|
456
|
+
const D = 2800;
|
|
457
|
+
const g = peca(m, 'left:0;top:0;width:320px;height:200px');
|
|
458
|
+
A.push(loop(g, [
|
|
459
|
+
{ clipPath: 'inset(0 0 0 0)' }, { clipPath: 'inset(0 0 0 0)', offset: .82, easing: MD3 },
|
|
460
|
+
{ clipPath: 'inset(0 0 0 100%)', offset: .92 }, { clipPath: 'inset(0 0 0 100%)' }], { duration: D }));
|
|
461
|
+
const titulo = palavra(g, 'left:36px;top:26px;font-size:36px');
|
|
462
|
+
A.push(loop(titulo, [
|
|
463
|
+
{ clipPath: 'inset(100% 0 0 0)', transform: 'translateY(16px)' }, { clipPath: 'inset(100% 0 0 0)', transform: 'translateY(16px)', offset: .03, easing: MD3 },
|
|
464
|
+
{ clipPath: 'inset(0 0 0 0)', transform: 'translateY(0)', offset: .18 }, { clipPath: 'inset(0 0 0 0)', transform: 'translateY(0)' }], { duration: D }));
|
|
465
|
+
[.7, .45, .86].forEach((v, i) => {
|
|
466
|
+
const y = 80 + i * 32;
|
|
467
|
+
const trilho = peca(g, `left:36px;top:${y}px;width:168px;height:22px;border-radius:7px;background:${VEU}`);
|
|
468
|
+
const cheio = peca(trilho, `left:0;top:0;height:22px;width:${v * 100}%;border-radius:7px;background:${TINTA};transform-origin:left`);
|
|
469
|
+
A.push(loop(trilho, [
|
|
470
|
+
{ transform: 'translateX(320px)' }, { transform: 'translateX(320px)', offset: .08 + i * .05, easing: MD3 },
|
|
471
|
+
{ transform: 'translateX(0)', offset: .24 + i * .05 }, { transform: 'translateX(0)' }], { duration: D }));
|
|
472
|
+
A.push(loop(cheio, [
|
|
473
|
+
{ transform: 'scaleX(0)' }, { transform: 'scaleX(0)', offset: .26 + i * .05, easing: MD3 },
|
|
474
|
+
{ transform: 'scaleX(1)', offset: .46 + i * .05 }, { transform: 'scaleX(1)' }], { duration: D }));
|
|
475
|
+
});
|
|
476
|
+
const NS = ['http:', '', 'www.w3.org', '2000', 'svg'].join('/');
|
|
477
|
+
const svg = document.createElementNS(NS, 'svg');
|
|
478
|
+
svg.setAttribute('viewBox', '0 0 64 64');
|
|
479
|
+
svg.style.cssText = 'position:absolute;left:222px;top:86px;width:68px;height:68px;overflow:visible;color:var(--cor)';
|
|
480
|
+
const circ = (attrs) => { const c = document.createElementNS(NS, 'circle'); Object.entries({ cx: 32, cy: 32, r: 26, fill: 'none', stroke: 'currentColor', 'stroke-width': 6, ...attrs }).forEach(([k, v]) => c.setAttribute(k, v)); svg.appendChild(c); return c; };
|
|
481
|
+
circ({ opacity: .12 });
|
|
482
|
+
const arco = circ({ 'stroke-linecap': 'round', 'stroke-dasharray': 163.4, 'stroke-dashoffset': 163.4, transform: 'rotate(-90 32 32)' });
|
|
483
|
+
const txt = document.createElementNS(NS, 'text');
|
|
484
|
+
Object.entries({ x: 32, y: 37, 'text-anchor': 'middle', 'font-size': 14, 'font-weight': 700, fill: 'currentColor', 'font-family': '-apple-system, sans-serif' }).forEach(([k, v]) => txt.setAttribute(k, v));
|
|
485
|
+
txt.textContent = '75%'; svg.appendChild(txt);
|
|
486
|
+
g.appendChild(svg);
|
|
487
|
+
A.push(loop(svg, [
|
|
488
|
+
{ transform: 'scale(.5)', opacity: 0 }, { transform: 'scale(.5)', opacity: 0, offset: .16, easing: OVER },
|
|
489
|
+
{ transform: 'scale(1)', opacity: 1, offset: .28 }, { transform: 'scale(1)', opacity: 1 }], { duration: D }));
|
|
490
|
+
A.push(loop(arco, [
|
|
491
|
+
{ strokeDashoffset: 163.4 }, { strokeDashoffset: 163.4, offset: .28, easing: MD3 },
|
|
492
|
+
{ strokeDashoffset: 41 }, { strokeDashoffset: 41 }].map((k, i) => (i === 2 ? { ...k, offset: .56 } : k)), { duration: D }));
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/* Enérgico: listras correndo, rastros do chicote, a palavra entra inclinada, dois socos de câmera com faísca e um selo carimbado. */
|
|
496
|
+
function cenaEnergico(m, A) {
|
|
497
|
+
const D = 1800;
|
|
498
|
+
const fundo = peca(m, 'left:-60px;top:-40px;width:440px;height:280px;background:repeating-linear-gradient(115deg, color-mix(in srgb, var(--cor) 7%, transparent) 0 3px, transparent 3px 24px)');
|
|
499
|
+
A.push(loop(fundo, [{ transform: 'translateX(0)' }, { transform: 'translateX(-53px)' }], { duration: 360, easing: 'linear' }));
|
|
500
|
+
const cam = peca(m, 'left:0;top:0;width:320px;height:200px');
|
|
501
|
+
A.push(loop(cam, [
|
|
502
|
+
{ transform: T(0, 0, 0, 1) }, { transform: T(0, 0, 0, 1), offset: .3 },
|
|
503
|
+
{ transform: T(0, 0, -2, 1.14), offset: .33, easing: 'ease-out' }, { transform: T(0, 0, 0, 1), offset: .45 },
|
|
504
|
+
{ transform: T(0, 0, 0, 1), offset: .64 }, { transform: T(0, 0, 2, 1.12), offset: .67, easing: 'ease-out' },
|
|
505
|
+
{ transform: T(0, 0, 0, 1), offset: .79 }, { transform: T(0, 0, 0, 1) }], { duration: D }));
|
|
506
|
+
[62, 84, 120, 140].forEach((y, i) => {
|
|
507
|
+
const r = peca(cam, `left:0;top:${y}px;width:${120 + i * 30}px;height:${i % 2 ? 2 : 3}px;border-radius:2px;background:${TINTA}`);
|
|
508
|
+
const t = .02 + i * .015;
|
|
509
|
+
A.push(loop(r, [
|
|
510
|
+
{ transform: 'translateX(-260px) scaleX(.3)', opacity: 0 }, { transform: 'translateX(-260px) scaleX(.3)', opacity: 0, offset: t, easing: 'ease-out' },
|
|
511
|
+
{ transform: 'translateX(120px) scaleX(1)', opacity: .9, offset: t + .12 }, { transform: 'translateX(380px) scaleX(.2)', opacity: 0, offset: t + .22 },
|
|
512
|
+
{ transform: 'translateX(380px) scaleX(.2)', opacity: 0 }], { duration: D }));
|
|
513
|
+
});
|
|
514
|
+
const p = palavra(cam, 'left:0;right:0;top:56px;text-align:center;font-size:70px;font-weight:900;font-style:italic;letter-spacing:-.05em');
|
|
515
|
+
A.push(loop(p, [
|
|
516
|
+
{ transform: 'translateX(-380px) skewX(-35deg)', easing: CHICOTE },
|
|
517
|
+
{ transform: 'translateX(14px) skewX(14deg)', offset: .16, easing: 'ease-out' },
|
|
518
|
+
{ transform: 'translateX(0) skewX(0deg)', offset: .24 },
|
|
519
|
+
{ transform: 'translateX(0) skewX(0deg)', offset: .86, easing: 'cubic-bezier(.7,0,.9,.3)' },
|
|
520
|
+
{ transform: 'translateX(400px) skewX(-30deg)' }], { duration: D }));
|
|
521
|
+
const sub = peca(cam, `left:78px;top:132px;width:164px;height:9px;border-radius:2px;background:${TINTA};transform-origin:left`);
|
|
522
|
+
A.push(loop(sub, [
|
|
523
|
+
{ transform: 'scaleX(0)' }, { transform: 'scaleX(0)', offset: .28, easing: OVER }, { transform: 'scaleX(1.12)', offset: .33 },
|
|
524
|
+
{ transform: 'scaleX(1)', offset: .4 }, { transform: 'scaleX(1)', offset: .86 }, { transform: 'scaleX(0)', offset: .92 }, { transform: 'scaleX(0)' }], { duration: D }));
|
|
525
|
+
for (let i = 0; i < 8; i++) {
|
|
526
|
+
const x = i < 4 ? 78 : 242, a = (i % 4) * 40 - 60 + (i < 4 ? 180 : 0), b = i < 4 ? .31 : .65;
|
|
527
|
+
const f = peca(cam, `left:${x}px;top:136px;width:16px;height:2.5px;border-radius:2px;background:${TINTA};transform-origin:left center;opacity:0`);
|
|
528
|
+
A.push(loop(f, [
|
|
529
|
+
{ opacity: 0, transform: `rotate(${a}deg) translateX(0) scaleX(.2)` }, { opacity: 0, transform: `rotate(${a}deg) translateX(0) scaleX(.2)`, offset: b },
|
|
530
|
+
{ opacity: 1, transform: `rotate(${a}deg) translateX(6px) scaleX(1)`, offset: b + .02, easing: 'ease-out' },
|
|
531
|
+
{ opacity: 0, transform: `rotate(${a}deg) translateX(30px) scaleX(.3)`, offset: b + .13 }, { opacity: 0, transform: `rotate(${a}deg) translateX(30px) scaleX(.3)` }], { duration: D }));
|
|
532
|
+
}
|
|
533
|
+
const selo = palavra(cam, `left:224px;top:28px;font-size:13px;font-weight:800;letter-spacing:.06em;padding:5px 9px;border-radius:6px;background:${TINTA};color:var(--palco)`, 'NOVO');
|
|
534
|
+
A.push(loop(selo, [
|
|
535
|
+
{ transform: T(0, 0, -30, 0), opacity: 0 }, { transform: T(0, 0, -30, 0), opacity: 0, offset: .63 },
|
|
536
|
+
{ transform: T(0, 0, -14, 2.2), opacity: .2, offset: .64, easing: 'ease-in' }, { transform: T(0, 0, -12, 1), opacity: 1, offset: .69 },
|
|
537
|
+
{ transform: T(0, 0, -12, 1), opacity: 1, offset: .86 }, { transform: T(0, 0, 0, 0), opacity: 0, offset: .92 }, { transform: T(0, 0, 0, 0), opacity: 0 }], { duration: D }));
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/* Cinema 3D: três planos empilhados em profundidade giram no espaço, a sombra acompanha e a palavra voa do fundo. */
|
|
541
|
+
function cenaCinema3d(m, A) {
|
|
542
|
+
const D = 4200, VAI = 'cubic-bezier(.45,0,.55,1)';
|
|
543
|
+
const chao = peca(m, 'left:96px;top:146px;width:128px;height:20px;border-radius:50%;background:radial-gradient(closest-side, color-mix(in srgb, var(--cor) 24%, transparent), transparent)');
|
|
544
|
+
A.push(loop(chao, [{ transform: 'scaleX(1)', easing: VAI }, { transform: 'scaleX(.72)', offset: .5, easing: VAI }, { transform: 'scaleX(1)' }], { duration: D }));
|
|
545
|
+
const pilha = peca(m, 'left:95px;top:26px;width:130px;height:86px;transform-style:preserve-3d');
|
|
546
|
+
const planos = [0, 1, 2].map((i) => peca(pilha, `left:0;top:0;width:130px;height:86px;box-sizing:border-box;border-radius:14px;border:2px solid ${TINTA};background:${i === 2 ? 'var(--palco)' : VEU};opacity:${i === 0 ? .5 : i === 1 ? .8 : 1};transform:translateZ(${(i - 1) * 34}px)`));
|
|
547
|
+
peca(planos[2], `left:16px;top:18px;width:34px;height:34px;border-radius:50%;border:2.5px solid ${TINTA};box-sizing:border-box`);
|
|
548
|
+
peca(planos[2], `left:62px;top:24px;width:50px;height:6px;border-radius:3px;background:${TINTA}`);
|
|
549
|
+
peca(planos[2], `left:62px;top:38px;width:34px;height:6px;border-radius:3px;background:${TINTA};opacity:.4`);
|
|
550
|
+
peca(planos[2], `left:16px;top:62px;width:96px;height:6px;border-radius:3px;background:${TINTA};opacity:.2`);
|
|
551
|
+
A.push(loop(pilha, [
|
|
552
|
+
{ transform: 'translateY(0) rotateX(16deg) rotateY(-38deg)', easing: VAI },
|
|
553
|
+
{ transform: 'translateY(-8px) rotateX(6deg) rotateY(38deg)', offset: .5, easing: VAI },
|
|
554
|
+
{ transform: 'translateY(0) rotateX(16deg) rotateY(-38deg)' }], { duration: D }));
|
|
555
|
+
const p = palavra(m, 'left:0;right:0;top:140px;text-align:center;font-size:30px;letter-spacing:.02em');
|
|
556
|
+
A.push(loop(p, [
|
|
557
|
+
{ transform: 'translateZ(-900px)', opacity: 0, filter: 'blur(8px)' },
|
|
558
|
+
{ transform: 'translateZ(-900px)', opacity: 0, filter: 'blur(8px)', offset: .12, easing: 'cubic-bezier(.15,.85,.3,1)' },
|
|
559
|
+
{ transform: 'translateZ(50px)', opacity: 1, filter: 'blur(0px)', offset: .4, easing: 'ease-out' },
|
|
560
|
+
{ transform: 'translateZ(0px)', opacity: 1, filter: 'blur(0px)', offset: .48 },
|
|
561
|
+
{ transform: 'translateZ(0px)', opacity: 1, filter: 'blur(0px)', offset: .86, easing: 'ease-in' },
|
|
562
|
+
{ transform: 'translateZ(380px)', opacity: 0, filter: 'blur(6px)' }], { duration: D }));
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/* Letra que dança: cada letra chega por um caminho, uma onda passa por elas, o O gira e todas se espalham. */
|
|
566
|
+
function cenaCinetico(m, A) {
|
|
567
|
+
const D = 3400;
|
|
568
|
+
const de = [[0, -140, -30, 1], [0, 140, 40, 1], [0, 0, 180, 0], [-200, 0, -40, 1], [220, 0, -200, 1]];
|
|
569
|
+
letras(m, 'left:0;right:0;top:64px;justify-content:center;font-size:66px;font-weight:900').forEach((s, i) => {
|
|
570
|
+
const t0 = i * .045, onda = .38 + i * .045;
|
|
571
|
+
const kf = [
|
|
572
|
+
{ transform: T(...de[i]), opacity: 0 },
|
|
573
|
+
{ transform: T(...de[i]), opacity: 0, offset: t0, easing: OVER },
|
|
574
|
+
{ transform: T(), opacity: 1, offset: t0 + .16 },
|
|
575
|
+
{ transform: T(), opacity: 1, offset: onda, easing: 'ease-out' },
|
|
576
|
+
{ transform: T(0, -22, 0, .9, 1.2), opacity: 1, offset: onda + .06, easing: 'ease-in' },
|
|
577
|
+
{ transform: T(0, 4, 0, 1.12, .86), opacity: 1, offset: onda + .11, easing: 'ease-out' },
|
|
578
|
+
{ transform: T(), opacity: 1, offset: onda + .15 },
|
|
579
|
+
];
|
|
580
|
+
if (i === 4) kf.push({ transform: T(0, 0, 0, 1), opacity: 1, offset: .74, easing: OVER }, { transform: T(0, -10, 360, 1.2), opacity: 1, offset: .82 }, { transform: T(0, 0, 360, 1), opacity: 1, offset: .86 });
|
|
581
|
+
else kf.push({ transform: T(), opacity: 1, offset: .86 });
|
|
582
|
+
const r0 = i === 4 ? 360 : 0;
|
|
583
|
+
kf.push({ transform: T(0, 0, r0, 1), opacity: 1, offset: .88 + i * .01, easing: 'ease-in' },
|
|
584
|
+
{ transform: T((i - 2) * 34, -150, r0 + (i - 2) * 40, .6), opacity: 0, offset: .96 + i * .008 },
|
|
585
|
+
{ transform: T((i - 2) * 34, -150, r0 + (i - 2) * 40, .6), opacity: 0 });
|
|
586
|
+
A.push(loop(s, kf, { duration: D }));
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/* O anti-exemplo do passo 3: colado na borda, tremendo, coisa demais na tela. */
|
|
591
|
+
function cenaNao(m, A) {
|
|
592
|
+
const p = palavra(m, 'left:8px;top:8px;font-size:34px');
|
|
593
|
+
const c = peca(m, `left:236px;top:118px;width:110px;height:72px;border-radius:12px;border:2.5px solid ${TINTA}`);
|
|
594
|
+
const b = peca(m, `left:150px;top:120px;width:24px;height:24px;border-radius:50%;background:${TINTA}`);
|
|
595
|
+
[[40, 150], [120, 40], [200, 72], [262, 40], [92, 108]].forEach(([x, y], i) => {
|
|
596
|
+
const q = peca(m, `left:${x}px;top:${y}px;width:${8 + i * 3}px;height:${8 + i * 3}px;border-radius:${i % 2 ? '50%' : '2px'};border:2px solid ${TINTA};opacity:.6`);
|
|
597
|
+
A.push(loop(q, [{ transform: T(0, 0, 0) }, { transform: T(i * 3 - 6, 5 - i * 2, 90 * (i + 1)) }], { duration: 400 + i * 90, direction: 'alternate' }));
|
|
598
|
+
});
|
|
599
|
+
peca(m, 'right:10px;top:10px;width:26px;height:26px;border-radius:50%;display:grid;place-items:center;background:var(--vermelho);color:#fff;font:700 14px/1 var(--f-display)', '✕');
|
|
600
|
+
A.push(loop(p, [{ transform: T(0, 0) }, { transform: T(3, -2, 1) }, { transform: T(-3, 2, -1) }, { transform: T(2, 3) }, { transform: T(0, 0) }], { duration: 180 }));
|
|
601
|
+
A.push(loop(c, [{ transform: T(0, 0, -6) }, { transform: T(0, 0, 8, 1.15) }, { transform: T(0, 0, -6) }], { duration: 500 }));
|
|
602
|
+
A.push(loop(b, [{ transform: T(-60, 0) }, { transform: T(60, -30) }, { transform: T(-40, 20) }, { transform: T(-60, 0) }], { duration: 700 }));
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/* ── mais 14 motions ─────────────────────────────────────────────────────
|
|
606
|
+
Mesmo mundo de 320×200; ACENTO é o azul da tela, pra cada cena ter duas cores. */
|
|
607
|
+
const ACENTO = 'var(--ambar)';
|
|
608
|
+
const sempre = (o) => [{ ...o }, { ...o }];
|
|
609
|
+
|
|
610
|
+
/* Órbita: três anéis inclinados giram em volta da palavra, cada um com sua lua. */
|
|
611
|
+
function cenaOrbita(m, A) {
|
|
612
|
+
const D = 3600;
|
|
613
|
+
[[68, 0, ACENTO], [68, 60, TINTA], [68, -60, ACENTO]].forEach(([rx, rz, c], i) => {
|
|
614
|
+
const anel = peca(m, `left:65px;top:5px;width:190px;height:190px;border-radius:50%;border:1.5px solid color-mix(in srgb, ${c} 40%, transparent);transform-style:preserve-3d;transform:rotateZ(${rz}deg) rotateX(${rx}deg)`);
|
|
615
|
+
const lua = peca(anel, `left:88px;top:-7px;width:13px;height:13px;border-radius:50%;background:${c};box-shadow:0 0 14px ${c}`);
|
|
616
|
+
A.push(loop(anel, [{ transform: `rotateZ(${rz}deg) rotateX(${rx}deg) rotateZ(0deg)` }, { transform: `rotateZ(${rz}deg) rotateX(${rx}deg) rotateZ(360deg)` }], { duration: 2200 + i * 650, easing: 'linear' }));
|
|
617
|
+
A.push(loop(lua, [{ transform: 'scale(1)' }, { transform: 'scale(1.5)' }], { duration: 900 + i * 200, direction: 'alternate', easing: LISO }));
|
|
618
|
+
});
|
|
619
|
+
const p = palavra(m, 'left:0;right:0;top:80px;text-align:center;font-size:40px');
|
|
620
|
+
A.push(loop(p, [{ transform: 'scale(.5)', opacity: 0, filter: 'blur(6px)' }, { transform: 'scale(1.1)', opacity: 1, filter: 'blur(0px)', offset: .18, easing: OVER },
|
|
621
|
+
{ transform: 'scale(1)', opacity: 1, filter: 'blur(0px)', offset: .26 }, { transform: 'scale(1)', opacity: 1, filter: 'blur(0px)', offset: .88, easing: 'ease-in' },
|
|
622
|
+
{ transform: 'scale(.5)', opacity: 0, filter: 'blur(6px)' }], { duration: D }));
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/* Gota: uma gota azul cai, abre três ondas na água e a palavra sobe de dentro delas. */
|
|
626
|
+
function cenaGota(m, A) {
|
|
627
|
+
const D = 3000;
|
|
628
|
+
const g = peca(m, `left:153px;top:-24px;width:14px;height:19px;border-radius:50% 50% 50% 50%/60% 60% 40% 40%;background:${ACENTO}`);
|
|
629
|
+
A.push(loop(g, [{ transform: T(0, 0), opacity: 1, easing: CAI }, { transform: T(0, 142, 0, .8, 1.3), opacity: 1, offset: .22 },
|
|
630
|
+
{ transform: T(0, 142, 0, 2.2, 0), opacity: 0, offset: .25 }, { transform: T(0, 0), opacity: 0 }], { duration: D }));
|
|
631
|
+
for (let i = 0; i < 3; i++) {
|
|
632
|
+
const r = peca(m, `left:110px;top:128px;width:100px;height:26px;border-radius:50%;border:2px solid ${ACENTO}`);
|
|
633
|
+
const t = .24 + i * .06;
|
|
634
|
+
A.push(loop(r, [{ transform: 'scale(0)', opacity: 0 }, { transform: 'scale(0)', opacity: 0, offset: t },
|
|
635
|
+
{ transform: 'scale(.3)', opacity: 1, offset: t + .01, easing: 'cubic-bezier(.1,.7,.3,1)' }, { transform: 'scale(2.8)', opacity: 0, offset: t + .42 },
|
|
636
|
+
{ transform: 'scale(2.8)', opacity: 0 }], { duration: D }));
|
|
637
|
+
}
|
|
638
|
+
const p = palavra(m, 'left:0;right:0;top:66px;text-align:center;font-size:54px;transform-origin:50% 100%');
|
|
639
|
+
A.push(loop(p, [{ transform: 'translateY(46px) scaleY(.1)', opacity: 0, filter: 'blur(6px)' },
|
|
640
|
+
{ transform: 'translateY(46px) scaleY(.1)', opacity: 0, filter: 'blur(6px)', offset: .27, easing: OVER },
|
|
641
|
+
{ transform: 'translateY(0) scaleY(1)', opacity: 1, filter: 'blur(0px)', offset: .46 },
|
|
642
|
+
{ transform: 'translateY(0) scaleY(1)', opacity: 1, filter: 'blur(0px)', offset: .86, easing: 'ease-in' },
|
|
643
|
+
{ transform: 'translateY(30px) scaleY(.3)', opacity: 0, filter: 'blur(4px)' }], { duration: D }));
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/* Glitch: a palavra treme, se parte em fatias coloridas e um raio de varredura corta a tela. */
|
|
647
|
+
function cenaGlitch(m, A) {
|
|
648
|
+
const D = 2200, base = 'left:0;right:0;top:62px;text-align:center;font-size:66px;font-weight:900;';
|
|
649
|
+
const c1 = palavra(m, base + `color:${ACENTO};opacity:.9`), c2 = palavra(m, base + 'color:var(--vermelho);opacity:.8'), p = palavra(m, base);
|
|
650
|
+
const pulo = (dx) => [
|
|
651
|
+
{ transform: T(0, 0), clipPath: 'inset(0 0 100% 0)' }, { transform: T(0, 0), clipPath: 'inset(0 0 100% 0)', offset: .08 },
|
|
652
|
+
{ transform: T(dx, 0), clipPath: 'inset(10% 0 55% 0)', offset: .1 }, { transform: T(-dx, 2), clipPath: 'inset(52% 0 18% 0)', offset: .14 },
|
|
653
|
+
{ transform: T(dx / 2, 0), clipPath: 'inset(30% 0 40% 0)', offset: .17 }, { transform: T(0, 0), clipPath: 'inset(0 0 100% 0)', offset: .19 },
|
|
654
|
+
{ transform: T(0, 0), clipPath: 'inset(0 0 100% 0)', offset: .56 }, { transform: T(dx * 1.6, -2), clipPath: 'inset(28% 0 42% 0)', offset: .58 },
|
|
655
|
+
{ transform: T(-dx, 1), clipPath: 'inset(68% 0 6% 0)', offset: .62 }, { transform: T(0, 0), clipPath: 'inset(0 0 100% 0)', offset: .65 },
|
|
656
|
+
{ transform: T(0, 0), clipPath: 'inset(0 0 100% 0)' }];
|
|
657
|
+
A.push(loop(c1, pulo(-10), { duration: D }));
|
|
658
|
+
A.push(loop(c2, pulo(10), { duration: D }));
|
|
659
|
+
A.push(loop(p, [{ transform: T(0, 0), opacity: 1 }, { transform: T(0, 0), opacity: 1, offset: .09 }, { transform: T(4, 0, 0, 1.05, .9), opacity: .5, offset: .12 },
|
|
660
|
+
{ transform: T(-2, 0), opacity: 1, offset: .17 }, { transform: T(0, 0), opacity: 1, offset: .57 }, { transform: T(-5, 0, 0, 1.08, .92), opacity: .4, offset: .6 },
|
|
661
|
+
{ transform: T(0, 0), opacity: 1, offset: .65 }, { transform: T(0, 0), opacity: 1 }], { duration: D }));
|
|
662
|
+
[[48, 5], [96, 3], [132, 8]].forEach(([y, h], i) => {
|
|
663
|
+
const b = peca(m, `left:0;top:${y}px;width:320px;height:${h}px;background:${i === 1 ? 'var(--vermelho)' : ACENTO}`);
|
|
664
|
+
const t = .1 + i * .015, t2 = .58 + i * .015;
|
|
665
|
+
A.push(loop(b, [{ transform: 'translateX(-60px) scaleX(.3)', opacity: 0 }, { transform: 'translateX(-60px) scaleX(.3)', opacity: 0, offset: t },
|
|
666
|
+
{ transform: 'translateX(0) scaleX(1)', opacity: .75, offset: t + .015 }, { transform: 'translateX(60px) scaleX(.3)', opacity: 0, offset: t + .04 },
|
|
667
|
+
{ transform: 'translateX(60px) scaleX(.3)', opacity: 0, offset: t2 }, { transform: 'translateX(0) scaleX(1)', opacity: .75, offset: t2 + .015 },
|
|
668
|
+
{ transform: 'translateX(-60px) scaleX(.3)', opacity: 0, offset: t2 + .04 }, { transform: 'translateX(-60px) scaleX(.3)', opacity: 0 }], { duration: D }));
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/* Contador: três rolos de número giram até 100%, a barra enche junto e o número dá um soco no fim. */
|
|
673
|
+
function cenaContador(m, A) {
|
|
674
|
+
const D = 3200, h = 64;
|
|
675
|
+
const caixa = peca(m, `left:0;right:0;top:46px;height:${h}px;display:flex;justify-content:center;align-items:center;gap:1px`);
|
|
676
|
+
[1, 10, 10].forEach((alvo, i) => {
|
|
677
|
+
const jan = el('div', { style: `height:${h}px;overflow:hidden` });
|
|
678
|
+
const fita = el('div', { style: `display:flex;flex-direction:column;font:900 58px/${h}px var(--f-display);letter-spacing:-.04em;color:${TINTA};font-variant-numeric:tabular-nums` }, '01234567890'.split('').map((d) => el('span', { text: d })));
|
|
679
|
+
jan.appendChild(fita); caixa.appendChild(jan);
|
|
680
|
+
A.push(loop(fita, [{ transform: 'translateY(0)' }, { transform: 'translateY(0)', offset: .06, easing: 'cubic-bezier(.6,0,.2,1)' },
|
|
681
|
+
{ transform: `translateY(${-alvo * h}px)`, offset: .5 + i * .05 }, { transform: `translateY(${-alvo * h}px)`, offset: .9, easing: 'ease-in' },
|
|
682
|
+
{ transform: 'translateY(0)' }], { duration: D }));
|
|
683
|
+
});
|
|
684
|
+
caixa.appendChild(el('div', { text: '%', style: `font:800 32px/1 var(--f-display);color:${ACENTO};margin-left:4px` }));
|
|
685
|
+
const trilho = peca(m, `left:70px;top:134px;width:180px;height:6px;border-radius:3px;background:${VEU}`);
|
|
686
|
+
const cheio = peca(trilho, `left:0;top:0;width:180px;height:6px;border-radius:3px;background:${ACENTO};transform-origin:left`);
|
|
687
|
+
A.push(loop(cheio, [{ transform: 'scaleX(0)' }, { transform: 'scaleX(0)', offset: .06, easing: 'cubic-bezier(.6,0,.2,1)' }, { transform: 'scaleX(1)', offset: .6 },
|
|
688
|
+
{ transform: 'scaleX(1)', offset: .9, easing: 'ease-in' }, { transform: 'scaleX(0)' }], { duration: D }));
|
|
689
|
+
A.push(loop(caixa, [{ transform: 'scale(1)' }, { transform: 'scale(1)', offset: .6, easing: 'ease-out' }, { transform: 'scale(1.18)', offset: .64, easing: OVER },
|
|
690
|
+
{ transform: 'scale(1)', offset: .74 }, { transform: 'scale(1)' }], { duration: D }));
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/* Cubo: um cubo 3D com uma letra por face gira de quadro em quadro e dá uma cambalhota no fim. */
|
|
694
|
+
function cenaCubo(m, A) {
|
|
695
|
+
const s = 92, D = 4800;
|
|
696
|
+
const chao = peca(m, `left:110px;top:160px;width:100px;height:18px;border-radius:50%;background:radial-gradient(closest-side, color-mix(in srgb, var(--cor) 26%, transparent), transparent)`);
|
|
697
|
+
const cubo = peca(m, `left:114px;top:44px;width:${s}px;height:${s}px;transform-style:preserve-3d`);
|
|
698
|
+
[['rotateY(0deg)', 'P'], ['rotateY(90deg)', 'R'], ['rotateY(180deg)', 'I'], ['rotateY(-90deg)', 'M'], ['rotateX(90deg)', 'O'], ['rotateX(-90deg)', '✦']].forEach(([r, t], i) => {
|
|
699
|
+
const azul = i % 2 === 1;
|
|
700
|
+
peca(cubo, `left:0;top:0;width:${s}px;height:${s}px;box-sizing:border-box;border-radius:14px;border:2px solid ${azul ? ACENTO : TINTA};background:${azul ? ACENTO : 'var(--palco)'};color:${azul ? 'var(--sobre)' : TINTA};display:grid;place-items:center;font:900 46px/1 var(--f-display);transform:${r} translateZ(${s / 2}px);backface-visibility:hidden`, t);
|
|
701
|
+
});
|
|
702
|
+
const k = (y, x = -22) => `rotateX(${x}deg) rotateY(${y}deg)`;
|
|
703
|
+
A.push(loop(cubo, [{ transform: k(0), easing: OVER }, { transform: k(-90), offset: .18 }, { transform: k(-90), offset: .24, easing: OVER },
|
|
704
|
+
{ transform: k(-180), offset: .42 }, { transform: k(-180), offset: .48, easing: OVER }, { transform: k(-270), offset: .66 },
|
|
705
|
+
{ transform: k(-270), offset: .72, easing: 'cubic-bezier(.6,0,.3,1)' }, { transform: k(-360, 338), offset: .94 }, { transform: k(-360, 338) }], { duration: D }));
|
|
706
|
+
A.push(loop(chao, [{ transform: 'scale(1)' }, { transform: 'scale(1)', offset: .72 }, { transform: 'scale(.6)', offset: .83 }, { transform: 'scale(1)', offset: .94 }, { transform: 'scale(1)' }], { duration: D }));
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/* Corte ao meio: as duas metades da palavra entram por lados opostos, se abrem e mostram a linha do meio. */
|
|
710
|
+
function cenaSplit(m, A) {
|
|
711
|
+
const D = 3000, base = 'left:0;right:0;top:56px;text-align:center;font-size:80px;font-weight:900;letter-spacing:-.05em;';
|
|
712
|
+
const cima = palavra(m, base + 'clip-path:inset(0 0 50% 0)'), baixo = palavra(m, base + 'clip-path:inset(50% 0 0 0)');
|
|
713
|
+
const meio = palavra(m, `left:0;right:0;top:91px;text-align:center;font-family:var(--f-mono);font-size:12px;font-weight:700;letter-spacing:.6em;color:${ACENTO}`, 'MOTION · 2026');
|
|
714
|
+
const lado = (sx, dy) => [{ transform: T(sx * 340, 0) }, { transform: T(0, 0), offset: .16, easing: MD3 }, { transform: T(0, 0), offset: .26, easing: OVER },
|
|
715
|
+
{ transform: T(0, dy), offset: .38 }, { transform: T(0, dy), offset: .76, easing: MD3 }, { transform: T(0, 0), offset: .84, easing: CHICOTE }, { transform: T(-sx * 340, 0) }];
|
|
716
|
+
lado.bind(null);
|
|
717
|
+
A.push(loop(cima, [{ ...lado(-1, -18)[0], easing: CHICOTE }, ...lado(-1, -18).slice(1)], { duration: D }));
|
|
718
|
+
A.push(loop(baixo, [{ ...lado(1, 18)[0], easing: CHICOTE }, ...lado(1, 18).slice(1)], { duration: D }));
|
|
719
|
+
A.push(loop(meio, [{ transform: 'scaleX(0)', opacity: 0 }, { transform: 'scaleX(0)', opacity: 0, offset: .3, easing: MD3 }, { transform: 'scaleX(1)', opacity: 1, offset: .46 },
|
|
720
|
+
{ transform: 'scaleX(1)', opacity: 1, offset: .74, easing: MD3 }, { transform: 'scaleX(0)', opacity: 0, offset: .82 }, { transform: 'scaleX(0)', opacity: 0 }], { duration: D }));
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/* Mosaico: 40 azulejos viram em onda na diagonal, mostram a palavra e viram de novo pra ir embora. */
|
|
724
|
+
function cenaMosaico(m, A) {
|
|
725
|
+
const D = 3400, cols = 8, rows = 5, w = 30, x0 = 40, y0 = 25;
|
|
726
|
+
for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) {
|
|
727
|
+
const q = peca(m, `left:${x0 + c * w}px;top:${y0 + r * w}px;width:${w - 3}px;height:${w - 3}px;border-radius:6px;background:${(r + c) % 5 ? ACENTO : TINTA}`);
|
|
728
|
+
const d = (r + c) * .025;
|
|
729
|
+
A.push(loop(q, [{ transform: 'rotateY(90deg) scale(.4)', opacity: 0 }, { transform: 'rotateY(90deg) scale(.4)', opacity: 0, offset: .04 + d, easing: OVER },
|
|
730
|
+
{ transform: 'rotateY(0deg) scale(1)', opacity: 1, offset: .14 + d }, { transform: 'rotateY(0deg) scale(1)', opacity: 1, offset: .5 + d, easing: 'ease-in' },
|
|
731
|
+
{ transform: 'rotateY(-90deg) scale(.4)', opacity: 0, offset: .6 + d }, { transform: 'rotateY(-90deg) scale(.4)', opacity: 0 }], { duration: D }));
|
|
732
|
+
}
|
|
733
|
+
const claro = palavra(m, 'left:0;right:0;top:72px;text-align:center;font-size:56px;color:var(--sobre)');
|
|
734
|
+
const escuro = palavra(m, 'left:0;right:0;top:72px;text-align:center;font-size:56px');
|
|
735
|
+
A.push(loop(claro, [{ opacity: 0, transform: 'scale(.8)' }, { opacity: 0, transform: 'scale(.8)', offset: .3, easing: OVER }, { opacity: 1, transform: 'scale(1)', offset: .4 },
|
|
736
|
+
{ opacity: 1, transform: 'scale(1)', offset: .58 }, { opacity: 0, transform: 'scale(1)', offset: .7 }, { opacity: 0, transform: 'scale(1)' }], { duration: D }));
|
|
737
|
+
A.push(loop(escuro, [{ opacity: 0, transform: 'scale(1)' }, { opacity: 0, transform: 'scale(1)', offset: .58 }, { opacity: 1, transform: 'scale(1)', offset: .7 },
|
|
738
|
+
{ opacity: 1, transform: 'scale(1)', offset: .88, easing: 'ease-in' }, { opacity: 0, transform: 'scale(1.3)' }], { duration: D }));
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/* Espiral: dezesseis pontos giram em espiral até o centro e explodem na palavra. */
|
|
742
|
+
function cenaEspiral(m, A) {
|
|
743
|
+
const D = 3200;
|
|
744
|
+
for (let i = 0; i < 16; i++) {
|
|
745
|
+
const a = i * 22.5, d = peca(m, `left:156px;top:96px;width:8px;height:8px;border-radius:50%;background:${i % 2 ? ACENTO : TINTA}`);
|
|
746
|
+
A.push(loop(d, [{ transform: `rotate(${a}deg) translateX(150px) scale(1)`, opacity: 0 },
|
|
747
|
+
{ transform: `rotate(${a}deg) translateX(150px) scale(1)`, opacity: 1, offset: .05, easing: 'cubic-bezier(.5,0,.8,.2)' },
|
|
748
|
+
{ transform: `rotate(${a + 540}deg) translateX(0px) scale(.4)`, opacity: 1, offset: .4 },
|
|
749
|
+
{ transform: `rotate(${a + 540}deg) translateX(0px) scale(0)`, opacity: 0, offset: .42 }, { transform: `rotate(${a + 540}deg) translateX(0px) scale(0)`, opacity: 0 }], { duration: D }));
|
|
750
|
+
}
|
|
751
|
+
const anel = peca(m, `left:130px;top:70px;width:60px;height:60px;border-radius:50%;border:3px solid ${ACENTO}`);
|
|
752
|
+
A.push(loop(anel, [{ transform: 'scale(0)', opacity: 0 }, { transform: 'scale(0)', opacity: 0, offset: .4 }, { transform: 'scale(.5)', opacity: 1, offset: .41, easing: 'cubic-bezier(.1,.8,.3,1)' },
|
|
753
|
+
{ transform: 'scale(4)', opacity: 0, offset: .62 }, { transform: 'scale(4)', opacity: 0 }], { duration: D }));
|
|
754
|
+
const p = palavra(m, 'left:0;right:0;top:76px;text-align:center;font-size:50px;font-weight:900');
|
|
755
|
+
A.push(loop(p, [{ transform: T(0, 0, -90, 0) }, { transform: T(0, 0, -90, 0), offset: .4, easing: OVER }, { transform: T(0, 0, 6, 1.25), offset: .5 },
|
|
756
|
+
{ transform: T(0, 0, 0, 1), offset: .58 }, { transform: T(0, 0, 0, 1), offset: .86, easing: 'cubic-bezier(.6,0,1,.5)' }, { transform: T(0, 0, 200, 0) }], { duration: D }));
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/* Caça-níquel: cada letra roda como num rolo de cassino, borrando, e trava uma de cada vez. */
|
|
760
|
+
function cenaSlot(m, A) {
|
|
761
|
+
const D = 3400, h = 70, mix = 'KZAXQVTEWYUBGH';
|
|
762
|
+
const caixa = peca(m, `left:0;right:0;top:56px;height:${h}px;display:flex;justify-content:center;gap:5px`);
|
|
763
|
+
'PRIMO'.split('').forEach((ch, i) => {
|
|
764
|
+
const seq = mix.slice(i, i + 7).split('').concat(ch), fim = -(seq.length - 1) * h;
|
|
765
|
+
const jan = el('div', { style: `height:${h}px;width:48px;overflow:hidden;border-radius:12px;background:${VEU}` });
|
|
766
|
+
const fita = el('div', { style: `display:flex;flex-direction:column;align-items:center;font:900 54px/${h}px var(--f-display);color:${TINTA}` }, seq.map((c) => el('span', { text: c })));
|
|
767
|
+
jan.appendChild(fita); caixa.appendChild(jan);
|
|
768
|
+
A.push(loop(fita, [{ transform: 'translateY(0)', filter: 'blur(0px)' }, { transform: 'translateY(0)', filter: 'blur(0px)', offset: .04, easing: 'ease-in' },
|
|
769
|
+
{ transform: `translateY(${fim * .6}px)`, filter: 'blur(4px)', offset: .2 + i * .05 }, { transform: `translateY(${fim - 16}px)`, filter: 'blur(0px)', offset: .3 + i * .07, easing: 'ease-out' },
|
|
770
|
+
{ transform: `translateY(${fim}px)`, filter: 'blur(0px)', offset: .36 + i * .07 }, { transform: `translateY(${fim}px)`, filter: 'blur(0px)', offset: .92 },
|
|
771
|
+
{ transform: 'translateY(0)', filter: 'blur(3px)' }], { duration: D }));
|
|
772
|
+
A.push(loop(jan, [{ boxShadow: '0 0 0 0 transparent' }, { boxShadow: '0 0 0 0 transparent', offset: .35 + i * .07 },
|
|
773
|
+
{ boxShadow: `0 0 0 3px ${ACENTO}`, offset: .37 + i * .07 }, { boxShadow: '0 0 0 0 transparent', offset: .5 + i * .07 }, { boxShadow: '0 0 0 0 transparent' }], { duration: D }));
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/* Túnel: quadrados saem do centro girando sem parar, e a palavra pulsa no meio como batida. */
|
|
778
|
+
function cenaTunel(m, A) {
|
|
779
|
+
for (let i = 0; i < 6; i++) {
|
|
780
|
+
const q = peca(m, `left:110px;top:50px;width:100px;height:100px;border-radius:16px;border:2.5px solid ${i % 2 ? ACENTO : TINTA}`);
|
|
781
|
+
A.push(loop(q, [{ transform: 'scale(0) rotate(0deg)', opacity: 0 }, { transform: 'scale(.7) rotate(40deg)', opacity: 1, offset: .3 }, { transform: 'scale(4.2) rotate(130deg)', opacity: 0 }],
|
|
782
|
+
{ duration: 2400, delay: -i * 400, easing: 'cubic-bezier(.5,0,.9,.5)' }));
|
|
783
|
+
}
|
|
784
|
+
const fundo = peca(m, `left:122px;top:80px;width:76px;height:40px;border-radius:10px;background:var(--palco)`);
|
|
785
|
+
const p = palavra(m, 'left:0;right:0;top:82px;text-align:center;font-size:36px;font-weight:900');
|
|
786
|
+
[fundo, p].forEach((e) => A.push(loop(e, [{ transform: 'scale(1)', easing: 'ease-out' }, { transform: 'scale(1.16)', offset: .12, easing: 'ease-in-out' }, { transform: 'scale(1)', offset: .5 }, { transform: 'scale(1)' }], { duration: 800 })));
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/* Equalizador: dezoito barras dançam em ritmos diferentes e a palavra quica na batida. */
|
|
790
|
+
function cenaEqualizador(m, A) {
|
|
791
|
+
for (let i = 0; i < 18; i++) {
|
|
792
|
+
const b = peca(m, `left:${35 + i * 14}px;top:76px;width:9px;height:104px;border-radius:5px;background:${i % 3 ? TINTA : ACENTO};transform-origin:bottom`);
|
|
793
|
+
const hs = [.2, .9, .4, 1, .3].map((v, k) => ((v + i * .37 + k * .21) % 1) * .85 + .15);
|
|
794
|
+
A.push(loop(b, [...hs, hs[0]].map((v) => ({ transform: `scaleY(${v})` })), { duration: 900 + (i % 4) * 140, easing: 'ease-in-out' }));
|
|
795
|
+
}
|
|
796
|
+
const p = palavra(m, 'left:0;right:0;top:18px;text-align:center;font-size:42px;font-weight:900');
|
|
797
|
+
A.push(loop(p, [{ transform: T(0, 0, 0, 1), easing: 'ease-out' }, { transform: T(0, -8, -3, 1.08), offset: .2, easing: 'ease-in' }, { transform: T(0, 0, 0, 1), offset: .5 },
|
|
798
|
+
{ transform: T(0, -8, 3, 1.08), offset: .7, easing: 'ease-in' }, { transform: T(0, 0, 0, 1) }], { duration: 900 }));
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
/* Cartas: um baralho cai na mesa, abre em leque, junta de novo e a palavra aparece embaixo. */
|
|
802
|
+
function cenaCartas(m, A) {
|
|
803
|
+
const D = 3600;
|
|
804
|
+
for (let i = 0; i < 5; i++) {
|
|
805
|
+
const topo = i === 4, ang = (i - 2) * 16;
|
|
806
|
+
const c = peca(m, `left:125px;top:22px;width:70px;height:100px;box-sizing:border-box;border-radius:11px;border:2px solid ${topo ? ACENTO : TINTA};background:${topo ? ACENTO : 'var(--palco)'};transform-origin:50% 140%;display:grid;place-items:center;font:900 30px/1 var(--f-display);color:var(--sobre)`, topo ? '✦' : '');
|
|
807
|
+
A.push(loop(c, [{ transform: T(0, -150, -20, 1), opacity: 0 }, { transform: T(0, -150, -20, 1), opacity: 0, offset: i * .02, easing: OVER },
|
|
808
|
+
{ transform: T(0, 0, 0, 1), opacity: 1, offset: .12 + i * .02 }, { transform: T(0, 0, 0, 1), opacity: 1, offset: .2, easing: OVER },
|
|
809
|
+
{ transform: T((i - 2) * 24, Math.abs(i - 2) * 5, ang, 1), opacity: 1, offset: .36 }, { transform: T((i - 2) * 24, Math.abs(i - 2) * 5, ang, 1), opacity: 1, offset: .6, easing: CHICOTE },
|
|
810
|
+
{ transform: T(0, 0, 0, 1), opacity: 1, offset: .7 }, { transform: T(0, 0, 0, 1), opacity: 1, offset: .88 + i * .015, easing: 'ease-in' },
|
|
811
|
+
{ transform: T(0, -170, 30, 1), opacity: 0, offset: .97 + i * .005 }, { transform: T(0, -170, 30, 1), opacity: 0 }], { duration: D }));
|
|
812
|
+
}
|
|
813
|
+
const p = palavra(m, 'left:0;right:0;top:146px;text-align:center;font-size:30px');
|
|
814
|
+
A.push(loop(p, [{ opacity: 0, transform: 'translateY(14px)' }, { opacity: 0, transform: 'translateY(14px)', offset: .68, easing: MD3 }, { opacity: 1, transform: 'translateY(0)', offset: .78 },
|
|
815
|
+
{ opacity: 1, transform: 'translateY(0)', offset: .9 }, { opacity: 0, transform: 'translateY(0)' }], { duration: D }));
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/* Traço: uma linha azul se desenha pela tela com uma bolinha na ponta, e a palavra se revela atrás dela. */
|
|
819
|
+
function cenaTraco(m, A) {
|
|
820
|
+
const D = 3400, d = 'M18 150 C 70 10, 130 10, 160 100 S 250 190, 302 40';
|
|
821
|
+
const NS = ['http:', '', 'www.w3.org', '2000', 'svg'].join('/'), svg = document.createElementNS(NS, 'svg');
|
|
822
|
+
svg.setAttribute('viewBox', '0 0 320 200');
|
|
823
|
+
svg.style.cssText = 'position:absolute;left:0;top:0;width:320px;height:200px;overflow:visible';
|
|
824
|
+
const linha = (w, c, op) => { const p = document.createElementNS(NS, 'path'); Object.entries({ d, fill: 'none', stroke: c, 'stroke-width': w, 'stroke-linecap': 'round', pathLength: 100, 'stroke-dasharray': 100, 'stroke-dashoffset': 100, opacity: op }).forEach(([k, v]) => p.setAttribute(k, v)); svg.appendChild(p); return p; };
|
|
825
|
+
const fina = linha(2, 'var(--cor)', .25), grossa = linha(7, 'var(--ambar)', 1);
|
|
826
|
+
m.appendChild(svg);
|
|
827
|
+
const desenha = (atraso) => [{ strokeDashoffset: 100 }, { strokeDashoffset: 100, offset: atraso, easing: 'cubic-bezier(.6,0,.3,1)' }, { strokeDashoffset: 0, offset: atraso + .4 },
|
|
828
|
+
{ strokeDashoffset: 0, offset: .82, easing: 'cubic-bezier(.6,0,.3,1)' }, { strokeDashoffset: -100, offset: .98 }, { strokeDashoffset: -100 }];
|
|
829
|
+
A.push(loop(grossa, desenha(.04), { duration: D }));
|
|
830
|
+
A.push(loop(fina, desenha(.1), { duration: D }));
|
|
831
|
+
const ponta = peca(m, `left:-8px;top:-8px;width:16px;height:16px;border-radius:50%;background:var(--palco);border:3px solid ${ACENTO};box-sizing:border-box;offset-path:path('${d}');offset-rotate:0deg`);
|
|
832
|
+
A.push(loop(ponta, [{ offsetDistance: '0%', opacity: 0 }, { offsetDistance: '0%', opacity: 1, offset: .04, easing: 'cubic-bezier(.6,0,.3,1)' }, { offsetDistance: '100%', opacity: 1, offset: .44 },
|
|
833
|
+
{ offsetDistance: '100%', opacity: 0, offset: .5 }, { offsetDistance: '100%', opacity: 0 }], { duration: D }));
|
|
834
|
+
const p = palavra(m, 'left:0;right:0;top:78px;text-align:center;font-family:var(--f-serifa);font-style:italic;font-weight:400;font-size:58px;letter-spacing:-.01em', 'Primo');
|
|
835
|
+
A.push(loop(p, [{ clipPath: 'inset(0 100% 0 0)' }, { clipPath: 'inset(0 100% 0 0)', offset: .14, easing: 'cubic-bezier(.6,0,.3,1)' }, { clipPath: 'inset(0 0% 0 0)', offset: .46 },
|
|
836
|
+
{ clipPath: 'inset(0 0% 0 0)', offset: .84, easing: MD3 }, { clipPath: 'inset(0 0 0 100%)', offset: .96 }, { clipPath: 'inset(0 0 0 100%)' }], { duration: D }));
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/* Estilhaço: um impacto quebra a palavra, as letras e os cacos voam e tudo se junta de volta no lugar. */
|
|
840
|
+
function cenaEstilhaco(m, A) {
|
|
841
|
+
const D = 3200, dx = [-130, -60, 10, 80, 140], dy = [-80, 70, -95, 85, -60], rr = [-220, 170, -130, 250, -190];
|
|
842
|
+
letras(m, 'left:0;right:0;top:64px;justify-content:center;font-size:66px;font-weight:900').forEach((s, i) => {
|
|
843
|
+
A.push(loop(s, [{ transform: T(), opacity: 1 }, { transform: T(), opacity: 1, offset: .26 }, { transform: T(-3, 2), opacity: 1, offset: .28 },
|
|
844
|
+
{ transform: T(dx[i], dy[i], rr[i], .5), opacity: 0, offset: .46, easing: 'cubic-bezier(.1,.8,.3,1)' }, { transform: T(dx[i], dy[i], rr[i], .5), opacity: 0, offset: .56, easing: OVER },
|
|
845
|
+
{ transform: T(), opacity: 1, offset: .76 + i * .02 }, { transform: T(), opacity: 1 }].map((k, j) => (j === 3 ? { ...k, easing: undefined } : k)).map((k) => { if (k.easing === undefined) delete k.easing; return k; }), { duration: D }));
|
|
846
|
+
});
|
|
847
|
+
const flash = peca(m, `left:110px;top:50px;width:100px;height:100px;border-radius:50%;background:radial-gradient(closest-side, ${ACENTO}, transparent)`);
|
|
848
|
+
A.push(loop(flash, [{ transform: 'scale(0)', opacity: 0 }, { transform: 'scale(0)', opacity: 0, offset: .27 }, { transform: 'scale(1)', opacity: .9, offset: .29 },
|
|
849
|
+
{ transform: 'scale(2.6)', opacity: 0, offset: .42 }, { transform: 'scale(2.6)', opacity: 0 }], { duration: D }));
|
|
850
|
+
for (let i = 0; i < 12; i++) {
|
|
851
|
+
const a = i * 30 + 10, r = 90 + (i % 3) * 30;
|
|
852
|
+
const caco = peca(m, `left:154px;top:94px;width:12px;height:12px;background:${i % 2 ? ACENTO : TINTA};clip-path:polygon(50% 0,100% 100%,0 70%)`);
|
|
853
|
+
A.push(loop(caco, [{ transform: `rotate(${a}deg) translateX(0) rotate(0deg) scale(0)`, opacity: 0 }, { transform: `rotate(${a}deg) translateX(0) rotate(0deg) scale(0)`, opacity: 0, offset: .28 },
|
|
854
|
+
{ transform: `rotate(${a}deg) translateX(10px) rotate(0deg) scale(1)`, opacity: 1, offset: .29, easing: 'cubic-bezier(.1,.8,.3,1)' },
|
|
855
|
+
{ transform: `rotate(${a}deg) translateX(${r}px) rotate(${i * 90}deg) scale(.5)`, opacity: 0, offset: .55 }, { transform: `rotate(${a}deg) translateX(${r}px) rotate(${i * 90}deg) scale(.5)`, opacity: 0 }], { duration: D }));
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
ESTILOS.push(
|
|
860
|
+
{ id: 'cubo', nome: 'Cubo', frase: '', ritmo: 'medio', cameras: ['orbita', 'push'], trocas: ['giro', 'zoom'], tipografias: ['pesada', 'poster'], overshoot: .2 },
|
|
861
|
+
{ id: 'glitch', nome: 'Glitch', frase: '', ritmo: 'rapido', cameras: ['chicote', 'pulso'], trocas: ['tremor', 'corte'], tipografias: ['tecnica', 'pesada'], overshoot: .05 },
|
|
862
|
+
{ id: 'espiral', nome: 'Espiral', frase: '', ritmo: 'rapido', cameras: ['orbita', 'pulso'], trocas: ['zoom', 'encolhe'], tipografias: ['pesada', 'arredondada'], overshoot: .2 },
|
|
863
|
+
{ id: 'slot', nome: 'Caça-níquel', frase: '', ritmo: 'rapido', cameras: ['pulso', 'trilho'], trocas: ['corte', 'persiana'], tipografias: ['pesada', 'poster'], overshoot: .1 },
|
|
864
|
+
{ id: 'tunel', nome: 'Túnel', frase: '', ritmo: 'rapido', cameras: ['push', 'pulso'], trocas: ['zoom', 'giro'], tipografias: ['geometrica', 'poster'], overshoot: .1 },
|
|
865
|
+
{ id: 'mosaico', nome: 'Mosaico', frase: '', ritmo: 'medio', cameras: ['push', 'deriva'], trocas: ['persiana', 'abre'], tipografias: ['geometrica', 'pesada'], overshoot: .15 },
|
|
866
|
+
{ id: 'estilhaco', nome: 'Estilhaço', frase: '', ritmo: 'rapido', cameras: ['chicote', 'pulso'], trocas: ['zoom', 'tremor'], tipografias: ['pesada', 'poster'], overshoot: .22 },
|
|
867
|
+
{ id: 'contador', nome: 'Contador', frase: '', ritmo: 'medio', cameras: ['push', 'trilho'], trocas: ['empurra', 'corte'], tipografias: ['tecnica', 'geometrica'], overshoot: .06 },
|
|
868
|
+
{ id: 'orbita', nome: 'Órbita', frase: '', ritmo: 'medio', cameras: ['orbita', 'cinema'], trocas: ['giro', 'dissolve'], tipografias: ['geometrica'], overshoot: .08 },
|
|
869
|
+
{ id: 'equalizador', nome: 'Equalizador', frase: '', ritmo: 'rapido', cameras: ['pulso', 'chicote'], trocas: ['corte', 'tremor'], tipografias: ['pesada', 'poster'], overshoot: .12 },
|
|
870
|
+
{ id: 'cartas', nome: 'Cartas', frase: '', ritmo: 'medio', cameras: ['cinema', 'deriva'], trocas: ['abre', 'giro'], tipografias: ['editorial', 'arredondada'], overshoot: .18 },
|
|
871
|
+
{ id: 'gota', nome: 'Gota', frase: '', ritmo: 'lento', cameras: ['deriva', 'cinema'], trocas: ['desfoque', 'dissolve'], tipografias: ['serifa_fina', 'editorial'], overshoot: .12 },
|
|
872
|
+
{ id: 'split', nome: 'Corte ao meio', frase: '', ritmo: 'rapido', cameras: ['trilho', 'chicote'], trocas: ['persiana', 'empurra'], tipografias: ['pesada', 'tecnica'], overshoot: .04 },
|
|
873
|
+
{ id: 'traco', nome: 'Traço', frase: '', ritmo: 'medio', cameras: ['trilho', 'deriva'], trocas: ['abre', 'cortina'], tipografias: ['manuscrita', 'editorial'], overshoot: .08 },
|
|
874
|
+
);
|
|
875
|
+
/* a ordem do carrossel: os mais fortes primeiro, alternando energia */
|
|
876
|
+
const ORDEM = ['brincalhao', 'cubo', 'glitch', 'cinetico', 'espiral', 'energico', 'slot', 'cinema3d', 'tunel', 'mosaico', 'premium', 'estilhaco',
|
|
877
|
+
'corporativo', 'contador', 'orbita', 'equalizador', 'cartas', 'gota', 'split', 'traco'];
|
|
878
|
+
const NOVAS_CENAS = { orbita: cenaOrbita, gota: cenaGota, glitch: cenaGlitch, contador: cenaContador, cubo: cenaCubo, split: cenaSplit, mosaico: cenaMosaico,
|
|
879
|
+
espiral: cenaEspiral, slot: cenaSlot, tunel: cenaTunel, equalizador: cenaEqualizador, cartas: cenaCartas, traco: cenaTraco, estilhaco: cenaEstilhaco };
|
|
880
|
+
|
|
881
|
+
/* ── as prévias do catálogo ───────────────────────────────────────────── */
|
|
882
|
+
function quadrosAB(m) {
|
|
883
|
+
const base = 'left:50px;top:35px;width:220px;height:130px;box-sizing:border-box;border-radius:14px;display:grid;place-items:center;font:800 54px/1 var(--f-display);letter-spacing:-.04em;';
|
|
884
|
+
return [peca(m, base + `background:${VEU};color:${TINTA};border:2px solid ${TINTA}`, 'A'), peca(m, base + `background:${TINTA};color:var(--palco)`, 'B')];
|
|
885
|
+
}
|
|
886
|
+
const fixo = (o) => [{ ...o, offset: .3 }, { ...o, offset: .7 }];
|
|
887
|
+
const TRANSICOES_KF = {
|
|
888
|
+
encolhe: [[{ transform: 'scale(1)', offset: .3, easing: 'cubic-bezier(.6,0,.9,.4)' }, { transform: 'scale(0)', offset: .5 }], [{ transform: 'scale(0)', offset: .48, easing: OVER }, { transform: 'scale(1)', offset: .7 }]],
|
|
889
|
+
empurra: [[{ transform: 'translateX(0)', offset: .3, easing: MD3 }, { transform: 'translateX(-300px)', offset: .7 }], [{ transform: 'translateX(300px)', offset: .3, easing: MD3 }, { transform: 'translateX(0)', offset: .7 }]],
|
|
890
|
+
zoom: [[{ transform: 'scale(1)', opacity: 1, offset: .3, easing: 'ease-in' }, { transform: 'scale(3)', opacity: 0, offset: .52 }], [{ transform: 'scale(.3)', opacity: 0, offset: .46, easing: 'ease-out' }, { transform: 'scale(1)', opacity: 1, offset: .7 }]],
|
|
891
|
+
chicote: [[{ transform: 'translateX(0) skewX(0deg)', filter: 'blur(0px)', offset: .3, easing: CHICOTE }, { transform: 'translateX(-340px) skewX(-25deg)', filter: 'blur(6px)', offset: .48 }], [{ transform: 'translateX(340px) skewX(-25deg)', filter: 'blur(6px)', offset: .45, easing: 'cubic-bezier(.1,.8,.2,1)' }, { transform: 'translateX(0) skewX(0deg)', filter: 'blur(0px)', offset: .68 }]],
|
|
892
|
+
desfoque: [[{ filter: 'blur(0px)', opacity: 1, offset: .3, easing: LISO }, { filter: 'blur(16px)', opacity: 0, offset: .58 }], [{ filter: 'blur(16px)', opacity: 0, offset: .42, easing: LISO }, { filter: 'blur(0px)', opacity: 1, offset: .7 }]],
|
|
893
|
+
cortina: [fixo({ transform: 'translateY(0)' }), [{ transform: 'translateY(-230px)', offset: .3, easing: 'cubic-bezier(.3,1.25,.6,1)' }, { transform: 'translateY(0)', offset: .66 }]],
|
|
894
|
+
giro: [[{ transform: 'rotateY(0deg)', offset: .3, easing: 'ease-in' }, { transform: 'rotateY(90deg)', offset: .5 }], [{ transform: 'rotateY(-90deg)', offset: .5, easing: 'ease-out' }, { transform: 'rotateY(0deg)', offset: .7 }]],
|
|
895
|
+
tremor: [[{ transform: 'translate(0,0)', opacity: 1, offset: .3 }, { transform: 'translate(-7px,3px)', opacity: 1, offset: .34 }, { transform: 'translate(7px,-4px)', opacity: 1, offset: .38 }, { transform: 'translate(-6px,-3px)', opacity: 1, offset: .42 }, { transform: 'translate(6px,4px)', opacity: 1, offset: .46 }, { transform: 'translate(0,0)', opacity: 1, offset: .499 }, { transform: 'translate(0,0)', opacity: 0, offset: .5 }], [{ opacity: 0, offset: .499 }, { opacity: 1, offset: .5 }]],
|
|
896
|
+
abre: [fixo({ opacity: 1 }), [{ clipPath: 'inset(0 50% 0 50% round 14px)', offset: .3, easing: MD3 }, { clipPath: 'inset(0 0% 0 0% round 14px)', offset: .68 }]],
|
|
897
|
+
dissolve: [[{ opacity: 1, offset: .3, easing: LISO }, { opacity: 0, offset: .7 }], [{ opacity: 0, offset: .3, easing: LISO }, { opacity: 1, offset: .7 }]],
|
|
898
|
+
corte: [[{ opacity: 1, offset: .499 }, { opacity: 0, offset: .5 }], [{ opacity: 0, offset: .499 }, { opacity: 1, offset: .5 }]],
|
|
899
|
+
};
|
|
900
|
+
const completar = (kfs) => [{ ...kfs[0], offset: 0, easing: 'linear' }, ...kfs, { ...kfs[kfs.length - 1], offset: 1, easing: 'linear' }];
|
|
901
|
+
|
|
902
|
+
function previaTransicao(m, id, A) {
|
|
903
|
+
const [a, b] = quadrosAB(m);
|
|
904
|
+
const o = { duration: 1500, direction: 'alternate' };
|
|
905
|
+
if (id === 'persiana') {
|
|
906
|
+
b.style.background = 'transparent';
|
|
907
|
+
const letra = b.textContent; b.textContent = '';
|
|
908
|
+
for (let i = 0; i < 5; i++) {
|
|
909
|
+
const s = peca(b, `left:${i * 44}px;top:0;width:44.5px;height:130px;background:${TINTA};transform-origin:left;${i === 0 ? 'border-radius:14px 0 0 14px;' : ''}${i === 4 ? 'border-radius:0 14px 14px 0;' : ''}`);
|
|
910
|
+
A.push(loop(s, completar([{ transform: 'scaleX(0)', offset: .3 + i * .05, easing: MD3 }, { transform: 'scaleX(1)', offset: .45 + i * .05 }]), o));
|
|
911
|
+
}
|
|
912
|
+
const l = peca(b, 'left:0;top:0;width:220px;height:130px;display:grid;place-items:center;color:var(--palco)', letra);
|
|
913
|
+
A.push(loop(l, completar([{ opacity: 0, offset: .6 }, { opacity: 1, offset: .7 }]), o));
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
const [ka, kb] = TRANSICOES_KF[id];
|
|
917
|
+
A.push(loop(a, completar(ka), o));
|
|
918
|
+
A.push(loop(b, completar(kb), o));
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
function previaCamera(m, id, A) {
|
|
922
|
+
const cam = peca(m, 'left:0;top:0;width:320px;height:200px;transform-style:preserve-3d');
|
|
923
|
+
const fundo = peca(cam, 'left:-60px;top:-40px;width:440px;height:280px;background-image:radial-gradient(color-mix(in srgb, var(--cor) 24%, transparent) 1.4px, transparent 1.7px);background-size:18px 18px');
|
|
924
|
+
const card = peca(cam, `left:96px;top:40px;width:128px;height:84px;box-sizing:border-box;border-radius:14px;background:${VEU};border:2px solid ${TINTA}`);
|
|
925
|
+
peca(card, `left:14px;top:16px;width:26px;height:26px;box-sizing:border-box;border-radius:50%;border:2.5px solid ${TINTA}`);
|
|
926
|
+
peca(card, `left:50px;top:20px;width:52px;height:6px;border-radius:3px;background:${TINTA}`);
|
|
927
|
+
const p = palavra(cam, 'left:0;right:0;top:138px;text-align:center;font-size:28px');
|
|
928
|
+
if (id === 'orbita') {
|
|
929
|
+
fundo.style.transform = 'translateZ(-80px)'; p.style.transform = 'translateZ(50px)';
|
|
930
|
+
A.push(loop(cam, [{ transform: 'rotateY(-30deg) rotateX(8deg)' }, { transform: 'rotateY(30deg) rotateX(8deg)' }], { duration: 3000, direction: 'alternate', easing: LISO }));
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
const M = {
|
|
934
|
+
deriva: (f) => [[{ transform: `translate(${-14 * f}px,${-6 * f}px)` }, { transform: `translate(${14 * f}px,${6 * f}px)` }], { duration: 3200, direction: 'alternate', easing: LISO }],
|
|
935
|
+
pulso: (f) => [[{ transform: 'scale(1)', easing: 'ease-out' }, { transform: `scale(${1 + .14 * f})`, offset: .08, easing: 'ease-in-out' }, { transform: 'scale(1)', offset: .34 }, { transform: 'scale(1)' }], { duration: 700 }],
|
|
936
|
+
trilho: (f) => [[{ transform: `translateX(${50 * f}px)` }, { transform: `translateX(${-50 * f}px)` }], { duration: 2600, direction: 'alternate', easing: LISO }],
|
|
937
|
+
push: (f) => [[{ transform: 'scale(1)' }, { transform: `scale(${1 + .4 * f})` }], { duration: 2600, direction: 'alternate', easing: LISO }],
|
|
938
|
+
chicote: (f) => [[{ transform: 'translateX(0)', filter: 'blur(0px)' }, { transform: 'translateX(0)', filter: 'blur(0px)', offset: .4, easing: CHICOTE }, { transform: `translateX(${-90 * f}px)`, filter: `blur(${3 * f}px)`, offset: .52 }, { transform: `translateX(${-90 * f}px)`, filter: 'blur(0px)', offset: .58 }, { transform: `translateX(${-90 * f}px)`, filter: 'blur(0px)' }], { duration: 1800, direction: 'alternate' }],
|
|
939
|
+
cinema: (f) => [[{ transform: `translateY(${10 * f}px) scale(${1 + .04 * f}) rotate(-1deg)` }, { transform: `translateY(${-10 * f}px) scale(${1 + .16 * f}) rotate(1deg)` }], { duration: 3800, direction: 'alternate', easing: LISO }],
|
|
940
|
+
};
|
|
941
|
+
[[fundo, .35], [card, .7], [p, 1]].forEach(([e, f]) => { const [kf, o] = M[id](f); A.push(loop(e, kf, o)); });
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
function previaTipografia(m, id, A) {
|
|
945
|
+
const D = 2600, centro = 'left:0;right:0;text-align:center;';
|
|
946
|
+
const sai = (e, extra = {}) => [{ opacity: 1, ...extra, offset: .86, easing: 'ease-in' }, { opacity: 0, ...extra }];
|
|
947
|
+
if (id === 'editorial') {
|
|
948
|
+
const a = palavra(m, 'left:52px;top:76px;font-size:40px;font-weight:600;letter-spacing:-.03em', 'Primo');
|
|
949
|
+
const b = palavra(m, 'left:164px;top:70px;font-size:46px;font-family:var(--f-serifa);font-style:italic;font-weight:400;letter-spacing:-.01em', 'motion');
|
|
950
|
+
[a, b].forEach((e, i) => A.push(loop(e, [
|
|
951
|
+
{ opacity: 0, transform: 'translateY(24px)' }, { opacity: 0, transform: 'translateY(24px)', offset: .08 + i * .12, easing: MD3 },
|
|
952
|
+
{ opacity: 1, transform: 'translateY(0)', offset: .32 + i * .12 }, ...sai(e, { transform: 'translateY(0)' })], { duration: D })));
|
|
953
|
+
} else if (id === 'poster') {
|
|
954
|
+
const e = palavra(m, centro + 'top:50px;font-family:Impact,Haettenschweiler,"Arial Narrow Bold",var(--f-display);font-weight:400;font-size:90px;letter-spacing:0', 'PRIMO');
|
|
955
|
+
A.push(loop(e, [
|
|
956
|
+
{ clipPath: 'inset(100% 0 0 0)', transform: 'translateY(30px)' }, { clipPath: 'inset(100% 0 0 0)', transform: 'translateY(30px)', offset: .08, easing: MD3 },
|
|
957
|
+
{ clipPath: 'inset(0 0 0 0)', transform: 'translateY(0)', offset: .34 }, { clipPath: 'inset(0 0 0 0)', transform: 'translateY(0)', offset: .84, easing: MD3 },
|
|
958
|
+
{ clipPath: 'inset(0 0 100% 0)', transform: 'translateY(-30px)', offset: .96 }, { clipPath: 'inset(0 0 100% 0)', transform: 'translateY(-30px)' }], { duration: D }));
|
|
959
|
+
} else if (id === 'tecnica') {
|
|
960
|
+
const ls = letras(m, 'left:0;right:0;top:84px;justify-content:center;font-family:var(--f-mono);font-weight:500;font-size:26px;letter-spacing:0', 'primo.run()');
|
|
961
|
+
ls.forEach((s, i) => A.push(loop(s, [{ opacity: 0 }, { opacity: 0, offset: .06 + i * .04 }, { opacity: 1, offset: .061 + i * .04 }, ...sai(s)], { duration: D })));
|
|
962
|
+
const cur = peca(m, `left:236px;top:82px;width:12px;height:30px;background:${TINTA}`);
|
|
963
|
+
A.push(loop(cur, [{ opacity: 1 }, { opacity: 1, offset: .5 }, { opacity: 0, offset: .51 }, { opacity: 0 }], { duration: 700 }));
|
|
964
|
+
} else if (id === 'manuscrita') {
|
|
965
|
+
const e = palavra(m, centro + 'top:56px;font-family:"Snell Roundhand","Segoe Script","Brush Script MT",cursive;font-weight:400;font-size:70px;letter-spacing:0', 'Primo');
|
|
966
|
+
A.push(loop(e, [
|
|
967
|
+
{ clipPath: 'inset(0 100% 0 0)', opacity: 1 }, { clipPath: 'inset(0 100% 0 0)', opacity: 1, offset: .08, easing: 'cubic-bezier(.45,0,.55,1)' },
|
|
968
|
+
{ clipPath: 'inset(0 0% 0 0)', opacity: 1, offset: .58 }, ...sai(e, { clipPath: 'inset(0 0% 0 0)' })], { duration: D }));
|
|
969
|
+
} else if (id === 'pesada') {
|
|
970
|
+
const e = palavra(m, centro + 'top:58px;font-size:80px;font-weight:900;letter-spacing:-.05em');
|
|
971
|
+
A.push(loop(e, [
|
|
972
|
+
{ transform: 'scale(2.6)', opacity: 0 }, { transform: 'scale(2.6)', opacity: 0, offset: .08, easing: 'cubic-bezier(.6,0,1,.6)' },
|
|
973
|
+
{ transform: 'scale(.92)', opacity: 1, offset: .2, easing: 'ease-out' }, { transform: 'scale(1)', opacity: 1, offset: .28 }, ...sai(e, { transform: 'scale(1)' })], { duration: D }));
|
|
974
|
+
A.push(loop(m, [{ transform: T() }, { transform: T(), offset: .2 }, { transform: T(-5, 3) }, { transform: T(5, -3) }, { transform: T(-3, -2) }, { transform: T() }].map((k, i) => (i > 1 && i < 5 ? { ...k, offset: .2 + (i - 1) * .025 } : i === 5 ? { ...k, offset: .3 } : k)).concat([{ transform: T() }]), { duration: D }));
|
|
975
|
+
} else if (id === 'serifa_fina') {
|
|
976
|
+
const e = palavra(m, centro + 'top:60px;font-family:var(--f-serifa);font-weight:300;font-size:64px;letter-spacing:.02em', 'Primo');
|
|
977
|
+
A.push(loop(e, [
|
|
978
|
+
{ opacity: 0, letterSpacing: '.45em' }, { opacity: 0, letterSpacing: '.45em', offset: .06, easing: LISO },
|
|
979
|
+
{ opacity: 1, letterSpacing: '.02em', offset: .5 }, ...sai(e, { letterSpacing: '.02em' })], { duration: D }));
|
|
980
|
+
} else if (id === 'arredondada') {
|
|
981
|
+
letras(m, 'left:0;right:0;top:66px;justify-content:center;font-family:ui-rounded,"SF Pro Rounded","Arial Rounded MT Bold",var(--f-display);font-weight:700;font-size:62px;letter-spacing:-.02em', 'Primo').forEach((s, i) => A.push(loop(s, [
|
|
982
|
+
{ transform: T(0, 60, 0, .3), opacity: 0 }, { transform: T(0, 60, 0, .3), opacity: 0, offset: .06 + i * .05, easing: OVER },
|
|
983
|
+
{ transform: T(0, 0, 0, 1), opacity: 1, offset: .26 + i * .05 }, ...sai(s, { transform: T() })], { duration: D })));
|
|
984
|
+
} else if (id === 'geometrica') {
|
|
985
|
+
const e = palavra(m, 'left:58px;top:74px;font-family:"Avenir Next",Futura,"Century Gothic",var(--f-display);font-weight:500;font-size:36px;letter-spacing:.18em', 'PRIMO');
|
|
986
|
+
const barra = peca(m, `left:60px;top:124px;width:190px;height:4px;background:${TINTA};transform-origin:left`);
|
|
987
|
+
A.push(loop(e, [
|
|
988
|
+
{ opacity: 0, transform: 'translateX(-60px)' }, { opacity: 0, transform: 'translateX(-60px)', offset: .06, easing: MD3 },
|
|
989
|
+
{ opacity: 1, transform: 'translateX(0)', offset: .34 }, ...sai(e, { transform: 'translateX(0)' })], { duration: D }));
|
|
990
|
+
A.push(loop(barra, [{ transform: 'scaleX(0)' }, { transform: 'scaleX(0)', offset: .24, easing: MD3 }, { transform: 'scaleX(1)', offset: .48 }, ...sai(barra, { transform: 'scaleX(1)' })], { duration: D }));
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
function montarPrevia(grupo, id, palco) {
|
|
995
|
+
const m = mundo(palco), A = [];
|
|
996
|
+
if (parar) { palavra(m, 'left:0;right:0;top:80px;text-align:center;font-size:36px', id === 'poster' ? 'PRIMO' : 'Primo'); return A; }
|
|
997
|
+
if (grupo === 'trocas') previaTransicao(m, id, A);
|
|
998
|
+
else if (grupo === 'cameras') previaCamera(m, id, A);
|
|
999
|
+
else previaTipografia(m, id, A);
|
|
1000
|
+
return A;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
const cor = (id) => `var(--c-${id})`;
|
|
1004
|
+
|
|
1005
|
+
/* ── passo 1 ────────────────────────────────────────────────────────────── */
|
|
1006
|
+
function passo1() {
|
|
1007
|
+
const grade = $('#grade');
|
|
1008
|
+
let coluna = null;
|
|
1009
|
+
const conhecidos = new Set(((window.GOSTO && window.GOSTO.ESTILOS) || ESTILOS).map((x) => x.id));
|
|
1010
|
+
ORDEM.filter((id) => conhecidos.has(id)).map((id) => ESTILOS.find((x) => x.id === id)).filter(Boolean).forEach((e, i) => {
|
|
1011
|
+
if (i % 2 === 0) { coluna = el('div', { class: 'coluna' }); grade.appendChild(coluna); }
|
|
1012
|
+
const palco = el('div', { class: 'palco' });
|
|
1013
|
+
const card = el('button', { class: 'card', 'aria-pressed': 'false', 'aria-label': e.nome, id: 'card-' + e.id, style: `--cor:${cor(e.id)}` }, [
|
|
1014
|
+
el('span', { class: 'selo', text: 'escolhido' }), palco]);
|
|
1015
|
+
card.addEventListener('click', () => {
|
|
1016
|
+
const on = card.getAttribute('aria-pressed') !== 'true';
|
|
1017
|
+
card.setAttribute('aria-pressed', String(on));
|
|
1018
|
+
if (on) estado.escolhidos.set(e.id, estado.escolhidos.get(e.id) || { gostei: new Set(), texto: '' }); else estado.escolhidos.delete(e.id);
|
|
1019
|
+
atualizarConta();
|
|
1020
|
+
});
|
|
1021
|
+
coluna.appendChild(card);
|
|
1022
|
+
soNaTela(palco, montarCena(e.id, palco));
|
|
1023
|
+
});
|
|
1024
|
+
ligarSetas();
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/* só anima o que está à vista: são mais de 30 telinhas no carrossel */
|
|
1028
|
+
const vigia = 'IntersectionObserver' in window ? new IntersectionObserver((es) => es.forEach((x) => {
|
|
1029
|
+
(x.target.__anims || []).forEach((a) => (x.isIntersecting ? a.play() : a.pause()));
|
|
1030
|
+
}), { rootMargin: '0px 120px' }) : null;
|
|
1031
|
+
function soNaTela(palco, anims) { palco.__anims = anims; if (vigia) vigia.observe(palco); }
|
|
1032
|
+
|
|
1033
|
+
/* cada coluna tem uma vaga relativa ao começo da página: 0 a vistas-1 aparecem inteiras, a de cada lado
|
|
1034
|
+
aparece esmaecida e as outras ficam escondidas; avançar só muda o deslocamento, e a coluna que dá a volta
|
|
1035
|
+
pula de um lado pro outro sem animação, enquanto está invisível */
|
|
1036
|
+
function ligarSetas(t = $('#grade'), volta = $('#setaVolta'), vai = $('#setaVai'), caixa = $('#carrossel')) {
|
|
1037
|
+
const cols = [...t.children], N = cols.length, GAP = 20;
|
|
1038
|
+
let ini = 0, vistas = 3, passoX = 0, vagaAntes = new Map();
|
|
1039
|
+
const vaga = (i) => { let v = ((i - ini) % N + N) % N; if (v >= N - 2) v -= N; return v; };
|
|
1040
|
+
function medir() {
|
|
1041
|
+
const W = t.clientWidth;
|
|
1042
|
+
vistas = W < 560 ? 1 : W < 860 ? 2 : 3;
|
|
1043
|
+
const cw = (W - GAP * (vistas - 1)) / vistas;
|
|
1044
|
+
passoX = cw + GAP;
|
|
1045
|
+
cols.forEach((c) => { c.style.width = cw + 'px'; });
|
|
1046
|
+
t.style.height = (cols[0].offsetHeight || cw * 1.25 + GAP) + 'px';
|
|
1047
|
+
pintar(true);
|
|
1048
|
+
}
|
|
1049
|
+
function pintar(semAnim) {
|
|
1050
|
+
cols.forEach((c, i) => {
|
|
1051
|
+
const v = vaga(i), antes = vagaAntes.get(c);
|
|
1052
|
+
const salta = semAnim || (antes != null && Math.abs(v - antes) > vistas + 1);
|
|
1053
|
+
c.classList.toggle('salta', salta);
|
|
1054
|
+
const dentro = v >= 0 && v < vistas, vizinha = v === -1 || v === vistas;
|
|
1055
|
+
const op = dentro ? 1 : vizinha ? .4 : 0, esc = dentro ? 1 : .9;
|
|
1056
|
+
c.style.transform = `translateX(${v * passoX}px) scale(${esc})`;
|
|
1057
|
+
c.style.opacity = op;
|
|
1058
|
+
c.style.filter = dentro ? 'none' : 'blur(2px)';
|
|
1059
|
+
c.classList.toggle('vis', dentro);
|
|
1060
|
+
c.classList.toggle('longe', !dentro);
|
|
1061
|
+
vagaAntes.set(c, v);
|
|
1062
|
+
});
|
|
1063
|
+
if (semAnim) requestAnimationFrame(() => cols.forEach((c) => c.classList.remove('salta')));
|
|
1064
|
+
}
|
|
1065
|
+
const andar = (n) => { ini = ((ini + n * vistas) % N + N) % N; pintar(false); };
|
|
1066
|
+
volta.addEventListener('click', () => andar(-1));
|
|
1067
|
+
vai.addEventListener('click', () => andar(1));
|
|
1068
|
+
t.addEventListener('keydown', (ev) => { if (ev.key === 'ArrowRight') { ev.preventDefault(); andar(1); } if (ev.key === 'ArrowLeft') { ev.preventDefault(); andar(-1); } });
|
|
1069
|
+
/* arrastar com o dedo ou o trackpad também passa a página */
|
|
1070
|
+
let x0 = null;
|
|
1071
|
+
t.addEventListener('pointerdown', (ev) => { x0 = ev.clientX; });
|
|
1072
|
+
let arrastou = false;
|
|
1073
|
+
addEventListener('pointerup', (ev) => { if (x0 == null) return; const dx = ev.clientX - x0; x0 = null; if (Math.abs(dx) > 50) { arrastou = true; andar(dx < 0 ? 1 : -1); } });
|
|
1074
|
+
t.addEventListener('click', (ev) => { if (arrastou) { arrastou = false; ev.stopPropagation(); ev.preventDefault(); } }, true);
|
|
1075
|
+
let rodaPronta = true;
|
|
1076
|
+
caixa.addEventListener('wheel', (ev) => {
|
|
1077
|
+
if (Math.abs(ev.deltaX) < Math.abs(ev.deltaY) || Math.abs(ev.deltaX) < 20) return;
|
|
1078
|
+
ev.preventDefault();
|
|
1079
|
+
if (rodaPronta) { rodaPronta = false; andar(ev.deltaX > 0 ? 1 : -1); setTimeout(() => { rodaPronta = true; }, 700); }
|
|
1080
|
+
}, { passive: false });
|
|
1081
|
+
try { new ResizeObserver(medir).observe(t); } catch { addEventListener('resize', medir); }
|
|
1082
|
+
medir();
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
function mostrar(n) {
|
|
1086
|
+
[1, 2, 3, 4].forEach((i) => { $('#passo' + i).hidden = i !== n; });
|
|
1087
|
+
const t = { 1: ['Qual movimento tem a sua cara?', 'Toque nos estilos que você curtiu. Pode ser mais de um. O PrimoCode aprende com isso e usa nos próximos vídeos.'],
|
|
1088
|
+
2: ['Quase lá. Mais disso ou menos disso?', ''],
|
|
1089
|
+
3: ['E o que não pode ter?', 'Isso pesa contra no diretor. Marca só o que te incomoda de verdade.'],
|
|
1090
|
+
4: ['Pronto. Seu próximo vídeo já sai com a sua cara.', ''] }[n];
|
|
1091
|
+
$('#titulo').textContent = t[0];
|
|
1092
|
+
window.scrollTo({ top: 0, behavior: parar ? 'auto' : 'smooth' });
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
function chip(texto, ligado, aoTrocar) {
|
|
1096
|
+
const c = el('button', { class: 'chip', 'aria-pressed': String(ligado), text: texto });
|
|
1097
|
+
c.addEventListener('click', () => { const on = c.getAttribute('aria-pressed') !== 'true'; c.setAttribute('aria-pressed', String(on)); aoTrocar(on); });
|
|
1098
|
+
return c;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
/* ── passo 2 ────────────────────────────────────────────────────────────── */
|
|
1102
|
+
function svgSeta(d) {
|
|
1103
|
+
const NS = ['http:', '', 'www.w3.org', '2000', 'svg'].join('/'), s = document.createElementNS(NS, 'svg'), p = document.createElementNS(NS, 'path');
|
|
1104
|
+
s.setAttribute('viewBox', '0 0 24 24'); s.setAttribute('aria-hidden', 'true'); p.setAttribute('d', d); s.appendChild(p); return s;
|
|
1105
|
+
}
|
|
1106
|
+
const RISCOS = { rapido: 3, lento: 2 };
|
|
1107
|
+
function opcao(k, t, ligado, aoTrocar) {
|
|
1108
|
+
const ic = el('span', { class: 'ic ic-' + k, 'aria-hidden': 'true' }, Array.from({ length: RISCOS[k] || 1 }, () => el('i')));
|
|
1109
|
+
const b = el('button', { class: 'op', 'aria-pressed': String(ligado) }, [ic, el('span', { text: t })]);
|
|
1110
|
+
b.addEventListener('click', () => { const on = b.getAttribute('aria-pressed') !== 'true'; b.setAttribute('aria-pressed', String(on)); aoTrocar(on); });
|
|
1111
|
+
return b;
|
|
1112
|
+
}
|
|
1113
|
+
/* uma pergunta só, valendo pra todos os escolhidos: escolher 15 não vira 15 perguntas */
|
|
1114
|
+
const geral = { gostei: new Set(), texto: '' };
|
|
1115
|
+
function passo2() {
|
|
1116
|
+
const lista = $('#lista2'); lista.replaceChildren();
|
|
1117
|
+
const ids = [...estado.escolhidos.keys()];
|
|
1118
|
+
let fila;
|
|
1119
|
+
if (ids.length <= 3) {
|
|
1120
|
+
fila = el('div', { class: 'mini-fila' });
|
|
1121
|
+
ids.forEach((id) => { const palco = el('div', { class: 'palco' }); fila.appendChild(palco); soNaTela(palco, montarCena(id, palco)); });
|
|
1122
|
+
} else {
|
|
1123
|
+
/* o carrossel infinito precisa de um vizinho de cada lado: com 4 ou 5, repete a fila */
|
|
1124
|
+
const voltas = ids.length < 6 ? ids.concat(ids) : ids;
|
|
1125
|
+
const trilho = el('div', { class: 'trilho', tabindex: '0', 'aria-label': 'Os motions que você escolheu' },
|
|
1126
|
+
voltas.map((id) => { const palco = el('div', { class: 'palco' }); soNaTela(palco, montarCena(id, palco)); return el('div', { class: 'coluna' }, [palco]); }));
|
|
1127
|
+
const seta = (lado, rot) => el('button', { class: 'seta seta-' + lado, 'aria-label': rot }, [svgSeta(lado === 'vai' ? 'M9 5l7 7-7 7' : 'M15 5l-7 7 7 7')]);
|
|
1128
|
+
const volta = seta('volta', 'Voltar'), vai = seta('vai', 'Avançar');
|
|
1129
|
+
fila = el('div', { class: 'carrossel' }, [volta, trilho, vai]);
|
|
1130
|
+
requestAnimationFrame(() => ligarSetas(trilho, volta, vai, fila));
|
|
1131
|
+
}
|
|
1132
|
+
const ops = (lista, tem, poe) => el('div', { class: 'ops' }, lista.map(([k, t]) => opcao(k, t, tem(k), poe(k))));
|
|
1133
|
+
const mais = ops(GOSTEI, (k) => geral.gostei.has(k), (k) => (on) => on ? geral.gostei.add(k) : geral.gostei.delete(k));
|
|
1134
|
+
const menos = ops(NAO_QUERO, (k) => estado.nao.has(k), (k) => (on) => on ? estado.nao.add(k) : estado.nao.delete(k));
|
|
1135
|
+
lista.append(fila,
|
|
1136
|
+
el('div', { class: 'item item-ops' }, [el('div', { class: 'grupo mais' }, [el('h3', { text: 'Mais disso' }), mais]), el('div', { class: 'grupo menos' }, [el('h3', { text: 'Menos disso' }), menos])]));
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
/* ── passo 3 ────────────────────────────────────────────────────────────── */
|
|
1140
|
+
function passo3() {
|
|
1141
|
+
const box = $('#chipsNao'); if (box.childElementCount) return;
|
|
1142
|
+
NAO_QUERO.forEach(([k, t]) => box.appendChild(chip(t, estado.nao.has(k), (on) => on ? estado.nao.add(k) : estado.nao.delete(k))));
|
|
1143
|
+
const ta = $('#naoTexto');
|
|
1144
|
+
ta.addEventListener('input', (ev) => { estado.naoTexto = ev.target.value.slice(0, 280); });
|
|
1145
|
+
$('#sugNao').replaceChildren(...sugestoes(SUG_NAO, ta, (v) => { estado.naoTexto = v; }).children);
|
|
1146
|
+
montarCena('nao', $('#palcoNao'));
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
/* ── o gosto vira pesos (o mesmo cálculo que o diretor vai usar) ─────────── */
|
|
1150
|
+
function gostoJson(pulou = false) {
|
|
1151
|
+
return { versao: 1, quando: new Date().toISOString(), pulou,
|
|
1152
|
+
escolhidos: [...estado.escolhidos].map(([id]) => ({ id, gostei: [...geral.gostei], texto: '' })), gostei: [...geral.gostei], texto: geral.texto.trim(),
|
|
1153
|
+
nao_quero: [...estado.nao], nao_texto: estado.naoTexto.trim(), catalogo: [...estado.extras] };
|
|
1154
|
+
}
|
|
1155
|
+
function pesos(g) {
|
|
1156
|
+
const p = { ritmo: { rapido: 1, medio: 1, lento: 1 }, cameras: {}, trocas: {}, tipografias: {}, overshoot: null };
|
|
1157
|
+
const mult = (o, k, m) => { o[k] = Math.min(5, (o[k] || 1) * m); };
|
|
1158
|
+
const chips = new Set(g.escolhidos.flatMap((x) => x.gostei));
|
|
1159
|
+
g.escolhidos.forEach(({ id }) => {
|
|
1160
|
+
const e = ESTILOS.find((x) => x.id === id);
|
|
1161
|
+
mult(p.ritmo, e.ritmo, 1.8);
|
|
1162
|
+
e.cameras.forEach((c) => mult(p.cameras, c, 2.2)); e.trocas.forEach((t) => mult(p.trocas, t, 2.2)); e.tipografias.forEach((t) => mult(p.tipografias, t, 2.2));
|
|
1163
|
+
});
|
|
1164
|
+
(g.catalogo || []).forEach((k) => { const [gr, id] = k.split(':'); if (p[gr]) mult(p[gr], id, 2.2); });
|
|
1165
|
+
if (chips.has('rapido')) mult(p.ritmo, 'rapido', 1.5);
|
|
1166
|
+
if (chips.has('calmo')) { mult(p.ritmo, 'lento', 1.5); mult(p.trocas, 'tremor', .4); mult(p.trocas, 'chicote', .4); }
|
|
1167
|
+
if (chips.has('quique')) { mult(p.trocas, 'giro', 1.4); mult(p.trocas, 'encolhe', 1.4); }
|
|
1168
|
+
if (chips.has('tres_d')) { mult(p.cameras, 'orbita', 1.5); mult(p.cameras, 'cinema', 1.5); mult(p.trocas, 'giro', 1.4); }
|
|
1169
|
+
if (chips.has('camera')) ['pulso', 'chicote', 'orbita'].forEach((c) => mult(p.cameras, c, 1.3));
|
|
1170
|
+
if (chips.has('cortes')) { mult(p.trocas, 'corte', 1.4); mult(p.trocas, 'chicote', 1.4); }
|
|
1171
|
+
if (g.nao_quero.includes('lento')) mult(p.ritmo, 'lento', .3);
|
|
1172
|
+
if (g.nao_quero.includes('liso')) { mult(p.trocas, 'dissolve', .4); mult(p.trocas, 'desfoque', .4); }
|
|
1173
|
+
if (g.nao_quero.includes('exagero')) { mult(p.trocas, 'tremor', .4); mult(p.trocas, 'chicote', .4); }
|
|
1174
|
+
if (g.nao_quero.includes('tremido')) mult(p.trocas, 'tremor', .2);
|
|
1175
|
+
if (g.escolhidos.length) {
|
|
1176
|
+
let o = g.escolhidos.reduce((s, { id }) => s + ESTILOS.find((x) => x.id === id).overshoot, 0) / g.escolhidos.length;
|
|
1177
|
+
if (chips.has('quique')) o += .05; if (g.nao_quero.includes('exagero')) o -= .05;
|
|
1178
|
+
p.overshoot = Math.max(0, Math.min(.3, o));
|
|
1179
|
+
}
|
|
1180
|
+
return p;
|
|
1181
|
+
}
|
|
1182
|
+
const topo = (o, n) => Object.entries(o).filter(([, v]) => v > 1).sort((a, b) => b[1] - a[1]).slice(0, n).map(([k]) => k.replace('_', ' '));
|
|
1183
|
+
function resumo(g) {
|
|
1184
|
+
const nomeG = Object.fromEntries(GOSTEI), nomeN = Object.fromEntries(NAO_QUERO);
|
|
1185
|
+
const partes = g.escolhidos.map(({ id }) => ESTILOS.find((x) => x.id === id).nome);
|
|
1186
|
+
const doCat = (g.catalogo || []).map((k) => { const [gr, id] = k.split(':'); const c = CATALOGO.find((x) => x.grupo === gr); const it = c && c.itens.find((x) => x[0] === id); return it ? it[1] : id; });
|
|
1187
|
+
if (doCat.length) partes.push(`${doCat.join(', ')} do catálogo`);
|
|
1188
|
+
let s = `Você curtiu ${partes.join(' e ')}.`;
|
|
1189
|
+
if (g.gostei && g.gostei.length) s += ` O que pegou: ${g.gostei.map((k) => nomeG[k]).join(', ')}.`;
|
|
1190
|
+
if (g.nao_quero.length) s += ` Não quer ${g.nao_quero.map((k) => nomeN[k]).join(', ')}.`;
|
|
1191
|
+
const txt = [g.texto, g.nao_texto].filter(Boolean);
|
|
1192
|
+
if (txt.length) s += ` Nas suas palavras: “${txt.join(' · ')}”.`;
|
|
1193
|
+
return s;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
/* ── passo 4 ────────────────────────────────────────────────────────────── */
|
|
1197
|
+
|
|
1198
|
+
|
|
1199
|
+
$('#ir2').addEventListener('click', () => { passo2(); mostrar(2); });
|
|
1200
|
+
$('#volta1').addEventListener('click', () => mostrar(1));
|
|
1201
|
+
let salvando = false;
|
|
1202
|
+
$('#ir3').addEventListener('click', () => {
|
|
1203
|
+
if (salvando) return;
|
|
1204
|
+
salvando = true; erro(''); $('#ir3').disabled = true;
|
|
1205
|
+
mandar('/salvar', gostoJson()).then(() => mostrar(4)).catch((e) => {
|
|
1206
|
+
salvando = false; $('#ir3').disabled = false; $('#ir3').textContent = 'Tentar de novo';
|
|
1207
|
+
erro('Não consegui salvar: ' + e.message + '. O PrimoCode ainda está aberto no terminal?');
|
|
1208
|
+
});
|
|
1209
|
+
});
|
|
1210
|
+
$('#pular').addEventListener('click', () => {
|
|
1211
|
+
mandar('/pular', {}).then(() => {
|
|
1212
|
+
mostrar(4);
|
|
1213
|
+
$('#titulo').textContent = 'Tudo bem, pulei.';
|
|
1214
|
+
$('#fimSub').textContent = 'O PrimoCode segue sem gosto salvo. Pra escolher depois: /gosto refazer.';
|
|
1215
|
+
}).catch((e) => erro('Não consegui pular: ' + e.message));
|
|
1216
|
+
});
|
|
1217
|
+
$('#volta2').addEventListener('click', () => mostrar(estado.escolhidos.size ? 2 : 1));
|
|
1218
|
+
$('#salvar').addEventListener('click', () => { passo4(); mostrar(4); });
|
|
1219
|
+
$('#finalizar').addEventListener('click', (ev) => {
|
|
1220
|
+
const b = ev.currentTarget;
|
|
1221
|
+
try { window.close(); } catch { /* aba que o navegador não deixa fechar */ }
|
|
1222
|
+
setTimeout(() => { $('#fimSub').textContent = 'Pode fechar esta aba. O PrimoCode já está com o seu gosto.'; b.hidden = true; }, 250);
|
|
1223
|
+
});
|
|
1224
|
+
/* ── catálogo completo: todos os tipos de motion do diretor, animados e escolhíveis ── */
|
|
1225
|
+
const CATALOGO = [
|
|
1226
|
+
{ grupo: 'trocas', titulo: 'Transições', sub: 'como uma cena vira a outra', itens: [['encolhe', 'encolhe'], ['empurra', 'empurra'], ['zoom', 'zoom'], ['persiana', 'persiana'], ['chicote', 'chicote'], ['desfoque', 'desfoque'], ['cortina', 'cortina'], ['giro', 'giro'], ['tremor', 'tremor'], ['abre', 'abre'], ['dissolve', 'dissolve'], ['corte', 'corte seco']] },
|
|
1227
|
+
{ grupo: 'cameras', titulo: 'Câmeras', sub: 'como a câmera se mexe', itens: [['deriva', 'deriva'], ['pulso', 'pulso'], ['trilho', 'trilho'], ['orbita', 'órbita'], ['push', 'push'], ['chicote', 'chicote'], ['cinema', 'cinema']] },
|
|
1228
|
+
{ grupo: 'tipografias', titulo: 'Tipografias', sub: 'como a letra entra', itens: [['editorial', 'editorial'], ['poster', 'pôster'], ['tecnica', 'técnica'], ['manuscrita', 'manuscrita'], ['pesada', 'pesada'], ['serifa_fina', 'serifa fina'], ['arredondada', 'arredondada'], ['geometrica', 'geométrica']] },
|
|
1229
|
+
];
|
|
1230
|
+
const TIPO = { trocas: 'Transição', cameras: 'Câmera', tipografias: 'Tipografia' };
|
|
1231
|
+
function montarCatalogo() {
|
|
1232
|
+
const grade = $('#grade');
|
|
1233
|
+
CATALOGO.forEach(({ grupo, sub, itens }) => {
|
|
1234
|
+
itens.forEach(([id, nome]) => {
|
|
1235
|
+
const chave = grupo + ':' + id, palco = el('div', { class: 'palco' });
|
|
1236
|
+
const t = el('button', { class: 'card tile', 'aria-pressed': String(estado.extras.has(chave)), style: '--cor:var(--giz)' },
|
|
1237
|
+
[el('span', { class: 'selo', text: 'escolhido' }), palco, el('div', { class: 'rotulo' }, [el('span', { class: 'tipo', text: TIPO[grupo] }), el('b', { text: nome }), el('small', { text: sub })])]);
|
|
1238
|
+
t.addEventListener('click', () => {
|
|
1239
|
+
const on = !estado.extras.has(chave);
|
|
1240
|
+
if (on) estado.extras.add(chave); else estado.extras.delete(chave);
|
|
1241
|
+
t.setAttribute('aria-pressed', String(on));
|
|
1242
|
+
atualizarConta();
|
|
1243
|
+
});
|
|
1244
|
+
grade.appendChild(t);
|
|
1245
|
+
soNaTela(palco, montarPrevia(grupo, id, palco));
|
|
1246
|
+
});
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
function atualizarConta() {
|
|
1250
|
+
const n = estado.escolhidos.size, x = estado.extras.size, partes = [];
|
|
1251
|
+
if (n) partes.push(`${n} estilo${n > 1 ? 's' : ''}`);
|
|
1252
|
+
if (x) partes.push(`${x} do catálogo`);
|
|
1253
|
+
$('#ir2').disabled = n + x === 0;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
/* No produto, a tela é aberta pelo próprio PrimoCode (servidor local com token) e o
|
|
1257
|
+
gosto vai num POST /salvar, que grava ~/.primocode/gosto-motion.json sozinho.
|
|
1258
|
+
Neste protótipo não há servidor, então só guarda na memória da página. */
|
|
1259
|
+
function mandar(rota, corpo) {
|
|
1260
|
+
return fetch(rota, { method: 'POST', headers: { 'content-type': 'application/json', 'x-gosto-token': TOKEN }, body: JSON.stringify(corpo) })
|
|
1261
|
+
.then((r) => r.json().then((j) => { if (!r.ok || !j.ok) throw new Error(j.error || ('erro ' + r.status)); return j; }));
|
|
1262
|
+
}
|
|
1263
|
+
function erro(msg) { const e = $('#erro'); e.hidden = !msg; e.textContent = msg || ''; }
|
|
1264
|
+
|
|
1265
|
+
passo1();
|
|
1266
|
+
|
|
1267
|
+
/* ── o fundo: ondas 3D em degradê, desenhadas na GPU ───────────────────────
|
|
1268
|
+
Seis camadas de onda, de trás pra frente; cada uma tem luz pela inclinação
|
|
1269
|
+
(difusa + brilho na crista), então a superfície parece ter volume. */
|
|
1270
|
+
(function ondas() {
|
|
1271
|
+
const cv = $('#ondas');
|
|
1272
|
+
const gl = cv.getContext('webgl', { antialias: false, premultipliedAlpha: false });
|
|
1273
|
+
if (!gl) return; // sem WebGL: fica o degradê do CSS
|
|
1274
|
+
const vs = 'attribute vec2 p;void main(){gl_Position=vec4(p,0.,1.);}';
|
|
1275
|
+
const fs = `precision mediump float;
|
|
1276
|
+
uniform vec2 r; uniform float t; uniform vec3 ceu, clara, media, funda; uniform vec3 mouse;
|
|
1277
|
+
float ruido(vec2 p) { return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453); }
|
|
1278
|
+
void main(){
|
|
1279
|
+
vec2 uv = gl_FragCoord.xy / r;
|
|
1280
|
+
float asp = r.x / r.y;
|
|
1281
|
+
float x = (uv.x - 0.5) * asp;
|
|
1282
|
+
float lado = clamp(abs(x) / (0.5 * asp), 0.0, 1.0);
|
|
1283
|
+
/* a onda se mexe sozinha o tempo todo: quatro senos em velocidades diferentes e a crista inteira respirando;
|
|
1284
|
+
o mouse ainda puxa a crista e abre um anel por onde passa */
|
|
1285
|
+
float crista = 0.15 + 0.26 * smoothstep(0.0, 1.0, lado) + 0.035 * sin(t * 0.8)
|
|
1286
|
+
+ 0.085 * sin(x * 1.7 + t * 1.15) + 0.05 * sin(x * 3.3 - t * 1.6 + 1.3)
|
|
1287
|
+
+ 0.028 * sin(x * 6.1 + t * 2.4) + 0.012 * sin(x * 11.0 - t * 3.1);
|
|
1288
|
+
float perto = exp(-pow((x - mouse.x) / 0.32, 2.0)) * mouse.z;
|
|
1289
|
+
crista += perto * (0.07 + 0.22 * clamp(mouse.y - crista, 0.0, 0.6));
|
|
1290
|
+
float dm = length(vec2(x - mouse.x, uv.y - mouse.y));
|
|
1291
|
+
crista += 0.014 * sin(dm * 26.0 - t * 5.0) * exp(-dm * 3.5) * mouse.z;
|
|
1292
|
+
float d = uv.y - crista;
|
|
1293
|
+
vec3 col = ceu;
|
|
1294
|
+
col = mix(col, media, exp(-pow(d / 0.17, 2.0)) * 0.95);
|
|
1295
|
+
float abaixo = smoothstep(0.03, -0.34, d);
|
|
1296
|
+
col = mix(col, funda, abaixo * (0.65 + 0.3 * lado));
|
|
1297
|
+
/* a fita de luz: uma segunda onda fina, mais rápida, que corre por cima da primeira */
|
|
1298
|
+
float c2 = crista + 0.075 + 0.04 * sin(x * 2.6 - t * 1.9 + 2.0);
|
|
1299
|
+
col = mix(col, clara, exp(-pow((uv.y - c2) / 0.012, 2.0)) * 0.75);
|
|
1300
|
+
float c3 = crista - 0.06 + 0.035 * sin(x * 3.4 + t * 2.2 + 0.7);
|
|
1301
|
+
col = mix(col, clara, exp(-pow((uv.y - c3) / 0.01, 2.0)) * 0.45 * (0.6 + 0.4 * sin(x * 5.0 - t * 2.0)));
|
|
1302
|
+
/* brilho correndo na crista */
|
|
1303
|
+
float brilho = exp(-pow((d + 0.015) / 0.035, 2.0)) * (0.55 + 0.45 * sin(x * 7.0 - t * 3.2));
|
|
1304
|
+
col = mix(col, clara, brilho * 0.6);
|
|
1305
|
+
col = mix(col, clara, exp(-dm * dm / 0.02) * 0.4 * mouse.z * smoothstep(0.2, -0.1, d));
|
|
1306
|
+
col = mix(col, ceu, smoothstep(0.24, 0.62, d));
|
|
1307
|
+
col += (ruido(gl_FragCoord.xy + fract(t * 0.5)) - 0.5) * 0.03;
|
|
1308
|
+
gl_FragColor = vec4(col, 1.0);
|
|
1309
|
+
}`;
|
|
1310
|
+
const sh = (tipo, src) => { const s = gl.createShader(tipo); gl.shaderSource(s, src); gl.compileShader(s); return gl.getShaderParameter(s, gl.COMPILE_STATUS) ? s : null; };
|
|
1311
|
+
const v = sh(gl.VERTEX_SHADER, vs), f = sh(gl.FRAGMENT_SHADER, fs);
|
|
1312
|
+
if (!v || !f) return;
|
|
1313
|
+
const pr = gl.createProgram(); gl.attachShader(pr, v); gl.attachShader(pr, f); gl.linkProgram(pr);
|
|
1314
|
+
if (!gl.getProgramParameter(pr, gl.LINK_STATUS)) return;
|
|
1315
|
+
gl.useProgram(pr);
|
|
1316
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
|
|
1317
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
|
|
1318
|
+
const lp = gl.getAttribLocation(pr, 'p'); gl.enableVertexAttribArray(lp); gl.vertexAttribPointer(lp, 2, gl.FLOAT, false, 0, 0);
|
|
1319
|
+
const U = (n) => gl.getUniformLocation(pr, n);
|
|
1320
|
+
const uR = U('r'), uT = U('t'), uM = U('mouse');
|
|
1321
|
+
const alvo = [0, .5, 0], m = [0, .5, 0]; // x na largura da onda, y de baixo pra cima, força (some quando o mouse para)
|
|
1322
|
+
let parado = 0;
|
|
1323
|
+
addEventListener('pointermove', (ev) => { alvo[0] = (ev.clientX / innerWidth - .5) * (innerWidth / innerHeight); alvo[1] = 1 - ev.clientY / innerHeight; alvo[2] = 1; parado = performance.now(); }, { passive: true });
|
|
1324
|
+
const rgb = (h) => { h = h.trim().replace('#', ''); if (h.length === 3) h = h.replace(/./g, '$&$&'); const n = parseInt(h, 16); return [(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255]; };
|
|
1325
|
+
function cores() {
|
|
1326
|
+
const cs = getComputedStyle(document.documentElement);
|
|
1327
|
+
[['ceu', '--onda-ceu'], ['clara', '--onda-clara'], ['media', '--onda-media'], ['funda', '--onda-funda']].forEach(([u, v]) => gl.uniform3fv(U(u), rgb(cs.getPropertyValue(v) || '#ffffff')));
|
|
1328
|
+
}
|
|
1329
|
+
function medir() {
|
|
1330
|
+
const d = Math.min(window.devicePixelRatio || 1, 1.5) * 0.75;
|
|
1331
|
+
cv.width = Math.max(1, Math.round(innerWidth * d)); cv.height = Math.max(1, Math.round(innerHeight * d));
|
|
1332
|
+
gl.viewport(0, 0, cv.width, cv.height); gl.uniform2f(uR, cv.width, cv.height);
|
|
1333
|
+
}
|
|
1334
|
+
const quadro = (ms) => {
|
|
1335
|
+
if (performance.now() - parado > 1800) alvo[2] = 0;
|
|
1336
|
+
for (let i = 0; i < 3; i++) m[i] += (alvo[i] - m[i]) * (i === 2 ? .04 : .08);
|
|
1337
|
+
gl.uniform3f(uM, m[0], m[1], m[2]); gl.uniform1f(uT, ms / 1000); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
1338
|
+
};
|
|
1339
|
+
cores(); medir();
|
|
1340
|
+
addEventListener('resize', () => { medir(); if (parar) quadro(4000); });
|
|
1341
|
+
matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { cores(); if (parar) quadro(4000); });
|
|
1342
|
+
new MutationObserver(() => { cores(); if (parar) quadro(4000); }).observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
|
|
1343
|
+
if (parar) { quadro(4000); return; } // reduzir movimento: as ondas ficam paradas
|
|
1344
|
+
const tick = (ms) => { if (!document.hidden) quadro(ms); requestAnimationFrame(tick); };
|
|
1345
|
+
requestAnimationFrame(tick);
|
|
1346
|
+
})();
|
|
1347
|
+
</script>
|
|
1348
|
+
|
|
1349
|
+
</body></html>
|