下一站,陌生人。
陌生人可能是周围最受欢迎和庆祝的标题顺序!让我们将其分解,看看我们是否可以在其荣耀的最多中模仿它。这是一个52秒的序列,所以我不会重新创建它完全!
tldr
这是完成的动画。
有开关可以打开音频和阴影。阴影太要求Firefox。
在codepen上给它!
关于标题序列
这是标题序列的视频:
标题的艺术做了一个fascinating write-up on the title sequence。他们采访了虚构力量创意总监Michelle Doughtery,他创建了标题序列。有趣的是看到他们考虑的想法,以及想法的迭代如何导致最终结果。
正如米歇尔(Michelle)指出的那样,标题序列没有首先显示,而是在情节的开幕场景之后显示。这使它在故事的流程中更多。
Duffers所做的真是太好了,这是在非常戏剧性的时刻之后的标题序列的位置。几乎是味觉清洁剂,或呼吸时刻。我认为这些特殊标题感到新鲜的部分原因是因为它成为讲故事的组成部分。
另外,Vox做了一个简短的"making of" video of the title sequence,也具有Michelle。
标题的主题非常简单。它是标题散布的字母的特写,慢慢地被绘制在一起。它是由迈克尔·斯坦(Michael Stein)和凯尔·迪克森(Kyle Dixon)制作的喜怒无常的合成器配乐的支持。字母是一种霓虹红,所有这些都引用了1980年代的风格。
标题使用的字体为ITC Benguiat。该字体免费用于个人使用。最值得注意的是,该字体是在无数史蒂芬·金小说的封面上使用的,斯蒂芬·金小说的封面可能有助于其选择标题。对某些字母进行了一些改动,以使它们更加细微。
我们正在做什么
我将重点关注标题序列的后半部分,从第25秒到结尾。这是有利位置固定的地方,标题紧密地放大,只有几个字母。它正在慢慢缩小以揭示完整的标题,而某些位于偏移位置的字母落入最终位置。
由于我们需要编辑某些字母的形状,因此我们将创建一个SVG(可扩展的向量图形)。另一种选择是自定义已获得许可的字体,这超出了我的技能。所以,让我们不要去那里!
麦克斯韦里奇韦(Maxwell Ridgeway
SVG的准备
以下是标题最终状态的屏幕截图。
让我们在Inkscape中创建一个基本版本。
我们想要景观SVG,3:2的长宽比是合适的。
在主菜单上,选择 file ,然后选择文档属性... 以打开下面的选项卡。
输入1200 AS 宽度,800作为 height ,然后选择“ px”作为 units 。我选择了1200x800,因为它是最方便的宽度比。 SVG的width
和height
可以在以后更改而不会出现问题。
我们想要一个黑色矩形,可以填充整个画布。我们添加一个rect
元素。给它与画布相同的width
和height
。默认的fill
是黑色的。
我们为每个单词添加一个text
元素。我们将font-family
设置为“ ITC Benguiat”。我们希望它是轮廓文本 - 因此,我们给它一个fill="none"
并为stroke
选择红色颜色。
为了使尺寸正确,我们可以尝试一些字体尺寸,直到我们的文字覆盖很大一部分画布为止。调整stroke-width
,直到我们得到正确的厚度为止,对我来说,有4个看起来很正确。
我们为包围文本的装饰盒添加了3个rect
元素。
我们想垂直和水平地将元素集中。为此,我们打开对齐并分发选项卡。在菜单上,单击对象,然后选择对齐并分发 ...。它按照下面的屏幕截图打开标签。
我们想相对于页面对齐我们的文本元素,并以两个轴为中心:
- 检查该下拉框中选择“页面”
- 在Align Align 部分中,单击“垂直轴上对齐”按钮。这是第一行上的第三个按钮,如上面的屏幕截图中的绿色。
- 现在,单击“水平对齐”按钮。这是第二行上的第三个按钮,如上面的屏幕截图中的绿色。
下面是SVG标记填写。我删除了width
和height
,稍后将在CSS中设置它。我删除了不必要的tspan
元素,只有一个text
元素来表示每个单词。
<svg viewBox="0 0 1200 800" xmlns="http://www.w3.org/2000/svg">
<rect id="bg" x="0" y="0" width="1200" height="800"/>
<rect x="925.24" y="449.54" width="168.95" height="14" fill="none" stroke="#a3280e" stroke-linecap="round" stroke-linejoin="round" stroke-width="4"/>
<text x="139.79877" y="401.03232" fill="#000000" font-family="'ITC Benguiat'" font-size="160px" stroke="#a3280e" stroke-width="4">STRANGER</text>
<text x="293.13965" y="536.1662" font-family="'ITC Benguiat'" font-size="160px" stroke="#a3280e" stroke-width="4">THINGS</text>
<rect x="105.81" y="263.09" width="965.55" height="14" fill="none" stroke="#a3280e" stroke-linecap="round" stroke-linejoin="round" stroke-width="4"/>
<rect x="111.29" y="452.78" width="168.95" height="14" fill="none" stroke="#a3280e" stroke-linecap="round" stroke-linejoin="round" stroke-width="4"/>
</svg>
这就是它的样子:
我们需要进行一些更改才能使其与原始标题匹配!以下是屏幕截图,具有突出显示和注释的差异。
我们需要更改以下内容:
- 所有字母都在标题中伸展。 “ t”也比其他字母更高。
- “陌生人”一词的第一个和最后一个字母比其他字母大。
- 一些衬线已被修改。第一个“ s”有一些改变,“ t”失去了顶部的衬线。另外,“ g”的背面也被扁平了。
- 有一些可以连接一些字母的kerning。角落消失看起来有点像魔术!
- 这些元素的颜色为荧光,在某些区域比其他区域更明亮。他们有点模糊。
编辑字母
我们需要做的是将text
元素转换为路径。我们想要每个字母的path
。
选择两个单词(text
元素)。您可以按住[[Shift]]键,然后单击它们。
在主菜单上,选择路径,然后选择对路径。现在,text
元素已成为path
元素的组(g
),每个字母为path
。
我们现在想解开这些,以便我们可以单独查看每个路径。从“上下文”菜单中选择组和右键单击,选择 ungroup 。现在选择画布上的所有元素,您应该看到每个字母现在都可以选择(它们周围有虚线),如下所示。
。
现在,我们可以操纵每个字母的形状和大小。我们使用节点工具的编辑路径。您可以通过击中[[n]]键,或从下面突出显示的工具栏中选择它。
。
现在,当您单击字母时,您将看到一个可以拖动以更改字母形状的控件点。
为了拉伸字母,您可以选择这些控件的组并向方向移动。在此视频演示中最容易看到。在这里,我使字母变细,更长。
如果您希望像我们对第一个“ S”一样按比例扩展大小,则可以更改width
和height
。但是,我们想按比例进行,因此看起来并不奇怪。为此,我们必须确保选择挂锁以锁定园艺。请参阅下面的屏幕截图。
现在,当您增加一个时,另一个将与它成比例的速度增长。您可以在下面的视频中看到我扩展“ S”。
编辑衬线更为挑剔。您需要编辑控件点并调整某些段的曲率。我讨厌这部分!
需要一段时间才能完成所有操作。当我确定差异并准确执行它们时,我花了2个小时才能按照我喜欢的方式获得它!精度在这里很重要,因为文本将在动画中的 lot 中缩放。如果我们在这里或那里被一小部分掉了,它将以非常明显的方式伸出!在其他情况下,您可以远离精确的问题。
以下是带有编辑字母的标题。
值得怀疑的一件事是重叠的字母的连接。当单词“陌生人”中的“ r”和“ a”汇聚在一起时,触发了变形,以创建2个字母的统一形状。
我将在动画中做一些黑魔法来实现这一目标!
获得合适的颜色以使外观呈荧光外观
我们需要尝试梯度以使颜色正确。
让我们来信,看看我们是否可以识别颜色的图案。让我们看一下标题的第一个“ s”。
下面我圈出了颜色较浅的区域。有些区域也带有中间色调。
如果您通过字母来看字母。
,这不是一个固定的,可预测的模式
让我们尝试从屏幕截图中获取一个调色板,以查看我们正在使用多少颜色。我用Big“ S”拍摄了同样的裁剪屏幕截图,然后将其上传到https://colordesigner.io/color-palette-from-image,为我获取调色板。请参阅下面的屏幕截图。
它标识了5个调色板:4种红色和1个黑色。我没有看到那里的超鲜红色。
我可以移动滑块以制作带有更多颜色的调色板。当我将其移至7时,我将结果在下面的屏幕截图中获取。我可以看到第二种颜色看起来更像是我期望的最鲜艳的颜色。
所以,我将从这个调色板中拿出一个明亮的(#E05E44),一个中间(#721209)和一种深红色(#4A0604),以使我自己的最小调色板。我会玩一些渐变,看看是否可以得到这些颜色的有机外观组合。
也许只是我,但我真的不喜欢在Inkscape中编辑梯度!对我来说真是太笨拙了。我会自己进行实验,并向您展示实验的结果。
第一件事是我的迷你调色板不起作用。太醇厚了。 bin!
其次,我认为radialGradient
比linearGradient
捕获了明亮照明区域的质量。 linearGradient
适用于特定侧面照明的字母。
我也尝试了混合模式,并且没有任何明显的改进。
让我们看看标题上的一个径向梯度之一。以下是“ radial3”应用于整个标题。
它看起来太均匀,并且作为刺耳的模式伸出来。也许,也许,如果您应用模糊和阴影,它看起来不太苛刻。不过,我认为使用几个不同的梯度将是一个更好的主意。
让我们尝试使用将它们应用于随机元素的“ radial2”和“ radial3”梯度。
Wayy 更好。它可能更亮,通过使用更多颜色,梯度可能会更光滑。
很容易陷入着色和哮喘调整。我们可以暂时让它成为它,并在动画完成后将其进一步改进。
为那种朦胧的霓虹灯氛围添加阴影和模糊怎么样?
目前,我们将只预览阴影和模糊。为什么?
如果要添加掉落阴影或模糊SVG中的元素,则需要使用filters。过滤器的动画很昂贵。
,即使我们在动画中也不会更改过滤器的值,如果我们移动一个在其上应用过滤器的字母,CPU/GPU必须进行更深入的计算和渲染。您会发现,如果将过滤器添加到动画元素中,则帧速率将大大减少!当我们优化和抛光动画时,我们可以稍后探索这一点。
我将进行快速预览,看看我们是否在正确的轨道上,模糊和落下的阴影将完成我们追求的外观。
,如果您在中风中添加7.5%的模糊,这就是外观:
,如果我们添加滴影( filter >> 阴影和发光>> 滴阴影.. ),它看起来像:33
让我们对我的版本与原件进行并排比较,看看我有多远:
它不远!我的版本肯定需要更顺畅,更明亮的渐变。需要努力使阴影更加霓虹灯,我可能会过度模糊。
动画的版本
我将在没有模糊和掉落阴影过滤器的情况下进行版本。我将进入SVG标记,并在每个path
和rect
中添加id
,因此我们可以在动画中引用它们。这样的东西,省略了许多属性和简洁的元素:
<svg id="titleSvg" viewBox="0 0 1200 800">
<!--gradients are here -->
<rect id="bg" width="1200" height="800"></rect>
<g id="title">
<rect id="top-box"/>
<path id="word1-s" />
<path id="word1-t" />
<path id="word1-r1" />
<!-- and so on -->
</g>
</svg>
我们将复制SVG标记并将其插入我们的 index.html inline。
动画时间
动画的中心部分是慢速放大以揭示标题。该变焦就像是一台关注标题不同部分的相机。我们需要将字母转移到不同的起始位置,并将其移至他们的最终位置。虽然动画都是简单的变换,但要同步表演者的动作是芭蕾舞。
我们有4个动画的零件将持续20秒:
- 缩放标题 - 这个生物从0到18秒。
- 字母的移动 - 字母从一开始就移动了,但是我们只会在缩小足够远时看到一些字母。所有字母都在14秒内到位。
- 装饰盒的扩展 - 在第二个14号,盒子扩展。顶盒首先是较小的第二箱和三分之二的盒子延迟了几百秒。
- 慢慢淡出标题 - 标题在动画的最后2秒内淡入黑色。
我们将尝试在动画中绑上标签,以使这些零件在我们的代码中清晰清晰。
第1部分:缩放标题
我们2个Broads选项,我们可以使用transform: scale()
或transform: translateZ()
。我们想缩放以恒定的速度显示标题,因此我们希望获得线性放松。
两个选项之间的一个重要区别是transform: scale()
是2D操作,而transform: translateZ()
是3D操作。从理论上讲,transform: translateZ()
有可能更容易地将其卸载到GPU上。这可能会更好。很难判断它是否会更好,因为我们将对许多字母进行另一种转换。因此,让我们尝试通过两个选项获得相同的结果,并以后查看它如何与动画的其他部分一起工作。
方法1:使用比例转换
缩放的棘手之处在于它的行为就像指数操作。这是一个有趣的现象,当您对物体的刻度进行动画化时,即使是线性的,它似乎也会改变速度。 GSAP创建了一个Easepack,其中包括ExpoScaleEase
,该Easepack通过相应地弯曲宽松曲线来补偿。这是用于柔滑放大/缩放动画的秘密调味料。
要将EasePack包含在项目中,您可以将其用作html文件中的脚本( index.html ):
<html>
<!--head-->
<body>
<!--other stuff-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/EasePack.min.js"></script>
<script src="main.js"></script> <!--animation code in here -->
</body>
</html>
或您可以在 main.js 中导入它:
// if you have the gsap package locally
import { gsap } from "gsap";
import { EasePack } from "gsap/EasePack";
gsap.registerPlugin(EasePack);
// using webpack or rollup
import { gsap, EasePack } from "gsap/all;
gsap.registerPlugin(EasePack);
//animation code here
docs for koude36有一个很好的解释,以下示例的演出。
让我们将其应用于我们的缩放版本。
let tl = gsap.timeline();
tl.fromTo(
"#titleSvg",
{ scale: 17 },
{ duration : 18, scale: 1, ease: ExpoScaleEase.config(17, 1) }
);
在这里,我们在18秒内从17到1个规模。配置函数具有以下签名:config( startingScale:Number, endingScale:Number, ease:Ease [optional] )
,因此我们提供比例值作为前2个参数。
尝试一下,它使我们想要的方式动画,但这很笨拙!
我们可以通过打开Chrome DevTools中的“框架渲染统计数据”来审查这一点。根据下面的屏幕截图,您将在Devtools底部的渲染选项卡上找到此选项。我不是Chrome Devtools布局的忠实拥护者。有时,底部窗格带有其他选项卡,例如渲染选项卡,看不到。如果看不到此,则必须在DevTool菜单栏中单击“溢出”按钮(3个垂直分配的点),然后选择“选项” 更多工具,然后选择渲染 em>。
如下所示,我们每秒获得23.4帧。理想情况下,这个酒吧是完全绿色的。如果框架掉落,则会看到红线。我们有很多红线! ð¥µ
让我们看看是否针对标题(字母和装饰盒),而不是整个SVG!
,它是否有所不同
现在,我们每秒获得近60帧(FPS)。没有红线! ð
很棒,但是等等,现在动画从标题文本的左上角开始。这是因为转换使用画布左上方的转换来源。
为了解决此问题,我使用了koude39方法将转换原点设置为画布的中心。
我使用koude40方法而不是fromTo()
进行动画。
tl.set("#title", { transformOrigin: "50% 50%", scale: 17 });
tl.to("#title", { duration: 18, scale: 1, ease: ExpoScaleEase.config(17, 1) });
现在,我们从正确的起点有60fps(或多或少)。
这是我们想要进入的直觉状态,不包括“执行制片人”信用。
这就是我们所拥有的:
我们被放大了太多,我们的焦点看上去了。忽略字母之间的间距,我们在下一步中倾向于这一点。我们只是关心现在的规模和焦点。
让我们尝试使用不同的值为scale
获得正确的缩放级别。尝试一些较小的值,5个看起来在球场上。
现在,让我们调整transform-origin
以更改焦点。我们想离开一点,因此我们将减少第一个数字(X-Origin)。然后,我们想稍作下降,因此会增加第二个数字(Y-Origin)。
tl.set("#title", { transformOrigin: "48% 70%", scale: 5 });
tl.to("#title", { duration: 18, scale: 1, ease: ExpoScaleEase.config(5, 1) });
这看起来更好。
在第2部分中,当我们移动字母的初始位置时,我们可能需要调整值。
方法2:使用z翻译
使用translateZ()
的一个陷阱是,您无法使用SVG元素进行3D转换(请参阅Stackoverflow问题How can I get translateZ to work in svg groups?)。因此,我们只能在SVG本身上执行我们的translateZ()
转换。
我们需要在SVG的母体上设置perspective
属性,以控制Z转换的感知距离。最好将我们的SVG用div
包裹,而不是让body
作为父母对布局的更多控制。现在,我们将对svg
的z
属性进行动画动画,以将SVG从观看者中移开。我们将z
在SVG上设置为正值,使其开始靠近查看器。这是JavaScript:
tl.set(".wrapper", {
perspective: 800,
});
tl.set("#titleSvg", {
z: 700,
});
gsap.to("#titleSvg", {
duration: 18,
z: 0,
ease: Power0.easeNone,
});
这有效,但它很笨拙!它是从飞溅开始的,然后逐渐消失至35 fps。
嗯,神秘的koude52 property怎么样?
此属性为浏览器提供了一个主题,我们将对特定属性进行动画,因此它可以优化并可能将其推向GPU。
tl.set("#titleSvg", {
z: 700,
willChange: "transform",
});
,这种加入使我们达到了近60 fps。
但是,我们不希望它移动这么快!线性易于ease: Power0.easeNone
实际上没有产生我们想要的恒定速率。我们正遇到与scale
相似的问题,在我们希望的方式上,宽松并不能控制动画的进展。
更改包装器div
上的perspective
的值以及SVG上的z
的值并没有太大的不同。我无法在正确的值中击中以获得所需的结果。
不幸的是,通过自定义放松和玩耍的价值观以我们想要的方式来获得这似乎是一件长途射击!
我注意到的另一个问题是,在动画开始时,它看起来有点模糊!请参阅下面的屏幕截图! ð
让我们暂时将其停放,然后使用第2部分的scale
解决方案,以查看我们是否想要的结果。
第2部分 - 字母的移动
我们需要在这里进行实验。这里的过程是将字母偏移到最终位置,然后在它们进入时开始移动它们。
概述时间表
让我们概述我们的时间表!这就是我从标题序列中推断出来的:
- 0.0S-> 8.0s:第一个单词的字母'a'和n'开始视为,并正在水平朝每个。
- 0.2s-> 9.2s:第二个单词的字母“ i”以0.25s的视图从相反的方向移动。这些字母之间的“ n”位于下面的偏移量。
- 1.0S-> 12.0s:第一个单词的字母'g'和第二个单词开始移动的字母'g'的速度非常缓慢。这是微妙的,可能会跳过。当他们触摸“ n”时,G的这一背面就伸直了。我需要做更多的工作来纳入它的这一方面。
- 4.0S-> 10.0s:第一个单词的字母'r'来自左侧。领先腿上的衬线与相邻的“ A”结合在一起。一些黑魔法在那里完成!
- 5.0s-> 10.0s:第二个单词的字母'n'来自下面。
- 9.0S-> 15.0S:第一个单词的字母't'从上方下降。
- 9.5S-> 14.0S:第二个单词的“ H”。它们位于外部的距离是相等的。
- 10.0s-> 17.0s:第一个单词的字母“ e”从上方下降。第二个单词的字母“ s”来自下面。
- 11.0S-> 17.0s:第一个单词的最后一个“ r”开始向左移动。
- 12.75s-> 17.0s:第一个单词的“ s”开始向右移动。
为第一个补间组织代码
让我们考虑一下我们如何做。
我们将为每个部分创建一个单独的时间表。我们将从第1部分命名为zoomTimeline
。
let zoomTimeline = gsap.timeline();
zoomTimeline.set("#title", { transformOrigin: "48% 70%", scale: 5 });
zoomTimeline.to("#title", {
duration: 18,
scale: 1,
ease: ExpoScaleEase.config(5, 1),
});
我们将这部分的时间表命名为lettersTimeline
。
出现的第一个字母是第一个单词的“ a”和“ n”。他们在一起。因此,我们需要将“ a”重新放在左侧(负x翻译),右侧的“ n”(正x翻译)。
let lettersTimeline = gsap.timeline();
lettersTimeline.set("#word1-a", { x: -20 });
lettersTimelin.set("#word1-n", { x: 20 });
如果我们评论scaleTimeline
代码,它看起来像这样:
现在,我们需要添加一个动画以将x
的值更改为零。
lettersTimeline.to("#word1-a, #word1-n", { x: 0, duration: 8 });
现在,我们可以删除scaleTimeline
代码并查看其外观。
我们可以调整值,直到对这两个字母感到满意。我们需要将它们移开更多,#word1-a
的x
,#word1-a
,x
of -30 for #word1-n
看起来更好。
我们需要重复此过程的其他字母。这并不复杂,但需要时间和耐心。
定位所有字母
在我们进一步之前,将所有字母放置可能更容易。这样,他们就不愿意一个人一个动画。目前不需要确切。当我们对它们进行动画化时,我们将完善这些位置。
我评论了scaleTimeline
,并为每个字母选择了一些值。这就是我最初设置它们的方式:
//first word: STRANGER
lettersTimeline.set("#word1-s", { x: -150 }); //prob should have same absolute value as #word2-r2
lettersTimeline.set("#word1-t", { y: -180 }); //prob should be same absolute value as #word2-h
lettersTimeline.set("#word1-r1", { x: -50 });
lettersTimeline.set("#word1-a", { x: -20 });
lettersTimeline.set("#word1-n", { x: 20 });
lettersTimeline.set("#word1-g", { x: 50 }); //prob should be same value as #word2-g
lettersTimeline.set("#word1-e", { y: -180 });
lettersTimeline.set("#word1-r2", { x: 150 }); //prob should have same absolute value as #word1-s
//second word: THINGS
// 'T' is static
lettersTimeline.set("#word2-h", { y: 180 }); //prob should be same absolute value as #word1-t
lettersTimeline.set("#word2-i", { x: -100 });
lettersTimeline.set("#word2-n", { y: 100 });
lettersTimeline.set("#word2-g", { x: 50 }); //prob should be same value as #word1-g
lettersTimeline.set("#word2-s", { y: 180 });
这应该可以阅读,因为字母是按顺序出现的!
唯一的事情是,正如您可以在注释中看到的那样,某些字母的值应被相同的绝对值所抵消。例如,对于我们动画的前两个字母,我们在X轴上移动了“ A”减去30,而X轴上的“ N”加30。它们是等待的。
拥有这些值的变量可能是有意义的,因此我们可以在以后进行调整,因为我们每次介绍了。
所以,这就是变量,没有评论:
let batch1Distance = 30;
let batch3Distance = 50;
let batch6and8Distance = 180;
let batch9and10Distance = 150;
//first word: STRANGER
lettersTimeline.set("#word1-s", { x: `-${batch9and10Distance}` });
lettersTimeline.set("#word1-t", { y: `-${batch6and8Distance}` });
lettersTimeline.set("#word1-r1", { x: -50 });
lettersTimeline.set("#word1-a", { x: `-${batch1Distance}` });
lettersTimeline.set("#word1-n", { x: `${batch1Distance}` });
lettersTimeline.set("#word1-g", { x: `${batch3Distance}` });
lettersTimeline.set("#word1-e", { y: -180 });
lettersTimeline.set("#word1-r2", { x: `${batch9and10Distance}` });
//second word: THINGS
// 'T' is static
lettersTimeline.set("#word2-h", { y: `${batch6and8Distance}` });
lettersTimeline.set("#word2-i", { x: -130 });
lettersTimeline.set("#word2-n", { y: 100 });
lettersTimeline.set("#word2-g", { x: `${batch3Distance}` });
lettersTimeline.set("#word2-s", { y: 180 });
现在看起来像这样了!
第二批和添加标签
让我们现在做下一封信。这是第二个单词的“我”。
我将使用标签来分组,以跟踪我在做什么。您可以使用标签而不是使用raw数字来用于position
参数(最后一个参数)。
lettersTimeline
.addLabel("batch1", 0)
.addLabel("batch2", 0.2)
.to("#word1-a, #word1-n", { x: 0, duration: 8 }, "batch1")
.to("#word2-i", { x: 0, duration: 9 }, "batch2");
如果您可以提出好名字,这可以使阅读更容易阅读。在这种情况下我不能!
以前,我们在使用set()
放置我们的字母方面做了艰苦的工作。现在,我们需要更改Animaiton的值很简单。我们将x
或y
值设置为零,然后选择适当的duration
。
这封信的出现比我们想要的要早一些,因此我将值从-100降低到130,因此在正确的时间进行了屏幕。
这是前2批的完整代码:
通过时间表进行专注于单个二聚体的过程
包括一个小仪表板来控制时间表可能很不错,因此您可以创建一个较短的反馈循环,其中包括您正在使用的时间表的部分。您必须这样做不必这样做,但可以使您的生活更轻松。
没有某些控件,您可以发现自己评论代码并使用临时值来磨练时间表的特定部分。我可以在另一个时间单独的话题中介绍这个想法。
一个很好的替代方法是编写一些代码以在时间轴中设置起点。我们可以创建一个currentPoint
变量来设置我们的临时起点。我们最初使用pause()
来暂停时间表,然后使用seek()
函数将时间表移至currentPoint
,然后使用play()
函数从那时开始。这样的东西:
let currentPoint = 1; //in seconds (decimal allowed)
let zoomTimeline = gsap.timeline();
zoomTimeline.pause();
//setting of values and tweens
let lettersTimeline = gsap.timeline();
lettersTimeline.pause();
//setting of values and tweens
zoomTimeline.seek(currentPoint);
lettersTimeline.seek(currentPoint);
zoomTimeline.play();
lettersTimeline.play();
上面的代码将以1秒标记启动时间表,这是我们想要开始的第三批次开始的地方。因此,添加批次的代码,即第一个单词的字母“ r”,看起来像这样:
字母批次4至10
我不会掩盖其余的字母。它们是我们在本节中讨论的所有内容的变体。我希望我对事情进行了清晰的解释,如果您不得不,您可以自己完成!
第3部分 - 装饰盒的扩展
我们可以使用scaleX()
转换水平扩展框。
要确定扩展的方向,我们设置了transformOrigin
:
- 如果您希望它从中心扩展,则可以
transformOrigin: 50% 50%
。我们希望顶框这样做。
- 如果您希望它从左到右扩展,则可以设置
transformOrigin: 0% 50%
。我们希望右下的框来做。
- 如果您希望它向右扩展到左侧,则可以设置
transformOrigin: 100% 50%
。我们希望左下的框来做。
序列是顶部框首先扩展,持续时间为1秒。然后,在完全扩展之前不久,底部的2个盒子扩展了,大约需要四分之三。它们重叠约半秒钟。
代码在下面。
在此版本中,动画立即运行,但在最终版本中,该序列大约15秒钟进入完整的标题序列。
第4部分 - 淡出
最后一部分是标题中的淡出。
我们将称此时间表 - visibilityTimeline
!你的男孩能说出东西不能吗? ðü£
淡出标题很简单,对吗?我们创建了将opacity
设置为零的补间。
let visibilityTimeline = gsap.timeline();
visibilityTimeline.to("#title", { opacity: 0, duration: 1.5 });
您可以,但是在这种情况下可能会忽略一个额外的元素!有一个小插图效应,不是均匀的褪色。正如您在下面的屏幕截图中看到的那样,实际上标题的外部以渐变的方式变暗。
我们可以使用包含koude88形状的koude87实现这一目标。
我发现最容易找到正确的位置和大小是将koude88元素添加为页面内部SVG的最后一个元素。我给它一个属性:fill=white
和opacity=0.5
。这样,我可以看到下面的标题。
我为fill
选择白色,因为对于面具,白色是透明的部分,较深的颜色是半op的。
现在,我尝试为ellipse
的属性提供值,例如:cx
,cy
,rx
和ry
,以便我可以按照自己想要的方式获得大小并塑造。要在面具的边缘周围给出一个稍暗的带,我们添加了一个stroke
并使用浅灰色使其略微不透明。
一旦我们对结果感到满意,我们就可以从ellipse
中删除opacity="0.5"
并将其放入mask
元素中。这样的东西:
<svg>
<defs>
<mask id="spotReveal">
<ellipse
fill="white"
stroke="#d6d6d6"
cx="600"
rx="600"
stroke-width="80"
ry="300"
cy="380"
></ellipse>
</mask>
<!--our gradients are in here too-->
</defs>
<rect id="bg" width="1200" height="800" />
<g id="title" mask="url(#spotReveal)">
<!--boxes and letters here-->
</g>
</svg>
使用掩码的id
用作参考。我们将蒙版应用于“标题”组(g
元素,带有“标题的id
”),带有mask="url(#spotReveal)"
。
在JavaScript中,我们可以对ellipse
进行动画操作,以通过scale
缩小大小,并减少opacity
以创建Vignette Fadeout效果。
使其更容易可视化面具的效果,这是没有2秒持续时间的补间。我不是 为了清楚地显示椭圆的尺寸。
请注意,我们还为椭圆设置了transformOrigin: "50% 50%"
。 SVGS的默认transform-origin
是启动左上角。我们希望它从中心扩展。
现在,让我们更改补间以获取想要的结果。我们需要更改补间,以将opacity
减少到零,以使整个标题淡出。我们也需要使duration
也短。现在,看起来像这样:
有时令人惊讶的是,一些细节如何提升某些东西,有时它们可能会不受影响。当您加快这样的速度时,很容易错过细节!
在最终版本中,这发生在动画中18秒钟。
将所有这些放在一起
当我将4个部分添加在一起时,我注意到性能的大量退化! ð¥
由于它从一开始就发生了,所以我专注于动画的第一部分,以了解问题可能是什么。这使我研究了第3部分和第4部分所应用的东西,但并不重要。我从“标题”组中删除了第4部分中使用的面具,那是坏人!
我们只有在需要时才将蒙版设置在标题上。在visibilityTimeline
中,我们可以在使用onStart
属性开始时间线时设置该属性。
visibilityTimeline.to("#spotReveal ellipse", {
scale: 0.6,
opacity: 0,
duration: 2,
onStart: () => {
document.querySelector("#title").setAttribute("mask", "url(#spotReveal)");
},
});
我应该将4个时间表组合到一个时间表中吗?
作为第一个努力,更容易在主时间轴中嵌套时间表。这样,我们就不需要更改代码,并且可以保留从命名中获得的信息。
要嵌套时间表,您可以将其包装在功能中,然后将该函数调用到主时间轴的add()
函数中。这是我们代码的骨架:
function part1() {
// scaleTimeline stuff
}
function part2(){
//letterTimeline stuff
}
function part3(){
//letterTimeline stuff
}
function part4(){
//visibilityTimeline stuff
}
const masterTimeline = gsap.timeline();
masterTimeline
.add(part1(), 0)
.add(part2(), 0)
.add(part3(), 15) // call at 15 second mark
.add(part4(), 19);
,随着值的调整以使事情变得更紧,这是结果:
这很好!它的外观可以改善,但动画的性能非常好。它的平均镀铬平均约为55 fps。我在Chrome DevTools中录制了性能,这表明很少有帧被删除。请参阅下面的屏幕截图中的单词 frames 在同一行上的红色条。
在这里,它在chrome中的统计数据中呈现显示。
有几个点框架下降。如上所述,当很多字母立即移动时,它是在下降的时候。可以审查这是否可以进行一些改进。
没有合成器配乐,它不完全相同,所以接下来我们将添加。
添加音频
随附的配乐很好地补充了序列。我认为没有它并不完全相同。让我们添加歌曲以与动画同步播放。
最初这首歌被静音。我在右上角添加了一个静音切换按钮(从技术上讲,一个复选框)以启用歌曲。您可能需要进行取消静脉切换,然后单击标题重新启动动画以听到音频,这是因为某些浏览器默认情况下由用户启动的音频。
它与我在本系列的Schitt Creek标题序列中使用的代码相同,您可以访问the "Adding audio" section of that post以了解更多信息。
吐和抛光
让我们尝试将其抛光,并使额外的5%至10%的增长。首要任务是梯度。
抛光梯度
这是我最讨厌的部分,因为我发现Inkscape中的编辑梯度很笨拙!
我遍历了每个字母,并给了每个字母一个个体梯度。我保持了颜色较高的饱和度和浅色。我希望使用具有更平滑过渡的颜色,并使用不同的色调来进行更加照明的边缘。您可以在下面的这项工作之前和之后看到并排比较。
最大的胜利是刺耳的模式消失了。我认为使用更多细微差别的梯度可以使其具有更高的反射性质量。
这花了我一段时间才能做到!我不得不反对自己的自然倾向,以减少某些颜色的饱和度和轻盈。
都需要在整个过程中变得明亮和大胆。
添加衬线的黑魔法变形
我们可以添加的第二种抛光是“黑魔法”,它导致第一个单词(r,a和n)中某些相邻字母的重叠的串行连接。
为了实现这一目标,我在SVG上添加了一些黑匣子(rect
元素),并将它们放在字母最终重叠的点 - 我按照下面的屏幕截图将它们涂成黄色。
这个想法是最初隐藏框,当字母到达重叠点时,我将通过opacity
属性或通过比例转换来使它们动画。我为此添加了另一个时间表,您可以在最终版本中看到它是polish
函数!它确实为最终外观增加了一点,尤其是当放大时。
我们可以添加阴影吗?
使用过滤器为发光的霓虹灯效应添加一些阴影,噪音和模糊,这可能是对其他一切进行动画的负担。让我们看看而不是推测!我将优化SVG,看看我能得到多近。
优化SVG后,我再次通过菜单中添加了一个“滴影”过滤器 - 选择 filter> filter >> shadows and Glow >> 滴影.. 。我添加了一个半透明的红色颜色和模糊半径为3的阴影。这就是外观:
在此版本中,您可以欣赏我们之前获得的第一个单词字母的衬线!
无论如何,我在动画中使用了此版本,我惊讶地发现Chrome可以很好地处理它,并且以55 fps的速度运行。但是,Firefox无法处理,动画确实分解了!
在最终版本中,我添加了一个复选框,如果您想使用它,请打开阴影,并实时查看性能的退化。
最终动画
为了方便起见,这是最终版本。
在codepen上给它!
包起来
这是一段旅程!我为自己的动画达到了高水平而感到自豪。
我一路上学到了一些东西,这使它值得。它需要很多耐心才能完成详细的工作,以将其从好处提高到好。我能够通过独自留几个星期来做到这一点,然后用新鲜的头再次回来以再次解决一些乏味的部件。
在本系列中,我探索了是否可以作为CSS动画做动画。在这种情况下,无需进一步调查!这不可能。我们需要JavaScript为标题的平滑缩放提供特殊的宽松,这就是我在第1部分中涵盖的一切。 /p>
这种苛刻的动画演示了动画HTML或SVG的上限。如果您想要对字母嘈杂的霓虹灯发光的更多逼真的效果,那么对SVG过滤器进行动画效果太大了,浏览器无法与其他转换一致。为了使视频完美地重复,您需要使用Canvas或Web GL进行动画。也许我可以再试一次。 Web GL是我想学习的。
感谢您的阅读!