{"id":205895,"date":"2015-08-03T06:00:39","date_gmt":"2015-08-03T13:00:39","guid":{"rendered":"http:\/\/css-tricks.com\/?p=205895"},"modified":"2015-08-03T20:30:49","modified_gmt":"2015-08-04T03:30:49","slug":"debugging-css-keyframe-animations","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/debugging-css-keyframe-animations\/","title":{"rendered":"Debugging CSS Keyframe Animations"},"content":{"rendered":"<p>Creating CSS animations may be about learning the syntax, but mastering a beautiful and intuitive-feeling animation requires a bit more nuance. Since animations command so much attention, it&#8217;s important to refine our code to get the timing right and debug things when they go wrong. After tackling this problem myself, I thought I&#8217;d collect some of the tools that exist to aid in this process.<\/p>\n<p><!--more--><\/p>\n<h3>Using Negative Delay Values<\/h3>\n<p>Say you have multiple animations running at the same time and you&#8217;d like them to stagger just a bit. You can use <a href=\"https:\/\/css-tricks.com\/almanac\/properties\/a\/animation\/#almanac-animation-delay\"><code>animation-delay<\/code><\/a>, but don&#8217;t necessarily want the viewer to visit the page and have some things not moving, waiting for their delay. <\/p>\n<p>You can set <code>animation-delay<\/code> to a negative number, and it will push the playhead back in time, so that all animations are running when the viewer shows up. This is particularly useful when the animations share the same keyframe values and are differentiated in movement only by the delay. <\/p>\n<p>You can use this concept for debugging. Set <code>animation-play-state: paused;<\/code> and then adjust the delay to different negative times. You&#8217;ll see the animation in different paused states along the tween. <\/p>\n<pre rel=\"CSS\"><code class=\"language-css\">.thing {\r\n  animation: move 2s linear infinite alternate;\r\n  animation-play-state: paused;\r\n  animation-delay: -1s;\r\n}<\/code><\/pre>\n<p>Example:<\/p>\n<p data-height=\"268\" style=\"height: 268px; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1rem 0; padding: 1rem; overflow: auto;\" data-theme-id=\"1\" data-slug-hash=\"LVMMGZ\" data-default-tab=\"result\" data-user=\"css-tricks\" class='codepen'>See the Pen <a href=\"http:\/\/codepen.io\/team\/css-tricks\/pen\/LVMMGZ\/\" rel=\"noopener\">LVMMGZ<\/a> by CSS-Tricks (<a href=\"http:\/\/codepen.io\/css-tricks\" rel=\"noopener\">@css-tricks<\/a>) on <a href=\"http:\/\/codepen.io\" rel=\"noopener\">CodePen<\/a>.<\/p>\n<p>In a fun demo, we see the two robotters hovering at a very slightly different time in order to feel a little more natural. We give the purple robotter a negative delay when we declare the hovering animation so that he&#8217;s moving when the viewer first sees the page.<\/p>\n<pre rel=\"CSS\"><code class=\"language-css\">.teal {\r\n animation: hover 2s ease-in-out infinite both;\r\n}\r\n \r\n.purple {\r\n animation: hover 2s -0.5s ease-in-out infinite both;\r\n}\r\n \r\n@keyframes hover {\r\n  50% {\r\n    transform: translateY(-4px);\r\n  }\r\n}<\/code><\/pre>\n<p data-height=\"525\" style=\"height: 525px; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1rem 0; padding: 1rem; overflow: auto;\" data-theme-id=\"1\" data-slug-hash=\"qdLJLJ\" data-default-tab=\"result\" data-user=\"sdras\" class='codepen'>See the Pen <a href=\"http:\/\/codepen.io\/sdras\/pen\/qdLJLJ\/\" rel=\"noopener\">Robotter Love<\/a> by Sarah Drasner (<a href=\"http:\/\/codepen.io\/sdras\" rel=\"noopener\">@sdras<\/a>) on <a href=\"http:\/\/codepen.io\" rel=\"noopener\">CodePen<\/a>.<\/p>\n<h3>The Pains of Multiple Transform Values<\/h3>\n<p>For best possible performance, you should also be moving and changing things with <a href=\"https:\/\/css-tricks.com\/almanac\/properties\/t\/transform\/\"><code>transform<\/code><\/a>, and save yourself from the cost of repaints with margin, or top\/left and the like. Paul Lewis has a great resource called <a href=\"http:\/\/csstriggers.com\/\" rel=\"noopener\">CSS Triggers<\/a> that break down these costs in an easy-to-see table. The gotcha here is that if you try to move things with multiple transforms, there are a number of problems. <\/p>\n<p>One big problem is ordering. Transforms will not be applied simultaneously as one might expect, but rather, in an order of operation. The first operation done is the one furthest on the right, then inwards. For example, in the code below, the scale will be applied first, then the translate, then the rotate.<\/p>\n<pre rel=\"CSS\"><code class=\"language-css\">@keyframes foo {\r\n to {\r\n   \/*         3rd           2nd              1st      *\/\r\n   transform: rotate(90deg) translateX(30px) scale(1.5);\r\n }\r\n}<\/code><\/pre>\n<p>In most situations, this is not ideal. It&#8217;s more likely that you&#8217;d rather all to happen concurrently. Furthermore, this becomes far more complex when you begin splitting the transforms into multiple keyframes with some values at the same time and some not, like so:<\/p>\n<pre rel=\"CSS\"><code class=\"language-css\">@keyframes foo {\r\n  30% {\r\n    transform: rotateY(360deg);\r\n  }\r\n  65% {\r\n    transform: translateY(-30px) rotateY(-360deg) scale(1.5);\r\n  }\r\n  90% {\r\n    transform: translateY(10px) scale(0.75);\r\n  }\r\n}<\/code><\/pre>\n<p>This will lead to somewhat surprising, and less than ideal results. The answer, unfortunately, is often to use multiple nested <code>&lt;div&gt;<\/code>s, applying a single translation to each, so that no conflicts arise.<\/p>\n<p data-height=\"419\" style=\"height: 419px; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1rem 0; padding: 1rem; overflow: auto;\" data-theme-id=\"1\" data-slug-hash=\"bdOvJL\" data-default-tab=\"result\" data-user=\"sdras\" class='codepen'>See the Pen <a href=\"http:\/\/codepen.io\/sdras\/pen\/bdOvJL\/\" rel=\"noopener\">Show Order of Operations Transform Fail<\/a> by Sarah Drasner (<a href=\"http:\/\/codepen.io\/sdras\" rel=\"noopener\">@sdras<\/a>) on <a href=\"http:\/\/codepen.io\" rel=\"noopener\">CodePen<\/a>.<\/p>\n<p>There are some alternatives, such as using matrix transforms (not intuitive to code by hand) or to use a JavaScript animation API such as <a href=\"http:\/\/greensock.com\/\" rel=\"noopener\">GreenSock<\/a>, where there is no ordering sequence for multiple transform interpolations.<\/p>\n<p>The multiple div implementation can also help with troubling bugs with SVG. In Safari, you can&#8217;t declare opacity and transform in animation at the same time &mdash; one will fail. You can see the workaround in action in the first demo in this article. <\/p>\n<p>In early August 2015, <a href=\"https:\/\/drafts.csswg.org\/css-transforms-2\/#individual-transforms\" rel=\"noopener\">independent transform declarations<\/a> have moved into Chrome Canary. This means we won&#8217;t have to worry about ordering much longer. You&#8217;ll be able to declare <code>rotate<\/code>, <code>translate<\/code>, and <code>scale<\/code> separately. <\/p>\n<h3>DevTools Timing Helpers<\/h3>\n<p>Both <a href=\"http:\/\/valhead.com\/2015\/01\/06\/quick-tip-chrome-animation-controls\/\" rel=\"noopener\">Chrome<\/a> and <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Tools\/Page_Inspector\/How_to\/Work_with_animations\" rel=\"noopener\">Firefox<\/a> now ship with some tools specificially for helping work with animations. They offer a slider for controlling the speed, a pause button, and UI for working with the easing values. Slowing things way down, and seeing the animation at particular stopped points is pretty darn helpful for debugging CSS animations.<\/p>\n<p>They both use Lea Verou&#8217;s <a href=\"http:\/\/cubic-bezier.com\/\" rel=\"noopener\">cubic-bezier.com<\/a> visualization and GUI. This is extraordinarily helpful, as you no longer have to do the back-and-forth from cubic-bezier.com to text editor to proofing. <\/p>\n<p>These tools allow us to fine-tune our animations much more intuitively. Here&#8217;s a look at the UI offered in both:<\/p>\n<figure id='post-205912' class='align-none media-205912'><img data-recalc-dims=\"1\" src=\"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2015\/11\/chrome-devopt2.jpg\" alt='' \/><img data-recalc-dims=\"1\" src=\"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2015\/11\/firefox-dev-opt2.jpg\" alt='' \/><\/figure>\n<p>Both Chrome and Firefox allows you to control the timing (speed up or slow down), and also manually scrub through the animation. More advanced timeline tools <a href=\"https:\/\/www.youtube.com\/watch?v=U9xfYbKxosI\" rel=\"noopener\">are coming in Chrome<\/a> that can look at multiple elements at at time. That will be nice, as working with only a single element at a time in an animation is fairly big limiting factor.<\/p>\n<p>One thing I have some trouble with is grabbing the element quickly enough if the animation is short-lived and fast. In those cases, I&#8217;ll usually set it to <code>animation-iteration-count: infinite;<\/code> so that I can continue to play with it without having to fight time.<\/p>\n<p>I also find it extremely helpful to slow the animation way down and then replay and adjust the timing in the browser with these tools. It allows you to pull apart each movement at a fundamental level and see how everything is interacting and what the motion progress looks like. If you refine it at that speed, when you adjust it to play faster, it will look much more masterful.<\/p>\n<h3>Debugging CSS Animation Events with JavaScript<\/h3>\n<p>If you&#8217;d like to figure out exactly where and when each animation is fired, you can use a little JavaScript to detect and alert you to when each event is occurring, by hooking into <code>animationstart<\/code>, <code>animationiteration<\/code> and <code>animationend<\/code>. <\/p>\n<p>Here&#8217;s a demo of that:<\/p>\n<p data-height=\"409\" style=\"height: 409px; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1rem 0; padding: 1rem; overflow: auto;\" data-theme-id=\"1\" data-slug-hash=\"PqXeMX\" data-default-tab=\"result\" data-user=\"sdras\" class='codepen'>See the Pen <a href=\"http:\/\/codepen.io\/sdras\/pen\/PqXeMX\/\" rel=\"noopener\">Showing how to Debug Animation Play States in JavaScript<\/a> by Sarah Drasner (<a href=\"http:\/\/codepen.io\/sdras\" rel=\"noopener\">@sdras<\/a>) on <a href=\"http:\/\/codepen.io\" rel=\"noopener\">CodePen<\/a>.<\/p>\n<h3>Keep Keyframes Concise<\/h3>\n<p>I often see people declare the same property and value at the 0% keyframe and 100% keyframe. This is unnecessary and leads to bloated code. The browser will take the properties value as the initial and ending value by default.<\/p>\n<p>Meaning this is overkill:<\/p>\n<pre rel=\"CSS\"><code class=\"language-css\">.element {\r\n animation: animation-name 2s linear infinite;\r\n}\r\n \r\n@keyframes animation-name {\r\n  0% {\r\n   transform: translateX(200px);\r\n }\r\n  50% {\r\n   transform: translateX(350px);\r\n }\r\n 100% {\r\n   transform: translateX(200px);\r\n }\r\n}\r\n <\/code><\/pre>\n<p>It could be written like this:<\/p>\n<pre rel=\"CSS\"><code class=\"language-css\">.element {\r\n transform: translateX(200px);\r\n animation: animation-name 2s linear infinite;\r\n}\r\n \r\n@keyframes animation-name {\r\n  50% {\r\n   transform: translateX(350px);\r\n }\r\n}<\/code><\/pre>\n<h3>DRY-ing Out Animations<\/h3>\n<p>Creating a beautiful and succinct animation usually means writing a very specific <code>cubic-bezier()<\/code> easing function. A fine-tuned easing function works similarly to a company&#8217;s palette. You have your own specific branding and &#8220;voice&#8221; in your motion. If you&#8217;re using this all over a website, (and you should, for consistency) the easiest way to do so is to store one or two easing functions in a variable, just as we do with our palettes. SASS and other pre\/post processors make that simple:<\/p>\n<pre rel=\"SCSS\"><code class=\"language-scss\">$smooth: cubic-bezier(0.17, 0.67, 0.48, 1.28);\r\n \r\n.foo { animation: animation-name 3s $smooth; }\r\n \r\n.bar { animation: animation-name 1s $smooth; }<\/code><\/pre>\n<p>When animating with CSS keyframes, we want as much help from the GPU as possible. That means that if you&#8217;re animating multiple objects, you want a way to easily prepare the DOM for the incoming movement and layerize the element. You can hardware accelerate a native DOM element (not SVG) with CSS by using a standard declaration block. Since we reuse that on all of the elements we\u2019re animating, it makes sense to save some typing, and add this in using a mixin or extend:<\/p>\n<pre rel=\"SCSS\"><code class=\"language-scss\">@mixin accelerate($name) {\r\n will-change: $name;\r\n transform: translateZ(0);\r\n backface-visibility: hidden;\r\n perspective: 1000px;\r\n}\r\n\r\n.foo {\r\n  @include accelerate(transform);\r\n}<\/code><\/pre>\n<p>Be careful. Offloading too many elements at once can cause an inverse effect and performance to tank. Most animations should be fine, but be aware of this if you&#8217;re using something like haml to generate tons of DOM elements.<\/p>\n<h3>Loops for Better Performance<\/h3>\n<p>Smashing Magazine recently published a <a href=\"http:\/\/www.smashingmagazine.com\/2015\/06\/the-making-of-in-pieces\/\" rel=\"noopener\">great piece<\/a> showing the work behind the fantastic project, <a href=\"http:\/\/species-in-pieces.com\/\" rel=\"noopener\">Species in Pieces<\/a>. In one particular section, the author goes into detail about how animating all of the pieces at one was causing performance problems. He states:<\/p>\n<blockquote><p>Imagine that you&#8217;re moving 30 objects at the same time; you are asking a lot of the browser, and it makes sense that this would create problems. If you have a speed of 0.199 seconds and a delay of 0.2 seconds on each object, you would fix the problem by moving only one object at a time. The fact that the same amount of total movement happens doesn&#8217;t matter: If the animation is done as a chain, performance is immediately improved by 30 times.<\/p><\/blockquote>\n<p>You can take advantage of Sass or other pre\/post-processor <code>for<\/code> loops for this kind of functionality. Here\u2019s a pretty simple one that I wrote to loop through nth-child:<\/p>\n<pre rel=\"SCSS\"><code class=\"language-scss\">@for $i from 1 through $n {\r\n  &amp;:nth-child(#{$i}) {\r\n    animation: loadIn 2s #{$i*0.11}s $easeOutSine forwards;\r\n  }\r\n}<\/code><\/pre>\n<p>Not only that, but you can use them to stagger visual effects like color as well. (Hit replay to rerun the animation.)<\/p>\n<p data-height=\"362\" style=\"height: 362px; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1rem 0; padding: 1rem; overflow: auto;\" data-theme-id=\"1\" data-slug-hash=\"RPEMZr\" data-default-tab=\"result\" data-user=\"sdras\" class='codepen'>See the Pen <a href=\"http:\/\/codepen.io\/sdras\/pen\/RPEMZr\/\" rel=\"noopener\">SASS for loops in CSS Animations<\/a> by Sarah Drasner (<a href=\"http:\/\/codepen.io\/sdras\" rel=\"noopener\">@sdras<\/a>) on <a href=\"http:\/\/codepen.io\" rel=\"noopener\">CodePen<\/a>.<\/p>\n<h3>Adjust Many Animations in Sequence<\/h3>\n<p>When you&#8217;re creating longer animations, the way to sequence multiple animations or events is usually to chain them together with progressive delays. So something like:<\/p>\n<pre rel=\"CSS\"><code class=\"language-css\">animation: foo 3s ease-in-out, bar 4s 3s ease-in-out, brainz 6s 7s ease-in-out;<\/code><\/pre>\n<p>But let&#8217;s say you&#8217;re making refinements, and you discover that the second count of the first animation should change. This affects the delays of everything following it, so let&#8217;s adjust our timing for each one after. No big deal.<\/p>\n<pre rel=\"CSS\"><code class=\"language-css\">animation: foo 2.5s ease-in-out, bar 4s 2.5s ease-in-out, brainz 6s 6.5s ease-in-out;<\/code><\/pre>\n<p>But now let&#8217;s add another animation and adjust the timing of the second one again (this kind of fine-tuning happens all the time when creating a really nice animation in production). Well, this is starting to become a little inefficient. If you do that 3 more times, it&#8217;s <em>really<\/em> inefficient.<\/p>\n<p>Then imagine halfway through the animation two things have to fire at once so you have to keep consistent timing with two different properties and\u2026 well, you get it. <strong>That&#8217;s why anytime I get beyond three or four chained animations in a sequence, I usually switch to JavaScript.<\/strong> Personally, I like the <a href=\"https:\/\/greensock.com\/\" rel=\"noopener\">GreenSock animation API<\/a> because it has a very robust timeline functionality, but most JS animation will allow for you to easily stack animation without any recalculation which is definitely a workflow boon.<\/p>\n<h3>\u221e<\/h3>\n<p>Making an animation work well is so much more than just building it. Typically, it&#8217;s the editing, refining, and debugging that take a project from merely moving to a well-orchestrated and performant piece. Hopefully these tips put a few more tools in your toolbox and smooth some rough edges in your workflow.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Creating CSS animations may be about learning the syntax, but mastering a beautiful and intuitive-feeling animation requires a bit more [&hellip;]<\/p>\n","protected":false},"author":7699,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[4],"tags":[],"class_list":["post-205895","post","type-post","status-publish","format-standard","hentry","category-articles"],"acf":{"show_toc":"No"},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":179881,"url":"https:\/\/css-tricks.com\/starting-css-animations-mid-way\/","url_meta":{"origin":205895,"position":0},"title":"Starting CSS Animations Mid-Way","author":"Chris Coyier","date":"August 19, 2014","format":false,"excerpt":"Say you have a @keyframe animation that animates an element all the way across the screen. From off the left edge to off the right edge. You apply it to multiple elements. But you don't want all the elements to start at the same exact position. You can change the\u2026","rel":"","context":"In &quot;Articles&quot;","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":244442,"url":"https:\/\/css-tricks.com\/staggering-animations\/","url_meta":{"origin":205895,"position":1},"title":"Staggering Animations","author":"David DeSandro","date":"August 16, 2016","format":false,"excerpt":"The following is a guest post by David DeSandro. David wanted to offer a new feature in Isotope: staggered animations. Like so many things web, there are lots of ways he could have approached it. Here he looks at some of the possibilities, the advantages and disadvantages of each, and\u2026","rel":"","context":"In &quot;Articles&quot;","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":311206,"url":"https:\/\/css-tricks.com\/a-new-way-to-delay-keyframes-animations\/","url_meta":{"origin":205895,"position":2},"title":"A New Way to Delay Keyframes Animations","author":"Eric Johnson","date":"June 2, 2020","format":false,"excerpt":"If you\u2019ve ever wanted to add a pause between each iteration of your CSS @keyframes animation, you\u2019ve probably been frustrated to find there\u2019s no built-in way to do it in CSS. Sure, we can delay the start of a set of @keyframes with animation-delay, but there's no way to add\u2026","rel":"","context":"In &quot;Articles&quot;","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/05\/shooting-stars.gif?fit=800%2C400&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/05\/shooting-stars.gif?fit=800%2C400&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/05\/shooting-stars.gif?fit=800%2C400&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/05\/shooting-stars.gif?fit=800%2C400&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":357239,"url":"https:\/\/css-tricks.com\/a-handy-little-system-for-animated-entrances-in-css\/","url_meta":{"origin":205895,"position":3},"title":"A Handy Little System for Animated Entrances in CSS","author":"Neale Van Fleet","date":"November 26, 2021","format":false,"excerpt":"I love little touches that make a website feel like more than just a static document. What if web content wouldn\u2019t just \u201cappear\u201d when a page loaded, but instead popped, slid, faded, or spun into place? It might be a stretch to say that movements like this are always useful,\u2026","rel":"","context":"In &quot;Articles&quot;","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/11\/pop-in.gif?fit=900%2C450&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/11\/pop-in.gif?fit=900%2C450&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/11\/pop-in.gif?fit=900%2C450&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/11\/pop-in.gif?fit=900%2C450&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":255880,"url":"https:\/\/css-tricks.com\/repeatable-staggered-animation-three-ways-sass-gsap-web-animations-api\/","url_meta":{"origin":205895,"position":4},"title":"Repeatable, Staggered Animation Three Ways: Sass, GSAP and Web Animations API","author":"Opher Vishnia","date":"July 4, 2017","format":false,"excerpt":"Staggered animation, also known as \"follow through\" or \"overlapping action\" is one of the twelve Disney principles of animation as defined by Ollie Johnston and Frank Thomas in their 1981 book \"The Illusion of Life\". At its core, the concept deals with animating objects in delayed succession to produce fluid\u2026","rel":"","context":"In &quot;Articles&quot;","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":372850,"url":"https:\/\/css-tricks.com\/hacking-css-animation-state-and-playback-time\/","url_meta":{"origin":205895,"position":5},"title":"Hacking CSS Animation State and Playback Time","author":"Lu Wang","date":"September 6, 2022","format":false,"excerpt":"CSS-only Wolfenstein is a little project that I made a few weeks ago. It was an experiment with CSS 3D transformations and animations. Inspired by the FPS demo and another Wolfenstein CodePen, I decided to build my own version. It is loosely based on Episode 1 - Floor 9 of\u2026","rel":"","context":"In &quot;Articles&quot;","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2022\/08\/hacking-css-animations.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2022\/08\/hacking-css-animations.jpg?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2022\/08\/hacking-css-animations.jpg?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2022\/08\/hacking-css-animations.jpg?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2022\/08\/hacking-css-animations.jpg?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/205895","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/7699"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=205895"}],"version-history":[{"count":39,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/205895\/revisions"}],"predecessor-version":[{"id":206029,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/205895\/revisions\/206029"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=205895"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=205895"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=205895"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}