tsParticles Canvas Mask 插件深度指南:基于 CHANGELOG 的功能演进、配置解析与像素级实现原理
【免费下载链接】tsparticlestsParticles - Easily create highly customizable JavaScript particles effects, confetti explosions and fireworks animations and use them as animated backgrounds for your website. Ready to use components available for React.js, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Inferno, Solid, Riot and Web Components.项目地址: https://gitcode.com/GitHub_Trending/ts/tsparticles
tsParticles 的 Canvas Mask(画布遮罩)插件能够将图片、文本乃至外部 canvas 元素的像素信息转化为粒子群,让粒子特效"绘制"出任意图形或文字。本文以插件 CHANGELOG.md 记录的功能演进为主线,结合插件源码与配置文件,完整讲解该插件的安装加载方式、全部配置项、文本/图片/画布三种遮罩输入源,以及从像素到粒子的底层实现原理,帮助你快速上手并在自己的页面中复现 Logo 粒子、文字粒子等视觉效果。
一、插件定位与功能演进概览
Canvas Mask 是 tsParticles 官方维护的插件,包名为@tsparticles/plugin-canvas-mask(v2 时代为tsparticles-plugin-canvas-mask)。从 CHANGELOG 可以梳理出这条清晰的功能演进线:
- 2.3.0(2022-09-11):插件首个版本,一次性落地了四个核心能力——支持文本与通用 canvas 输入、字体(font)选项、位置(position)选项、以及使用外部创建的 canvas 元素(element 选项),对应提交 [0770c13] 与 [c576656] 等。
- 2.4.0(2022-10-30):为文本遮罩加入多行文本支持,并修复了多行文本下遮罩尺寸输出错误的问题(对应提交 [eceacbe]、[9b00acc])。
- 2.7.0(2022-12-23):粒子添加顺序改为基于
getRandom的随机打乱(shuffle),让遮罩粒子呈现更自然的分布(提交 [0161280])。 - 2.10.0(2023-06-03):大版本聚合更新,包含标准化错误前缀、为引擎加入版本号、移除所有 canvas context 的 save/restore 调用(性能优化)、新增 motion 插件配合、新增 SVG 路径 path 插件等(提交 [208722f] 等)。
- 3.x 系列(2023-2025):进入动态导入与加载机制优化阶段——3.2.0 起插件"仅在使用时加载"(dynamic imports),3.4.0 改变 bundle 加载方式,不再预加载插件;3.7.0 引入命名颜色插件与引擎 hex 颜色;3.8.1 修复全屏模式下 z-index 样式问题。
- 4.0.0-alpha.27(2026-03-09):一个重要的 API 变更——用
particles.fill取代particles.color,使粒子填充与描边(particles.stroke)拥有几乎一致的选项结构(提交 [d1793cc])。这意味着在 v4 配置中,粒子颜色相关的遮罩覆盖配置需要写在paint.fill之下(见下文实现原理)。 - 4.0.2(2026-05-16):修复 peer dependencies 问题;4.2.0(2026-06-17):修复 eslint 配置与循环依赖。
当前仓库中该插件的最新版本为4.3.3(2026-07-23)(见 package.json),主版本号 4.x 对应 tsParticles 引擎 v4 系列。
二、安装与加载:三步接入指南
插件的使用遵循"先加载插件、再加载实例"的固定顺序,这一点在 README.md 的 Quick checklist 中被明确强调:
- 安装
@tsparticles/engine(或直接引入 CDN bundle); - 在调用
tsParticles.load(...)之前先调用插件的加载函数; - 在
tsParticles.load(...)的配置中启用canvasMask选项。
2.1 CDN / Vanilla JS 方式
引入tsparticles.plugin.canvas-mask.min.js后,全局会暴露loadCanvasMaskPlugin函数,用法如下:
(async () => { await loadCanvasMaskPlugin(tsParticles); await tsParticles.load({ id: "tsparticles", options: {/* options */}, }); })();2.2 ESM / CommonJS 方式
$ npm install @tsparticles/plugin-canvas-mask # 或 $ yarn add @tsparticles/plugin-canvas-maskimport { tsParticles } from "@tsparticles/engine"; import { loadCanvasMaskPlugin } from "@tsparticles/plugin-canvas-mask"; (async () => { await loadCanvasMaskPlugin(tsParticles); })();CommonJS 用户使用require同样可以:
const { tsParticles } = require("@tsparticles/engine"); const { loadCanvasMaskPlugin } = require("@tsparticles/plugin-canvas-mask"); (async () => { await loadCanvasMaskPlugin(tsParticles); })();从 package.json 可以看出该包通过exports字段同时提供了 ESM、CJS、浏览器与类型声明四种入口,并额外暴露了./lazy子路径(对应 index.lazy.ts),支持按需懒加载。插件对@tsparticles/engine声明了 peer dependency,因此引擎与插件版本需要配套使用——这正是 CHANGELOG 4.0.2 "fixed peer dependencies" 修复的核心背景。
2.3 加载的底层机制
loadCanvasMaskPlugin注册的是一个实现IPlugin接口的类,见 CanvasMaskPlugin.ts:
export class CanvasMaskPlugin implements IPlugin { readonly id = "canvas-mask"; async getPlugin(container: Container): Promise<IContainerPlugin> { const { CanvasMaskPluginInstance } = await import("./CanvasMaskPluginInstance.js"); return new CanvasMaskPluginInstance(container); } needsPlugin(options?: RecursivePartial<ICanvasMaskOptions>): boolean { return options?.canvasMask?.enable ?? false; } }三个关键点与 CHANGELOG 中的修复项一一对应:
- 按需创建实例:
getPlugin使用动态import加载CanvasMaskPluginInstance,这正是 3.2.0 "plugins will be loaded only if used"(仅在使用时加载)的落地方式; - 启用开关:
needsPlugin只检查options.canvasMask.enable,只有配置了canvasMask.enable: true时插件才会真正生效; - 懒加载能力:
import()的动态引入方式配合sideEffects: false(见 package.json),让打包工具可以安全地对插件进行 tree-shaking。
三、三种遮罩输入源:图片、文本与外部 canvas
Canvas Mask 的核心能力是"读取像素、生成粒子"。插件支持三种输入源,这一能力源自 2.3.0 的 "added support to text and generic canvas input" 与 "added element options ... for using an external created canvas",并在 CanvasMaskPluginInstance.ts 的init()方法中按优先级分支处理:
async init(): Promise<void> { const container = this.#container, options = container.actualOptions.canvasMask; if (!options?.enable) { return; } let pixelData: CanvasPixelData = { pixels: [], height: 0, width: 0 }; const offset = options.pixels.offset; if (options.image) { const url = options.image.src; if (!url) return; pixelData = await getImageData(url, offset, container.canvas.render.settings); } else if (options.text) { const data = getTextData(textOptions, offset, textOptions.fill, container.canvas.render.settings); if (isNull(data)) return; pixelData = data; } else if (options.element ?? options.selector) { const canvas = options.element ?? (options.selector && safeDocument().querySelector<HTMLCanvasElement>(options.selector)); if (!canvas) return; const context = canvas.getContext("2d", container.canvas.render.settings); if (!context) return; pixelData = getCanvasImageData(context, canvas, offset); } addParticlesFromCanvasPixels(container, pixelData, options.position, options.scale, options.override, options.pixels.filter); }三种输入源的优先级为:图片 > 文本 > 外部 canvas 元素/选择器,配置了多个时只会采用最先匹配的那个。
3.1 图片遮罩(image)
通过image.src指定图片地址(支持任意可通过Image加载的 URL,包括 data URI 与跨域资源——后者需要服务端配合 CORS)。像素提取由@tsparticles/canvas-utils中的getImageData完成,其核心思想是将图片绘制到离屏 canvas 上,再按pixels.offset的采样步长读取RGBA像素数据。
const options = { canvasMask: { enable: true, image: { src: "/images/your-logo.png", // 任意可加载的图片地址 }, pixels: { offset: 4 }, // 采样步长,越大粒子越稀疏 scale: 1, position: { x: 50, y: 50 }, }, };3.2 文本遮罩(text)
文本遮罩是插件最常用的场景(制作文字粒子标语)。2.3.0 加入字体选项、2.4.0 加入多行文本支持,最终形成了text下的三层结构:
const options = { canvasMask: { enable: true, text: { text: "Hello\nWorld", // 支持 \n 换行(2.4.0 多行文本) color: "#000000", // 遮罩采样颜色,默认黑色 fill: true, // true=填充模式,false=描边模式 font: { // 2.3.0 加入的字体选项 family: "sans-serif", // 字体族,默认 sans-serif size: 100, // 字号,默认 100 style: "", // 如 italic variant: "", // 如 small-caps weight: "", // 如 bold }, lines: {}, // 多行文本的行间距等控制 }, }, };对应源码 TextMask.ts 中默认值为color = "#000000"、fill = true、text = "";FontTextMask.ts 中family = "sans-serif"、size = 100,其余四项默认空字符串。多行文本由 TextMaskLine.ts 类承载,getTextData在渲染文本时会根据行配置测量每一行的宽高,因此 2.4.0 专门修复了"多行文本下遮罩尺寸输出"的问题(提交 [9b00acc])。
提示:
fill: true会按文字填充区域采样(适合大字标语);fill: false则只采样文字笔画轮廓,可做出"空心粒子字"效果。
3.3 外部 canvas 元素/选择器(element / selector)
这是 2.3.0 "element options ... for using an external created canvas" 与 2.10.0 "generic canvas input" 所扩展的能力:直接把页面中已有的<canvas>元素作为粒子来源,适合把任意绘制结果(图表、签名、绘画作品)转化为粒子。
// 方式一:直接传入 canvas 元素(仅限运行时 JS 配置) const myCanvas = document.querySelector("#my-canvas"); const options = { canvasMask: { enable: true, element: myCanvas, // HTMLCanvasElement 实例 position: { x: 50, y: 50 }, }, }; // 方式二:通过 CSS 选择器(适用于 JSON 配置) const options = { canvasMask: { enable: true, selector: "#my-canvas", }, };注意 CanvasMask.ts 的load()方法对element做了严格校验:只有data.element instanceof HTMLCanvasElement才会被接受,因此element选项无法通过纯 JSON 配置传递(JSON 中无法承载 DOM 对象),JSON 配置请使用selector。这一"选择器 vs 元素"的双通道设计在init()中合并处理:options.element ?? (options.selector && safeDocument().querySelector(options.selector))。
四、核心配置项全解析
顶层canvasMask配置对象由 CanvasMask.ts 定义,除三种输入源外还包含以下关键项:
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enable | boolean | false | 总开关,needsPlugin仅凭此项决定插件是否加载 |
position | { x, y } | { x: 50, y: 50 } | 遮罩在画布中的位置,百分比值(2.3.0 加入,提交 [8759b84]) |
scale | number | 1 | 遮罩缩放系数,放大可让粒子间距成倍拉开 |
override | object | 见下 | 是否用像素颜色/透明度覆盖粒子外观 |
pixels | object | 见下 | 像素采样与过滤控制 |
element/selector | - | 无 | 外部 canvas 输入源(见 3.3) |
4.1 position:百分比定位
position的取值是 0~100 的百分比(见 utils.ts 中percentDenominator参与计算),x: 50, y: 50表示遮罩居中。换算公式为:
const positionOffset = { x: (canvasSize.width * position.x) / percentDenominator - width * scale * half, y: (canvasSize.height * position.y) / percentDenominator - height * scale * half, };即"画布宽高 × 百分比"减去"遮罩实际尺寸的一半",从而让遮罩以百分比点为中心对齐。
4.2 override:用像素信息覆盖粒子外观
CanvasMaskOverride.ts 提供两个开关:
| 配置项 | 默认值 | 说明 |
|---|---|---|
override.color | true | 用像素 RGBA 颜色作为粒子填充色 |
override.opacity | false | 用像素 alpha 覆盖粒子透明度 |
在 v4 中,颜色覆盖写入了paint.fill(对应 4.0.0-alpha.27 的particles.fill取代particles.color变更),见 utils.ts:
if (override.color) { pOptions.paint = { fill: { color: { value: pixel }, enable: true, }, }; } if (override.opacity) { pOptions["opacity"] = { value: pixel.a }; }默认开启颜色覆盖后,粒子会直接继承原图的颜色,实现"像素级还原";若关闭override.color,粒子则使用粒子配置中的统一颜色。
4.3 pixels:采样步长与像素过滤
CanvasMaskPixels.ts 控制"取哪些像素、取多密":
| 配置项 | 默认值 | 说明 |
|---|---|---|
offset | 4 | 采样步长。每 offset 个像素取一个点,值越大粒子越稀疏 |
filter | 函数 | 像素过滤器,默认pixel => pixel.a > 0(只保留非透明像素) |
filter支持两种形式:直接传(pixel) => boolean函数,或传一个已挂载在globalThis上的函数名字符串(插件会从全局对象中查找并校验是否为函数)。你可以利用它实现"只保留指定颜色区域的粒子"等高级玩法。
五、底层原理:从像素矩阵到粒子群
addParticlesFromCanvasPixels(utils.ts)是整条流水线的终点,其算法可以用以下伪代码概括:
1. 读取像素矩阵 data(width × height 的 RGBA 二维数组) 2. 生成 [0, width*height) 的索引数组并做 Fisher-Yates 洗牌 3. 确定可创建的最大粒子数 = min(像素总数, particles.number.value) 4. 循环弹出打乱后的索引: - 将索引还原为 (x, y) 像素坐标 - 用 filter(pixel) 判断该像素是否满足条件 - 满足则按 position/scale 换算屏幕坐标,addParticle 生成粒子几个与 CHANGELOG 呼应的实现细节:
- 随机打乱(2.7.0):
shuffle()使用引擎的getRandom()而非Math.random(),保持随机数来源统一,便于调试与复现; - 粒子数量上限:
maxParticles = Math.min(numPixels, container.actualOptions.particles.number.value)——实际粒子数同时受像素总数与particles.number配置约束,遮罩越复杂(offset 越小)粒子越多; - 性能优化(2.10.0):插件在 v2.10.0 移除了所有 canvas context 的
save/restore调用(提交 [208722f]),减少不必要的上下文状态保存开销;3.3.0 又针对 Chrome 修复了异步requestAnimationFrame相关问题,减少 vite 构建下的异步方法(提交 [2600f6f])。
六、常见陷阱与排查建议
结合 README.md 的 Common pitfalls 与 CHANGELOG 的修复记录,使用中最容易踩的坑如下:
- 加载顺序错误:在
loadCanvasMaskPlugin(tsParticles)之前调用tsParticles.load(...),插件不会生效且不报错。加载函数返回 Promise,务必await后再加载实例。 enable未开启:needsPlugin只认canvasMask.enable,忘记开启会导致插件实例不创建、配置被静默忽略。- JSON 配置误用
element:element只接受HTMLCanvasElement实例(CanvasMask.ts 中有instanceof校验),JSON/静态配置必须改用selector。 - 跨域图片无法采样:
getImageData读取像素受 canvas 同源策略约束,跨域图片需服务端返回Access-Control-Allow-Origin并正确配置crossOrigin。 - 版本配套:4.0.2 修复了 peer dependencies(对应 issue #5763),升级插件时需同步升级
@tsparticles/engine;v3 → v4 迁移时注意particles.color已被particles.fill取代。 - 全屏背景的层级问题:3.8.1 修复了
fullScreen激活时的 z-index 样式问题(issue #5458),若发现粒子被页面元素遮挡,请确认引擎与插件都已升级到包含该修复的版本。
七、结语
从 CHANGELOG.md 可以完整看到 canvas mask 插件三年的演进轨迹:v2 时代奠基了文本/图片/canvas 三种输入源、字体与位置选项、多行文本能力;v3 时代转向动态加载、tree-shaking 与加载机制优化;v4 时代则跟随引擎完成了particles.fill的选项重构与依赖治理。对于开发者而言,理解这段演进史不仅有助于正确配置插件,更能帮助你在升级版本时精准定位行为变化。若想深入自定义(例如编写自己的像素过滤器或修改采样逻辑),可直接阅读 CanvasMaskPluginInstance.ts 与 utils.ts 两处核心源码。
【免费下载链接】tsparticlestsParticles - Easily create highly customizable JavaScript particles effects, confetti explosions and fireworks animations and use them as animated backgrounds for your website. Ready to use components available for React.js, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Inferno, Solid, Riot and Web Components.项目地址: https://gitcode.com/GitHub_Trending/ts/tsparticles
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考