在复古手账与蒸汽朋克风格的插画设计中机械齿轮与单摆时钟一直是最具象征意义的美学符号。发条拧紧时的金属微颤、大小齿轮齿面之间严丝合缝的连续啮合咬合、老式钟摆在两极点之间迟疑而笃定的回摆……这些机械运动所传达的不仅是纯粹的工科几何理性更是一种对“时间流转、岁月刻度”的温情敬畏。很多前端开发者在尝试用 SVG 绘制齿轮动画时常常随手在圆形外侧贴上一圈均匀分布的矩形或梯形。这种粗糙的做法在静态展示时或许还能蒙混过关但一旦让两个不同尺寸的齿轮相对旋转就会立刻暴露出齿顶打架、穿模干涉或者齿隙悬空脱节的严重破绽毫无机械运动的咬合真实感。在本文中我们将深入机械工程学中的渐开线齿轮Involute Gear几何原理利用三角函数在纯前端动态推导生成严谨精确的 SVG 闭合齿廓矢量路径并配合现代 CSS 硬件加速与角速度反比传动比计算打造一套丝滑运转、绝不穿模的复古时钟摆动动画。机械原理两个齿轮为什么能完美啮合要让两个齿轮在相对旋转时既不互相撞击、又不相互脱离必须满足经典机械传动准则模数相同原则Equal Module模数 $m$ 是决定单个轮齿高矮胖瘦的基础参数。两个能够互相啮合的齿轮其模数必须完全相等分度圆与中心距设大齿轮齿数为 $z_1$小齿轮齿数为 $z_2$。分度圆直径 $d_1 m \cdot z_1$$d_2 m \cdot z_2$两齿轮的安装中心距必须严格等于两分度圆半径之和$L \frac{d_1 d_2}{2} \frac{m(z_1 z_2)}{2}$角速度反比与反向旋转主动轮与从动轮旋转方向相反。若大轮齿数为 18 齿、小轮齿数为 12 齿则传动比为 $18 / 12 1.5$。大齿轮顺时针旋转一周需要 6 秒小齿轮必须严格在 4 秒内逆时针旋转整整一周初始相位偏置Phase Offset小齿轮在起始时刻必须绕自身轴心预先偏转半个齿距角$\Delta \theta \frac{360^\circ}{2 \cdot z_2}$确保大轮的齿凸恰好嵌入小轮的齿凹之中。[主动大齿轮 z118] [从动小齿轮 z212] 分度圆 R1 分度圆 R2 ( O1 ) --- 中心距 L --- ( O2 ) | | 顺时针旋转周期 T1 6s 逆时针旋转周期 T2 4s (严格反向相切啮合无缝咬合绝无穿模)核心实现渐开线齿廓 SVG 路径生成器在 Web 端我们无需引入重量级的 CAD 库只需一段精巧的 TypeScript 数学算法就能通过正弦余弦极坐标变换在毫秒级内输出标准的 SVGpath d...字符串// utils/svg-gear-generator.ts export interface GearConfig { teeth: number; // 齿数 z module: number; // 模数 m pressureAngleDeg?: number; // 压力角 (标准通常为 20 度) holeRadius?: number; // 轴心内孔半径 } export class SvgGearGenerator { /** * 生成标准机械齿轮的闭合 SVG 路径数据 */ public static generateGearPath(config: GearConfig): string { const { teeth: z, module: m, pressureAngleDeg 20, holeRadius 14 } config; // 机械关键圆半径计算 const pitchRadius (m * z) / 2; // 分度圆半径 const addendum m * 1.0; // 齿顶高 const dedendum m * 1.25; // 齿根高 const outerRadius pitchRadius addendum; // 齿顶圆半径 const rootRadius Math.max(holeRadius 2, pitchRadius - dedendum); // 齿根圆半径 const anglePerTooth (2 * Math.PI) / z; const points: [number, number][] []; for (let i 0; i z; i) { const baseAngle i * anglePerTooth; // 单个齿形分为 4 个关键角度区段齿根左 - 齿顶左 - 齿顶右 - 齿根右 const a0 baseAngle; const a1 baseAngle anglePerTooth * 0.25; const a2 baseAngle anglePerTooth * 0.55; const a3 baseAngle anglePerTooth * 0.80; // 1. 齿根谷底左端 points.push([rootRadius * Math.cos(a0), rootRadius * Math.sin(a0)]); // 2. 渐开线上升段至齿顶 points.push([outerRadius * Math.cos(a1), outerRadius * Math.sin(a1)]); // 3. 齿顶平坦圆弧顶 points.push([outerRadius * Math.cos(a2), outerRadius * Math.sin(a2)]); // 4. 渐开线下降段至齿根 points.push([rootRadius * Math.cos(a3), rootRadius * Math.sin(a3)]); } // 组装外齿多边形 let d M ${points[0][0].toFixed(2)} ${points[0][1].toFixed(2)} ; for (let i 1; i points.length; i) { d L ${points[i][0].toFixed(2)} ${points[i][1].toFixed(2)} ; } d Z ; // 轴心内孔挖空使用偶数奇数填充规则镂空轴心 d M ${holeRadius} 0 A ${holeRadius} ${holeRadius} 0 1 0 ${-holeRadius} 0 A ${holeRadius} ${holeRadius} 0 1 0 ${holeRadius} 0 Z; return d; } }机械钟表与单摆联动组件实现在 Vue 3 组件中我们放置两个齿数比为 18:12 的齿轮计算其分度圆中心距进行精确定位并在底部悬挂一个优雅摆动的单摆!-- components/MechanicalClockwork.vue -- template div classclockwork-container svg classclockwork-svg viewBox0 0 500 400 xmlnshttp://www.w3.org/2000/svg defs !-- 复古做旧黄铜金属渐变 -- linearGradient idbrassGrad x10% y10% x2100% y2100% stop offset0% stop-color#e8c07d / stop offset40% stop-color#b8863b / stop offset70% stop-color#8a5c22 / stop offset100% stop-color#d4a359 / /linearGradient filter idgearShadow x-15% y-15% width130% height130% feDropShadow dx1 dy3 stdDeviation3 flood-color#2a1805 flood-opacity0.35 / /filter /defs !-- 机械摆锤挂载点 -- g classpendulum-group transformtranslate(250, 120) !-- 摆杆 -- line x10 y10 x20 y2190 stroke#7a4f1a stroke-width4 stroke-linecapround / !-- 摆锤重块 -- circle cx0 cy190 r24 fillurl(#brassGrad) filterurl(#gearShadow) / circle cx0 cy190 r14 fill#54330d / /g !-- 主动大齿轮 (18 齿, 坐标 200, 120) -- g classgear gear-driver transformtranslate(200, 120) path :ddriverGearPath fillurl(#brassGrad) filterurl(#gearShadow) fill-ruleevenodd / !-- 辐条装饰 -- circle cx0 cy0 r28 fillnone stroke#54330d stroke-width3 stroke-dasharray8 6 / /g !-- 从动小齿轮 (12 齿, 啮合中心距精确计算) -- g classgear gear-driven :styledrivenGearStyle path :ddrivenGearPath fillurl(#brassGrad) filterurl(#gearShadow) fill-ruleevenodd / circle cx0 cy0 r18 fillnone stroke#54330d stroke-width2.5 / /g /svg /div /template script setup langts import { computed } from vue; import { SvgGearGenerator } from ../utils/svg-gear-generator; const m 6; // 模数 const z1 18; // 大齿轮齿数 const z2 12; // 小齿轮齿数 const driverGearPath SvgGearGenerator.generateGearPath({ teeth: z1, module: m, holeRadius: 18 }); const drivenGearPath SvgGearGenerator.generateGearPath({ teeth: z2, module: m, holeRadius: 12 }); // 计算两圆心距离 L m * (z1 z2) / 2 6 * (18 12) / 2 90px const centerDist (m * (z1 z2)) / 2; const driverX 200; const driverY 120; const drivenX driverX centerDist; // 290 const drivenY driverY; // 初始相位角对齐微调 15 度齿顶嵌入 const drivenGearStyle computed(() ({ transform: translate(${drivenX}px, ${drivenY}px) rotate(15deg), transformOrigin: 0 0 })); /script style scoped .clockwork-container { display: flex; justify-content: center; align-items: center; padding: 24px; } .clockwork-svg { width: 500px; height: 400px; overflow: visible; } /* 主动大齿轮顺时针 6 秒/周 */ .gear-driver { animation: rotateClockwise 6s linear infinite; transform-origin: 200px 120px; will-change: transform; } /* 从动小齿轮逆时针 4 秒/周 (严格保持 1.5 倍速反向) */ .gear-driven { animation: rotateCounterClockwise 4s linear infinite; transform-origin: 290px 120px; will-change: transform; } /* 钟摆单摆振动周期 2 秒平滑加减速简谐运动 */ .pendulum-group { animation: pendulumSwing 2s cubic-bezier(0.4, 0, 0.6, 1) infinite alternate; transform-origin: 250px 120px; will-change: transform; } keyframes rotateClockwise { from { transform: translate(200px, 120px) rotate(0deg); } to { transform: translate(200px, 120px) rotate(360deg); } } keyframes rotateCounterClockwise { from { transform: translate(290px, 120px) rotate(15deg); } to { transform: translate(290px, 120px) rotate(-345deg); } } keyframes pendulumSwing { 0% { transform: translate(250px, 120px) rotate(-16deg); } 100% { transform: translate(250px, 120px) rotate(16deg); } } /style避坑指南机械啮合动画的核心细节动画时间函数的严格线性linear两个连续咬合的齿轮必须绝对使用linear匀速转动。如果误用了ease或ease-in-out两轮在不同周期阶段的瞬时角速度会发生错位导致肉眼可见的相对打滑与撞击中心距与 SVG 视口单位严格匹配在设置 CSS 旋转中心transform-origin时必须精准对齐分度圆几何圆心坐标哪怕偏离 1px旋转时都会产生明显的偏心摆动偏磨感摆锤周期与齿轮转速的声画共振单摆的来回往复周期2秒设计为大齿轮转动周期6秒的整倍数。这种数学上的共振节奏会让用户在凝视手账画面时感受到一种深邃悠长的秩序感与平静感。听汐的机械手记齿轮缝隙里的时间沉思在所有的人类发明中机械时钟大概是最浪漫的一种装置。它不需要任何网络连接不需要电池仅仅依靠几枚相互咬合的金属小齿轮与一根左右摆动的游丝发条就能日夜不息地把浩瀚无垠的宇宙时间切分成一声声清脆温润的“滴答”。在手账页面的角落里放上这样一对咬合无声的小齿轮看着它们不紧不慢地旋转心底的躁动总会悄悄平复。生活也是这样不需要急功近利地狂奔只要选对方向让每一分、每一秒都在平稳的齿轨上笃定运转时间自会为你结出最甘甜的秋实。