#app
View Compiled
* {
box-sizing: border-box;
}
body {
background: #ad9c85;
}
:root {
--initial-delay: 1;
--delay-step: 0.3;
}
.car {
height: max(50px, 10vmin);
position: absolute;
bottom: 5%;
left: 50%;
transform: translate(-50%, 0) translate(var(--offset), 0);
animation-name: race;
animation-duration: calc(var(--speed, 2) * 1s);
animation-fill-mode: forwards;
animation-timing-function: ease-in;
}
.car--green {
--offset: -80%;
--speed: 2.5;
--step: var(--green-car);
}
.car--red {
--offset: 80%;
--speed: 2;
--step: var(--red-car);
}
img {
height: 100%;
}
.race__strip {
width: calc(2 * max(50px, 10vmin));
height: 100vh;
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, 0);
background: repeating-linear-gradient(0deg, #fff 0 20px, transparent 20px 25px) no-repeat 50% 0/4px 100%, #bfbfbf;
}
.race__lights {
padding: 5px;
background: hsl(0, 0%, 15%);
position: absolute;
display: grid;
grid-gap: 5px 6px;
grid-template-columns: repeat(5, 1fr);
grid-template-rows: repeat(2, 1fr);
left: 50%;
top: 5%;
transform: translate(-50%, 0);
z-index: 2;
}
.race__light {
background: hsl(0, 0%, 25%);
border-radius: 50%;
height: 14px;
width: 14px;
position: relative;
}
.race__light--animated {
animation-name: flash;
animation-duration: 0.2s;
animation-timing-function: steps(1);
animation-fill-mode: both;
}
.race__light--animated,
.race__light-cover,
.car {
animation-delay: calc((var(--initial-delay, 0) + (var(--step, 0) * var(--delay-step, 0))) * 1s);
}
.race__light--5 {
--step: var(--light-one);
}
.race__light--6 {
--step: var(--light-two);
}
.race__light--7 {
--step: var(--light-three);
}
.race__light--8 {
--step: var(--light-four);
}
.race__light--9 {
--step: var(--light-five);
}
.race__light-cover {
--step: var(--lights-out);
position: absolute;
top: 50%;
left: 50%;
height: 15px;
width: 15px;
border-radius: 50%;
background: hsl(0, 0%, 25%);
opacity: 0;
transform: translate(-50%, -50%);
animation-name: out;
animation-duration: 0.2s;
animation-fill-mode: both;
animation-timing-function: steps(1);
}
@keyframes out {
to {
opacity: 1;
}
}
@keyframes flash {
to {
background: hsl(10, 100%, 50%);
}
}
@keyframes race {
to {
transform: translate(-50%, 0) translate(var(--offset), 0) translate(0, -100vh);
}
}
import React, { useEffect, useState } from 'https://cdn.skypack.dev/react'
import { render } from 'https://cdn.skypack.dev/react-dom'
import { GUI } from 'https://cdn.skypack.dev/dat.gui'
const ROOT_NODE = document.querySelector('#app')
const App = () => {
const [time, setTime] = useState(new Date().getTime())
const DEFAULT_CONFIG = {
'light-one': 0,
'light-two': 1,
'light-three': 2,
'light-four': 3,
'light-five': 4,
'lights-out': 8,
'red-car': 10,
'green-car': 9,
'delay-step': 0.3,
'initial-delay': 1,
restart: () => setTime(new Date().getTime()),
}
const [config, setConfig] = useState(DEFAULT_CONFIG)
useEffect(() => {
const CTRL = new GUI()
const STEPS = CTRL.addFolder('Steps')
Object.keys(DEFAULT_CONFIG).forEach((key, index, items) => {
if (key !== 'restart' && key !== 'initial-delay' && key !== 'delay-step') STEPS.add(DEFAULT_CONFIG, key, 0, 10, 1).onChange(
() => {
setTime(new Date().getTime())
setConfig(DEFAULT_CONFIG)
}
)
})
CTRL.add(DEFAULT_CONFIG, 'delay-step', 0.1, 1, 0.1).name('Delay Step').onChange(() => {
setTime(new Date().getTime())
setConfig(DEFAULT_CONFIG)
})
CTRL.add(DEFAULT_CONFIG, 'initial-delay', 0, 5, 0.1).name('Initial Delay').onChange(() => {
setTime(new Date().getTime())
setConfig(DEFAULT_CONFIG)
})
CTRL.add(DEFAULT_CONFIG, 'restart').name('Restart')
}, [])
return (
<div className='race' key={time} style={{
'--delay-step': config['delay-step'],
'--initial-delay': config['initial-delay'],
'--light-one': config['light-one'],
'--light-two': config['light-two'],
'--light-three': config['light-three'],
'--light-four': config['light-four'],
'--light-five': config['light-five'],
'--lights-out': config['lights-out'],
'--red-car': config['red-car'],
'--green-car': config['green-car'],
}}>
<div className='race__lights'>
{new Array(10).fill().map((_, index) => (
<div className={`race__light race__light--${index} ${index > 4 ? 'race__light--animated' : ''}`}>
{index > 4 ? <div className="race__light-cover"></div> : null}
</div>
))}
</div>
<div className="race__strip">
<div className='race__car car car--green'>
<img src="https://assets.codepen.io/605876/green-car.png" alt="green car"/>
</div>
<div className='race__car car car--red'>
<img src="https://assets.codepen.io/605876/little-red-car.png" alt="red car"/>
</div>
</div>
</div>
)
}
render(<App/>, ROOT_NODE)
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.