# Editor de video estándar

Kit reusable para producir videos verticales de principio a fin con IA: creás una **imagen** a partir de texto, la **animás**, le ponés **voz** y **subtítulos sincronizados**, le sumás **música** instrumental y lo **renderizás** a un MP4 listo para redes. Es un conjunto de scripts pequeños en Node.js (uno por paso) más un comando que corre todo el flujo de una sola vez. Cada paso es independiente: podés usar solo el que necesités.

> Este repo es **público y sin secretos**. No incluye API keys ni datos de ninguna cuenta: el código las lee de variables de entorno o del Keychain de macOS en tiempo de ejecución (ver [`docs/02-configurar-keys.md`](docs/02-configurar-keys.md)). El `.env` real está en `.gitignore` y nunca se versiona.

## El flujo en 8 pasos

1. **Imagen** — texto → imagen con IA (Kie.ai, modelo GPT Image), como cuando le pedís una imagen a ChatGPT.
2. **Animar** — la imagen estática cobra movimiento con I2V (image-to-video, modelo Grok).
3. **Voz** — la narración se genera con ElevenLabs (text-to-speech en español).
4. **Transcribir** — se transcribe la voz con Whisper para sincronizar los subtítulos palabra por palabra.
5. **Música** — pista instrumental de fondo con Suno.
6. **Build** — se arma la composición HTML (HyperFrames) con los clips + subtítulos karaoke + la voz.
7. **Render** — la composición se renderiza a MP4 (la voz ya queda dentro).
8. **Mezcla** — se mezcla la música de fondo bajo la voz y se masteriza para redes (−16 LUFS, techo de pico).

```
texto
  │
  ▼
[1] imagen ──► [2] animar ──► clips .mp4
                                  │
guion.txt ──► [3] voz ──► [4] transcribir ──► subtítulos
                                  │                 │
              [5] música ─────────┤                 │
                                  ▼                 ▼
                            [6] build (composición HTML)
                                  │
                                  ▼
                            [7] render ──► video con voz
                                  │
                            [8] mezcla ──► FINAL .mp4 (voz + música)
```

## Requisitos

- **Node.js >= 18** (recomendado 20.6+ si querés usar archivos `.env` con `--env-file`).
- **ffmpeg** y **ffprobe** en el `PATH` (normalización de clips y mezcla de audio).
- **npx** (viene con Node): se usa para HyperFrames, que se baja on-demand.
- API keys de los servicios que vayas a usar (ver abajo). Gemini es opcional.

No hay dependencias npm que instalar: el repo no trae `node_modules` propios y HyperFrames se descarga solo cuando se invoca con `npx`.

Detalle de instalación en [`docs/01-instalar.md`](docs/01-instalar.md).

## Quickstart

### 1. Clonar y entrar

```bash
git clone <url-del-repo> editor-video-estandar
cd editor-video-estandar
```

### 2. Configurar las keys

El código resuelve cada key en este orden: **1)** la variable de entorno; **2)** si no está, el Keychain de macOS. Elegí una de las dos opciones.

**Opción A — Keychain de macOS** (recomendada en Mac; pide el valor de forma interactiva y no queda en el historial del shell):

```bash
security add-generic-password -a editor -s "editor:kie-ai-key" -w
security add-generic-password -a editor -s "editor:elevenlabs-key" -w
security add-generic-password -a editor -s "editor:sunoapi-org-key" -w
# opcional (respaldo de imágenes):
security add-generic-password -a editor -s "editor:gemini-key" -w
```

**Opción B — archivo `.env`** (cualquier sistema):

```bash
cp .env.example .env
# editá .env y pegá tus keys
node --env-file=.env scripts/check-setup.mjs
```

Tabla de keys:

| Servicio | Variable de entorno | Entrada de Keychain (cuenta `editor`) | Para qué | Dónde se obtiene |
|---|---|---|---|---|
| Kie.ai | `KIE_API_KEY` | `editor:kie-ai-key` | imágenes + animación I2V | https://kie.ai |
| ElevenLabs | `ELEVENLABS_API_KEY` | `editor:elevenlabs-key` | voz + efectos de sonido | https://elevenlabs.io |
| Suno | `SUNO_API_KEY` | `editor:sunoapi-org-key` | música de fondo | https://sunoapi.org |
| Gemini (opcional) | `GEMINI_API_KEY` | `editor:gemini-key` | respaldo de imágenes | — |

Guía completa en [`docs/02-configurar-keys.md`](docs/02-configurar-keys.md).

### 3. Verificar que todo está listo

```bash
npm run check
```

Comprueba Node, ffmpeg, ffprobe, npx y las keys. **No imprime ninguna key**: solo dice si está configurada o no. Gemini se reporta como aviso (es opcional).

### 4. Producir el video

**Opción A — todo de una vez** (corre los 8 pasos sobre el proyecto de ejemplo):

```bash
node src/runners/pipeline.mjs --project ejemplo/proyecto-demo
```

Lee `escenas.json` (las escenas, voz y música) y `guion.txt` (la narración), y deja el resultado en `ejemplo/proyecto-demo/export/`. Si querés cortar antes de gastar todos los créditos, usá `--until`:

```bash
node src/runners/pipeline.mjs --project ejemplo/proyecto-demo --until voz
```

Pasos válidos para `--until`: `imagen`, `animar`, `voz`, `transcribir`, `musica`, `build`, `render`. El pipeline reusa lo ya generado (si un clip existe, no lo regenera).

**Opción B — manual, paso por paso** (para entender cada etapa). Cada runner es un script suelto:

```bash
# 1) imagen (texto → PNG). Imprime la URL remota que necesita el paso 2.
node src/runners/imagen.mjs --prompt "un robot de dibujos saludando, fondo blanco" --out ./assets/escena-1.png

# 2) animar (imagen → clip MP4 vertical, normalizado a 1080x1920 30fps)
node src/runners/animar.mjs --image ./assets/escena-1.png --out ./assets/clip-1.mp4 --movement "respiración suave, un parpadeo"

# 3) voz (texto → MP3)
node src/runners/voz.mjs --file ./guion.txt --out ./assets/voz.mp3 --voice <voice_id>

# 4) transcribir (genera transcript.json + words.json + groups.json junto al audio)
node src/runners/transcribir.mjs --audio ./assets/voz.mp3 --language es --model small

# 5) música (instrumental por defecto; deja <name>-track0.mp3 en el dir de salida)
node src/runners/musica.mjs --prompt "tech minimal, calmo, cinematic, instrumental" --out ./assets --name musica

# 6) build de la composición: genera index.html con clips + subtítulos + voz.
#    build.mjs lee ../escenas.json y la carpeta assets/ de la composición (escena-N.mp4, voz.mp3,
#    groups.json). El pipeline (Opción A) deja esos archivos en su sitio; para un build 100% manual,
#    colocá ahí los assets con esos nombres. Cableado exacto en docs/03-crear-primer-video.md.
cd ejemplo/proyecto-demo/composicion && node build.mjs && cd -

# 7) render a MP4 (la voz ya queda dentro)
node src/runners/render.mjs --dir ./ejemplo/proyecto-demo/composicion --out ./renders/video.mp4

# 8) mezcla: música de fondo bajo la voz + masterización
node src/runners/mezclar.mjs --video ./renders/video.mp4 --music ./assets/musica-track0.mp3 --out ./final.mp4 --volume 0.12
```

Paso a paso narrado en [`docs/03-crear-primer-video.md`](docs/03-crear-primer-video.md).

## CLI de cada runner

Resumen de flags (los corchetes son opcionales). Detrás de cada uno hay un módulo en `src/runners/`.

| Runner | Comando | Notas |
|---|---|---|
| Imagen | `node src/runners/imagen.mjs --prompt "..." --out <png> [--model gpt-image\|nano-banana] [--aspect 9:16]` | Default `gpt-image` (texto legible). `9:16` por defecto. |
| Animar | `node src/runners/animar.mjs (--image-url <url> \| --image <png>) --out <mp4> [--movement "..."] [--model grok\|wan]` | Si pasás `--image` local, lo sube a Kie solo. Default `grok`. |
| Voz | `node src/runners/voz.mjs (--text "..." \| --file <txt>) --out <mp3> [--voice <id\|alias>] [--model eleven_multilingual_v2]` | Para español, pasá un `voice_id` de tu panel. |
| Música | `node src/runners/musica.mjs --prompt "..." --out <dir> [--name base] [--model V4_5] [--withVocals]` | Instrumental por defecto; `--withVocals` la habilita. |
| SFX (opcional) | `node src/runners/sfx.mjs --prompt "<en inglés>" --out <mp3> [--dur 2]` | Duración 0.5–22 s. |
| Transcribir | `node src/runners/transcribir.mjs --audio <voz.mp3\|video.mp4> [--language es] [--model small]` | **Nunca** modelos `.en` con audio en español: traducen al inglés. |
| Render | `node src/runners/render.mjs --dir <carpeta con index.html> [--out <mp4>]` | Valida con HyperFrames antes de renderizar. |
| Mezclar | `node src/runners/mezclar.mjs --video <render.mp4> --music <fondo.mp3> --out <final.mp4> [--volume 0.12]` | Bloquea música con voces (compite con la narración). |
| Pipeline | `node src/runners/pipeline.mjs --project <carpeta> [--until imagen\|animar\|voz\|transcribir\|musica\|build\|render]` | Corre el flujo completo. |

También hay scripts npm de atajo: `npm run check`, `imagen`, `animar`, `voz`, `musica`, `sfx`, `transcribir`, `render`, `mezclar` (con `npm run <script> -- <flags>`).

## Costos por video

Las imágenes y los clips consumen **créditos de Kie.ai**; la voz, la música y los SFX se cobran en sus propias cuentas (ElevenLabs y Suno). Estos son los costos de Kie por unidad:

| Etapa | Modelo (slug) | Costo |
|---|---|---|
| Imagen | `gpt-image` = `gpt-image-2-text-to-image` (default) | 6 cr c/u |
| Imagen | `nano-banana` = `google/nano-banana` | 4 cr c/u |
| Clip I2V | `grok` = `grok-imagine/image-to-video` (default) | 18 cr c/u |
| Clip I2V | `wan` = `wan/2-6-flash-image-to-video` | 30 cr c/u |

Ejemplo con el proyecto de demo (3 escenas = 3 imágenes + 3 clips), todo con los modelos por defecto:

| Concepto | Cálculo | Créditos Kie |
|---|---|---|
| Imágenes | 3 × 6 cr | 18 cr |
| Clips I2V | 3 × 18 cr | 54 cr |
| **Total Kie** | | **72 cr** |
| Voz | ElevenLabs (caracteres del guion) | — (cuenta ElevenLabs) |
| Música | Suno (1 generación) | — (cuenta Suno) |

Para abaratar: usá `nano-banana` en imágenes (4 cr en vez de 6) o reducí la cantidad de escenas. Podés consultar tu saldo de Kie antes de un lote:

```bash
curl -sS https://api.kie.ai/api/v1/chat/credit -H "Authorization: Bearer $KIE_API_KEY"
```

## Mapa de carpetas

```
editor-video-estandar/
├── package.json              scripts: check, imagen, animar, voz, musica, sfx, transcribir, render, mezclar
├── .env.example              plantilla de variables de entorno (sin secretos)
├── scripts/
│   └── check-setup.mjs       verifica herramientas + keys (no imprime ninguna key)
├── src/
│   ├── lib/
│   │   ├── keys.mjs          resuelve las keys (env → Keychain), nunca las imprime
│   │   ├── kie.mjs           cliente Kie.ai (imágenes + video I2V): jobs, créditos, upload
│   │   ├── elevenlabs.mjs    cliente ElevenLabs (voz + SFX)
│   │   ├── suno.mjs          cliente Suno (música por sunoapi.org)
│   │   ├── ffmpeg.mjs        normalizar clips + mezclar voz/música + masterizar
│   │   └── cli.mjs           parser de argumentos
│   └── runners/
│       ├── imagen.mjs        1) imagen IA
│       ├── animar.mjs        2) animación I2V
│       ├── voz.mjs           3) voz TTS
│       ├── transcribir.mjs   4) subtítulos (Whisper)
│       ├── musica.mjs        5) música
│       ├── sfx.mjs           (opcional) efectos de sonido
│       ├── render.mjs        7) render a MP4 (el build es el paso 6, en composicion/build.mjs)
│       ├── mezclar.mjs       8) mezcla final
│       └── pipeline.mjs      el flujo completo de un proyecto
├── docs/                     guías paso a paso (ver abajo)
└── ejemplo/
    └── proyecto-demo/
        ├── escenas.json      escenas, voz y música del proyecto
        ├── guion.txt         narración
        ├── composicion/      composición HyperFrames (index.html se genera en el build)
        └── export/           video final
```

## Guías

- [`docs/01-instalar.md`](docs/01-instalar.md) — instalar Node, ffmpeg y dejar la máquina lista.
- [`docs/02-configurar-keys.md`](docs/02-configurar-keys.md) — keys en Keychain o `.env`, sin filtrarlas.
- [`docs/03-crear-primer-video.md`](docs/03-crear-primer-video.md) — el primer video, paso por paso (modo manual).
- [`docs/04-referencia-modelos.md`](docs/04-referencia-modelos.md) — modelos, slugs, costos y endpoints.
- [`docs/05-solucion-problemas.md`](docs/05-solucion-problemas.md) — errores comunes y cómo resolverlos.

## Notas sobre los modelos

- **Imagen:** `gpt-image` escribe texto legible en español; `nano-banana` es más barato pero no escribe bien texto en español.
- **Voz:** `eleven_multilingual_v2` para español. El alias por defecto (`rachel`) es una voz en inglés; para español pasá un `voice_id` de tu cuenta con `--voice`.
- **Subtítulos:** Whisper local vía HyperFrames. Regla dura: nunca uses modelos `.en` con audio en español (traducen al inglés y rompen la transcripción).
- **Música:** instrumental por defecto, para que no compita con la narración. El paso de mezcla bloquea pistas que parezcan tener voces.
- **Imagen propia → animar:** si querés animar una imagen que ya tenés en disco, `animar.mjs --image <png>` la sube a Kie y obtiene una URL pública temporal (esas URLs se borran a los ~3 días).

## Licencia

MIT.
