@ignix-social/editor 0.1.8 → 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/cli.mjs +13 -8
- 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/cli.mjs
CHANGED
|
@@ -80,7 +80,7 @@ const commands = {
|
|
|
80
80
|
async doctor() {
|
|
81
81
|
const major = Number(process.versions.node.split('.')[0]);
|
|
82
82
|
log(`${major >= 22 ? '✓' : '✗'} Node ${process.versions.node}${major >= 22 ? '' : ' — Node 22 or newer is required'}`);
|
|
83
|
-
log(`✓ Ignix Editor ${PKG.version} ·
|
|
83
|
+
log(`✓ Ignix Editor ${PKG.version} · engine ${UPSTREAM.version} (patches: ${UPSTREAM.patches.join(', ')})`);
|
|
84
84
|
log(` Platform ${PLATFORM} · data in ${HOME}`);
|
|
85
85
|
let ok = major >= 22;
|
|
86
86
|
// doctor deja la máquina lista: descarga lo que falte en vez de solo avisar.
|
|
@@ -304,17 +304,22 @@ const commands = {
|
|
|
304
304
|
process.exit(r.status ?? 1);
|
|
305
305
|
},
|
|
306
306
|
|
|
307
|
+
// La skill donde la buscan los agentes: Claude (~/.claude/skills) y Codex y otros
|
|
308
|
+
// (~/.agents/skills). Con --dir, solo ahí.
|
|
307
309
|
async skills(argv) {
|
|
308
310
|
const { pos, opts } = parseArgs(argv, { dir: 'str' });
|
|
309
|
-
if (pos[0] !== 'add') fail('Usage: ignix-editor skills add [--dir
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
311
|
+
if (pos[0] !== 'add') fail('Usage: ignix-editor skills add [--dir <skills folder>]');
|
|
312
|
+
const dirs = opts.dir ? [resolve(opts.dir)] : [join(homedir(), '.claude', 'skills'), join(homedir(), '.agents', 'skills')];
|
|
313
|
+
for (const dir of dirs) {
|
|
314
|
+
const target = join(dir, 'ignix-editor');
|
|
315
|
+
rmSync(target, { recursive: true, force: true });
|
|
316
|
+
cpSync(join(PKG_DIR, 'skills', 'ignix-editor'), target, { recursive: true });
|
|
317
|
+
log(`✓ Skill installed in ${target}`);
|
|
318
|
+
}
|
|
314
319
|
},
|
|
315
320
|
|
|
316
321
|
async version() {
|
|
317
|
-
console.log(`ignix-editor ${PKG.version} (
|
|
322
|
+
console.log(`ignix-editor ${PKG.version} (engine ${UPSTREAM.version})`);
|
|
318
323
|
},
|
|
319
324
|
|
|
320
325
|
async help() {
|
|
@@ -334,7 +339,7 @@ const commands = {
|
|
|
334
339
|
ignix-editor fetch [--whisper small] [--no-analysis] downloads everything up front (each file SHA-256-checked)
|
|
335
340
|
ignix-editor serve local service for Ignix Creator (JSON lines on stdin/stdout)
|
|
336
341
|
|
|
337
|
-
The folder defaults to the current one.
|
|
342
|
+
The folder defaults to the current one. Open source (Apache-2.0); credits in NOTICE.`);
|
|
338
343
|
},
|
|
339
344
|
};
|
|
340
345
|
|
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)) {
|