add 38c3 theming

This commit is contained in:
Julian Brammer 2024-11-25 00:26:13 +01:00
parent 03c801ecc5
commit 13f6399fc0
5 changed files with 334 additions and 35 deletions

View File

@ -127,8 +127,8 @@
"group": 2 "group": 2
}, },
{ {
"name": "source code", "name": "source code (38c3 branch)",
"href": "https://git.brulijam.com/brulijam/introduction-website", "href": "https://git.brulijam.com/brulijam/introduction-website/src/branch/38c3-theme",
"group": "footer" "group": "footer"
}, },
{ {

View File

@ -1,22 +1,45 @@
/* Root Variables */ /* Root Variables */
:root { :root {
--bg-color: rgb(15, 15, 15);
--primary: rgb(240, 240, 240);
--secondary-color: hsl(210, 80%, 80%);
--secondary-color2: hsl(210, 60%, 40%);
--secondary-color-bg: hsl(210, 40%, 5%);
--font-weight: 350; --font-weight: 350;
--font-family: "Lucida Console"; --font-family: 'space-mono';
--bigger-font-weight: 700; --bigger-font-weight: 700;
--link-border-radius: 1000px; --link-border-radius: 1000px;
--page-max-width: 700px; --page-max-width: 700px;
--color-primary: #FF5053;
--color-highlight: #FEF2FF;
--color-accent-a: #B2AAFF;
--color-accent-b: #6A5FDB;
--color-accent-c: #29114C;
--color-accent-d: #261A66;
--color-accent-e: #190B2F;
--color-background: #0F000A;
}
@font-face {
font-family: 'pilowlava';
/*src: URL('../fonts/pilowlava/Fonts/webfonts/Pilowlava-Regular.woff2') format('woff2');*/
src: url('../fonts/pilowlava/Fonts/webfonts/Pilowlava-Regular.woff2') format('woff2');
}
@font-face {
font-family: 'spacegrotesk';
src: url('../fonts/space-grotesk-1.1.4/webfont/SpaceGrotesk-Regular.woff2') format('woff2');
}
@font-face {
font-family: 'space-mono';
src: url('../fonts/space-mono/SpaceMono-Regular.ttf') format('truetype');
}
@font-face {
font-family: 'uncut-sans';
src: url('../fonts/uncut-sans/Webfonts/UncutSans-Regular.woff2') format('woff2');
} }
/* General Styles */ /* General Styles */
body { body {
background-color: var(--secondary-color-bg); background-color: var(--color-background);
color: var(--primary); color: var(--color-accent-a);
/*color: var(--primary);*/
font-family: var(--font-family), monospace; font-family: var(--font-family), monospace;
font-weight: var(--font-weight); font-weight: var(--font-weight);
overflow-x: hidden; overflow-x: hidden;
@ -31,23 +54,59 @@ h1, p {
main { main {
position: relative; position: relative;
z-index: 1; z-index: 2;
max-width: var(--page-max-width); max-width: var(--page-max-width);
margin: 0 auto; margin: 0 auto;
padding: 20px; padding: 20px;
filter: drop-shadow(0 0 2px var(--secondary-color)) brightness(1); /*filter: drop-shadow(0 0 2px var(--color-primary)) brightness(1);*/
} }
::selection { ::selection {
color: var(--bg-color); color: var(--color-background);
background: var(--secondary-color); background: var(--color-primary);
} }
/* 38c3 */
.blobs {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1; /* Keep the container behind all content */
pointer-events: none; /* Prevent interaction */
overflow: hidden;
}
.blobs img {
pointer-events: none; /* Ensure the images don't block anything */
will-change: transform; /* Improve performance for animations */
}
.grid {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -2; /* Ensure the grid is behind the blobs */
display: grid;
pointer-events: none; /* Prevent interaction */
opacity: 0.5;
background-image: linear-gradient(var(--color-accent-e) 1px, transparent 1px),
linear-gradient(90deg, var(--color-accent-e) 1px, transparent 1px);
background-size: 60px 60px; /* Adjust the grid spacing */
background-color: var(--color-background); /* Base color for the grid */
}
/* Header Styles */ /* Header Styles */
header { header {
text-align: center; text-align: center;
width: max-content; width: max-content;
margin: 0 auto; margin: 0 auto;
/*background-color: var(--color-background);*/
/*border: 1px var(--color-accent-e) solid;*/
} }
header .names { header .names {
@ -57,7 +116,14 @@ header .names {
header h1, header p { header h1, header p {
text-align: left; text-align: left;
color: var(--secondary-color); font-size: 35px;
color: var(--color-primary);
font-family: pilowlava, monospace;
}
header p {
font-family: space-mono, monospace;
font-size: 25px;
} }
header img { header img {
@ -66,10 +132,24 @@ header img {
padding: 0; padding: 0;
} }
/* Description */
header, .description, .linkGroup, .timer, footer {
background-color: rgba(15, 0, 10, 0.9);
/*border: 1px var(--color-primary) solid;*/
border: 1px var(--color-accent-c) solid;
}
header, .description, .linkGroup, .timer {
padding: 5px;
}
/* Links Styles */ /* Links Styles */
h2 { h2 {
width: 100%; width: 100%;
font-size: 30px;
margin: 0; margin: 0;
color: var(--color-accent-a);
font-family: pilowlava, monospace;
@media only screen and (max-width: 480px) { @media only screen and (max-width: 480px) {
text-align: center; /* slim */ text-align: center; /* slim */
@ -77,7 +157,7 @@ h2 {
} }
@media only screen and (min-width: 480px) { @media only screen and (min-width: 480px) {
text-align: left; /* wide */ text-align: center; /* wide */
margin: 0; margin: 0;
} }
} }
@ -91,7 +171,7 @@ h2 {
} }
.text-link { .text-link {
color: var(--secondary-color); color: var(--color-primary);
text-decoration: none; text-decoration: none;
position: relative; position: relative;
padding: 5px; padding: 5px;
@ -100,13 +180,13 @@ h2 {
} }
.text-link:hover { .text-link:hover {
filter: drop-shadow(0 0 5px var(--secondary-color2)) brightness(1.02); filter: drop-shadow(0 0 5px var(--color-primary)) brightness(1.02);
top: -2px; top: -2px;
} }
/* Links Container */ /* Links Container */
.links { .links {
padding: 0 10px; padding: 0 0;
} }
/* Link Group */ /* Link Group */
@ -119,6 +199,11 @@ h2 {
} }
} }
.linkGroup * {
color: var(--color-accent-a);
border: none;
}
/* Link Styles */ /* Link Styles */
.link { .link {
height: fit-content; height: fit-content;
@ -142,8 +227,8 @@ h2 {
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
text-transform: lowercase; text-transform: lowercase;
color: var(--bg-color); color: var(--color-background);
background-color: var(--secondary-color); background-color: var(--color-primary);
display: block; display: block;
box-sizing: border-box; box-sizing: border-box;
padding: 10px 20px; padding: 10px 20px;
@ -152,6 +237,7 @@ h2 {
@media only screen and (min-width: 480px) { @media only screen and (min-width: 480px) {
width: auto; /* wide */ width: auto; /* wide */
padding: 5px 20px;
} }
} }
@ -166,7 +252,7 @@ h2 {
/* Default Hover Effect */ /* Default Hover Effect */
.hoverHighlight:hover { .hoverHighlight:hover {
@media only screen and (min-width: 480px) { @media only screen and (min-width: 480px) {
filter: drop-shadow(0 0 8px var(--secondary-color)) brightness(1.1); filter: drop-shadow(0 0 8px var(--color-primary)) brightness(1.1);
top: -2px; top: -2px;
} }
} }
@ -178,7 +264,7 @@ h2 {
/* Search Highlighting */ /* Search Highlighting */
.highlightSearch { .highlightSearch {
filter: drop-shadow(0 0 8px var(--secondary-color)) brightness(1.1); filter: drop-shadow(0 0 8px var(--color-primary)) brightness(1.1);
z-index: 1; z-index: 1;
@media only screen and (min-width: 480px) { @media only screen and (min-width: 480px) {
top: -2px; top: -2px;
@ -206,9 +292,9 @@ h2 {
} }
#link-search { #link-search {
background-color: var(--secondary-color2); background-color: var(--color-background);
color: var(--secondary-color); color: var(--color-accent-a);
border: 2px solid var(--secondary-color2); border: 2px solid var(--color-primary);
border-radius: 50px; border-radius: 50px;
padding: 10px 15px; padding: 10px 15px;
font-size: 16px; font-size: 16px;
@ -221,21 +307,21 @@ h2 {
} }
#link-search::placeholder { #link-search::placeholder {
color: var(--secondary-color); color: var(--color-accent-a);
opacity: 0.9; /* Placeholder text opacity */ opacity: 0.9; /* Placeholder text opacity */
} }
#link-search:focus::placeholder { #link-search:focus::placeholder {
color: var(--secondary-color); color: var(--color-accent-e);
opacity: 0.9; /* Placeholder text opacity */ opacity: 0.9; /* Placeholder text opacity */
} }
#link-search:focus { #link-search:focus {
outline: none; outline: none;
background-color: var(--secondary-color-bg); background-color: var(--color-background);
box-shadow: 0 0 10px var(--secondary-color); box-shadow: 0 0 10px var(--color-primary);
border-color: var(--secondary-color2); border-color: var(--color-primary);
color: var(--secondary-color); color: var(--color-primary);
} }
@media only screen and (max-width: 480px) { @media only screen and (max-width: 480px) {
@ -252,6 +338,9 @@ h2 {
} }
/* Timers Styles */ /* Timers Styles */
.timer {
}
.timer p { .timer p {
@media only screen and (max-width: 480px) { @media only screen and (max-width: 480px) {
margin-bottom: 20px; /* slim */ margin-bottom: 20px; /* slim */
@ -259,7 +348,8 @@ h2 {
} }
.timer p span { .timer p span {
color: var(--secondary-color); color: var(--color-primary);
/*color: var(--color-primary);*/
text-decoration: none; text-decoration: none;
} }

View File

@ -6,10 +6,11 @@
<title>Julian Brammer</title> <title>Julian Brammer</title>
<link rel="stylesheet" href="css/main.css"> <link rel="stylesheet" href="css/main.css">
<link rel="me" href="https://social.brulijam.com/@brulijam"> <link rel="me" href="https://social.brulijam.com/@brulijam">
<script src="js/main.js"></script> <!-- <script src="js/main.js"></script>-->
<script src="js/fuzzysearch.js" type="module"></script> <script src="js/fuzzysearch.js" type="module"></script>
<script src="js/links.js"></script> <script src="js/links.js"></script>
<script src="js/timer.js"></script> <script src="js/timer.js"></script>
<script src="js/background.js"></script>
</head> </head>
<body> <body>
<main> <main>

105
src/js/background.js Normal file
View File

@ -0,0 +1,105 @@
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function generateGridPositions(rows, cols) {
const positions = [];
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
const top = (row + 0.5) * (100 / rows);
const left = (col + 0.5) * (100 / cols);
positions.push({ top, left });
}
}
return positions;
}
function getRandomPosition(availablePositions) {
const index = Math.floor(Math.random() * availablePositions.length);
return availablePositions.splice(index, 1)[0];
}
function createBlob(blobContainer, type, fileName, zIndex, position) {
const blob = document.createElement('img');
blob.src = `assets/blobs/${fileName}`;
blob.classList.add(type);
const randomRotation = getRandomInt(0, 360);
// blob.style.top = `${Math.random() * 100}%`;
// blob.style.left = `${Math.random() * 100}%`;
blob.style.top = `${position.top}%`;
blob.style.left = `${position.left}%`;
blob.style.transform = `translate(-50%, -50%) rotate(${randomRotation}deg)`;
blob.style.position = 'absolute';
blob.style.maxWidth = '300%';
blob.style.opacity = type === 'line' ? '0.5' : '0.8';
blob.style.zIndex = zIndex;
blob.dataset.rotation = randomRotation;
blobContainer.appendChild(blob);
return blob;
}
function adjustBlobCount() {
const width = window.innerWidth;
const height = window.innerHeight;
const baseCount = 5;
const widthFactor = Math.max(1, Math.floor(width / 400));
const heightFactor = Math.max(1, Math.floor(height / 600));
const totalCount = Math.min(baseCount * widthFactor, baseCount * heightFactor);
const solidsCount = Math.max(1, Math.floor(totalCount * 0.5));
const linesCount = totalCount - solidsCount;
return { solidsCount, linesCount };
}
document.addEventListener('DOMContentLoaded', () => {
const grid = document.createElement('div');
grid.classList.add('grid');
document.body.prepend(grid);
const blobContainer = document.createElement('div');
blobContainer.classList.add('blobs');
document.body.prepend(blobContainer);
const { solidsCount, linesCount } = adjustBlobCount();
let zIndexCounter = 1;
const gridSize = Math.ceil(Math.sqrt(solidsCount + linesCount));
const positions = generateGridPositions(gridSize, gridSize);
for (let i = 0; i < solidsCount; i++) {
const x = getRandomInt(1, 13);
const position = getRandomPosition(positions);
createBlob(blobContainer,'solid', `blob-freeform-${x}_filled.svg`, zIndexCounter, position);
zIndexCounter += 2;
}
for (let i = 0; i < linesCount; i++) {
const x = getRandomInt(1, 13);
const position = getRandomPosition(positions);
const color = Math.random() > 0.5 ? '_red' : '';
createBlob(blobContainer, 'line', `blob-freeform-${x}${color}.svg`, zIndexCounter - 1, position);
}
});
document.addEventListener('mousemove', (event) => {
const elements = [...document.querySelectorAll('.solid, .line')];
const { clientX: mouseX, clientY: mouseY } = event;
const { innerWidth: width, innerHeight: height } = window;
const xOffset = (mouseX / width - 0.5) * 200;
const yOffset = (mouseY / height - 0.5) * 200;
elements.forEach((element, i) => {
const strength = element.classList.contains('solid') ? 5 + i * 3 : 1 + i * 0.5;
const rotation = element.dataset.rotation || 0;
element.style.transform = `translate(-50%, -50%) translate(${xOffset / strength}px, ${yOffset / strength}px) rotate(${rotation}deg)`;
});
});

103
src/js/blobs.js Normal file
View File

@ -0,0 +1,103 @@
document.addEventListener('DOMContentLoaded', () => {
// Add the grid element to the body
const grid = document.createElement('div');
grid.classList.add('grid');
document.body.prepend(grid); // Add grid to the very back
const container = document.createElement('div');
container.classList.add('blobs'); // Use "blobs" as the container class
document.body.prepend(container);
// Function to get a weighted random value favoring edges
const getEdgeBiasedRandom = () => {
const rand = Math.random(); // Random number between 0 and 1
if (rand < 0.5) {
// Favor edges (closer to 10% or 90%)
return Math.random() < 0.5 ? getRandomInt(5, 25) : getRandomInt(75, 95);
} else {
// Occasionally place blobs elsewhere (30-70%)
return getRandomInt(25, 75);
}
};
// Function to get a random integer between min and max (inclusive)
const getRandomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
// Function to adjust the number of blobs based on window size
const adjustBlobCount = () => {
const width = window.innerWidth;
const height = window.innerHeight;
// Base number of blobs, and scale based on window width and height
const baseCount = 5;
const widthMultiplier = Math.max(1, Math.floor(width / 500)); // Increase blobs per 500px width
const heightMultiplier = Math.max(1, Math.floor(height / 500)); // Increase blobs per 400px height
const totalCount = Math.min(baseCount * widthMultiplier, baseCount * heightMultiplier);
// Return number of solids and lines based on adjusted total count
const NUM_SOLIDS = Math.max(1, Math.floor(totalCount * 0.3)); // 30% solids
const NUM_LINES = totalCount - NUM_SOLIDS; // The rest are lines
return { NUM_SOLIDS, NUM_LINES };
};
// Get the number of blobs based on the window size
const { NUM_SOLIDS, NUM_LINES } = adjustBlobCount();
// Create and position blobs with distinct z-index layers
let zIndexCounter = 1; // Start z-index at 1 to avoid overlap with default content
// Randomly select and create solids (background blobs)
for (let i = 0; i < NUM_SOLIDS; i++) {
const x = getRandomInt(1, 13); // Randomly pick a blob design
createBlob('background-blob', `blob-freeform-${x}_filled.svg`, zIndexCounter);
zIndexCounter += 2; // Increment by 2 to leave gaps for lines
}
// Randomly select and create lines (foreground blobs)
for (let i = 0; i < NUM_LINES; i++) {
const x = getRandomInt(1, 13); // Randomly pick a blob design
const color = Math.random() > 0.5 ? '_red' : ''; // 50% chance to pick the red variant
createBlob('background-line', `blob-freeform-${x}${color}.svg`, zIndexCounter - 1); // Ensure lines fit between solids
}
// Function to create and position a blob
function createBlob(type, fileName, zIndex) {
const blob = document.createElement('img');
blob.src = `assets/blobs/${fileName}`; // Corrected path to assets folder
blob.classList.add(type);
blob.style.top = `${getEdgeBiasedRandom()}%`; // Use edge-biased random for top
blob.style.left = `${getEdgeBiasedRandom()}%`; // Use edge-biased random for left
blob.style.transform = `translate(-50%, -50%)`;
blob.style.position = 'absolute';
blob.style.maxWidth = '300%'; // Adjust size
blob.style.opacity = type === 'background-line' ? '0.5' : '0.8'; // More transparent for lines
blob.style.zIndex = zIndex; // Set z-index dynamically
container.appendChild(blob);
return blob;
}
// Add mouse movement effect
document.addEventListener('mousemove', (event) => {
const blobs = document.querySelectorAll('.background-blob');
const lines = document.querySelectorAll('.background-line');
const { clientX: mouseX, clientY: mouseY } = event;
const { innerWidth: width, innerHeight: height } = window;
// Stronger movement scaling factors
const xOffset = (mouseX / width - 0.5) * 100; // Amplified to 100 for stronger movements
const yOffset = (mouseY / height - 0.5) * 100;
blobs.forEach((blob, i) => {
const strength = 3 + i; // Reduce divisor for stronger movements
blob.style.transform = `translate(-50%, -50%) translate(${xOffset / strength}px, ${yOffset / strength}px)`;
});
lines.forEach((line, i) => {
const strength = 2 + i * 0.5; // Even stronger for lines
line.style.transform = `translate(-50%, -50%) translate(${xOffset / strength}px, ${yOffset / strength}px)`;
});
});
});