primocode 10.16.0 → 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 +11 -2
- 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 +36 -8
- package/lib/catalogo.js +4 -0
- 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.js +45 -4
- package/lib/estudio/index.js +8 -5
- 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 +61 -7
- 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 +60 -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/local/cerebro.json +192 -6
- package/lib/local/motor.js +5 -2
- package/lib/nuvem.js +11 -1
- package/lib/passagem.js +50 -0
- package/lib/perigo.js +19 -11
- package/lib/protecao.js +134 -0
- package/lib/titulo-conversa.js +46 -0
- package/lib/tools.js +3 -0
- package/lib/ui.js +1 -1
- 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/app.py +43 -4
- package/voz/primo_voz/chat.html +17 -6
- package/voz/primo_voz/painel_dados.py +134 -0
|
@@ -26,10 +26,12 @@ function kBase(comp, P) {
|
|
|
26
26
|
function kAmbiente(comp, P, cam) {
|
|
27
27
|
if (KIT.cenaComElemento || !cam) return;
|
|
28
28
|
var W = comp.width, H = comp.height, m = Math.min(W, H), ze = kZonaTexto(comp, false), mx = ze.x, my = ze.top, myb = ze.bot, k, colocados = [], R = [], ri;
|
|
29
|
-
for (ri = 0; ri < KIT.rects.length; ri++) if (KIT.rects[ri].cena == KIT.cenaIdx) R.push(kRectLayout(KIT.rects[ri]));
|
|
29
|
+
for (ri = 0; ri < KIT.rects.length; ri++) if (KIT.rects[ri].cena == KIT.cenaIdx && !KIT.rects[ri].fora) R.push(kRectLayout(KIT.rects[ri]));
|
|
30
30
|
var tams = [m * 0.5, m * 0.15];
|
|
31
|
+
// folga do texto: 7% da largura (no mínimo 60 px), pra a câmera que empurra (até 1,1×) não encostar o objeto nas letras
|
|
32
|
+
var fo = Math.max(60, W * 0.07);
|
|
31
33
|
function livre(x, y, w) {
|
|
32
|
-
var x0 = x - w / 2 -
|
|
34
|
+
var x0 = x - w / 2 - fo, x1 = x + w / 2 + fo, y0 = y - w / 2 - fo, y1 = y + w / 2 + fo, i;
|
|
33
35
|
if (x - w / 2 < mx + W * 0.04 || x + w / 2 > W - mx - W * 0.04 || y - w / 2 < my + W * 0.04 || y + w / 2 > H - myb - W * 0.04) return false;
|
|
34
36
|
for (i = 0; i < R.length; i++) { var r = R[i]; if (x0 < r.x1 && x1 > r.x0 && y0 < r.y1 && y1 > r.y0) return false; }
|
|
35
37
|
for (i = 0; i < colocados.length; i++) { var q = colocados[i]; if (x0 < q[2] && x1 > q[0] && y0 < q[3] && y1 > q[1]) return false; }
|
|
@@ -48,13 +50,23 @@ function kAmbiente(comp, P, cam) {
|
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
52
|
}
|
|
53
|
+
// onde o raio que sai de (cx, cy) no ângulo a cruza a borda da caixa (+ m para fora); sem caixa, o próprio centro
|
|
54
|
+
function kNaBorda(c, cx, cy, a, m) {
|
|
55
|
+
if (!c) return [cx, cy];
|
|
56
|
+
var dx = Math.cos(a), dy = Math.sin(a), hw = (c[2] - c[0]) / 2, hh = (c[3] - c[1]) / 2;
|
|
57
|
+
var k = Math.min(Math.abs(dx) > 1e-6 ? hw / Math.abs(dx) : 1e9, Math.abs(dy) > 1e-6 ? hh / Math.abs(dy) : 1e9) + (m || 0);
|
|
58
|
+
return [cx + dx * k, cy + dy * k];
|
|
59
|
+
}
|
|
51
60
|
// pontos que estalam em volta de um centro (confete discreto), com som
|
|
52
|
-
|
|
61
|
+
/* caixa (opcional, [x0, y0, x1, y1]): o estouro nasce na BORDA dela e vai para fora — o confete nunca passa por cima do texto que
|
|
62
|
+
mora dentro (o rótulo do botão virava "Começa: agora" com um ponto branco em cima do "r"). */
|
|
63
|
+
function kEstouro(comp, cam, cx, cy, t, cor, n, raio, som0, caixa) {
|
|
53
64
|
var i;
|
|
54
65
|
for (i = 0; i < n; i++) {
|
|
55
66
|
var a = (i / n) * Math.PI * 2 + 0.4, r = raio * (0.8 + 0.4 * ((i * 37) % 10) / 10), d = 10 + (i % 3) * 6;
|
|
56
|
-
var
|
|
57
|
-
|
|
67
|
+
var p0 = kNaBorda(caixa, cx, cy, a, d + 6), p1 = [p0[0] + Math.cos(a) * r, p0[1] + Math.sin(a) * r];
|
|
68
|
+
var L = forma(comp, 'circulo', { x: p0[0], y: p0[1], w: d * 2, cor: cor, parent: cam.no, nome: 'estouro', alfa: 0 });
|
|
69
|
+
curva(kP(L), [[t, p0, null, 20], [t + 0.7, p1, 85, null]]);
|
|
58
70
|
curva(kO(L), [[t - 0.04, 0, null, 30], [t, 100, null, 30], [t + 0.2, 100, 50, 30], [t + 0.75, 0, 70, null]]);
|
|
59
71
|
curva(kS(L), [[t, [40, 40], null, 20], [t + 0.25, [100, 100], 70, 30], [t + 0.75, [20, 20], 70, null]]);
|
|
60
72
|
}
|
|
@@ -203,8 +215,8 @@ function cenaAntesDepois(comp, P, d) {
|
|
|
203
215
|
var seta = texto(comp, '>', { fonte: P.fonteTitulo, tamanho: 190 * u, cor: P.ac, x: v ? W / 2 : W / 2, y: v ? H * 0.5 : H * 0.5, parent: cam.no, entrada: 'palavra', t0: t2 - 0.25, sublinhado: false, largura: 200, sobrepoe: true, semAuditoria: true });
|
|
204
216
|
if (v) for (var s = 0; s < seta.camadas.length; s++) kR(seta.camadas[s]).expression = 'value + 90';
|
|
205
217
|
som(t2 - 0.25, 'swoosh', 0.6);
|
|
206
|
-
var B = forma(comp, 'retangulo', { x: bx, y: by, w: cw, h: ch, r: 56 * u, cor: P
|
|
207
|
-
var cor2 =
|
|
218
|
+
var B = forma(comp, 'retangulo', { x: bx, y: by, w: cw, h: ch, r: 56 * u, cor: kCardAc(P), parent: cam.no, nome: 'depois' });
|
|
219
|
+
var cor2 = kSobreCard(P);
|
|
208
220
|
mola(kS(B), t2, [60, 60], [100, 100], { quique: 0.7, dur: 0.75 });
|
|
209
221
|
curva(kO(B), [[t2, 0, null, 30], [t2 + 0.1, 100, 60, null]]);
|
|
210
222
|
mola(kR(B), t2, v ? 3 : -3, 0, { quique: 0.5, dur: 0.8 });
|
|
@@ -212,7 +224,7 @@ function cenaAntesDepois(comp, P, d) {
|
|
|
212
224
|
texto(comp, 'DEPOIS', { fonte: P.fonteTitulo, tamanho: 44 * u, cor: P.bg, x: bx, y: by - ch / 2, parent: cam.no, entrada: 'sobe', t0: t2 + 0.18, largura: 220 * u, maxLinhas: 1, sublinhado: false });
|
|
213
225
|
texto(comp, d.depois || '', { tamanho: 96 * u, cor: cor2, corDestaque: cor2, x: bx, y: by + 24 * u, parent: cam.no, entrada: 'palavra', t0: t2 + 0.32, largura: cw * 0.84, maxLinhas: 4, sublinhado: false });
|
|
214
226
|
som(t2, 'impacto', 0.7); som(t2 + 0.05, 'brilho', 0.6);
|
|
215
|
-
kEstouro(comp, cam, bx, by, t2 + 0.05, P.fg, 8, ch * 0.
|
|
227
|
+
kEstouro(comp, cam, bx, by, t2 + 0.05, P.fg, 8, ch * 0.4, false, [bx - cw / 2, by - ch / 2, bx + cw / 2, by + ch / 2]);
|
|
216
228
|
cam.empurra(0.8, v ? 0 : -60 * u, v ? -120 * u : 0, 1.02).empurra(t2 + 0.5, v ? 0 : 70 * u, v ? 130 * u : 0, 1.1).empurra(comp.duration - 0.2, v ? 0 : 90 * u, v ? 150 * u : 0, 1.13);
|
|
217
229
|
fecha(comp);
|
|
218
230
|
}
|
|
@@ -263,6 +275,19 @@ function cenaCitacao(comp, P, d) {
|
|
|
263
275
|
fecha(comp);
|
|
264
276
|
}
|
|
265
277
|
|
|
278
|
+
// ---------------------------------------------------------------- o cursor que clica num botão
|
|
279
|
+
/* kCursorNoBotao(comp, alvo, rot, ox, oy, cresce, preferido, u): a ponta do clique (no espaço do pai do cursor) pela regra da guarda
|
|
280
|
+
(gCursor): dentro do botão `alvo`, a setinha sem cobrir o rótulo `rot` (o retorno do texto(), com x, y, w, h no espaço do grupo do
|
|
281
|
+
botão, que está em ox, oy e cresce até `cresce`× no clique). Escreve a linha GUARDA da cena com a caixa do cursor e a do rótulo. */
|
|
282
|
+
function kCursorNoBotao(comp, alvo, rot, ox, oy, cresce, preferido, u) {
|
|
283
|
+
var k = cresce || 1, cx = ox || 0, cy = oy || 0, rx = rot && rot.w ? rot.x : 0, ry = rot && rot.w ? rot.y : 0;
|
|
284
|
+
var rc0 = rot && rot.w ? [cx + (rx - rot.w / 2) * k, cy + (ry - rot.h / 2) * k, cx + (rx + rot.w / 2) * k, cy + (ry + rot.h / 2) * k] : null;
|
|
285
|
+
var r = gCursor(alvo, rc0 ? [rc0] : [], { w: 48 * u, h: 70 * u, folga: 10 * u, preferido: preferido });
|
|
286
|
+
var log = ['cursor: clica em [' + Math.round(r.ponta[0]) + ',' + Math.round(r.ponta[1]) + ']' + (r.movido ? ' (saiu de cima do texto)' : '') + (r.ok ? '' : ' na borda de baixo do botão')];
|
|
287
|
+
writeLn('GUARDA ' + JSON.stringify({ cena: KIT.cenaIdx, w: comp.width, h: comp.height, log: log, caixas: [{ tipo: 'cursor', nome: 'cursor', c: [Math.round(r.c[0]), Math.round(r.c[1]), Math.round(r.c[2]), Math.round(r.c[3])], fora: 0 }].concat(rc0 ? [{ tipo: 'texto', nome: 'rótulo do botão', c: [Math.round(rc0[0]), Math.round(rc0[1]), Math.round(rc0[2]), Math.round(rc0[3])], fora: 0 }] : []), violacoes: gVerificar([{ tipo: 'cursor', nome: 'cursor', c: r.c }].concat(rc0 ? [{ tipo: 'texto', nome: 'rótulo', c: rc0, livre: false }] : []), comp.width, comp.height, { zona: { x0: -1e9, x1: 1e9, y0: -1e9, y1: 1e9, trilho: null } }) }));
|
|
288
|
+
return r.ponta;
|
|
289
|
+
}
|
|
290
|
+
|
|
266
291
|
// ---------------------------------------------------------------- CTA
|
|
267
292
|
/* O CTA: título que voa, botão SÓLIDO com brilho que varre (Merge Paths em Intersect: o brilho só existe dentro da pílula) e um
|
|
268
293
|
ícone; o cursor entra, o botão afunda e volta com quique, estoura em ondas e partículas, com clique + impacto. Sem camada fantasma. */
|
|
@@ -296,7 +321,7 @@ function cenaCta(comp, P, d) {
|
|
|
296
321
|
var ic = caminho(comp, [[-22 * u, 0], [24 * u, 0]], { cor: ink, esp: 11 * u, parent: btn, nome: 'seta-haste' });
|
|
297
322
|
caminho(comp, [[6 * u, -20 * u], [26 * u, 0], [6 * u, 20 * u]], { cor: ink, esp: 11 * u, parent: btn, nome: 'seta-ponta' });
|
|
298
323
|
var arrows = [];
|
|
299
|
-
texto(comp, d.botao || 'Começar agora', { fonte: P.fonteTitulo, tamanho: (v ? 84 : 58) * u, cor: ink, corDestaque: ink, x: -28 * u, y: 0, parent: btn, entrada: 'sobe', t0: tb + 0.08, largura: bw * 0.7, maxLinhas: 1, sublinhado: false, livre: true, fala: false });
|
|
324
|
+
var rot = texto(comp, d.botao || 'Começar agora', { fonte: P.fonteTitulo, tamanho: (v ? 84 : 58) * u, cor: ink, corDestaque: ink, x: -28 * u, y: 0, parent: btn, entrada: 'sobe', t0: tb + 0.08, largura: bw * 0.7, maxLinhas: 1, sublinhado: false, livre: true, fala: false });
|
|
300
325
|
var iconX = bw / 2 - 74 * u;
|
|
301
326
|
var j, kids = [];
|
|
302
327
|
// posiciona a seta à direita do rótulo
|
|
@@ -307,7 +332,10 @@ function cenaCta(comp, P, d) {
|
|
|
307
332
|
// o cursor entra, o botão afunda e explode
|
|
308
333
|
var tp = tb + 1.05;
|
|
309
334
|
var cur = kCursor(comp, cam.no, u, '#FFFFFF', '#101010');
|
|
310
|
-
|
|
335
|
+
// o cursor é ELEMENTO para a guarda: a ponta clica dentro do botão, depois do texto (na seta) ou na borda; a setinha
|
|
336
|
+
// inteira (48×70 a partir da ponta) nunca cobre o rótulo, nem com o botão crescendo 10% no estouro do clique
|
|
337
|
+
var c1 = kCursorNoBotao(comp, [bx - bw / 2, by - bh / 2, bx + bw / 2, by + bh / 2], rot, bx, by, 1.1, [bx + iconX - 4 * u, by + 10 * u], u);
|
|
338
|
+
var c0 = [c1[0] + bw * 0.1, by + 460 * u];
|
|
311
339
|
kP(cur).setValue(c0);
|
|
312
340
|
curva(kP(cur), [[tp - 0.75, c0, null, 18], [tp - 0.05, c1, 82, 40]]);
|
|
313
341
|
curva(kO(cur), [[tp - 0.75, 0, null, 30], [tp - 0.55, 100, 60, null], [tp + 0.8, 100, null, 30], [tp + 1.05, 0, 60, null]]);
|
|
@@ -319,8 +347,9 @@ function cenaCta(comp, P, d) {
|
|
|
319
347
|
curva(kS(on), [[tp + j * 0.07, [100, 100], null, 20], [tp + j * 0.07 + 0.7, [150 + j * 14, 220 + j * 30], 80, null]]);
|
|
320
348
|
curva(kO(on), [[tp + j * 0.07 - 0.02, 0, null, 30], [tp + j * 0.07, 85, null, 30], [tp + j * 0.07 + 0.7, 0, 70, null]]);
|
|
321
349
|
}
|
|
322
|
-
|
|
323
|
-
kEstouro(comp, cam, bx, by, tp + 0.
|
|
350
|
+
var cxBotao = [bx - bw / 2 * 1.1, by - bh / 2 * 1.1, bx + bw / 2 * 1.1, by + bh / 2 * 1.1]; // o botão a 110% no estouro
|
|
351
|
+
kEstouro(comp, cam, bx, by, tp + 0.04, P.ac, 16, bw * 0.25, false, cxBotao);
|
|
352
|
+
kEstouro(comp, cam, bx, by, tp + 0.08, P.fg, 10, bw * 0.18, false, cxBotao);
|
|
324
353
|
som(tp, 'clique', 0.9); som(tp + 0.03, 'impacto', 0.6); som(tp + 0.1, 'brilho', 0.6);
|
|
325
354
|
// depois do clique o botão respira e solta um halo, sem parar
|
|
326
355
|
var halo = forma(comp, 'pilula', { x: bx, y: by, w: bw, h: bh, traco: P.ac, tracoL: 6 * u, alfa: 0, parent: cam.no, nome: 'halo' });
|
|
@@ -331,14 +360,14 @@ function cenaCta(comp, P, d) {
|
|
|
331
360
|
}
|
|
332
361
|
|
|
333
362
|
// ---------------------------------------------------------------- montagem
|
|
334
|
-
/* O vocabulário de cenas: 8 clássicas (aqui) +
|
|
363
|
+
/* O vocabulário de cenas: 8 clássicas (aqui) + 31 primitivas (primitivas.jsx; a 31ª, "foto", só entra quando o pedido traz foto). O diretor (maquina-diretor.js) escolhe. */
|
|
335
364
|
var CENAS = {
|
|
336
365
|
gancho: cenaGancho, celular: cenaCelular, numero: cenaNumero, lista: cenaLista, antes_depois: cenaAntesDepois, icones: cenaIcones, citacao: cenaCitacao, cta: cenaCta,
|
|
337
366
|
cinetico: cenaCinetico, interface: cenaInterface, mergulho: cenaMergulho, camera_nulls: cenaCameraNulls, barras: cenaBarras, linha: cenaLinha, mapa: cenaMapa,
|
|
338
367
|
cards_pulam: cenaCardsPulam, cursor: cenaCursor, notificacoes: cenaNotificacoes, chat: cenaChat, linha_tempo: cenaLinhaTempo, laco: cenaLaco, explosao: cenaExplosao,
|
|
339
368
|
revela: cenaRevela, split: cenaSplit, heroi: cenaHeroi, particulas: cenaParticulas, relogio: cenaRelogio, calendario: cenaCalendario, funil: cenaFunil,
|
|
340
369
|
parede_logos: cenaParedeLogos, prompt: cenaPrompt, odometro: cenaOdometro, medidor: cenaMedidor, carimbo: cenaCarimbo, leque: cenaLeque, ondas: cenaOndas,
|
|
341
|
-
rolagem: cenaRolagem, estrelas: cenaEstrelas
|
|
370
|
+
rolagem: cenaRolagem, estrelas: cenaEstrelas, foto: cenaFoto
|
|
342
371
|
};
|
|
343
372
|
|
|
344
373
|
function montar(PL) {
|
|
@@ -366,7 +395,10 @@ function montar(PL) {
|
|
|
366
395
|
var c = PL.cenas[i], dur = c.dur + (i < n - 1 ? TROCA_DUR + 0.05 : 0), f = Math.max(1, Math.min(2.4, c.f || 1));
|
|
367
396
|
// a cena é montada em tempo NOMINAL (dur × f) e tocada f vezes mais rápido dentro de uma comp-embrulho: tudo entra nos primeiros ~35%
|
|
368
397
|
var comp = novaComp('CENA ' + i, W, H, dur * f, fps);
|
|
369
|
-
|
|
398
|
+
// enfeite só onde há espaço livre de verdade (nada de herói em cima de janela, prompt ou botão)
|
|
399
|
+
KIT.cenaComElemento = !!c.elemento; KIT.semAmbiente = !!c.semAmbiente || !{ cinetico: 1, gancho: 1, numero: 1, citacao: 1, particulas: 1, odometro: 1, relogio: 1, carimbo: 1 }[c.tipo];
|
|
400
|
+
// (até 20/10 esta linha morava DEPOIS do comentário acima, na mesma linha: o cenaIdx, o t0, o ajuste e o f nunca eram postos)
|
|
401
|
+
KIT.semRotulos = !!c.semRotulos; KIT.cenaHeroi = c.tipo == 'heroi' || c.tipo == 'revela'; KIT.titulosL = []; KIT.tituloB = null; KIT.t0 = starts[i]; KIT.cenaIdx = i; KIT.estilo = c.camera || PL.camera || 'deriva'; KIT.ajusteCena = c.ajuste || 1; KIT.tituloDesce = c.tituloDesce || 0; KIT.f = f; KIT.entMax = 0;
|
|
370
402
|
var P = c.pal; KIT.pal = P;
|
|
371
403
|
P.fonteTitulo = PL.fontes.titulo; P.fonteTexto = PL.fontes.texto; P.fonteDestaque = PL.fontes.destaque;
|
|
372
404
|
if (!CENAS[c.tipo]) KIT.avisos.push('cena ' + i + ': tipo desconhecido ' + c.tipo);
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/* guarda.jsx — a GUARDA de layout do motion (ES3: só var e function).
|
|
2
|
+
|
|
3
|
+
O mesmo arquivo roda em dois lugares, ANTES do render:
|
|
4
|
+
1. no Node (lib/estudio/maquina-guarda.js carrega pelo vm): planeja a cena "foto" (foto, título, ícones) com a largura
|
|
5
|
+
medida da fonte e escreve o layout no plano;
|
|
6
|
+
2. no kit (o maquina.js concatena depois do base.jsx): no fecha() de CADA cena, com as caixas reais (sourceRectAtTime),
|
|
7
|
+
conserta o que o modelo ou o diretor puseram torto.
|
|
8
|
+
|
|
9
|
+
Regras (a régua do dono: muito movimento, mas NADA feio — nada gigante, nada sobreposto, nada colado na borda):
|
|
10
|
+
tamanho texto até 88% da largura; ícone entre 12% e 24% do lado menor; foto entre 55% e 80% da largura no 9:16
|
|
11
|
+
zona tudo dentro de 6% de margem; no 9:16 fora das faixas de interface do Reels/TikTok (10% em cima, 20% embaixo)
|
|
12
|
+
e do trilho de botões da direita
|
|
13
|
+
sobrepor texto não encosta em nada (folga mínima); ícone nunca sobre texto, foto/rosto ou outro ícone
|
|
14
|
+
lotação no máximo N elementos ao mesmo tempo (os ícones de menor prioridade saem)
|
|
15
|
+
Quando viola, CONSERTA (reposiciona, encolhe, tira o ícone de trás); se não der, pede a troca da peça (trocar: true).
|
|
16
|
+
Cada conserto vira uma linha do log da cena.
|
|
17
|
+
|
|
18
|
+
item = { id, tipo: 'texto'|'icone'|'foto'|'cartao'|'cursor', c: [x0, y0, x1, y1] (o envelope de todos os quadros-chave),
|
|
19
|
+
fixo (não move nem encolhe), prio (maior fica), nome, alvo (cursor: a caixa do botão que ele clica) }
|
|
20
|
+
cursor a setinha é elemento: nunca em cima de letra; clica na borda do botão ou depois do texto (gCursor)
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
var GUARDA = { margem: 0.06, folga: 28, maxSimult: 6, textoMaxL: 0.88, iconeMin: 0.12, iconeMax: 0.24, fotoMin: 0.55, fotoMax: 0.8, passo: 0.025 };
|
|
24
|
+
|
|
25
|
+
function gAlto(W, H) { return H / W > 1.6; }
|
|
26
|
+
/* A zona segura (no mesmo espaço das caixas). o.legenda: a legenda sobe a faixa de baixo. */
|
|
27
|
+
function gZona(W, H, o) {
|
|
28
|
+
o = o || {};
|
|
29
|
+
var m = GUARDA.margem, z = { x0: W * m, x1: W * (1 - m), y0: H * m, y1: H * (1 - m), trilho: null };
|
|
30
|
+
if (gAlto(W, H)) {
|
|
31
|
+
z.y0 = H * 0.1; z.y1 = H * (o.legenda ? 0.73 : 0.8);
|
|
32
|
+
z.trilho = [W * 0.885, H * 0.5, W, H]; // a coluna de curtir/comentar/compartilhar
|
|
33
|
+
}
|
|
34
|
+
return z;
|
|
35
|
+
}
|
|
36
|
+
function gW(c) { return c[2] - c[0]; }
|
|
37
|
+
function gH(c) { return c[3] - c[1]; }
|
|
38
|
+
function gCx(c) { return (c[0] + c[2]) / 2; }
|
|
39
|
+
function gCy(c) { return (c[1] + c[3]) / 2; }
|
|
40
|
+
function gR(n) { return Math.round(n); }
|
|
41
|
+
function gTxt(c) { return '[' + gR(c[0]) + ',' + gR(c[1]) + ',' + gR(c[2]) + ',' + gR(c[3]) + ']'; }
|
|
42
|
+
function gCaixa(cx, cy, w, h) { return [cx - w / 2, cy - h / 2, cx + w / 2, cy + h / 2]; }
|
|
43
|
+
function gMove(c, dx, dy) { return [c[0] + dx, c[1] + dy, c[2] + dx, c[3] + dy]; }
|
|
44
|
+
function gEscala(c, k) { return gCaixa(gCx(c), gCy(c), gW(c) * k, gH(c) * k); }
|
|
45
|
+
/* Encostam? (com folga m entre as duas) */
|
|
46
|
+
function gToca(a, b, m) { m = m || 0; return a[0] < b[2] + m && b[0] < a[2] + m && a[1] < b[3] + m && b[1] < a[3] + m; }
|
|
47
|
+
function gCabe(c, z) { return c[0] >= z.x0 - 0.5 && c[2] <= z.x1 + 0.5 && c[1] >= z.y0 - 0.5 && c[3] <= z.y1 + 0.5; }
|
|
48
|
+
function gNoTrilho(c, z) { return !!z.trilho && gToca(c, z.trilho, 0); }
|
|
49
|
+
function gNome(it) { return it.nome || (it.tipo + ' ' + it.id); }
|
|
50
|
+
|
|
51
|
+
/* Põe a caixa dentro da zona (encolhe se for maior). Devolve a caixa nova. */
|
|
52
|
+
function gEncaixa(c, z) {
|
|
53
|
+
var w = gW(c), h = gH(c), zw = z.x1 - z.x0, zh = z.y1 - z.y0, k = Math.min(1, zw / w, zh / h);
|
|
54
|
+
if (k < 1) c = gEscala(c, k);
|
|
55
|
+
var dx = 0, dy = 0;
|
|
56
|
+
if (c[0] < z.x0) dx = z.x0 - c[0]; else if (c[2] > z.x1) dx = z.x1 - c[2];
|
|
57
|
+
if (c[1] < z.y0) dy = z.y0 - c[1]; else if (c[3] > z.y1) dy = z.y1 - c[3];
|
|
58
|
+
return gMove(c, dx, dy);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Procura um lugar livre do tamanho (w, h) o mais perto de (cx, cy): nada em `ocupado` (com folga), dentro da zona, fora do trilho. */
|
|
62
|
+
function gLugarLivre(cx, cy, w, h, z, ocupado, folga, W) {
|
|
63
|
+
var passo = Math.max(8, W * GUARDA.passo), melhor = null, md = 1e18, x, y, j;
|
|
64
|
+
for (y = z.y0 + h / 2; y <= z.y1 - h / 2 + 0.5; y += passo) {
|
|
65
|
+
for (x = z.x0 + w / 2; x <= z.x1 - w / 2 + 0.5; x += passo) {
|
|
66
|
+
var c = gCaixa(x, y, w, h), livre = !gNoTrilho(c, z);
|
|
67
|
+
for (j = 0; livre && j < ocupado.length; j++) if (gToca(c, ocupado[j], folga)) livre = false;
|
|
68
|
+
if (!livre) continue;
|
|
69
|
+
var d = (x - cx) * (x - cx) + (y - cy) * (y - cy);
|
|
70
|
+
if (d < md) { md = d; melhor = c; }
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return melhor;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* O CURSOR é um elemento como os outros: a ponta clica DENTRO do alvo (botão, campo), mas a setinha inteira (da ponta para a
|
|
77
|
+
direita e para baixo) nunca cobre letra. Clica na borda do botão ou depois do texto.
|
|
78
|
+
gCursor(alvo, textos, o) → { ponta: [x, y], c: caixa da setinha, movido, ok }
|
|
79
|
+
o = { w, h (a setinha a partir da ponta), folga, preferido: [x, y], pilula (o alvo é pílula: a ponta fica dentro do arredondado) } */
|
|
80
|
+
function gCaixaCursor(p, w, h) { return [p[0] - 3, p[1] - 3, p[0] + w, p[1] + h]; }
|
|
81
|
+
function gDentroAlvo(p, c, pilula) {
|
|
82
|
+
var h = gH(c), r = h / 2, cy = gCy(c), m = h * 0.1;
|
|
83
|
+
if (!pilula) return p[0] >= c[0] + m && p[0] <= c[2] - m && p[1] >= c[1] + m && p[1] <= c[3] - m;
|
|
84
|
+
var x = Math.max(c[0] + r, Math.min(c[2] - r, p[0]));
|
|
85
|
+
return (p[0] - x) * (p[0] - x) + (p[1] - cy) * (p[1] - cy) <= (r - m) * (r - m);
|
|
86
|
+
}
|
|
87
|
+
function gCursor(alvo, textos, o) {
|
|
88
|
+
o = o || {};
|
|
89
|
+
var w = o.w || 48, h = o.h || 70, folga = o.folga != null ? o.folga : 6, i, j, x, y;
|
|
90
|
+
var pref = o.preferido || [alvo[2] - gH(alvo) * 0.45, gCy(alvo) + gH(alvo) * 0.12];
|
|
91
|
+
var livre = function (p) {
|
|
92
|
+
if (!gDentroAlvo(p, alvo, o.pilula !== false)) return false;
|
|
93
|
+
var c = gCaixaCursor(p, w, h);
|
|
94
|
+
for (j = 0; j < textos.length; j++) if (gToca(c, textos[j], folga)) return false;
|
|
95
|
+
return true;
|
|
96
|
+
};
|
|
97
|
+
if (livre(pref)) return { ponta: pref, c: gCaixaCursor(pref, w, h), movido: false, ok: true };
|
|
98
|
+
var passo = Math.max(4, Math.min(gW(alvo), gH(alvo)) / 12), melhor = null, md = 1e18;
|
|
99
|
+
for (y = alvo[1]; y <= alvo[3]; y += passo) {
|
|
100
|
+
for (x = alvo[0]; x <= alvo[2]; x += passo) {
|
|
101
|
+
if (!livre([x, y])) continue;
|
|
102
|
+
var d = (x - pref[0]) * (x - pref[0]) + (y - pref[1]) * (y - pref[1]);
|
|
103
|
+
if (d < md) { md = d; melhor = [x, y]; }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (melhor) return { ponta: melhor, c: gCaixaCursor(melhor, w, h), movido: true, ok: true };
|
|
107
|
+
// sem lugar dentro sem cobrir letra: a ponta vai para a borda de baixo do botão, abaixo do texto (a setinha pende para fora)
|
|
108
|
+
var baixo = alvo[3] - gH(alvo) * 0.06;
|
|
109
|
+
for (j = 0; j < textos.length; j++) if (gToca(textos[j], alvo, 0) && textos[j][3] + folga + 3 > baixo) baixo = textos[j][3] + folga + 3;
|
|
110
|
+
var p2 = [alvo[2] - gH(alvo) * 0.5, baixo];
|
|
111
|
+
return { ponta: p2, c: gCaixaCursor(p2, w, h), movido: true, ok: false };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* TEXTO DENTRO DE CARTÃO (faixa, placa, botão): o texto cabe no cartão com folga. Não cabe: o corpo encolhe até o mínimo (kMin);
|
|
115
|
+
ainda não cabe: o cartão cresce em volta do texto (até a caixa `max`, se houver).
|
|
116
|
+
gTextoNoCartao(t, c, o) → { k (escala do texto), cartao (a caixa nova), cresceu, ok, log } o = { folga, kMin, max } */
|
|
117
|
+
function gTextoNoCartao(t, c, o) {
|
|
118
|
+
o = o || {};
|
|
119
|
+
var f = o.folga || 0, kMin = o.kMin == null ? 0.8 : o.kMin, log = [];
|
|
120
|
+
var k = Math.min(1, (gW(c) - 2 * f) / Math.max(1, gW(t)), (gH(c) - 2 * f) / Math.max(1, gH(t)));
|
|
121
|
+
var dentro = t[0] >= c[0] + f - 0.5 && t[2] <= c[2] - f + 0.5 && t[1] >= c[1] + f - 0.5 && t[3] <= c[3] - f + 0.5;
|
|
122
|
+
if (k >= 1 && dentro) return { k: 1, cartao: c, cresceu: false, ok: true, log: log };
|
|
123
|
+
if (k >= 1) k = 1;
|
|
124
|
+
else if (k >= kMin) log.push('texto apertado no cartão: o corpo encolheu para ' + Math.round(k * 100) + '%');
|
|
125
|
+
else k = kMin;
|
|
126
|
+
var w = Math.max(gW(c), gW(t) * k + 2 * f), h = Math.max(gH(c), gH(t) * k + 2 * f), ok = true;
|
|
127
|
+
if (o.max) { if (w > gW(o.max)) { w = gW(o.max); ok = false; } if (h > gH(o.max)) { h = gH(o.max); ok = false; } }
|
|
128
|
+
var nc = gCaixa(gCx(t), gCy(t), w, h), cresceu = w > gW(c) + 0.5 || h > gH(c) + 0.5 || Math.abs(gCy(t) - gCy(c)) > 0.5 || Math.abs(gCx(t) - gCx(c)) > 0.5;
|
|
129
|
+
if (cresceu) log.push('texto vazava do cartão: o cartão foi para ' + Math.round(w) + '×' + Math.round(h) + (ok ? '' : ' (no máximo; o texto ainda encosta)'));
|
|
130
|
+
return { k: k, cartao: nc, cresceu: cresceu, ok: ok, log: log };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/*
|
|
134
|
+
* gConsertar(itens, W, H, o) → { itens, log: [texto], trocar: bool, violacoes: [texto] }
|
|
135
|
+
* o = { zona (gZona), folga, so: 'icones' (só move/encolhe/tira ícones e a foto: o kit, com o texto já posto), legenda,
|
|
136
|
+
* escalaMundo (layout → tela: a regra da foto 55–80% vale pro que se vê) }
|
|
137
|
+
* Cada item ganha: c (a caixa final), k (escala aplicada), dx/dy (deslocamento do centro), removido.
|
|
138
|
+
*/
|
|
139
|
+
function gConsertar(itens, W, H, o) {
|
|
140
|
+
o = o || {};
|
|
141
|
+
var z = o.zona || gZona(W, H, o), folga = o.folga != null ? o.folga : GUARDA.folga * Math.min(W, H) / 1080;
|
|
142
|
+
var log = [], trocar = false, i, j, a, b, alto = gAlto(W, H), lado = Math.min(W, H), soIcones = o.so == 'icones', em = o.escalaMundo || 1;
|
|
143
|
+
var L = [];
|
|
144
|
+
for (i = 0; i < itens.length; i++) { a = itens[i]; a.c0 = [a.c[0], a.c[1], a.c[2], a.c[3]]; a.removido = false; L.push(a); }
|
|
145
|
+
var pode = function (it) { return !it.fixo && (!soIcones || it.tipo == 'icone' || it.movel); };
|
|
146
|
+
|
|
147
|
+
// 1. tamanho por tipo
|
|
148
|
+
for (i = 0; i < L.length; i++) {
|
|
149
|
+
a = L[i];
|
|
150
|
+
if (!pode(a)) continue;
|
|
151
|
+
if (a.tipo == 'texto' && gW(a.c) > W * GUARDA.textoMaxL) { a.c = gEscala(a.c, W * GUARDA.textoMaxL / gW(a.c)); log.push('texto largo: ' + gNome(a) + ' encolheu para ' + Math.round(GUARDA.textoMaxL * 100) + '% da largura'); }
|
|
152
|
+
if (a.tipo == 'icone') {
|
|
153
|
+
var s = Math.max(gW(a.c), gH(a.c)) / (a.infla || 1);
|
|
154
|
+
if (s > lado * GUARDA.iconeMax) { a.c = gEscala(a.c, lado * GUARDA.iconeMax / s); log.push('ícone gigante: ' + gNome(a) + ' de ' + Math.round(s) + ' px para ' + Math.round(lado * GUARDA.iconeMax) + ' px'); }
|
|
155
|
+
else if (s < lado * GUARDA.iconeMin) { a.c = gEscala(a.c, lado * GUARDA.iconeMin / s); log.push('ícone pequeno: ' + gNome(a) + ' cresceu para ' + Math.round(lado * GUARDA.iconeMin) + ' px'); }
|
|
156
|
+
}
|
|
157
|
+
if (a.tipo == 'foto' && alto) {
|
|
158
|
+
var fw = gW(a.c) / (a.infla || 1) * em; // no MUNDO: a regra é sobre o que o espectador vê
|
|
159
|
+
if (fw < W * GUARDA.fotoMin - 0.5) { a.c = gEscala(a.c, W * GUARDA.fotoMin / fw); log.push('foto pequena: ' + Math.round(fw / W * 100) + '% da largura, cresceu para ' + Math.round(GUARDA.fotoMin * 100) + '%'); }
|
|
160
|
+
else if (fw > W * GUARDA.fotoMax + 0.5) { a.c = gEscala(a.c, W * GUARDA.fotoMax / fw); log.push('foto gigante: ' + Math.round(fw / W * 100) + '% da largura, encolheu para ' + Math.round(GUARDA.fotoMax * 100) + '%'); }
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// 2. zona segura (e o trilho de botões do 9:16)
|
|
164
|
+
for (i = 0; i < L.length; i++) {
|
|
165
|
+
a = L[i];
|
|
166
|
+
if (!pode(a) || a.livre) continue;
|
|
167
|
+
var antes = a.c;
|
|
168
|
+
if (!gCabe(a.c, z)) a.c = gEncaixa(a.c, z);
|
|
169
|
+
if (gNoTrilho(a.c, z) && (a.tipo == 'icone' || a.tipo == 'foto')) {
|
|
170
|
+
var nx = gMove(a.c, z.trilho[0] - folga * 0.5 - a.c[2], 0);
|
|
171
|
+
if (gCabe(nx, z)) a.c = nx; else { var ny = gMove(a.c, 0, z.trilho[1] - a.c[3]); if (gCabe(ny, z)) a.c = ny; }
|
|
172
|
+
}
|
|
173
|
+
if (antes !== a.c) log.push('fora da zona segura: ' + gNome(a) + ' ' + gTxt(antes) + ' → ' + gTxt(a.c));
|
|
174
|
+
}
|
|
175
|
+
// 3. texto × foto/cartão: afasta (a foto sobe ou desce; ou o texto), depois encolhe a foto até o mínimo; senão, troca a peça
|
|
176
|
+
for (i = 0; i < L.length; i++) {
|
|
177
|
+
a = L[i];
|
|
178
|
+
if (a.tipo != 'texto') continue;
|
|
179
|
+
for (j = 0; j < L.length; j++) {
|
|
180
|
+
b = L[j];
|
|
181
|
+
if (b === a || (b.tipo != 'foto' && b.tipo != 'cartao') || !gToca(a.c, b.c, folga)) continue;
|
|
182
|
+
var feito = false, tentativa;
|
|
183
|
+
if (pode(b)) { // a foto vai para o lado oposto ao do texto
|
|
184
|
+
var cima = gCy(b.c) <= gCy(a.c);
|
|
185
|
+
for (tentativa = 0; tentativa < 12 && !feito; tentativa++) {
|
|
186
|
+
var nb = cima ? gMove(b.c, 0, a.c[1] - folga - b.c[3]) : gMove(b.c, 0, a.c[3] + folga - b.c[1]);
|
|
187
|
+
if (gCabe(nb, z)) { log.push('texto encostado na foto: ' + gNome(b) + ' foi para ' + (cima ? 'cima' : 'baixo') + (tentativa ? ' (encolhida ' + Math.round(gW(b.c) / W * 100) + '%)' : '')); b.c = nb; feito = true; break; }
|
|
188
|
+
var min = b.tipo == 'foto' && alto ? W * GUARDA.fotoMin * (b.infla || 1) / em : gW(b.c0) * 0.6;
|
|
189
|
+
if (gW(b.c) * 0.94 < min) break;
|
|
190
|
+
b.c = gEscala(b.c, 0.94);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (!feito && pode(a)) {
|
|
194
|
+
var embaixo = gCy(a.c) >= gCy(b.c);
|
|
195
|
+
var na = embaixo ? gMove(a.c, 0, b.c[3] + folga - a.c[1]) : gMove(a.c, 0, b.c[1] - folga - a.c[3]);
|
|
196
|
+
if (gCabe(na, z)) { log.push('texto encostado em ' + gNome(b) + ': o texto foi para ' + (embaixo ? 'baixo' : 'cima')); a.c = na; feito = true; }
|
|
197
|
+
}
|
|
198
|
+
if (!feito) { trocar = true; log.push('não coube: ' + gNome(a) + ' e ' + gNome(b) + ' se sobrepõem sem saída: troca a peça'); }
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// 3b. cursor: nunca em cima de letra; a ponta continua dentro do alvo (o botão), a setinha vai para a borda ou depois do texto
|
|
202
|
+
var textosC = [];
|
|
203
|
+
for (i = 0; i < L.length; i++) if (L[i].tipo == 'texto' && !L[i].removido) textosC.push(L[i].c);
|
|
204
|
+
for (i = 0; i < L.length; i++) {
|
|
205
|
+
a = L[i];
|
|
206
|
+
if (a.tipo != 'cursor' || !a.alvo) continue;
|
|
207
|
+
var bateC = false;
|
|
208
|
+
for (j = 0; j < textosC.length; j++) if (gToca(a.c, textosC[j], folga * 0.25)) bateC = true;
|
|
209
|
+
if (!bateC) continue;
|
|
210
|
+
var rc = gCursor(a.alvo, textosC, { w: gW(a.c) - 3, h: gH(a.c) - 3, folga: folga * 0.25, pilula: a.pilula !== false });
|
|
211
|
+
log.push('cursor sobre o texto: ' + gNome(a) + ' ' + gTxt(a.c) + ' → ' + gTxt(rc.c) + (rc.ok ? '' : ' (na borda do botão)'));
|
|
212
|
+
a.c = rc.c; a.ponta = rc.ponta;
|
|
213
|
+
}
|
|
214
|
+
// 4. ícones: nunca sobre texto, foto/rosto, cartão ou outro ícone; acha um lugar livre, encolhe até o mínimo, ou sai
|
|
215
|
+
var ordem = [];
|
|
216
|
+
for (i = 0; i < L.length; i++) if (L[i].tipo == 'icone') ordem.push(L[i]);
|
|
217
|
+
ordem.sort(function (p, q) { return (q.prio || 0) - (p.prio || 0); });
|
|
218
|
+
var ocupado = [];
|
|
219
|
+
for (i = 0; i < L.length; i++) if (L[i].tipo != 'icone') ocupado.push(L[i].c);
|
|
220
|
+
for (i = 0; i < ordem.length; i++) {
|
|
221
|
+
a = ordem[i];
|
|
222
|
+
var bate = !gCabe(a.c, z) || gNoTrilho(a.c, z), quem = '';
|
|
223
|
+
for (j = 0; !bate && j < ocupado.length; j++) if (gToca(a.c, ocupado[j], folga)) bate = true;
|
|
224
|
+
if (!bate) { ocupado.push(a.c); continue; }
|
|
225
|
+
if (!pode(a)) { log.push('ícone fixo sobreposto: ' + gNome(a)); continue; }
|
|
226
|
+
for (j = 0; j < L.length; j++) if (L[j] !== a && !L[j].removido && L[j].tipo != 'icone' && gToca(a.c, L[j].c, folga)) { quem = L[j].tipo == 'texto' ? 'o texto' : (L[j].tipo == 'foto' ? 'a foto' : gNome(L[j])); break; }
|
|
227
|
+
var w = gW(a.c), h = gH(a.c), achou = null, k = 1, s0 = Math.max(w, h) / (a.infla || 1), minK = Math.min(1, lado * GUARDA.iconeMin / s0);
|
|
228
|
+
while (!achou && k >= minK - 0.001) {
|
|
229
|
+
achou = gLugarLivre(gCx(a.c), gCy(a.c), w * k, h * k, z, ocupado, folga, W);
|
|
230
|
+
if (!achou) k = k > minK + 0.001 ? Math.max(minK, k * 0.85) : minK - 1;
|
|
231
|
+
}
|
|
232
|
+
if (achou) {
|
|
233
|
+
log.push('ícone ' + (quem ? 'sobre ' + quem : 'fora do lugar') + ': ' + gNome(a) + ' ' + gTxt(a.c) + ' → ' + gTxt(achou) + (k < 0.999 ? ' (encolhido ' + Math.round(k * 100) + '%)' : ''));
|
|
234
|
+
a.c = achou; ocupado.push(achou);
|
|
235
|
+
} else { a.removido = true; log.push('ícone sem lugar livre' + (quem ? ' (estava sobre ' + quem + ')' : '') + ': ' + gNome(a) + ' saiu'); }
|
|
236
|
+
}
|
|
237
|
+
// 5. lotação: no máximo N ao mesmo tempo (sai o ícone de menor prioridade)
|
|
238
|
+
var vivos = 0;
|
|
239
|
+
for (i = 0; i < L.length; i++) if (!L[i].removido) vivos++;
|
|
240
|
+
for (i = ordem.length - 1; i >= 0 && vivos > (o.maxSimult || GUARDA.maxSimult); i--) {
|
|
241
|
+
if (ordem[i].removido || !pode(ordem[i])) continue;
|
|
242
|
+
ordem[i].removido = true; vivos--; log.push('elementos demais na cena: ' + gNome(ordem[i]) + ' saiu');
|
|
243
|
+
}
|
|
244
|
+
for (i = 0; i < L.length; i++) {
|
|
245
|
+
a = L[i];
|
|
246
|
+
a.k = gW(a.c) / Math.max(1e-6, gW(a.c0));
|
|
247
|
+
a.dx = gCx(a.c) - gCx(a.c0); a.dy = gCy(a.c) - gCy(a.c0);
|
|
248
|
+
}
|
|
249
|
+
return { itens: L, log: log, trocar: trocar, violacoes: gVerificar(L, W, H, { zona: z, folga: folga * 0.5 }) };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/* Só confere (não mexe): o que ainda viola. É a conferência por caixa quando não há olho (Vision) depois do render. */
|
|
253
|
+
function gVerificar(itens, W, H, o) {
|
|
254
|
+
o = o || {};
|
|
255
|
+
var z = o.zona || gZona(W, H, o), folga = o.folga != null ? o.folga : 0, v = [], i, j, a, b;
|
|
256
|
+
for (i = 0; i < itens.length; i++) {
|
|
257
|
+
a = itens[i];
|
|
258
|
+
if (a.removido || a.livre) continue;
|
|
259
|
+
if (!gCabe(a.c, { x0: z.x0 - 6, x1: z.x1 + 6, y0: z.y0 - 6, y1: z.y1 + 6 })) v.push('fora da zona segura: ' + gNome(a) + ' ' + gTxt(a.c));
|
|
260
|
+
else if ((a.tipo == 'icone' || a.tipo == 'foto') && gNoTrilho(a.c, z)) v.push('no trilho de botões: ' + gNome(a));
|
|
261
|
+
for (j = i + 1; j < itens.length; j++) {
|
|
262
|
+
b = itens[j];
|
|
263
|
+
if (b.removido || b.livre) continue;
|
|
264
|
+
if (a.tipo == 'texto' && b.tipo == 'texto') continue; // texto × texto: quem confere é o kit (tempos diferentes)
|
|
265
|
+
if (a.tipo == 'cursor' || b.tipo == 'cursor') { // o cursor só não pode cobrir letra
|
|
266
|
+
if ((a.tipo == 'texto' || b.tipo == 'texto') && gToca(a.c, b.c, 0)) v.push('cursor sobre o texto: ' + gNome(a.tipo == 'cursor' ? b : a));
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if ((a.tipo == 'cartao' && b.tipo == 'cartao')) continue;
|
|
270
|
+
if (gToca(a.c, b.c, folga - 1e-6) && (a.tipo == 'texto' || b.tipo == 'texto' || a.tipo == 'icone' || b.tipo == 'icone')) v.push('sobreposição: ' + gNome(a) + ' × ' + gNome(b));
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return v;
|
|
274
|
+
}
|