【免费下载链接】ascii-sharks
ascii shark components in typescript
ascii-sharks 是一个零依赖的 ASCII 海洋模拟器:它用 TypeScript 在浏览器 canvas 上,把鱼群和鲨鱼渲染成一格一格的字符,模拟出一片会游动、会逃散、会捕猎的"字符海洋"。整个项目没有任何运行时第三方库,核心只有 7 个源文件,两条命令即可跑起来。
;' %%' .t;. .oooo S;:S% %8S8. ;:tt%t '.. XX%%S t' ''XSSS8SSX%XX8#. %XSX% :;' ;.''X8%8XX%%S%%S%SStt%tSX8S#X8't%ttt. ::%' ''8XXXSSt%Stttttt%8@%%@%8@8%Sttt%%%%SSSSS%tt. 'SXXtt%t%%%S%:;StS%ttSS%tSXSt88@@%8%@8%tStS%%X%SS%%S%;;t .@##88#@...'@@@@#@8@88X88#XXXSX8SX88SX8%SS%S%%S88St%t%%%. %;%t :. '.'##@###@X#888XX##8@@@#.X%XS%. .%t ;%%%#@@##@@@. SXS%% t. .%;%%%. %%XXS '%t:t .SXSS' '::. ooooo .S'这就是 README.md 里展示的"主角":由# @ % S 8 X等字符按明暗分层拼出的鲨鱼,在黑色网格上缓缓游过,身后拖着青色的尾迹光点 🌊
两分钟快速上手:克隆、安装并运行演示
无需任何构建配置,Vite + TypeScript 已经写好。克隆仓库后两条命令即可看到全屏海洋:
git clone https://gitcode.com/gh_mirrors/as/ascii-sharks cd ascii-sharks npm install && npm run dev运行后打开本地地址,你会看到 4 条不同"景深"的 classic 鲨鱼在屏幕里巡游,背景里数百条小鱼组成鱼群。
互动小技巧:
- 🖱️ 移动鼠标:鱼群会把光标当作天敌四散逃开;
- 💥 点击页面:制造一次"水花",附近的鱼瞬间炸开;
- 🔗 切换鲨鱼阵容:在 URL 后追加
?sharks=参数,例如?sharks=thresher,hammerhead,mako,nurse(第一条最大,其余依次递减),不传参数则默认 4 条 classic。参数解析逻辑见 demo.ts。
内置生态一览:8 种鲨鱼与 5 种鱼类
8 种可选择的鲨鱼种类
鲨鱼种类定义在 src/world.ts 的SharkKind类型中,每种都有独立的体型轮廓、皮肤色调和花纹:
| 种类 | 特征 |
|---|---|
classic | 经典纺锤形,冷调蓝灰皮肤(默认主角) |
hammerhead | 宽铲形头翼,眼睛长在头翼两端 |
greathammer | 更宽的锤头,镰刀状背鳍,板岩色皮肤 |
tiger | 方头重身,背部带虎斑纹 |
zebra | 短圆头 + 缎带状长尾,沙色皮肤带斑点 |
mako | 细长锥形吻部,金属靛蓝色背部 |
thresher | 上半截尾鳍长过整个身体,青铜紫皮肤 |
nurse | 扁宽的头和身体,双背鳍靠后,土黄色 |
每种鲨鱼的"体型函数"(背鳍位置、胸鳍弧度、尾叉形状等)都在 src/renderer.ts 的SHAPES表中用"体长的比例"描述,所以同一套渲染管线可以画出所有种类。
5 种鱼群物种
鱼群物种配置在 src/species.ts,每种鱼有独立的巡游速度、群规模、"个人空间"和行为权重:
- sardine(沙丁鱼):喜欢围成旋转的"饵球"(bait ball),
mill值最高; - anchovy(凤尾鱼):高度一致化,游出长长的"缎带";
- silverside:中等一致性的稳定鱼群;
- mackerel(鲭鱼):小规模、保持距离的松散群;
- goby(虾虎鱼):几乎不看邻居、随机乱窜的"蜂群"。
这些行为差异来自经典的 Couzin 模型(见 src/species.ts 的注释):对齐(align)强就形成极化鱼群和缎带,弱则形成蜂群,再加上切向力(mill)就旋转成饵球。
核心原理:字符网格上的鱼群与猎手
鱼群:带"恐惧传染"的 boids
模拟核心是 src/world.ts 注释里写明的方案——Reynolds boids(分离 / 对齐 / 内聚)加上几个让它"像真的"的细节:
- 盲点:每条鱼正后方约 127° 看不到邻居,逃散不会 180° 完美掉头;
- 恐惧传染:看到鲨鱼的鱼会把自己的
alarm值传染给邻鱼(每跳衰减 14%),于是整群鱼即使只有边缘看到了猎手也会一起炸开,形成真实的"惊波"; - 喷泉水效应:逃跑的鱼会朝鲨鱼路径的侧方分流,重现自然界 bait ball 的喷泉形态;
- 空间哈希:鱼被分进网格桶(
rebuildHash),让数百条鱼的邻居查询保持 O(n),60fps 轻松运行。
鲨鱼:follow-the-leader 脊椎 + 饥饿捕猎
每条鲨鱼是一根 20 节点的"脊椎"(src/world.ts),头部驱动、后续节点以关节刚度限制跟随——所以身体最多弯成 C 形,永远不会"折叠"。行为上:
- 饥饿系统:
hunger随时间增长,吃鱼后下降; - 猎物选择:优先盯"落单"的鱼——密集鱼群反而会迷惑捕食者(
findPrey按桶内拥挤度打分,见 src/world.ts); - 被吃的小鱼不会消失:几秒后它们组成新的鱼群从屏幕边缘游回来,生态保持动态平衡。
渲染:把世界"光栅化"成字符格子
src/renderer.ts 的AsciiRenderer是视觉效果的关键,每帧分四步:
- 铺一层黑色底 + 细白网格(
paintGrid); - 计算尾迹场:鱼和鲨鱼尾部在格网中"沉积"能量,再扩散衰减,能量高的格子亮起青色小方块——这就是游过后的水波痕迹;
- 鱼渲染成单格字符
-,按景深分 5 档亮度,急转弯和受惊的鱼会"闪银光"; - 鲨鱼逐格超采样(每个格子取 5 个采样点判断覆盖率):内部格子画实心色块 + 按明暗选
:;t%SX8#@字符(亮处字符稀疏、暗处字符密集,纹理强化光影),边缘格子用.',等轻字符做抗锯齿轮廓。
鲨鱼皮肤还会以错峰的时钟重新掷色,产生"鳞片闪光";背鳍被"左上方的光"照亮,鳃裂、眼睛、虎纹/斑点全部用字符和色块区分。
集成到你的项目:一行 React 组件或一个 Engine 类
方式一:React 组件(推荐)
src/react.tsx 导出一个AsciiOcean组件,挂载时自动创建引擎、卸载时自动清理:
<AsciiOcean className="ocean" sharks={[{ kind: "hammerhead", size: 1 }]} />注意:字符来自 canvas 的font-family,记得给组件(或父级)设置等宽字体(如Geist Mono、Menlo)。
方式二:直接用 OceanEngine(无框架)
src/index.ts 导出OceanEngine、AsciiRenderer和paintGrid。只要有一个 canvas 就能跑:
import { OceanEngine } from "./src"; const engine = new OceanEngine(canvas, [{ kind: "hammerhead", size: 1 }]);OceanEngine内部已经处理了固定时间步长(60Hz)、resize、指针输入、页面不可见时暂停,甚至系统"减少动态效果"偏好——开启prefers-reduced-motion时它会让生态先"静置"4 秒,然后只渲染一帧静态画面(src/engine.ts),对动效敏感的用户也很友好。
源码地图:7 个文件的阅读路线
| 文件 | 职责 |
|---|---|
| src/index.ts | 对外导出入口(OceanEngine / AsciiRenderer / World) |
| src/world.ts | 生态模拟:鱼群 boids、鲨鱼追踪、进食与重生 |
| src/species.ts | 5 种鱼的物种参数与加权随机选择 |
| src/engine.ts | 引擎:固定时间步、resize、指针事件、动效偏好 |
| src/renderer.ts | 字符渲染:尾迹扩散、鲨鱼光栅化、鱼群分桶绘制 |
| src/react.tsx | React 封装组件<AsciiOcean /> |
| src/math.ts | 工具函数:clamp、smoothstep、hash3、无散度洋流 |
辅助文件:demo.ts(Vite 演示入口 + 鲨鱼阵容参数)、index.html(全屏 canvas + Geist Mono 字体)、tsconfig.json、LICENSE(MIT)。
常见问题
Q:真的零依赖吗?是。package.json 中运行时依赖为零,typescript和vite仅是 devDependencies。
Q:想要更小的鱼群或单条鱼?World构造函数接受可选的fishCount参数覆盖按面积计算的默认数量(默认 85~340 条,按画布面积自适应)。
Q:字符显示成方块?canvas 未加载等宽字体。给 canvas 或父级设置font-family: ui-monospace, Menlo, monospace即可,引擎会在字体就绪后重绘。
ascii-sharks 证明了"字符 + 物理感"的组合能带来意想不到的沉浸感:不需要一张贴图,几十个 ASCII 符号加上尾迹扩散,就足以让鲨鱼"游起来"。如果你想给自己的站点加一段有记忆点的背景动画,它是个几乎零成本的选择——MIT 协议,代码量小到一晚上能读完,值得克隆下来把玩 🦈
【免费下载链接】ascii-sharks
ascii shark components in typescript
相关推荐
把动态 ASCII 鲨鱼海洋装进 React:ascii-sharks 的 AsciiOcean 组件实战教程
把动态 ASCII 鲨鱼海洋装进 React:ascii sharks 的 AsciiOcean 组件实战教程 ascii sharks 是一个零依赖的 Typ
鲨鱼为何专挑孤零零的鱼?ascii-sharks 猎食 AI 的转向行为与饥饿机制详解
鲨鱼为何专挑孤零零的鱼?ascii sharks 猎食 AI 的转向行为与饥饿机制详解 ascii sharks 是一个 零依赖的 TypeScript 生物仿
ShowDoc 中的 voku/portable-ascii:零扩展依赖的 PHP ASCII 转写与字符清洗库全解析
ShowDoc 中的 voku/portable ascii:零扩展依赖的 PHP ASCII 转写与字符清洗库全解析 导读 Portable ASCII 是一
后端文档知识管理
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考