Русский · English · Español · 中文 · Português

«Espacio ahora» — API de agente

Esta página es para agentes de IA (y sus humanos). Explica cómo un agente se conecta a una página «Espacio ahora» en vivo (known.html) en el navegador de una persona y qué puede hacer allí: todo lo que puede hacer la interfaz — abrir cualquier objeto, mover la cámara, avanzar el tiempo, cambiar capas y filtros, modo astronauta, buscar eclipses y desfiles de planetas, contar una historia con voz y subtítulos, mostrar sus propias imágenes, grabar vídeo, leer errores. El renderizado ocurre en el navegador de la persona (WebGL en su GPU); el agente envía comandos y recibe respuestas y capturas de pantalla.

1. Emparejamiento

  1. La persona abre el sitio y pulsa el botón redondo 🤖 (abajo a la derecha, encima del astronauta): se abre la barra del agente; «Encender el agente» muestra un código (20 caracteres, p. ej. r4fxjbjsxdy6ex3pf4hd). El código es el pase: quien lo tiene controla esta pestaña. 🤖 solo oculta/muestra la barra, la conexión se mantiene; «Desconectar» en la barra la apaga. La barra siempre tiene 📂 (abrir un archivo de historia o guardar la mostrada — también sin agente) y «MCP ↗» (esta página).
  2. La persona da el código al agente. El agente llama a connect con él.
  3. Conexión permanente (opcional): en la página — 📌 «Recordar» en la barra del agente (el código se queda en este navegador, el sitio se conecta solo cada vez que se abre); el agente — connect con save: true (código en ~/.orbit-agent.json, MCP se conecta al iniciar). Después, basta con abrir el sitio. Para olvidar: desactivar 📌 y llamar a forget.
  4. «Desconectar» en la página (o la salida del agente) termina la sesión; entonces la página devuelve las capas y la interfaz a como estaban antes del agente, detiene la música, la voz, los subtítulos, las imágenes y los guiones, y elimina los sitios de aterrizaje (sites), los dibujos y las marcas (draw, mark, flybys), las ventanas multimedia y los cuerpos propios (spawn) — independientemente de onstop. La cámara, el tiempo y la selección también se restauran (por defecto; onstop {restore: false} — conservar lo que mostró el agente). Excepción: play / story run con detach: true — la presentación se reproduce hasta el final y luego se revierte.

El sonido (voz, música) solo empieza después de que la persona haya hecho clic en la página al menos una vez — regla del navegador. La voz está desactivada por defecto: la persona la activa con 🔊 en la barra del agente (se recuerda); los subtítulos siempre se muestran.

Lista de comprobación de la presentación — hazlo siempre

[
  {"cmd":"onstop","args":{"restore":true}},        // primer paso: al terminar, con Esc o ✕ todo vuelve
  {"cmd":"reset"},
  {"cmd":"view","args":{"on":["oplanets"]}},        // solo las capas necesarias: satélites, naves, órbitas, constelaciones apagados
  {"cmd":"hideUi","args":{"on":true,"labels":false}},
  {"cmd":"time","args":{"at":"<moment>","rate":0}}, // fija tú el tiempo; rate 0 — la iluminación no se desplazará
  … vuelo (fly) …
  … la presentación …
]

2. Transporte

Ambos lados se conectan a una sala de retransmisión en el mismo sitio: wss://<site>/agent/<code>?r=agent (la página usa ?r=page). La sala reenvía mensajes entre los dos; no se almacena nada. Mensajes JSON:

agent → page   { "id": 1, "cmd": "go", "args": { "search": "?o=Mars" } }
page  → agent  { "id": 1, "ok": true, "result": … }   |   { "id": 1, "ok": false, "error": "…" }
room  → both   { "sys": "peer", "on": true|false }      (el otro lado se unió / salió)
keepalive      envía { "sys": "ping" } cada 30 s, la sala responde { "sys": "pong" }

Una conexión por rol (un agente nuevo con el mismo código reemplaza al anterior, código de cierre 4000 — no te reconectes entonces). Mensajes de hasta 4 MB. Sitios: https://space.bl2.ru, https://space.bl2.net (el mismo sitio, ru/en por defecto).

3. Servidor MCP

Servidor MCP listo para usar (stdio): scripts/agent-mcp.mjs en el repositorio orbit-proto (Node ≥ 20, dependencia ws). Cada comando de abajo es una herramienta del mismo nombre (hide_ui → comando de página hideUi), más connect, disconnect, help (esta página como texto; lang: es). Archivos: image toma path, record guarda en path, screenshot devuelve una imagen.

{ "mcpServers": { "orbit-space": { "command": "node", "args": ["scripts/agent-mcp.mjs"] } } }

Env: AGENT_SITE — sitio por defecto, AGENT_CODE — conectar al inicio.

Conexión sin el servidor MCP (agentes en la nube)

// «iniciar y volver» — desde la consola de una pestaña en space.bl2.ru (o Node ≥ 22)
const code = '<code>', ws = new WebSocket(`wss://space.bl2.ru/agent/${code}?r=agent`);
let id = 0; const wait = new Map();
const cmd = (name, args = {}, ms = 8000) => new Promise((res, rej) => {
  const i = ++id, t = setTimeout(() => (wait.delete(i), rej(new Error('timeout ' + name))), ms);
  wait.set(i, (m) => (clearTimeout(t), m.ok ? res(m.result) : rej(new Error(m.error))));
  ws.send(JSON.stringify({ id: i, cmd: name, args }));
});
ws.onmessage = (e) => { const m = JSON.parse(e.data); if (!m.sys) wait.get(m.id)?.(m), wait.delete(m.id); };
ws.onopen = async () => {
  await cmd('onstop', { restore: true });
  await cmd('play', { detach: true, onError: 'skip', steps: [
    { cmd: 'reset' },
    { cmd: 'view', args: { on: ['oplanets'] } },
    { cmd: 'hideUi', args: { on: true, labels: false } },
    { cmd: 'fly', args: { name: 'Saturn', size: 0.5, lit: true }, wait: 6500 },
    { cmd: 'caption', args: { title: 'Saturn', sub: '1.4 billion km from the Sun' }, wait: 8000 },
  ] });
  ws.close(); // la presentación continúa sola y luego lo devuelve todo
};

4. Comandos

Observación y estado

cmdargsqué hace
statetiempo, velocidad, objeto seleccionado, centro de la vista, cámara (yaw, pitch, dist km, fov), estrella cercana, claves de las capas visibles, tamaño del lienzo en px
screenshotwidth, quality, fullJPEG de la escena 3D. full: true — toda la pestaña con la interfaz (la persona permite la captura de pestaña una vez con «📷» en la barra del agente)
bodynamepara el encuadre: radio km, tipo, padre, lunas, ángulos de cámara, sunYaw/sunPitch (dirección de cámara desde la que el cuerpo está totalmente iluminado), fov, distForSize {0.25, 0.5, 0.66, 0.8 → km}: distancia a la que el disco llena esa proporción de la altura de pantalla (= radio / tan(fov/2) / k)
wherename, atposición en un instante: km y UA desde el Sol y la Tierra, AR/Dec desde la Tierra (J2000)
logslevel, last, clearerrores/advertencias/info de la consola de la página (búfer circular de 300)
snapshotestado completo (tiempo, velocidad, cámara, centro, selección, todas las casillas de capas, interfaz oculta, enlace del astronauta) — guárdalo para reproducir un error
restorestatevolver a una instantánea

Vista, cámara, tiempo, capas

cmdargsqué hace
searchq, limitbuscar en la base de objetos como el campo de búsqueda: cuerpos, lunas, naves espaciales, nebulosas y galaxias (cuando su capa está activa), satélites terrestres (nombre o NORAD), asteroides (nombre o número; el catálogo se carga mediante la fila load-asteroids). Devuelve filas con n
opennabrir un resultado de búsqueda: selección, ficha, vuelo — como al hacer clic en la fila
gosearchabrir una vista como un enlace para compartir: ?o= cuerpo (Mars, Марс, ISS…), ?a= asteroide (número o nombre), ?s= satélite NORAD, ?g= galaxia, ?n= nebulosa, ?st= estrella de constelación; extras d= cámara km, v=yaw,pitch, t= hora ISO
flyname, size, lit, face, secondsvuelo suave a un cuerpo (como un clic en el árbol). size — proporción de la altura de pantalla para el cuerpo (0.66 — dos tercios), lit: true — desde el lado iluminado; el encuadre tarda ~2,5 s más después del vuelo (~6 s en total, usa wait ≥ 6500). face: "spot" — Júpiter: el tiempo retrocede hasta que la Gran Mancha Roja está en el lado diurno
camerayaw, pitch, dist, mscámara alrededor del centro de la vista (rad, km). ms > 0 — moverse suavemente durante ms. Ejemplo «llenar 2/3 de la pantalla, lado iluminado»: body → camera {yaw: sunYaw+0.4, pitch: sunPitch, dist: distForSize[0.66], ms: 3000}
timeat, rate, live, from, tofrom, to, ms, ease — avance suave de una fecha a otra; at — segundos Unix o instante ISO (a. C.: -000500-01-01), velocidad (1 real, 3600 = 1 h/s, negativa = hacia atrás, 0 pausa), live: true
viewon, set, orbitsvista — claves estándar para cada interruptor. Sin args — lista {key, on}; on: [...] — apaga todo y enciende solo lo indicado; set: {key: true|false} — cambia solo esas; orbits: false — todas las líneas de órbita a la vez. Claves (cada grupo tiene también <key>:orbits — sus líneas de órbita): oplanets — Sol, planetas y lunas; odwarfs — planetas enanos y los mayores asteroides; ohelio — heliopausa; oshock — choque de terminación; osandbox — cuerpos propios (spawn); oknown-small — pequeños conocidos (Apofis, Bennu…); ocomets — cometas; ointerstellar — objetos interestelares (1I, 2I, 3I); okuiper — cinturón de Kuiper; ooort — nube de Oort; a0…a9 — asteroides por tamaño (a0 — más de 100 km); ocraft, ocraft-orbit, ocraft-l — naves en vuelo, en órbita alrededor de cuerpos, en puntos de Lagrange; s0…s30 — grupos de satélites terrestres, sats — todos a la vez; ogalaxy — modelo de la Vía Láctea; ouniverse — galaxias; stars — estrellas de constelaciones con nombre; conlines — líneas de las figuras de constelaciones (con stars; no aparece en view {on} — sin líneas); galmarks — etiquetas del centro galáctico y del ápex; galsun — «Sol — usted está aquí»; scenelabels — etiquetas solo de lo que necesita la escena (labels {only}). Una única trayectoria interestelar: apaga ointerstellar:orbits, select {name: '3I/ATLAS'} — su trayectoria brillante. También: earth:ph|cities|seas|mountains|volcanoes, weather, aurora (aurora), sw (clima espacial), sk:0…6, sk:neb. Las historias y diapositivas aceptan un campo on (se aplica antes de los pasos): indica solo lo necesario — las capas nuevas activadas por defecto no aparecerán en historias antiguas
layerstodos los grupos de capas: key, name, visible, orbits, count
layerkey, visible, orbitscambiar una capa. Claves: oplanets, odwarfs, ocomets, ocraft*, ogalaxy, ouniverse, a0…a9 asteroides por tamaño, s0… grupos de satélites…
galaxyfarvista de la Vía Láctea (far — con otras galaxias). Para escenas: dist (0 — modelo en el Sol, > 0 — alejarse), pitch, center: true — órbita alrededor del centro galáctico, off: true; tiempo galáctico — galtime {rate} (años/s)
galaxiescount, dwellsobrevolar N galaxias famosas por distancia, dwell segundos cada una
cleardeseleccionar, cerrar la ficha

Eventos (calculados por la página, sin necesidad de fórmulas)

cmdargsqué hace
findkind, from, to, total, count, minlunar (total: true — «luna de sangre»), solar, parade (min planetas 3…7) desde cualquier fecha; devuelve el instante central, total?, lat/lon/región donde es visible; lunar — contact (contacto con la umbra)
showkind, at, keepViewmostrar un evento como «📅 Eventos»: tiempo — media hora antes del máximo, velocidad ×100 (fija time {rate: 0} o la tuya), selección borrada, centro de la vista y cámara en la Tierra (solar: sobre el punto de la sombra) o la Luna (lunar); un desfile — vista en primera persona desde la Tierra, solo planetas. Las capas fijadas con view se mantienen (keepView: false — las del evento). Después: hideUi, camera si hace falta

Interfaz completa

cmdargsqué hace
uitext, withincada botón, casilla, control deslizante, campo, fila de lista/árbol visible con ref, texto, id, atributos data, estado. Filtra por texto o área CSS
clickref | selectorpulsarlo
setref | selector, valuecasilla true/false, control deslizante, campo, select
keycode, ms, shift, ctrlpulsación de tecla (KeyW… mantén ms para volar, Space pausa, KeyH oculta paneles, Escape…)
pointeraction, x, y, to, dyratón sobre la escena 3D: click (seleccionar), dblclick (volar hasta), move (pasar por encima), drag (rotar) hasta [x,y], wheel (dy zoom)
hideUion, labelsocultar todo: paneles, botones de las esquinas, la barra del agente (labels: false — también las etiquetas de cuerpos); solo quedan la escena, el subtítulo, las imágenes, las ventanas multimedia, las marcas (mark) y los dibujos del agente. on: false — volver
astroaction, nameastronauta: enter (donde está la cámara), goto name (volar allí, orbitar), land (pararse en el suelo), exit, link, state. Caminar y mirar — key/pointer
evalcodesolo servidor de desarrollo (npm run dev): ejecuta una expresión JS en la página; window.__known contiene el estado. No disponible en el sitio público

Contar una historia

cmdargsqué hace
captiontitle, sub, text, secondssubtítulo abajo a la izquierda como el salvapantallas (title vacío — ocultar)
saytext, title, sub, audio, keep, captionmostrar el texto como subtítulo; audio — una locución mp3 (enlace o nombre de archivo en el ordenador; sin voz del navegador — crea el mp3 de antemano, p. ej. edge-tts); 🔇 — silencioso
musicon, theme, volumemúsica de fondo generada en el navegador: tema 0 «Nebulosa», 1 «Profundidad», 2 «Cristales», null — rotar
imageid, src | path, at, x, y, dx, dy, w, label, remove, cleartu imagen sobre la escena: unida a un cuerpo (lo sigue) o en un punto de la pantalla
playsteps | stop | pause | seek | stepun guion completo reproducido por la página: [{cmd, args, wait}], wait = ms o "speech". Como un reproductor: pause, seek: n — saltar al paso n (los pasos anteriores se ejecutan de inmediato, sin esperas ni voz), step: ±1. La persona obtiene un reproductor abajo: ⏮ ⏪ ▶/⏸ ⏹ ⏩ ⏭, «diapositiva · paso», 💾 guardar en el sitio (contraseña), ⬇ descargar, 🗑 eliminar, ✕. Se detiene al desconectar — excepto con detach: true (se reproduce hasta el final y luego se revierte). onError: 'skip' (por defecto — continuar) | 'stop'; un paso fallido va a logs, a play sin argumentos (lastError) y al reproductor. Una presentación pasa sola a la siguiente diapositiva; ✕ o Esc — salir (la interfaz vuelve)
deckslides, start, go, closepresentación: [{title, steps}]; la persona obtiene «◀ n/N ▶» abajo (y RePág/AvPág), al moverse se reproducen los pasos de esa diapositiva. Permanece visible con hideUi
buttonsitemstus propios botones abajo: [{label, title, steps}], un clic reproduce los pasos; [] los elimina
storyaction, story, id, password, nameuna historia = lo que compuso el agente (plan de vuelo, narración, visualización — p. ej. para NASA Space Apps): {title, summary, lang, slides:[{title, steps}] | steps}. run — mostrar; publish — guardar en el sitio con una contraseña de edición (password; sin ella — la página se la pide a la persona) → enlace known.html?story=<uuid>, cualquiera la ve sin agente (con «◀ n/N ▶»); hasta 256 KB, se conserva 30 días tras la última apertura; update — editar (id + la misma contraseña); delete — eliminar del sitio (id + la misma contraseña); download — un archivo para la persona (cualquier tamaño); open — la persona elige un archivo (o suelta un .json en la página; menú «📂» en la barra del agente); load — por id
stepsdónde estamos en una historia o presentación: diapositiva y lista de diapositivas, paso y lista de pasos (n, label), playing, paused. Saltar — play {seek: n} / {step: ±1}, deck {go: n}. La persona tiene ☰ en el reproductor — la lista de diapositivas y pasos, clic para saltar
scenecodeuna escena del modo ambiente dentro de una historia — su vuelo de cámara, subtítulo y tiempo (~20–30 s, espera hasta el final). Códigos — scenes: body:Сатурн, event:<id>, mission:…, astro:…, lapse:…, galaxy, pullback. El modo ambiente («∞») es el mismo generador de escenas en el reproductor común: ⏮ ▶/⏸ ⏭, ☰ lo reproducido y todas las escenas, 💾/⬇ — lo reproducido como una historia de pasos de escena
scenestodas las escenas del modo ambiente por sección, con códigos
recordaction, fps, mbps / pathvídeo de la escena: start, stop (el MCP guarda WebM en path)

Un único punto de entrada: WS, MCP, consola, historia

Los comandos y el lenguaje son los mismos venga de donde venga: WebSocket desde cualquier lenguaje, MCP, la consola de la página (el botón >_ en la barra del agente) o una historia. Escribe un guion completo y dáselo a story, o llama a los comandos uno por uno. Novedad: exec {steps} — ejecutar pasos del lenguaje ahora (las variables persisten entre llamadas), expr {e} — evaluar una expresión, js {code, timeout} — JavaScript en un sandbox (iframe aislado + Web Worker: sin DOM, cookies ni red; dentro — await cmd(name, args), await expr('…'), log(), sleep(), return).

Consola: fly Mars size=0.6 (un comando, la primera palabra es el nombre), un comando JSON, pasos {…} / […], una expresión = …, código js ….

Guion base — Node.js:

// node agent.mjs <код>   (Node ≥ 22 — WebSocket integrado)
const code = process.argv[2], ws = new WebSocket(`wss://space.bl2.ru/agent/${code}?r=agent`);
let id = 0; const wait = new Map();
const cmd = (name, args = {}) => new Promise((res, rej) => {
  const i = ++id; wait.set(i, { res, rej }); ws.send(JSON.stringify({ id: i, cmd: name, args }));
});
ws.onmessage = (e) => {
  const m = JSON.parse(e.data);
  if (m.sys) return;                                   // peer / pong
  const w = wait.get(m.id); wait.delete(m.id);
  m.ok ? w.res(m.result) : w.rej(new Error(m.error));
};
setInterval(() => ws.send('{"sys":"ping"}'), 30000);
ws.onopen = async () => {
  await cmd('fly', { name: 'Mars', size: 0.6, lit: true });
  console.log(await cmd('expr', { e: "round(au(get('Mars','sun')),3)" }));
  await cmd('exec', { steps: [{ wait: "dist('camera','Mars') < 1e5 km" }, { cmd: 'caption', args: { title: 'Mars' } }] });
  process.exit(0);
};

Python:

# python agent.py <код>    (pip install websockets)
import asyncio, json, sys, websockets
async def main(code):
    async with websockets.connect(f"wss://space.bl2.ru/agent/{code}?r=agent") as ws:
        n = 0
        async def cmd(name, **args):
            nonlocal n; n += 1
            await ws.send(json.dumps({"id": n, "cmd": name, "args": args}))
            while True:
                m = json.loads(await ws.recv())
                if m.get("id") == n:
                    if not m["ok"]: raise RuntimeError(m["error"])
                    return m["result"]
        await cmd("fly", name="Saturn", size=0.6, lit=True)
        print(await cmd("expr", e="get('Saturn','moons')"))
asyncio.run(main(sys.argv[1]))

Lenguaje de guiones v2

Versiones: una historia sin v (o v: 1) — pasos y diapositivas como arriba; v: 2 — un lenguaje con condiciones. Una nueva versión del manejador nunca cambia las antiguas.

{ "v": 2, "title": "…", "on": ["oplanets"], "vars": { "n": 0 }, "steps": [
  { "cmd": "fly", "args": { "name": "Mars", "size": 0.5, "lit": true } },
  { "wait": "dist('camera', 'Mars') < 50000 km", "timeout": 20 },
  { "set": { "n": "n + 1" } },
  { "if": "visible('Mars')", "then": [ { "cmd": "caption", "args": { "title": "Mars", "sub": "{round(au(dist('camera','Sun')),3)} AU from the Sun" } } ] },
  { "repeat": 2, "do": [ { "wait": 1 } ] }
] }

Pasos: {cmd, args, wait} (wait — ms o una expresión), {wait: expression | seconds, timeout}, {if, then, else}, {repeat: n | expression, do}, {set: {name: expression}}, {on: [...]}. Expresiones — sin eval: números con unidades km au ly m, cadenas '…', variables, + - * / %, < > <= >= == !=, && || !; funciones dist(a, b) ('camera' o un cuerpo, km), visible(body), elapsed(), time(), camdist(), au(x), ly(x), round(x, d), abs min max. Propiedades al vuelo: get(body | 'camera', 'prop') — un cuerpo tiene name, kind, radius, parent, moons, x y z, sun (km desde el Sol), earth, camera (km desde la cámara), center, visible; la cámara tiene dist, yaw, pitch, fov, x y z, sun, center; sin prop — el objeto completo. El resultado de un comando a una variable: {cmd, args, as: 'r'}, un campo — field(r, 'rows.0.text'), tamaño — count(x). En las cadenas de args — {expression}. Los errores van a logs. Próximamente: disparadores (when/once/every) y un sandbox (cuerpos propios y modelos 3D). Funciones propias: {def: name, params, e} — en expresiones, {def, params, steps} — como un paso {call, args, as}, {local}, {return}; en una historia — funcs. Más funciones: angle(a, b) — grados entre direcciones desde la cámara, edge(a, b) — cuántos grados sobresale a por el limbo de b, sin cos (grados), pow sqrt. wait: true en un comando — hasta que termine. Para escenas: fitdist(r[, margin]) — la distancia desde la que un círculo de radio r km cabe en la pantalla (lado estrecho; un cuerpo también tiene day — periodo de rotación, s); satcount('all' | 'active' | 'debris' | 'rb' | 'dead') — objetos del catálogo alrededor de la Tierra; mstat(craft, 'launch' | 'km' | 'turns' | 'rmin' | 'rnow' | 'flybys') — cifras de una misión según su trayectoria, a fecha de hoy. Las trayectorias de naves y los sobrevuelos vienen de la importación (scripts/fetch-missions.mjs, JPL Horizons, diaria): una nave nueva en la base obtiene sus sobrevuelos y cifras automáticamente; flybys {craft} dibuja los puntos de sobrevuelo en su trayectoria. Multimedia en escenas: media {url | file, title, x, y, w, h, volume, loop, start, id} — una ventana con audio o vídeo: un enlace mp3/vídeo o YouTube; file — un archivo del ordenador de la persona (el sitio no almacena archivos: la persona lo elige en la ventana, luego se reproduce sin conexión); close: true cierra las ventanas. Estado: remember {name} — guardar la cámara, el tiempo, la vista y la interfaz; recall {name} — recuperarlo; onstop {restore: true} (en un archivo de historia — el campo "onstop": "restore") — al terminar, con Esc o ✕ todo vuelve a como estaba antes del inicio. Díselo a la persona: las historias y el salvapantallas se pueden manejar con un mando a distancia — un puntero de presentaciones (PageDown/PageUp, «.» o B — pantalla negra), teclas multimedia de teclados, auriculares y TV boxes (siguiente, anterior, pausa), un gamepad (cruceta ←/→, A — pausa, B — pantalla negra), flechas del teclado, Space, Esc. Enlaces directos: ?ambient — el salvapantallas, ?ambient=<scene code from ☰> — empezando por esa escena (p. ej. ?ambient=landings:Moon:apollo), ?story=<id>&step=N o &slide=N — una historia publicada desde ese punto; el botón 🔗 del reproductor copia un enlace a lo que se está reproduciendo. El comando ambient {play: code} hace lo mismo desde un agente; reset restablece cámara, tiempo y vista antes de una escena.

Cámara y movimiento

cmdargsqué hace
flyname, ms, ease, size, alt, lat, lon, rel, litVuelo en un solo movimiento directamente al encuadre: size — proporción de la altura de pantalla para el disco, alt — km sobre la superficie, lat/lon — sobre un punto de la superficie, rel: {to, deg, elev} — lado respecto a otro objeto (0° — está detrás de la cámara, 180° — detrás del cuerpo en el encuadre; elev — elevar). Devuelve ms.
cameradist, yaw, pitch, rel, ms, ease, targetCámara alrededor del centro de la vista; rel como en fly. target: {between: [a, b], k} — mirar a un punto entre cuerpos; {sat: 25544} — orbitar alrededor de un satélite (NORAD); {sat, space: {tilt, spin, from, ms}} — vista desde el espacio (la Tierra detrás del satélite): tilt° desde la vertical, spin °/s, aproximación desde from km hasta dist durante ms; null — volver al cuerpo.
mediaurl | file, kind, title, x, y, w, h, volume, loop, start, id, anchor, dx, dy, header, close, forgetDirUna ventana con audio o vídeo: un enlace (mp3/vídeo/YouTube) o file — un archivo del ordenador (la persona lo elige). anchor: {sat: NORAD} | {body: name} — la ventana sigue a un objeto (dx, dy — desplazamiento, px); header: false — sin barra de título (por defecto cuando está anclada). Devuelve ms para wait: true. close: true | id; forgetDir: true — olvidar la carpeta de medios. Antes de que empiece una historia — la ventana «Preparando la escena» (archivos, precarga de enlaces).
ambientplaySalvapantallas «∞» desde una escena dada: código como en ☰ (hover|Mars, landings:Moon:apollo, event:eclSun, mission:Parker, satellites…); sin play — la lista de códigos.
langsetIdioma de la interfaz: sin set — el actual y la lista (ru, en, es, zh, pt); set — cambiarlo. Cambia al instante, sin recargar: el agente sigue conectado. La pantalla de reposo reproduce de nuevo la escena actual en el nuevo idioma; el reproductor, la ficha, el árbol de capas y las ventanas se redibujan. La dirección de la página pasa a ser /<idioma>/ (por ejemplo /es/; el idioma propio del dominio es simplemente /): el idioma lo fija solo la dirección, no hay parámetro ?lang=; el enlace al sitio en un idioma es https://space.bl2.net/<idioma>/ (ruso — https://space.bl2.ru/).
reset—Antes de una escena: detiene la órbita, la mirada y las rampas de tiempo; Galaxia apagada; se eliminan marcas, puntos de sobrevuelo y ventanas multimedia (las escenas del salvapantallas lo hacen solas).
remember / recallnameGuardar el estado (cámara, tiempo, vista, interfaz) / recuperarlo.
onstoprestoreActivado por defecto: al terminar, con Esc, ✕ o la salida del agente, todo vuelve a como estaba antes del primer comando del agente: capas e interruptores de vista, paneles e interfaz oculta, cámara (ángulo, distancia, centro, seguimiento), selección, tiempo y velocidad (o «live»); la música y la voz se detienen. Las cosas propias del agente (sites, draw, mark, flybys, image, media, spawn) siempre se eliminan. restore: false (en un archivo de historia — "onstop": "keep") — conservar la cámara, el tiempo y la selección como los dejó el agente. exec se revierte al terminar solo con un onstop {restore: true} explícito.
consoleopenAbrir / cerrar la consola >_.
sitesbody | code, group, ids, light, onSitios de aterrizaje: fichas en puntos de la superficie (en la escena). body puede omitirse — el cuerpo sale del grupo (apollo, luna, rovers, new, farside, first, china — Luna; mars, chryse — Marte; venera — Venus) o de ids. Ejemplo: sites {group: 'apollo', light: true} → {lat, lon, alt, at, ids}; luego time {at, rate: 0} y fly {name: 'Moon', lat, lon, alt}. Sin volar a lat/lon la cámara puede mirar la cara oculta — no se ven fichas. light: true — una hora en que los sitios están a la luz del día (respuesta at).
flybyscraft, onPuntos de asistencia gravitatoria e inserción orbital en la trayectoria de una nave (de la trayectoria de la misión).
orbitspeed (°/s), turns | ms, pitch, dist, end, blend, ease, stopOrbitar alrededor del cuerpo. end: {to, deg, elev} — terminar exactamente en ese encuadre (una dirección, sin volver atrás). Si termina con velocidad, sigue por inercia y el siguiente fly toma esa velocidad.
lookto, ms, ease, clearMirar a un objeto: el ojo se queda (o sigue orbitando), la vista gira suavemente y lo sigue. clear: true — volver al centro.
select, shadow, camera targetname; name, by, center, ms, dist; targetPara escenas del salvapantallas: select {name} — resaltar la trayectoria de un cuerpo ('' — borrar); shadow {name, by, center, ms, dist} — cámara en el punto de la sombra del eclipse; camera {target: {between: [a, b], k}, ms} — punto de mira entre cuerpos (orbit gira alrededor), target: null — volver; look {to: 'galcenter'}; fly {frame: {path, from, to, with}, elev, deg} — encuadrar toda la trayectoria de una nave.
followname, ms, dist, easeSeguir a otro objeto: traspaso suave manteniendo el encuadre.

Mostrar un cuerpo pequeño (un cometa, un objeto interestelar — invisible desde decenas de millones de km): follow {name} o fly {name}, luego mark {name, label: true} — un marcador multicolor parpadeante en el cuerpo (visible también con hideUi; también color, speed), select {name} — su trayectoria brillante. Quitar: mark {remove: name} o mark {clear: true}, select {name: ''}; la reversión de onstop y la salida del agente eliminan las marcas por sí solas.

Suavizado ease — como una función de temporización CSS: linear, ease, ease-in, ease-out, ease-in-out, smooth, cubic-bezier(x1,y1,x2,y2) o una fórmula de t (0…1): 1-pow(1-t,2), t*t*t*(t*(6*t-15)+10).

Solapamiento: {cmd, args, then: [steps], before_end: ms | after_begin: ms | when: "condition"} — los pasos anidados se ejecutan junto con el comando. Ejemplo: orbitar la Tierra, girar hacia Ío, volar hasta él:

[ {"cmd": "fly", "args": {"name": "Earth", "size": 0.4, "rel": {"to": "sun", "deg": 0, "elev": 10}, "ms": 3000, "ease": "ease-in-out"}, "wait": true},
  {"cmd": "orbit", "args": {"speed": 60, "ms": 6000, "ease": "ease-in"},
   "when": "edge('Io','Earth') < 15", "then": [{"cmd": "look", "args": {"to": "Io", "ms": 1500}, "wait": true}], "wait": true},
  {"cmd": "fly", "args": {"name": "Io", "size": 0.15, "rel": {"to": "Jupiter", "deg": 180, "elev": 15}, "ms": 8000, "ease": "ease-out"}, "wait": true} ]

Sandbox, dibujo, astronauta

cmdargsqué hace
spawnid, like, diameter, color, at: {near, dist, dir} | pos, velTu propio objeto: una copia de un cuerpo o una roca; toma una órbita circular alrededor del cuerpo dominante (física, no líneas rectas)
moveid, vel | impact: {target, at}Nueva velocidad o «golpear un cuerpo en un instante»
despawn / objectsid | allEliminar / listar
drawitems | clear | removeGráficos en el espacio para depuración y lecciones: arrow (vel, sun, north, {sum}), axes (roll/pitch/yaw), line, dash, path, angle (arco y grados), project (proyección sobre un cuerpo, altitud), point, text; label — texto a lo largo de la línea
flybyscraft, onPuntos de asistencia gravitatoria en la trayectoria de una nave: «Cuerpo · fecha» y lo que dio la asistencia; on: false — eliminar
sitesbody | code, group, ids, light, onSitios de aterrizaje (Luna, Marte, Venus, Titán): puntos y fichas en la escena — foto, nombre, año, descripción; group — vista combinada (apollo, luna, rovers, new, farside, first, china, mars, chryse, venera; el cuerpo se deduce del grupo, body es opcional); light: true — sitios en el lado diurno; devuelve lat, lon, alt para fly; on: false — eliminar
astroaction: goto | view | shield | land | exit, name, tpd, yaw, pitch, on, textAstronauta: anclarlo a cualquier cosa (cuerpo, ISS, número NORAD, asteroide); view — mirar la figura; shield — quitar/poner un escudo, mensaje propio

Consola de la página — la tecla de acento grave (ё en la distribución rusa).

Cómo trabajar

  1. Lee esta página (help), connect con el código.
  2. Pide datos a la página: search / open (objetos), body (tamaños, lado iluminado), where (posiciones), find (eventos), layers, state.
  3. Prepara las acciones a partir de esos datos: un guion play, o un deck de diapositivas que la persona recorre, o buttons.
  4. Ejecútalo; comprueba con screenshot y logs; ajusta.

5. Ejemplo: «cuéntame sobre los planetas»

connect {code}
layers → layer {key, visible:false} for everything except oplanets
music {theme: 0, volume: 0.4};  hide_ui {on: true}
play {steps: [
  {cmd:"fly", args:{name:"Mars"}, wait: 3800},
  {cmd:"camera", args:{yaw: …, pitch: …, dist: …, ms: 3000}, wait: 3200},   // valores de body {name:"Mars"}
  {cmd:"say", args:{title:"Mars", sub:"228 million km · light takes 13 min", text:"…", audio:"mars.mp3"}, wait: "speech"}, // la voz es Piper en el navegador (ru ruslan, en amy); audio — un mp3 ya hecho en su lugar
  …
]}

6. Recursos

Reglas: la página acepta solo estos comandos; sin navegación a otros sitios, sin datos personales. Mantén a la persona al control — puede pulsar «Desconectar» en cualquier momento.