Русский · English · Español · 中文 · Português
「Space Now」— 智能体 API
本页面面向 AI 智能体(及其使用者)。它说明智能体如何连接到用户浏览器中正在运行的「Space Now」页面 (known.html),以及能在其中做什么:界面能做的一切——打开任意天体、 飞行相机、拖动时间、切换图层和过滤器、宇航员模式、查找日食和行星连珠、配合语音和字幕讲故事、展示自己的图片、 录制视频、读取错误。渲染在用户的浏览器中完成(使用其 GPU 的 WebGL);智能体只发送命令,并获得回复和截图。
1. 配对
- 用户打开网站,点击圆形的 🤖 按钮(右下角,宇航员上方)——智能体栏展开;点击「开启智能体」会显示一个代码(20 个字符,例如
r4fxjbjsxdy6ex3pf4hd)。该代码就是通行证:持有者即可控制此标签页。🤖 只是隐藏/显示该栏,连接不会断开;栏中的「断开连接」会关闭连接。该栏始终有 📂(打开故事文件或保存当前显示的故事——没有智能体也可用)和「MCP ↗」(即本页)。 - 用户把代码交给智能体。智能体用该代码调用
connect。 - 永久连接(可选):在页面上——智能体栏中的 📌「记住」(代码保存在此浏览器中,网站每次打开时自动连接);在智能体端——使用
save: true调用connect(代码保存到~/.orbit-agent.json,MCP 启动时自动连接)。之后只需打开网站即可。要忘记:取消固定 📌 并调用forget。 - 页面上的「断开连接」(或智能体离开)会结束会话;随后页面会把图层和界面恢复到智能体介入之前的状态,停止音乐、语音、字幕、图片和脚本,并移除着陆点(
sites)、绘图和标记 (draw、mark、flybys)、媒体窗口和自建天体(spawn)——与onstop无关。相机、时间和 选中项也会恢复(默认如此;onstop {restore: false}— 保留智能体展示的内容)。例外:带detach: true的play/story run— 演示会播放到结束,然后回滚。
声音(语音、音乐)只有在用户至少点击过一次页面后才会启动——这是浏览器的规定。语音默认关闭:用户通过智能体栏中的 🔊 开启(会被记住);字幕始终显示。
演示检查清单——务必照做
[
{"cmd":"onstop","args":{"restore":true}}, // 第一步:结束、按 Esc 或 ✕ 时一切恢复原状
{"cmd":"reset"},
{"cmd":"view","args":{"on":["oplanets"]}}, // 只开需要的图层:卫星、航天器、轨道、星座一律关闭
{"cmd":"hideUi","args":{"on":true,"labels":false}},
{"cmd":"time","args":{"at":"<moment>","rate":0}}, // 自己设定时间;rate 0 — 光照不会漂移
… 飞行 (fly) …
… 演示 …
]
- 不要依赖默认值:显式设置图层、时间、相机和界面。
- 用
view(或故事的on字段)设置的视图会被show保留(keepView: false— 使用事件自己的图层)。fly、camera、sites、time不会改动图层;galaxy、scene和ambient会设置自己的视图——如有需要,在它们之后再次调用view。 - 演示结束后,场景必须恢复原样:
onstop {restore: true},并清除你自己放置的东西——sites {on: false}、flybys {on: false}、draw {clear: true}、image {clear: true}、media {close: true}。智能体离开时它们也会被自动移除。 - 在对用户说「请看」之前,先用
screenshot检查画面。 caption位于左下角:title要简短,长文本放进sub和text。play中失败的步骤会进入logs(error 级别)、不带参数的play(lastError: {step, cmd, error}),并在播放器中显示为「⚠ step N」。steps 中出现未知命令会在开始前立即报错。
2. 传输
双方都连接到同一网站上的中继房间:wss://<site>/agent/<code>?r=agent(页面使用
?r=page)。房间在两端之间转发消息;不保存任何内容。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 } (对端加入 / 离开)
keepalive 每 30 秒发送一次 { "sys": "ping" },房间回复 { "sys": "pong" }
每个角色只允许一个连接(使用相同代码的新智能体会替换旧的,关闭码 4000 — 此时不要重连)。
消息最大 4 MB。站点:https://space.bl2.ru、https://space.bl2.net(同一网站,默认语言为 ru/en)。
3. MCP 服务器
现成的 MCP 服务器(stdio):orbit-proto 仓库中的 scripts/agent-mcp.mjs(Node ≥ 20,依赖 ws)。
下面的每个命令都是同名工具(hide_ui → 页面命令 hideUi),另外还有 connect、
disconnect、help(本页的文本形式;lang: en)。文件:image 接受 path,record 保存
到 path,screenshot 返回图片。
{ "mcpServers": { "orbit-space": { "command": "node", "args": ["scripts/agent-mcp.mjs"] } } }
环境变量:AGENT_SITE — 默认站点,AGENT_CODE — 启动时连接。
不使用 MCP 服务器的连接方式(云端智能体)
- 许多智能体运行在云沙箱中,出站网络仅限于白名单,因此
wss://space.bl2.ru可能无法访问。变通办法:在space.bl2.ru的任意浏览器标签页(例如本帮助页)中打开 WebSocket,并从那里发送命令。连接检查:{"sys":"ping"}→{"sys":"pong"}。 - 智能体离开 =
play停止且场景回滚。会话较短的智能体(浏览器工具每次调用约允许 45 秒)使用detach: true发送演示——play {steps, detach: true}或story {action: 'run', story, detach: true}——并立即返回:页面自己播放演示,结束时(按onstop)回滚。不带detach时,需保持套接字打开直到脚本结束。 - 给每个命令设置独立的超时(比如 8 秒):否则一个没有回应的命令会挂起整个调用。
// 「启动后立即返回」— 在 space.bl2.ru 标签页的控制台中(或 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(); // 演示由页面自行播放,结束后再把一切恢复原状
};
4. 命令
查看与状态
| cmd | args | 说明 |
|---|---|---|
| state | 时间、速率、选中天体、视图中心、相机(yaw、pitch、dist km、fov)、附近恒星、可见图层的键、画布尺寸(像素) | |
| screenshot | width, quality, full | 3D 场景的 JPEG。full: true — 带界面的整个标签页(用户需通过智能体栏中的「📷」一次性允许标签页捕获) |
| body | name | 用于取景:半径 km、类型、母天体、卫星、相机角度、sunYaw/sunPitch(使天体被完全照亮的相机方向)、fov、distForSize {0.25, 0.5, 0.66, 0.8 → km}:圆盘占满屏幕高度该比例时的距离(= radius / tan(fov/2) / k) |
| where | name, at | 某一时刻的位置:距太阳和地球的 km 与 AU、从地球看的赤经/赤纬(J2000) |
| logs | level, last, clear | 页面控制台的错误/警告/信息(环形缓冲区 300 条) |
| snapshot | 完整状态(时间、速率、相机、中心、选中项、所有图层复选框、界面是否隐藏、宇航员链接)— 保存下来可用于复现 bug | |
| restore | state | 返回到某个快照 |
视图、相机、时间、图层
| cmd | args | 说明 |
|---|---|---|
| search | q, limit | 像搜索框一样搜索天体库:天体、卫星、航天器、星云和星系(其图层开启时)、地球卫星(名称或 NORAD)、小行星(名称或编号;星表通过 load-asteroids 行加载)。返回带 n 的行 |
| open | n | 打开一个搜索结果:选中、卡片、飞行 — 如同点击该行 |
| go | search | 像分享链接一样打开视图:?o= 天体(Mars、Марс、ISS…),?a= 小行星(编号或名称),?s= 卫星 NORAD,?g= 星系,?n= 星云,?st= 星座中的恒星;附加参数 d= 相机 km、v=yaw,pitch、t= ISO 时间 |
| fly | name, size, lit, face, seconds | 平滑飞向某个天体(如同在树中点击)。size — 天体占屏幕高度的比例(0.66 — 三分之二),lit: true — 从受光面观察;飞行结束后取景还需约 2.5 秒(总计约 6 秒,请使用 wait ≥ 6500)。face: "spot" — 木星:时间回退,直到大红斑转到白天一侧 |
| camera | yaw, pitch, dist, ms | 围绕视图中心的相机(rad、km)。ms > 0 — 在 ms 毫秒内平滑移动。示例「占满屏幕 2/3,受光面」:body → camera {yaw: sunYaw+0.4, pitch: sunPitch, dist: distForSize[0.66], ms: 3000} |
| time | at, rate, live, from, to | from, to, ms, ease — 从一个日期平滑拖动到另一个日期;at — Unix 秒或 ISO 时刻(公元前:-000500-01-01),速度(1 实时,3600 = 1 小时/秒,负数 = 倒退,0 暂停),live: true |
| view | on, set, orbits | view — 每个开关的标准键。无参数 — 列出 {key, on};on: [...] — 全部关闭,只开启列出的;set: {key: true|false} — 只切换这些;orbits: false — 一次关闭所有轨道线。键(每个组还有 <key>:orbits — 其轨道线):oplanets — 太阳、行星和卫星;odwarfs — 矮行星和最大的小行星;ohelio — 日球层顶;oshock — 终端激波;osandbox — 自建天体(spawn);oknown-small — 已知小天体(Apophis、Bennu…);ocomets — 彗星;ointerstellar — 星际天体(1I、2I、3I);okuiper — 柯伊伯带;ooort — 奥尔特云;a0…a9 — 按大小划分的小行星(a0 — 大于 100 km);ocraft、ocraft-orbit、ocraft-l — 飞行中的航天器、环绕天体轨道上的航天器、位于拉格朗日点的航天器;s0…s30 — 地球卫星组,sats — 全部;ogalaxy — 银河系模型;ouniverse — 星系;stars — 带名称的星座恒星;conlines — 星座连线图(与 stars 一起;不在 view {on} 的列表中 — 无连线);galmarks — 银心和奔赴点标签;galsun — 「太阳 — 你在这里」;scenelabels — 仅标注场景所需内容的标签(labels {only})。单独显示一条星际轨迹:关闭 ointerstellar:orbits,select {name: '3I/ATLAS'} — 其轨迹高亮。另有:earth:ph|cities|seas|mountains|volcanoes、weather、aurora(极光)、sw(空间天气)、sk:0…6、sk:neb。故事和幻灯片带有 on 字段(在步骤之前应用):只列出需要的——默认开启的新图层不会出现在旧故事中 |
| layers | 所有图层组:key、name、visible、orbits、count | |
| layer | key, visible, orbits | 切换图层。键:oplanets、odwarfs、ocomets、ocraft*、ogalaxy、ouniverse、a0…a9 按大小的小行星、s0… 卫星组… |
| galaxy | far | 银河系视图(far — 连同其他星系)。用于场景:dist(0 — 模型位于太阳处,> 0 — 向外飞出)、pitch、center: true — 绕银心轨道运行、off: true;银河时间 — galtime {rate}(年/秒) |
| galaxies | count, dwell | 按距离依次飞越 N 个著名星系,每个停留 dwell 秒 |
| clear | 取消选中,关闭卡片 |
事件(由页面计算,无需自备公式)
| cmd | args | 说明 |
|---|---|---|
| find | kind, from, to, total, count, min | 从任意日期起查找 lunar(total: true — 「血月」)、solar、parade(min 行星数 3…7);返回食甚时刻、是否全食、可见的纬度/经度/地区;lunar — contact(本影接触) |
| show | kind, at, keepView | 像「📅 事件」那样展示事件:时间 — 食甚前半小时,速度 ×100(请设置 time {rate: 0} 或你自己的值),取消选中,视图中心和相机置于地球(日食:阴影点上方)或月球(月食);行星连珠 — 从地球出发的第一人称视角,仅显示行星。用 view 设置的图层会保留(keepView: false — 使用事件自己的图层)。之后:hideUi,必要时 camera |
整个界面
| cmd | args | 说明 |
|---|---|---|
| ui | text, within | 每个可见的按钮、复选框、滑块、输入框、列表/树行,附带 ref、文本、id、data 属性、状态。可按文本或 CSS 区域过滤 |
| click | ref | selector | 点击它 |
| set | ref | selector, value | 复选框 true/false、滑块、输入框、select |
| key | code, ms, shift, ctrl | 按键(KeyW… 按住 ms 毫秒以飞行,Space 暂停,KeyH 隐藏面板,Escape…) |
| pointer | action, x, y, to, dy | 3D 场景上的鼠标:click(选中)、dblclick(飞向)、move(悬停)、drag(旋转)到 [x,y]、wheel(dy 缩放) |
| hideUi | on, labels | 隐藏一切:面板、角落按钮、智能体栏(labels: false — 连天体标签也隐藏);只保留场景、字幕、图片、媒体窗口、标记(mark)和智能体的绘图。on: false — 恢复 |
| astro | action, name | 宇航员:enter(相机所在处)、goto name(飞过去,绕轨道运行)、land(站到地面上)、exit、link、state。行走和环顾 — key/pointer |
| eval | code | 仅限开发服务器(npm run dev):在页面中运行 JS 表达式;window.__known 保存状态。公共网站上不可用 |
讲故事
| cmd | args | 说明 |
|---|---|---|
| caption | title, sub, text, seconds | 左下角的字幕,样式同屏保(title 为空 — 隐藏) |
| say | text, title, sub, audio, keep, caption | 以字幕形式显示文本;audio — mp3 配音(链接或电脑上的文件名;不使用浏览器语音 — 请事先制作 mp3,例如用 edge-tts);🔇 — 静音 |
| music | on, theme, volume | 浏览器中生成的背景音乐:theme 0 «Nebula»、1 «Depth»、2 «Crystals»,null — 轮换 |
| image | id, src | path, at, x, y, dx, dy, w, label, remove, clear | 覆盖在场景上的你自己的图片:附着在天体上(随之移动)或位于屏幕某点 |
| play | steps | stop | pause | seek | step | 由页面播放的完整脚本:[{cmd, args, wait}],wait = 毫秒或 "speech"。如同播放器:pause、seek: n — 跳到第 n 步(之前的步骤立即执行,不等待、不播放语音)、step: ±1。用户在底部会看到播放器:⏮ ⏪ ▶/⏸ ⏹ ⏩ ⏭、「幻灯片 · 步骤」、在网站上保存 💾(密码)、下载 ⬇、删除 🗑、✕。断开连接时停止 — 带 detach: true 除外(播放到结束,然后回滚)。onError: 'skip'(默认 — 继续)| 'stop';失败的步骤会进入 logs、不带参数的 play(lastError)和播放器。演示会自动切到下一张幻灯片;✕ 或 Esc — 退出(界面恢复) |
| deck | slides, start, go, close | 演示文稿:[{title, steps}];用户在底部看到「◀ n/N ▶」(以及 PageUp/PageDown),翻页会播放该幻灯片的步骤。在 hideUi 下仍保持可见 |
| buttons | items | 底部你自己的按钮:[{label, title, steps}],点击即播放这些步骤;[] 移除 |
| story | action, story, id, password, name | 故事 = 智能体编排的内容(飞行计划、解说、可视化 — 例如用于 NASA Space Apps):{title, summary, lang, slides:[{title, steps}] | steps}。run — 演示;publish — 用编辑密码保存到网站(password;不提供 — 页面会询问用户)→ 链接 known.html?story=<uuid>,任何人无需智能体即可观看(带「◀ n/N ▶」);最大 256 KB,最后一次打开后保留 30 天;update — 编辑(id + 相同密码);delete — 从网站删除(id + 相同密码);download — 给用户的文件(不限大小);open — 用户选择文件(或把 .json 拖到页面上;智能体栏中的「📂」菜单);load — 按 id 加载 |
| steps | 当前在故事或演示文稿中的位置:幻灯片及幻灯片列表、步骤及步骤列表(n、label)、播放中、已暂停。跳转 — play {seek: n} / {step: ±1}、deck {go: n}。播放器中有 ☰ — 幻灯片和步骤列表,点击即可跳转 | |
| scene | code | 故事中的环境模式场景 — 其相机飞行、字幕和时间(约 20–30 秒,等待结束)。代码见 scenes:body:Сатурн、event:<id>、mission:…、astro:…、lapse:…、galaxy、pullback。环境模式(「∞」)本身就是通用播放器中的同一个场景生成器:⏮ ▶/⏸ ⏭、☰ 已播放的和所有场景、💾/⬇ — 把已播放内容保存为场景步骤构成的故事 |
| scenes | 按分区列出所有环境场景及其代码 | |
| record | action, fps, mbps / path | 场景视频:start、stop(MCP 把 WebM 保存到 path) |
统一入口:WS、MCP、控制台、故事
无论命令来自哪里,命令和语言都是相同的:任意语言的 WebSocket、MCP、页面控制台(智能体栏中的 >_ 按钮)或故事。可以写好整个脚本交给 story,也可以逐条调用命令。新增:exec {steps} — 立即运行语言步骤(变量在多次调用之间保留),expr {e} — 求值表达式,js {code, timeout} — 沙箱中的 JavaScript(隔离的 iframe + Web Worker:没有 DOM、cookie 或网络;内部可用 await cmd(name, args)、await expr('…')、log()、sleep()、return)。
控制台:fly Mars size=0.6(一条命令,第一个词是名称)、JSON 命令、步骤 {…} / […]、表达式 = …、代码 js …。
基础脚本 — Node.js:
// node agent.mjs <code> (Node ≥ 22 — 内置 WebSocket)
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 <code> (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]))
脚本语言 v2
版本:不带 v(或 v: 1)的故事 — 如上所述的步骤和幻灯片;v: 2 — 带条件的语言。新版本的处理器绝不会改变旧版本的行为。
{ "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 } ] }
] }
步骤:{cmd, args, wait}(wait — 毫秒或表达式)、{wait: expression | seconds, timeout}、{if, then, else}、{repeat: n | expression, do}、{set: {name: expression}}、{on: [...]}。表达式 — 不使用 eval:带单位的数字 km au ly m、字符串 '…'、变量、+ - * / %、< > <= >= == !=、&& || !;函数 dist(a, b)('camera' 或某个天体,km)、visible(body)、elapsed()、time()、camdist()、au(x)、ly(x)、round(x, d)、abs min max。即时属性:get(body | 'camera', 'prop') — 天体有 name、kind、radius、parent、moons、x y z、sun(距太阳 km)、earth、camera(距相机 km)、center、visible;相机有 dist、yaw、pitch、fov、x y z、sun、center;不带 prop — 整个对象。把命令结果存入变量:{cmd, args, as: 'r'},取字段 — field(r, 'rows.0.text'),大小 — count(x)。在 args 字符串中 — {expression}。错误进入 logs。后续计划:触发器(when/once/every)和沙箱(生成天体和 3D 模型)。自定义函数:{def: name, params, e} — 用于表达式,{def, params, steps} — 作为步骤 {call, args, as}、{local}、{return};在故事中 — funcs。更多函数:angle(a, b) — 从相机看去两个方向之间的角度(度),edge(a, b) — a 超出 b 边缘露出多少度,sin cos(度)、pow sqrt。命令上的 wait: true — 等到它完成。用于场景:fitdist(r[, margin]) — 半径 r km 的圆恰好放进屏幕(取窄边)的距离(天体还有 day — 自转周期,秒);satcount('all' | 'active' | 'debris' | 'rb' | 'dead') — 地球周围的星表天体;mstat(craft, 'launch' | 'km' | 'turns' | 'rmin' | 'rnow' | 'flybys') — 根据任务轨迹得出的任务数据,截至今天。航天器轨迹和飞掠来自导入脚本(scripts/fetch-missions.mjs,JPL Horizons,每日):库中新增的航天器会自动获得其飞掠和数据;flybys {craft} 在其路径上绘制飞掠点。场景中的媒体:media {url | file, title, x, y, w, h, volume, loop, start, id} — 带音频或视频的窗口:mp3/视频链接或 YouTube;file — 用户电脑上的文件(网站不存储文件:用户在窗口中选择,之后可离线播放);close: true 关闭窗口。状态:remember {name} — 保存相机、时间、视图和界面;recall {name} — 恢复;onstop {restore: true}(在故事文件中 — 字段 "onstop": "restore")— 结束、按 Esc 或 ✕ 时把一切恢复到开始前的样子。请告诉用户:故事和屏保可以用遥控器操控 — 演示翻页笔(PageDown/PageUp,「.」或 B — 黑屏)、键盘、耳机和电视盒子上的媒体键(下一个、上一个、暂停)、游戏手柄(方向键 ←/→,A — 暂停,B — 黑屏)、键盘方向键、Space、Esc。直达链接:?ambient — 屏保,?ambient=<scene code from ☰> — 从该场景开始(例如 ?ambient=landings:Moon:apollo),?story=<id>&step=N 或 &slide=N — 从该处开始播放已发布的故事;播放器中的 🔗 按钮会复制指向当前播放内容的链接。智能体可以用 ambient {play: code} 命令实现同样的效果;reset 在场景之前重置相机、时间和视图。
相机与运动
| cmd | args | 说明 |
|---|---|---|
| fly | name, ms, ease, size, alt, lat, lon, rel, lit | 一气呵成地飞到取景位置:size — 圆盘占屏幕高度的比例,alt — 距表面的高度(km),lat/lon — 位于某个表面点上方,rel: {to, deg, elev} — 相对于另一个天体的方位(0° — 它在相机身后,180° — 在画面中天体的身后;elev — 抬高)。返回 ms。 |
| camera | dist, yaw, pitch, rel, ms, ease, target | 围绕视图中心的相机;rel 同 fly。target:{between: [a, b], k} — 看向天体之间的某一点;{sat: 25544} — 绕卫星(NORAD)运行;{sat, space: {tilt, spin, from, ms}} — 从太空视角(地球在卫星身后):tilt° 为偏离垂直方向的角度,spin °/s,在 ms 内从 from km 接近到 dist;null — 回到该天体。 |
| media | url | file, kind, title, x, y, w, h, volume, loop, start, id, anchor, dx, dy, header, close, forgetDir | 带音频或视频的窗口:链接(mp3/视频/YouTube)或 file — 电脑上的文件(由用户选择)。anchor: {sat: NORAD} | {body: name} — 窗口跟随某个天体(dx, dy — 偏移,px);header: false — 无标题栏(附着时的默认值)。为 wait: true 返回 ms。close: true | id;forgetDir: true — 忘记媒体文件夹。故事开始前会出现「准备场景」窗口(文件、链接预加载)。 |
| ambient | play | 从指定场景开始的屏保「∞」:代码同 ☰(hover|Mars、landings:Moon:apollo、event:eclSun、mission:Parker、satellites…);不带 play — 代码列表。 |
| lang | set | 界面语言:不带 set — 返回当前语言和列表(ru、en、es、zh、pt);set — 切换。即时切换,无需重新加载:智能体保持连接。屏保会用新语言重新播放当前场景,播放器、卡片、图层树和窗口都会重绘。页面地址变为 /<语言>/(例如 /zh/;域名自身语言就是 /)——语言只由地址决定,没有 ?lang= 参数;指定语言的网站链接为 https://space.bl2.net/<语言>/(俄语为 https://space.bl2.ru/)。 |
| reset | — | 场景之前:停止环绕、视线和时间的渐变;关闭银河;移除标记、飞掠点和媒体窗口(屏保场景会自行完成这些)。 |
| remember / recall | name | 保存状态(相机、时间、视图、界面)/ 恢复。 |
| onstop | restore | 默认开启:结束、按 Esc、✕ 或智能体离开时,把一切恢复到智能体第一条命令之前的样子:图层和视图开关、面板和被隐藏的界面、相机(角度、距离、中心、跟踪)、选中项、时间和速度(或「live」);音乐和语音停止。智能体自己放置的东西(sites、draw、mark、flybys、image、media、spawn)一律会被移除。restore: false(在故事文件中 — "onstop": "keep")— 保持相机、时间和选中项为智能体离开时的状态。exec 仅在显式 onstop {restore: true} 时于结束时回滚。 |
| console | open | 打开 / 关闭 >_ 控制台。 |
| sites | body | code, group, ids, light, on | 着陆点:表面点上的卡片(在场景中)。可省略 body — 天体由 group 决定(apollo、luna、rovers、new、farside、first、china — 月球;mars、chryse — 火星;venera — 金星)或由 ids 决定。示例:sites {group: 'apollo', light: true} → {lat, lon, alt, at, ids};然后 time {at, rate: 0} 和 fly {name: 'Moon', lat, lon, alt}。如果不飞到 lat/lon,相机可能朝向背面 — 看不到卡片。light: true — 着陆点处于白天的时间(回复 at)。 |
| flybys | craft, on | 航天器路径上的引力弹弓和入轨点(来自任务轨迹)。 |
| orbit | speed (°/s), turns | ms, pitch, dist, end, blend, ease, stop | 绕天体运行。end: {to, deg, elev} — 恰好在该取景处结束(单向,不回头)。带速度结束 — 惯性滑行,下一个 fly 会接管该速度。 |
| look | to, ms, ease, clear | 看向某个天体:视点不动(或继续环绕),视线平滑转向并跟踪它。clear: true — 回到中心。 |
| select, shadow, camera target | name; name, by, center, ms, dist; target | 用于屏保场景:select {name} — 高亮天体的路径('' — 清除);shadow {name, by, center, ms, dist} — 相机对准食的阴影点;camera {target: {between: [a, b], k}, ms} — 天体之间的注视点(orbit 会绕它转),target: null — 返回;look {to: 'galcenter'};fly {frame: {path, from, to, with}, elev, deg} — 把航天器的整条路径纳入取景。 |
| follow | name, ms, dist, ease | 跟随另一个天体:保持取景的平滑交接。 |
展示小天体(彗星、星际天体 — 在数千万 km 外看不见):follow {name} 或 fly {name},然后 mark {name, label: true} — 在该天体处显示闪烁的彩色标记(hideUi 下也可见;另有 color、speed),select {name} — 其路径高亮。移除:mark {remove: name} 或 mark {clear: true}、select {name: ''};onstop 回滚和智能体离开时会自动移除标记。
缓动 ease — 类似 CSS 时间函数:linear, ease, ease-in, ease-out, ease-in-out, smooth, cubic-bezier(x1,y1,x2,y2) 或关于 t(0…1)的公式:1-pow(1-t,2)、t*t*t*(t*(6*t-15)+10)。
重叠:{cmd, args, then: [steps], before_end: ms | after_begin: ms | when: "condition"} — 嵌套步骤与该命令同时运行。示例:绕地球运行,转向木卫一,飞向它:
[ {"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} ]
沙箱、绘图、宇航员
| cmd | args | 说明 |
|---|---|---|
| spawn | id, like, diameter, color, at: {near, dist, dir} | pos, vel | 你自己的天体:某个天体或岩石的副本;它会进入围绕主导天体的圆轨道(按物理规律,而非直线) |
| move | id, vel | impact: {target, at} | 新速度或「在某一时刻撞击某个天体」 |
| despawn / objects | id | all | 移除 / 列出 |
| draw | items | clear | remove | 太空中的图形,用于调试和教学:arrow(vel、sun、north、{sum})、axes(roll/pitch/yaw)、line、dash、path、angle(弧线和度数)、project(向天体投影、高度)、point、text;label — 沿线的文字 |
| flybys | craft, on | 航天器路径上的引力弹弓点:「天体 · 日期」及弹弓带来的效果;on: false — 移除 |
| sites | body | code, group, ids, light, on | 着陆点(月球、火星、金星、土卫六):点和场景内的卡片 — 照片、名称、年份、描述;group — 组合视图(apollo、luna、rovers、new、farside、first、china、mars、chryse、venera;天体由 group 决定,body 可省略);light: true — 位于白天一侧的着陆点;返回供 fly 使用的 lat、lon、alt;on: false — 移除 |
| astro | action: goto | view | shield | land | exit, name, tpd, yaw, pitch, on, text | 宇航员:锚定到任何对象(天体、ISS、NORAD 编号、小行星);view — 看向人物;shield — 移除/设置护盾、自己的消息 |
页面控制台 — 反引号键(俄文键盘布局上为 ё)。
工作方式
- 阅读本页(
help),用代码connect。 - 向页面索取数据:
search/open(天体)、body(大小、受光面)、where(位置)、find(事件)、layers、state。 - 根据这些数据准备动作:一个
play脚本,或让用户逐页翻看的幻灯片deck,或buttons。 - 运行;用
screenshot和logs检查;调整。
5. 示例:「给我讲讲行星」
connect {code}
layers → layer {key, visible:false} 关闭除 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}, // 数值取自 body {name:"Mars"}
{cmd:"say", args:{title:"Mars", sub:"228 million km · light takes 13 min", text:"…", audio:"mars.mp3"}, wait: "speech"}, // 语音由浏览器中的 Piper 提供(ru ruslan,en amy);audio — 用现成的 mp3 代替
…
]}
6. 资源
- 天体:太阳、8 颗行星及其卫星、矮行星、约 140 万颗小行星(按大小分组)、彗星、行星际航天器、 约 30 000 颗地球卫星(CelesTrak,每日更新)、3D 星座、含星云和星团的银河系模型、44 000 个星系(2MRS)。
- 名称支持俄语和英语(
Марс/Mars);位置为 J2000 赤道坐标,单位 km。 - 时间范围:任意日期(距今越远星历精度越低;卫星仅限星表前后 ±90 天)。
- 分享链接(
?o=…&d=…&v=…&t=…)可让任何人打开相同的视图。
规则:页面只接受这些命令;不能跳转到其他网站,不涉及个人数据。请让用户始终保有控制权 — 他们可以随时点击「断开连接」。