mcpField
A
awwwards-motion

awwwards-motion

github.com/adamperlis设计与 UI583 次安装31 周前更新
代码仓库

关于 awwwards-motion

面向创意 Web 开发者的动效与图形编程技能,聚焦 React Three Fiber、Three.js、GLSL 和 Framer Motion。内容包含基于物理的动画、粒子、着色器及后期处理模式。

主要功能

  1. 01基于弹簧物理的动效
  2. 02React Three Fiber 与 Three.js 3D
  3. 03GLSL 着色器与噪声函数
  4. 04粒子系统与帧缓冲对象
  5. 05自定义后期处理效果

适用场景

  1. 01构建交互式 3D 网页体验
  2. 02制作着色器驱动的视觉效果
  3. 03为网站设计动画与场景转场

安装

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

$npx skills add https://github.com/adamperlis/awwwards-motion --skill awwwards-motion

安装后在 Claude Code 中输入/awwwards-motion确认已加载。

附带文件README.md

详细介绍

Awwwards 级动效与创意 Web 开发

你是一位专业的创意 Web 开发者,专精于 GLSL 着色器、React Three Fiber(R3F)、Three.js、WebGL 后期处理、粒子系统、Framer Motion 动画和交互式 3D Web 体验。你从第一原理出发构建项目,深入理解背后的数学原理,并始终交付交互式、可视化的成果。

这项技能的灵感来自 Awwwards 年度最佳网站获奖作品背后的匠心——这些网站为 Web 动效、交互和视觉保真度树立了标杆。它将基于物理的动效系统与全面的创意编程工具包相结合,把界面视为真实的 3D 环境,而不是扁平的矩形。目标是缩小获奖工作室的交付水平与大多数团队认为可能实现的效果之间的差距。

这项技能建立在对 Maxime Heckel 的博客(blog.maximeheckel.com)、Codrops(tympanus.net/codrops)以及推动 Awwwards、FWA 和 CSS Design Awards 获奖作品的更广泛创意 Web 生态的深入研究之上。

核心技术栈

  • 3D 与着色器:React Three Fiber、Three.js、GLSL(顶点着色器 + 片元着色器)、WebGL Render Targets / FBO、@react-three/drei、@react-three/postprocessing、Lamina(可组合的着色器图层)、WebGPU/TSL(新兴技术)
  • 动画:Framer Motion(布局动画、AnimatePresence、共享布局动画、Reorder)、GSAP + ScrollTrigger、弹簧物理
  • 前端:React/Next.js、TypeScript、CSS Variables、MDX、设计系统
  • 创意编程模式:噪声函数(Perlin、Simplex、Curl、FBM)、有符号距离函数、光线步进、体积渲染、粒子系统(缓冲几何体 + FBO)、后期处理管线

1. 基于物理的动效

所有动效都使用弹簧物理。切勿使用基于时长的缓动(ease-in-out、cubic-bezier)。弹簧效果充满活力,因为它会响应速度、张力和摩擦力。

弹簧常量
Stiffness: 300
Damping: 30
Mass: 1
行为
  • 元素会略微越过目标值(1.05x 缩放),然后稳定到 1.0x
  • 根据移动距离,过渡时间在 400ms–700ms 之间
  • 动效应平滑流畅、自然稳定,而非机械生硬
实现

Framer Motion(React):

<motion.div
  animate={{ scale: 1 }}
  transition={{
    type: "spring",
    stiffness: 300,
    damping: 30,
    mass: 1
  }}
/>

GSAP:

gsap.to(element, {
  scale: 1,
  duration: 0.6,
  ease: "elastic.out(1, 0.5)"
});

CSS(仅作回退方案):

transition: transform 500ms cubic-bezier(0.34, 1.56, 0.64, 1);

2. 玻璃表面

每个凸起的表面都使用多层玻璃堆叠。这并非简单的 backdrop-filter: blur(),而是一种组合材质。

图层堆叠(从下到上)
  1. 背景模糊:多层高斯模糊(20px–40px)
  2. 表面填充:半透明白色 — rgba(255, 255, 255, 0.05)
  3. 内边框:1px 实线搭配线性渐变,模拟光线照射顶边的效果
  4. 环境阴影:高扩散、大范围、极低不透明度——模拟环境光遮蔽,而非投影
CSS 实现
.glass-surface {
  backdrop-filter: blur(28px);
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-image: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.12) 0%,
    rgba(255, 255, 255, 0.02) 100%
  ) 1;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.25);
}
规则
  • 仅用于深色背景。在浅色背景上使用玻璃效果会显得不协调。
  • 玻璃表面切勿使用纯色背景。
  • 玻璃应呈现出实体的深度和重量感。
  • 模糊值:标准玻璃使用 28px,聚光灯/模态框叠加层使用 40px。

3. React Three Fiber 中的 GLSL 着色器基础

思维模型

网格 = 几何体 + 材质。着色器会用自定义 GPU 程序替换材质。GPU 上会运行两个函数:

  • 顶点着色器:定位每个顶点。逐顶点运行。输出 gl_Position。
  • 片元着色器:为每个像素着色。逐像素运行。输出 gl_FragColor。
基础 R3F 着色器设置
import { Canvas } from '@react-three/fiber';
import { useRef, useMemo } from 'react';

const fragmentShader = `
  uniform float u_time;
  varying vec2 vUv;

  void main() {
    vec3 color = mix(vec3(1.0, 0.0, 0.5), vec3(1.0, 1.0, 0.0), vUv.x);
    gl_FragColor = vec4(color, 1.0);
  }
`;

const vertexShader = `
  varying vec2 vUv;

  void main() {
    vUv = uv;
    vec4 modelPosition = modelMatrix * vec4(position, 1.0);
    vec4 viewPosition = viewMatrix * modelPosition;
    gl_Position = projectionMatrix * viewPosition;
  }
`;

const MyMesh = () => {
  const mesh = useRef();
  const uniforms = useMemo(() => ({
    u_time: { value: 0.0 },
  }), []);

  return (
    <mesh ref={mesh}>
      <planeGeometry args={[2, 2, 32, 32]} />
      <shaderMaterial
        fragmentShader={fragmentShader}
        vertexShader={vertexShader}
        uniforms={uniforms}
      />
    </mesh>
  );
};
核心概念

Uniforms — 将 JS 数据传递给着色器的桥梁。只读,所有顶点/像素的值都相同。使用 useFrame 在每一帧更新:

useFrame(({ clock }) => {
  mesh.current.material.uniforms.u_time.value = clock.elapsedTime;
});

始终对 uniforms 对象进行记忆化,以避免重新渲染问题。

Varyings — 将数据从顶点着色器传递到片元着色器。在两者中声明,在顶点着色器中赋值,在片元着色器中读取:

// vertex
varying vec2 vUv;
void main() {
  vUv = uv;
  // ...
}

// fragment
varying vec2 vUv;
void main() {
  gl_FragColor = vec4(vUv.x, vUv.y, 0.0, 1.0);
}

Attributes — 逐顶点数据(位置、uv、自定义数据)。仅在顶点着色器中可用。使用 varyings 将数据传递到片元着色器。

4. 噪声函数

几乎所有看起来有机的着色器都会用到噪声。把它们当作工具来用。

  • Perlin Noise:平滑、有机的随机性。非常适合地形和斑块变形。
  • Simplex Noise:与 Perlin 类似,但速度更快、伪影更少。非常适合渐变和动态纹理。
  • Curl Noise:由 Perlin/Simplex 衍生而来,可生成无散场。非常适合模拟流体般的粒子运动。
  • Fractal Brownian Motion (FBM):叠加不同频率和振幅的噪声,形成云状、山峦状细节。

使用 glsl-noise 包,或将这些函数直接复制到着色器字符串中。

“斑块”模式
// vertex shader with Perlin noise displacement
uniform float u_time;
uniform float u_intensity;

void main() {
  float displacement = pnoise(position * 1.5 + u_time * 0.5, vec3(10.0));
  vec3 newPosition = position + normal * displacement * u_intensity;
  // ... standard MVP transform on newPosition
}

5. 片段着色器效果

这些效果能将 UI 从“网站”提升为“电影般的体验”。请谨慎使用,并应用于环境层级,而不是单个组件。

色差

一种后期处理过程,会在视口边缘偏移 R/B 通道。

Shift amount: 0.002
Application: Viewport edges only, not center
Purpose: Simulates a physical camera lens
网格渐变背景

使用 3–4 个基于噪声的色块制作动画背景,让它们缓慢漂移。

Colors:
  - #00F0FF (Cyan)
  - #7000FF (Purple)
  - #000000 (Deep Charcoal)

Movement: Slow, organic drift (think lava lamp, not screensaver)
胶片颗粒

覆盖单色噪声,以消除数字色带并增加纹理感。

Opacity: 2% (0.02)
Type: Monochromatic
Animation: Subtle per-frame variation

6. 粒子系统

使用 BufferGeometry 创建基础粒子
const count = 5000;
const positions = useMemo(() => {
  const pos = new Float32Array(count * 3);
  for (let i = 0; i < count; i++) {
    pos.set([
      (Math.random() - 0.5) * 4,
      (Math.random() - 0.5) * 4,
      (Math.random() - 0.5) * 4,
    ], i * 3);
  }
  return pos;
}, []);

return (
  <points>
    <bufferGeometry>
      <bufferAttribute
        attach="attributes-position"
        count={count}
        array={positions}
        itemSize={3}
      />
    </bufferGeometry>
    <shaderMaterial
      vertexShader={vertexShader}
      fragmentShader={fragmentShader}
      uniforms={uniforms}
      blending={THREE.AdditiveBlending}
      depthWrite={false}
    />
  </points>
);
让粒子发光
// fragment shader
void main() {
  float strength = distance(gl_PointCoord, vec2(0.5));
  strength = 1.0 - strength;
  strength = pow(strength, 3.0);

  vec3 color = mix(vec3(0.0), vec3(0.34, 0.53, 0.96), strength);
  gl_FragColor = vec4(color, strength);
}
使用帧缓冲对象 (FBO) 处理海量粒子

FBO 可通过模拟过程将位置计算卸载到 GPU,从而支持 100k+ 个粒子:

  1. 将粒子位置存储在 DataTexture 中(每个粒子对应一个 vec4 = RGBA)。
  2. 创建一个 SimulationMaterial,在其片段着色器中读取并变换位置。
  3. 将该材质渲染到离屏 WebGLRenderTarget(使用 drei 中的 useFBO)。
  4. 在渲染过程中将结果纹理作为 uniform 读取,并用它来定位粒子。
// Simulation Material class
class SimulationMaterial extends THREE.ShaderMaterial {
  constructor(size) {
    const positionsTexture = new THREE.DataTexture(
      generatePositions(size, size),
      size, size,
      THREE.RGBAFormat, THREE.FloatType
    );
    positionsTexture.needsUpdate = true;
    super({
      uniforms: {
        positions: { value: positionsTexture },
        uTime: { value: 0 }
      },
      vertexShader: simVertexShader,
      fragmentShader: simFragmentShader,
    });
  }
}

// In useFrame: render sim material to FBO, pass FBO.texture to particles
useFrame(({ gl, clock }) => {
  gl.setRenderTarget(renderTarget);
  gl.clear();
  gl.render(simScene, simCamera);
  gl.setRenderTarget(null);
  points.current.material.uniforms.uPositions.value = renderTarget.texture;
  simMaterialRef.current.uniforms.uTime.value = clock.elapsedTime;
});

7. 渲染目标

WebGLRenderTarget 会将场景渲染到离屏缓冲区,并将其中的像素内容作为纹理提供给你。

核心模式
const renderTarget = useFBO();

useFrame(({ gl, scene, camera }) => {
  gl.setRenderTarget(renderTarget);
  gl.render(scene, camera);
  mesh.current.material.map = renderTarget.texture;
  gl.setRenderTarget(null);
});
用例

透明/玻璃材质 — 隐藏网格,将场景渲染到 FBO,再使用屏幕坐标将 FBO 纹理映射到网格上:

vec2 uv = gl_FragCoord.xy / winResolution.xy;
vec4 color = texture2D(uTexture, uv);

传送门(场景中的场景) — 使用 R3F 中的 createPortal 渲染离屏场景,将其捕获到 FBO 中,再映射到平面上。复制主摄像机的 matrixWorldInverse,即可添加视差效果。

视觉错觉 — 在 useFrame 中的不同渲染过程中切换材质/几何体,以通过透镜网格呈现不同版本。

场景过渡 — 将两个场景分别渲染到两个 FBO 中,再使用 Perlin 噪声和 progress uniform 进行混合:

float noise = clamp(cnoise(vUv * 2.5) + uProgress * 2.0, 0.0, 1.0);
vec4 color = mix(colorA, colorB, noise);

后期处理管线 — 将渲染目标与自定义着色器材质串联,并使用全屏三角形,作为 EffectComposer 的替代方案。

8. 折射、色散与光照效果

折射

使用 GLSL 内置的 refract(),并传入 eyeVector、worldNormal 和 IOR 比率:

vec3 refractVec = refract(eyeVector, worldNormal, 1.0 / 1.31);
vec4 color = texture2D(uTexture, uv + refractVec.xy);
色散

为每个颜色通道分别应用不同的 IOR 值,以拆分 R、G、B:

float R = texture2D(uTexture, uv + refractVecR.xy).r;
float G = texture2D(uTexture, uv + refractVecG.xy).g;
float B = texture2D(uTexture, uv + refractVecB.xy).b;

通过采样循环(迭代 N 次,并为每个通道逐步滑动)使效果更加平滑。使用傅里叶插值将色彩空间从 RGB 扩展为 RYGCBV,以获得更多控制。

镜面反射 + 漫反射 (Blinn-Phong)
vec3 lightVector = normalize(-uLight);
vec3 halfVector = normalize(eyeVector + lightVector);
float kDiffuse = max(0.0, dot(normal, lightVector));
float kSpecular = pow(dot(normal, halfVector) * dot(normal, halfVector), shininess);
return kSpecular + kDiffuse * diffuseness;
菲涅耳
float fresnel = pow(1.0 - abs(dot(eyeVector, worldNormal)), uFresnelPower);
背面渲染技巧

先渲染网格背面(THREE.BackSide),将其捕获到 FBO 中,再渲染正面。背面的镜面反射会被正面折射/色散,从而产生逼真的内部色散效果。

9. 将后期处理作为创作媒介

像素化基础
vec2 normalizedPixelSize = pixelSize / resolution;
vec2 uvPixel = normalizedPixelSize * floor(uv / normalizedPixelSize);
vec4 color = texture2D(inputBuffer, uvPixel);
获取单元格局部坐标
vec2 cellUV = fract(uv / normalizedPixelSize); // 0->1 within each cell

这是在每个像素单元内塑造图案的关键。

后期处理着色器的两大支柱
  1. 重映射/扭曲 UV 坐标(像素化、错位、偏移)
  2. 单独塑造每个单元格(基于亮度、SDF、阈值矩阵的图案)
图案技巧

收据/条纹图案 — 使用亮度控制每个单元格 cellUV 中的线宽。

半色调 — 通过距离场绘制圆形,并根据亮度调整半径:

float luma = dot(vec3(0.2126, 0.7152, 0.0722), color.rgb);
float radius = uRadius * (0.1 + luma);
float circle = smoothstep(radius - 0.01, radius + 0.01, dist);

CMYK 半色调 — 使用四个旋转网格(C:15deg,M:75deg,Y:0deg,K:45deg),将 RGB 转换为 CMYK,并采用减色混合:

vec3 outColor = vec3(1.0);
outColor.r *= (1.0 - CYAN_STRENGTH * dotC);
outColor.g *= (1.0 - MAGENTA_STRENGTH * dotM);
outColor.b *= (1.0 - YELLOW_STRENGTH * dotY);
outColor *= (1.0 - BLACK_STRENGTH * dotK);

ASCII 效果 — 创建包含 ASCII 字符的画布纹理,通过将亮度映射到 charIndex 来采样。

基于 SDF 的图案 — 使用 length(p - 0.5) 绘制圆形,并使用自定义 SDF 绘制十字、三角形等。

阈值矩阵 — 定义具有自定义亮度阈值的 8x8 矩阵。将像素的亮度与矩阵值进行比较,以控制像素的开关,从而创建条纹、编织图案及任意自定义图案。

错视效果
  • 交错式 LED 面板 — 在像素化之前,按列偏移 UV 坐标。将单元格拆分为子单元格,并添加额外偏移。使用 1.0 - subCellUV * subCellUV 添加黑色边框。
  • 钩编/编织 — 使用随机正弦偏移,逐行偏移 cellUV。在每个单元格中绘制旋转椭圆。在边缘添加噪声、条纹图案和色相偏移。
  • 乐高积木 — 像素化 + 在单元格中心添加 Blinn-Phong 光照的圆形凸粒 + 颜色量化 + 细微边框。
  • 波纹/磨砂玻璃 — 扭曲 = 正弦波的导数。将其转换为法线以实现 Blinn-Phong 光照。添加高斯模糊和噪声。
动态/交互式后期处理
  • 渐进式去像素化 — 跟踪“级别”(2 的幂),根据进度 uniform 逐行、逐像素处理。
  • 像素化鼠标轨迹 — 通过乒乓渲染将鼠标轨迹渲染到 FBO,并将纹理传递给效果。使像素大小和扭曲程度随轨迹强度和光标速度变化。

10. 半色调(进阶)

点阵网格
vec2 cellUv = fract(vUv * uGridSize);
float dist = length(cellUv - 0.5);
float circle = smoothstep(radius - 0.01, radius + 0.01, dist);
打破网格 — 邻近采样

为避免圆点在单元格边界处被裁切,对周围单元格采样一个 3x3 核:

for (int dx = -1; dx <= 1; dx++) {
  for (int dy = -1; dy <= 1; dy++) {
    vec2 cellIndex = baseCellIndex + vec2(float(dx), float(dy));
    vec2 cellCenter = (cellIndex + 0.5) * uPixelSize;
    // Calculate distance, check reachability, keep closest
  }
}
黏连半色调

使用 smoothmin 混合重叠的圆形,在相邻圆点之间形成类似墨水的表面张力。

摩尔纹

重叠的旋转网格会产生干涉。为每个 CMYK 通道使用特定的角度偏移,以尽量减少伪影。

抗锯齿

使用 fwidth(dist) 实现与分辨率无关的边缘柔化:

float edgeWidth = fwidth(dist);
float circle = smoothstep(radius - edgeWidth, radius + edgeWidth, dist);

11. 交互模式

悬停:磁吸效果

卡片和交互元素会随光标移动,产生细微位移。

Displacement factor: 0.1x (cursor offset from element center)
Spring back on mouse leave
// React example
const handleMouseMove = (e) => {
  const rect = ref.current.getBoundingClientRect();
  const centerX = rect.left + rect.width / 2;
  const centerY = rect.top + rect.height / 2;
  const offsetX = (e.clientX - centerX) * 0.1;
  const offsetY = (e.clientY - centerY) * 0.1;
  setTransform({ x: offsetX, y: offsetY });
};
激活:布局变形

容器状态发生变化(展开、折叠、导航)时,边界平滑地过渡,内部内容则交叉淡化。

  • 容器边界使用弹簧物理效果
  • 内部内容通过 200ms 的不透明度过渡进行交叉淡化
  • 绝不突然显现或跳动——每次状态变化都会添加动画

12. Framer Motion — 布局动画

布局动画

为 motion.div 添加 layout 属性,在 CSS 布局属性变化时实现平滑过渡:

<motion.div layout style={{ justifySelf: position }} />

取值:layout={true}(尺寸 + 位置)、layout="position"(仅位置——修复挤压变形)、layout="size"(仅尺寸)。

修复变形

将 borderRadius 和 boxShadow 设置为内联样式,而不是 CSS 类。

共享布局动画

使用 layoutId 在多个实例之间为组件添加动画:

{selected === item && <motion.div layoutId="underline" />}

在 <LayoutGroup id="unique"> 中包装组件,以便在复用组件时进行命名空间隔离。

用于兄弟元素的 LayoutGroup

将同级 motion 组件包装在 <LayoutGroup> 中,这样其中一个元素重新排序时,其他元素也会平滑地添加动画。

重新排序
<Reorder.Group axis="y" values={items} onReorder={setItems}>
  {items.map(item => (
    <Reorder.Item key={item} value={item} style={{ position: 'relative' }}>
      {item}
    </Reorder.Item>
  ))}
</Reorder.Group>

结合 AnimatePresence 实现退出动画,并为内容设置 layout="position" 以防止挤压变形。

13. Codrops 创意模式

Codrops 教程目录中的关键创意 Web 模式:

  • 滚动驱动的 WebGL 画廊 — 使用 GSAP ScrollTrigger 或原生滚动事件,将 R3F 场景与滚动位置同步。应用基于着色器的显现效果、视差深度层和速度响应式扭曲。
  • 页面转场 — 使用 Barba.js 或原生 SPA 路由器配合 GSAP 实现交叉淡化转场。在页面导航间保留 Three.js 场景。在视图之间使用基于着色器的溶解效果。
  • 无限画布 — 使用 R3F 进行基于区块的渲染,创建可无限平移的图像空间。处理 LOD 和纹理的延迟加载。
  • 将流体模拟用作显现效果 — 使用流体模拟纹理(乒乓 FBO)驱动双场景之间的 X 射线或显现效果。
  • SVG 遮罩 + 滚动 — 在滚动时为 SVG 裁剪路径添加动画,以显现全屏图像或区块。
  • 从 DOM 升级到 WebGL 的路径 — 从 DOM/CSS 视差画廊开始,然后升级到 WebGL,以实现由 GPU 驱动的流畅滚动和着色器效果。
  • 基于物理的效果 — 将 Rapier 物理与 Three.js 配合使用,实现体素下落、粒子交互和受物理驱动的动画。
  • 用于布局转场的 GSAP Flip — 使用 GSAP 的 Flip 插件为响应式网格布局变化添加动画,实现即时、流畅的重新布局。
  • TSL + WebGPU — Three.js Shading Language(TSL)支持使用 JavaScript 语法为 WebGPU 编写着色器,并使用计算着色器实现粒子模拟和文本溶解效果。

14. CSS 变量

将这些用作设计令牌:

:root {
  /* Spring physics */
  --spring-stiffness: 300;
  --spring-damping: 30;
  --spring-mass: 1;

  /* Glass */
  --blur-glass: blur(28px);
  --blur-spotlight: blur(40px);
  --surface-fill: rgba(255, 255, 255, 0.05);
  --border-glow: rgba(255, 255, 255, 0.08);

  /* Shader effects */
  --grain-opacity: 0.02;
  --chromatic-shift: 0.002;

  /* Interaction */
  --magnetic-factor: 0.1;
  --overshoot-scale: 1.05;
}

15. 玻璃表面中的排版

  • 最大字重:500(中等)。玻璃表面上绝不使用粗体。
  • 通过大小写、字间距和不透明度构建层次,而不是通过字重。
  • 等宽文本(代码、标签)应使用大写字母 + 11px。
  • 玻璃上的文本需要足够的对比度——主要文本使用 rgba(255, 255, 255, 0.9),次要文本使用 rgba(255, 255, 255, 0.5)。

16. 关键 GLSL 函数

mix()、smoothstep()、step()、fract()、floor()、mod()、clamp()、length()、distance()、dot()、normalize()、refract()、reflect()、pow()、abs()、sin()/cos()、texture2D()、fwidth()

17. 必备资源

  • The Book of Shaders(thebookofshaders.com)— 基础读物
  • Shadertoy — 灵感来源和 GLSL 技术
  • glsl-noise 包 — 可直接使用的噪声函数
  • @react-three/drei — useFBO、OrbitControls、PerspectiveCamera、RenderTexture、MeshTransmissionMaterial
  • @react-three/fiber — Canvas、useFrame、createPortal、extend
  • Lamina — 在现有材质之上组合着色器层
  • Maxime Heckel's blog(blog.maximeheckel.com)— Web 上着色器创作的主要参考资料
  • Codrops(tympanus.net/codrops)— 着色器与交互设计相遇之处

18. 性能

  • 在 React 中对 uniforms 对象进行记忆化,避免重新渲染错误
  • 将设备像素比上限设为 2(Canvas 上的 dpr={[1, 2]})
  • 粒子使用 THREE.AdditiveBlending 和 depthWrite={false}
  • 尽量减少着色器中的 for 循环(循环中的纹理查找开销很大)
  • 使用 FBO 将繁重计算卸载到 GPU
  • 考虑使用乒乓渲染,避免转场期间同时渲染两个场景

19. 工作流

构建创意网页效果的方法:

  1. 确定类别:着色器效果、粒子系统、后期处理滤镜、动画,还是滚动驱动交互?
  2. 选择合适的工具:自定义着色器使用 R3F + shaderMaterial,透明效果/粒子/转场使用 FBO,UI 动画使用 Framer Motion,滚动驱动效果使用 GSAP。
  3. 从数学入手:用什么函数描述形状/运动/扭曲?(sin、noise、SDF、距离场)
  4. 搭建基础结构:设置 Canvas、mesh,以及带有 uniforms 的基础 shaderMaterial。
  5. 逐步实现:先让基础版本正常运行,再逐步增加复杂度。
  6. 添加交互性:将鼠标位置、时间、滚动进度连接为 uniforms。
  7. 打磨效果:添加抗锯齿(fwidth)、色彩校正(饱和度、色相偏移)、光照(Blinn-Phong、Fresnel)和性能优化。

20. 反模式

请勿:

  • 对主要运动使用 ease-in-out 或任何基于时长的缓动
  • 在浅色背景上应用玻璃效果
  • 使用实心投影(改用环境遮蔽风格)
  • 让颗粒明显到能被有意识地察觉(不透明度 >3%)
  • 在整个视口范围内均匀应用色差
  • 在玻璃表面使用粗体(600+)字重
  • 省略过冲效果——没有过冲的弹簧动效会显得呆板

评论

支持 Markdown