粒子时钟:秒针一抖就散成星尘,看时间也上头

举报
deli007 发表于 2026/09/23 12:00:01 2026/09/23
【摘要】 粒子时钟:秒针一抖就散成星尘,看时间也上头

这个时钟把“看时间”变成一场微型演出:数字不是印刷体,而是由一千多颗发光粒子飞过去拼成的 5×7 点阵。每到整秒,所有粒子会先散开成星尘,再一边抖动一边重新聚成下一个时间;粒子颜色、数量和拖尾都能调,还可以切 12/24 小时制。下面先看成品,再讲这个单文件应用是怎么用码道 WebUI 生成并部署出来的。

粒子时钟 运行效果

为什么值得看

它把数字当成 5×7 的点阵,用粒子当“像素”:每位数字的黑色格子就是一个目标点,粒子朝最近的目标点做弹簧式归位。整秒变化时,旧的数字布局目标被替换成新布局,同时给每颗粒子一个向外散射的速度,就有了“散开再聚拢”的节奏:

  • 点阵字形:0 到 9 和冒号都写在 FONT 里,每行 5/6 位二进制字符串。
  • 弹簧物理:目标点吸引力 k = 0.021、阻尼 damp = 0.9,再加正弦抖动,粒子不会死板。
  • 整秒重聚:只要时间标签变化就 respawn(true),先 scatter 再飞向新目标。
  • 1200 粒子可调:滑块直接改变目标数量,拖动时实时增减。
  • 6 套主题:霓虹绿、冰晶蓝、星云紫、熔岩橙、月光金,再加一套旋转色相幻彩。

任务描述

在码道 WebUI 输入框粘贴以下需求,回车发送:

我仍只说明最终效果。它这轮的动作是:

- 新建项目目录并写入单文件 `index.html`,随后补齐字形布局、粒子弹簧和主题切换逻辑。
- 提取内嵌 JavaScript 跑 `node --check` 语法检查,确认没有语法错误。
- 探测空闲端口(这轮是 3000),用 `python3 -m http.server` 起服务,`curl` 自检 HTTP 200 后给出内部预览地址。
- 最后把功能清单、文件位置和访问地址一起写回对话,预览地址就在对话末尾。

码道实际做了什么

开发一个“粒子时钟”网页应用:深色夜空背景,用大量发光粒子实时拼出当前时间,每秒钟数字散去再重新聚合;粒子颜色、数量和拖尾效果可调节;支持 24 小时制和 12 小时制的 AM/PM 显示;提供多套配色主题;界面简洁美观,单个 index.html 即开即玩。完成后自动部署成可访问的网页应用,并把访问地址写出来。

1. 数字不是画出来的,是 5×7 点阵

FONT 里每个数字是 7 行字符串,字符为 1 的位置记成目标点;buildLayout() 遍历当前时间字符串,把每位的点阵坐标摊到整块画布上:

const FONT = {
  "0": ["01110", "10001", "10011", "10101", "11001", "10001", "01110"],
  "1": ["00100", "01100", "00100", "00100", "00100", "00100", "01110"],
  ":": ["00", "10", "10", "00", "10", "10", "00"]
};

function buildLayout() {
  cell = Math.min(W * 0.88 / 42, H * 0.52 / 7);
  gridWidth = calcWidth();
  gridTop = (H - 7 * cell) / 2;
  // 遍历 timeStr,把每个 '1' 的网格坐标压入 pts
}

每个目标点再叠加每颗粒子自己随机的 jx / jy,这样聚拢后不是死死的正方形,而是有颗粒感的数字。

2. 粒子靠弹簧逼近,不写缓动函数

draw() 里每帧只朝目标点拉一下,再乘阻尼、叠加两个相位不同的正弦扰动。效果天然带一点呼吸感:

const k = 0.021, damp = 0.9;
for (const p of particles) {
  if (themeIdx === RAINBOW) {
    p.hue = (p.hue + 0.45) % 360;
    p.rgb = hsvToRgb(p.hue, 0.92, 0.98);
  }
  p.vx += (p.tx - p.x) * k;
  p.vy += (p.ty - p.y) * k;
  p.vx *= damp;
  p.vy *= damp;
  p.x += p.vx;
  p.y += p.vy;
  p.x += Math.sin(time * 0.0011 + p.seed * 7.3) * 0.14;
  p.y += Math.cos(time * 0.0009 + p.seed * 5.1) * 0.14;
}

3. 整秒“散星尘”来自一次散射

主循环只在时间字符串变化时触发替换,避免每秒都重建数组:

function frame(time) {
  t = time;
  const label = getTimeLabel();
  if (label !== lastLabel) {
    lastLabel = label;
    respawn(true);
  }
  draw(time);
  requestAnimationFrame(frame);
}

respawn(true) 会重新计算目标点,并调 scatter(forceByCount()) 给每颗粒子一个随机方向的初速度,于是整秒数字先是炸开,再被弹簧拉回。

验证与踩坑

生成结束后打开对话里的内部预览地址,页面标题是「Particle Clock · 粒子时钟」,数字确实由粒子拼成。

  • 截取两个不同秒数的画面,两个文件内容不同:目标点阵已经变化,粒子位置也处于不同状态。
  • 踩坑:粒子数量拉到 1200 时,每颗要画两圈光晕外加亮点,低端设备会有压力;右下角个数调到 400 以下会明显顺畅。
  • 从代码看,k = 0.021 决定“追目标”的快慢,越大越快贴上去但越像坚硬机械;damp = 0.9 尽量别改,否则秒针散开后很难收敛回字形。

本地复现

项目是单文件 index.html,没有第三方依赖。把文件保存到本地后用浏览器直接打开就能玩;如果希望通过本地 HTTP 服务访问:

cd codearts-particle-clock
python3 -m http.server 8080
# 然后打开 http://127.0.0.1:8080

直接下载试玩

源码同步到公开 Demo Park 仓库:

准备环境:进入 AI 开发者空间

本文用码道 WebUI 版演示。先进入 AI 开发者空间并选择体验版,不需要本地安装:

  1. 浏览器打开 https://devstation.developer.huaweicloud.com/aidevspace?utm_source=opcsfsq&utm_medium=wbwz
  2. 弹窗「请选择要进入的版本」→ 点击 体验版
  3. 首次使用跳到华为云登录页,登录一次后浏览器会话可复用
  4. 弹窗「临时凭证自动配置」→ 点击 同意,沙箱自动创建

进入主界面后,等左侧菜单加载出来,找到 CodeArts,点它右侧的浏览器图标,就打开了码道 WebUI 对话窗口。

AI 开发者空间主界面

开通后有三种使用方式:WebUI(浏览器对话)、TUI(终端命令行)和桌面 IDE(IDE 插件)。本文用 WebUI 版演示。

进入 CodeArts:https://developer.huaweicloud.com/codeartsco.html?source=dmzntgwsf&sourcead=dmzntgwwbwz

码道 WebUI 生成完成

使用码道体会

最实用的还是「点阵 + 弹簧」这套思路。以前想画数字会想到 Canvas 字体,但字体不好控制发光感;点阵把显示层和粒子运动彻底分开,改个字符串就能换图案。它甚至把冒号也当成字形处理,AM/PM 则用普通 fillText 单独画在旁边,没有强行塞进粒子系统。这种“该用文本时用文本,该用粒子时用粒子”的分寸,读代码时很舒服。

总结

粒子时钟把时间显示拆成三件事:字形点阵给出目标,弹簧物理让粒子动起来,整秒变更触发一次散射。后面可以继续加「倒计时」「自定义点阵文字」「保存 GIF」或「点击屏幕召唤一波粒子」,核心循环都不用大改。

粒子时钟 运行效果对照

连续截取的两个运行画面,左右分别是不同秒数、粒子处于不同聚散状态的对比:

粒子时钟 连续运行画面

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。