组件/设计工程概念手册/Alpha 噪点掩膜与光斑追踪

Alpha 噪点掩膜与光斑追踪

解决 Overlay 混合导致底色发灰的难题,通过 mask-composite: intersect 实现晶莹微质感与光标反光追踪;TxCard 的折射光源还能用弹簧跟随指针。

设计理念

Alpha 噪点掩膜与光斑追踪

在拟真材质设计中,噪点(Grain)与高光(Specular)是赋予界面物理触感的关键细节,但错误的实现会破坏色彩纯净度。

传统 Overlay 叠加噪点发灰的根源

许多设计师习惯在半透明卡片上叠加一层 5% 灰度噪点,并使用 CSS mix-blend-mode: overlay。 在浅色或淡色调(Alpha 约 16%)的色洗(Wash)上,叠加混合模式的算法公式: Overlay(A,B)={2ABB<0.51−2(1−A)(1−B)B≥0.5\text{Overlay}(A, B) = \begin{cases} 2AB & B < 0.5 \\ 1 - 2(1-A)(1-B) & B \ge 0.5 \end{cases} 会导致每个像素点的亮度被强制向灰色拉扯,在 Retina 视网膜高清屏上呈现出一层肮脏的灰色麻点,彻底丧失通透感。

mask-composite: intersect 解决方案

TuffEx 的核心突破在于:不修改像素的 RGB 颜色,而是将分形噪点编织到透明通道(Alpha Mask)中:

EXAMPLE.SCSS
@supports (mask-composite: intersect) {
  .tx-status-hint__wash {
    background-color: var(--tx-status-hint-accent, #67c23a);
    // 线性渐变与分形噪点进行交集合成,仅控制透光程度
    mask-image:
      linear-gradient(
        to right,
        rgb(0 0 0 / var(--tx-status-hint-wash-strength, 0.26)),
        rgb(0 0 0 / calc(var(--tx-status-hint-wash-strength, 0.26) * 0.45)) 38%,
        transparent
      ),
      $grain; // 140px 见方的 feTurbulence 分形噪点 SVG
    mask-size: 100% 100%, 140px 140px;
    mask-repeat: no-repeat, repeat;
    mask-composite: intersect;
  }
}

这种做法让噪点只决定“色彩以多大的物理密度透出”,底层背景的纯净度丝毫不受污染。噪点的 alpha 平均约 0.6,所以前缘 0.26 的强度在浅色主题里约合 16%;暗色主题取 0.2,因为同样的色调在深色页面上更显眼。

示例加载中...

卡片物理反光追踪(Specular Light)

在 TxCard 上,用户滑动鼠标时,卡片表面与边缘会呈现随光标游走的微弱径向高光(Specular Light)。它由 specular 属性控制:不设置时跟随 clickable,可点击的卡片默认就有,禁用的卡片不画。

  • 相对坐标采样:指针在卡片上移动时,组件把光标位置换算成卡片内的百分比坐标,写成反光层的 --tx-card-light-x、--tx-card-light-y。
  • 极低透明度漫射:高光是一道 600px 的圆形径向渐变,中心 6% 的白色,到 40% 处完全透明。强度严格压制在 0.06,只在暗色主题下绘制(浅色底上 6% 的白看不出来),高对比度模式下不画,绝不夺取卡片内部文字的主角地位。指针进入时用 240ms 淡入,离开时淡出。

阻尼平滑与法线贴图错觉

为了防止鼠标快速移动时光斑出现机械跳动,反光点不直接跳到光标处,而是每帧向它靠近一段: P⃗render(t)=P⃗render(t−1)+α′⋅(P⃗cursor(t)−P⃗render(t−1)),α′=1−(1−α)Δ\vec{P}_{\text{render}}(t) = \vec{P}_{\text{render}}(t-1) + \alpha' \cdot \left(\vec{P}_{\text{cursor}}(t) - \vec{P}_{\text{render}}(t-1)\right), \qquad \alpha' = 1 - (1 - \alpha)^{\Delta} α = 0.18 是 60Hz 下一帧走完的比例,Δ 是帧间隔除以 16.67ms(限制在 0.1–2)。按 Δ 复合以后,120Hz、144Hz 屏幕上的走法与 60Hz 一致;按 60Hz 推算,一次跳变 16 帧(约 267ms)走完 95%。指针刚进入卡片时,反光点直接出现在光标下,而不是从上次离开的地方滑过来;系统开启“减少动态效果”时,反光点始终直接跳到光标处,也不做淡入淡出。

高光与卡片边缘 1px 细线相互干涉:光斑掠过边框时,边框占据的那一圈另画一道 240px、中心 30% 白色的更紧更亮的光,用 mask-composite: exclude 挖掉内容区,只留在边框上,形成如同光线擦过倒角边缘的法线高光错觉(Normal Map Illusion),大大增强了三维立体触感。这一圈只画在 solid 卡片的实线边框上:dashed 的虚线会把间隙一起照亮,所以不画;plain 没有边框。

示例加载中...

折射光源跟随

另一种跟随指针的光属于折射材质本身。TxCard 的折射光源跟随默认关闭,只在 background="refraction" 且打开 refraction-light-follow-mouse 时工作:

  • 相对坐标采样:指针在卡片上移动时,组件把光标位置换算成卡片内 0–1 的归一化坐标,作为光源的目标点;指针离开卡片,目标点回到中心 (0.5, 0.5)。
  • 移动折射的光源点:光源点经 TxBaseSurface 的 refraction-light-x/y 写成 --tx-surface-refraction-light-x/y,决定折射滤镜层与色膜层上几处径向光晕的位置,其中一处落在对角的对称点上。这条路径不另加白色高光层,白色高光是上面的 specular。
  • 随指针微调强度与角度:光源离中心越远,折射强度最多加 16 × refraction-light-follow-intensity(默认 0.45,即最多 +7.2);折射角度按同一系数向指针方向插值。

弹簧平滑

为了防止鼠标快速移动时光斑机械跳动,光源点不直接跳到目标点,而是由一根逐帧积分的弹簧带过去: v←(v+k (Ptarget−P) Δ)cΔ,P←clamp⁡(P+v Δ, 0, 1)v \leftarrow \left(v + k\,(P_{\text{target}} - P)\,\Delta\right) c^{\Delta}, \qquad P \leftarrow \operatorname{clamp}(P + v\,\Delta,\ 0,\ 1) k 是 refraction-light-spring-stiffness(默认 0.15,取值限制在 0.01–0.55),c 是 refraction-light-spring-damping(默认 0.6,限制在 0.55–0.99),Δ 是帧间隔除以 16.67ms(限制在 0.1–2,第一帧取 1)。位置差与速度都小于 0.002 时视为停稳,循环随之停止。关掉 refraction-light-spring,光源点直接跳到目标点。按 60Hz 推算,默认参数下一次跳变只冲过目标约 3%,约 130ms 后稳定在 5% 以内。位置这一步也乘 Δ,所以 120Hz、144Hz 屏幕上光源点的走法与 60Hz 基本一致。

示例加载中...