See code snippet for bouncing circle in 24 sprite frames.
<text y='12'>n:0</text>
displays the sprite framenr
How can I get rid of the horizontal jitter movement, is it SVG or CSS?
The offset is less at less frames in sprite, and gets worse and worse at more frames per sprite
It is less obvious in Chromium, and more obvious in FireFox
I tried https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio
<style>
#bounce {
--w: 200px;
width: var(--w);
height: var(--w);
overflow: hidden;
display: inline-flex;
background: lightgreen;
}
img {
position: relative;
left: 0;
animation: moveX 1s steps(23) infinite;
}
@keyframes moveX {
to {
transform: translate(-100%);
left: 100%;
}
}
</style>
<div id="bounce"><img id=svgimg src="SVG injected here"></div>
<script>
window.onload = () => svgimg.src = `data:image/svg+xml,` + svg.innerHTML;
</script>
<template id=svg>
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2400 100' height='200'>
<style>
ellipse {
fill: none;
stroke: green;
stroke-width: 5;
}
</style>
<g transform='translate(0 0)'>
<ellipse cx='50' cy='32' rx='30' ry='30'></ellipse><text y='12'>n:0</text>
</g>
<g transform='translate(100 0)'>
<ellipse cx='50' cy='32.3' rx='30' ry='30'></ellipse><text y='12'>n:1</text>
</g>
<g transform='translate(200 0)'>
<ellipse cx='50' cy='33.2' rx='30' ry='30'></ellipse><text y='12'>n:2</text>
</g>
<g transform='translate(300 0)'>
<ellipse cx='50' cy='34.5' rx='30' ry='30'></ellipse><text y='12'>n:3</text>
</g>
<g transform='translate(400 0)'>
<ellipse cx='50' cy='36.5' rx='30' ry='30'></ellipse><text y='12'>n:4</text>
</g>
<g transform='translate(500 0)'>
<ellipse cx='50' cy='39' rx='30' ry='30'></ellipse><text y='12'>n:5</text>
</g>
<g transform='translate(600 0)'>
<ellipse cx='50' cy='42' rx='30' ry='30'></ellipse><text y='12'>n:6</text>
</g>
<g transform='translate(700 0)'>
<ellipse cx='50' cy='45.7' rx='30' ry='30'></ellipse><text y='12'>n:7</text>
</g>
<g transform='translate(800 0)'>
<ellipse cx='50' cy='49.8' rx='30' ry='30'></ellipse><text y='12'>n:8</text>
</g>
<g transform='translate(900 0)'>
<ellipse cx='50' cy='54.5' rx='31.3' ry='30'></ellipse><text y='12'>n:9</text>
</g>
<g transform='translate(1000 0)'>
<ellipse cx='50' cy='59.8' rx='33.9' ry='30'></ellipse><text y='12'>n:10</text>
</g>
<g transform='translate(1100 0)'>
<ellipse cx='50' cy='65.7' rx='36.9' ry='30'></ellipse><text y='12'>n:11</text>
</g>
<g transform='translate(1200 0)'>
<ellipse cx='50' cy='72' rx='40' ry='30'></ellipse><text y='12'>n:12</text>
</g>
<g transform='translate(1300 0)'>
<ellipse cx='50' cy='65.7' rx='36.9' ry='30'></ellipse><text y='12'>n:13</text>
</g>
<g transform='translate(1400 0)'>
<ellipse cx='50' cy='59.8' rx='33.9' ry='30'></ellipse><text y='12'>n:14</text>
</g>
<g transform='translate(1500 0)'>
<ellipse cx='50' cy='54.5' rx='31.3' ry='30'></ellipse><text y='12'>n:15</text>
</g>
<g transform='translate(1600 0)'>
<ellipse cx='50' cy='49.8' rx='30' ry='30'></ellipse><text y='12'>n:16</text>
</g>
<g transform='translate(1700 0)'>
<ellipse cx='50' cy='45.7' rx='30' ry='30'></ellipse><text y='12'>n:17</text>
</g>
<g transform='translate(1800 0)'>
<ellipse cx='50' cy='42' rx='30' ry='30'></ellipse><text y='12'>n:18</text>
</g>
<g transform='translate(1900 0)'>
<ellipse cx='50' cy='39' rx='30' ry='30'></ellipse><text y='12'>n:19</text>
</g>
<g transform='translate(2000 0)'>
<ellipse cx='50' cy='36.5' rx='30' ry='30'></ellipse><text y='12'>n:20</text>
</g>
<g transform='translate(2100 0)'>
<ellipse cx='50' cy='34.5' rx='30' ry='30'></ellipse><text y='12'>n:21</text>
</g>
<g transform='translate(2200 0)'>
<ellipse cx='50' cy='33.2' rx='30' ry='30'></ellipse><text y='12'>n:22</text>
</g>
<g transform='translate(2300 0)'>
<ellipse cx='50' cy='32.3' rx='30' ry='30'></ellipse><text y='12'>n:23</text>
</g>
</svg></template>
I can not use a library, I am generating (and changing) spritesheets Client-Side
Template for this circle is a template-literal:
<template id="bounce">
<ellipse cx='50'
cy='${72-1*ease(40)}'
rx='${minmax(30,40-ease(20))}'
ry='30' fill='none' stroke='black' stroke-width='5'>
</ellipse>
<text y='12'>n:${framenr}</text>
</template>
A Web Component then (re)creates the sprite and IMG, and everything to display the sprite
<svg-spriter do="bounce" steps="24" duration="1s" animation="infinite"></svg-spriter>
I have made some changes to the fiddle, and it seems to work. One point seems to be that the last left
coordinate in the transformation should be the total length of the svg
minus the length of the window. In the fiddle, you can change
transform: translate(calc(-1 * var(--steps) * var(--w)));
to
transform: translate(calc(-1 * calc(var(--steps) - 1) * var(--w)));
In your snippet, the transform: translate(-100%);
percentage should be (2300/2400)*100
.
More importantly, I have added the width='2400'
property to the svg
. The matter of setting a missing length property for an svg is quite complex, and I do not think that every browser behaves the same way.
In the fiddle, I have changed the --w
property to 100, which is the height and width of each svg frame. If you want to set it to 200, you would need to change the size of the svg and the coordinates of each frame proportionally.