Create a rectangle that fills up the entire SVG, just behind the horse, text and frame. Note that the fill attribute points to skyGradient, which we have not yet created.
<svg width="600" height="400" style="background-color:rgb(100,200,0)" viewBox="0 0 600 400" xmlns="www.w3.org">
<rect fill="url(#skyGradient)" x="0" y="0" width="600" height="400" />
<text x="300" y="30" text-anchor="middle" font-size="30px" fill="rgb(250, 100, 0)" stroke="rgba(250, 0, 0, 0.8)" stroke-width="2">潮州雷祝大家龙马精神!</text>
<rect fill="url(#skyGradient)" x="0" y="0" width="600" height="400" />
<text x="300" y="30" text-anchor="middle" font-size="30px" fill="rgb(250, 100, 0)" stroke="rgba(250, 0, 0, 0.8)" stroke-width="2">潮州雷祝大家龙马精神!</text>
Now we're going to create the linearGradient tag skyGradient, inside a defs tag. This gradient begins changing colors at the 50% mark, vertically.
<svg width="600" height="400" style="background-color:rgb(100,200,0)" viewBox="0 0 600 400" xmlns="www.w3.org">
<defs>
<linearGradient id="skyGradient" x1="0%" y1="0%" x2="0%" y2="50%">
</linearGradient>
</defs>
<rect fill="url(#skyGradient)" x="0" y="0" width="600" height="400" />
<defs>
<linearGradient id="skyGradient" x1="0%" y1="0%" x2="0%" y2="50%">
</linearGradient>
</defs>
<rect fill="url(#skyGradient)" x="0" y="0" width="600" height="400" />
It goes from a deep blue to a purplish blue.
<defs>
<linearGradient id="skyGradient" x1="0%" y1="0%" x2="0%" y2="50%">
<stop offset="0%" stop-color="rgb(0, 0, 50)">
</stop>
<stop offset="100%" stop-color="rgb(50, 50, 250)">
</stop>
</linearGradient>
</defs>
<linearGradient id="skyGradient" x1="0%" y1="0%" x2="0%" y2="50%">
<stop offset="0%" stop-color="rgb(0, 0, 50)">
</stop>
<stop offset="100%" stop-color="rgb(50, 50, 250)">
</stop>
</linearGradient>
</defs>
Here, you can see the gradient.
Now add some animation here. It animates the stop-color attribute, changing from deep blue to purplish blue, to brown, then back to deep blue, in the space of 10 seconds, and runs indefinitely. We set the begin attribute to 0 seconds, so it starts right away.
<linearGradient id="skyGradient" x1="0%" y1="0%" x2="0%" y2="50%">
<stop offset="0%" stop-color="rgb(0, 0, 50)">
<animate
attributeName="stop-color"
values="rgb(0, 0, 50);rgb(50, 150, 255);rgb(50, 150, 255);rgb(150, 20, 0);rgb(0, 0, 50)"
dur="10s"
begin="0s"
repeatCount="indefinite"
/>
</stop>
<stop offset="100%" stop-color="rgb(50, 50, 250)">
</stop>
</linearGradient>
<stop offset="0%" stop-color="rgb(0, 0, 50)">
<animate
attributeName="stop-color"
values="rgb(0, 0, 50);rgb(50, 150, 255);rgb(50, 150, 255);rgb(150, 20, 0);rgb(0, 0, 50)"
dur="10s"
begin="0s"
repeatCount="indefinite"
/>
</stop>
<stop offset="100%" stop-color="rgb(50, 50, 250)">
</stop>
</linearGradient>
And in the lower regions of the gradient, we also animate the stop-color attribute, going from blue to near-white, then orange, and back to blue.
<linearGradient id="skyGradient" x1="0%" y1="0%" x2="0%" y2="50%">
<stop offset="0%" stop-color="rgb(0, 0, 50)">
<animate
attributeName="stop-color"
values="rgb(0, 0, 50);rgb(50, 150, 255);rgb(150, 20, 0);rgb(0, 0, 50)"
dur="10s"
begin="0s"
repeatCount="indefinite"
/>
</stop>
<stop offset="100%" stop-color="rgb(50, 50, 250)">
<animate
attributeName="stop-color"
values="rgb(50, 50, 250);rgb(250, 250, 255);rgb(250, 150, 0);rgb(50, 50, 250)"
dur="10s"
begin="0s"
repeatCount="indefinite"
/>
</stop>
</linearGradient>
<stop offset="0%" stop-color="rgb(0, 0, 50)">
<animate
attributeName="stop-color"
values="rgb(0, 0, 50);rgb(50, 150, 255);rgb(150, 20, 0);rgb(0, 0, 50)"
dur="10s"
begin="0s"
repeatCount="indefinite"
/>
</stop>
<stop offset="100%" stop-color="rgb(50, 50, 250)">
<animate
attributeName="stop-color"
values="rgb(50, 50, 250);rgb(250, 250, 255);rgb(250, 150, 0);rgb(50, 50, 250)"
dur="10s"
begin="0s"
repeatCount="indefinite"
/>
</stop>
</linearGradient>
Here you can see the transitions!
It feels like the horse is galloping through dawn...
... to day...
... to dusk!
We're going to add a sun. Or moon. Whatever, a heavenly body up in the sky. This is meant to help propagate the illusion that the horse is running forward. This takes the form of a circle tag. I've made it a pale yellow, with a translucent pale yellow border.
<rect fill="url(#skyGradient)" x="0" y="0" width="600" height="400" />
<circle r="10" cx="650" cy="100" fill="rgb(250,250,200)" stroke="rgba(250,250,200,0.8)" stroke-width="5">
</circle>
<text x="300" y="30" text-anchor="middle" font-size="30px" fill="rgb(250, 100, 0)" stroke="rgba(250, 0, 0, 0.8)" stroke-width="2">潮州雷祝大家龙马精神!</text>
<circle r="10" cx="650" cy="100" fill="rgb(250,250,200)" stroke="rgba(250,250,200,0.8)" stroke-width="5">
</circle>
<text x="300" y="30" text-anchor="middle" font-size="30px" fill="rgb(250, 100, 0)" stroke="rgba(250, 0, 0, 0.8)" stroke-width="2">潮州雷祝大家龙马精神!</text>
You won't see anything even if you refresh. That's because the center of the circle, defined by the attributes cx and cy, are outside of the SVG, which is only 600 pixels in width. We're going to animate the position of this circle. The attribute to animate is cx, because we'll be moving the circle horizontally. Set repeatCount to 1; we won't need anything higher than this. For now, the duration should be 5 seconds. Let's name this moon0.
<circle r="10" cx="650" cy="100" fill="rgb(250,250,200)" stroke="rgba(250,250,200,0.8)" stroke-width="5">
<animate
id="moon0"
attributeName="cx"
from="620" to="400"
dur="5s"
begin="0s"
repeatCount="1"
/>
</circle>
<animate
id="moon0"
attributeName="cx"
from="620" to="400"
dur="5s"
begin="0s"
repeatCount="1"
/>
</circle>
We now create a new animation, moon1. It will run parallel to moon0, and animate the opacity property from 1 to 0. This means that the "moon" will enter the screen from the right, and fade in.
<circle r="10" cx="650" cy="100" fill="rgb(250,250,200)" stroke="rgba(250,250,200,0.8)" stroke-width="5">
<animate
id="moon0"
attributeName="cx"
from="620" to="400"
dur="5s"
begin="0s"
repeatCount="1"
/>
<animate
id="moon1"
attributeName="opacity"
from="1" to="0"
dur="5s"
begin="0s"
repeatCount="1"
/>
</circle>
<animate
id="moon0"
attributeName="cx"
from="620" to="400"
dur="5s"
begin="0s"
repeatCount="1"
/>
<animate
id="moon1"
attributeName="opacity"
from="1" to="0"
dur="5s"
begin="0s"
repeatCount="1"
/>
</circle>
For the next two animations, moon2 runs once moon1 ends, and moves the "moon" all the way to the left side of the screen, out of sight.
<circle r="10" cx="650" cy="100" fill="rgb(250,250,200)" stroke="rgba(250,250,200,0.8)" stroke-width="5">
<animate
id="moon0"
attributeName="cx"
from="620" to="400"
dur="5s"
begin="0s"
repeatCount="1"
/>
<animate
id="moon1"
attributeName="opacity"
from="1" to="0"
dur="5s"
begin="0s"
repeatCount="1"
/>
<animate
id="moon2"
attributeName="cx"
from="300" to="-10"
dur="5s"
begin="moon1.end"
repeatCount="1"
/>
</circle>
<animate
id="moon0"
attributeName="cx"
from="620" to="400"
dur="5s"
begin="0s"
repeatCount="1"
/>
<animate
id="moon1"
attributeName="opacity"
from="1" to="0"
dur="5s"
begin="0s"
repeatCount="1"
/>
<animate
id="moon2"
attributeName="cx"
from="300" to="-10"
dur="5s"
begin="moon1.end"
repeatCount="1"
/>
</circle>
The final animation, moon3, also runs once moon1 ends, and animates the opacity attribute back to 1. In essence, the "moon" moves left, out of screen, and fades out.
<circle r="10" cx="650" cy="100" fill="rgb(250,250,200)" stroke="rgba(250,250,200,0.8)" stroke-width="5">
<animate
id="moon0"
attributeName="cx"
from="620" to="400"
dur="5s"
begin="0s"
repeatCount="1"
/>
<animate
id="moon1"
attributeName="opacity"
from="1" to="0"
dur="5s"
begin="0s"
repeatCount="1"
/>
<animate
id="moon2"
attributeName="cx"
from="300" to="-10"
dur="5s"
begin="moon1.end"
repeatCount="1"
/>
<animate
id="moon3"
attributeName="opacity"
from="0" to="1"
dur="5s"
begin="moon1.end"
repeatCount="1"
/>
</circle>
<animate
id="moon0"
attributeName="cx"
from="620" to="400"
dur="5s"
begin="0s"
repeatCount="1"
/>
<animate
id="moon1"
attributeName="opacity"
from="1" to="0"
dur="5s"
begin="0s"
repeatCount="1"
/>
<animate
id="moon2"
attributeName="cx"
from="300" to="-10"
dur="5s"
begin="moon1.end"
repeatCount="1"
/>
<animate
id="moon3"
attributeName="opacity"
from="0" to="1"
dur="5s"
begin="moon1.end"
repeatCount="1"
/>
</circle>
We then make sure moon0 also runs when moon3 ends, making this entire sequence run indefinitely.
<animate
id="moon0"
attributeName="cx"
from="620" to="400"
dur="5s"
begin="0s;moon3.end"
repeatCount="1"
/>
id="moon0"
attributeName="cx"
from="620" to="400"
dur="5s"
begin="0s;moon3.end"
repeatCount="1"
/>
You can see that circle fade in fron the right...
...and fade out on the right as the sky changes!
Now we have a galloping horse, and it looks like it's galloping through night and day! The horse looks like it's galloping through the air. We'll need to plant some ground for it.
Before that, let's define the background colors for the ground. We want it paler green at the top and deeper green at the bottom. And then we want to animate the colors in time to the "sky", so we set both animations at 10 seconds. Both animations cycle through different shades of green at four stages, but the constant is that the upper half of the grassGradient is always significantly lighter than the lower half.
<defs>
<linearGradient id="skyGradient" x1="0%" y1="0%" x2="0%" y2="50%">
<stop offset="0%" stop-color="rgb(0, 0, 50)">
<animate
attributeName="stop-color"
values="rgb(0, 0, 50);rgb(50, 150, 255);rgb(150, 20, 0);rgb(0, 0, 50)"
dur="10s"
begin="0s"
repeatCount="indefinite"
/>
</stop>
<stop offset="100%" stop-color="rgb(50, 50, 250)">
<animate
attributeName="stop-color"
values="rgb(50, 50, 250);rgb(250, 250, 255);rgb(250, 150, 0);rgb(50, 50, 250)"
dur="10s"
begin="0s"
repeatCount="indefinite"
/>
</stop>
</linearGradient>
<linearGradient id="grassGradient" x1="0%" y1="0%" x2="0%" y2="50%">
<stop offset="0%" stop-color="rgb(80, 100, 80)">
<animate
attributeName="stop-color"
values="rgb(80, 100, 80);rgb(100, 150, 100);rgb(120, 200, 120);rgb(100, 150, 100);rgb(80, 100, 80)"
dur="10s"
begin="0s"
repeatCount="indefinite"
/>
</stop>
<stop offset="100%" stop-color="rgb(0, 20, 0)">
<animate
attributeName="stop-color"
values="rgb(0, 20, 0);rgb(20, 50, 20);rgb(50, 100, 50);rgb(20, 50, 20);rgb(0, 20, 0)"
dur="10s"
begin="0s"
repeatCount="indefinite"
/>
</stop>
</linearGradient>
</defs>
<linearGradient id="skyGradient" x1="0%" y1="0%" x2="0%" y2="50%">
<stop offset="0%" stop-color="rgb(0, 0, 50)">
<animate
attributeName="stop-color"
values="rgb(0, 0, 50);rgb(50, 150, 255);rgb(150, 20, 0);rgb(0, 0, 50)"
dur="10s"
begin="0s"
repeatCount="indefinite"
/>
</stop>
<stop offset="100%" stop-color="rgb(50, 50, 250)">
<animate
attributeName="stop-color"
values="rgb(50, 50, 250);rgb(250, 250, 255);rgb(250, 150, 0);rgb(50, 50, 250)"
dur="10s"
begin="0s"
repeatCount="indefinite"
/>
</stop>
</linearGradient>
<linearGradient id="grassGradient" x1="0%" y1="0%" x2="0%" y2="50%">
<stop offset="0%" stop-color="rgb(80, 100, 80)">
<animate
attributeName="stop-color"
values="rgb(80, 100, 80);rgb(100, 150, 100);rgb(120, 200, 120);rgb(100, 150, 100);rgb(80, 100, 80)"
dur="10s"
begin="0s"
repeatCount="indefinite"
/>
</stop>
<stop offset="100%" stop-color="rgb(0, 20, 0)">
<animate
attributeName="stop-color"
values="rgb(0, 20, 0);rgb(20, 50, 20);rgb(50, 100, 50);rgb(20, 50, 20);rgb(0, 20, 0)"
dur="10s"
begin="0s"
repeatCount="indefinite"
/>
</stop>
</linearGradient>
</defs>
And now let's use a path tag. It goes all the way from the far left bottom of the SVG, stretching to the right end of the SVG. There are curves along the way, resulting in slight bumps. We'll want to use the stroke-dasharray attribute to simulate a fuzzy edge, like grass.
<circle r="10" cx="650" cy="100" fill="rgb(250,250,200)" stroke="rgba(250,250,200,0.8)" stroke-width="5">
<animate
id="moon0"
attributeName="cx"
from="620" to="400"
dur="5s"
begin="0s;moon3.end"
repeatCount="1"
/>
<animate
id="moon1"
attributeName="opacity"
from="1" to="0"
dur="5s"
begin="0s;moon3.end"
repeatCount="1"
/>
<animate
id="moon2"
attributeName="cx"
from="300" to="-10"
dur="5s"
begin="moon1.end"
repeatCount="1"
/>
<animate
id="moon3"
attributeName="opacity"
from="0" to="1"
dur="5s"
begin="moon1.end"
repeatCount="1"
/>
</circle>
<path d="M0 350
Q100 340 200 350
Q300 345 350 350
Q500 340 600 350
Z"
stroke-dasharray="2,3"
stroke="url(#grassGradient)"
stroke-width="5"
fill="url(#grassGradient)"
/>
<text x="300" y="30" text-anchor="middle" font-size="30px" fill="rgb(250, 100, 0)" stroke="rgba(250, 0, 0, 0.8)" stroke-width="2">潮州雷祝大家龙马精神!</text>
<animate
id="moon0"
attributeName="cx"
from="620" to="400"
dur="5s"
begin="0s;moon3.end"
repeatCount="1"
/>
<animate
id="moon1"
attributeName="opacity"
from="1" to="0"
dur="5s"
begin="0s;moon3.end"
repeatCount="1"
/>
<animate
id="moon2"
attributeName="cx"
from="300" to="-10"
dur="5s"
begin="moon1.end"
repeatCount="1"
/>
<animate
id="moon3"
attributeName="opacity"
from="0" to="1"
dur="5s"
begin="moon1.end"
repeatCount="1"
/>
</circle>
<path d="M0 350
Q100 340 200 350
Q300 345 350 350
Q500 340 600 350
Z"
stroke-dasharray="2,3"
stroke="url(#grassGradient)"
stroke-width="5"
fill="url(#grassGradient)"
/>
<text x="300" y="30" text-anchor="middle" font-size="30px" fill="rgb(250, 100, 0)" stroke="rgba(250, 0, 0, 0.8)" stroke-width="2">潮州雷祝大家龙马精神!</text>
Now, we want the path to stretch all the way to twice the width of the SVG. So copy and paste whatever we've done so far to create more points...
<path d="M0 350
Q100 340 200 350
Q300 345 350 350
Q500 340 600 350
Q100 340 200 350
Q300 345 350 350
Q500 340 600 350
Z"
stroke-dasharray="2,3"
stroke="url(#grassGradient)"
stroke-width="5"
fill="url(#grassGradient)"
/>
Q100 340 200 350
Q300 345 350 350
Q500 340 600 350
Q100 340 200 350
Q300 345 350 350
Q500 340 600 350
Z"
stroke-dasharray="2,3"
stroke="url(#grassGradient)"
stroke-width="5"
fill="url(#grassGradient)"
/>
... note that for the numbers pertaining to the horizontal positioning, we'll want to add 600 (which is the width of the SVG) to them, while keeping the vertical positioning the same. Then use the L directive to finish out the path.
<path d="M0 350
Q100 340 200 350
Q300 345 350 350
Q500 340 600 350
Q700 340 800 350
Q900 345 950 350
Q1100 340 1200 350
L1200 450
L0 450
Z"
stroke-dasharray="2,3"
stroke="url(#grassGradient)"
stroke-width="5"
fill="url(#grassGradient)"
/>
Q100 340 200 350
Q300 345 350 350
Q500 340 600 350
Q700 340 800 350
Q900 345 950 350
Q1100 340 1200 350
L1200 450
L0 450
Z"
stroke-dasharray="2,3"
stroke="url(#grassGradient)"
stroke-width="5"
fill="url(#grassGradient)"
/>
You see the grassy ground!
Now, this looks weird because in order to complete the illusion of movement and progress, the ground must move with the horse. Envelope the path in a g tag. This will be necessary if we ever want to add any separate objects with the ground, such as a rock, or a shrub. But let's keep it simple for now.
<g>
<path d="M0 350
Q100 340 200 350
Q300 345 350 350
Q500 340 600 350
Q700 340 800 350
Q900 345 950 350
Q1100 340 1200 350
L1200 450
L0 450
Z"
stroke-dasharray="2,3"
stroke="url(#grassGradient)"
stroke-width="5"
fill="url(#grassGradient)"
/>
</g>
<path d="M0 350
Q100 340 200 350
Q300 345 350 350
Q500 340 600 350
Q700 340 800 350
Q900 345 950 350
Q1100 340 1200 350
L1200 450
L0 450
Z"
stroke-dasharray="2,3"
stroke="url(#grassGradient)"
stroke-width="5"
fill="url(#grassGradient)"
/>
</g>
Here, the g tag simplifies the animation, because when we add that animation, it's on the g tag instead of the path. Instead of worrying about what attribute to animate, we use an animateTransform tag and translate it left 600 pixels, in the space of 2.5 seconds. And because 600 is the width of the SVG and we've already made the path twice that in width, when you set repeatCount to indefinite, it seems to go on forever!
<g>
<path d="M0 350
Q100 340 200 350
Q300 345 350 350
Q500 340 600 350
Q700 340 800 350
Q900 345 950 350
Q1100 340 1200 350
L1200 450
L0 450
Z"
stroke-dasharray="2,3"
stroke="url(#grassGradient)"
stroke-width="5"
fill="url(#grassGradient)"
/>
<animateTransform
attributeName="transform"
type="translate"
from="0,0"
to="-600,0"
dur="2.5s"
repeatCount="indefinite"
/>
</g>
<path d="M0 350
Q100 340 200 350
Q300 345 350 350
Q500 340 600 350
Q700 340 800 350
Q900 345 950 350
Q1100 340 1200 350
L1200 450
L0 450
Z"
stroke-dasharray="2,3"
stroke="url(#grassGradient)"
stroke-width="5"
fill="url(#grassGradient)"
/>
<animateTransform
attributeName="transform"
type="translate"
from="0,0"
to="-600,0"
dur="2.5s"
repeatCount="indefinite"
/>
</g>






































