Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
b2e68cec12 |
|
@ -18,7 +18,7 @@ const permaTitle = 'Hacking in Parallel 2022 //// Berlin'
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header class='site-header'>
|
<header class='site-header'>
|
||||||
<a href='/' class={title ? '' : 'invisible'}>
|
<a href='/'>
|
||||||
<img class='logo' src='/design-resources/logo/slashes.svg' />
|
<img class='logo' src='/design-resources/logo/slashes.svg' />
|
||||||
</a>
|
</a>
|
||||||
<input type='checkbox' id='nav-toggle' />
|
<input type='checkbox' id='nav-toggle' />
|
||||||
|
@ -115,6 +115,7 @@ const permaTitle = 'Hacking in Parallel 2022 //// Berlin'
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
margin-left: 0.75rem;
|
margin-left: 0.75rem;
|
||||||
|
margin-right: 5rem;
|
||||||
}
|
}
|
||||||
nav {
|
nav {
|
||||||
// mobile menu styles
|
// mobile menu styles
|
||||||
|
@ -156,7 +157,7 @@ const permaTitle = 'Hacking in Parallel 2022 //// Berlin'
|
||||||
}
|
}
|
||||||
|
|
||||||
// desktop menu styles
|
// desktop menu styles
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 1024px) {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -205,7 +206,7 @@ const permaTitle = 'Hacking in Parallel 2022 //// Berlin'
|
||||||
&.desktop-only {
|
&.desktop-only {
|
||||||
height: 4.5rem;
|
height: 4.5rem;
|
||||||
width: auto;
|
width: auto;
|
||||||
gap: 1.5rem;
|
gap: 0.75rem;
|
||||||
ul {
|
ul {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
|
@ -243,6 +244,17 @@ const permaTitle = 'Hacking in Parallel 2022 //// Berlin'
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
#hero {
|
||||||
|
position: relative;
|
||||||
|
svg {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
.gradient-bg {
|
.gradient-bg {
|
||||||
background: var(--gradient);
|
background: var(--gradient);
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
|
@ -276,12 +288,12 @@ const permaTitle = 'Hacking in Parallel 2022 //// Berlin'
|
||||||
padding: 1.5rem 0;
|
padding: 1.5rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 1024px) {
|
||||||
.desktop-only {
|
.desktop-only {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 1024px) {
|
||||||
.mobile-only {
|
.mobile-only {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ import Layout from '../layouts/Layout.astro'
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
<article>
|
<article>
|
||||||
<header>
|
<header id='hero'>
|
||||||
<div>
|
<div class='hero-content'>
|
||||||
<h1><img src='/logo.svg' alt='Hacking in Parallel ////' /></h1>
|
<h1><img src='/logo.svg' alt='Hacking in Parallel ////' /></h1>
|
||||||
<time>December 27-30 2022</time>
|
<time>December 27-30 2022</time>
|
||||||
</div>
|
</div>
|
||||||
|
@ -54,10 +54,10 @@ import Layout from '../layouts/Layout.astro'
|
||||||
>.
|
>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
We also need and welcome support during HiP. For our ACC
|
We also need and welcome support during HiP. For our ACC "Angel
|
||||||
"Angel Coordination Center" we have on the 5th floor, on the roof, a
|
Coordination Center" we have on the 5th floor, on the roof, a nice big
|
||||||
nice big room with terrace and view over Berlin available as Heaven.
|
room with terrace and view over Berlin available as Heaven. Just
|
||||||
Just register in our <a href='https://engelsystem.hip-berlin.de/'
|
register in our <a href='https://engelsystem.hip-berlin.de/'
|
||||||
>Angel Coordination Center</a
|
>Angel Coordination Center</a
|
||||||
>.
|
>.
|
||||||
</p>
|
</p>
|
||||||
|
@ -84,19 +84,27 @@ import Layout from '../layouts/Layout.astro'
|
||||||
</article>
|
</article>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import '../scripts/visual.ts'
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang='scss'>
|
<style lang='scss'>
|
||||||
header {
|
header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
min-height: 50vh;
|
min-height: 64vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
.hero-content {
|
||||||
|
padding: 1.5rem 1rem;
|
||||||
|
}
|
||||||
h1 {
|
h1 {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 6.4ch;
|
font-size: 6.4ch;
|
||||||
line-height: 1.1;
|
line-height: 1.1;
|
||||||
|
// margin: 0;
|
||||||
color: var(--headline-color);
|
color: var(--headline-color);
|
||||||
img {
|
img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
@ -107,7 +115,7 @@ import Layout from '../layouts/Layout.astro'
|
||||||
}
|
}
|
||||||
.tickets {
|
.tickets {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 1024px) {
|
||||||
margin: 0 -1.5rem 3rem;
|
margin: 0 -1.5rem 3rem;
|
||||||
width: calc(100% + 3rem);
|
width: calc(100% + 3rem);
|
||||||
}
|
}
|
||||||
|
@ -117,7 +125,7 @@ import Layout from '../layouts/Layout.astro'
|
||||||
}
|
}
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 1024px) {
|
||||||
font-size: 2.2rem;
|
font-size: 2.2rem;
|
||||||
}
|
}
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
|
|
|
@ -22,8 +22,7 @@ import Layout from '../../layouts/Layout.astro'
|
||||||
</p>
|
</p>
|
||||||
<h2>Font</h2>
|
<h2>Font</h2>
|
||||||
<p>
|
<p>
|
||||||
We are using <a
|
We are using <a href='https://www.ibm.com/plex/'>IBM Plex Mono Medium</a
|
||||||
href='https://www.ibm.com/plex/'>IBM Plex Mono Medium</a
|
|
||||||
>.
|
>.
|
||||||
</p>
|
</p>
|
||||||
<section>
|
<section>
|
||||||
|
@ -243,13 +242,13 @@ import Layout from '../../layouts/Layout.astro'
|
||||||
.grid-2col {
|
.grid-2col {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 1024px) {
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.grid-3col {
|
.grid-3col {
|
||||||
display: grid;
|
display: grid;
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 1024px) {
|
||||||
grid-template-columns: repeat(3, 1fr);
|
grid-template-columns: repeat(3, 1fr);
|
||||||
}
|
}
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
|
|
185
src/scripts/visual.ts
Normal file
185
src/scripts/visual.ts
Normal 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);
|
Loading…
Reference in a new issue