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

«Espaço Agora» — API do agente

Esta página é para agentes de IA (e para as pessoas que os usam). Ela explica como um agente se conecta a uma página «Espaço Agora» ativa (known.html) no navegador de uma pessoa e o que ele pode fazer ali: tudo o que a interface faz — abrir qualquer objeto, mover a câmera, avançar o tempo, alternar camadas e filtros, modo astronauta, encontrar eclipses e desfiles de planetas, contar um roteiro com voz e legendas, exibir imagens próprias, gravar vídeo, ler erros. A renderização acontece no navegador da pessoa (WebGL na GPU dela); o agente envia comandos e recebe respostas e capturas de tela.

1. Pareamento

  1. A pessoa abre o site e pressiona o botão redondo 🤖 (canto inferior direito, acima do astronauta) — a barra do agente se abre; «Ligar o agente» mostra um código (20 caracteres, ex.: r4fxjbjsxdy6ex3pf4hd). O código é a senha: quem o tem controla esta aba. 🤖 apenas oculta/mostra a barra, a conexão permanece; «Desconectar» na barra a desliga. A barra sempre tem 📂 (abrir um arquivo de roteiro ou salvar o exibido — também sem agente) e «MCP ↗» (esta página).
  2. A pessoa entrega o código ao agente. O agente chama connect com ele.
  3. Conexão permanente (opcional): na página — 📌 «Lembrar» na barra do agente (o código fica neste navegador, o site se conecta sozinho toda vez que abre); o agente — connect com save: true (código em ~/.orbit-agent.json, o MCP conecta ao iniciar). Depois disso, basta abrir o site. Para esquecer: desafixe 📌 e chame forget.
  4. «Desconectar» na página (ou a saída do agente) encerra a sessão; a página então devolve camadas e interface ao estado anterior ao agente, para a música, a voz, as legendas, as imagens e os cenários, e remove locais de pouso (sites), desenhos e marcas (draw, mark, flybys), janelas de mídia e corpos próprios (spawn) — independentemente de onstop. A câmera, o tempo e a seleção também voltam (por padrão; onstop {restore: false} — manter o que o agente mostrou). Exceção: play / story run com detach: true — a apresentação toca até o fim e só então é revertida.

O som (voz, música) só começa depois que a pessoa clicou na página ao menos uma vez — regra do navegador. A voz vem desligada por padrão: a pessoa a liga com 🔊 na barra do agente (fica lembrado); as legendas são sempre exibidas.

Checklist da apresentação — faça sempre

[
  {"cmd":"onstop","args":{"restore":true}},        // primeiro passo: ao terminar, com Esc ou ✕ tudo volta
  {"cmd":"reset"},
  {"cmd":"view","args":{"on":["oplanets"]}},        // só as camadas necessárias: satélites, naves, órbitas, constelações desligados
  {"cmd":"hideUi","args":{"on":true,"labels":false}},
  {"cmd":"time","args":{"at":"<moment>","rate":0}}, // defina o tempo você mesmo; rate 0 — a iluminação não se desloca
  … voo (fly) …
  … a apresentação …
]

2. Transporte

Os dois lados se conectam a uma sala de retransmissão no mesmo site: wss://<site>/agent/<code>?r=agent (a página usa ?r=page). A sala encaminha mensagens entre os dois; nada é armazenado. Mensagens 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 }      (o outro lado entrou / saiu)
keepalive      envie { "sys": "ping" } a cada 30 s, a sala responde { "sys": "pong" }

Uma conexão por papel (um novo agente com o mesmo código substitui o antigo, código de fechamento 4000 — não reconecte nesse caso). Mensagens de até 4 MB. Sites: https://space.bl2.ru, https://space.bl2.net (o mesmo site, ru/en por padrão).

3. Servidor MCP

Servidor MCP pronto (stdio): scripts/agent-mcp.mjs no repositório orbit-proto (Node ≥ 20, dependência ws). Cada comando abaixo é uma ferramenta de mesmo nome (hide_ui → comando da página hideUi), além de connect, disconnect, help (esta página como texto; lang: en). Arquivos: image recebe path, record salva em path, screenshot retorna uma imagem.

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

Env: AGENT_SITE — site padrão, AGENT_CODE — conectar na inicialização.

Conexão sem o servidor MCP (agentes na nuvem)

// «iniciar e retornar» — do console de uma aba em space.bl2.ru (ou 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 bilhão de km do Sol' }, wait: 8000 },
  ] });
  ws.close(); // a apresentação continua sozinha e depois recoloca tudo no lugar
};

4. Comandos

Observação e estado

cmdargso quê
statetempo, rate, objeto selecionado, centro da vista, câmera (yaw, pitch, dist km, fov), estrela próxima, chaves das camadas visíveis, tamanho do canvas em px
screenshotwidth, quality, fullJPEG da cena 3D. full: true — a aba inteira com a interface (a pessoa autoriza a captura da aba uma vez, pelo «📷» na barra do agente)
bodynamepara enquadramento: raio km, kind, parent, luas, ângulos da câmera, sunYaw/sunPitch (direção da câmera da qual o corpo fica totalmente iluminado), fov, distForSize {0.25, 0.5, 0.66, 0.8 → km}: distância em que o disco ocupa essa fração da altura da tela (= raio / tan(fov/2) / k)
wherename, atposição em um instante: km e UA a partir do Sol e da Terra, AR/Dec a partir da Terra (J2000)
logslevel, last, clearerros/avisos/informações do console da página (buffer circular de 300)
snapshotestado completo (tempo, rate, câmera, centro, seleção, todas as caixas de camadas, interface oculta, link do astronauta) — guarde-o para reproduzir um bug
restorestatevoltar a um snapshot

Vista, câmera, tempo, camadas

cmdargso quê
searchq, limitbusca na base de objetos como o campo de busca: corpos, luas, naves espaciais, nebulosas e galáxias (quando a camada delas está ligada), satélites da Terra (nome ou NORAD), asteroides (nome ou número; o catálogo carrega pela linha load-asteroids). Retorna linhas com n
opennabrir um resultado da busca: seleção, ficha, voo — como clicar na linha
gosearchabrir uma vista como um link de compartilhamento: ?o= corpo (Mars, Марс, ISS…), ?a= asteroide (número ou nome), ?s= satélite NORAD, ?g= galáxia, ?n= nebulosa, ?st= estrela de constelação; extras d= câmera km, v=yaw,pitch, t= tempo ISO
flyname, size, lit, face, secondsvoo suave até um corpo (como um clique na árvore). size — fração da altura da tela para o corpo (0.66 — dois terços), lit: true — pelo lado iluminado; o enquadramento leva ~2,5 s a mais depois do voo (~6 s no total, use wait ≥ 6500). face: "spot" — Júpiter: o tempo retrocede até a Grande Mancha Vermelha estar no lado diurno
camerayaw, pitch, dist, mscâmera em torno do centro da vista (rad, km). ms > 0 — mover suavemente ao longo de ms. Exemplo «preencher 2/3 da tela, lado iluminado»: body → camera {yaw: sunYaw+0.4, pitch: sunPitch, dist: distForSize[0.66], ms: 3000}
timeat, rate, live, from, tofrom, to, ms, ease — avanço suave de uma data a outra; at — segundos Unix ou instante ISO (a.C.: -000500-01-01), velocidade (1 real, 3600 = 1 h/s, negativa = para trás, 0 pausa), live: true
viewon, set, orbitsview — chaves padrão para cada alternância. Sem args — lista {key, on}; on: [...] — desliga tudo e liga só o listado; set: {key: true|false} — altera só estas; orbits: false — todas as linhas de órbita de uma vez. Chaves (cada grupo também tem <key>:orbits — suas linhas de órbita): oplanets — Sol, planetas e luas; odwarfs — planetas anões e os maiores asteroides; ohelio — heliopausa; oshock — choque de terminação; osandbox — corpos próprios (spawn); oknown-small — pequenos conhecidos (Apophis, Bennu…); ocomets — cometas; ointerstellar — objetos interestelares (1I, 2I, 3I); okuiper — cinturão de Kuiper; ooort — nuvem de Oort; a0…a9 — asteroides por tamanho (a0 — acima de 100 km); ocraft, ocraft-orbit, ocraft-l — naves em voo, em órbita de corpos, em pontos de Lagrange; s0…s30 — grupos de satélites da Terra, sats — todos de uma vez; ogalaxy — modelo da Via Láctea; ouniverse — galáxias; stars — estrelas de constelações com nomes; conlines — linhas das figuras de constelações (com stars; não listado em view {on} — sem linhas); galmarks — rótulos do centro galáctico e do ápice; galsun — «Sol — você está aqui»; scenelabels — rótulos só no que a cena precisa (labels {only}). Um único caminho interestelar: desligue ointerstellar:orbits, select {name: '3I/ATLAS'} — o caminho dele fica brilhante. Também: earth:ph|cities|seas|mountains|volcanoes, weather, aurora (aurora), sw (clima espacial), sk:0…6, sk:neb. Roteiros e slides aceitam um campo on (aplicado antes dos passos): liste só o necessário — novas camadas ligadas por padrão não aparecerão em roteiros antigos
layerstodos os grupos de camadas: key, name, visible, orbits, count
layerkey, visible, orbitsalternar uma camada. Chaves: oplanets, odwarfs, ocomets, ocraft*, ogalaxy, ouniverse, a0…a9 asteroides por tamanho, s0… grupos de satélites…
galaxyfarvista da Via Láctea (far — com outras galáxias). Para cenas: dist (0 — modelo no Sol, > 0 — afastar-se), pitch, center: true — orbitar o centro galáctico, off: true; tempo galáctico — galtime {rate} (anos/s)
galaxiescount, dwellsobrevoar N galáxias famosas por distância, dwell segundos em cada
cleardesselecionar, fechar a ficha

Eventos (calculados pela página, sem precisar de fórmulas)

cmdargso quê
findkind, from, to, total, count, minlunar (total: true — «lua de sangue»), solar, parade (min de planetas 3…7) a partir de qualquer data; retorna o instante médio, total?, lat/lon/região onde é visível; lunar — contact (toque da umbra)
showkind, at, keepViewmostrar um evento como em «📅 Eventos»: tempo — meia hora antes do meio, velocidade ×100 (defina time {rate: 0} ou a sua), seleção limpa, centro da vista e câmera na Terra (solar: acima do ponto da sombra) ou na Lua (lunar); um desfile — vista em primeira pessoa a partir da Terra, só planetas. As camadas definidas com view permanecem (keepView: false — as do evento). Depois: hideUi, camera se necessário

Interface inteira

cmdargso quê
uitext, withintodo botão, caixa de seleção, controle deslizante, campo, linha de lista/árvore visível, com ref, texto, id, atributos data, estado. Filtro por texto ou área CSS
clickref | selectorpressionar
setref | selector, valuecaixa de seleção true/false, controle deslizante, campo, select
keycode, ms, shift, ctrlpressionar tecla (KeyW… segure ms para voar, Space pausa, KeyH oculta painéis, Escape…)
pointeraction, x, y, to, dymouse na cena 3D: click (selecionar), dblclick (voar até), move (hover), drag (girar) até [x,y], wheel (dy zoom)
hideUion, labelsocultar tudo: painéis, botões de canto, a barra do agente (labels: false — também os rótulos dos corpos); ficam só a cena, a legenda, as imagens, as janelas de mídia, as marcas (mark) e os desenhos do agente. on: false — volta
astroaction, nameastronauta: enter (onde a câmera está), goto name (voar até lá, orbitar), land (ficar de pé no solo), exit, link, state. Andar e olhar — key/pointer
evalcodesó no servidor de desenvolvimento (npm run dev): executa uma expressão JS na página; window.__known guarda o estado. Indisponível no site público

Contar um roteiro

cmdargso quê
captiontitle, sub, text, secondslegenda no canto inferior esquerdo como na proteção de tela (title vazio — ocultar)
saytext, title, sub, audio, keep, captionmostrar o texto como legenda; audio — uma narração em mp3 (link ou nome de arquivo no computador; sem voz do navegador — gere o mp3 antes, p. ex. com edge-tts); 🔇 — silencioso
musicon, theme, volumemúsica de fundo gerada no navegador: theme 0 «Nebulosa», 1 «Profundeza», 2 «Cristais», null — alternar
imageid, src | path, at, x, y, dx, dy, w, label, remove, clearsua imagem sobre a cena: presa a um corpo (o acompanha) ou em um ponto da tela
playsteps | stop | pause | seek | stepum cenário inteiro tocado pela página: [{cmd, args, wait}], wait = ms ou "speech". Como um player: pause, seek: n — pular para o passo n (os passos anteriores executam de imediato, sem esperas nem voz), step: ±1. A pessoa recebe um player embaixo: ⏮ ⏪ ▶/⏸ ⏹ ⏩ ⏭, «slide · passo», 💾 salvar no site (senha), ⬇ baixar, 🗑 excluir, ✕. Para ao desconectar — exceto com detach: true (toca até o fim e depois reverte). onError: 'skip' (padrão — continuar) | 'stop'; um passo com falha vai para logs, para play sem args (lastError) e para o player. Uma apresentação passa ao próximo slide sozinha; ✕ ou Esc — sair (a interface volta)
deckslides, start, go, closeapresentação: [{title, steps}]; a pessoa recebe «◀ n/N ▶» embaixo (e PageUp/PageDown), avançar executa os passos daquele slide. Permanece visível com hideUi
buttonsitemsseus próprios botões embaixo: [{label, title, steps}], um clique executa os passos; [] remove
storyaction, story, id, password, nameum roteiro = o que o agente compôs (plano de voo, narração, visualização — p. ex. para o NASA Space Apps): {title, summary, lang, slides:[{title, steps}] | steps}. run — exibir; publish — salvar no site com uma senha de edição (password; sem ela — a página pergunta à pessoa) → link known.html?story=<uuid>, qualquer um o vê sem agente (com «◀ n/N ▶»); até 256 KB, guardado por 30 dias após a última abertura; update — editar (id + a mesma senha); delete — excluir do site (id + a mesma senha); download — um arquivo para a pessoa (qualquer tamanho); open — a pessoa escolhe um arquivo (ou solta um .json na página; menu «📂» na barra do agente); load — por id
stepsonde estamos em um roteiro ou apresentação: slide e lista de slides, passo e lista de passos (n, label), playing, paused. Pular — play {seek: n} / {step: ±1}, deck {go: n}. A pessoa tem ☰ no player — a lista de slides e passos, clique para pular
scenecodeuma cena do modo ambiente dentro de um roteiro — seu voo de câmera, legenda e tempo (~20–30 s, aguarda o fim). Códigos — scenes: body:Сатурн, event:<id>, mission:…, astro:…, lapse:…, galaxy, pullback. O próprio modo ambiente («∞») é o mesmo gerador de cenas no player comum: ⏮ ▶/⏸ ⏭, ☰ reproduzidas e todas as cenas, 💾/⬇ — o que foi reproduzido como um roteiro de passos de cena
scenestodas as cenas ambiente por seção, com códigos
recordaction, fps, mbps / pathvídeo da cena: start, stop (o MCP salva WebM em path)

Um ponto de entrada: WS, MCP, console, roteiro

Os comandos e a linguagem são os mesmos, venham de onde vierem: WebSocket de qualquer linguagem, MCP, o console da página (o botão >_ na barra do agente) ou um roteiro. Escreva um cenário inteiro e entregue a story, ou chame os comandos um a um. Novidade: exec {steps} — executa passos da linguagem agora (as variáveis persistem entre chamadas), expr {e} — avalia uma expressão, js {code, timeout} — JavaScript em sandbox (iframe isolado + Web Worker: sem DOM, cookies ou rede; dentro — await cmd(name, args), await expr('…'), log(), sleep(), return).

Console: fly Mars size=0.6 (um comando, a primeira palavra é o nome), um comando JSON, passos {…} / […], uma expressão = …, código js ….

Script base — Node.js:

// node agent.mjs <código>   (Node ≥ 22 — WebSocket embutido)
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 <código>    (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]))

Linguagem de cenário v2

Versões: um roteiro sem v (ou v: 1) — passos e slides como acima; v: 2 — uma linguagem com condições. Uma nova versão do manipulador nunca altera as antigas.

{ "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)} UA do Sol" } } ] },
  { "repeat": 2, "do": [ { "wait": 1 } ] }
] }

Passos: {cmd, args, wait} (wait — ms ou uma expressão), {wait: expression | seconds, timeout}, {if, then, else}, {repeat: n | expression, do}, {set: {name: expression}}, {on: [...]}. Expressões — sem eval: números com unidades km au ly m, strings '…', variáveis, + - * / %, < > <= >= == !=, && || !; funções dist(a, b) ('camera' ou um corpo, km), visible(body), elapsed(), time(), camdist(), au(x), ly(x), round(x, d), abs min max. Propriedades na hora: get(body | 'camera', 'prop') — um corpo tem name, kind, radius, parent, moons, x y z, sun (km do Sol), earth, camera (km da câmera), center, visible; a câmera tem dist, yaw, pitch, fov, x y z, sun, center; sem prop — o objeto inteiro. O resultado de um comando em uma variável: {cmd, args, as: 'r'}, um campo — field(r, 'rows.0.text'), tamanho — count(x). Em strings de args — {expression}. Os erros vão para logs. A seguir: gatilhos (when/once/every) e um sandbox (spawn de corpos e modelos 3D). Funções próprias: {def: name, params, e} — em expressões, {def, params, steps} — como um passo {call, args, as}, {local}, {return}; em um roteiro — funcs. Mais funções: angle(a, b) — graus entre as direções a partir da câmera, edge(a, b) — quantos graus a aparece além do limbo de b, sin cos (graus), pow sqrt. wait: true em um comando — até ele terminar. Para cenas: fitdist(r[, margin]) — a distância a partir da qual um círculo de raio r km cabe na tela (lado menor; um corpo também tem day — período de rotação, s); satcount('all' | 'active' | 'debris' | 'rb' | 'dead') — objetos do catálogo ao redor da Terra; mstat(craft, 'launch' | 'km' | 'turns' | 'rmin' | 'rnow' | 'flybys') — números da missão a partir de sua trajetória, até hoje. As trajetórias de naves e os sobrevoos vêm da importação (scripts/fetch-missions.mjs, JPL Horizons, diária): uma nova nave na base recebe seus sobrevoos e números automaticamente; flybys {craft} desenha os pontos de sobrevoo em seu caminho. Mídia em cenas: media {url | file, title, x, y, w, h, volume, loop, start, id} — uma janela com áudio ou vídeo: um link de mp3/vídeo ou YouTube; file — um arquivo do computador da pessoa (o site não guarda arquivos: a pessoa o escolhe na janela e então ele toca offline); close: true fecha as janelas. Estado: remember {name} — salva a câmera, o tempo, a vista e a interface; recall {name} — traz de volta; onstop {restore: true} (em um arquivo de roteiro — o campo "onstop": "restore") — ao terminar, com Esc ou ✕, recoloca tudo como antes do início. Avise a pessoa: roteiros e a proteção de tela podem ser controlados por um controle remoto — um apresentador de slides (PageDown/PageUp, «.» ou B — tela preta), teclas de mídia de teclados, fones e TV boxes (próximo, anterior, pausa), um gamepad (D-pad ←/→, A — pausa, B — tela preta), setas do teclado, Space, Esc. Links diretos: ?ambient — a proteção de tela, ?ambient=<scene code from ☰> — começando por aquela cena (p. ex. ?ambient=landings:Moon:apollo), ?story=<id>&step=N ou &slide=N — um roteiro publicado a partir daquele ponto; o botão 🔗 no player copia um link para o que está tocando. O comando ambient {play: code} faz o mesmo a partir de um agente; reset zera câmera, tempo e vista antes de uma cena.

Câmera e movimento

cmdargso quê
flyname, ms, ease, size, alt, lat, lon, rel, litVoo em um só movimento direto para o enquadramento: size — fração da altura da tela para o disco, alt — km acima da superfície, lat/lon — acima de um ponto da superfície, rel: {to, deg, elev} — lado em relação a outro objeto (0° — ele fica atrás da câmera, 180° — atrás do corpo no quadro; elev — elevar). Retorna ms.
cameradist, yaw, pitch, rel, ms, ease, targetCâmera em torno do centro da vista; rel como em fly. target: {between: [a, b], k} — olhar para um ponto entre corpos; {sat: 25544} — orbitar um satélite (NORAD); {sat, space: {tilt, spin, from, ms}} — vista do espaço (a Terra atrás do satélite): tilt° da vertical, spin °/s, aproximação de from km até dist ao longo de ms; null — volta ao corpo.
mediaurl | file, kind, title, x, y, w, h, volume, loop, start, id, anchor, dx, dy, header, close, forgetDirUma janela com áudio ou vídeo: um link (mp3/vídeo/YouTube) ou file — um arquivo no computador (a pessoa o escolhe). anchor: {sat: NORAD} | {body: name} — a janela acompanha um objeto (dx, dy — deslocamento, px); header: false — sem barra de título (padrão quando ancorada). Retorna ms para wait: true. close: true | id; forgetDir: true — esquecer a pasta de mídia. Antes de um roteiro começar — a janela «Preparando a cena» (arquivos, pré-carregamento de links).
ambientplayProteção de tela «∞» a partir de uma cena dada: código como em ☰ (hover|Mars, landings:Moon:apollo, event:eclSun, mission:Parker, satellites…); sem play — a lista de códigos.
langsetIdioma da interface: sem set — o atual e a lista (ru, en, es, zh, pt); set — trocar. Troca na hora, sem recarregar: o agente continua conectado. O protetor de tela reproduz a cena atual de novo no novo idioma; o player, o cartão, a árvore de camadas e as janelas são redesenhados. O endereço da página passa a ser /<idioma>/ (por exemplo /pt/; o idioma do próprio domínio é só /): o idioma é definido apenas pelo endereço, não existe o parâmetro ?lang=; o link do site em um idioma é https://space.bl2.net/<idioma>/ (russo — https://space.bl2.ru/).
reset—Antes de uma cena: para a órbita, as rampas de olhar e de tempo; Galáxia desligada; marcas, pontos de sobrevoo e janelas de mídia removidos (as cenas da proteção de tela fazem isso sozinhas).
remember / recallnameSalvar o estado (câmera, tempo, vista, interface) / trazê-lo de volta.
onstoprestoreLigado por padrão: ao terminar, com Esc, ✕ ou a saída do agente, recoloca tudo como antes do primeiro comando do agente: camadas e alternâncias de vista, painéis e interface oculta, câmera (ângulo, distância, centro, rastreamento), seleção, tempo e velocidade (ou «ao vivo»); música e voz param. As coisas do próprio agente (sites, draw, mark, flybys, image, media, spawn) são sempre removidas. restore: false (em um arquivo de roteiro — "onstop": "keep") — mantém a câmera, o tempo e a seleção como o agente os deixou. exec reverte ao seu término só com um onstop {restore: true} explícito.
consoleopenAbrir / fechar o console >_.
sitesbody | code, group, ids, light, onLocais de pouso: fichas em pontos da superfície (na cena). body pode ser omitido — o corpo vem do grupo (apollo, luna, rovers, new, farside, first, china — Lua; mars, chryse — Marte; venera — Vênus) ou de ids. Exemplo: sites {group: 'apollo', light: true} → {lat, lon, alt, at, ids}; depois time {at, rate: 0} e fly {name: 'Moon', lat, lon, alt}. Sem voar até lat/lon, a câmera pode ficar de frente para o lado oculto — nenhuma ficha visível. light: true — um instante em que os locais estão sob luz do dia (resposta at).
flybyscraft, onPontos de assistência gravitacional e de inserção em órbita no caminho de uma nave (da trajetória da missão).
orbitspeed (°/s), turns | ms, pitch, dist, end, blend, ease, stopOrbitar o corpo. end: {to, deg, elev} — terminar exatamente nesse enquadramento (uma direção, sem voltar). Terminando em velocidade — segue por inércia, o próximo fly assume a velocidade.
lookto, ms, ease, clearOlhar para um objeto: o olho fica (ou continua orbitando), a vista gira suavemente e o acompanha. clear: true — volta ao centro.
select, shadow, camera targetname; name, by, center, ms, dist; targetPara cenas da proteção de tela: select {name} — destacar o caminho de um corpo ('' — limpar); shadow {name, by, center, ms, dist} — câmera no ponto da sombra do eclipse; camera {target: {between: [a, b], k}, ms} — ponto de mira entre corpos (a órbita o circunda), target: null — volta; look {to: 'galcenter'}; fly {frame: {path, from, to, with}, elev, deg} — enquadrar o caminho inteiro de uma nave.
followname, ms, dist, easeSeguir outro objeto: passagem suave mantendo o enquadramento.

Mostrar um corpo pequeno (um cometa, um objeto interestelar — invisível a dezenas de milhões de km): follow {name} ou fly {name}, depois mark {name, label: true} — um marcador multicolorido piscante no corpo (visível também com hideUi; também color, speed), select {name} — o caminho dele fica brilhante. Remover: mark {remove: name} ou mark {clear: true}, select {name: ''}; a reversão do onstop e a saída do agente removem as marcas sozinhas.

Suavização ease — como uma função de temporização CSS: linear, ease, ease-in, ease-out, ease-in-out, smooth, cubic-bezier(x1,y1,x2,y2) ou uma fórmula de t (0…1): 1-pow(1-t,2), t*t*t*(t*(6*t-15)+10).

Sobreposição: {cmd, args, then: [steps], before_end: ms | after_begin: ms | when: "condition"} — os passos aninhados rodam junto com o comando. Exemplo: orbitar a Terra, voltar-se para Io, voar até ela:

[ {"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, desenho, astronauta

cmdargso quê
spawnid, like, diameter, color, at: {near, dist, dir} | pos, velSeu próprio objeto: uma cópia de um corpo ou uma rocha; ele assume uma órbita circular em torno do corpo dominante (física, não linhas retas)
moveid, vel | impact: {target, at}Nova velocidade ou «atingir um corpo em um instante»
despawn / objectsid | allRemover / listar
drawitems | clear | removeGráficos no espaço para depuração e aulas: arrow (vel, sun, north, {sum}), axes (roll/pitch/yaw), line, dash, path, angle (arco e graus), project (projeção sobre um corpo, altitude), point, text; label — texto ao longo da linha
flybyscraft, onPontos de assistência gravitacional no caminho de uma nave: «Corpo · data» e o que a assistência deu; on: false — remover
sitesbody | code, group, ids, light, onLocais de pouso (Lua, Marte, Vênus, Titã): pontos e fichas na cena — foto, nome, ano, descrição; group — vista combinada (apollo, luna, rovers, new, farside, first, china, mars, chryse, venera; o corpo vem do grupo, body é opcional); light: true — locais no lado diurno; retorna lat, lon, alt para fly; on: false — remover
astroaction: goto | view | shield | land | exit, name, tpd, yaw, pitch, on, textAstronauta: ancorar em qualquer coisa (corpo, ISS, número NORAD, asteroide); view — olhar para a figura; shield — remover/colocar um escudo, mensagem própria

Console da página — a tecla crase (ё no layout russo).

Como trabalhar

  1. Leia esta página (help), faça connect com o código.
  2. Peça dados à página: search / open (objetos), body (tamanhos, lado iluminado), where (posições), find (eventos), layers, state.
  3. Prepare as ações a partir desses dados: um cenário play, ou um deck de slides que a pessoa percorre, ou buttons.
  4. Execute; confira com screenshot e logs; ajuste.

5. Exemplo: «conte-me sobre os 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"}, // a voz é Piper no navegador (ru ruslan, en amy); audio — um mp3 pronto no lugar dela
  …
]}

6. Recursos

Regras: a página aceita somente esses comandos; sem navegação para outros sites, sem dados pessoais. Mantenha a pessoa no controle — ela pode pressionar «Desconectar» a qualquer momento.