我把一个古早 Flash 头像生成器,用现代前端重做了一遍

3 阅读10分钟

前段时间在网上瞎逛,撞见一个日本复古头像生成器,画风特别对味——线条简单,配色很克制,一眼就是那种“古早互联网”才有的调调。但问题也摆在那:它是个 Flash 应用,现在浏览器早就跟 Flash 说再见了,想跑起来得靠 Ruffle 这类兼容层硬撑。

说是“能用”,实际上体验挺糟心的。风扇呼呼转,标签页动不动就卡住,有两次直接把整个浏览器窗口干崩了。原本该是个解压小玩具,结果活生生变成电脑压力测试。

于是脑子里冒出个念头:把它用现代前端技术完整重写一遍,行不行?

最后还真做出来了,起名叫 Square Face Generator。视觉气质保留了原版的味道,底层完全换成现代 Web 那一套,跑起来顺滑多了。按我自己的体感来说,浏览器端的体验大概好了十倍不止。

og1.png

这篇就聊聊我是怎么搞的。


一、为什么要费这个劲

出发点其实特朴素:我就是想正常用它。

原版站点几个比较劝退的地方:

  • 整体依赖 Flash 那套资源和逻辑
  • 现在只能通过兼容层勉强跑起来
  • 兼容层本质上是模拟旧环境,开销很大
  • 在现代浏览器里跑模拟器,体验远不如原生实现

这类头像生成器说穿了就是大量素材叠来叠去、切换部件、实时调色预览。放在兼容层里,浏览器得扛起一整套旧时代运行时的重担;而用现在的 Canvas 和前端能力来做,完全可以很轻巧。

所以我从一开始就没打算做个“长得像”的仿品,目标是:在尽量尊重原版风格和玩法的基础上,让它真正活在现代浏览器里。


二、大概的实现路子

整个过程可以分成两大步。

1)先把 Flash 内容拆开看看

我用 FFDEC 反编译了原始的 Flash 文件,主要拿到了两类东西:素材资源,还有 ActionScript 里藏着的那套逻辑。

这一步挺关键的。如果光靠肉眼对着网页截图去模仿,顶多还原个外观,但内部的素材组织方式和交互规则根本摸不准。

拆开之后心里就有谱了:它就是个典型的“分层素材 + 配置切换 + 实时预览”编辑器。头像的各个部件——刘海、侧发、眼睛、嘴巴、帽子、眼镜、衣服——是一层一层往上叠的。

问题就变成了:怎么把 Flash 里的素材分层模型,搬到浏览器里做成一套好维护、能扩展、渲染还快的前端架子。

2)用现代前端重新搭起来

我没有去一行行“翻译”原始代码,而是换了种方式:

  • 保留原版的设计味道和素材体系
  • 用现代前端技术从头搭一个头像生成框架
  • 把反编译拿到的素材一点点填进去
  • 让新框架去承载旧内容

技术选型上没搞太复杂,主要就是 Next.js、React、TypeScript 和 Canvas 2D。核心目标很简单:把运行开销尽量压在浏览器原生能力附近,别又搞出一套重型运行时。


三、把“头像生成器”抽象成前端模型

头像生成器看起来像换装小游戏,但真下手做的时候,关键不在 UI,而在于渲染模型怎么定义。

我后来把它拆成了三层。

第一层:素材发现与配置

最先要解决的其实不是“怎么画”,而是“系统怎么知道有哪些素材可用”。

我搞了一套素材自动发现机制:系统会从素材目录里把资源都扫出来,同时解析文件名里藏着的位移、缩放这些元信息。比如文件名里带上 _x-35_y25_s0.5 这种后缀,绘制的时候系统就知道要对它做相应的偏移和缩放处理。

这么干的好处是:

  • 不用手写一大堆素材坐标了
  • 新素材只要按规则命名就能直接接入
  • 配置和渲染逻辑解耦,改起来互不干扰

这个部分我后来花了不少精力打磨,核心就是把每个素材的偏移和缩放信息收进文件名规则里,同时优化了素材的预加载流程。

第二层:状态层

头像本质上就是一份状态快照。

比如当前选的是哪种眼睛、哪种嘴巴、有没有戴帽子、各部件用的什么颜色、某些部件有没有手动调过位置或大小。

我把当前头像抽象成一个统一的状态对象,编辑器里所有操作归根到底都是在改这份状态。渲染入口就盯着这个状态走,状态一变就重绘 Canvas。

这样做有几个实在的好处:

  • UI 和渲染之间的边界很清楚
  • 随机生成、本地编辑、重置功能都好实现
  • 以后想加分享链接、导出配置、恢复历史记录什么的,成本也低

第三层:绘制层

最后所有选择都会汇到一个 Canvas 绘制函数里。

这个函数干的事情包括:按固定顺序遍历各个部件,找到当前状态对应的素材,根据元数据和默认配置算位置,再结合缩放、锚点、偏移信息定出最终绘制坐标,有需要的话还要处理镜像、着色、多层叠加,最后画到 Canvas 上。

这部分是整个项目里最“关键但不怎么显眼”的环节。

头像生成器乍一看简单,素材一多,麻烦就来了:

  • 素材尺寸不统一
  • 视觉中心不一样
  • 有的要按面部中心对齐
  • 有的要保留原色,有的得跟着肤色或部件颜色一起染色
  • 有的帽子还不是单层,是前后分层叠的

这些问题要是靠写死坐标硬扛,素材稍微多起来就会变成噩梦。所以后来我把很多逻辑都收敛成“配置 + 元数据 + 绘制规则”的组合,系统才能撑得住素材规模的增长。


四、最磨人的不是写代码,是跟旧素材较劲

做过这类复刻项目的人估计都懂:最花时间的是素材校准。

从 Flash 里拆出来的资源,不是天生就能在前端环境里完美对齐的。原系统能对齐,是因为工程文件里有一套自己的坐标系、锚点规则和运行时逻辑在背后撑着。把素材单独拎出来之后,问题就全冒出来了——帽子会偏、眼镜尺寸不对、五官叠不到一块儿。

后来我用了种挺管用的笨办法:把位移和缩放信息直接编码进文件名里。

比如 hat_30_x50_y-50.pngglasses_21_x-35_y25_s0.5.png 这种。

运行时系统自动解析这些后缀,再参与绘制计算。这套机制的好处是,调素材从“改代码”变成了“改文件名 + 自动读取配置”,效率高了不止一点。

我前前后后修了好几版渲染一致性相关的问题,尤其是椭圆头像那版,背景底色和图案叠加规则来回调了好几轮,确保手动选、随机换、重置之后视觉效果都能对上。


五、一个很值的小优化:素材分阶段加载

另一个直接影响体验的点是首屏加载速度。

头像生成器有个天然矛盾:既希望用户一打开就能玩,又背着一堆素材资源。

全部一次性加载,首屏肯定慢;但什么都不提前加载,切换部件就会闪。最后我折中了一下:

  • 第一阶段:只加载默认头像必需的那部分素材,尽快让页面可操作
  • 第二阶段:后台静悄悄把剩下的资源补上

用户感知到的就是:打开页面马上能玩,切换部件也不卡。这个优化没啥技术含量,但特别值。因为用户根本不关心你加载了多少资源,他们只在意能不能立刻上手。

这也是现代前端重做相比 Flash 兼容层更容易做到的事情——你可以按交互路径来设计加载策略,而不是被旧运行时绑架。


六、为什么我说体验好了十倍

这里的“十倍”不是跑分跑出来的,是真实用下来的综合感受。

提升主要来自这几处:

  • 扔掉了 Flash 兼容层那个大包袱
  • 换成原生前端渲染链路,路径短多了
  • 素材加载更可控,优先保证“能玩”
  • 配置驱动代替硬编码堆叠,越往后越省心
  • 现代浏览器本来就擅长干这类活儿

以前打开旧站,我得先担心浏览器会不会先趴下;现在打开自己这版,基本就是秒进、秒改、秒导出。对一个头像生成器来说,“轻”和“快”比多塞几个花里胡哨的功能重要太多了。


七、AI 在这项目里到底干了啥

这个项目里我确实用 AI 帮了忙,但不是那种“一句话生成整个网站”的用法。

更准确地说,AI 扮演的角色是搭架子、提速度

我是这么用的:先自己把原始项目结构理清楚,明确哪些是素材问题、哪些是渲染问题、哪些是交互问题,然后让 AI 协助搭编辑器框架、整理类型定义、补一些重复性的实现部分,最后再由我把原始素材和细节一项项校准进去。

真正难的地方不是“写一个 React 页面”,而是理解原版系统、还原素材组织方式、处理那些细碎但关键的渲染细节,把旧时代的内容平移到现代浏览器模型里。AI 帮我省了些体力活,但方向、架构、校准和最终取舍,还是得自己来。


八、做完之后的一点感受

以前我觉得这类项目就是怀旧或者玩票。但真做完之后,反而觉得它挺有意义的。

很多老产品不是内容不行,而是被旧技术栈困住了

它们有好的创意、成熟的玩法、独特的视觉风格,甚至在一部分人心里还留着位置。真正过时的,往往只是承载它们的那个技术壳子。

把这些内容用现代前端重新表达出来,其实是在做一件挺有价值的事:把一段旧互联网体验,安安全全地迁移到当代 Web 里。

这不是简单翻新个界面,而是一次工程层面的重新实现。


九、最后,放一下成品

最终做出来的版本叫 Square Face Generator

它保留了那种很经典的日系复古头像味儿,但整个生成过程已经是现代浏览器原生能跑的体验了——不需要 Flash,不依赖兼容层硬撑,支持实时编辑和导出 PNG,用起来特别轻。

感兴趣的话可以自己上手玩玩:squareface.me

如果你也折腾过 Flash 老项目迁移、素材复刻、Canvas 编辑器,或者踩过 Ruffle 和老资源重构的坑,欢迎一起聊聊。