Creación de programas vos
Generas archivos VosConfigJson — configuraciones de animación declarativas que se compilan en animaciones con Three.js + dialecto GSAP sobre el motor vos (github.com/vosjs/vos, MIT). La vista previa es el render: una configuración produce los mismos fotogramas en cualquier máquina.
Flujo de trabajo
- Interpreta la petición: identifica el concepto de animación, el estado de ánimo, los colores y cualquier imagen referenciada.
- Diseña el enfoque: elige la cámara predefinida, los materiales, los efectos y la estrategia de animación (consulta la guía de categorías a continuación).
- Genera la configuración: escribe un VosConfigJson completo y válido en
<nombre-en-kebab-case>.jsondonde el proyecto guarde las configuraciones. - Valida localmente (ver más abajo), luego renderiza o previsualiza.
Si el usuario proporciona una imagen, analiza su estilo visual (colores, ambiente, composición, iluminación) y traduce esas cualidades a la escena.
Validar y renderizar localmente
npm i @vosjs/core # compilador + lints
node -e "import('@vosjs/core/compiler').then(async m => { \
const cfg = JSON.parse(require('fs').readFileSync('my-config.json','utf8')); \
m.compileVosConfig(cfg); console.error('compila limpio') })"
compileVosConfig(config) no debe lanzar una excepción — es el mismo compilador que
ejecutan todos los reproductores y servidores de render. Para comprobaciones visuales, el CLI
(npm i -D @vosjs/cli):
vos render my-config.json out.webm # render de video determinista
vos still my-config.json out.webp --time 2.5
vos preview my-config.json # página de reproducción local
vos info my-config.json
Compartir para vista previa (sin necesidad de cuenta)
El render local es el predeterminado — nada sale de la máquina a menos que el usuario solicite compartir o alojar. Cuando quiera verlo alojado (enlace reproducible, ajuste fino en el estudio vos.so) y no haya una clave API configurada, usa el push reclamable:
vos push my-config.json --claimable --title "…"
# → claim: https://vos.so/claim/… expira: <72h desde ahora>
# ¿Sin CLI o uno antiguo? Lo mismo a través de HTTP plano:
curl -s -X POST https://vos.so/api/claim \
-H 'content-type: application/json' \
-d '{"title": "…", "config": <el VosConfigJson>}'
# → { "claimUrl": "https://vos.so/claim/…", "expiresAt": "…" }
Entrega claimUrl al usuario y a nadie más — es la única referencia y
la única credencial. Dura 72 horas; el trabajo no reclamado se elimina después
de ese tiempo (vuelve a hacer push si caduca). Reclamar mueve el vos a la
biblioteca del usuario. Con una clave configurada (VOS_API_KEY o vos login), prefiere
vos push — los pushes autenticados no tienen caducidad. Solo programas, config ≤200KB,
5 pushes por día por red.
Estructura de VosConfigJson
{
"version": 2,
"duration": 8,
"scene": { "background": "#0a0a1a", "fog": { "type": "exp2", "color": 0, "density": 0.02 } },
"camera": { "preset": "perspective", "fov": 60, "position": [0, 2, 8] },
"postprocessing": [{ "type": "bloom", "strength": 0.8 }, { "type": "output" }],
"elements": [{ "type": "text", "id": "title", "content": "Hola", "position": "center", "font": { "size": 64, "color": "#fff" } }],
"setup": "async (ctx) => { ... return data }",
"createContent": "(ctx, setupData?) => { ... return { objects, refs, dispose } }",
"createTimeline": "(ctx, content, duration) => { ... return tl }"
}
Referencia completa de campos: references/schema-reference.md. Ejemplos
funcionales de cada tipo principal: references/examples.md.
Reglas críticas
HACER
- Las funciones deben ser cadenas JavaScript válidas — SIN TypeScript (sin
as, sin anotaciones de tipo) - Accede a Three.js mediante
ctx.THREE, al dialecto GSAP mediantectx.gsap, a la escena mediantectx.scene createContentDEBE devolver{ objects: [...], refs: {...}, dispose: () => {...} }createTimelineDEBE devolverctx.gsap.timeline({ paused: true })- Incluye siempre
dispose()que limpie geometrías, materiales, texturas - Usa
ctx.resolution.drawingBufferWidth/drawingBufferHeightpara eliResolutiondel shader - Establece
mesh.frustumCulled = falsepara quads de shader a pantalla completa - Establece
depthWrite: false, depthTest: falseen ShaderMaterial a pantalla completa - Incluye siempre
{ "type": "output" }como última entrada cuando uses postprocesado - Añade todos los objetos de la escena tanto a
scenecomo al arrayobjectsdevuelto - Anima uniformes de shader directamente:
tl.to(uniforms.iTime, { value: duration, duration, ease: 'none' }) - Para lógica por fotograma (actualizaciones de InstancedMesh, matemática de cámara), usa callbacks
onUpdateen los tweens
NO HACER
- NO uses plantillas literales
${}en cadenas de función — se evalúan en tiempo de compilación. Usa concatenación de cadenas. - NO escapes acentos graves — escribe shaders como cadenas inline, o usa concatenación en una sola línea
- NUNCA uses
repeat: -1en tweens individuales — el bucle lo maneja el reproductor; esto rompe el seguimiento de duración - NO uses objetos
styleal estilo CSS nitextContenten elementos — los elementos son planos WebGL - NO uses importaciones externas — todo está en
ctx(THREE, gsap, cargadores, utilidades) - NO uses
requestAnimationFramenisetTimeout— usa callbacksonUpdate - NO uses
Date.now()/Math.random()en rutas de fotogramas — el determinismo es el contrato; deriva todo del tiempo de la línea de tiempo yctx.data - NO uses
onFramepara configuraciones nuevas — pon toda la lógica por fotograma enonUpdate
Parámetros y Looks (hazlo remezclable)
Declara 2–4 controles mediante config.params — los editores los renderizan como controles
en vivo, y otros agentes pueden reajustar el programa sin tocar el código. Cada parámetro
documenta una clave ctx.data que el programa lee:
"params": [{ "key": "hue", "label": "Tono", "kind": "number",
"min": 0, "max": 1, "default": 0.6,
"hint": "Desplaza cada color alrededor del círculo cromático",
"unit": "°", "group": "Color", "order": 1 }]
- tipos:
number(min/max/step) |color|select(options) |toggle hint: UNA oración sobre qué cambia visualmente — escríbela- el programa la lee donde anima:
const d = ctx.data || {}; if (typeof d.hue === 'number') u.uHue.value = d.hue - Nombra los controles por INTENCIÓN (
mood,drama,pace), nunca por implementación (blurRadius). Cada control debe cambiar visiblemente la salida — un control muerto es peor que ningún control.
Distribuye Looks mediante config.presets — conjuntos de nombre y valores de parámetros (2–3 cuando el
programa tiene 4+ parámetros):
"presets": [{ "name": "Vívido", "values": { "hue": 0.9, "speed": 2 } },
{ "name": "Calma", "values": { "hue": 0.3, "speed": 0.6 } }]
Los valores deben referenciar claves de parámetros declaradas con tipos coincidentes.
Precaución sobre renderizado en servidor
Las configuraciones enviadas a vos.so se renderizan en vista previa en un grupo de software-GL: no
uses THREE.DoubleSide en materiales de transmisión (cuelga el sistema), no uses dispersion
(demasiado lento), y cualquier recurso obtenido debe ser accesible y tener CORS abierto. Estos
están bien para renders puramente locales en una GPU real.
Principios de diseño
- Impacto visual: bloom para brillo (incluso 0.3–0.5 eleva); materiales emisivos
- bloom = emisores de luz; niebla exp2 (0.01–0.05) para profundidad; fondos oscuros hacen que los colores resalten; vidrio (transmisión + entorno HDR) se ve premium; un desplazamiento sutil de cámara añade vida.
- Calidad de animación: bucles de 4–10 s, narrativas de 10–30 s;
ease: 'none'para movimiento constante;power2.inOut/sine.inOutpara transiciones; escalonamiento para revelaciones secuenciales; superposición de tweens en diferentes tiempos de inicio. - Color: máximo 2–3 colores complementarios; clave cálida + borde frío; tonos
oscuros (
0x0a0a1a,0x1a1a2e) para fondos. - Rendimiento:
InstancedMeshpara 10+ objetos idénticos; 5k–20k puntos, 100–500 InstancedMesh; desecha todo.
Guía de selección de categoría
| Concepto | Cámara | Técnica |
|---|---|---|
| Arte de shader / fractales | fullscreen | ShaderMaterial + tweens de uniformes |
| Objetos 3D | perspective | Mesh + Material + luces |
| Isométrico/plano | orthographic | InstancedMesh + posiciones calculadas |
| Exhibición de texto | perspective o fullscreen | TextGeometry (3D) o elements (2D) |
| Vidrio/refracción | perspective | MeshPhysicalMaterial + mapa de entorno HDR |
| Partículas | perspective | Points + shader o InstancedMesh |
| Medios mixtos | perspective | Escena 3D + array de elements |