primocode 8.38.1 → 8.40.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/lib/act.js +87 -2
- package/lib/audio-livre.js +172 -0
- package/lib/catalogo.js +7 -0
- package/lib/marca.js +280 -0
- package/lib/referencia.js +210 -63
- package/lib/remotion.js +245 -45
- package/lib/studio.js +76 -3
- package/lib/tools.js +13 -0
- package/package.json +2 -2
- package/studio/__pycache__/edge.cpython-311.pyc +0 -0
- package/studio/__pycache__/elevenlabs.cpython-311.pyc +0 -0
- package/studio/arquivos/tela-motion-3ecaa.json +135 -0
- package/studio/arquivos/tela-motion-d6150.json +135 -0
- package/studio/edge.py +66 -16
- package/studio/ferramentas/01-modelos.md +20 -2
- package/studio/ferramentas/corte.md +140 -35
- package/studio/ferramentas/tela.md +21 -0
- package/studio/server.py +47 -11
- package/studio/studio.log +28 -0
- package/studio/web/js/player.js +30 -2
- package/studio/web/js/render.js +74 -4
- package/studio/web/js/sfx.js +128 -2
- package/studio/web/render.css +95 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "tela-motion-d6150",
|
|
3
|
+
"ferramenta": "tela",
|
|
4
|
+
"titulo": "motion",
|
|
5
|
+
"doc": {
|
|
6
|
+
"tema": "meia-noite",
|
|
7
|
+
"largura": 1920,
|
|
8
|
+
"altura": 1080,
|
|
9
|
+
"cenas": [
|
|
10
|
+
{
|
|
11
|
+
"layout": "livre",
|
|
12
|
+
"duracao": 6,
|
|
13
|
+
"fundo": "aurora",
|
|
14
|
+
"elementos": [
|
|
15
|
+
{
|
|
16
|
+
"tipo": "forma",
|
|
17
|
+
"forma": "circulo",
|
|
18
|
+
"x": 1250,
|
|
19
|
+
"y": 120,
|
|
20
|
+
"l": 520,
|
|
21
|
+
"a": 520,
|
|
22
|
+
"preenchimento": "#ff5a36",
|
|
23
|
+
"opacidade": 0.9
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"tipo": "forma",
|
|
27
|
+
"forma": "retangulo",
|
|
28
|
+
"material": "vidro",
|
|
29
|
+
"x": 120,
|
|
30
|
+
"y": 140,
|
|
31
|
+
"l": 860,
|
|
32
|
+
"a": 420,
|
|
33
|
+
"raio": 36,
|
|
34
|
+
"preenchimento": "#22d3ee"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"tipo": "texto",
|
|
38
|
+
"x": 170,
|
|
39
|
+
"y": 190,
|
|
40
|
+
"l": 760,
|
|
41
|
+
"a": 120,
|
|
42
|
+
"texto": "Liquid glass de verdade",
|
|
43
|
+
"tamanho": 74,
|
|
44
|
+
"peso": 750
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"tipo": "texto",
|
|
48
|
+
"x": 170,
|
|
49
|
+
"y": 330,
|
|
50
|
+
"l": 760,
|
|
51
|
+
"a": 60,
|
|
52
|
+
"texto": "desfoca o que está atrás, bisel em cima",
|
|
53
|
+
"tamanho": 34,
|
|
54
|
+
"cor": "#bfe9f4"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"tipo": "texto",
|
|
58
|
+
"material": "vidro",
|
|
59
|
+
"x": 170,
|
|
60
|
+
"y": 430,
|
|
61
|
+
"l": 420,
|
|
62
|
+
"a": 70,
|
|
63
|
+
"texto": "pílula de vidro",
|
|
64
|
+
"tamanho": 32
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"tipo": "icone",
|
|
68
|
+
"nome": "foguete",
|
|
69
|
+
"estilo": "app",
|
|
70
|
+
"x": 1130,
|
|
71
|
+
"y": 640,
|
|
72
|
+
"tamanho": 220,
|
|
73
|
+
"fundo": "#8b5cf6",
|
|
74
|
+
"som": "pop"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"tipo": "icone",
|
|
78
|
+
"nome": "raio",
|
|
79
|
+
"estilo": "vidro",
|
|
80
|
+
"x": 1400,
|
|
81
|
+
"y": 640,
|
|
82
|
+
"tamanho": 220,
|
|
83
|
+
"cor": "#ffb03a"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"tipo": "objeto3d",
|
|
87
|
+
"forma": "cubo",
|
|
88
|
+
"x": 620,
|
|
89
|
+
"y": 620,
|
|
90
|
+
"tamanho": 260,
|
|
91
|
+
"girar": 0,
|
|
92
|
+
"faces": [
|
|
93
|
+
"IA",
|
|
94
|
+
"3D",
|
|
95
|
+
"Motion",
|
|
96
|
+
"Vidro",
|
|
97
|
+
"Som",
|
|
98
|
+
"Marca"
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"tipo": "texto",
|
|
103
|
+
"x": 120,
|
|
104
|
+
"y": 700,
|
|
105
|
+
"l": 400,
|
|
106
|
+
"a": 100,
|
|
107
|
+
"texto": "chaves 3D",
|
|
108
|
+
"tamanho": 60,
|
|
109
|
+
"peso": 700,
|
|
110
|
+
"chaves": [
|
|
111
|
+
{
|
|
112
|
+
"t": 0,
|
|
113
|
+
"giroY": -60,
|
|
114
|
+
"opacidade": 0,
|
|
115
|
+
"x": -200
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"t": 0.4,
|
|
119
|
+
"giroY": 0,
|
|
120
|
+
"opacidade": 1,
|
|
121
|
+
"x": 0
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"t": 1,
|
|
125
|
+
"giroY": 20
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
"suavizar": "elastico"
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
},
|
|
134
|
+
"atualizado": "2026-09-09T12:31:01+00:00"
|
|
135
|
+
}
|
package/studio/edge.py
CHANGED
|
@@ -117,32 +117,81 @@ def disponivel():
|
|
|
117
117
|
return _verificado
|
|
118
118
|
|
|
119
119
|
|
|
120
|
+
# Por que a instalação falhava calada, e o vídeo saía com a voz do Google:
|
|
121
|
+
# `pip install --user` é recusado pelo Python do sistema em Debian/Ubuntu e
|
|
122
|
+
# no do Homebrew ("externally-managed-environment", PEP 668), e em máquina
|
|
123
|
+
# sem pip o `-m pip` nem existe. Um `pip install` só, em segundo plano, com a
|
|
124
|
+
# saída jogada fora, era exatamente a falha que ninguém vê. Agora são várias
|
|
125
|
+
# tentativas, em ordem, e a última linha do erro de cada uma fica guardada
|
|
126
|
+
# para o status contar o que houve.
|
|
127
|
+
ESTRATEGIAS = [
|
|
128
|
+
["-m", "pip", "install", "--user", "--quiet", "edge-tts"],
|
|
129
|
+
["-m", "pip", "install", "--user", "--quiet", "--break-system-packages", "edge-tts"],
|
|
130
|
+
["-m", "pip", "install", "--quiet", "edge-tts"],
|
|
131
|
+
["-m", "pip", "install", "--quiet", "--break-system-packages", "edge-tts"],
|
|
132
|
+
]
|
|
133
|
+
_ultimo_erro = ""
|
|
134
|
+
_thread = None
|
|
135
|
+
|
|
136
|
+
|
|
120
137
|
def _rotina_instalar():
|
|
121
|
-
global _instalando, _verificado
|
|
138
|
+
global _instalando, _verificado, _ultimo_erro
|
|
122
139
|
try:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
140
|
+
# Sem pip, primeiro o ensurepip — é o que o python.org e a Apple
|
|
141
|
+
# trazem para o caso.
|
|
142
|
+
try:
|
|
143
|
+
r = subprocess.run([sys.executable, "-m", "pip", "--version"],
|
|
144
|
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=30)
|
|
145
|
+
if r.returncode != 0:
|
|
146
|
+
subprocess.run([sys.executable, "-m", "ensurepip", "--user", "--default-pip"],
|
|
147
|
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=120)
|
|
148
|
+
except Exception:
|
|
149
|
+
pass
|
|
150
|
+
for args in ESTRATEGIAS:
|
|
151
|
+
try:
|
|
152
|
+
r = subprocess.run([sys.executable] + args, stdout=subprocess.DEVNULL,
|
|
153
|
+
stderr=subprocess.PIPE, timeout=240)
|
|
154
|
+
except Exception as e:
|
|
155
|
+
_ultimo_erro = str(e)[-200:]
|
|
156
|
+
continue
|
|
157
|
+
_verificado = None
|
|
158
|
+
if r.returncode == 0 and disponivel():
|
|
159
|
+
_ultimo_erro = ""
|
|
160
|
+
sys.stderr.write("[edge] edge-tts instalado (%s)\n" % " ".join(args[2:]))
|
|
161
|
+
return
|
|
162
|
+
_ultimo_erro = (r.stderr or b"").decode("utf-8", "replace").strip().splitlines()[-1:][0][-200:] \
|
|
163
|
+
if (r.stderr or b"").strip() else "pip devolveu %s" % r.returncode
|
|
164
|
+
sys.stderr.write("[edge] não consegui instalar o edge-tts: %s\n" % _ultimo_erro)
|
|
128
165
|
finally:
|
|
129
166
|
_verificado = None # força nova checagem
|
|
130
167
|
with _tranca:
|
|
131
168
|
_instalando = False
|
|
132
169
|
|
|
133
170
|
|
|
134
|
-
def instalar():
|
|
135
|
-
"""
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
171
|
+
def instalar(esperar=0):
|
|
172
|
+
"""Traz o pacote — em segundo plano por padrão; com `esperar` (segundos),
|
|
173
|
+
quem chamou fica aguardando até esse teto.
|
|
174
|
+
|
|
175
|
+
Esperar existe porque a narração de um vídeo NÃO pode sair pela voz de
|
|
176
|
+
reserva só porque o pip ainda estava rodando: quem pede voz agora e tem
|
|
177
|
+
internet merece a voz neural agora. Meio minuto de pip é menos ruim que
|
|
178
|
+
um vídeo inteiro com voz de robô."""
|
|
179
|
+
global _instalando, _thread
|
|
139
180
|
if disponivel():
|
|
140
|
-
return
|
|
181
|
+
return True
|
|
141
182
|
with _tranca:
|
|
142
|
-
if _instalando:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
183
|
+
if not _instalando:
|
|
184
|
+
_instalando = True
|
|
185
|
+
_thread = threading.Thread(target=_rotina_instalar, daemon=True)
|
|
186
|
+
_thread.start()
|
|
187
|
+
t = _thread
|
|
188
|
+
if t and esperar:
|
|
189
|
+
t.join(esperar)
|
|
190
|
+
return disponivel()
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def ultimo_erro():
|
|
194
|
+
return _ultimo_erro
|
|
146
195
|
|
|
147
196
|
|
|
148
197
|
def _dur_do_vtt(caminho):
|
|
@@ -215,6 +264,7 @@ def estado():
|
|
|
215
264
|
"motor": "edge",
|
|
216
265
|
"disponivel": disponivel(),
|
|
217
266
|
"instalando": inst,
|
|
267
|
+
"erro": _ultimo_erro or None,
|
|
218
268
|
"precisa_internet": True,
|
|
219
269
|
"vozes": [{"id": v["id"], "nome": v["nome"], "genero": v["genero"],
|
|
220
270
|
"padrao": bool(v.get("padrao"))} for v in CATALOGO],
|
|
@@ -89,12 +89,22 @@ um elemento flutuando por cima do layout.
|
|
|
89
89
|
// path SVG numa caixa 24×24 (string ou lista de strings), no traço da casa
|
|
90
90
|
{ "tipo":"icone", "nome":"raio", "tamanho":120, "cor":"#ffb03a" }
|
|
91
91
|
{ "tipo":"icone", "caminho":"M3 6h18l-2 10H5zM8 20h.01M16 20h.01", "tamanho":96 }
|
|
92
|
+
// como OBJETO: estilo "app" (azulejo de aplicativo) ou "vidro" (liquid glass)
|
|
93
|
+
{ "tipo":"icone", "nome":"foguete", "estilo":"app", "tamanho":200, "fundo":"#8b5cf6" }
|
|
92
94
|
|
|
93
95
|
// FORMA
|
|
94
96
|
{ "tipo":"forma", "forma":"retangulo", "x":200,"y":200,"l":400,"a":220,
|
|
95
97
|
"preenchimento":"#ff5a36", "raio":24, "rotacao":-4, "opacidade":0.9 }
|
|
96
98
|
// forma: retangulo | circulo | triangulo | linha | seta
|
|
97
99
|
|
|
100
|
+
// MATERIAL — em qualquer elemento: "vidro" é o liquid glass (desfoca o que
|
|
101
|
+
// está atrás, bisel de luz, reflexo). Na forma, preenchimento vira a tinta.
|
|
102
|
+
{ "tipo":"forma", "forma":"retangulo", "material":"vidro", "raio":32, "x":100,"y":100,"l":800,"a":400 }
|
|
103
|
+
|
|
104
|
+
// SOM — no elemento, toca quando ele entra: whoosh | impacto | click | pop |
|
|
105
|
+
// ding | subida | tique | brilho, ou {"arquivo":"/midia/x.mp3","volume":0.8}
|
|
106
|
+
{ "tipo":"numeros", "itens":["+38% | em 12 meses"], "contar":true, "som":"ding" }
|
|
107
|
+
|
|
98
108
|
// CÓDIGO
|
|
99
109
|
{ "tipo":"codigo", "texto":"npm install primocode" }
|
|
100
110
|
|
|
@@ -186,8 +196,16 @@ completa em segundos (`0` deixa parado no `angulo` dado), `inclinar` levanta
|
|
|
186
196
|
ou baixa a câmera, `cores` pinta face a face.
|
|
187
197
|
|
|
188
198
|
Aceita `chaves` como qualquer elemento: dá para o cubo atravessar a cena
|
|
189
|
-
girando. Use **um** por cena — dois objetos girando disputam o olho.
|
|
190
|
-
|
|
199
|
+
girando. Use **um** por cena — dois objetos girando disputam o olho.
|
|
200
|
+
|
|
201
|
+
### Chaves de animação (motion)
|
|
202
|
+
|
|
203
|
+
`chaves` em qualquer elemento: instantes de `t` 0 a 1 com `x`, `y`
|
|
204
|
+
(deslocamento), `escala`, `escalaX`, `escalaY`, `giro`, **`giroX`, `giroY`,
|
|
205
|
+
`prof`** (3D: vira em profundidade, aproxima da câmera), `opacidade`,
|
|
206
|
+
`desfoque`. No elemento: `suavizar` (`suave` · `linear` · `entrada` · `saida`
|
|
207
|
+
· `elastico` · `salto` · `degrau`), `repetir`, `vaiEVolta`. A spec do Corte
|
|
208
|
+
tem os exemplos.
|
|
191
209
|
|
|
192
210
|
### Mídia do computador
|
|
193
211
|
|
|
@@ -181,40 +181,63 @@ narração, e uma disputa com quem fala em qualquer outro caso.
|
|
|
181
181
|
`src` vem de `POST /api/midia` (upload) ou é uma URL direta de áudio.
|
|
182
182
|
`inicio` pula os primeiros segundos da faixa.
|
|
183
183
|
|
|
184
|
-
|
|
185
|
-
plataformas e o direito autoral da faixa. Use música do próprio usuário, faixa
|
|
186
|
-
livre de direitos, ou uma das trilhas geradas acima.
|
|
184
|
+
### Música da internet, com licença (`buscar_audio`)
|
|
187
185
|
|
|
188
|
-
|
|
186
|
+
Uma faixa de verdade, tocada por gente, sem o usuário ter arquivo nenhum:
|
|
187
|
+
`buscar_audio` procura no Openverse (Jamendo, Freesound, Wikimedia — licenças
|
|
188
|
+
Creative Commons que permitem uso, inclusive comercial), **baixa** a melhor e
|
|
189
|
+
devolve a URL `/midia/…` pronta:
|
|
189
190
|
|
|
190
|
-
|
|
191
|
+
```
|
|
192
|
+
buscar_audio { "consulta": "upbeat corporate", "duracao": 30 }
|
|
193
|
+
→ url "/midia/corporate-succes-8c2911.mp3", licenca "CC BY-SA",
|
|
194
|
+
credito "Corporate Succes — Arkadii Kaplan (CC BY-SA 3.0, via jamendo)"
|
|
195
|
+
```
|
|
191
196
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
197
|
+
```json
|
|
198
|
+
"trilha": { "tipo": "arquivo", "src": "/midia/corporate-succes-8c2911.mp3", "volume": 0.55, "repetir": true }
|
|
199
|
+
```
|
|
195
200
|
|
|
196
|
-
|
|
201
|
+
Consulta **em inglês**, pelo clima: `upbeat corporate`, `calm piano`, `epic
|
|
202
|
+
cinematic`, `lofi chill`, `acoustic warm`. `duracao` é a do vídeo, para a faixa
|
|
203
|
+
combinar. Para efeitos, `"tipo": "efeito"` (`whoosh`, `click`, `ding`,
|
|
204
|
+
`swoosh`, `pop`) — a URL vai em `som: {"arquivo": …}`.
|
|
197
205
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
3. **O usuário quer mexer no código.** O projeto que nasce é React, é dele, e
|
|
204
|
-
entra no git.
|
|
206
|
+
**O crédito faz parte da peça.** Licença `CC BY`/`BY-SA` pede o crédito: ponha
|
|
207
|
+
a linha `credito` da resposta na assinatura ou numa legenda pequena da última
|
|
208
|
+
cena. `CC0` e domínio público não pedem nada. A resposta diz qual é o caso.
|
|
209
|
+
Quando a busca não acha nada, use a trilha **gerada** — nunca um "parecido"
|
|
210
|
+
de YouTube.
|
|
205
211
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
212
|
+
**Não baixe áudio de YouTube, Spotify ou similares** — quebra os termos dessas
|
|
213
|
+
plataformas e o direito autoral da faixa. Use `buscar_audio`, música do próprio
|
|
214
|
+
usuário ou uma das trilhas geradas acima.
|
|
209
215
|
|
|
210
|
-
|
|
211
|
-
`npm install` ter sido feito** — diga ao usuário os dois comandos e deixe ele
|
|
212
|
-
decidir se quer esperar.
|
|
216
|
+
---
|
|
213
217
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
+
## Studio E Remotion — os dois, mesclados
|
|
219
|
+
|
|
220
|
+
**Não é uma escolha.** O Studio é quem AUTORA e mostra: a cena, o motion, a
|
|
221
|
+
narração, a trilha gerada, os efeitos — o link "ver" é o vídeo, na hora. Quando
|
|
222
|
+
o usuário pede o ARQUIVO (`studio_exportar`), o PrimoCode renderiza a mesma
|
|
223
|
+
peça quadro a quadro pelo **Remotion** (instalado uma vez, sozinho, em
|
|
224
|
+
`~/.primocode/remotion`) — determinístico, sem perder quadro, com todas as
|
|
225
|
+
animações, chaves 3D, contagem e clipes no instante certo — e **mistura o
|
|
226
|
+
áudio do Studio** (narração, trilha, efeitos sintetizados) no MP4 final. Você
|
|
227
|
+
não escolhe motor: chama `studio_exportar` e recebe o arquivo.
|
|
228
|
+
|
|
229
|
+
O primeiro vídeo que saiu só do Remotion estava **mudo e parado** — animações
|
|
230
|
+
desligadas, só `trilha.src` como som. Foi por isso que a mescla existe: o
|
|
231
|
+
Remotion sozinho não tem a narração nem a trilha gerada; o Studio sozinho
|
|
232
|
+
grava em tempo real. Juntos, o arquivo sai como a prévia.
|
|
233
|
+
|
|
234
|
+
`remotion_projeto` (com o `id` da peça) é OUTRA coisa: gera o **projeto React**
|
|
235
|
+
na pasta do usuário, com as cenas, a mídia e o motion, para quem quer mexer no
|
|
236
|
+
código, versionar no git ou renderizar em servidor. Só quando o usuário pedir
|
|
237
|
+
isso — não é o jeito de gerar o arquivo. O projeto nasce sem `node_modules`;
|
|
238
|
+
diga os dois comandos (`npm install`, `npm run render`) e deixe ele decidir. A
|
|
239
|
+
trilha **gerada** e os sons **sintetizados** não existem no projeto solto
|
|
240
|
+
(são WebAudio ao vivo): lá, use `buscar_audio` para ter a trilha em arquivo.
|
|
218
241
|
|
|
219
242
|
---
|
|
220
243
|
|
|
@@ -242,6 +265,15 @@ número, botão, detalhe, o cartão — e libera o fundo `"marca"`:
|
|
|
242
265
|
"tema": "claro"
|
|
243
266
|
```
|
|
244
267
|
|
|
268
|
+
**De onde vêm a cor e a logo: do site da empresa.** Antes de escrever a peça,
|
|
269
|
+
chame `marca_da_empresa { "nome": "PicPay" }` (ou `"site": "https://…"`). Ela
|
|
270
|
+
lê o site, baixa a logo para o estúdio e devolve `marca: {cor, logo}` pronta
|
|
271
|
+
para colar, mais a paleta, as fontes e a frase da empresa. Não chute cor de
|
|
272
|
+
marca nem peça o arquivo ao usuário antes de tentar isso — a logo está no
|
|
273
|
+
site. Só quando a tool não achar (site montado por JavaScript, sem logo
|
|
274
|
+
baixável) é que se pede o arquivo (`studio_midia`) ou se assina com o nome em
|
|
275
|
+
texto.
|
|
276
|
+
|
|
245
277
|
Tema CLARO na maioria dos anúncios de marca. O escuro é para a cena de
|
|
246
278
|
produto e para a vitrine; o resto da peça respira no branco.
|
|
247
279
|
|
|
@@ -423,11 +455,38 @@ cena e a série ganha movimento sem esforço. `opcoes` marca a alternativa
|
|
|
423
455
|
`certa` com ✓ (não escreva o ✓ no texto: ele vem sozinho). Alternativa faz o
|
|
424
456
|
espectador pensar antes da resposta, e pensar é o que segura alguém no vídeo.
|
|
425
457
|
|
|
426
|
-
### Vidro
|
|
458
|
+
### Vidro — o liquid glass, em qualquer elemento
|
|
427
459
|
|
|
428
|
-
`"
|
|
429
|
-
|
|
430
|
-
|
|
460
|
+
`"material": "vidro"` em **qualquer** elemento: texto vira pílula de vidro,
|
|
461
|
+
`forma` vira painel, `imagem` ganha moldura, `lista`/`cartoes`/`numeros`
|
|
462
|
+
ganham fundo. É vidro de verdade: **desfoca o que está atrás** (o fundo
|
|
463
|
+
`aurora`, a foto, o círculo colorido), tem o bisel de luz em cima e a sombra
|
|
464
|
+
embaixo, e o reflexo diagonal atravessa devagar durante a cena.
|
|
465
|
+
|
|
466
|
+
```json
|
|
467
|
+
{ "tipo": "forma", "forma": "retangulo", "material": "vidro", "raio": 36,
|
|
468
|
+
"x": 120, "y": 140, "l": 860, "a": 420, "preenchimento": "#22d3ee" }
|
|
469
|
+
{ "tipo": "texto", "material": "vidro", "texto": "pílula de vidro", "tamanho": 32 }
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
Na forma, `preenchimento` vira a **tinta** do vidro (fraca) — não pinta o
|
|
473
|
+
fundo. `raio` arredonda (padrão 28). **Ponha algo atrás**: vidro sobre fundo
|
|
474
|
+
liso é só um retângulo claro; sobre `aurora`, `brilho`, uma foto ou uma forma
|
|
475
|
+
colorida, é o efeito. `"estilo": "vidro"` em `cartoes` continua valendo.
|
|
476
|
+
|
|
477
|
+
### Ícone como objeto (`estilo: "app"` / `"vidro"`)
|
|
478
|
+
|
|
479
|
+
```json
|
|
480
|
+
{ "tipo": "icone", "nome": "foguete", "estilo": "app", "tamanho": 220, "fundo": "#8b5cf6" }
|
|
481
|
+
{ "tipo": "icone", "nome": "raio", "estilo": "vidro", "tamanho": 220, "cor": "#ffb03a" }
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
`app` é o azulejo de aplicativo: gradiente da cor, brilho na metade de cima,
|
|
485
|
+
sombra colorida embaixo, o traço branco. `vidro` é o mesmo azulejo em liquid
|
|
486
|
+
glass. `fundo` pinta o azulejo (sem ele, a cor do tema). Um ícone de traço
|
|
487
|
+
sozinho é sinal; no azulejo vira **coisa** — é o que se usa para "o app", "o
|
|
488
|
+
produto", "o recurso" numa cena de lançamento. Combina com `som: "pop"` na
|
|
489
|
+
entrada e com `chaves` de `giroY` para ele virar ao pousar.
|
|
431
490
|
|
|
432
491
|
---
|
|
433
492
|
|
|
@@ -647,11 +706,33 @@ Para controlar:
|
|
|
647
706
|
|
|
648
707
|
```json
|
|
649
708
|
"sfx": false // no documento: desliga todos os efeitos
|
|
650
|
-
{ "transicao": "deslizar", "
|
|
709
|
+
{ "transicao": "deslizar", "som": "impacto" } // na cena: força um efeito
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
Valores: `"whoosh"` · `"impacto"` · `"click"` · `"pop"` · `"ding"` ·
|
|
713
|
+
`"subida"` · `"tique"` · `"brilho"` · `"nenhum"`. (`sfx` na cena ainda vale;
|
|
714
|
+
`som` é o nome novo, o mesmo dos elementos.)
|
|
715
|
+
|
|
716
|
+
### Som por elemento — o que faz motion soar motion
|
|
717
|
+
|
|
718
|
+
`"som"` num **elemento** toca no instante em que ele entra (o mesmo atraso da
|
|
719
|
+
animação de entrada). É a diferença entre um slide animado e uma peça de
|
|
720
|
+
motion: o número faz **ding** ao aparecer, o ícone faz **pop** ao pousar, a
|
|
721
|
+
barra sobe com a **subida** (o riser) e o texto final chega com **brilho**.
|
|
722
|
+
|
|
723
|
+
```json
|
|
724
|
+
{ "tipo": "numeros", "itens": ["+38% | em 12 meses"], "contar": true, "som": "ding" }
|
|
725
|
+
{ "tipo": "icone", "nome": "foguete", "estilo": "app", "som": "pop" }
|
|
726
|
+
{ "tipo": "texto", "texto": "Agora.", "som": { "arquivo": "/midia/little-whoosh-3.mp3", "volume": 0.8 } }
|
|
727
|
+
{ "tipo": "texto", "texto": "3, 2, 1", "som": { "nome": "tique", "em": 1.5 } }
|
|
651
728
|
```
|
|
652
729
|
|
|
653
|
-
|
|
654
|
-
|
|
730
|
+
`som` aceita o nome, ou `{ "arquivo": "/midia/…", "volume": 0–1 }` para um
|
|
731
|
+
efeito baixado com `buscar_audio` (tipo `"efeito"`) ou enviado pelo usuário;
|
|
732
|
+
`"em"` (segundos na cena) força o instante. O arquivo entra no mesmo grafo da
|
|
733
|
+
trilha, então vai junto para o MP4. Regra: **um som por ideia, não por
|
|
734
|
+
elemento** — três ou quatro por vídeo; tudo apitando é ruído, e a narração
|
|
735
|
+
tem de continuar por cima.
|
|
655
736
|
|
|
656
737
|
---
|
|
657
738
|
|
|
@@ -684,8 +765,32 @@ Campos de uma chave, todos opcionais: `x` e `y` (**deslocamento** em pixels a
|
|
|
684
765
|
partir de onde o elemento está — não é posição absoluta), `escala` (1 = tamanho
|
|
685
766
|
normal), `giro` (graus), `opacidade` (0 a 1) e `desfoque` (pixels).
|
|
686
767
|
|
|
687
|
-
|
|
688
|
-
|
|
768
|
+
**Em 3D:** `giroY` e `giroX` (graus — o elemento vira em profundidade, como um
|
|
769
|
+
cartão girando na mão), `prof` (pixels — aproxima ou afasta da câmera) e
|
|
770
|
+
`escalaX`/`escalaY` (achatar num eixo só: a gota que pousa e se espalha).
|
|
771
|
+
|
|
772
|
+
```json
|
|
773
|
+
{ "tipo": "icone", "nome": "foguete", "estilo": "app", "tamanho": 220,
|
|
774
|
+
"chaves": [
|
|
775
|
+
{ "t": 0, "giroY": -90, "prof": -400, "opacidade": 0 },
|
|
776
|
+
{ "t": 0.35, "giroY": 0, "prof": 0, "opacidade": 1 },
|
|
777
|
+
{ "t": 1, "giroY": 12 }
|
|
778
|
+
], "suavizar": "elastico", "som": "pop" }
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
**A curva** (`suavizar`, no elemento): `"suave"` (padrão) · `"linear"` ·
|
|
782
|
+
`"entrada"` (acelera) · `"saida"` (freia) · `"elastico"` (passa do ponto e
|
|
783
|
+
volta — o pouso de app) · `"salto"` (recua, dispara e assenta) · `"degrau"`
|
|
784
|
+
(quadro a quadro, stop-motion). Aceita também um `cubic-bezier(…)` cru.
|
|
785
|
+
`"repetir": true` roda sem parar; com `"vaiEVolta": true` ele vai e volta em
|
|
786
|
+
vez de recomeçar — é a levitação de um objeto.
|
|
787
|
+
|
|
788
|
+
Um exemplo de cada coisa que motion pede — **entrar de lado, respirar, sair**:
|
|
789
|
+
|
|
790
|
+
```json
|
|
791
|
+
"chaves": [ { "t": 0, "x": -300, "opacidade": 0 }, { "t": 0.2, "x": 0, "opacidade": 1 },
|
|
792
|
+
{ "t": 0.85, "x": 0, "opacidade": 1 }, { "t": 1, "x": 120, "opacidade": 0 } ]
|
|
793
|
+
```
|
|
689
794
|
|
|
690
795
|
Duas chaves já bastam. Quem tem `chaves` ignora `anim` — as duas disputariam o
|
|
691
796
|
mesmo movimento, e a chave é mais específica. Use em **um ou dois** elementos
|
|
@@ -61,6 +61,27 @@ você controla cada `x`, `y`, `l`, `a` em pixels da tela.
|
|
|
61
61
|
`globo` `chave` `presente` `sino` `mapa` `dinheiro` `crescimento` `grafico` `balao`
|
|
62
62
|
`pasta` `livro` `play2` `check` `imagem` `codigo` `tabela` `lista`
|
|
63
63
|
|
|
64
|
+
## Vidro e ícone-objeto
|
|
65
|
+
|
|
66
|
+
`"material": "vidro"` em qualquer elemento é o liquid glass: painel
|
|
67
|
+
translúcido que **desfoca o que está atrás**, com bisel de luz em cima e
|
|
68
|
+
reflexo diagonal. Precisa de algo atrás (gradiente, forma colorida, foto) para
|
|
69
|
+
aparecer. Na forma, `preenchimento` vira a tinta do vidro.
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{ "tipo": "forma", "forma": "retangulo", "material": "vidro", "raio": 32,
|
|
73
|
+
"x": 86, "y": 300, "l": 908, "a": 380, "preenchimento": "#ff5a36" }
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`"estilo": "app"` no ícone faz o azulejo de aplicativo (gradiente da cor,
|
|
77
|
+
brilho, sombra, traço branco); `"estilo": "vidro"` faz o mesmo azulejo em
|
|
78
|
+
vidro. `fundo` pinta o azulejo. É o ícone de produto para capa e post de
|
|
79
|
+
lançamento:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{ "tipo": "icone", "nome": "foguete", "estilo": "app", "x": 86, "y": 120, "tamanho": 200, "fundo": "#8b5cf6" }
|
|
83
|
+
```
|
|
84
|
+
|
|
64
85
|
## Várias artes no mesmo arquivo
|
|
65
86
|
|
|
66
87
|
Cada item de `cenas` é uma prancha independente. Um carrossel de Instagram é um
|