mcpField
M
mask-reveal-transition

mask-reveal-transition

github.com/rheinmir设计与 UI1076 次安装2 周前更新
代码仓库

关于 mask-reveal-transition

用于以原生 HTML、CSS 和 JavaScript 实现有机形状遮罩揭示图片,或在固定分栏布局中随内容切换图片。涵盖滚动进度和活动面板两种方式,并要求处理减少动态效果及浏览器兼容。

主要功能

  1. 01有机径向遮罩揭示图片
  2. 02遮罩半径随滚动进度变化
  3. 03固定分栏布局切换图片
  4. 04支持减少动态效果设置
  5. 05兼容 Safari 遮罩前缀

适用场景

  1. 01为作品集添加墨迹扩散式揭示
  2. 02随案例文字滚动切换固定图片

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/rheinmir/setup --skill mask-reveal-transition

安装后在 Claude Code 中输入/mask-reveal-transition确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/
demo.html
mask-reveal-transition.css
mask-reveal-transition.js

详细介绍

技能:mask-reveal-transition

原生 HTML/CSS/JS 组件——通过有机形状的遮罩(墨迹晕染圆环,中心固定,半径逐渐增大)显示图片,而非普通的交叉淡入淡出/透明度过渡。两个变体共用同一套底层机制:通过 getBoundingClientRect() 测量 section 内的滚动进度,将其映射到 0..1,然后把晕染半径写入 CSS 自定义属性。

内容

用途与背景
  • 用途: 根据滚动进度,通过有机形状的遮罩(墨迹晕染圆环)显示/切换图片;或使用固定分屏布局,左侧 sticky 显示图片,图片根据右侧当前阅读的面板通过遮罩切换——优先使用 Rheinmir/uiux-asset 中的原始代码;assets/ 是轻量的原生备用版本。
  • 触发条件(何时使用):
    • 艺术作品集风格的图片切换,像“墨迹晕染”一样与滚动同步(不是平滑的交叉淡入淡出)。
    • 案例研究/作品集双栏布局:左侧固定图片,右侧滚动文本,图片根据当前阅读的段落切换。
  • 非目标: 不要用于简单的显示效果(进入视口时淡入并轻微滑动)——那是 skills/scroll-effects 的模式 #1,不包含形状遮罩。不要用于 GPU 开销较大的全屏缩放模糊图片切换——那是 skills/blur(Three.js/shader)。此技能只使用 CSS mask-image,不使用 canvas/WebGL。
心智模型

section → 测量滚动进度(getBoundingClientRect → 0..1)或当前活动面板(IntersectionObserver)→ --mrt-r → 对“上层”图片应用 mask-image radial-gradient → 透明孔洞向外晕染 → 显示“下层”图片。两个变体:[data-mrt-blob](每帧写入 --mrt-r,不使用 transition)和 [data-mrt-split](根据面板离散切换,通过 @property 实现 transition)。

输入和输出约定
字段必填?含义
输入图片(blob 使用 2 张;split 每个面板使用 1 张)是替换原始版本/资源中的内容
输入项目是否允许引入外部库/文件否(默认:允许)不允许时 → 使用原生 assets/
输出带遮罩显示效果的 HTML 页面/组件是通过本地 HTTP 运行,包含 -webkit-mask-image,并包含 prefers-reduced-motion 分支
输出Playwright 验证证据是前/中/后截图(变体 1);断言图片已切换且保持固定(变体 2)
规则与能力
  • RULE-01(MUST):支持浏览器的 mask-image:Safari(包括较新的 Safari)只接受 -webkit-mask-image/-webkit-mask-repeat——必须同时编写标准 mask-image 和 -webkit-mask-image(CSS 资源中已包含,不要在适配/压缩时删除前缀)。缺少前缀 = Safari 中的上层图片永远不会出现孔洞,可视为效果未运行。
  • RULE-02(MUST):如果任意祖先元素(包括远端祖先,直至 <body>)设置了 overflow: hidden/auto/scroll 或 clip,position: sticky 就不会生效——这是将 .mrt-split-sticky 嵌入现有布局时最常见的错误(许多页面会在 wrapper 上设置 overflow: hidden 来阻止横向滚动,却意外导致所有子元素的 sticky 失效)。在报告“sticky 不工作”是 bug 之前,检查整个祖先链。
  • RULE-03(MUST):变体 2 使用 @property --mrt-r,让浏览器能够动画处理位于 calc()/gradient 中的自定义属性——缺少此声明时,通过 JS 更改 --mrt-r 会立即跳变,而不是平滑过渡。
  • RULE-04(MUST):prefers-reduced-motion: reduce → 两个变体都立即将 --mrt-r 设置为最大半径(完全显示图片),并关闭动画/过渡——JS/CSS 中已预先实现此分支,适配时不要删除。
  • RULE-05(MUST):页面上所有 [data-mrt-blob] 只使用一个经 rAF 节流的 scroll 监听器;每个 [data-mrt-split] 只使用一个 IntersectionObserver 观察其面板——不要绑定多个独立的 scroll 监听器或用途重复的 observer。
  • RULE-06(MUST):使用 playwright-verify 验证:滚动经过变体 1 时,分别在开始/中间/结束处截图,以确认晕染圆环逐渐扩大;并断言变体 2 在每个面板进入视口中部时切换到正确图片,且阅读过程中图片栏确实保持固定(不随页面滚动)。
  • 能力:从外部资源仓库或技能的 assets/ 中读取/复制文件;编写项目 HTML/CSS/JS 文件;运行无头浏览器进行验证。
失败边界
  • 效果在 Safari 上不运行 → 缺少 -webkit-mask-image → 修复前缀,不要认定为其他 bug。
  • Sticky 不固定 → 报告 bug 前,检查整条父级链中的 overflow/clip。
  • 通过 file:// 打开 → 无效;改用 HTTP 重新运行。
  • 实际需求是 opacity/translate reveal 或全屏 shader 图像切换 → 不属于此 skill,转到 skills/scroll-effects 或 skills/blur。

HOW

主要工作流
StepTypeInputsActionOutputs/exitFailure/next
W01judgment需求选择变体(blob 或 split)和来源:原版(默认)或 assets/ vanilla选择不允许拉取外部 lib → B01
W02effect原版 pen打开运行链接确认效果正确 → 复制完整 .html 文件(+ _assets/)→ 保留署名注释 → 只修改内容/图片/颜色项目中的文件—
W03deterministic页面通过 HTTP 在本地运行,使用 playwright-verify 验证截图 + 断言Safari/sticky 出错 → 查看 Failure boundaries,修复后重试

各步骤详情(W01–W03 的事实来源):

原版 — 优先使用(复制完整文件,不要重写)

作者的原始代码(公开 CodePen = MIT)位于外部 repo Rheinmir/uiux-asset — 可运行 gallery:https://rheinmir.github.io/uiux-asset/scroll-effects/ 。 流程:打开运行链接确认效果正确 → 将完整 .html 文件(+ 文件引用的 _assets/ 目录)复制到项目中 → 保留首行署名注释 → 只修改内容/图片/颜色。通过 HTTP 在本地运行,不要使用 file://。 如需离线获取完整套件,可运行 git clone --depth 1 https://github.com/Rheinmir/uiux-asset。

原版 Pen — 作者链接
Ink Transition Scroll Effect — iamryanyu运行 · 代码
Pinned Split-Screen Mask Reveal — gridmorphic运行 · 代码
Parallax Jungle Leaves Reveal — Mamboleoo运行 · 代码

此 skill 中的 assets/ 只是自行编写的精简 vanilla 版本 — 仅在项目不允许拉取外部 lib 时使用;默认使用上面的原版。

Assets

assets/demo.html + assets/mask-reveal-transition.css + assets/mask-reveal-transition.js — 阅读后进行 ADAPT(更换图片、调整 --mrt-edge 边缘柔和度、修改面板内容)。

分支
IDKindGuard行为Skip / failureRejoin
B01conditional_required项目不允许拉取外部 lib/file使用 assets/demo.html + .css + .js,阅读后进行 ADAPT(图片、--mrt-edge、面板内容)—W03
B02user_optional需要离线获取完整套件git clone --depth 1 https://github.com/Rheinmir/uiux-asset—W02
验证与停止

确定性验证(playwright):变体 1 在滚动前/中/后截图,确认墨迹圆环逐渐变大;变体 2 断言每个面板进入视口中央时图片正确切换,且图片列确实固定。需要人工审核:确认“墨迹扩散”的方向正确(逐渐显露,而不是逐渐遮盖)。上述断言全部通过后停止。

示例
  • 正例: 双列作品集案例研究,“左侧图片固定,右侧文字滚动” → 从 Rheinmir/uiux-asset 复制完整的 pinned-split-screen-mask-reveal.html,更换面板图片 → 使用 playwright 断言每个 [data-mrt-panel] 进入视口中央时图片会切换,且图片列不会随页面滚动。
  • 边界/失败: 将 .mrt-split-sticky 嵌入带有 overflow: hidden 的布局 wrapper → 图片随页面滚动,无法固定 → 检查父级链,移除 wrapper 上的 overflow,不要报告为组件 bug。Minify 移除了 -webkit-mask-image → Safari 中没有 mask 镂空效果 → 恢复该前缀。
参考 — 通用底层机制

对于每个 section([data-mrt-blob] 或 [data-mrt-split]):同一框架内绝对定位叠放 2 张图片——下层图片(z-index 较低,始终预先显示)和上层图片(z-index 较高,带有蒙版)。上层图片具有

mask-image: radial-gradient(circle at 50% 50%, transparent 0, transparent var(--mrt-r), black calc(var(--mrt-r) + var(--mrt-edge)), black 100%);

— 半径 --mrt-r 内的区域透明(上层图片在此处消失 → 显露下层图片),--mrt-r + --mrt-edge 之外的区域仍为不透明(上层图片完全遮挡)。--mrt-r 逐渐增大 = 透明圆逐渐扩展 = 下层图片从中心“晕开”,呈现墨迹扩散的感觉——而不是反过来(实心圆点逐渐变大),因为那样只会逐渐遮挡,而不是逐渐显露。

变体 1 — Blob/墨迹蒙版显露([data-mrt-blob])
<section data-mrt-blob>
  <div class="mrt-blob-frame">
    <img class="mrt-blob-under" src="B.jpg" alt="…">
    <img class="mrt-blob-over" src="A.jpg" alt="…">
  </div>
</section>

每一帧都根据滚动进度直接设置 --mrt-r(不使用 CSS transition):滚动监听器通过 rAF 限流,测量 stage.getBoundingClientRect(),progress = (vh - rect.top) / (vh + rect.height) 并限制在 0..1,再乘以最大半径(框架对角线 / 2 + margin)→ over.style.setProperty('--mrt-r', ...)。此变体不使用 transition——transition 会导致扩散圆相对于真实滚动位置滞后(原因与 svg-stroke-reveal 的 "scroll" 模式不使用 transition 相同)。

变体 2 — 固定分屏蒙版显露([data-mrt-split])
<div class="mrt-split-section" data-mrt-split>
  <div class="mrt-split-sticky">
    <img class="mrt-split-under" alt="…">
    <img class="mrt-split-over" alt="">
  </div>
  <div class="mrt-split-scroll">
    <article data-mrt-panel data-mrt-src="1.jpg">…</article>
    <article data-mrt-panel data-mrt-src="2.jpg">…</article>
  </div>
</div>

图片列纯粹使用 CSS position: sticky(不使用 GSAP/ScrollTrigger——采用浏览器原生支持的最简单固定方式)。JS 仅负责根据当前 active 面板切换图片/蒙版:在每个 [data-mrt-panel] 上附加一个 IntersectionObserver(threshold 0.5),当面板进入视口中心时 → 调用 revealTo(src):将当前图片移到“上层”(完全遮挡,立即设置 --mrt-r = 0,强制 reflow),将新图片放到“下层”,然后通过 requestAnimationFrame 将 --mrt-r 设回最大半径,让 CSS transition(通过 @property --mrt-r { syntax: "<length>"; ... } 注册)平滑运行。这里 --mrt-r 会随面板事件离散变化,而不是随着滚动的每个 px 变化——因此(与变体 1 不同)在 --mrt-r 上使用 CSS transition 才是合适的。

来源

Batch 180926 — 原始版本原样保存在 Rheinmir/uiux-asset/scroll-effects/(参见上方“原始版本”一节);assets/ 是手写的精简 vanilla 版本。

评论

支持 Markdown