@ignix-social/editor 0.1.9 → 0.1.10
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/package.json +1 -1
- package/src/engine.mjs +10 -2
- package/src/runtime/ignix-frame.js +6 -0
- package/src/validate.mjs +5 -2
package/package.json
CHANGED
package/src/engine.mjs
CHANGED
|
@@ -80,15 +80,23 @@ export async function renderProject(dir, output, { lufs = -14, normalize = true,
|
|
|
80
80
|
mkdirSync(dirname(output), { recursive: true });
|
|
81
81
|
const raw = join(build, 'raw.mp4');
|
|
82
82
|
const args = ['render', build, '-o', raw, ...engineArgs];
|
|
83
|
-
// Avance: «Capturing frame N/M» del motor; luego codifica y monta.
|
|
83
|
+
// Avance: «Capturing frame N/M» del motor; luego codifica y monta. Y si la animación no llegó a
|
|
84
|
+
// registrarse, el motor renderiza igual (con un aviso) un vídeo congelado: eso es un fallo.
|
|
85
|
+
let frozen = false;
|
|
84
86
|
const onLine = (line) => {
|
|
87
|
+
if (/sub_timeline_readiness_timeout|still unregistered|Root timeline not bound/.test(line)) frozen = true;
|
|
85
88
|
const m = line.match(/Capturing frame (\d+)\/(\d+)/);
|
|
86
89
|
if (m) onProgress?.({ stage: 'rendering', fraction: Math.min(0.99, Number(m[1]) / Math.max(1, Number(m[2]))) });
|
|
87
90
|
else if (/Encoding video|Assembling final video/.test(line)) onProgress?.({ stage: 'encoding', fraction: 0.95 });
|
|
88
91
|
};
|
|
89
|
-
const code =
|
|
92
|
+
const code = await runEngineAsync(args, env, dir, { onLine, signal });
|
|
90
93
|
if (signal?.aborted) throw Object.assign(new Error('cancelled'), { code: 'cancelled' });
|
|
91
94
|
if (code !== 0 || !existsSync(raw)) throw new Error('The render failed (see the messages above).');
|
|
95
|
+
if (frozen) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
'The animation never started, so the video would stay frozen on its first frame. Usually GSAP is not loaded before ignix-frame.js, or IgnixFrame.run threw an error: run `ignix-editor check` and fix what it reports, then render again.',
|
|
98
|
+
);
|
|
99
|
+
}
|
|
92
100
|
let level = null;
|
|
93
101
|
if (normalize !== false && hasAudio(ffprobe, raw)) {
|
|
94
102
|
const r = normalizeLoudness(ffmpeg, raw, output, { lufs: Number(lufs ?? -14) });
|
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
* `id` es el data-composition-id del nodo raíz. Necesita GSAP cargado antes.
|
|
13
13
|
*/
|
|
14
14
|
(function () {
|
|
15
|
+
// GSAP va antes que este fichero (la plantilla de `init` lo pone). Si un agente reescribió el
|
|
16
|
+
// HTML sin él, se carga aquí mientras la página aún se lee: sin GSAP nada se movería y el
|
|
17
|
+
// vídeo saldría congelado en su primer fotograma (pasó dos veces, 2026-10-06).
|
|
18
|
+
if (!window.gsap && document.readyState === 'loading') {
|
|
19
|
+
document.write('<script src="assets/gsap.min.js"><\/script>');
|
|
20
|
+
}
|
|
15
21
|
const clamp01 = (x) => Math.min(1, Math.max(0, x));
|
|
16
22
|
|
|
17
23
|
// Curva cúbica de Bézier como en CSS (x1, y1, x2, y2).
|
package/src/validate.mjs
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
// · <video>/<audio> creados desde JS (el extractor lee el HTML, no la página viva: salen negros o mudos);
|
|
4
4
|
// · recursos de internet (el render no debe depender de la red: fuentes que llegan tarde);
|
|
5
5
|
// · ids que el motor trata de forma especial (id="caption" cambió la fuente de los subtítulos).
|
|
6
|
-
import { readFileSync } from 'node:fs';
|
|
6
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
7
|
+
import { dirname, join } from 'node:path';
|
|
7
8
|
import { parse } from 'parse5';
|
|
8
9
|
|
|
9
10
|
// Avisos de parse5 que no cambian cómo se pinta la página.
|
|
@@ -65,7 +66,9 @@ export function validateHtml(file) {
|
|
|
65
66
|
if (frame) {
|
|
66
67
|
const gsap = scripts.find((x) => /gsap(\.min)?\.js$/i.test(x.src));
|
|
67
68
|
if (!gsap || gsap.at > frame.at) {
|
|
68
|
-
|
|
69
|
+
// ignix-frame.js lo carga solo desde assets/gsap.min.js: si el fichero está, es un aviso.
|
|
70
|
+
const there = existsSync(join(dirname(file), 'assets', 'gsap.min.js'));
|
|
71
|
+
issues.push({ level: there ? 'warning' : 'error', line: lineOf(src, frame.at), rule: 'gsap_before_frame', msg: `ignix-frame.js needs GSAP loaded first. Put <script src="assets/gsap.min.js"></script> right above <script src="ignix-frame.js"></script> (as \`ignix-editor init\` writes it)${there ? '. ignix-frame.js loads it from assets/ meanwhile.' : ': assets/gsap.min.js is missing too.'}` });
|
|
69
72
|
}
|
|
70
73
|
}
|
|
71
74
|
for (const m of src.matchAll(/@import\s+url\(\s*["']?https?:|url\(\s*["']?https?:\/\/fonts\./gi)) {
|