Ferrofluid Microphone
对着麦克风吹口哨,黑色磁流体会颤动、长刺、塌落;声音输入被翻译成了触感十足的形变。
它是什么:对着麦克风说话或唱歌,屏幕上的黑色磁流体就会长出尖刺;安静下来,它又塌回一滩。
好在哪:声音 → 形状的因果关系一眼就懂,而且材质像真的磁流体,黑亮、带反光。
怎么做到的:
- 液体由很多小粒子组成,每帧计算它们之间的推拉,形成流动感。
- 麦克风的音高和音量被实时分析,数值越大,“磁场”越强、尖刺越高。
- 鼠标/手指也能当作磁铁去拨它。
完整技术拆解
今日拆解 · Ferrofluid Microphone
- Live: https://robert.leitl.dev/artifacts/ferrofluid
- Gallery: https://mesh3d.gallery/experiment/ferrofluid-microphone
- Author: Robert Leitl
- Bundle:
/artifacts/ferrofluid/index-8a2ccd9a.js(约 267 KB)
为何选它
在 8 条里它把「麦克风音高 → 黑色磁流体长刺 / 塌落」做成可感知的因果链:既有完整的 GPU 流体模拟,又有 Web Audio 分析,视觉材质也够炫。Splish Splash 主要是流体玩具;Beat Machine 偏 UI/节奏反馈;bleibtgleich / Rows 更偏排版与微交互。Ferrofluid 的技术深度与「一眼就懂」的效果同时成立。
实际在源码里找到的技术栈
/* @license twgl.js 5.2.0 ... http://github.com/greggman/twgl.js */#version 300 es 开头;扩展枚举含 webgl2const Ls=new e("3.1.0") 且导出 Pane / BladeApi;仅在 URL 带 ?debug 时挂载new AudioContext、getUserMedia({audio:...})、createAnalyser()、fftSize = 2048ge(window,"resize").pipe(...) 的操作符形态;未在 bundle 内找到明确的 rxjs@x.y.z 字符串粒子数默认:NUM_PARTICLES = 500。平面高度图分辨率:planeResolution = 256。
核心效果怎么工作(源码 + 标明推测)
1. SPH 粒子模拟(确认)
GPU 上做经典 SPH(Smoothed Particle Hydrodynamics):
- 状态存在纹理:
u_positionTexture、u_velocityTexture、u_forceTexture、u_densityPressureTexture - 邻域用网格哈希:
u_indicesTexture/u_offsetTexture+CELL_TEX_SIZE/CELL_SIZE(有 bitonic 风格的多 pass 排序) - 核函数常量在 UBO
u_SimulationParams里:POLY6 / SPIKY_GRAD / VISC_LAP / REST_DENS / GAS_CONST / VISC / MASS / H / HSQ —— 这是 Müller 式 SPH 的标准组合
Pass 大致顺序(确认):
- 按位置写入 cell index
- 排序 indices
- 建 offset 表
- density + pressure(
poly6Weight) - 力(压力梯度 + 粘度
VISC_LAP) - integrate:
ai = fi / rho; vi += ai * dt,再叠加 pointer 力与边界阻尼
2. 麦克风 → 形变(确认)
mic → MediaStreamSource → AnalyserNode (fftSize=2048, minDecibels=-90)
→ getByteFrequencyData
→ 取能量最大的 frequency bin
→ freq = index * (sampleRate/2 / bufferLength)
→ 在 [MIN_FREQ=400, MAX_FREQ=2400] 上做 log2 归一化,再映射到 [-1, 1]
→ 经弹簧阻尼(targetZoomLerp / zoomOffsetMomentum)驱动 this.ZOOM
→ ZOOM 写入 shader uniform:u_zoom、u_spikeFactor
集成 shader 里有明确的 zoom 力:
pi.xy += zoomForce * 0.008 * max(0., (1. - u_zoom * 2.5));
高度/网格绘制 shader 里用 u_zoom 控制边缘与 spike 位移(u_spikeFactor)。
推测:尖刺观感主要来自「粒子被径向/向上推开 + 高度网格按密度/位移抬起 + 高光黑材质」,而不是单独的铁磁学方程;铁流体是视觉隐喻。
3. 指针交互(确认)
UBO u_PointerParams:pointerPos / pointerVelocity / pointerRadius / pointerStrength。在 integrate 中若粒子距指针 < radius,则叠加 pointerVelocity * pointerStrength * (1 - pr/radius)。另有一处 idle 微扰力。
4. 伪代码(忠实于源码结构)
each frame:
audio = peakFreqNorm() # [-1,1] or 0 if silent
ZOOM = spring(ZOOM, audio) # zoomOffsetMomentum damping
# GPGPU SPH
hash particles into cells
sort + build neighbor offsets
density, pressure = SPH_poly6(neighbors)
force = SPIKY_grad(pressure) + VISC_lap(velocity)
integrate(pos, vel, force, pointerForce, zoomForce(ZOOM))
# render
draw points / height mesh with spikeFactor(ZOOM), dark glossy shading
如果我来重做(步骤清单)
- Vite + Canvas,申请
webgl2,引入 twgl.js 管 framebuffer / program。 - 实现 500 粒子的 RGBA32F 状态纹理 + ping-pong FBO。
- 写 SPH:density → force → integrate(先 2D),网格哈希邻域。
getUserMedia+AnalyserNode,把峰值频率映射到一个zoomuniform。- 用粒子生成 height map 或直接画 metaball/points,加高光黑色材质。
- 可选:Tweakpane 调 REST_DENS / VISC / POINTER_STRENGTH。
- 最后再加 entry 动画与麦克风按钮 UX。
证据文件
artifact.html、index-8a2ccd9a.js、index-295bf82f.css(本目录)
零基础也能看懂。先认识这件作品用到的技术,再学一个知识点。
1技术栈小白版
只列拆解里在源码中确认过的技术。点开看它在这件作品里做了什么。
WebGL2 / GLSL
在这件作品里粒子模拟和黑色磁流体的绘制,全都在 GPU 上跑。
怎么认出来画面能实时回应你的声音和手指,而且非常流畅。
twgl.js 5.2.0
在这件作品里帮作者管理着色器程序和「画布」——模拟每一步的结果都存在图片一样的数据里,来回倒着用。
怎么认出来看不出来,它是幕后工具。(它和 09-28 的 Liquid Geo 出自同一位作者,用的也是同一个库。)
Web Audio + 麦克风
在这件作品里实时听麦克风,找出此刻最响的那个音高(在 400 到 2400 赫兹之间),换算成一个数字去推磁流体。
怎么认出来网页会请求麦克风权限;你一出声,画面就变。
GPU 上的 SPH 流体模拟
在这件作品里默认 500 个粒子,每一帧依次算:谁和谁挨着 → 挤得多密 → 受多大的力 → 往哪儿移动。
怎么认出来东西会流动、会聚成一团、有粘稠感。
Tweakpane 3.1.0(调试面板)
在这件作品里只有在网址后面加上 ?debug 时才会出现,用来调粒子的粘度、密度等参数;普通访客看不到。
怎么认出来页面角落出现一个满是滑杆的小面板(一般只在调试时)。
2今日知识点
交互是什么:输入 → 处理 → 反馈
看一幅画,是你单方面地「看」它;玩一件交互作品,是你和它在「对话」:你做一件事(输入),它想一想(处理),然后回应你(反馈)。你再根据它的回应做下一件事——这就是交互回路。
Ferrofluid Microphone 把这个回路做得特别清楚:
- 输入:你对着麦克风发声,或者用手指去拨;
- 处理:程序找出你声音里最响的音高,换成一个 -1 到 1 之间的数字,再像弹簧一样让它平滑地变化;
- 反馈:黑色的磁流体长出尖刺,或者塌回一滩。
为什么它让人忍不住一直玩?因为它的反馈快(几乎没有延迟)、清楚(声音和形状直接对应)、还带点惊喜(每次形状都不太一样)。好的交互,几乎都满足这三点。
一句话记住:交互 = 输入 → 处理 → 反馈,然后循环。 反馈越快、越清楚,人就越觉得「是我在控制它」。
它从哪里来
认知科学家、设计师唐·诺曼(Don Norman)在 1988 年出版的《设计心理学》(The Design of Everyday Things)里强调:好的设计要让人清楚地看到自己的操作带来了什么结果——这就是「反馈」。这本书至今仍是交互设计的入门必读。
游戏设计师把这件事推到了极致。2008 年,Steve Swink 写了《Game Feel》,专门讨论实时操控带来的「手感」;2012 年,Martin Jonasson 和 Petri Purho 在一场叫「Juice it or lose it」的演讲里演示:同一个小游戏,只是加上抖动、粒子和音效这些反馈,就变得好玩得多。
经典参考
- 唐·诺曼《设计心理学 1:日常的设计》英文名 The Design of Everyday Things。讲门、开关、水龙头为什么有的好用、有的难用。
- 「Juice it or lose it」(2012 演讲)Martin Jonasson 与 Petri Purho 的演讲,网上能搜到视频,15 分钟看懂「反馈让东西变好玩」。
- Steve Swink《Game Feel》(2008)专门讲游戏「手感」的书,适合以后进阶。
- 打开 Ferrofluid Microphone,先不出声看 10 秒;然后轻轻「嗯——」一声,再大声一点,再分别试试高音和低音。每次都留意磁流体怎么回应。
- 画三个格子:输入 / 处理 / 反馈,把你看到的填进去(「处理」那格可以写「它好像在听我的音高」)。
- 在生活里找一个「反馈很差」的东西,比如按了没反应的电梯按钮、不知道发没发出去的表单。想一想:给它加一个什么反馈就好了?
小词典
- 交互(interaction)
- 人和作品之间你来我往的「对话」。
- 输入(input)
- 你对作品做的事:点、拖、说话、晃手机。
- 反馈(feedback)
- 作品对你的回应:动画、声音、震动、文字提示。
- 延迟(latency)
- 从你操作到看到反馈之间的时间。越短越好。
- 交互回路(loop)
- 输入 → 处理 → 反馈,然后你再输入,不断循环。
3知识地图进度
设计雷达 · 每天 8 个值得看的网站、App UI 和网页小游戏