first blockout integration of key visual

This commit is contained in:
Leif Niemczik 2022-11-29 00:33:43 +01:00
parent e809b7ea9e
commit b2e68cec12
4 changed files with 225 additions and 21 deletions

View file

@ -18,7 +18,7 @@ const permaTitle = 'Hacking in Parallel 2022 //// Berlin'
</head>
<body>
<header class='site-header'>
<a href='/' class={title ? '' : 'invisible'}>
<a href='/'>
<img class='logo' src='/design-resources/logo/slashes.svg' />
</a>
<input type='checkbox' id='nav-toggle' />
@ -115,6 +115,7 @@ const permaTitle = 'Hacking in Parallel 2022 //// Berlin'
height: 100%;
margin: auto;
margin-left: 0.75rem;
margin-right: 5rem;
}
nav {
// mobile menu styles
@ -132,10 +133,10 @@ const permaTitle = 'Hacking in Parallel 2022 //// Berlin'
transform: translateX(100vw);
transition: transform 0.25s ease-in-out;
z-index: 10;
@supports (height: 100dvh) {
height:100dvh;
padding:2rem;
height: 100dvh;
padding: 2rem;
}
label {
@ -156,7 +157,7 @@ const permaTitle = 'Hacking in Parallel 2022 //// Berlin'
}
// desktop menu styles
@media screen and (min-width: 768px) {
@media screen and (min-width: 1024px) {
flex-direction: row;
padding: 0;
position: relative;
@ -205,7 +206,7 @@ const permaTitle = 'Hacking in Parallel 2022 //// Berlin'
&.desktop-only {
height: 4.5rem;
width: auto;
gap: 1.5rem;
gap: 0.75rem;
ul {
flex-direction: row;
}
@ -243,6 +244,17 @@ const permaTitle = 'Hacking in Parallel 2022 //// Berlin'
font-weight: 500;
cursor: pointer;
}
#hero {
position: relative;
svg {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: -1;
}
}
.gradient-bg {
background: var(--gradient);
padding: 1.5rem;
@ -276,12 +288,12 @@ const permaTitle = 'Hacking in Parallel 2022 //// Berlin'
padding: 1.5rem 0;
}
@media screen and (max-width: 768px) {
@media screen and (max-width: 1024px) {
.desktop-only {
display: none;
}
}
@media screen and (min-width: 768px) {
@media screen and (min-width: 1024px) {
.mobile-only {
display: none;
}

View file

@ -4,8 +4,8 @@ import Layout from '../layouts/Layout.astro'
<Layout>
<article>
<header>
<div>
<header id='hero'>
<div class='hero-content'>
<h1><img src='/logo.svg' alt='Hacking in Parallel ////' /></h1>
<time>December 27-30 2022</time>
</div>
@ -54,10 +54,10 @@ import Layout from '../layouts/Layout.astro'
>.
</p>
<p>
We also need and welcome support during HiP. For our ACC
"Angel Coordination Center" we have on the 5th floor, on the roof, a
nice big room with terrace and view over Berlin available as Heaven.
Just register in our <a href='https://engelsystem.hip-berlin.de/'
We also need and welcome support during HiP. For our ACC "Angel
Coordination Center" we have on the 5th floor, on the roof, a nice big
room with terrace and view over Berlin available as Heaven. Just
register in our <a href='https://engelsystem.hip-berlin.de/'
>Angel Coordination Center</a
>.
</p>
@ -84,19 +84,27 @@ import Layout from '../layouts/Layout.astro'
</article>
</Layout>
<script>
import '../scripts/visual.ts'
</script>
<style lang='scss'>
header {
width: 100%;
padding: 1.5rem;
min-height: 50vh;
min-height: 64vh;
display: flex;
align-items: center;
justify-content: center;
}
.hero-content {
padding: 1.5rem 1rem;
}
h1 {
display: block;
font-size: 6.4ch;
line-height: 1.1;
// margin: 0;
color: var(--headline-color);
img {
max-width: 100%;
@ -107,7 +115,7 @@ import Layout from '../layouts/Layout.astro'
}
.tickets {
width: 100%;
@media screen and (min-width: 768px) {
@media screen and (min-width: 1024px) {
margin: 0 -1.5rem 3rem;
width: calc(100% + 3rem);
}
@ -117,7 +125,7 @@ import Layout from '../layouts/Layout.astro'
}
h2 {
font-size: 2rem;
@media screen and (min-width: 768px) {
@media screen and (min-width: 1024px) {
font-size: 2.2rem;
}
line-height: 1.2;

View file

@ -22,8 +22,7 @@ import Layout from '../../layouts/Layout.astro'
</p>
<h2>Font</h2>
<p>
We are using <a
href='https://www.ibm.com/plex/'>IBM Plex Mono Medium</a
We are using <a href='https://www.ibm.com/plex/'>IBM Plex Mono Medium</a
>.
</p>
<section>
@ -243,13 +242,13 @@ import Layout from '../../layouts/Layout.astro'
.grid-2col {
display: grid;
gap: 2rem;
@media screen and (min-width: 768px) {
@media screen and (min-width: 1024px) {
grid-template-columns: repeat(2, 1fr);
}
}
.grid-3col {
display: grid;
@media screen and (min-width: 768px) {
@media screen and (min-width: 1024px) {
grid-template-columns: repeat(3, 1fr);
}
gap: 2rem;

185
src/scripts/visual.ts Normal file
View file

@ -0,0 +1,185 @@
import { SVG, on as SVGOn, Svg } from "@svgdotjs/svg.js"
import { colord } from "colord"
import RandomGen from "random-seed"
interface Config {
canvas?: Svg;
seed?: string;
keepSeed: boolean;
width: number;
height: number;
circleSize: number;
padding: number;
stepSize: number;
lineChance: number;
maxLineLength: number;
colorsPerLine: number;
coloredDots?: boolean;
blockout?: { left: number, top: number, bottom: number, right: number }
}
let config: Config = {
seed: "",
keepSeed: false,
width: 800,
height: 800,
padding: 25,
circleSize: 10,
stepSize: 50,
lineChance: .1,
maxLineLength: 3,
colorsPerLine: 3,
coloredDots: true,
}
const colors = [
"#FED61E",
"#44B4E9",
"#008317",
"#002E5C",
"#003A3E",
"#6C2400",
"#FF9900",
]
// calculate absolute pposition with padding
function calcPosition({ x, y, padding, numElements, reducedDims, subtractHalfCircle = true }) {
const pos: Record<string, number> = {
posX: x / numElements.x * reducedDims.width + padding,
posY: y / numElements.y * reducedDims.height + padding
}
if (subtractHalfCircle) {
for (const key in pos) {
pos[key] -= reducedDims.halfCircle
}
}
return pos
}
function drawElement({ x, y, canvas, occupationMap, random, lineChance, lineLengthLimit, numElements, padding, circleSize, colorsPerLine, coloredDots, reducedDims, blockedDimensions }: Config & { x: number, y: number, occupationMap: number[][], random: RandomGen, lineLengthLimit: number, numElements: { x: number, y: number }, reducedDims: { width: number, height: number, halfCircle: number }, blockedDimensions: { top: number, left: number, right: number, bottom: number } }) {
let length = null
if (random.random() < lineChance!) length = random.intBetween(2, lineLengthLimit)
if (occupationMap[x].includes(y) || !canvas) return
if (length && x != numElements.x && y != 0 && (x < blockedDimensions.left - 1 || x >= blockedDimensions.right || y < blockedDimensions.top || y >= blockedDimensions.bottom - 1)) {
// Line
const { posX, posY } = calcPosition({ x, y, padding, numElements, reducedDims, subtractHalfCircle: false, })
const overshootX = Math.min(x + length - numElements.x, x + length - blockedDimensions.left);
const overshootY = Math.min((y - length) * -1, (y - blockedDimensions.bottom + length) * -1);
if (y >= blockedDimensions.bottom) { console.log(x, y, length, overshootY) };
const overshoot = Math.max(overshootX, overshootY)
if (overshoot > 0) length -= overshoot
const { posX: endX, posY: endY } = calcPosition({
x: x + length,
y: y - length,
padding,
numElements,
reducedDims,
subtractHalfCircle: false,
})
const gradient = canvas!.gradient("linear", (add) => {
for (let i = 0; i < colorsPerLine; i++) {
add.stop({ offset: i / (colorsPerLine - 1), color: colors[random(colors.length)] })
}
}).transform({
rotate: -45,
origin: { x: .5, y: .5 }
})
canvas.line(posX, posY, endX, endY).stroke({
width: circleSize,
linecap: "round"
}).attr({ "stroke": gradient })
for (let i = 0; i <= length; i++) {
if (x + i <= numElements.x) occupationMap[x + i].push(y - i)
}
} else {
// Circle
const { posX, posY } = calcPosition({ x, y, padding, numElements, reducedDims })
canvas
.circle(circleSize)
.fill(coloredDots ? colors[random(colors.length)] : "#333")
.move(posX, posY)
occupationMap[x].push(y)
}
}
function render(configParams: Config) {
// config.canvas?.remove()
if (config.seed === "") config.seed = RandomGen.create().string(16)
const { seed, width, height, padding, circleSize, stepSize, maxLineLength, blockout } = configParams
const random = RandomGen.create(seed)
const reducedDims = {
width: width - 2 * padding,
height: height - 2 * padding,
halfCircle: circleSize / 2
}
const numElements = {
x: Math.floor(reducedDims.width / stepSize),
y: Math.floor(reducedDims.height / stepSize)
}
const blockedDimensions = {
top: Math.floor((blockout!.top - padding) / stepSize),
right: Math.floor((blockout!.right + padding) / stepSize),
bottom: Math.floor((blockout!.bottom + padding) / stepSize),
left: Math.floor((blockout!.left - padding) / stepSize),
}
const lineLengthLimit = maxLineLength;
// Create 2D array of points in grid
let occupationMap: number[][] = Array.from({ length: numElements.x + 1 }, (_: never, x: number) => {
let k = [];
if (x >= blockedDimensions.left && x < blockedDimensions.right) {
for (let index = blockedDimensions.top; index < blockedDimensions.bottom - 2; index++) {
k.push(index)
}
}
return k
})
for (let x = 0; x <= numElements.x; x++) {
for (let y = 0; y <= numElements.y; y++) {
drawElement({ x, y, occupationMap, random, numElements, lineLengthLimit, reducedDims, blockedDimensions, ...config })
}
}
}
SVGOn(document, "DOMContentLoaded", () => {
const hero = document.querySelector("#hero")!
const dimens = hero.getBoundingClientRect()
const { width, height } = dimens;
config.width = width
config.height = height
config.canvas = SVG().viewbox(0, 0, width, height).size(width, height).addTo('#hero')
const block = hero.children[0]
config.blockout = block.getBoundingClientRect()
render(config)
window.addEventListener('resize', () => {
config.canvas!.clear()
const hero = document.querySelector("#hero")!
const dimens = hero.getBoundingClientRect()
const { width, height } = dimens;
config.width = width
config.height = height
config.canvas!.viewbox(0, 0, width, height).size(width, height)
config.blockout = block.getBoundingClientRect()
render(config)
})
})
console.log(config.canvas);