208 lines
6.2 KiB
PHP
208 lines
6.2 KiB
PHP
<?php snippet('header') ?>
|
|
|
|
<style>
|
|
body { display: grid; grid: 1fr auto / 1fr; height: 100dvh; }
|
|
#bgCanvas { position: fixed; z-index: -1; }
|
|
</style>
|
|
|
|
<canvas id="bgCanvas"></canvas>
|
|
|
|
<script>
|
|
const NORMAL_SMALL = 29
|
|
const NORMAL_BIG = 49
|
|
|
|
const MOBILE_SMALL = 10
|
|
const MOBILE_BIG = 19.5
|
|
|
|
let small = NORMAL_SMALL
|
|
let big = NORMAL_BIG
|
|
|
|
function setupCanvas(canvas) {
|
|
const dpr = window.devicePixelRatio || 1
|
|
const rect = canvas.getBoundingClientRect()
|
|
canvas.width = rect.width * dpr
|
|
canvas.height = rect.height * dpr
|
|
const ctx = canvas.getContext('2d')
|
|
ctx.scale(dpr, dpr)
|
|
|
|
if (canvas.width > 750) {
|
|
small = NORMAL_SMALL
|
|
big = NORMAL_BIG
|
|
} else {
|
|
small = MOBILE_SMALL
|
|
big = MOBILE_BIG
|
|
}
|
|
|
|
return ctx
|
|
}
|
|
|
|
let interval = null
|
|
|
|
function resizeCanvas() {
|
|
clearInterval(interval)
|
|
|
|
const canvas = document.getElementById('bgCanvas')
|
|
canvas.style.width = `${window.innerWidth}px`
|
|
canvas.style.height = `${window.innerHeight}px`
|
|
const ctx = setupCanvas(canvas)
|
|
drawBackground(ctx, canvas)
|
|
|
|
interval = setInterval(() => drawBackground(ctx, canvas), 1000)
|
|
}
|
|
// white, pink, green, lila, orange, black
|
|
const colors = ["#f1edeb", "#ff00ff", "#48bd8d", "#8200ff", "#ff6700", "#000000"]
|
|
|
|
function grid(colorIndex, canvas, ctx) {
|
|
ctx.strokeStyle = colors[colorIndex]
|
|
|
|
for (let x = 0; x < canvas.width; x += small + big + small) {
|
|
ctx.moveTo(x, 0)
|
|
ctx.lineTo(x, canvas.height)
|
|
ctx.moveTo(x + small, 0)
|
|
ctx.lineTo(x + small, canvas.height)
|
|
ctx.moveTo(x + small + big, 0)
|
|
ctx.lineTo(x + small + big, canvas.height)
|
|
}
|
|
|
|
for (let y = 0; y < canvas.height; y += small + big) {
|
|
ctx.moveTo(0, y)
|
|
ctx.lineTo(canvas.width, y)
|
|
ctx.moveTo(0, y + small)
|
|
ctx.lineTo(canvas.width, y + small)
|
|
}
|
|
|
|
ctx.stroke()
|
|
}
|
|
|
|
function bg(colorIndex, canvas, ctx, randomColors) {
|
|
const a = colors[(colorIndex + Math.round(Math.random() * (colors.length - 1))) % colors.length]
|
|
const b = colors[(colorIndex + Math.round(Math.random() * (colors.length - 1))) % colors.length]
|
|
const c = colors[(colorIndex + Math.round(Math.random() * (colors.length - 1))) % colors.length]
|
|
const d = colors[(colorIndex + Math.round(Math.random() * (colors.length - 1))) % colors.length]
|
|
const e = colors[(colorIndex + Math.round(Math.random() * (colors.length - 1))) % colors.length]
|
|
const f = colors[(colorIndex + Math.round(Math.random() * (colors.length - 1))) % colors.length]
|
|
|
|
for (let x = 0; x < canvas.width; x += small + big + small) {
|
|
for (let y = 0; y < canvas.height; y += small + big) {
|
|
if (randomColors) ctx.fillStyle = ctx.fillStyle = a
|
|
ctx.fillRect(x, y, small, small)
|
|
if (randomColors) ctx.fillStyle = ctx.fillStyle = b
|
|
ctx.fillRect(x + small, y, big, small)
|
|
if (randomColors) ctx.fillStyle = ctx.fillStyle = c
|
|
ctx.fillRect(x + small + big, y, small, small)
|
|
|
|
if (randomColors) ctx.fillStyle = ctx.fillStyle = d
|
|
ctx.fillRect(x, y + small, small, big)
|
|
if (randomColors) ctx.fillStyle = ctx.fillStyle = e
|
|
ctx.fillRect(x + small, y + small, big, big)
|
|
if (randomColors) ctx.fillStyle = ctx.fillStyle = f
|
|
ctx.fillRect(x + small + big, y + small, small, big)
|
|
}
|
|
}
|
|
}
|
|
|
|
function font(colorIndex, canvas, ctx) {
|
|
if (canvas.width > 750) {
|
|
ctx.font = '195px Kobata'
|
|
|
|
kerningNormal = { R: -12, E: -27, C: -13, A: -13, P: -13, I: -13, T: -13, U: -13, L: -13, N: -13, G: -13 }
|
|
kerningWide = { Q: 178.7, U: 178.7, E: 178.7 }
|
|
} else {
|
|
ctx.font = '74px Kobata'
|
|
|
|
kerningNormal = { R: -6, E: -13, C: -6, A: -6, P: -6, I: -6, T: -6, U: -6, L: -6, N: -6, G: -6 }
|
|
kerningWide = { Q: 38, U: 38, E: 38 }
|
|
}
|
|
|
|
const patterns = [
|
|
[0],
|
|
[0, 1]
|
|
]
|
|
|
|
function word(str, y, colorIndex, pattern, kerning) {
|
|
let x = -10
|
|
for (var i = 0; i < str.length; i++) {
|
|
const t = colorIndex + pattern[i % pattern.length]
|
|
ctx.fillStyle = colors[t % colors.length]
|
|
|
|
const char = str[i]
|
|
ctx.fillText(char, x, y)
|
|
x += ctx.measureText(char).width
|
|
|
|
if (kerning[char]) {
|
|
let k = kerning[char]
|
|
if (canvas.width < 750) k = k * 0.51724138
|
|
x += k
|
|
}
|
|
|
|
if (char == "A" && str[i+1] == "T") {
|
|
x -= 7
|
|
}
|
|
}
|
|
}
|
|
|
|
const a = patterns[Math.round(Math.random() * (patterns.length - 1))]
|
|
const b = patterns[Math.round(Math.random() * (patterns.length - 1))]
|
|
|
|
const height = ctx.measureText('A').actualBoundingBoxAscent
|
|
|
|
ctx.letterSpacing = 0
|
|
for (var y = 0; y < canvas.height; y += height * 2) {
|
|
word('RE CAPITULATING.', y + height, colorIndex, a, kerningNormal)
|
|
word('QUEER', y + height + height, colorIndex, b, kerningWide)
|
|
}
|
|
}
|
|
|
|
function drawBackground(ctx, canvas) {
|
|
const colorIndex = Math.round(Math.random() * (colors.length - 1))
|
|
|
|
bg(colorIndex, canvas, ctx, true)
|
|
grid(colorIndex, canvas, ctx)
|
|
font(colorIndex, canvas, ctx)
|
|
}
|
|
|
|
async function start() {
|
|
const font = new FontFace('Kobata', 'url(assets/Kobata-Bold.woff2)')
|
|
|
|
await font.load()
|
|
|
|
document.fonts.add(font)
|
|
|
|
window.addEventListener('resize', resizeCanvas)
|
|
resizeCanvas()
|
|
}
|
|
|
|
start()
|
|
</script>
|
|
|
|
<style>
|
|
#info { display: none; position: absolute; left: 498px; top: 0; bottom: 0; padding: 22pt; padding-bottom: calc(22pt + 40pt + 22pt + 22pt); overflow-x: hidden; }
|
|
#info-button { padding-left: calc(498px + 22pt); padding-top: 22pt; overflow-wrap: initial; hyphens: initial; }
|
|
@media (max-width: 750px) {
|
|
#info { left: 0; overflow-y: scroll; padding-bottom: calc(11pt + 16pt + 11pt + 11pt); }
|
|
#info-button { padding-left: 79pt }
|
|
}
|
|
</style>
|
|
|
|
<div id="info-button">
|
|
<button id="info_open" aria-label="Info Open" class="menu-button no-button flex font-kobata text-40 uppercase">Info</button>
|
|
</div>
|
|
|
|
<div id="info" class="bg-white-green">
|
|
<button id="info_close" aria-label="Info Close" class="menu-button no-button flex" style="margin-top: 4px"><div style="transform: rotate(45deg); "></div><div style="transform: translate(0,-6px) rotate(135deg);"></div></button>
|
|
<div class="text-22" style="margin-top: 34pt">
|
|
<?= $page->text()->kirbytext() ?>
|
|
</div>
|
|
</div>
|
|
|
|
<script defer>
|
|
const $info = document.getElementById('info')
|
|
document.getElementById('info_open').addEventListener('click', () => {
|
|
$info.classList.add('block')
|
|
})
|
|
document.getElementById('info_close').addEventListener('click', () => {
|
|
$info.classList.remove('block')
|
|
})
|
|
</script>
|
|
|
|
<?php snippet('footer', ['dont_show_footer' => true]) ?>
|