CSS Box Shadow-Animated Pixel Art Flickering - html

Partly for funsies, and partly for a design idea I had, I'm trying to convert an animated gif into pure animated CSS.
It's very nearly working but I've hit a snag and am unsure what is causing my issue, or how I could fix it. I have an unfortunate suspicion that I've simply hit a limitation of the technology.
The gif I've been using for testing is this: https://us.v-cdn.net/5018289/uploads/editor/yj/lcdjneh1yoxv.gif
As for the actual CSS, I've been trying to implement the method here (animated box-shadow properties), as it seemed like the most feasible: https://codepen.io/andrewarchi/pen/OXEEgL
#ash::after {
animation: ash-frames 0.4s steps(1) infinite;
}
#keyframes ash-frames {
0% {box-shadow: 32px 8px #181818, 40px 8px #181818,...}
...
}
The animation seems fairly seamless in the given example, so I figured it was worth a try. Obvious differences: the gif I'm using has more frames and more pixels.
And just as a quick overview, my CSS (I am using vendor tags etc, this is just an example):
.pixel-art-3940::after {
animation: pixel-art-3940-frames 1s steps(5, end) infinite;
}
#keyframes pixel-art-3940-frames {
0% {box-shadow: 112px 68px rgba(77, 69, 64, 1),...}
16.666666666666668% {box-shadow:115px 65px rgba(77, 69, 64, 1),...}
...
}
The animation does seem to be actually working, however there's an intense 'flickering' effect on the animation. See below:
I've tried the usual solutions to 'flickering transitions' in Chrome - such as setting -webkit-backface-visibility to hidden - but so far nothing has solved the issue.
As I said, I fear I've simply hit a limitation of the technology itself. Any ideas what the problem might be, and whether I can solve it?
EDIT: The full source code of this particular animation can be found in these two Gists. I opted for Gists because of the size of the CSS file.
HTML: https://gist.githubusercontent.com/ChrGriffin/2f1f221143e24d3e39cad8e7369bc167/raw/16ea77d21aa79cf9da52fc3477a6773af41130f2/image.html
CSS: https://gist.githubusercontent.com/ChrGriffin/7dcff0f119532ff37f68c01a8a22ecb5/raw/3e49d3dd0b7fa93aef6708750770d2616c53f682/image.css

Correct answer
In the end, it was all due to the animation-timing-function. First param in steps() function is not the number of keyframes (or number of steps in the loop) but the number of steps rendered in between keyframes.
So changing it to steps(1,end) fixes it, as the browser no longer has to calculate intermediary frames (where it obviously fails due to the large number of box-shadow values - there's basically 1 value for each pixel - wicked technique, btw).
See it working: https://jsfiddle.net/websiter/wnrxmapu/2/
Previous answer: (partially incorrect, led to the correct one above - i left it as it might prove helpful to others debugging similar animations):
Initially I thought your exporting tool was... simply wrong.
Why? Because increasing animation-duration from 1s to 100s produced this result.
The apparent conclusion is that your intermediary frames are bugged.
However, I tested each of them individually and, to my surprise, they rendered correctly.
Which leads to the conclusion that the number of box-shadow calculations per keyframe is limited and some sort of clustering algorithm is performed.
Which makes sense, since we're talking box-shadow here, which, in 99.999999999% of cases (basically all except yours) does not have to be accurate. It should be (and obviously is) approximated favoring rendering speed, for obvious reasons: we're talking user experience and "feel". Most users are non-technical and they simply expect smooth scrolling under any and all conditions.
I've come to the conclusion there must be a limit on the amount allowed calculations per keyframe after trying my best at optimizing your code, reducing it to less than half the initial size: https://jsfiddle.net/websiter/wnrxmapu/1/
I wasn't able to find any material on pixel clustering techniques for box-shadow and I don't think much is available online - this should be classified information.
However, IMHO, other than bragging rights, I don't think your technique stands a chance in terms of rendering performance when compared to a gif or svg. Emphasis on "IMHO". If you insist on getting this done, you might want to slice the image up and check if the limit on allowed calculation is per element or per page.
But I wouldn't keep my hopes too high. It is optimizations like the one your code has revealed that make CSS lightning fast. If it had to be accurate it wouldn't be so fast.

Related

Misalignment of image and gradient border

For a web application, I need to display small images as a circle and draw a circular gradient-filled border around them using only HTML and CSS. For unknown reasons, some systems reproducibly show misalignment between the image and the border so that they are not concentric. On affected systems, this behavior is visible in both Chrome, Firefox, and Edge, however, the direction of the misalignment is different. Other systems, however, are perfectly fine.
Enlarged screenshot of the misalignment in my web application:
My first thought was, that this might be a subpixel rendering issue but since I am using an even-numbered image size of 24x24px and an even-numbered border width of 2px this seems unlikely. I did some experiments by gradually increasing the image size by 1px and found that the direction and extent of misalignment are inconsistent and sometimes there seems to be an oval distortion. Below you find a reduced code snippet at screenshots from Chrome, Firefox, and Edge. I indicated the direction of misalignment in red. Increasing the border width yielded similar results, but the effect seems most pronounced with 2px.
.rounded-corners-gradient-borders {
box-sizing: border-box;
padding: 2px;
border-radius: 100%;
background: linear-gradient(45deg, #F48ACE 0%, #493A97 100%);
}
<img class="rounded-corners-gradient-borders" src="https://i.picsum.photos/id/368/24/24.jpg?hmac=qTESgqsVn81m_y-i5SDjG0xncWcyf-gYC40Jw9amc-k" />
https://codepen.io/grilly17/pen/VwXNrMO
Annotated screenshot of Codepen output in Firefox:
Annotated screenshot of Codepen output in Chrome:
I am aware that drawing a perfectly concentric "solid colored" border can be achieved a lot easier, but the gradient is a hard requirement in this case.
Since it doesn't seem to affect all systems, I asked friends and colleagues to have a look at different OS types, OS versions, browsers, browser versions, monitors, screen resolutions, and different compute hardware but I was not able to find a common cause for this. The direction and extent of misalignment seemed to be different on every system and browser but it does not change when reloading the page in the same browser again. So it appears to be deterministic.
At this point, my best guess is that it is related to some rounding error in the rendering process, but I would love to get to the bottom of this. Does anybody know why this is happening at all and why it is only affecting some systems? Is there a better solution to achieve this?
Thanks to the hint of "CSS pixels vs screen pixels" I was able to understand the root cause and find a solution to my problem. I should have realized that the screenshot of the icon was 35px high instead of the expected 28px including padding.
Most OS have a display setting for "scaling" up everything on your screen by a certain factor, e.g. 125%. This affects everything on your screen and may cause fractional pixel values, which results in the effect described above. If you have multiple screens, the value might be different on every screen. For web applications, the active screen's scaling value is applied only on page loading/rendering and not when moving the page between screens.
The scaling factor can be accessed via the JavaScript window property window.devicePixelRatio.
Using this I was able to work out two acceptable solutions, which might be useful for others:
Get a "device pixel perfect" representation by undoing the scaling
Get a "no subpixel" representation by accounting for pixel fractions in the unscaled value
The enlarged screenshot below shows from left to right the original misaligned image, the "device pixel perfect" image, and the "no subpixel" image when using a display scaling of 125%.
Here is my code (tested on FF, Chrome, Edge): https://codepen.io/grilly17/pen/QWmegPj
function precompensateScaling(value, scale) {
return value / scale;
}
function precompensatePixelFractions(value, scale) {
return value - value * scale % 1 / scale;
}
// wait until page is fully loaded
window.onload = (event) => {
const original = document.getElementById('original');
const oHeight = parseFloat(window.getComputedStyle(original).getPropertyValue('height'));
const oPadding = parseFloat(window.getComputedStyle(original).getPropertyValue('padding'));
const scale = window.devicePixelRatio;
const unscaled = document.getElementById('unscaled');
//unscaled.style.transform = `scale(${1/scale})`; // alternative
unscaled.style.height = `${precompensateScaling(oHeight, scale)}px`;
unscaled.style.padding = `${precompensateScaling(oPadding, scale)}px`;
const adjusted = document.getElementById('adjusted');
adjusted.style.height = `${precompensatePixelFractions(oHeight, scale)}px`;
adjusted.style.padding = `${precompensatePixelFractions(oPadding, scale)}px`;
};
Thank you all for your support. I <3 the Stack Overflow community!

Can I use content-visibility on all elements?

So, with content-visibility improving the page load time by skipping content that are not in the viewport, is there a real reason preventing its usage across all DOM elements?
Rather than use
.card {
content-visibility: auto;
}
Why not use
* {
content-visibility: auto;
}
I think the short answer is that you would loose a little of the performance benefits of 'content-visibility'.
Why?
as they say, "There ain't no such thing as a free lunch", so there is always a trade of. content-visibility improves performance by not rendering parts of the dom that are not on screen (info), so it will firts validate if the part needs to be rendered or not, and then perform the rendering process.
So you are adding some processing (the validation) and removing other (the rendering). You are gonna have performance improvement as long as what you are removing is greater than what you are adding.
If you use something like
* {
content-visibility: auto;
}
You are basically telling the browser to validate everything before rendering. This means that the nodes, and their children recursively will be validated.
Let me do a brief extremely over simplificated and over exagerated example to explain what I mean (numbers here are not real at all)
Lets say that you have a screen with three .card of which 1 and a half are visible initially, each has 10 children.
Lets say and each card renders in 1 second and each node validation takes lets say 100ms.
So currently the render time would be 3 seconds
Applying content-visibility: auto; to the .card would result in 3 validations (+300ms) and one of the cards would not be rendered (-1 second) so the total render time would be 2.3 seconds
Applying content-visibility: auto; to * would result in 30 validations (+3000ms) and one and a half of the cards would not be rendered (-1.5 seconds) so the total render time would be 4.5 seconds
So content-visibility works best for blocks of elements that are expensive to render on the inside.
Its possible that the browsers will implement some optimizations in the future; I have not found information about optimizations, but for now as the feature is quite new, using it like that may cause issues.
The main point of using content-visibility is performance. It can help to speed up page load because the browser is able to defer rendering elements that are not in the user’s viewport until the user scrolls to them.
By using this,
* {
content-visibility: auto;
}
You are basically telling the browser to validate everything before rendering. This means that the nodes, and their children recursively will be validated.
If you use a content-visibility for a particular section or element,
section{
content-visibility:auto;
}
The browser only renders that particular element or section. it will saves the browser's rendering time.

Smooth Scrolling in SDL

My use case is need to build large table using SDL. and I’m looking for smooth scroll like browser does. Anyone have idea ? how to implement smooth scrolling in SDL ?. I tried with SDL_MouseWheel event . but it doesn’t look smooth.
If the target devices have an "analogue-y" input method, like a touchscreen or trackpad, you will find the smoothest subjective scrolling experience by using that. Perhaps SDL_TouchFingerEvent or SDL_MultiGestureEvent will get you what you need.
If all you have to work with is a traditional notched scroll wheel, you'll need to interpolate, as #keltar suggests.
The absolute easiest way to accomplish that is linear over time, something like
/* on mouse wheel event received */
if (event.type == SDL_MOUSEWHEEL)
{
targetScrollPosition += event.wheel.y * MY_SCROLL_SENSITIVITY;
}
/* each frame, animate scroll */
if (visibleScrollPosition < targetScrollPosition)
{
visibleScrollPosition += MY_SCROLL_SPEED;
}
else if (visibleScrollPosition > targetScrollPosition)
{
visibleScrollPosition -= MY_SCROLL_SPEED;
}
However you'll find this is not much smoother and quite unfriendly to rapid scrolling, so you'll want to look into cubic or other methods.
Here is some background reading with code examples. http://paulbourke.net/miscellaneous/interpolation/
Bear in mind that the user can scroll further--in either direction--during the animation so it needs to follow the desired position at all times. There is nothing more frustrating than scrolling down, then scrolling up, and then watching the viewport slowly do both instead of just going straight to where I wanted to be. In fact, I personally don't like smooth scrolling at all, and usually turn it off in favor of immediate feedback; so, if this table will have users other than yourself, before putting in a ton of effort be sure to account for their personal taste.

Is there a way to slow down a gif as a background in html and css?

I'm making a website for school. As a background of the first page I chose a gif. But the gif is too fast. Is there some attribute or a way to slow down the gif. Maybe there is something I can type in css to slow it down?
You need to resample the gif to change the speed of it.
I haven't tried this tool, but perhaps it will be of help to you: http://ezgif.com/speed
Unfortunately, there is no way to directly control the animation of a GIF with only HTML/CSS.
However, the answer to your other question is "yes" - there are ways to slow down your GIF, or even enable complete CSS control of the animation, with a little help from an image editor.
If you're willing to use an image editor, such as the excellent and free GIMP, then there are some simple solutions to this problem. No experience necessary.
The Simple Problem/Solution
When you really just need to change the GIF speed and don't really need to control it with CSS.
Open your GIF file with GIMP.
In the "Layers" panel, change the layer display duration to whatever you need for each layer. It is displayed like this: (40ms). Just double click the name and enter your new time (80ms if you want to slow it down to half speed in this example), then press enter.
Export as a GIF!
The Complex Problem/Solution
When you do need dynamic control of the animation using CSS.
Overview: We'll convert the GIF into a PNG spritemap, make it the background-image of our HTML element, then use a basic CSS animation to move the frames in steps. With this we gain full control over animation easing, duration, and delay. The code below shows a basic example of the result, followed by a detailed breakdown.
HTML
<div class="slowme"></div>
CSS
.slowme {
background: url("url-for-spritemap.png") 0 0 no-repeat;
background-size: 2400%;
animation: anim-ss steps(23) 1s infinite;
}
#keyframes anim-ss { 0% {background-position: 0%;} 100% {background-position: 100%;} }
Detailed Explanation
Convert the GIF into a spritemap. You can do this completely manually, though it is tedious if the GIF has many layers. (See manual and automatic spritemap solutions at the bottom for detailed instructions.)
Set the spritemap as the background image of a div.
Set the background-size attribute to be a 100% multiplied by your number of frames. In this example, I have 24 frames, so background-size is 2400%. This changes the size of the image relative to the width of your div so that each "frame" of the spritemap is the width to fill the div.
Add a basic keyframes animation to your CSS (code below) to control the position over time. This will move the background image from right to left over the course of the animation.
Set the animation for the div including the steps() for the animation-timing-function property. Set the steps to be the number of frames minus 1. Since we have 24 frames in this example, we'll use steps(23). Without the steps, the image background would slide smoothly, the steps move the background in step with frame widths.
That's it!
The animation should look exactly like the GIF did, except now you can control it like a standard CSS animations.
Control Examples
/* Slow the animation (by increasing duration) to half */
animation: anim-ss steps(23) 2s infinite;
/* Delay the animation start by 5 seconds */
animation: anim-ss steps(23) 1s 5s infinite;
/* Pause the animation (can use to pause/play with a JS button) */
animation-play-state: paused;
/* Play animation in reverse */
animation: anim-ss steps(23) 1s 5s infinite reverse;
I know this was a lot of extra information, but I really hope it helps someone out there!
Detailed GIMP Instructions
Please Note: These instructions are correct at time of writing, using GIMP v2.10. If they fail you, future reader, please refer to the GIMP documentation.
Manual Spritemap Conversion
Increase the canvas width to make room for all frames. So if the GIF is 219x219px, and there are 10 layers (frames) then change the canvas width to 2190px.
Image > Canvas Size
Set your grid to allow for easy snapping.
View > Show Grid
View > Snap to Grid
Image > Configure Grid
Set the horizontal and vertical spacing to your frame dimensions.
On each layer, move the contents to the respective grid position. So the base frame image is in the leftmost slot, then frame 2 (in the 2nd layer) is directly to the right, and so on.
Click on the layer of the frame you're moving in the Layers panel to select it.
Select the "Move Tool" by pressing M.
Select the contents of the layer with ctrl/cmd-a then drag them to the correct grid position.
Export as a PNG: File > Export As , then change the file extension to PNG and export.
Automatic Spritemap Conversion
A simple GIMP plugin created by Spydarlee will automate the whole process for you.
Download that file (or create a script.py file yourself and paste the code into it).
Paste/move the script into your plugins folder.
To find the plugins folder location in GIMP: Edit > Preferences > Folders > Plug-ins
Restart GIMP to load the plugin.
Open the GIF in GIMP.
Use the plugin: Filters > Animation > Create Spritesheet
Change "Output to a single row?" to "Yes" and then click "Ok". All Done!
No.. Never. Because the gif is an image type. You can consider it as a set of image that rapodally change. The movement is not made by the CSS animation so can not control if using CSS. Find another image or make own CSS animation.

GameMaker converted game to HTML5, showing huge bugs

I recently made a game with game maker and I've tried converting it to html5, but it's got some big errors... here is the game in html format: http://ivatrix.com/Game/index.html
First off, text is meant to appear in the top left like how you can see in this screenshot: http://gyazo.com/baa386fe06cfac9439c83b6e5192efd8 the text only appears after you create a combo.
Secondly, when you click on an orb it's meant to scale down to half it's size then scale up to 1.5x it's size, but instead it's shrinking until it's 1px large then infinitely increasing in size. Draw code is here:
if sl=1
{
if (s=0.6 or s=1) then d=d*(-1)
s+=d
if(frozen=1)
{
draw_sprite_ext(sprite_index,global.skin,x,y,s,s,0,c_blue,1)
}
}
And then there's other small errors like some text won't display, particle effects don't seem to draw, the game always returns saying there is no match on the board. That's all I've found so far.
Does anyone have any idea what I can do to fix this?
Thanks.
Since no one has provided an answer and I've found one myself, I'll put it up here so others in the same boat can benefit as well. Practically, the source of all my problems with floating point numbers being irregular, for example instead of it being 1 it could be 1.000000003, which meant if you were to check if that variable was equal to one, it would return false. Further information here: http://help.yoyogames.com/entries/77891197-HTML5-Issues-And-Differences
So for an example in my case, I changed the line
if (s=0.6 or s=1) then d=d*(-1)
to
if (s<0.6 or s>1) then d=d*(-1)
And now the problem is fixed.