Skip to content

About

零依赖 Canvas2D 动效:同心摆动环(Vanta Trunk 的原生复刻,带可调参演示页)

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

Repository files navigation

Trunk — 同心摆动环

零依赖的 Canvas2D 动效:同心环在噪声场里缓慢摆动,像年轮 / 指纹。

复刻自 Vanta 的 TRUNK 效果(原效果作者 Kjetil Midtgarden Golid)。 Vanta 的 vanta.trunk.min.js 本身只有 10KB,但它要求你先引入 800KB 的 p5.js——而 p5 在这里只用到 noise() 和 random() 两个函数。这个仓库把用到的那部分移植了过来,加起来 12KB,单文件,无任何依赖。

预览

在线调参

index.html 打开就是一个可调参的演示页:拖动滑块即时生效,地址栏同步更新 —— 把链接发给别人,看到的就是同一张图。

# 直接双击 index.html 也行(无依赖、无构建、可离线)
open index.html

参数全部走 URL,方便分享和固化:

?color=458498&chaos=5&spacing=0&rings=55&speed=0.3&seed=7
参数 默认 说明
color 458498 环的颜色(六位十六进制,不带 #)
chaos 5 摆动幅度。Vanta 原版默认是 1,越大越乱
spacing 0 环间距额外增量,>0 时环与环之间会拉得更开
rings 55 环数。原版桌面用 55、移动端用 35;嫌卡就调小
speed 0.3 动画速度倍率
seed 7 随机种子。原版每次刷新都不一样的图案,给个固定值就能复现

用到自己的项目里

1. 原生(任何页面)

复制 index.html 里 <script> 中画布部分的代码即可,没有任何依赖。核心就是每帧:

for (let i = 0; i < rings; i++) {
  const dim  = 0.12 * i + 0.2;                     // 噪声取样维度随环递增
  const base = 4 * i + 50 + (i * spacing || 0);    // 基础半径
  ctx.beginPath();
  for (let a = 0; a < 360; a++) {
    const ca = cosA[a], sa = sinA[a];              // 预算好的 cos/sin 表
    const r = chaos * 20 * noise(ox + ca * dim, oy + sa * dim, oz + dim) + base;
    a ? ctx.lineTo(r * ca, r * sa) : ctx.moveTo(r * ca, r * sa);
  }
  ctx.closePath();
  ctx.stroke();
}
// oy -= 0.02 * speed;  oz += 0.00005 * speed;   ← 每帧推进

2. React / Next.js

TrunkField.tsx 是现成组件("use client",fixed 全屏 canvas,自带 resize 与卸载清理),顶部几个常量就是上面那张参数表:

import TrunkField from "./TrunkField";

<div style={{ position: "relative", height: "100vh" }}>
  <TrunkField zIndex={0} />
</div>

性能

每帧要算 rings × 360 = 19800 次 noise(每次 4 个八度)。实测在一台 2015 款 Intel MacBook Pro 上约占单核 20–30ms/帧。

  • 想更省:把 rings 降到 35(原版移动端的取值),直接省 36%
  • 想更省且不介意边缘略糊:canvas 按 CSS 像素渲染、不乘 devicePixelRatio

已知取舍

  • 速度是帧驱动的,照抄原版:每帧固定推进 oy -= 0.02。所以同一个 speed 在 120Hz 屏上会比 60Hz 快一倍。要跨机器一致,得改成按时间推进(oy -= 0.02 * speed * elapsed / (1000/60))。
  • 画到第 360 个点就 closePath(),最后一段是直连的弦——和原版(p5 的 endShape(CLOSE))行为一致,角度只差 1°,看不出来。

与原版的一致性

noise() / random() 是从 p5.js 1.1.9 逐行移植的,做了对拍验证:

  • 同一颗种子下,400 个采样点的噪声值 最大差 0.000e+0(逐位一致)
  • 把两边随机种子钉死后同帧比较:实心像素 100% 颜色一致,笔画位置对齐;残差只出现在 1px 细线的抗锯齿边缘

Credits & License

这个仓库是复刻,不是原创效果的诞生地:

  • 原效果:Kjetil Midtgarden Golid (@kgolid) — p5ycho/trunk
  • 本仓库复刻的是 Vanta 收录的 TRUNK 版本 — MIT, © 2020 Teng Bao
  • noise() / random() 移植自 p5.js 1.1.9(LGPL-2.1)——只移植了这两个函数用到的部分

本仓库代码以 MIT 发布,见 LICENSE。

About

零依赖 Canvas2D 动效:同心摆动环(Vanta Trunk 的原生复刻,带可调参演示页)

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages