文本转 GIF 动画 — React Pet 项目开发日志
我有一个想法,用简单的文本创建故事板会很酷:
在本文中,我将与大家分享我对这个项目的想法和构建过程。
我一定会向你展示最终结果!
剧透:事情没有按计划结束。tl ;dr 最终结果
0. 想法
我开始将这个想法视觉化。首先用纸笔,然后是draw.io(你可以在上面看到第一个概念之一),最后写一个概括性的概述:
用户使用简单的英语定义场景:
Scene
Ann as woman to the right
Frame
Ann says "Hello!"
场景定义描述演员(装饰)和框架
演员使用预设的精灵,如,,tree
框架定义演员执行的动作man
woman
用户将能够分享他们的故事并“喜欢”和修改其他人的故事。
当想法和语言或多或少确定下来后,就该起草开发计划了:
- 设置——项目准备
- JSON 到图像—测试我是否可以按我想要的方式创建图像
- 图像转为 GIF —确保我可以在客户端生成 GIF,尝试一些库
- 文本转 JSON —我需要为该语言创建一个解析器
- 后端——需要登录/保存/共享流程
- 发布
注意:为了简洁起见,我不会提及很多死胡同的想法或愚蠢的错误:所以如果你觉得一切进展太顺利——那只是因为编辑的原因。此外,我会删减大量代码,并使用类似伪代码的风格来缩短源代码。如果你有任何问题——请随时提问!
我们走吧!
1. 设置
我需要一个 git 仓库来组织我的开发流程,并需要一个框架来加速开发。我使用了create-react-app和git init:
npx create-react-app my-app
cd my-app
# [skipped TypeScript adding process]
git init -y
git commit -m "initial"
npm start
重要提示:我们需要快速测试我们的想法!使用哪种语言、框架或版本控制系统并不重要,只要你熟练掌握并高效使用即可。
2. JSON 转图像
我首先定义一个简单的 JSON 来测试我是否可以根据这个结构渲染图像。
JSON 应该描述:
sprites
— 演员和装饰的图片 URLscenes
— 应包含并定位演员和装饰- 并且
frames
- 应该包含动作,例如“安向左移动”
({
sprites: { name: 'http://sprite.url' },
scenes:
// scene descriptions
{ scene_ONE:
{ entries:
/* entries with their sprites and position */
{ Ann: { sprite: 'woman'
, position: { /* ... */ }
}
}
},
},
frames:
[ { scene_name: 'scene_ONE'
, actions: [
{ target: 'Ann'
, action: 'move'
, value: {x, y}
}
]
}
, // ...other frames
]
})
对于演员,我定义了三个预设精灵:tree
、woman
和man
,并将相关图像添加到项目中。
-
现在我们将对每一帧执行所有动作(移动和说话)
// for each frame
const computedFrames = frames.map(frame => {
// clone entries
const entries = _.merge({}, frame.scene.entries);
// perform actions on the target entry
frame.actions.forEach(action => {
const entry = entries[action.target];
if (action.type == 'talk') {
entry.says = action.value;
}
if (action.type == 'move') {
entry.position = action.value;
}
});
return { entries };
});
-
对于绘制入口精灵,我们肯定会使用canvas:
// draw the entries
const images = computedFrames.map(frame => {
const canvas = document.create('canvas');
const ctx = canvas.getContext('2d');
frame.entries.forEach(entry => {
ctx.drawImage(entry.sprite); // for sprites
ctx.fillText(entry.says); // for speech
});
// return rendered frame URL
return URL.createObjectURL(canvas.toBlob());
})
Canvas 可以将其内容导出为dataURL或blob — 我们稍后需要它来生成 .gif!
^ 实际上,代码更加异步:toBlob
是异步的,并且所有图像都应该在之前下载ctx.drawImage
,我使用了Promise链来处理这个问题。
至此,我已经证明图像可以按预期呈现:
所以我们可以继续:
3. 图像转GIF
这需要研究一些可用的库。我最终选择了gif.js。可惜的是,它已经一年没更新了,不过它的工作做得还不错(demo)。
要生成 .gif 文件 — — 我们需要将每个图像提供给gif.js
生成器,然后调用render()
它:
const gif = new GIF({ /* GIF settings */ });
images.forEach(imgUrl => {
const img = new Image();
img.src = imgUrl;
gif.addFrame(img, { delay: 1000 });
});
gif.on('finished', blob => {
// Display the blob
updateGifURL(URL.createObjectURL(blob));
});
gif.render();
太棒了,现在我们可以生成并下载 .gif 了:
4. 文本转 JSON
我希望用户能够用简单的英语输入命令。这对我来说是最难的部分,因为我甚至不知道从哪里开始:
- 创建我自己的解析器?
input.split(/\n/)
然后使用正则表达式?- 使用一些英语语法解析器?
幸运的是,经过一番搜索后,我偶然发现了这篇文章“使用 PegJS 编写 DSL 解析器”,它向我介绍了 PEG.js(@barryosull,谢谢)。
PEG.js是一个简单易用的解析器构建器:
- 使用类似正则表达式的规则来定义你的语言
- 它会
.js
使用您个人的全新解析器生成一个文件 - 你插入这个解析器并针对你的文本运行它
例如,下面是我的规则中解析 s 的摘录Scene
:
这些规则将解析此文本:
Scene
with Tree as tree at { y: 160 scale: 1.5 }
对此 JSON:
{
"type": "scene",
"values": [
{
"type": "object",
"objectName": "Tree",
"sprite": "tree",
"state": {
"y": 160,
"scale": 1.5
}
}
]
}
在使用 PEG.js在线版本几个小时后,我最终找到了一种适合使用的语言和输出结构。
将其插入应用程序后,我得到了这个:
附注 1:此时,我放弃了模糊定位的想法Ann to the right
,并更新了 PEG.js 来定义类似 js 的对象符号:Ann at { x: 100 y: 100 }
。
附注2:另外,我没法每次更新文本都重新生成GIF。这太麻烦了。每次按键都会阻塞100毫秒的UI线程,太麻烦了。
RxJS 😍 来救援了!用于输入文本更新的去抖动和一个简单的计时器,映射到帧切换imgRef.current.src = next_frame
以模拟动画。
只有当用户点击“下载”按钮时才会生成实际的 .gif!
5. 后端
这个宠物项目已经花费了我一个周末的开发时间,所以我不得不放弃所有与后端相关的任务,暂时坚持使用静态网络应用程序。
6.出版
我使用GitHub Pages功能来部署和共享项目。
GitHub Pages 将在其域名下为你的网站提供服务http://username.github.io/repository
。由于我稍后可能会添加后端,所以我需要购买一个域名,以便我现在分享的所有链接将来仍然有效。
对我来说,取名字总是很难。经过一个小时的折腾,我最终确定了:
去尝试一下framd.cc吧!🙂
结尾
剧情反转:部署项目并与朋友们分享后,我发现我的精灵图不够用了!原来,光靠男人、女人和一棵树的图片根本讲不完故事。所以我决定用表情符号做精灵图👻。现在,你拥有了海量表情符号🌳👩🚀🌍,可以好好讲述你的故事了!
结束
就到这里!感谢阅读!🙏
有任何问题吗?请在评论区留言,我很乐意解答!
如果你喜欢阅读 — — 请考虑给这篇文章和这条推文点个赞
科斯帕尔奇克@kddsky
“文本到 GIF 动画 — — React Pet 项目 Devlog”
从构思到生产仅用 4 天
dev.to/kosich/text-to…
6 分钟阅读
#React #canvas #js #ts #dsl #devlog #creativity #DEVCommunity2020年6月17日下午6:08
这很有帮助!
谢谢!
PS:一些 gif 示例:
文章来源:https://dev.to/kosich/text-to-gif-animation-react-pet-project-devlog-5eel