morfeo 0.0.0-stage → 0.1.1

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.
Files changed (51) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +210 -2
  3. package/assets/fuentes/Anton.ttf +0 -0
  4. package/assets/fuentes/JetBrainsMono.ttf +0 -0
  5. package/assets/fuentes/Montserrat.ttf +0 -0
  6. package/bin/morfeo.mjs +184 -0
  7. package/bin/postinstall.mjs +10 -0
  8. package/index.d.ts +250 -0
  9. package/lib/config.mjs +284 -0
  10. package/lib/entorno.mjs +93 -0
  11. package/lib/guion.mjs +313 -0
  12. package/lib/imagenes.mjs +99 -0
  13. package/lib/index.mjs +15 -0
  14. package/lib/instalar.mjs +193 -0
  15. package/lib/navegador.mjs +64 -0
  16. package/lib/personajes.mjs +94 -0
  17. package/lib/render.mjs +312 -0
  18. package/lib/voces.mjs +122 -0
  19. package/lib/whisper.mjs +45 -0
  20. package/package.json +84 -5
  21. package/plantilla/assets/.gitkeep +0 -0
  22. package/plantilla/env.example +7 -0
  23. package/plantilla/escenas/Barras.tsx +15 -0
  24. package/plantilla/gitignore +4 -0
  25. package/plantilla/guiones/cachalote.mjs +24 -0
  26. package/plantilla/guiones/tutorial.mjs +16 -0
  27. package/plantilla/morfeo.config.mjs +43 -0
  28. package/plantilla/package.json +13 -0
  29. package/plantilla/videos.mjs +25 -0
  30. package/python/musica.py +221 -0
  31. package/python/preparar.py +268 -0
  32. package/python/requirements.txt +5 -0
  33. package/remotion/Root.tsx +35 -0
  34. package/remotion/Short.tsx +278 -0
  35. package/remotion/escenas.tsx +430 -0
  36. package/remotion/estilo.ts +73 -0
  37. package/remotion/iconos.ts +326 -0
  38. package/remotion/index.ts +4 -0
  39. package/remotion/motor/Video.tsx +121 -0
  40. package/remotion/motor/capas.tsx +622 -0
  41. package/remotion/motor/fondo.tsx +148 -0
  42. package/remotion/motor/modelo3d.tsx +252 -0
  43. package/remotion/motor/plantillas.tsx +125 -0
  44. package/remotion/motor/registro.ts +11 -0
  45. package/remotion/motor/subtitulos.tsx +137 -0
  46. package/remotion/motor/tema.ts +207 -0
  47. package/remotion/motor/util.ts +66 -0
  48. package/remotion/motor/widgets.tsx +248 -0
  49. package/remotion/piezas.tsx +181 -0
  50. package/remotion/tipos.ts +43 -0
  51. package/remotion/tres/Capa3D.tsx +153 -0
@@ -0,0 +1,326 @@
1
+ // Íconos pixel art originales (copiados del motor anterior). 1 = cuadro pintado.
2
+ export const ICONOS: Record<string, {color: string; grid: string[]}> = {
3
+ "question": {
4
+ "color": "#FFD400",
5
+ "grid": [
6
+ "01110",
7
+ "10001",
8
+ "00001",
9
+ "00110",
10
+ "00100",
11
+ "00000",
12
+ "00100"
13
+ ]
14
+ },
15
+ "warning": {
16
+ "color": "#FFD400",
17
+ "grid": [
18
+ "00000100000",
19
+ "00001110000",
20
+ "00011011000",
21
+ "00011011000",
22
+ "00111011100",
23
+ "00111011100",
24
+ "01111111110",
25
+ "01111011110",
26
+ "11111111111"
27
+ ]
28
+ },
29
+ "building": {
30
+ "color": "#96A5D2",
31
+ "grid": [
32
+ "1111111",
33
+ "1010101",
34
+ "1111111",
35
+ "1010101",
36
+ "1111111",
37
+ "1010101",
38
+ "1111111",
39
+ "1100011",
40
+ "1100011"
41
+ ]
42
+ },
43
+ "star": {
44
+ "color": "#FFD400",
45
+ "grid": [
46
+ "0001000",
47
+ "0001000",
48
+ "0011100",
49
+ "1111111",
50
+ "0111110",
51
+ "0011100",
52
+ "0110110",
53
+ "1100011"
54
+ ]
55
+ },
56
+ "alien": {
57
+ "color": "#78F0C8",
58
+ "grid": [
59
+ "0100010",
60
+ "0011100",
61
+ "0111110",
62
+ "1101011",
63
+ "1111111",
64
+ "0101010",
65
+ "1000001"
66
+ ]
67
+ },
68
+ "cloud": {
69
+ "color": "#FAFAFF",
70
+ "grid": [
71
+ "000111000",
72
+ "001111100",
73
+ "011111110",
74
+ "111111111",
75
+ "111111111",
76
+ "011111110"
77
+ ]
78
+ },
79
+ "joystick": {
80
+ "color": "#FF4050",
81
+ "grid": [
82
+ "0011100",
83
+ "0111110",
84
+ "0011100",
85
+ "0001000",
86
+ "0001000",
87
+ "0001000",
88
+ "1111111",
89
+ "1111111",
90
+ "1111111"
91
+ ]
92
+ },
93
+ "eye": {
94
+ "color": "#FFFFFF",
95
+ "grid": [
96
+ "0011100",
97
+ "0111110",
98
+ "1100011",
99
+ "1101011",
100
+ "1100011",
101
+ "0111110",
102
+ "0011100"
103
+ ]
104
+ },
105
+ "tblock": {
106
+ "color": "#AA5AFF",
107
+ "grid": [
108
+ "111",
109
+ "010"
110
+ ]
111
+ },
112
+ "car": {
113
+ "color": "#FF4050",
114
+ "grid": [
115
+ "0011110000",
116
+ "0110011000",
117
+ "1111111111",
118
+ "1111111111",
119
+ "0110000110"
120
+ ]
121
+ },
122
+ "fist": {
123
+ "color": "#F0BE96",
124
+ "grid": [
125
+ "0111100",
126
+ "1111110",
127
+ "1111111",
128
+ "1111111",
129
+ "0111111",
130
+ "0011110"
131
+ ]
132
+ },
133
+ "book": {
134
+ "color": "#BE8250",
135
+ "grid": [
136
+ "0111111",
137
+ "1100001",
138
+ "1101101",
139
+ "1100001",
140
+ "1101101",
141
+ "1100001",
142
+ "1111111"
143
+ ]
144
+ },
145
+ "computer": {
146
+ "color": "#CDCDD7",
147
+ "grid": [
148
+ "1111111",
149
+ "1000001",
150
+ "1000001",
151
+ "1000001",
152
+ "1111111",
153
+ "0001000",
154
+ "0111110"
155
+ ]
156
+ },
157
+ "cards": {
158
+ "color": "#FF4050",
159
+ "grid": [
160
+ "0011111",
161
+ "0010001",
162
+ "1111101",
163
+ "1000101",
164
+ "1010101",
165
+ "1000111",
166
+ "1111100"
167
+ ]
168
+ },
169
+ "coin": {
170
+ "color": "#FFD400",
171
+ "grid": [
172
+ "0011100",
173
+ "0110110",
174
+ "1101011",
175
+ "1101011",
176
+ "1101011",
177
+ "0110110",
178
+ "0011100"
179
+ ]
180
+ },
181
+ "truck": {
182
+ "color": "#CDCDD7",
183
+ "grid": [
184
+ "1111100000",
185
+ "1111111100",
186
+ "1111110110",
187
+ "1111111111",
188
+ "0110000110"
189
+ ]
190
+ },
191
+ "skull": {
192
+ "color": "#FFFFFF",
193
+ "grid": [
194
+ "0111110",
195
+ "1111111",
196
+ "1001001",
197
+ "1001001",
198
+ "1111111",
199
+ "0110110",
200
+ "0101010"
201
+ ]
202
+ },
203
+ "box": {
204
+ "color": "#C8A064",
205
+ "grid": [
206
+ "1111111",
207
+ "1000001",
208
+ "1111111",
209
+ "1010101",
210
+ "1000001",
211
+ "1111111"
212
+ ]
213
+ },
214
+ "fog": {
215
+ "color": "#AAAFBE",
216
+ "grid": [
217
+ "000111000",
218
+ "001111100",
219
+ "011111110",
220
+ "111111111",
221
+ "111111111",
222
+ "011111110"
223
+ ]
224
+ },
225
+ "pickaxe": {
226
+ "color": "#AFAFBE",
227
+ "grid": [
228
+ "0111110",
229
+ "1100011",
230
+ "0001000",
231
+ "0001000",
232
+ "0001000",
233
+ "0001000"
234
+ ]
235
+ },
236
+ "zap": {
237
+ "color": "#FFD400",
238
+ "grid": [
239
+ "0001110",
240
+ "0011100",
241
+ "0111000",
242
+ "1111110",
243
+ "0001100",
244
+ "0011000",
245
+ "0110000"
246
+ ]
247
+ },
248
+ "phone": {
249
+ "color": "#CDCDD7",
250
+ "grid": [
251
+ "11111",
252
+ "10001",
253
+ "10001",
254
+ "10001",
255
+ "10001",
256
+ "11111",
257
+ "11011"
258
+ ]
259
+ },
260
+ "camera": {
261
+ "color": "#B9B9C3",
262
+ "grid": [
263
+ "1111110",
264
+ "1111111",
265
+ "1111110",
266
+ "0011000",
267
+ "0011000",
268
+ "1111111"
269
+ ]
270
+ },
271
+ "mustache": {
272
+ "color": "#784628",
273
+ "grid": [
274
+ "0011001100",
275
+ "0111111110",
276
+ "1111111111",
277
+ "1111111111",
278
+ "1100000011"
279
+ ]
280
+ },
281
+ "cap": {
282
+ "color": "#FF4050",
283
+ "grid": [
284
+ "0011110000",
285
+ "0111111000",
286
+ "1111111100",
287
+ "1111111100",
288
+ "1111111111"
289
+ ]
290
+ },
291
+ "people": {
292
+ "color": "#78C8FF",
293
+ "grid": [
294
+ "0110110",
295
+ "0110110",
296
+ "0000000",
297
+ "1111111",
298
+ "1111111"
299
+ ]
300
+ },
301
+ "sword": {
302
+ "color": "#CDCDE1",
303
+ "grid": [
304
+ "0000011",
305
+ "0000111",
306
+ "0001110",
307
+ "1011100",
308
+ "0111000",
309
+ "0110000",
310
+ "1001000"
311
+ ]
312
+ },
313
+ "trophy": {
314
+ "color": "#FFD400",
315
+ "grid": [
316
+ "1111111",
317
+ "1111111",
318
+ "0111110",
319
+ "0111110",
320
+ "0011100",
321
+ "0001000",
322
+ "0011100",
323
+ "0111110"
324
+ ]
325
+ }
326
+ };
@@ -0,0 +1,4 @@
1
+ import {registerRoot} from 'remotion';
2
+ import {Root} from './Root';
3
+
4
+ registerRoot(Root);
@@ -0,0 +1,121 @@
1
+ // Composición del motor de capas: fondo + cámara + capas por escena, transiciones, subtítulos y marca.
2
+ import React from 'react';
3
+ import {AbsoluteFill, Audio, staticFile} from 'remotion';
4
+ import {Avatar, MarcaContexto, useMarca} from '../piezas';
5
+ import {FPS, W, clamp, easeIO, easeOut, lerp} from '../estilo';
6
+ import type {Datos, Escena} from '../tipos';
7
+ import {Capas} from './capas';
8
+ import {FondoTema, Textura, Vineta} from './fondo';
9
+ import {capasDe} from './plantillas';
10
+ import {Subtitulos} from './subtitulos';
11
+ import {mezclar, temaDe, type Tema} from './tema';
12
+ import type {CtxEscena} from './util';
13
+
14
+ const TRANSICION = 0.35;
15
+
16
+ /** Valor animado de cámara: número fijo o [inicio, fin] a lo largo de la escena. */
17
+ const rango = (v: unknown, k: number, porDefecto: number) => (Array.isArray(v) ? lerp(v[0], v[1], k) : typeof v === 'number' ? v : porDefecto);
18
+
19
+ const EscenaVista: React.FC<{e: Escena; t: number; tema: Tema; semilla: string}> = ({e, t, tema, semilla}) => {
20
+ const marca = useMarca();
21
+ const p = e.p;
22
+ const temaEsc = p.tema ? mezclar(tema, p.tema) : tema;
23
+ const ctx: CtxEscena = {t, dur: e.dur, habla: e.habla, palabras: e.palabras ?? [], tema: temaEsc, semilla: `${semilla}-${e.t0}`};
24
+ const cam = p.camara ?? {};
25
+ const k = easeIO(clamp((t - (cam.en ?? 0)) / (cam.duracion ?? e.dur)));
26
+ const zoom = rango(cam.zoom, k, lerp(1, temaEsc.zoomLento, clamp(t / e.dur)));
27
+ const cx = rango(cam.x, k, 0);
28
+ const cy = rango(cam.y, k, 0);
29
+ const temblor = cam.temblor && t < (cam.temblor.duracion ?? 0.4) ? Math.sin(t * 90) * (cam.temblor.fuerza ?? 12) * (1 - t / (cam.temblor.duracion ?? 0.4)) : 0;
30
+ return (
31
+ <AbsoluteFill>
32
+ <AbsoluteFill style={{transform: `scale(${1 + (zoom - 1) * 0.5}) translate(${-cx * 0.3}px, ${-cy * 0.3}px)`}}>
33
+ <FondoTema tema={temaEsc} fondo={p.fondo} t={t + e.t0} semilla={semilla} />
34
+ </AbsoluteFill>
35
+ <AbsoluteFill style={{transform: `scale(${zoom}) translate(${-cx + temblor}px, ${-cy}px)`, transformOrigin: `${540 + (cam.origen?.[0] ?? 0)}px ${960 + (cam.origen?.[1] ?? 0)}px`}}>
36
+ <Capas capas={capasDe(e.tipo, p, temaEsc, marca)} ctx={ctx} />
37
+ </AbsoluteFill>
38
+ </AbsoluteFill>
39
+ );
40
+ };
41
+
42
+ /** Capas fijas del video (HUD): usan el tiempo de todo el video; `cambios` las actualiza por escena o palabra. */
43
+ const Hud: React.FC<{d: Datos; T: number; tema: Tema}> = ({d, T, tema}) => {
44
+ const palabras = d.escenas.flatMap((e) => (e.palabras ?? []).map(([w, a, b]) => [w, a + e.t0, b + e.t0] as [string, number, number]));
45
+ const ultima = d.escenas[d.escenas.length - 1];
46
+ const enCta = ultima?.tipo === 'cta' && T >= ultima.t0;
47
+ if (enCta) return null;
48
+ const ctx: CtxEscena = {t: T, dur: d.duracion, habla: [0, d.duracion], palabras, tema, semilla: `${d.id}-hud`, inicios: d.escenas.map((e) => e.t0)};
49
+ return <Capas capas={d.hud as any} ctx={ctx} />;
50
+ };
51
+
52
+ /** Etiqueta de la marca en la esquina (avatar + nombre). */
53
+ const MarcaEsquina: React.FC<{tema: Tema}> = ({tema}) => {
54
+ const marca = useMarca();
55
+ if (tema.marca === 'ninguna' || (!marca.nombre && !marca.logo)) return null;
56
+ const claro = tema.colores.texto !== '#FFFFFF';
57
+ return (
58
+ <div style={{position: 'absolute', left: 44, top: 120, display: 'flex', alignItems: 'center', gap: 14, opacity: 0.92}}>
59
+ <div style={{position: 'relative', width: 74, height: 74}}>
60
+ <Avatar x={0} y={0} size={66} aro={4} />
61
+ </div>
62
+ {marca.nombre ? (
63
+ <div style={{fontFamily: tema.fuentes.texto, fontWeight: 800, fontSize: 34, color: claro ? '#141414' : '#fff', textShadow: claro ? undefined : '0 2px 8px rgba(0,0,0,0.5)'}}>{marca.nombre}</div>
64
+ ) : null}
65
+ </div>
66
+ );
67
+ };
68
+
69
+ export const VideoMotor: React.FC<{d: Datos; T: number; estilos?: Record<string, any>; miniatura?: boolean}> = ({d, T, estilos, miniatura}) => {
70
+ const tema = temaDe(d.estilo, d.tema, estilos);
71
+ const n = d.escenas.length;
72
+ let si = d.escenas.findIndex((e) => T < e.t0 + e.dur);
73
+ if (si < 0) si = n - 1;
74
+ const e = d.escenas[si];
75
+ const t = T - e.t0;
76
+ const semilla = d.id;
77
+ const trans = (e.p.transicion ?? tema.transicion) as string;
78
+ const enTransicion = si > 0 && t < TRANSICION && trans !== 'corte';
79
+ const k = easeOut(clamp(t / TRANSICION));
80
+ const prev = si > 0 ? d.escenas[si - 1] : null;
81
+ let estiloActual: React.CSSProperties = {};
82
+ let estiloPrevio: React.CSSProperties = {};
83
+ if (enTransicion) {
84
+ if (trans === 'fundido') estiloActual = {opacity: k};
85
+ else if (trans === 'deslizar') {
86
+ estiloActual = {transform: `translateX(${(1 - k) * W}px)`};
87
+ estiloPrevio = {transform: `translateX(${-k * W * 0.35}px)`, opacity: 1 - k * 0.5};
88
+ } else if (trans === 'zoom') {
89
+ estiloActual = {transform: `scale(${lerp(1.15, 1, k)})`, opacity: k};
90
+ estiloPrevio = {transform: `scale(${lerp(1, 0.9, k)})`};
91
+ }
92
+ }
93
+ return (
94
+ <AbsoluteFill style={{background: '#000', overflow: 'hidden'}}>
95
+ {enTransicion && prev ? (
96
+ <AbsoluteFill style={estiloPrevio}>
97
+ <EscenaVista e={prev} t={prev.dur + t} tema={tema} semilla={semilla} />
98
+ </AbsoluteFill>
99
+ ) : null}
100
+ <AbsoluteFill style={estiloActual}>
101
+ <EscenaVista e={e} t={t} tema={tema} semilla={semilla} />
102
+ </AbsoluteFill>
103
+ {/* la textura va quieta, fuera de la cámara: si se moviera con el zoom, cada cuadro sería distinto y el video pesaría 10 veces más */}
104
+ {tema.textura && tema.textura !== 'ninguna' ? <Textura tipo={tema.textura} /> : null}
105
+ <Vineta fuerza={tema.vineta ?? 0} />
106
+ {d.hud?.length ? <Hud d={d} T={T} tema={tema} /> : null}
107
+ {e.tipo !== 'cta' && !miniatura ? <Subtitulos tema={e.p.tema ? mezclar(tema, e.p.tema) : tema} palabras={e.palabras ?? []} t={t} dur={e.dur} /> : null}
108
+ {e.tipo !== 'cta' ? <MarcaEsquina tema={tema} /> : null}
109
+ </AbsoluteFill>
110
+ );
111
+ };
112
+
113
+ /** Componente raíz de un video del motor de capas (con su audio). */
114
+ export const VideoConAudio: React.FC<{d: Datos; frame: number; marca: any; estilos?: Record<string, any>; miniatura?: boolean}> = ({d, frame, marca, estilos, miniatura}) => (
115
+ <MarcaContexto.Provider value={marca}>
116
+ <AbsoluteFill>
117
+ <VideoMotor d={d} T={frame / FPS} estilos={estilos} miniatura={miniatura} />
118
+ <Audio src={staticFile(d.audio)} />
119
+ </AbsoluteFill>
120
+ </MarcaContexto.Provider>
121
+ );