JMOS文档与样张

JMOS 第一批改进样张 · motion-batch1

来源:仓库 reviews/2026-10-09/motion-batch1/README.md · 版本 0ca44f9 · 候选样张,未并入主应用 · 录屏 motion-batch1.mp4 与总览图 motion-batch1.png 体积较大,未随本站发布(仓库同目录可看)

在本站打开样张动效对照页07 工作台(样张)04 孪生 GLB(3D 档位)12 小锦对话

留档说明(2026-10-09):样张代码在 prototypes/motion-batch1/,未并入主应用。文中提到的 *.patch 是当时交付的补丁,内容就是该目录;补丁文件本身不入库。

状态:只是样张,没有并入 app/jmos。 等你确认后再合并。 基线是 33cffc2,样张在 prototypes/motion-batch1/。运行方法:node server.mjs,打开 (本机预览地址) 进入动效对照页。

交付文件:motion-batch1.png(总览)、motion-batch1.mp4(对照页录屏)、motion-batch1-sample.patch(只含 prototypes/motion-batch1/,相对 33cffc2;在 33cffc2 和 6782659 的临时副本上 git apply --check 都通过)。

数值和做法参考 RhineLabUI(MIT)reference.md 3.6、3.11 和 4.1 中第 6、14、15 项。代码都是新写的,没有复制片段,所以不需要附 MIT 声明。也没有使用莱茵生命的名称、配色或字体。样张文件只用语义 token,没有新增 HEX、rgba 或 color-mix。

0. 修正记录(2026-10-09 17:40–18:10 北京时间,复看录屏后)

#问题原因修正
1关闭弹窗时,前半段几乎不变淡,后半段才突然消失,显得拖滞透明度和位移用同一条出场曲线 (0.4,0,1,1),这条曲线在前 25% 时间里只走了约 10%,到一半时也才 33%出场透明度改为线性(--jm-ease-exit-fade),位移和滑出改为 (0.4,0,0.6,1)。总时长仍是 200ms。所有出场一律这样处理:CSS 过渡(弹窗遮罩、问小锦面板、菜单 / 气泡 / 提示、抽屉遮罩、设置面板)和 JS 动画(JMMotion.leave 把透明度和位移拆成两条动画,同一起点、同一时长,打断时一起取消、从当前值接续)
2侧面板、问小锦面板、手机抽屉关闭时像在滑一个空色块测量结果:12 右栏和问小锦面板的内容本来就和容器是同一个元素,关闭时没有单独淡出;但手机抽屉里嵌的 12 唤起面板有自己的进出动画,和抽屉不同步抽屉内容直接显示,不再单独做进出动画;退场时只有容器滑走。新增自动检查:退场过程中内容的透明度始终为 1、内部没有任何动画(侧边抽屉、手机抽屉都覆盖)
3手机抽屉打开时先出现空盒子,把手和内容一起淡入第一次打开时抽屉里的 iframe 还没加载完就开始滑;加载完以后,12 的唤起面板又单独淡入了 300ms把手 .grab 是抽屉边缘的一部分,跟容器一起滑;手机布局空闲时预加载抽屉 iframe;万一还没加载完,最多等 600ms 再滑;07 通知 12 时带 instant,唤起面板直接出现。新增自动检查:打开第一帧把手在容器内、不透明,内容已加载、已显示,没有单独的动画

注意:第 1 项让出场曲线和 spatial-motion.json 里的 motion.easing.exit (0.4,0,1,1) 不再一致。合并时需要同步修改契约,或者在契约里新增 exitMove / exitFade。

1. 现状盘点(33cffc2 实际使用的时长和曲线)

现有 token:--jm-duration-fast 120 / base 200 / slow 320,--jm-ease-out (0.22,1,0.36,1),--jmx-ease / --xa-ease / --mo-ease 都是 (.2,.8,.2,1),--xa-in 200 / --xa-out 140,--mo-dur 300。

部件所在位置现状:进 / 出曲线位移问题
问小锦迷你面板 .xa-popassist.css/js进 200 / 出 140(.2,.8,.2,1)跟随锚点方向进出曲线相同;打开时被 place() 提前计算样式,起点停在旧位置
问小锦底部抽屉(手机)assist.css200(遮罩),面板 200(.2,.8,.2,1)100%—
确认弹窗 .xa-dlg / 遮罩assist.css遮罩 160,面板只做 200 位移,透明度瞬间变化(.2,.8,.2,1)8px进出时长相同;关闭时直接移除,没有出场
菜单 / 气泡 / 提示 .xa-menu .xa-bubble .xa-toastassist.css120 / 120(toast 160)(.2,.8,.2,1)4px—
mvp .toastmvp.css200(.2,.8,.2,1)——
12 右栏 .aside / 左栏 .side 抽屉 + 遮罩12进 200 / 出 200(.2,.8,.2,1)100%进出时长相同
12 命令面板 .cmdk .cp12进 200(rise),出 0(.2,.8,.2,1)—没有出场
12 消息 .msg / .gc12200 / 320 rise(.2,.8,.2,1)—不在本批范围
07 窗口与托盘 .win .plate07300 / 透明度 240(.2,.8,.2,1)—保持原样(工作台布局)
07 应用中心 .ac 遮罩、放大、面纱07220/260/160/180/90/120(.2,.8,.2,1) / linear—07/05 已批准,不改
07 用户菜单 .menu070 / 0(display 切换)——没有动画
07 手机问小锦 .msheet07遮罩 200,面板 260(.2,.8,.2,1)100%进出时长相同
05 卡片阵列 .ac .lift .detail #gridv05300/200/300/160(.2,.8,.2,1)、(0.22,1,0.36,1)—已批准的空间动效,不改
05 详情页签、10 页签05/100(瞬切)——下划线和内容都是瞬切
13 步骤面板 .pane.on / .rise13420 / 500(.2,.8,.2,1)—不在本批范围
主题切换(base / theme-sync / 3D 底色)全站450(0.4,0,0.2,1)—加入「主题切换过渡」分组
3D 飞到工位 / 复位视角04-glb700 / 600(JS 补间)easeInOutCubic—加入「3D 镜头」分组
加载:骨架屏、转圈、思考点、进度条mvp/assist/12/041.4s/0.8s/1s 循环linear—加入「加载动画」分组

完整清单(78 条 CSS transition/animation)见附录 A。

2. Token 定义(prototypes/motion-batch1/motion-tokens.{json,css})

Token值用途
--jm-motion-enter300ms面板和弹窗进场
--jm-motion-exit200ms面板和弹窗出场
--jm-motion-shift-in / -out12px / 8px进场和出场的位移
--jm-motion-pop-in / -out / --jm-motion-shift-pop150 / 120ms,4px菜单、气泡、提示
--jm-motion-tab-content150ms,从 0.35 透明度开始页签内容
--jm-motion-tab-indicator180ms页签下划线
--jm-motion-feedback120ms等于现有的 duration-fast
--jm-motion-spatial320ms等于现有的 spatial / duration-slow,07/05 不动
--jm-motion-fade120ms linear「减少」时保留的淡入淡出
--jm-ease-enter(0.22,1,0.36,1)进场;和现有的 --jm-ease-out 及 spatial 曲线相同
--jm-ease-exit(0.4,0,0.6,1)出场的位移 / 滑出(修正前为 (0.4,0,1,1),见第 0 节)
--jm-ease-exit-fadelinear出场的透明度(与位移分开,一点关闭就开始变淡)
--jm-ease-long(0.16,1,0.3,1)长距离移动:抽屉、底部面板
--jm-ease-standard(0.2,0,0,1)预留

统一的范围只有面板、弹窗、页签、问小锦和抽屉。07 窗口、应用中心浮层和 05 卡片保持原样,已批准的角度和参数没有动。

可打断。 JMMotion.enter/leave 用 WAAPI 实现。打断时先读取当前的 opacity 和 transform,从这个值继续走,剩余时长按剩余距离等比缩放,最少保留 40%。CSS transition 部分(问小锦、抽屉)本来就从当前值反向。页签下划线从当前几何位置继续。

3. 改动内容(都只在样张里,靠服务端注入和带锚点的替换实现)

  1. 动效节奏
  1. 减少动态效果
  1. 3D 性能档位

4. 验证结果

验证时间:2026-10-09 17:00–17:30(北京时间)。浏览器为 Playwright 自带的 Chromium 和 WebKit,3D 使用 SwiftShader 软件渲染。

项目结果
矩阵:Chromium/WebKit × 浅/深 × 390 触屏/768/1440/2560 × 5 个独立页(07、12、04 查看器、04-glb、13)+ 07 内嵌 A-01(12)/C-03(04-glb)112/112 通过(修正后 10-09 18:00 北京时间重跑):0 报错,页面和内嵌页 0 横向溢出;07 切主题后内嵌页跟随;默认档为「完整」。截图已逐张看过
动效(两个引擎)82/82(修正后重跑,含新增的 6 项「内容随容器」检查)。时长和曲线通过 getAnimations() 的 timing 与 computed style 读取:问小锦进 300ms/12px/(0.22,1,0.36,1),出 200ms,位移 (0.4,0,0.6,1)、透明度线性;弹窗进 300/12px,出 200/8px;抽屉进 300 long 曲线,出 200 exit 曲线;页签下划线 180、内容 150 从 0.35;菜单 150/120、4px。中途打断(自动测试覆盖问小锦面板、唤起小锦命令面板、页签):在动画进行到一半时反向,从打断时刻的当前值继续,没有跳变。弹窗和抽屉是 CSS transition,浏览器本来就会从当前值反向;这部分在对照页的「打断」按钮下用肉眼看过(mp4 里也能看到),没有写成自动测试。「减少」时问小锦和弹窗只做 120ms 淡入淡出、不位移,3D 镜头瞬切;系统开启减少动态效果时,跟随系统且所有分组关闭
同步(两个引擎)14/14。独立页 → 其他标签页 / 07 / 内嵌页;07 → 内嵌页 / 独立页;内嵌页 → 07;内嵌页的设置入口打开 07 宿主面板;键盘 Enter、方向键、Tab 循环、Esc 都可用
3D(Chromium,DPR 2,1440×900)11/11。三档真实改变渲染设置;DOM 像素比保持 2;页面隐藏时 0 帧,恢复后继续;画布出视口时 0 帧;07 换下舞台后 0 帧;模拟慢帧时自动从均衡降到流畅,原因显示在设置里
完整档静止画面与原页一致28/28(Chromium/WebKit × 浅/深 × 7 页 @1440)。04-glb 有三处正常差异,比较时遮住:工位托盘的流动动画、时钟、画质控件(这是有意改的)
npm run check / center:check / motion:check全部通过(errors 0;center 4/4;motion 4/4)。git status 显示 app/jmos 没有改动
颜色和品牌样张文件中没有 HEX、rgb()、color-mix,也没有莱茵生命的名称或字体

3D 相对成本(软件渲染,只看比例):

页面 / 档位画布像素阴影单帧(软件渲染)
04-glb 高画质2048×14643.00MP2048,99 个投影物体1189ms
04-glb 均衡1536×10981.69MP1024(原配方)736ms
04-glb 流畅819×5850.48MP关247ms(≈21%)
04 查看器 高画质 / 均衡 / 流畅2112×1270 / 1584×952 / 844×5082.68 / 1.51 / 0.43MP2048 / 2048 / 关175 / 116 / 24ms(≈14%)

三档的绘制次数相同(glb 232,查看器 304),差别来自像素数和阴影。以上不是帧率,真实帧率需要在你的 MacBook Air 上测。

关键帧见 motion-batch1.png 第 ② 部分(进场,暂停后定位到 0/60/120/200/300ms)和第 ③ 部分(修正后的退场,0/50/100/150/200ms,录帧时冻结了页面计时器,避免元素被提前移除);第 ⓪ 部分是修正记录。mp4 已按修正后的版本重录:对照页 0.25× 慢放(弹窗、页签、面板、问小锦、手机抽屉,每个场景都包含「打断」),已剪掉页面加载的空白段,约 69 秒、3.3MB。

5. 需要你决定 / 已知问题

6. 合并时要改的文件

文件改什么
app/jmos/assets/tokens.css(或新建 assets/motion.css)加入第 2 节的 token
app/jmos/assets/theme-sync.js + mvp.js合入 JMPrefs / JMMotion 运行时:偏好读写、分组、跨页同步、enter/leave;主题过渡受 theme 分组控制
新增 app/jmos/assets/render-quality.js、settings-panel.{js,css}三维档位与设置面板
app/jmos/assets/assist.css / assist.js问小锦、弹窗、菜单使用新 token;首次打开清掉过渡;弹窗加出场;reduced() 改读分组
07-台前调度工作台.html菜单进出场、noanim 受 workspace 分组控制、手机问小锦面板、偏好下发给内嵌页、设置入口
12-小锦对话.html抽屉和命令面板的进出场
10-待确认队列.html、05-应用卡片首页.html(详情页签)页签下划线和内容过渡
04-孪生-glb.html、assets/twin-scene.js档位、像素比、阴影、停画、camera / theme 分组
design-system/ui/parts/spatial-motion.json偏好字段 renderQuality;tabChange 规则;系统设置与用户选择谁优先

附录 A:CSS 动效完整清单

文件选择器属性值
assets/mvp.css.btntransitionbackground-color var(--jm-duration-fast) var(--jmx-ease), border-color var(--jm-duration-fast) var(--jmx-ease), color var(--jm-duration-fast)
assets/mvp.css.inputtransitionborder-color var(--jm-duration-fast)
assets/mvp.css.card.clicktransitionborder-color var(--jm-duration-fast)
assets/mvp.css.list .litransitionbackground-color var(--jm-duration-fast)
assets/mvp.css.skelanimationskel 1.4s linear infinite
assets/mvp.css.spinanimationspin .8s linear infinite
assets/mvp.css.toasttransitiontransform var(--jm-duration-base) var(--jmx-ease), opacity var(--jm-duration-base)
assets/assist.css.xa-menutransitionopacity 120ms var(--xa-ease), transform 120ms var(--xa-ease)
assets/assist.css.xa-bubbletransitionopacity 120ms var(--xa-ease), transform 120ms var(--xa-ease)
assets/assist.css.xa-poptransitionopacity var(--xa-out) var(--xa-ease), transform var(--xa-out) var(--xa-ease)
assets/assist.css.xa-m.nw, .xa-thinkinganimationxa-rise var(--xa-in) var(--xa-ease)
assets/assist.css.xa-dots ianimationxa-dot 1s infinite
assets/assist.css.xa-toasttransitionopacity 160ms var(--xa-ease), transform 160ms var(--xa-ease)
assets/assist.css.xa-scrimtransitionopacity 160ms var(--xa-ease)
assets/assist.css.xa-dlgtransitiontransform 200ms var(--xa-ease)
assets/assist.css.xa-shscrimtransitionopacity 200ms var(--xa-ease)
04-孪生-glb.html.viewertransitionbackground-color 450ms
04-孪生-glb.html.loadingtransitionopacity var(--jm-duration-slow)
04-孪生-glb.html.loading .bar itransitionwidth .2s
04-孪生-glb.html.tiletransitionborder-color var(--jm-duration-fast), background-color var(--jm-duration-fast)
04-孪生-glb.html.fadeanimationfadeIn var(--jm-duration-base) var(--jmx-ease)
05-应用卡片首页.html.edgetransitionopacity 160ms
05-应用卡片首页.html.actransitiontransform 300ms cubic-bezier(.2,.8,.2,1), opacity 300ms cubic-bezier(.2,.8,.2,1)
05-应用卡片首页.html.lifttransitiontransform 200ms cubic-bezier(.2,.8,.2,1)
05-应用卡片首页.html.lift::beforetransitionopacity 200ms
05-应用卡片首页.html.hltransitionopacity 150ms
05-应用卡片首页.html.focustransitionopacity 200ms
05-应用卡片首页.html.ruler .tk itransitionheight 200ms, background 200ms
05-应用卡片首页.html#gridvtransitionopacity 160ms var(--jm-ease-out)
05-应用卡片首页.html#gridv .lifttransitiontransform 150ms var(--jm-ease-out)
05-应用卡片首页.html#gridv .fronttransitionborder-color 150ms
05-应用卡片首页.html.gfadetransitionopacity 160ms
05-应用卡片首页.html.detailtransitionopacity 300ms var(--jm-ease-out), transform 300ms var(--jm-ease-out)
05-应用卡片首页.html.detail .rel .chiptransitionborder-color 150ms, background 150ms
07-台前调度工作台.html.win.animtransitiontransform var(--mo-dur) var(--mo-ease), opacity 240ms var(--mo-ease)
07-台前调度工作台.html.platetransitiontransform var(--mo-dur) var(--mo-ease), opacity 240ms
07-台前调度工作台.html.fadeinanimationjmFade 180ms var(--mo-ease) 140ms both
07-台前调度工作台.html.slot .lbtransitiontransform 150ms var(--jm-ease-out)
07-台前调度工作台.html.droptransitionopacity 120ms
07-台前调度工作台.html.ac .scrimtransitionopacity 160ms linear
07-台前调度工作台.html.ac.show .scrimtransitionopacity 220ms var(--mo-ease)
07-台前调度工作台.html.ac .zoomtransitiontransform 220ms var(--mo-ease), opacity 0s linear 220ms
07-台前调度工作台.html.ac.show .zoomtransitiontransform 260ms var(--mo-ease), opacity 0s
07-台前调度工作台.html.ac.entering:not(.show) .zoomtransitionopacity 120ms linear
07-台前调度工作台.html.ac .veiltransitionopacity 90ms linear
07-台前调度工作台.html.ac.ready .veiltransitionopacity 180ms var(--mo-ease)
07-台前调度工作台.html.ac.ready.closing .veiltransitionopacity 90ms linear
07-台前调度工作台.html.msheet .scrtransitionopacity 200ms var(--mo-ease)
07-台前调度工作台.html.msheet .panetransitiontransform 260ms var(--mo-ease)
12-小锦对话.html.summontransitionborder-color var(--jm-duration-fast)
12-小锦对话.html.msganimationrise var(--jm-duration-base) var(--jmx-ease)
12-小锦对话.html.caretanimationblink 1s steps(2) infinite
12-小锦对话.html.dots ianimationdot 1.2s infinite
12-小锦对话.html.gcanimationrise var(--jm-duration-slow) var(--jmx-ease)
12-小锦对话.html.srctransitionborder-color var(--jm-duration-fast), background-color var(--jm-duration-fast)
12-小锦对话.html.prompttransitionborder-color var(--jm-duration-fast)
12-小锦对话.html.cboxtransitionborder-color var(--jm-duration-fast)
12-小锦对话.html.wave ianimationwv 0.9s ease-in-out infinite
12-小锦对话.html.cmdk .cpanimationrise var(--jm-duration-base) var(--jmx-ease)
12-小锦对话.html.prog itransitionwidth .6s linear
12-小锦对话.html.pinitanimationrise var(--jm-duration-base) var(--jmx-ease)
12-小锦对话.html.r12-scrimtransitionopacity var(--jm-duration-base) var(--jmx-ease)
12-小锦对话.html.asidetransitiontransform var(--jm-duration-base) var(--jmx-ease), visibility 0s linear var(--jm-duration-base)
12-小锦对话.htmlbody.r12-a .asidetransitiontransform var(--jm-duration-base) var(--jmx-ease), visibility 0s
12-小锦对话.html.sidetransitiontransform var(--jm-duration-base) var(--jmx-ease), visibility 0s linear var(--jm-duration-base)
12-小锦对话.htmlbody.r12-s .sidetransitiontransform var(--jm-duration-base) var(--jmx-ease), visibility 0s
13-故障诊断.html.stp .notransitionbackground-color var(--jm-duration-base), color var(--jm-duration-base), border-color var(--jm-duration-base)
13-故障诊断.html.stp.on.auto .bar ianimationfill var(--dur, 6s) linear forwards
13-故障诊断.html.log litransitionbackground-color var(--jm-duration-fast)
13-故障诊断.html.caretanimationblink 1s steps(2) infinite
13-故障诊断.html.pane.onanimationin .42s var(--jmx-ease)
13-故障诊断.html.riseanimationin .5s var(--jmx-ease) backwards
13-故障诊断.html.feed li.newanimationflash 1.6s var(--jmx-ease)
13-故障诊断.html.chk litransitioncolor var(--jm-duration-base)
13-故障诊断.html.lanes .drawanimationdraw 1.6s var(--jmx-ease) forwards
13-故障诊断.html.conf .track ianimationgrow 1s var(--jmx-ease) backwards
13-故障诊断.html.acttransitionbackground-color var(--jm-duration-fast)
13-故障诊断.html.qrow.newanimationslidein .7s var(--jmx-ease) backwards .2s