岛街 · 工程入口

一份渲染层,三个外壳,底层能力全部向下调用

这一页写给要加入的人。它回答四句话:整体长什么样、我改一行代码影响哪三个地方、为什么是这个引擎而它的坑在哪、第一天从哪开始读。 产品是什么在 另一页;每一条结论的出处在 记录。

读法:一份产物扇出到三个平级外壳,不是三套代码;每条边上写的是它真正走的那个调用。底座五件里有两件今天在小程序层还调不到。

哪个模块负责什么,以及它不负责什么

壳是宿主,小程序是客体。壳装载包、提供桥、管窗口与更新。它不知道包里在演什么。小程序是一个包,被沙箱关着,吃 20 MiB 的配额,能力全部经桥向宿主要。

这条分野决定了「所有能力都是小程序」这句话可不可能成立:只有当壳完全不懂业务,业务才能一个一个地做成包、独立审核、独立上下架。壳里塞一次业务,就少一个能被独立替换的能力。

宿主 · 壳装载包并提供桥iOS 壳已在生产装载包,把账号、支付、音视频经桥给包桌面壳已在库未接线把同一份包装进桌面窗口,管更新与本地能力网页壳已在库未接线免安装入口,同一份产物直接在浏览器里跑客体 · 小程序 · 每包 20 MiB 配额元宇宙包已在库未接线岛与角色的渲染、走动、遮挡与排序猜事件包已在库未接线猜一件真实事件会不会发生,记准确度与排名模拟仓包无作者化清单独立记账的模拟仓、季度重置、名次与称号商户店铺包无作者化清单实物商品与线下服务的成交卡包已在库未接线收纳企业发的会员卡,在实体店出示与核销沙箱关着,能力全部经桥向宿主要↓ 线以下是服务端。客体不许直连,一律经桥服务端 · 单机四核,日后加节点消息与账号已在生产账号、会话、消息、实时音视频小程序平台已在生产审核、货架、版本、包体扫描与配额判定资源控制面无作者化清单图集与音频的对象存储与分发
读法:壳不懂业务,服务端不懂岛。每个方块右边那行小字和框的线型讲的是同一个状态,线型的含义见架构图那块图例。

11 个模块,分三侧:3 个宿主外壳、5 个客体小程序、3 个服务端模块。「不负责什么」这一列是边界,不是补充说明 —— 它的每一行都是一条可以拿去否决一个改动的依据。改动跨过某一行之前,先解释为什么那条边界该被移动。

模块在哪一侧今天到哪了哪个仓负责什么不负责什么说明
iOS 壳宿主已在生产matrix-x-chat-ios装载包,把账号、支付、音视频经桥给包不渲染岛,不解释岛上任何规则今天已经在生产上跑着的那个 IM 就是这一层。小程序运行时是它的一个插件;元宇宙是它装载的一个包。壳里不许出现一行「岛」的逻辑 —— 出现一行,元宇宙就再也不能独立发版。
桌面壳宿主已在库未接线外置证据身份未公开把同一份包装进桌面窗口,管更新与本地能力不分叉业务逻辑,不做第二套渲染层外壳只负责窗口、更新与本地能力。桌面壳的 Electron 主进程与桌面侧的宿主 SDK 都已经在宿主仓的默认分支上,窗口能开起来。已知缺口:装载本地包用的自定义协议还没实现,所以今天桌面壳跑不起来一个真实包。这是一个洞,不是一句待办 —— 它拦住的是「三端跑同一份产物」这条结论的第三端。
网页壳宿主已在库未接线外置证据身份未公开免安装入口,同一份产物直接在浏览器里跑没有宿主能力,不假装有网页壳没有桥。所有需要底座的功能在这一端都必须有降级路径,而不是报错。壳本身还没有部署到任何域名下;不过「同一份包能在浏览器里跑」这件事已经有实物证据 —— 本站首屏那个能走动的商店就是那份包,直接在浏览器里跑,没有壳。
元宇宙包客体已在库未接线外置证据身份未公开岛与角色的渲染、走动、遮挡与排序不建账号,不碰资金,不自己存档渲染层用固定五层 depth,角色按脚底那一行排序。它是整个项目里唯一一个「画画」的模块,也是唯一一个受美术方向约束的模块。存档、账号、支付一律经桥向宿主要。这个仓 2026-08-04 推出创世提交时打开是白屏 —— 地图数据的行宽自相矛盾,模块加载期就抛异常;白屏已经修掉,并且补了一道「必须真跑」的门禁(真加载、真起浏览器、真渲染、真截图看到像素、真能动)。这一行仍写「已在库未接线」:它跑得起来了,但还没有接进任何宿主。
猜事件包客体已在库未接线外置证据身份未公开猜一件真实事件会不会发生,记准确度与排名不押筹码,不结算盈亏,不碰真实沙豆余额它和模拟仓包是两件事:模拟仓比的是一份仓位的收益率,这一件只问「这件事会不会发生」。猜对涨的是准确度分数和名次,不发也不扣沙豆 —— 这条边界是红线的第一条在产品上的落点,不是一句免责声明。这个仓 2026-08-04 才推出创世提交:默认分支上有工程骨架,没有接进任何宿主。
模拟仓包客体无作者化清单无作者化 manifest;不推断外部身份独立记账的模拟仓、季度重置、名次与称号不动真实沙豆余额,不做下单、撮合、仓位结算它和钱包是分开的两本账:模拟仓里的数字只拿沙豆当刻度,真实余额在它整个生命周期里一次也不变动。下单界面已裁决不做 —— 只接数据接口把数据拿进来。当前作者化 registry 没有为这个模块登记 manifest;这不推断外置组织观察中不存在实现。
商户店铺包客体无作者化清单无作者化 manifest;不推断外部身份实物商品与线下服务的成交不在包里卖数字商品依据是应用商店规则本身:实物与线下服务必须走非应用内购买,平台抽成 0%;在 app 里卖数字商品或卖曝光要走应用内购买,抽 15% 到 30%。这条差别决定了商户侧的整个设计,不是一个可以后面再优化的细节。当前作者化 registry 没有为这个模块登记 manifest;这不推断外置组织观察中不存在实现。
卡包客体已在库未接线外置证据身份未公开收纳企业发的会员卡,在实体店出示与核销不发卡,不记企业的账,不碰资金结算卡由企业组织在自己的店铺包里发出,卡包只负责收纳与出示。核销走商户侧的成交链路,卡包不做资金归集 —— 这条边界和商户店铺包「不在包里卖数字商品」是同一条线的延伸。这个仓 2026-08-04 才推出创世提交:默认分支上有工程骨架,没有一张卡真的发出去过,也没有接进任何宿主。
消息与账号服务端已在生产im-core账号、会话、消息、实时音视频不知道岛的存在,不为渲染层写专用代码这一层今天已经在生产上跑着。它必须对元宇宙一无所知 —— 一旦它开始为渲染层写特例,元宇宙这条线做砸的时候就会把底座一起拖下去,而「底下那些东西照样在跑」正是这件事敢立项的全部理由。
小程序平台服务端已在生产miniapp-open-platform审核、货架、版本、包体扫描与配额判定不运行包里的代码,不替包做业务判断20 MiB 整包、单文件上限、文件数上限这几条硬约束由它执行,扫描不过就是拒收。它是「所有能力都是小程序」这句话的执法者。首屏那个商店包过了它自己的扫描器。一条必须同时说清的边界:这套扫描器查的是包装 —— 体积、文件数、单文件上限、MIME —— 它不执行包里的代码,所以一个在模块加载期就抛异常、打开是白屏的包,照样能被它判为通过。2026-08-04 我们自己撞上过这件事。「过了扫描器」因此不等于「跑得起来」。
资源控制面服务端无作者化清单无作者化 manifest;不推断外部身份图集与音频的对象存储与分发不改资产内容,不当资产的真值来源资产的真值必须在作者化来源里,控制面只能负责分发;控制面上的内容被删除后必须能从权威来源重放。当前作者化 registry 没有登记这一模块的仓归属;这不推断外置观察中的身份或实现是否存在,也不把其他作者化媒体仓误写成这一控制面。

状态分布:已在生产 3 行、已在库未接线 5 行、无作者化清单 3 行。仓身份只从作者化 manifests 公开;“无作者化清单”不等于组织中不存在实现,外置观察身份用固定脱敏标签。2026-08-24 的 counts-only snapshot 记录 46 个组织仓,但不会把未登记名称或 live head 复制进页面。

渲染层的两条硬约束

美术方向全文 →

渲染层是整个项目里唯一一个「画画」的模块,所以它多背两条约束。这两条都不是审美偏好,写错了会直接打断别的能力,或者让美术验收无从下手。

第一条是层序:角色永不被完全遮挡。名牌永不被遮挡。排序按角色脚底那一行,不是按精灵中心 —— 中心排序会让站在同一排的两个角色随机互换前后。角色脚底落在建筑占地内时,该建筑的屋顶淡到 25%,不是淡到看不见:完全消失会让建筑轮廓丢失,玩家分不清自己在屋里还是在露天。这条是在保护一条已经付过费的能力,不是在迁就美术。

层depth装什么与角色的关系
L00地面、走道、地面暖光落点永远在下
L110墙厚、矮物件、家具与角色一起按脚底行排序
L220角色按脚底行排序
L330屋顶、树冠在上,但受淡出规则
L440名牌、头顶指示器、界面永远在上,永不被遮挡

第二条是角色规格:32 × 48 像素写死,4 朝向 × 4 帧共 16 格,图集 128 × 192,命名 char-<slug>-32x48-4x4.png —— 尺寸与格数写进文件名,是为了让代码里的切图参数与文件本身互为校验。达标判据是绝对的,不是「比某个竞品更细」:单个角色格内不透明色值不少于 9 个;必须有轮廓光 #6fa3c9,且只在受光侧一条不超过 2 像素宽的竖条上;必须有接触影 #14142a,落在最后两行。三条都能用一条命令查,所以验收不需要任何人凭眼睛拍板。

三端分工:同一份渲染层

三个外壳装的是同一份产物,不是三套代码。凡是需要在某一端「特殊处理」的东西,先怀疑是不是边界画错了 —— 把逻辑塞进外壳是这套架构最容易发生、也最贵的一种腐化。

次序写死:iOS 先做,Electron 桌面第二,安卓最后。安卓不在当前范围内。下表按这个次序排, 「今天到哪了」那一列是逐个仓打开看过的,不是排期意图。

外壳今天到哪了哪个仓它负责什么和另外两端共享什么这一端要当心什么
小程序(装进 iOS 上的 IM)壳已在生产,包在库matrix-x-chat-ios · 外置证据身份未公开元宇宙的主战场,三端里的第一端渲染层产物逐字节相同整包受 20 MiB 配额约束;本地服务器的 origin 每次启动都变,所有 Web 存储无一存活。
Electron 桌面已在库未接线外置证据身份未公开桌面外壳 + 后台管理,三端里的第二端渲染层产物逐字节相同外壳只负责窗口、更新与本地能力;业务逻辑不许在这一层分叉。已知缺口:装载本地包用的自定义协议还没实现 —— 在这两处按自定义协议注册相关的调用检索,命中为 0;同一批检索窗口构造的调用命中为真,所以那个 0 是「真的没写」,不是检索没生效。窗口能开,真实包装不进去。
网页壳在库,包已在浏览器里跑外置证据身份未公开浏览器直达渲染层产物逐字节相同没有宿主能力,所有需要底座的功能都要有降级路径。壳本身还没部署到任何域名下,但「同一份包能在浏览器里跑」已经有实物证据:叙事页首屏那个能走动的商店就是那份包,直接在浏览器里跑,没有壳。

底座提供什么,我们不实现什么

边界就是架构图上那条虚线。线以下的 5 件能力一律调用,不重写 —— 重写一次就等于多养一套要跟着底座升级的代码。仓归属只显示作者化 manifest;不适用与外置身份脱敏是两种不同状态,都不能被写成“仓不存在”。

能力谁提供哪个仓说明
小程序宿主iOS 上的 IM 底座matrix-x-chat-ios · miniapp-open-platform包格式、货架与运行时由宿主提供;渲染层是宿主里的一个小程序。这一件是「所有能力都是小程序」的承重墙,架构图上此前漏画了它。
账号与身份iOS 上的 IM 底座reits-auth · reits-sso-config登录态、身份与钥匙串访问组全部复用,我们不新建一套账号。
IM 与消息iOS 上的 IM 底座im-core · im-ui会话、消息与推送是既有能力,元宇宙侧只订阅,不重写。
支付通道iOS 上的 IM 底座仓归属不适用收款链路走既有通道;元宇宙侧不作为资金归集方。仓归属在这一能力边界不适用,不能据此推断组织仓不存在。它在小程序层还调不到:下单支付接口返回 404,所以架构图上这一格画虚线。
实时音视频已集成,未接线matrix-x-chat-iosSDK 与空间音频扩展都已经在构建里,缺的是把玩家坐标喂给空间音频接口这一段;桥上也还没有这个能力,所以包里今天调不到,架构图上同样画虚线。

引擎选型与它的代价

逐条证据 →

选定 Phaser 4.2.1,MIT 许可。判定依据不是喜好,是小程序服务端写死的单文件与整包限额:Godot 4 与 Unity Web 的导出物与限额正面冲突,在第一步就出局。

对外一律报 ≈3%,算式是 656,114 ÷ (20 × 1024 × 1024) = 656,114 ÷ 20,971,520 ≈ 3%。商只报到整数,因为这四件插件还没最后拍板,插件集一换这个数就得重算 —— 在那种情况下多报几位小数,多出来的那几位是编的。不报裸引擎那个数 —— 一个没有联机、没有寻路、没有界面插件的构建永远上不了线,拿它报预算等于用一个不存在的产品去承诺一个存在的产品。

净额约 16.2 MiB(扣除引擎 + 插件、游戏逻辑、共享角色图集、中文字体子集、UI 与音效之后)。

场景每岛算式装得下
共用 BGM0.78 MiB(地块 + 道具图集)16.160 ÷ 0.78 = 20.7220 个岛
各带 1 分钟 96kbps BGM0.78 + 0.687 = 1.467 MiBBGM:96 kbps × 60 s = 5,760 kbit = 720,000 B = 0.6866 MiB;16.160 ÷ 1.467 = 11.0211 个岛

v1 美术全部进包,不需要 CDN。 不上 CDN 不只是「省事」:origin 每次启动都变,CDN 资源每次开都要全量重下。进包是唯一能让美术资源真正只下一次的做法。

坑:四件插件已经换成 Phaser 4 的包并真打真量:colyseus.js 0.16.22、easystarjs 0.4.4、phaser4-rex-plugins 4.2.0 的界面插件与虚拟摇杆,全部 MIT。换插件则打包字节数要重算,别把当前这个数当成最终值锁死。

已在库、但还没接线的能力

四项资产的证据 →

距离衰减的空间语音是已付费、零美术、只需接线的能力,且它正是 Gather 的核心体验。

  • 已付费 —— SDK 在 Podfile 里,扩展在链接列表里,账号已经是付费账号。
  • 零美术 —— 空间语音不需要任何一张图、任何一个图集,因此不占 16.2 MiB 的岛屿预算。
  • 只需接线 —— AgoraRtcAdapter.swift 是生产实现,im-core/internal/live/ 是完整的域,缺的是把玩家坐标喂给空间音频 API 这一段。

单位经济:音频成立,视频不成立。 引用这条结论时必须连它的价格前提一起引,价格本身尚未复核。

不可逆边界

下面这几条是硬边界。任何方案如果需要推翻其中一条,作废的是方案,不是这条边界。

REITs 降级为垂类,不下线

REITs 内容、订阅关系与历史索引仍有真实流量,掉头是扩大母集而不是丢弃子集。

红线:reits.tech 不停服、不 404;旧内容路径必须保持可达。

iOS bundle ID 永久冻结

bundle ID 参与 App Store 身份、钥匙串访问组与推送凭证;改一次等于新 App,历史用户与订阅全部断裂。

红线:含加密串在内的标识符一律不动 —— 品牌可以换,标识符不可以。

gitea 永久留在 reits.tech

5 个 Go module path(im-core / opensdk / quant-platform / reits-auth / reits-media)、matrix-x-chat-ios 的 SPM 插件供应链(Package.swift 硬校验 host == gitea.reits.tech)、各仓 auto-deploy 默认 REMOTE_URL、800+ 文档 issue 链接全部锚定该域。

红线:reits.tech 到 2027-06-21 到期,必须永久续费;gitea 证书不申请新域 SAN。

两条产品线与阶段

品牌掉头本身还在收尾:定位从 REITs 垂直资讯平台 扩成 全球事件概率数据平台,REITs 从顶层实体降级为其中一个实例。两条产品线的差别不是优先级,也不是排期先后 —— A 线在做,B 线已经裁决不做。

立即做

数据与内容线

事件概率数据的采集、清洗、发布与解读 —— 掉头后立即可做的部分。

启动前提:无外部前提,仅受工程排期约束。

已裁决不做

交易面 builder 线

面向事件合约的下单与仓位构建界面 —— 已裁决不做。只接数据接口做数据,不做下单、不做撮合、不做仓位结算。

没有可以满足的前提。这一条不是等条件齐了再启动,是已经裁决不启动 —— 它与「系统内不存在任何押注机制」是同一条边界的两面。

阶段意图状态
决策把不可逆的边界一次性钉死,避免后续阶段反复回退。DECIDED
先立新不破旧新域与新证书全部就位,旧域行为零变化 —— 任何一步失败都不影响存量。ACTIVE
换壳视觉与文案层面完成 ProbAtlas 化,路由与标识符保持不动。QUEUED
语义掉头把数据模型与信息架构从「REITs 资产」抽象成「全球事件概率」。QUEUED
收尾旧域收敛到 301、补齐 catch-all,最后才允许改变旧域行为。HELD

成本形状:工程改造是掉头成本里的大头:域名、证书、品牌资产与站内引用要逐处换名;内容侧要把以 REITs 为主语写成的存量文稿重写为垂类口径。这里不给工作量数字 —— 此前写在这一行的两个人日区间在规划母版里查不到任何出处,已经删掉,不用一个新编的估算去替它。

名字分三层,不许混用:公司与平台是 ProbAtlas(概率图谱),生产主域 probatlas.com 与旧域 reits.tech 双域并行、旧域不下线;产品的中文名是岛街;而岛上那个以沙豆计价、独立记账、季度重置的模拟仓小程序,名字也叫 ProbAtlas。域名和证书里到处出现的是第一层,对外叙事讲的是第二层,「独立账本、不流入不流出」那条风险决策管的是第三层。平台名要不要随产品方向一起改,是老板级决定,尚未拍板 —— 工程侧在它拍板之前不许自行改名。

作者化仓级地图与外置身份边界

2026-08-24 的 counts-only snapshot 记录 46 个组织仓;这条方向公开关联 6 个作者化仓。未登记身份、live head 与逐仓 visibility 只留在外置 custody,因此表中只显示固定脱敏类别,不用静态页面反推仓是否存在。

这一带是什么哪些仓对这条线意味着什么
本方向在建miniapp-open-platform · 外置证据身份未公开服务端平台由作者化 manifest 指向;客体包、共享工具链与宿主外壳的外置证据身份不在公开树中复制。
复用的底座matrix-x-chat-ios · im-core · im-ui · reits-auth · reits-sso-config账号、消息、音视频。这一片只调用不重写 —— 架构图长划线以下画的就是它。资源控制面没有作者化 manifest;这不推断外置身份或实现不存在。
垂类维持,不在本方向路线图上reits-info-portal · reits-bbs · public-booking-platform · data-sources · quant-platform · trading-data-sourceREITs 与量化那一片降级为垂类,继续跑、不下线,但不在这条线的路线图上。读这些仓对本方向没有帮助。这一带只列到六个,剩下的同类仓同样按这条处置。
掉头前遗留,尚未下线im-polymarket-ui旧方向(预测市场)的产物。方向已于 2026 年 8 月 2 日改掉,而这个仓至今还在,既不在任何图上也不在任何路线图上。这一行就是它今天的位置:在老板对「退役还是留档」拍板之前,任何新工作不许引用它,也不许把它当成本方向的一部分。

第一天读哪里

  1. 第一天先读作者化的 miniapp-open-platform manifest 与包体扫描器合同;客体和宿主的外置证据身份只从受 custody 的工程交接材料读取,静态页面不复制其名称或 live head。
  2. 三端的次序是 iOS 先做、Electron 桌面第二、安卓最后。安卓不在当前范围里 —— 不写这一句,读者会默认三端同时开工。
  3. 再把这一页的架构图和三端分工读完 —— 它决定了你改的那一行会落在几个产物上。
  4. 然后读引擎与包体这一节:20 MiB 是硬约束,任何和它冲突的方案都在第一步出局。
  5. 接着去 /plans/record/evidence 看包体常量的逐条证据与运行时硬约束。
  6. 开工前必读 /plans/record/decisions:还没拍板的决策里有几条是不拍板就无法开工的。
  7. 改动任何一条既有结论之前,先读 /plans/record/overturned 的纪律段。

我推翻了一个结论怎么办

这套文档只有一条不许违反的纪律:推翻旧结论必须留档,被推翻的东西不许悄悄消失。不是「改掉那句话」,是「把旧结论、推翻依据、以及它影响了什么」三件一起写进台账 —— 删掉旧结论,下一个人就会重新做一遍同样的判断,然后重新踩一遍同一个坑。

同一条纪律的第二半:没核实的东西不许进正文当事实。核不到就登记成「没核实」,写清楚它影响什么、不影响什么、怎么才能关掉 —— 只写一侧等于没登记。