fix(motion): M305 r1 —— P1 空轨道重复脉冲 + 三条 P2(进场被删跳零 / 纯重排不落终态 / 遮罩取色与口径)

- P1-1:observe_progress 在「没有轨道且目标没变」时直接 return false。少了这一条,
  ratio 恒为 1.0 之后每条 stage 事件都会插一条 from==to 的空轨道 ⇒ 200ms 后再闪一次
  150ms 脉冲(违反「一次收束不循环」+ 空烧帧)。用例 a_repeated_reading_after_the_pulse…
- P2-1:visibility_of 改成按**当前采样**取(原来取 track.from ⇒ 进场途中被删的行 0→0,
  高度当拍归零、下面整列上跳)。用例 deleting_a_row_mid_enter_does_not_jump_to_zero
- P2-2:遮罩底色 Card → Canvas(版本行脚下就是画布;深色档会露出亮一档)
- P2-3:纯重排(同 id 换序)当场把 order 对齐 current。没有轨道 ⇒ advance 早退 ⇒
  expire 不跑 ⇒ order 会永远停在旧序。用例 a_pure_reorder_lands_on_the_new_order_at_once
- P2-4:fade.rs 收成唯一口径(预合成 = 恒不透明;子树淡出是唯一例外,且必须自成一层),
  reveal.rs 指向它并登记 interaction α 守卫扫不到这一处的盲区
- 出图补深色档 list-exit-dark.png,probe 复跑 PASS(墨色 110→148 / 105→154)
This commit is contained in:
AskaEth committed 2026-11-13 22:12:43 +08:00
1 parent ae33674293
commit d24ef21bee
8 files changed
+179 -18

No files matched your search

@@ -14,11 +14,20 @@
//! | 子内容的**排版** | `content_height`(整段过渡里不变 ⇒ 不重排) |
//! | 自己占的**格子**(= 裁切框) | `visible_height`(逐帧变,由行的可见度给) |
//!
//! ## 绘制
//! ## 绘制:裁切 + **一层与画布同色的收尾遮罩**
//!
//! 走 `Renderer::with_layer(bounds)`(tiny-skia 是 `push_clip`,wgpu 是同族的层栈),超出的部分
//! **画不出来**——「收起到 0」在像素上就是「一格都不占」,不需要半透明(D27 的单一口径)。
//! 淡出是另一件事,在 `motion/fade.rs`(色板预合成)。
//! 裁切走 `Renderer::with_layer(bounds)`(tiny-skia 是 `push_clip`,wgpu 是同族的层栈):超出的
//! 部分画不出来——「收起到 0」在像素上就是「一格都不占」。
//!
//! 淡出走 [`revealed`] 的 `veil` 参数:一层**与脚下画布同色**(`MaterialLayer::Canvas`)的 quad,
//! `α = 1 − 可见度`,**且必须自成一层**。为什么是 α 而不是预合成、为什么必须自成一层:
//!
//! | 问题 | 答案 |
//! |---|---|
//! | 为什么不用预合成(`with_alpha(α).over(底)`,D27 的正统口径) | 预合成要先知道被盖住的像素,而「一行的内容」在 `Element` 里是黑盒;替代方案(把整份 `Scheme` 预合成后传一个 `Ui` 下去)要求那个 `Ui` 活得比 `Element<'a>` 久——视图函数里造不出来,泄漏成 `'static` 则是每帧每行泄漏一份 49 色方案 |
//! | 为什么必须 `with_layer` | tiny-skia 的绘制按「四边形 → 三角 → 图 → 文字」分批(`iced_tiny_skia/src/lib.rs::present`),同层里文字永远排在四边形之后。第一版把遮罩塞进当前层:红色 α=0.3 的遮罩实测**一个文字像素都没盖住**(整图 0 个偏红像素);改成子层后同一实验 422 个偏红像素、正好落在动的那两行(y 262..307) |
//! | 静息帧 | `veil = None` ⇒ **一个 quad 都不画**,与改造前逐像素相同(出图基线与 M305 之前同源) |
//! | 口径归属 | 这是全仓**唯一**一处「把 α 交给渲染器」的地方,规则的真源写在 `motion/fade.rs` 的模块文档。`interaction/mod.rs` 的 α 守卫只扫状态层取色、**扫不到**这里(不经过任何 `Style`)——盲区已登记在 `fade.rs` |
//!
//! ## 与 `clip.rs` 的区别(为什么不再写一个通用件)
//!