Last active
March 28, 2025 14:22
-
-
Save cowboy/bb51e3da979be52e0558f84bd26e9738 to your computer and use it in GitHub Desktop.
GSG overlay structure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html, | |
body { | |
padding: 0; | |
margin: 0; | |
height: 100%; | |
} | |
body { | |
color: white; | |
background: #777; | |
background: #000; | |
display: flex; | |
justify-content: center; | |
align-items: end; | |
background: url("https://i.imgur.com/DnboIcQ.jpeg"); | |
background-position: center; | |
background-size: cover; | |
} | |
#debug-parent { | |
position: absolute; | |
top: 0; | |
bottom: 0; | |
left: 0; | |
right: 0; | |
width: 50px; | |
height: 50px; | |
background: rgba(0, 0, 0, 0.8); | |
z-index: 10000; | |
font-size: 1em; | |
overflow: hidden; | |
transition: all 0.2s; | |
} | |
#debug-parent:hover { | |
overflow: scroll; | |
width: 100vw; | |
height: 100vh; | |
} | |
#event-parent { | |
width: 100vw; | |
/* opacity: 0.95; */ | |
} | |
:root { | |
--schedule-grid-line-color: #ffbb22; | |
--schedule-h-grid-line-width: 4px; | |
--schedule-grid-bg-color: #000; | |
--schedule-h-time-height: 20px; | |
--schedule-h-slot-height: 80px; | |
--schedule-h-top-border-thickness: 3px; /* don't change this */ | |
--schedule-h-time-color: #000; | |
--schedule-h-time-bg-color: #ffbb22; | |
--schedule-h-outer-border-color: #000; | |
--schedule-h-time-border-thickness: 4px; | |
--schedule-h-slot-width: 200px; | |
--schedule-h-slot-border-width: 3px; | |
--schedule-h-slot-border: var(--schedule-h-slot-border-width) solid #fff; | |
--schedule-h-slot-color: #fff; | |
--schedule-h-slot-bg: #444; | |
--schedule-h-slot-now-bg: #fe6100; | |
--schedule-h-slot-bg-hover: #777; | |
--schedule-h-slot-now-bg-hover: #bd4800; | |
--schedule-h-gap-height: 10px; | |
--schedule-h-raid-train-name-height: 30px; | |
--schedule-h-raid-train-name-color: #fff; | |
--schedule-h-gap-width: calc( | |
2 * var(--schedule-h-gap-height) + var(--schedule-h-grid-line-width) | |
); | |
--schedule-h-time-width: var(--schedule-h-slot-width); | |
--schedule-h-time-width: 120px; | |
--now-auto-left-offset: 15vw; | |
--now-text-width: 60px; | |
--now-text-height: 50px; | |
--now-text-fg-color: #fff; | |
--now-text-bg-color: #fe6100; | |
--now-text-border-color: #000; | |
--now-v-offset: 8px; | |
/* computed */ | |
--schedule-h-gap-height-pre: var(--schedule-h-gap-height); | |
--now-h-position: calc( | |
(var(--now-position) - 1) * var(--schedule-h-slot-actual-width) - | |
(var(--schedule-h-gap-width) / 2) | |
); | |
--now-text-line-height-offset: calc(var(--schedule-h-time-height) + 20px); | |
--now-text-line-height-per-row: calc( | |
var(--schedule-h-gap-height) + var(--schedule-h-slot-height) | |
); | |
--schedule-h-slot-width-adjusted: calc( | |
var(--schedule-h-slot-width) - var(--schedule-h-slot-border-width) | |
); | |
--schedule-h-gap-width-adjusted: calc( | |
var(--schedule-h-gap-width) + var(--schedule-h-slot-border-width) | |
); | |
--schedule-h-slot-actual-width: calc( | |
var(--schedule-h-slot-width) + var(--schedule-h-gap-width) | |
); | |
--schedule-h-grid-center: calc( | |
(var(--schedule-h-slot-actual-width) - var(--schedule-h-gap-width)) / 2 | |
); | |
--schedule-h-grid-left-offset: calc( | |
(var(--schedule-h-slot-width) + var(--schedule-h-gap-width)) / 2 | |
); | |
} | |
.event { | |
display: grid; | |
position: relative; | |
overflow-x: hidden; | |
padding-top: calc(var(--now-text-height) - var(--now-v-offset)); | |
font-family: "Revalia", sans-serif; | |
font-weight: 400; | |
font-style: normal; | |
font-size: 12px; | |
user-select: none; | |
touch-action: none; | |
/* background: #0f0; */ | |
} | |
.show-raid-train-names { | |
--schedule-h-gap-height-pre: var(--schedule-h-raid-train-name-height); | |
} | |
.event-grid, | |
.top-border, | |
.now, | |
.set { | |
cursor: grab; | |
} | |
.event-grid:active, | |
.top-border:active, | |
.now:active, | |
.set:active { | |
cursor: grabbing; | |
} | |
.top-border { | |
position: sticky; | |
left: 0; | |
height: 0; | |
border-top: var(--schedule-h-top-border-thickness) solid | |
var(--schedule-h-outer-border-color); | |
border-bottom: var(--schedule-h-time-border-thickness) solid | |
var(--schedule-h-time-bg-color); | |
} | |
.event-grid { | |
display: inline-grid; | |
grid-template-columns: | |
auto var(--schedule-h-gap-width) | |
repeat( | |
var(--event-slots), | |
var(--schedule-h-slot-width-adjusted) var(--schedule-h-gap-width-adjusted) | |
) | |
auto; | |
grid-template-rows: | |
0 repeat( | |
var(--raid-trains), | |
var(--schedule-h-gap-height-pre) var(--schedule-h-slot-height) | |
) | |
var(--schedule-h-gap-height); | |
background: var(--schedule-grid-bg-color); | |
} | |
.set-row-gap, | |
.set.blank, | |
.set.blank + .set-col-gap, | |
.set.has-artist + .set-col-gap::after, | |
.set-col-gap.start { | |
--center: calc(var(--schedule-h-gap-width) / 2); | |
--half-line: calc(var(--schedule-h-grid-line-width) / 2); | |
--line-start: calc(var(--center) - var(--half-line)); | |
--line-end: calc(var(--center) + var(--half-line)); | |
--fg: var(--schedule-grid-line-color); | |
--bg: var(--schedule-grid-bg-color); | |
background-image: repeating-linear-gradient( | |
90deg, | |
var(--bg), | |
var(--bg) var(--line-start), | |
var(--fg) var(--line-start), | |
var(--fg) var(--line-end), | |
var(--bg) var(--line-end), | |
var(--bg) var(--schedule-h-slot-actual-width) | |
); | |
background-size: var(--schedule-h-slot-actual-width); | |
} | |
.scroll-to, | |
.now { | |
grid-row: 1 / span 1; | |
grid-column: 2 / span 1; | |
position: relative; | |
} | |
.scroll-to span, | |
.now span { | |
position: relative; | |
left: var(--now-h-position); | |
} | |
.scroll-to { | |
left: calc(var(--schedule-h-gap-width) - var(--now-auto-left-offset)); | |
/* height: 20px; | |
background: #0f0; */ | |
} | |
.scroll-to span { | |
width: var(--now-auto-left-offset); | |
/* display: block; | |
z-index: 9000; | |
height: 20px; | |
background: #00f; */ | |
} | |
.now { | |
z-index: 2000; | |
top: calc( | |
var(--now-v-offset) - var(--now-text-height) - | |
var(--schedule-h-top-border-thickness) | |
); | |
left: calc(var(--schedule-h-gap-width) - var(--now-text-width) / 2); | |
--c: 0px var(--now-text-border-color); | |
--s: 1px; | |
--t: calc(-1 * var(--s)); | |
filter: drop-shadow(var(--s) 0 var(--c)) drop-shadow(var(--t) 0 var(--c)) | |
drop-shadow(0 var(--s) var(--c)) drop-shadow(0 var(--t) var(--c)) | |
drop-shadow(var(--s) var(--s) var(--c)) | |
drop-shadow(var(--t) var(--t) var(--c)) | |
drop-shadow(var(--t) var(--s) var(--c)) | |
drop-shadow(var(--s) var(--t) var(--c)); | |
} | |
.now span { | |
width: var(--now-text-width); | |
height: var(--now-text-height); | |
color: var(--now-text-fg-color); | |
background: var(--now-text-bg-color); | |
display: grid; | |
place-items: center; | |
grid-template-rows: auto 22px; | |
font-size: 16px; | |
--offset: calc(var(--now-text-width) / 2); | |
clip-path: polygon( | |
0 0, | |
0 calc(100% - var(--offset)), | |
50% 100%, | |
100% calc(100% - var(--offset)), | |
100% 0 | |
); | |
} | |
.time { | |
grid-row: 1 / span 1; | |
z-index: 1000; | |
width: var(--schedule-h-slot-width); | |
justify-self: end; | |
position: relative; | |
left: var(--schedule-h-grid-left-offset); | |
margin-right: calc(-1 * var(--schedule-h-slot-border-width)); | |
top: calc( | |
0px - var(--schedule-h-time-border-thickness) - | |
var(--schedule-h-time-height) | |
); | |
} | |
.time.has-set { | |
display: grid; | |
justify-items: center; | |
--c: 0px var(--schedule-h-outer-border-color); | |
--s: 1px; | |
--t: calc(0px - var(--s)); | |
/* filter: drop-shadow(var(--s) 0 var(--c)) drop-shadow(var(--t) 0 var(--c)) | |
drop-shadow(0 var(--t) var(--c)) drop-shadow(var(--t) var(--t) var(--c)) | |
drop-shadow(var(--s) var(--t) var(--c)); */ | |
--s: 3px; | |
--t: calc(0px - var(--s)); | |
filter: drop-shadow(var(--s) 0 var(--c)) drop-shadow(var(--t) 0 var(--c)) | |
drop-shadow(0 var(--t) var(--c)); | |
} | |
.time.has-set span { | |
width: var(--schedule-h-time-width); | |
background-color: var(--schedule-h-time-bg-color); | |
color: var(--schedule-h-time-color); | |
text-align: center; | |
font-size: 14px; | |
line-height: var(--schedule-h-time-height); | |
/* --offset: var(--schedule-h-time-height); | |
clip-path: polygon( | |
100% 100%, | |
0 100%, | |
var(--offset) 0, | |
calc(100% - var(--offset)) 0 | |
); */ | |
/* clip-path: path("m0 20 C 10 -30, 190 -30, 200 20 z"); */ | |
/* border-radius: 18px 18px 0 0; */ | |
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); | |
transition: all 0.2s; | |
} | |
.time.has-set.past span { | |
clip-path: polygon(0 100%, 100% 100%, 100% 100%, 0 100%); | |
} | |
.time.has-set span::after { | |
display: inline-block; | |
position: relative; | |
/* top: 1px; */ | |
content: attr(data-time); | |
vertical-align: top; | |
} | |
.time.no-set { | |
background: var(--schedule-grid-bg-color); | |
visibility: hidden; | |
} | |
.raid-train-name { | |
display: none; | |
} | |
.show-raid-train-names .raid-train-name { | |
display: block; | |
color: var(--schedule-h-raid-train-name-color); | |
z-index: 1000; | |
grid-column: 3 / span 1; | |
position: sticky; | |
left: var(--schedule-h-gap-height); | |
font-size: 14px; | |
align-self: center; | |
text-transform: uppercase; | |
text-shadow: 0 0 3px var(--schedule-grid-bg-color), | |
0 0 3px var(--schedule-grid-bg-color), 0 0 3px var(--schedule-grid-bg-color); | |
} | |
.set-row-gap { | |
/* background: #f00; */ | |
background-position-x: var(--schedule-h-slot-width); | |
} | |
.set-row-gap.end { | |
grid-row: calc(var(--raid-trains) * 2 + 2) / span 1; | |
grid-column: 3 / span calc(var(--event-slots) * 2); | |
} | |
.set { | |
display: grid; | |
grid-template-columns: 66px auto; | |
grid-template-rows: auto auto auto; | |
align-content: start; | |
padding: 8px; | |
} | |
.set .img { | |
grid-row: 1 / span 3; | |
grid-column: 1 / span 1; | |
display: block; | |
--size: 52px; | |
width: var(--size); | |
height: var(--size); | |
border: var(--schedule-h-slot-border); | |
background: #000; | |
background-size: cover; | |
/* background-image: url("https://gsg.live/wp-content/uploads/2022/05/cropped-gsg_neoshrimp_mono-y_xtrasmall-150x150.png"); | |
background-size: cover; */ | |
} | |
.set .artist { | |
grid-row: 1 / span 1; | |
grid-column: 2 / span 1; | |
font-size: 13px; | |
line-height: 1.2em; | |
margin-top: -2px; | |
} | |
.set .location { | |
grid-row: 2 / span 1; | |
grid-column: 2 / span 1; | |
font-family: "Rajdhani", sans-serif; | |
font-weight: 500; | |
font-size: 14px; | |
line-height: 1.1em; | |
padding-top: 3px; | |
} | |
.set.has-artist { | |
text-decoration: none; | |
color: var(--schedule-h-slot-color); | |
border: var(--schedule-h-slot-border); | |
/* border-right: none; */ | |
border-right-width: 0; | |
background: var(--schedule-h-slot-bg); | |
overflow: hidden; | |
position: sticky; | |
--offset: calc(0px - var(--schedule-h-slot-border-width)); | |
left: var(--offset); | |
margin-right: var(--offset); | |
transition: background 1s; | |
} | |
/* .items-before.highlight, | |
.items-after.highlight, */ | |
.set.has-artist.highlight { | |
background: var(--schedule-h-slot-now-bg); | |
} | |
.sets-clickable a.set.has-artist { | |
cursor: pointer; | |
pointer-events: auto; | |
} | |
.sets-clickable a.set.has-artist.highlight:hover { | |
background: var(--schedule-h-slot-now-bg-hover); | |
} | |
.sets-clickable a.set.has-artist:hover { | |
background: var(--schedule-h-slot-bg-hover); | |
transition: background 0.2s; | |
} | |
.set.has-artist + .set-col-gap { | |
z-index: 2; | |
background: none; | |
background-position-x: var(--schedule-h-slot-border-width); | |
display: grid; | |
grid-template-columns: var(--schedule-h-slot-border-width) auto; | |
/* background: #00f; */ | |
} | |
/* | |
workaround for the 1px gap with position:sticky, see: | |
https://issues.chromium.org/issues/401693546 | |
https://stackoverflow.com/questions/79517440/adding-position-sticky-creates-extra-right-margin-1px-in-chrome | |
*/ | |
.set.has-artist + .set-col-gap::before { | |
display: block; | |
content: ""; | |
margin-top: calc( | |
var(--schedule-h-gap-height-pre) + var(--schedule-h-slot-border-width) - 1px | |
); | |
height: calc( | |
var(--schedule-h-slot-height) - var(--schedule-h-slot-border-width) | |
); | |
border-left: var(--schedule-h-slot-border); | |
/* background: #00f; */ | |
} | |
.set.has-artist + .set-col-gap::after { | |
display: block; | |
content: ""; | |
} | |
.set.blank { | |
z-index: 2; | |
background-position-x: var(--schedule-h-slot-width); | |
/* background: #0f0; */ | |
} | |
.set.blank > * { | |
display: none; | |
} | |
.set.blank + .set-col-gap { | |
z-index: 2; | |
background-position-x: var(--schedule-h-slot-border-width); | |
} | |
.set-col-gap.start { | |
grid-column: 2 / span 1; | |
} | |
.set-col-gap.start, | |
.event-before, | |
.event-after { | |
grid-row: 2 / span calc(var(--raid-trains) * 2 + 1); | |
} | |
.event-before, | |
.event-after { | |
z-index: 1000; | |
font-size: 20px; | |
display: grid; | |
align-items: center; | |
min-width: var(--schedule-h-slot-width); | |
background: var(--schedule-grid-bg-color); | |
--col: rgba(255, 255, 255, 0.1); | |
--gradient: #000, #000 20px, var(--col) 20px, var(--col) 40px; | |
} | |
.event-before span, | |
.event-after span { | |
opacity: 0; | |
margin: 0 var(--schedule-h-gap-height); | |
/* border: 1px solid #f00; */ | |
transition: all 1s; | |
} | |
.event-before.highlight span, | |
.event-after.highlight span { | |
opacity: 1; | |
} | |
.event-before { | |
grid-column: 1 / span 1; | |
grid-template-rows: auto; | |
justify-items: end; | |
text-align: right; | |
margin-right: calc(0px - var(--schedule-h-gap-height)); | |
padding: 0 var(--schedule-h-gap-height); | |
background-image: repeating-linear-gradient(-45deg, var(--gradient)); | |
} | |
.event-after { | |
grid-column: calc(var(--event-slots) * 2 + 3) / span 1; | |
margin-left: calc(0px - var(--schedule-h-gap-height)); | |
padding: 0 var(--schedule-h-gap-height); | |
background-image: repeating-linear-gradient(135deg, var(--gradient)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { Duration } = window.luxon; | |
const getArtist = (() => { | |
const artists = JSON.parse( | |
'["Neon Pulse","SynthWave Spectra","Byte Seeker","Circuit Dreamer","Voltage Echo","Quantum Flow","Pixel Drift","Soundwave Mirage","EchoVolt","FutureReverb","Phase Lazer","ByteStream","HyperDrive Beats","RetroWave Shifter","NeonCircuit","Solar Drift","EchoCore","Wave Voltage","GlitchMind","ElectroZenith","SynthVortex","Binary Specter","PulseWaves","Digital Mirage","Circuit Theory","Harmonic Prism","Byte Horizon","Neon Frequency","RoboWave","EchoSonic","Pixel Pulse","Frequency Drift","CircuitFreak","ByteRider","Vortexed Pulse","Quantum Echoes","Fractal Synapse","SubZero Beats","Electric Horizon","SynthGrid","BinaryRiff","EchoSynapse","NeonGlitch","XenoPulse","Voltage Nebula","Digital Haze","SynthCore","ByteScape","HoloWave","Chromatic Volt"]' | |
); | |
const locations = JSON.parse( | |
'["Paris, France","Tokyo, Japan","New York City, USA","London, United Kingdom","Sydney, Australia","Cairo, Egypt","Rio de Janeiro, Brazil","Barcelona, Spain","Berlin, Germany","Rome, Italy","Istanbul, Turkey","Mumbai, India","Buenos Aires, Argentina","Cape Town, South Africa","Moscow, Russia","Dubai, United Arab Emirates","Mexico City, Mexico","Seoul, South Korea","Bangkok, Thailand","Toronto, Canada"]' | |
); | |
let a = -1; //Math.floor(Math.random() * 1000); | |
let l = a; | |
return () => { | |
a = (a + 1) % artists.length; | |
l = (l + 1) % locations.length; | |
let seed = a + l; | |
let imgStyle = `background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=${seed}')`; | |
return `<span class="img" style="${imgStyle}"></span><span class="artist">${artists[a]}</span><span class="location">${locations[l]}</span>`; | |
}; | |
})(); | |
const animateNow = 0; | |
const setsClickable = 0; | |
let now = 0.5; | |
const rows = [ | |
// [1, 2, 1], | |
// [2, -1, 1], | |
// [-1, 2, 1], | |
// [-2, 2], | |
// [2, -2], | |
// [2, 2] | |
// [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2] | |
[2, 2, 2, 2, 1, 2, 2, 2, 3, 2, 2], | |
[2, 1, 2, 2, 1, 2, -1, 2, 2, 2, 2, 2, -1] | |
// [3, 3, 3, 2, 2, 3, 2, 2, 3, 2] | |
// [2, -2, 2, 2, 2, 3], | |
// [3, 3, 1, -2, 2, 1, -1], | |
// [-1, 2, -2, 4, 1, -1, 2] | |
// [2, -2, 2, 2, 2, 3].reverse(), | |
// [3, 3, 1, -2, 2, 1, -1].reverse(), | |
// [-1, 2, -2, 4, 1, -1, 2].reverse() | |
]; | |
const max = rows.reduce((acc, row) => { | |
const sum = row.reduce((acc, n) => acc + Math.abs(n), 0); | |
return Math.max(acc, sum); | |
}, 0); | |
const starts = Array.from({ length: max }); | |
rows.forEach((row) => { | |
let cur = 0; | |
row.forEach((n) => { | |
const hasItem = n > 0; | |
if (hasItem) { | |
starts[cur] = true; | |
} | |
cur += Math.abs(n); | |
}); | |
}); | |
let rootStyles = []; | |
const alpha = "abcdefghijklmnopqrstuvwxyz".repeat(10); | |
const img = `<span class="img"></span>`; | |
let alphaI = 0; | |
let html = rows | |
.map((arr, row) => { | |
let cur = 3; | |
const r = row * 2 + 3; | |
return ( | |
`\n<!-- row ${row + 1} -->\n\n` + | |
arr | |
.map((cols, i) => { | |
let blank = cols < 0; | |
let cls = blank ? " blank" : " has-artist"; | |
cols = Math.abs(cols); | |
let c = cols * 2 - 1; //cols % 2 === 0 ? cols + 1 : cols | |
let sp = 1; | |
let rr = r; | |
if (blank) { | |
rr -= 1; | |
sp += 1; | |
} | |
let z = r; | |
let s; | |
let start = (cur - 1) / 2; | |
let end = (cur + c - 2) / 2 + 1; | |
let text = blank ? "" : getArtist(); | |
let icls = cls; | |
s = `grid-row:${r - 1}/span 1;grid-column:${cur}/span ${c};z-index:${ | |
z + 1 | |
}`; | |
const pre = `<div class="set-row-gap" style="${s}"></div>`; | |
s = `grid-row:${r}/span 1;grid-column:${cur}/span ${c};z-index:${z}`; | |
let d = `data-start="${start}" data-end="${end}"`; | |
let tags = ["div", "div"]; | |
if (setsClickable || i % 2) { | |
tags = [ | |
`a href="http://gsg.live/" target="_blank" draggable="false"`, | |
"a" | |
]; | |
} | |
const item = `<${tags[0]} class="set${icls}" ${d} style="${s}">${text}</${tags[1]}>`; | |
cur += c; | |
s = `grid-row:${r - 1}/span ${ | |
sp + 1 | |
};grid-column:${cur}/span 1;z-index:${z + 1}`; | |
const post = `<div class="set-col-gap" style="${s}"></div>`; | |
cur += 1; | |
return [pre, item, post].join("\n"); | |
}) | |
.filter(Boolean) | |
.join("\n\n") | |
); | |
}) | |
.join("\n"); | |
const times = [...starts, undefined] | |
.map((start, i) => { | |
let c = start ? " has-set" : " no-set"; | |
// c = " has-set"; | |
let s = `grid-column:${i * 2 + 1}/span 1`; | |
let d = `data-slot="${i + 1}"`; | |
return `<div class="time${c}" ${d} style="${s}"><span data-time="In 00:00"></span></div>`; | |
}) | |
.join("\n"); | |
rootStyles.push(`--event-slots: ${max}`); | |
rootStyles.push(`--raid-trains: ${rows.length}`); | |
const rootClassMap = { | |
"show-raid-train-names": rows.length > 1, | |
"sets-clickable": setsClickable | |
}; | |
const rootClasses = Object.entries(rootClassMap) | |
.reduce((acc, [k, v]) => (v ? [...acc, k] : acc), []) | |
.join(" "); | |
html = [ | |
"<style>", | |
":root {", | |
rootStyles.join("\n").replace(/^(.*)$/gm, " $1;"), | |
"}", | |
"</style>", | |
"", | |
'<style id="now-styles"></style>', | |
"", | |
`<div class="event ${rootClasses}">`, | |
' <div class="top-border"></div>', | |
' <div class="event-grid">', | |
[ | |
"<!-- single items -->", | |
"", | |
'<div class="now"><span>NOW</span></div>', | |
'<div class="scroll-to"><span></span></div>', | |
'<div class="set-col-gap start"></div>', | |
'<div class="set-row-gap end"></div>', | |
'<div class="event-before"><span>Starting soon!</span></div>', | |
'<div class="event-after"><span>All done!</span></div>', | |
'<div class="raid-train-name" style="grid-row:2/span 1;">Shrimp Signal</div>', | |
'<div class="raid-train-name" style="grid-row:4/span 1;">Golden Groove</div>', | |
"", | |
"<!-- times -->", | |
"", | |
times, | |
html | |
] | |
.join("\n") | |
.replace(/^/gm, " "), | |
" </div>", | |
"</div>" | |
].join("\n"); | |
$(() => { | |
$("<pre/>").text(html).appendTo("#debug-parent"); | |
$("#event-parent").html(html); | |
setNow(now); | |
let rafId; | |
let totalMovementX = 0; | |
let moves = []; | |
const resetState = () => { | |
cancelAnimationFrame(rafId); | |
moves = []; | |
}; | |
const syncPosition = (event, elem) => { | |
const { timeStamp, movementX } = event; | |
moves.push({ timeStamp, movementX }); | |
elem.scrollLeft -= movementX; | |
}; | |
const startInertia = (event, elem) => { | |
const { timeStamp } = event; | |
const recency = 30; | |
const initialMultiplier = 0.4; | |
totalMovementX = moves.reduce((sum, m) => sum + m.movementX, 0); | |
let movementX = | |
initialMultiplier * | |
moves.reduce( | |
(sum, m) => (timeStamp - m.timeStamp < recency ? sum + m.movementX : 0), | |
0 | |
); | |
resetState(); | |
let lastTime; | |
rafId = requestAnimationFrame((time) => { | |
lastTime = time; | |
const animate = (time) => { | |
if (Math.abs(movementX) > 1) { | |
elem.scrollLeft -= movementX; | |
const frameTime = time - lastTime; | |
lastTime = time; | |
movementX *= 1 - 4.25 / (1000 / frameTime); | |
rafId = requestAnimationFrame(animate); | |
} | |
}; | |
rafId = requestAnimationFrame(animate); | |
}); | |
}; | |
let eventIsHappening = true; // todo: figure this out | |
const recentlyScrolledDelay = 5000; | |
let recentlyScrolled = false; | |
let scrollIntoViewTimeoutId; | |
const disableScrollIntoView = () => { | |
clearTimeout(scrollIntoViewTimeoutId); | |
recentlyScrolled = true; | |
}; | |
const enableScrollIntoView = () => { | |
clearTimeout(scrollIntoViewTimeoutId); | |
if (!eventIsHappening) { | |
return; | |
} | |
scrollIntoViewTimeoutId = setTimeout(() => { | |
recentlyScrolled = false; | |
console.log("scrollIntoView"); | |
updateScroll({ behavior: "smooth" }); | |
}, recentlyScrolledDelay); | |
}; | |
const updateScroll = ({ behavior = "instant" } = {}) => { | |
if (recentlyScrolled || !animateNow) { | |
return; | |
} | |
const elem = $(".event .scroll-to span").get(0); | |
elem.scrollIntoView({ behavior, inline: "start" }); | |
}; | |
updateScroll(); | |
$(window).on("resize", throttle(30, updateScroll)); | |
if (animateNow) { | |
setInterval(() => { | |
now += 0.007; | |
if (now > max + 2) { | |
now = 0; | |
} | |
setNow(now); | |
updateScroll(); | |
}, 30); | |
} | |
let pressed = false; | |
$(".event") | |
.on("click", (e) => { | |
if (!setsClickable || Math.abs(totalMovementX) > 0) { | |
e.preventDefault(); | |
} | |
}) | |
.on("pointerdown", ".event-grid, .top-border, .now", (e) => { | |
disableScrollIntoView(); | |
const elem = e.delegateTarget; | |
const event = e.originalEvent; | |
// console.log("pointerdown", event.pointerId); | |
// elem.setPointerCapture(event.pointerId); | |
pressed = true; | |
resetState(); | |
}) | |
.on("pointerup", (e) => { | |
enableScrollIntoView(); | |
const elem = e.delegateTarget; | |
const event = e.originalEvent; | |
// elem.releasePointerCapture(event.pointerId); | |
pressed = false; | |
// console.log("pointerup", event.pointerId); | |
startInertia(event, elem); | |
}) | |
.on("pointermove", (e) => { | |
const elem = e.delegateTarget; | |
const event = e.originalEvent; | |
// console.log("pointermove", event.pointerId, event.movementX); | |
if (pressed || elem.hasPointerCapture(event.pointerId)) { | |
syncPosition(event, elem); | |
// enableScrollIntoView(); | |
} | |
}); | |
}); | |
function setNow(now) { | |
const nowMin = 0.5; | |
const nowMax = max + 1.5; | |
const nowConstrained = Math.max(nowMin, Math.min(now, nowMax)); | |
let css = [`:root { --now-position: ${nowConstrained} }`]; | |
if (now < nowMin || now > nowMax) { | |
css.push(".now { visibility: hidden; }"); | |
} | |
css = css.join("\n"); | |
// console.log(css); | |
$("#now-styles").text(css); | |
$(".set.has-artist").each(function () { | |
const { start, end } = this.dataset; | |
$(this).toggleClass( | |
"highlight", | |
nowConstrained >= start && nowConstrained < end | |
); | |
}); | |
$(".time.has-set").each(function () { | |
const { slot } = this.dataset; | |
const isPast = nowConstrained >= slot; | |
let time = isPast | |
? "00:00" | |
: Duration.fromObject({ hours: slot - now }).toFormat("hh:mm"); | |
$(this) | |
.toggleClass("past", isPast) | |
.children() | |
.attr("data-time", `In ${time}`); | |
}); | |
$(".event-before").toggleClass("highlight", now < 1); | |
$(".event-after").toggleClass("highlight", now >= max + 1); | |
} | |
const throttle = (time, fn) => { | |
let lastTime = 0; | |
let timeoutId; | |
return (...args) => { | |
clearTimeout(timeoutId); | |
const now = Date.now(); | |
if (now - lastTime > time) { | |
lastTime = now; | |
fn(...args); | |
} else { | |
timeoutId = setTimeout(() => fn(...args), 10); | |
} | |
}; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<style> | |
:root { | |
--event-slots: 22; | |
--raid-trains: 2; | |
} | |
</style> | |
<style id="now-styles"></style> | |
<div class="event show-raid-train-names"> | |
<div class="top-border"></div> | |
<div class="event-grid"> | |
<!-- single items --> | |
<div class="now"><span>NOW</span></div> | |
<div class="scroll-to"><span></span></div> | |
<div class="set-col-gap start"></div> | |
<div class="set-row-gap end"></div> | |
<div class="event-before"><span>Starting soon!</span></div> | |
<div class="event-after"><span>All done!</span></div> | |
<div class="raid-train-name" style="grid-row:2/span 1;">Shrimp Signal</div> | |
<div class="raid-train-name" style="grid-row:4/span 1;">Golden Groove</div> | |
<!-- times --> | |
<div class="time has-set" data-slot="1" style="grid-column:1/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time no-set" data-slot="2" style="grid-column:3/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="3" style="grid-column:5/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="4" style="grid-column:7/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="5" style="grid-column:9/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="6" style="grid-column:11/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="7" style="grid-column:13/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="8" style="grid-column:15/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="9" style="grid-column:17/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="10" style="grid-column:19/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time no-set" data-slot="11" style="grid-column:21/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="12" style="grid-column:23/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time no-set" data-slot="13" style="grid-column:25/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="14" style="grid-column:27/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time no-set" data-slot="15" style="grid-column:29/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="16" style="grid-column:31/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time no-set" data-slot="17" style="grid-column:33/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="18" style="grid-column:35/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="19" style="grid-column:37/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="20" style="grid-column:39/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time has-set" data-slot="21" style="grid-column:41/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time no-set" data-slot="22" style="grid-column:43/span 1"><span data-time="In 00:00"></span></div> | |
<div class="time no-set" data-slot="23" style="grid-column:45/span 1"><span data-time="In 00:00"></span></div> | |
<!-- row 1 --> | |
<div class="set-row-gap" style="grid-row:2/span 1;grid-column:3/span 3;z-index:4"></div> | |
<div class="set has-artist" data-start="1" data-end="3" style="grid-row:3/span 1;grid-column:3/span 3;z-index:3"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=0')"></span><span class="artist">Neon Pulse</span><span class="location">Paris, France</span></div> | |
<div class="set-col-gap" style="grid-row:2/span 2;grid-column:6/span 1;z-index:4"></div> | |
<div class="set-row-gap" style="grid-row:2/span 1;grid-column:7/span 3;z-index:4"></div> | |
<a href="http://gsg.live/" target="_blank" draggable="false" class="set has-artist" data-start="3" data-end="5" style="grid-row:3/span 1;grid-column:7/span 3;z-index:3"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=2')"></span><span class="artist">SynthWave Spectra</span><span class="location">Tokyo, Japan</span></a> | |
<div class="set-col-gap" style="grid-row:2/span 2;grid-column:10/span 1;z-index:4"></div> | |
<div class="set-row-gap" style="grid-row:2/span 1;grid-column:11/span 3;z-index:4"></div> | |
<div class="set has-artist" data-start="5" data-end="7" style="grid-row:3/span 1;grid-column:11/span 3;z-index:3"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=4')"></span><span class="artist">Byte Seeker</span><span class="location">New York City, USA</span></div> | |
<div class="set-col-gap" style="grid-row:2/span 2;grid-column:14/span 1;z-index:4"></div> | |
<div class="set-row-gap" style="grid-row:2/span 1;grid-column:15/span 3;z-index:4"></div> | |
<a href="http://gsg.live/" target="_blank" draggable="false" class="set has-artist" data-start="7" data-end="9" style="grid-row:3/span 1;grid-column:15/span 3;z-index:3"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=6')"></span><span class="artist">Circuit Dreamer</span><span class="location">London, United Kingdom</span></a> | |
<div class="set-col-gap" style="grid-row:2/span 2;grid-column:18/span 1;z-index:4"></div> | |
<div class="set-row-gap" style="grid-row:2/span 1;grid-column:19/span 1;z-index:4"></div> | |
<div class="set has-artist" data-start="9" data-end="10" style="grid-row:3/span 1;grid-column:19/span 1;z-index:3"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=8')"></span><span class="artist">Voltage Echo</span><span class="location">Sydney, Australia</span></div> | |
<div class="set-col-gap" style="grid-row:2/span 2;grid-column:20/span 1;z-index:4"></div> | |
<div class="set-row-gap" style="grid-row:2/span 1;grid-column:21/span 3;z-index:4"></div> | |
<a href="http://gsg.live/" target="_blank" draggable="false" class="set has-artist" data-start="10" data-end="12" style="grid-row:3/span 1;grid-column:21/span 3;z-index:3"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=10')"></span><span class="artist">Quantum Flow</span><span class="location">Cairo, Egypt</span></a> | |
<div class="set-col-gap" style="grid-row:2/span 2;grid-column:24/span 1;z-index:4"></div> | |
<div class="set-row-gap" style="grid-row:2/span 1;grid-column:25/span 3;z-index:4"></div> | |
<div class="set has-artist" data-start="12" data-end="14" style="grid-row:3/span 1;grid-column:25/span 3;z-index:3"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=12')"></span><span class="artist">Pixel Drift</span><span class="location">Rio de Janeiro, Brazil</span></div> | |
<div class="set-col-gap" style="grid-row:2/span 2;grid-column:28/span 1;z-index:4"></div> | |
<div class="set-row-gap" style="grid-row:2/span 1;grid-column:29/span 3;z-index:4"></div> | |
<a href="http://gsg.live/" target="_blank" draggable="false" class="set has-artist" data-start="14" data-end="16" style="grid-row:3/span 1;grid-column:29/span 3;z-index:3"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=14')"></span><span class="artist">Soundwave Mirage</span><span class="location">Barcelona, Spain</span></a> | |
<div class="set-col-gap" style="grid-row:2/span 2;grid-column:32/span 1;z-index:4"></div> | |
<div class="set-row-gap" style="grid-row:2/span 1;grid-column:33/span 5;z-index:4"></div> | |
<div class="set has-artist" data-start="16" data-end="19" style="grid-row:3/span 1;grid-column:33/span 5;z-index:3"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=16')"></span><span class="artist">EchoVolt</span><span class="location">Berlin, Germany</span></div> | |
<div class="set-col-gap" style="grid-row:2/span 2;grid-column:38/span 1;z-index:4"></div> | |
<div class="set-row-gap" style="grid-row:2/span 1;grid-column:39/span 3;z-index:4"></div> | |
<a href="http://gsg.live/" target="_blank" draggable="false" class="set has-artist" data-start="19" data-end="21" style="grid-row:3/span 1;grid-column:39/span 3;z-index:3"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=18')"></span><span class="artist">FutureReverb</span><span class="location">Rome, Italy</span></a> | |
<div class="set-col-gap" style="grid-row:2/span 2;grid-column:42/span 1;z-index:4"></div> | |
<div class="set-row-gap" style="grid-row:2/span 1;grid-column:43/span 3;z-index:4"></div> | |
<div class="set has-artist" data-start="21" data-end="23" style="grid-row:3/span 1;grid-column:43/span 3;z-index:3"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=20')"></span><span class="artist">Phase Lazer</span><span class="location">Istanbul, Turkey</span></div> | |
<div class="set-col-gap" style="grid-row:2/span 2;grid-column:46/span 1;z-index:4"></div> | |
<!-- row 2 --> | |
<div class="set-row-gap" style="grid-row:4/span 1;grid-column:3/span 3;z-index:6"></div> | |
<div class="set has-artist" data-start="1" data-end="3" style="grid-row:5/span 1;grid-column:3/span 3;z-index:5"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=22')"></span><span class="artist">ByteStream</span><span class="location">Mumbai, India</span></div> | |
<div class="set-col-gap" style="grid-row:4/span 2;grid-column:6/span 1;z-index:6"></div> | |
<div class="set-row-gap" style="grid-row:4/span 1;grid-column:7/span 1;z-index:6"></div> | |
<a href="http://gsg.live/" target="_blank" draggable="false" class="set has-artist" data-start="3" data-end="4" style="grid-row:5/span 1;grid-column:7/span 1;z-index:5"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=24')"></span><span class="artist">HyperDrive Beats</span><span class="location">Buenos Aires, Argentina</span></a> | |
<div class="set-col-gap" style="grid-row:4/span 2;grid-column:8/span 1;z-index:6"></div> | |
<div class="set-row-gap" style="grid-row:4/span 1;grid-column:9/span 3;z-index:6"></div> | |
<div class="set has-artist" data-start="4" data-end="6" style="grid-row:5/span 1;grid-column:9/span 3;z-index:5"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=26')"></span><span class="artist">RetroWave Shifter</span><span class="location">Cape Town, South Africa</span></div> | |
<div class="set-col-gap" style="grid-row:4/span 2;grid-column:12/span 1;z-index:6"></div> | |
<div class="set-row-gap" style="grid-row:4/span 1;grid-column:13/span 3;z-index:6"></div> | |
<a href="http://gsg.live/" target="_blank" draggable="false" class="set has-artist" data-start="6" data-end="8" style="grid-row:5/span 1;grid-column:13/span 3;z-index:5"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=28')"></span><span class="artist">NeonCircuit</span><span class="location">Moscow, Russia</span></a> | |
<div class="set-col-gap" style="grid-row:4/span 2;grid-column:16/span 1;z-index:6"></div> | |
<div class="set-row-gap" style="grid-row:4/span 1;grid-column:17/span 1;z-index:6"></div> | |
<div class="set has-artist" data-start="8" data-end="9" style="grid-row:5/span 1;grid-column:17/span 1;z-index:5"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=30')"></span><span class="artist">Solar Drift</span><span class="location">Dubai, United Arab Emirates</span></div> | |
<div class="set-col-gap" style="grid-row:4/span 2;grid-column:18/span 1;z-index:6"></div> | |
<div class="set-row-gap" style="grid-row:4/span 1;grid-column:19/span 3;z-index:6"></div> | |
<a href="http://gsg.live/" target="_blank" draggable="false" class="set has-artist" data-start="9" data-end="11" style="grid-row:5/span 1;grid-column:19/span 3;z-index:5"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=32')"></span><span class="artist">EchoCore</span><span class="location">Mexico City, Mexico</span></a> | |
<div class="set-col-gap" style="grid-row:4/span 2;grid-column:22/span 1;z-index:6"></div> | |
<div class="set-row-gap" style="grid-row:4/span 1;grid-column:23/span 1;z-index:6"></div> | |
<div class="set blank" data-start="11" data-end="12" style="grid-row:5/span 1;grid-column:23/span 1;z-index:5"></div> | |
<div class="set-col-gap" style="grid-row:4/span 3;grid-column:24/span 1;z-index:6"></div> | |
<div class="set-row-gap" style="grid-row:4/span 1;grid-column:25/span 3;z-index:6"></div> | |
<a href="http://gsg.live/" target="_blank" draggable="false" class="set has-artist" data-start="12" data-end="14" style="grid-row:5/span 1;grid-column:25/span 3;z-index:5"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=34')"></span><span class="artist">Wave Voltage</span><span class="location">Seoul, South Korea</span></a> | |
<div class="set-col-gap" style="grid-row:4/span 2;grid-column:28/span 1;z-index:6"></div> | |
<div class="set-row-gap" style="grid-row:4/span 1;grid-column:29/span 3;z-index:6"></div> | |
<div class="set has-artist" data-start="14" data-end="16" style="grid-row:5/span 1;grid-column:29/span 3;z-index:5"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=36')"></span><span class="artist">GlitchMind</span><span class="location">Bangkok, Thailand</span></div> | |
<div class="set-col-gap" style="grid-row:4/span 2;grid-column:32/span 1;z-index:6"></div> | |
<div class="set-row-gap" style="grid-row:4/span 1;grid-column:33/span 3;z-index:6"></div> | |
<a href="http://gsg.live/" target="_blank" draggable="false" class="set has-artist" data-start="16" data-end="18" style="grid-row:5/span 1;grid-column:33/span 3;z-index:5"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=38')"></span><span class="artist">ElectroZenith</span><span class="location">Toronto, Canada</span></a> | |
<div class="set-col-gap" style="grid-row:4/span 2;grid-column:36/span 1;z-index:6"></div> | |
<div class="set-row-gap" style="grid-row:4/span 1;grid-column:37/span 3;z-index:6"></div> | |
<div class="set has-artist" data-start="18" data-end="20" style="grid-row:5/span 1;grid-column:37/span 3;z-index:5"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=20')"></span><span class="artist">SynthVortex</span><span class="location">Paris, France</span></div> | |
<div class="set-col-gap" style="grid-row:4/span 2;grid-column:40/span 1;z-index:6"></div> | |
<div class="set-row-gap" style="grid-row:4/span 1;grid-column:41/span 3;z-index:6"></div> | |
<a href="http://gsg.live/" target="_blank" draggable="false" class="set has-artist" data-start="20" data-end="22" style="grid-row:5/span 1;grid-column:41/span 3;z-index:5"><span class="img" style="background-image: url('https://api.dicebear.com/9.x/identicon/svg?seed=22')"></span><span class="artist">Binary Specter</span><span class="location">Tokyo, Japan</span></a> | |
<div class="set-col-gap" style="grid-row:4/span 2;grid-column:44/span 1;z-index:6"></div> | |
<div class="set-row-gap" style="grid-row:4/span 1;grid-column:45/span 1;z-index:6"></div> | |
<div class="set blank" data-start="22" data-end="23" style="grid-row:5/span 1;grid-column:45/span 1;z-index:5"></div> | |
<div class="set-col-gap" style="grid-row:4/span 3;grid-column:46/span 1;z-index:6"></div> | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function test(FOO, BAR) { | |
const result = [30, 60, 85, 120, 144].map((fps) => { | |
const refFrameTime = 1000 / 85; | |
const refLength = 90; | |
const frameTime = 1000 / fps; | |
const getSteps = (initialDelta) => { | |
let delta = initialDelta; | |
const result = []; | |
while (result.length < 1000 && delta > 1) { | |
result.push(delta); | |
delta *= FOO - BAR / fps; | |
} | |
const frameRatio = frameTime / refFrameTime; | |
const lenRatio = refLength / result.length; | |
return (1 - lenRatio / frameRatio) * 100 | |
}; | |
return Math.abs(getSteps(100)); | |
}); | |
const avg = result.reduce((a, n) => a + n, 0) / result.length | |
const str = result.map(n => String(n).slice(0,5)).join(' ') | |
return [FOO, BAR, avg, str]; | |
} | |
a = Array.from({ length: 200 }, (_, x) => Array.from({ length: 1000 }, (_, y) => { | |
return test((900 + x) / 1000, (3500 + y) / 1000) | |
})).reduce((acc, arr) => [...acc, ...arr], []).sort((a,b) => a[2] - b[2]).slice(0, 100) | |
a = a.reduce((acc,arr) => { | |
const [FOO, BAR, avg, str] = arr | |
return { | |
...acc, | |
[avg]: acc[avg] ? [...acc[avg], arr] : [arr] | |
} | |
}, {}) | |
Object.values(a).map(arr => arr.sort((a,b) => String(a[1]).length - String(b[1]).length)[0]) | |
/* | |
[ | |
[ 0.999, 4.16, 0.7116005098883238, '2.466 0.735 0 0.046 0.309' ], | |
[ 0.998, 4.05, 0.7179413134923607, '0.735 0.735 1.098 0.046 0.973' ], | |
[ 0.999, 4.17, 0.732608913249666, '2.466 0.840 0 0.046 0.309' ], | |
[ 0.998, 4.07, 0.7915966386554629, '0.735 0.735 0 0.840 1.647' ], | |
[ 0.998, 4.066, 0.8525731794837865, '0.735 0.735 1.098 0.046 1.647' ], | |
[ 0.999, 4.182, 0.8654693073201614, '2.466 0.840 0 0.046 0.973' ], | |
[ 0.998, 4.034, 0.8905107836752579, '0.735 2.262 1.098 0.046 0.309' ], | |
[ 0.999, 4.154, 0.9313807296685429, '2.466 0.735 1.098 0.046 0.309' ], | |
[ 1, 4.25, 1.0071095887035189, '2.466 0.840 0 0.735 0.993' ], | |
[ 0.998, 4.067, 1.011376858435682, '0.735 0.735 1.098 0.840 1.647' ] | |
] | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link rel="preconnect" href="https://fonts.googleapis.com"> | |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
<link href="https://fonts.googleapis.com/css2?family=Rajdhani:wght@300;400;500;600;700&family=Revalia&display=swap" rel="stylesheet"> | |
<div id="debug-parent"></div> | |
<div id="event-parent"></div> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://codepen.io/cowboy/pen/jEOKoQa