Adding cityscape and junk

This commit is contained in:
Dan 2025-12-11 11:58:40 +00:00
parent 0d21b06acd
commit c51942e5c0
19 changed files with 1351 additions and 146 deletions

76
assets/js/cityscape.js Normal file
View file

@ -0,0 +1,76 @@
// Configuration
const config = {
buildingsFar: { count: [10, 15], windows: [10, 30] },
buildingsMid: { count: [6, 10], windows: [20, 40] },
buildingsNear: { count: [5, 10], windows: [4, 8] },
};
// Helper function to get random integer between min and max (inclusive)
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Function to create a building with random windows
function createBuilding(minWindows, maxWindows) {
const building = document.createElement("div");
building.className = "building";
const windowsContainer = document.createElement("div");
windowsContainer.className = "building-windows";
const numWindows = randomInt(minWindows, maxWindows);
for (let i = 0; i < numWindows; i++) {
const window = document.createElement("div");
window.className = "window-light";
windowsContainer.appendChild(window);
}
building.appendChild(windowsContainer);
return building;
}
// Function to populate a layer with buildings
function populateLayer(layerName, numBuildings, windowRange) {
const layer = document.querySelector(`.${layerName}`);
if (!layer) {
console.warn(`Layer ${layerName} not found`);
return;
}
// Clear existing buildings
layer.innerHTML = "";
for (let i = 0; i < numBuildings; i++) {
const building = createBuilding(windowRange[0], windowRange[1]);
layer.appendChild(building);
}
}
// Initialize all layers
function initializeCityscape() {
populateLayer(
"buildings-far",
randomInt(...config.buildingsFar.count),
config.buildingsFar.windows,
);
populateLayer(
"buildings-mid",
randomInt(...config.buildingsMid.count),
config.buildingsMid.windows,
);
populateLayer(
"buildings-near",
randomInt(...config.buildingsNear.count),
config.buildingsNear.windows,
);
}
// Run when DOM is ready
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initializeCityscape);
} else {
initializeCityscape();
}

85
assets/js/nav_time.js Normal file
View file

@ -0,0 +1,85 @@
// Time display with glitch effect
(function () {
const timeDisplay = document.querySelector(".time-display");
if (!timeDisplay) return;
const lcdText = timeDisplay.querySelector(".lcd-text");
if (!lcdText) return;
let isHovered = false;
let timeInterval;
// Format time as hh:mm:ss
function getFormattedTime() {
const now = new Date();
const hours = String(now.getHours()).padStart(2, "0");
const minutes = String(now.getMinutes()).padStart(2, "0");
const seconds = String(now.getSeconds()).padStart(2, "0");
return `${hours}:${minutes}:${seconds}`;
}
// Update time display
function updateTime() {
if (!isHovered) {
lcdText.textContent = getFormattedTime();
}
}
// Glitch characters for effect
const glitchChars = [
"█",
"▓",
"▒",
"░",
"▀",
"▄",
"▌",
"▐",
"■",
"□",
"▪",
"▫",
"_",
"-",
"|",
];
// Create glitch effect
function glitchEffect(callback) {
let glitchCount = 0;
const maxGlitches = 5;
const glitchInterval = setInterval(() => {
// Generate random glitchy text
const glitchText = Array(8)
.fill(0)
.map(() => glitchChars[Math.floor(Math.random() * glitchChars.length)])
.join("");
lcdText.textContent = glitchText;
glitchCount++;
if (glitchCount >= maxGlitches) {
clearInterval(glitchInterval);
lcdText.textContent = "_N:OW:__";
if (callback) callback();
}
}, 50);
}
// Mouse over handler
timeDisplay.addEventListener("mouseenter", () => {
isHovered = true;
glitchEffect();
});
// Mouse out handler
timeDisplay.addEventListener("mouseleave", () => {
isHovered = false;
updateTime();
});
// Start time updates
updateTime();
timeInterval = setInterval(updateTime, 1000);
})();

View file

@ -1,25 +1,21 @@
if (document.getElementById("starfield")) { if (document.getElementById("starfield")) {
let starfield = document.getElementById("starfield"); let starfield = document.getElementById("starfield");
let numStars = 200; let numStars = parseInt(starfield.dataset.stars) || 200;
// Create static twinkling stars // Create static twinkling stars
for (let i = 0; i < numStars; i++) { for (let i = 0; i < numStars; i++) {
const star = document.createElement("div"); const star = document.createElement("div");
star.className = "star"; star.className = "star";
// Random size // Random size
const sizeClass = const sizeClass =
Math.random() < 0.7 ? "small" : Math.random() < 0.9 ? "medium" : "large"; Math.random() < 0.7 ? "small" : Math.random() < 0.9 ? "medium" : "large";
star.classList.add(sizeClass); star.classList.add(sizeClass);
// Random position // Random position
star.style.left = Math.random() * 100 + "%"; star.style.left = Math.random() * 100 + "%";
star.style.top = Math.random() * 100 + "%"; star.style.top = Math.random() * 100 + "%";
// Random animation duration (2-6 seconds) and delay // Random animation duration (2-6 seconds) and delay
star.style.animationDuration = 2 + Math.random() * 4 + "s"; star.style.animationDuration = 2 + Math.random() * 4 + "s";
star.style.animationDelay = Math.random() * 5 + "s"; star.style.animationDelay = Math.random() * 5 + "s";
starfield.appendChild(star); starfield.appendChild(star);
} }
} }

64
assets/sass/_mixins.scss Normal file
View file

@ -0,0 +1,64 @@
// Define your breakpoints
$breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
xxl: 1400px,
);
// Mixin for min-width (mobile-first)
@mixin media-up($breakpoint) {
@if map-has-key($breakpoints, $breakpoint) {
$value: map-get($breakpoints, $breakpoint);
@if $value == 0 {
@content;
} @else {
@media (min-width: $value) {
@content;
}
}
}
}
// Mixin for max-width (desktop-first)
@mixin media-down($breakpoint) {
@if map-has-key($breakpoints, $breakpoint) {
$value: map-get($breakpoints, $breakpoint);
@media (max-width: #{$value - 1px}) {
@content;
}
}
}
// Generate utility classes
@each $breakpoint, $value in $breakpoints {
// Hidden at this breakpoint and up
.hidden-#{$breakpoint}-up {
@include media-up($breakpoint) {
display: none !important;
}
}
// Hidden at this breakpoint and down
.hidden-#{$breakpoint}-down {
@include media-down($breakpoint) {
display: none !important;
}
}
// Visible only at this breakpoint
.visible-#{$breakpoint}-only {
display: none !important;
@include media-up($breakpoint) {
@if $breakpoint != xxl {
@include media-down($breakpoint) {
display: block !important;
}
} @else {
display: block !important;
}
}
}
}

View file

@ -34,7 +34,7 @@
.lamp-text { .lamp-text {
font-size: 30px; font-size: 30px;
color: rgba(224, 27, 36, 0.7); //color: rgba(224, 27, 36, 0.7);
} }
} }

View file

@ -1,16 +1,129 @@
.lava-lamp-container { .lava-lamp-container {
position: absolute;
bottom: 20%;
left: 20%;
width: 80px; width: 80px;
height: 150px; height: 150px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
z-index: 999; z-index: 999;
position: relative;
margin: 0 auto; margin: 0 auto;
//width: fit-content; /* or specify a fixed width */
.nav-lamp & {
top: -20px;
@include media-down(lg) {
top: auto;
}
}
&::before {
content: "";
position: absolute;
top: 10%;
width: 150%;
height: 80%;
background: conic-gradient(
from 0deg,
rgba(255, 100, 0, 0.8) 0deg,
transparent 5deg,
transparent 10deg,
rgba(255, 150, 0, 0.6) 15deg,
transparent 20deg,
transparent 25deg,
rgba(255, 200, 0, 0.7) 30deg,
transparent 35deg,
transparent 40deg,
rgba(255, 100, 0, 0.8) 45deg,
transparent 50deg,
transparent 55deg,
rgba(255, 150, 0, 0.6) 60deg,
transparent 65deg,
transparent 70deg,
rgba(255, 200, 0, 0.7) 75deg,
transparent 80deg,
transparent 85deg,
rgba(255, 100, 0, 0.8) 90deg,
transparent 95deg,
transparent 100deg,
rgba(255, 150, 0, 0.6) 105deg,
transparent 110deg,
transparent 115deg,
rgba(255, 200, 0, 0.7) 120deg,
transparent 125deg,
transparent 130deg,
rgba(255, 100, 0, 0.8) 135deg,
transparent 140deg,
transparent 145deg,
rgba(255, 150, 0, 0.6) 150deg,
transparent 155deg,
transparent 160deg,
rgba(255, 200, 0, 0.7) 165deg,
transparent 170deg,
transparent 175deg,
rgba(255, 100, 0, 0.8) 180deg,
transparent 185deg,
transparent 190deg,
rgba(255, 150, 0, 0.6) 195deg,
transparent 200deg,
transparent 205deg,
rgba(255, 200, 0, 0.7) 210deg,
transparent 215deg,
transparent 220deg,
rgba(255, 100, 0, 0.8) 225deg,
transparent 230deg,
transparent 235deg,
rgba(255, 150, 0, 0.6) 240deg,
transparent 245deg,
transparent 250deg,
rgba(255, 200, 0, 0.7) 255deg,
transparent 260deg,
transparent 265deg,
rgba(255, 100, 0, 0.8) 270deg,
transparent 275deg,
transparent 280deg,
rgba(255, 150, 0, 0.6) 285deg,
transparent 290deg,
transparent 295deg,
rgba(255, 200, 0, 0.7) 300deg,
transparent 305deg,
transparent 310deg,
rgba(255, 100, 0, 0.8) 315deg,
transparent 320deg,
transparent 325deg,
rgba(255, 150, 0, 0.6) 330deg,
transparent 335deg,
transparent 340deg,
rgba(255, 200, 0, 0.7) 345deg,
transparent 350deg,
transparent 355deg,
rgba(255, 100, 0, 0.8) 360deg
);
border-radius: 50%;
opacity: 0;
filter: blur(12px);
pointer-events: none;
transition:
opacity 0.4s ease,
transform 0.4s ease;
z-index: -1;
}
&:hover::before {
opacity: 1;
animation: rotate-beams 7s linear infinite;
}
}
@keyframes rotate-beams {
0% {
transform: rotate(0deg) scale(1);
}
50% {
transform: rotate(180deg) scale(1.2);
}
100% {
transform: rotate(360deg) scale(1);
}
} }
.lamp-cap { .lamp-cap {
@ -116,14 +229,32 @@
transform: translate(-35%, -50%) rotate(85deg); transform: translate(-35%, -50%) rotate(85deg);
font-size: 30px; font-size: 30px;
font-weight: bold; font-weight: bold;
color: rgba(224, 27, 36, 0); color: rgba(224, 27, 36, 0.7);
transition: color 0.5s ease; transition: color 0.5s ease;
pointer-events: none; pointer-events: none;
z-index: 1; z-index: 4;
letter-spacing: 2px; letter-spacing: 2px;
} }
.lava-lamp:hover .lamp-text { .lamp-text-shadow {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-35%, -50%) rotate(85deg);
font-size: 30px;
font-weight: bold;
color: rgba(224, 27, 36, 0);
transition: color 0.5s ease;
pointer-events: none;
z-index: 4;
letter-spacing: 2px;
@include media-down(lg) {
color: rgba(224, 27, 36, 0.2);
}
}
.lava-lamp:hover .lamp-text-shadow {
color: rgba(224, 27, 36, 0.7); color: rgba(224, 27, 36, 0.7);
} }

View file

@ -28,7 +28,7 @@
z-index: 1; z-index: 1;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
font-size: 2.2rem; font-size: 2em;
line-height: 1; line-height: 1;
&::before { &::before {

View file

@ -1,15 +1,17 @@
.music { .music {
position: absolute; // position: absolute;
bottom: 15%; // bottom: 15%;
right: 27%; // right: 27%;
cursor: pointer; cursor: pointer;
position: relative;
height: 100px;
} }
.music-text { .music-text {
display: block;
position: absolute; position: absolute;
top: 0px; display: block;
left: -150px; bottom: 0;
right: 0;
color: white; color: white;
font-size: 20px; font-size: 20px;
font-weight: bold; font-weight: bold;
@ -20,9 +22,17 @@
padding-left: 5px; padding-left: 5px;
padding-right: 5px; padding-right: 5px;
border-radius: 5px; border-radius: 5px;
background-color: black; background-color: rgba(0, 0, 0, 0.7);
opacity: 0; opacity: 0;
transition: opacity 0.3s ease; transition: opacity 0.3s ease;
text-align: center;
@include media-down(lg) {
opacity: 1;
transform: rotate(0deg);
bottom: 0;
font-size: 14px;
}
} }
.music:hover .music-text { .music:hover .music-text {
@ -33,7 +43,7 @@
.notes { .notes {
position: absolute; position: absolute;
bottom: 30%; bottom: 30%;
left: -100px; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
pointer-events: none; pointer-events: none;
z-index: 9999; z-index: 9999;
@ -134,8 +144,9 @@
/* iPod group container - maintains relative positioning */ /* iPod group container - maintains relative positioning */
.ipod-group { .ipod-group {
position: absolute; // position: absolute;
left: -200px; // left: -200px;
position: relative;
width: 150px; width: 150px;
height: 100px; height: 100px;
z-index: 15; z-index: 15;
@ -156,16 +167,21 @@
inset 0 -1px 3px rgba(0, 0, 0, 0.2); inset 0 -1px 3px rgba(0, 0, 0, 0.2);
transform: rotate(-8deg); transform: rotate(-8deg);
z-index: 2; z-index: 2;
@include media-down(lg) {
width: 70px;
height: 110px;
}
} }
.ipod::before { .ipod::before {
content: ""; content: "";
position: absolute; position: absolute;
top: 8px; top: 5%;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
width: 32px; width: 80%;
height: 22px; height: 40%;
background: linear-gradient(180deg, #1a1a2a 0%, #0a0a1a 100%); background: linear-gradient(180deg, #1a1a2a 0%, #0a0a1a 100%);
border-radius: 2px; border-radius: 2px;
box-shadow: inset 0 0 5px rgba(0, 100, 150, 0.3); box-shadow: inset 0 0 5px rgba(0, 100, 150, 0.3);
@ -173,11 +189,11 @@
.ipod-wheel { .ipod-wheel {
position: absolute; position: absolute;
bottom: 8px; bottom: 8%;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
width: 32px; width: 70%;
height: 30px; height: 42%;
background: radial-gradient( background: radial-gradient(
circle at center, circle at center,
#fff 0%, #fff 0%,

View file

@ -1,8 +1,8 @@
/* VU Meter on desk */ /* VU Meter on desk */
.vu-meter { .vu-meter {
position: absolute; position: absolute;
bottom: 18%; left: 90px;
right: 30%; top: 10px;
width: 120px; width: 120px;
height: 60px; height: 60px;
z-index: 8; z-index: 8;

View file

@ -0,0 +1,370 @@
.window-frame {
position: relative;
width: 100%;
aspect-ratio: 16/9;
background: #3a3a3a;
border: 3px solid #2a2520;
border-top: 0px;
box-shadow:
inset 0 0 20px rgba(0, 0, 0, 0.8),
0 10px 40px rgba(0, 0, 0, 0.9);
overflow: hidden;
}
.window-frame::before {
content: "";
position: absolute;
inset: -20px;
border: 5px solid #1a1510;
border-top: 0px;
pointer-events: none;
z-index: 10;
}
/* Cityscape view */
.cityscape {
width: 100%;
height: 100%;
position: relative;
background: linear-gradient(
180deg,
#1a2332 0%,
#2a3a52 30%,
#4a5a72 60%,
#6a7a92 100%
);
overflow: hidden;
}
/* Sky with slight gradient */
.starfield {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 100%;
background: linear-gradient(180deg, #0a0f1a 0%, #1a2a3a 50%, #2a3a52 100%);
}
.building-windows {
width: 100%;
display: grid;
> .window-light {
width: 100%;
aspect-ratio: 1/1;
}
}
@mixin buildings-base {
position: absolute;
bottom: 0;
top: 0;
left: 0;
right: 0;
display: flex;
align-items: flex-end;
@for $i from 1 through 20 {
> .building:nth-child(#{$i}) {
@if random(4) == 1 {
opacity: 0;
}
> .building-windows {
@for $j from 1 through 40 {
> .window-light:nth-child(#{$j}) {
@if random(2) == 1 {
background: transparent;
box-shadow: none;
} @else {
$color-choice: random(100);
$light-color: null;
@if $color-choice <= 85 {
$hue: 40 + random(20); // 40-60
$sat: 70 + random(30); // 70-100%
$light: 50 + random(30); // 50-80%
$light-color: hsl($hue, $sat * 1%, $light * 1%);
} @else if $color-choice <= 95 {
$hue: 320 + random(20); // 320-340 (pink range)
$sat: 60 + random(40); // 60-100%
$light: 60 + random(20); // 60-80%
$light-color: hsl($hue, $sat * 1%, $light * 1%);
} @else {
$hue: 260 + random(40); // 260-300 (purple range)
$sat: 50 + random(50); // 50-100%
$light: 50 + random(30); // 50-80%
$light-color: hsl($hue, $sat * 1%, $light * 1%);
}
background: $light-color;
box-shadow: 0 0 10px $light-color;
}
}
}
}
}
}
}
.buildings-far {
@include buildings-base;
> .building {
background: linear-gradient(180deg, #272629 0%, #2a3a52 100%);
box-shadow:
inset -2px 0 5px rgba(0, 0, 0, 0.1),
0 0 10px rgba(42, 38, 31, 0.1);
> .building-windows {
width: 100%;
height: 50%;
opacity: 0.3;
padding: 5%;
}
}
@for $i from 1 through 20 {
> .building:nth-child(#{$i}) {
@if random(2) == 1 {
$width: random(10) + 5;
width: $width * 1%;
} @else {
$width: random(15) + 5;
width: $width + 15px;
}
$height: random(60) + 30;
height: $height * 1%;
> .building-windows {
grid-template-columns: repeat(#{random(3) + 3}, 1fr);
> .window-light {
aspect-ratio: #{0.5 + random(150) / 100};
}
}
}
}
}
.buildings-mid {
@include buildings-base;
> .building {
background: linear-gradient(180deg, #201e22 0%, #2a3a52 100%);
box-shadow:
inset -2px 0 5px rgba(0, 0, 0, 0.1),
0 0 10px rgba(42, 38, 31, 0.1);
> .building-windows {
width: 100%;
height: 50%;
opacity: 0.7;
padding: 5%;
}
}
@for $i from 1 through 20 {
> .building:nth-child(#{$i}) {
@if random(2) == 1 {
$width: random(10) + 10;
width: $width * 1%;
} @else {
$width: random(15) + 10;
width: $width + 15px;
}
$height: random(20) + 30;
height: $height * 1%;
> .building-windows {
grid-template-columns: repeat(#{random(3) + 3}, 1fr);
> .window-light {
aspect-ratio: #{0.5 + random(150) / 100};
}
}
}
}
}
.buildings-near {
@include buildings-base;
> .building {
background: linear-gradient(180deg, #121113 0%, #182230 100%);
box-shadow:
inset -2px 0 5px rgba(0, 0, 0, 0.1),
0 0 10px rgba(42, 38, 31, 0.1);
> .building-windows {
width: 100%;
height: 50%;
opacity: 0.8;
padding: 5%;
}
}
@for $i from 1 through 20 {
> .building:nth-child(#{$i}) {
@if random(2) == 1 {
$width: random(3) * 7;
width: $width * 1%;
} @else {
$width: random(10) + 50;
width: $width + 15px;
}
$height: random(3) * 10;
height: $height * 1%;
> .building-windows {
grid-template-columns: repeat(#{random(2) + 3}, 1fr);
> .window-light {
aspect-ratio: #{0.5 + random(150) / 100};
}
}
}
}
}
/* Buildings container */
.buildings {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 60%;
display: flex;
align-items: flex-end;
justify-content: space-around;
> .building {
animation: buildingGlow 4s ease-in-out infinite;
}
}
.building {
position: relative;
background: linear-gradient(180deg, #1a1a2e 0%, #0a0a1e 100%);
box-shadow:
inset -2px 0 10px rgba(0, 0, 0, 0.5),
0 0 20px rgba(255, 200, 100, 0.1);
}
/* Building windows */
.building-windows {
gap: 10%;
padding: 5% 5%;
}
.window-light {
background: #ffd700;
box-shadow: 0 0 10px #ffd700;
animation: windowFlicker 5s ease-in-out infinite;
}
.window-light:nth-child(odd) {
animation-delay: 0.5s;
}
.window-light:nth-child(3n) {
animation-delay: 3s;
}
.window-light:nth-child(4n) {
animation-delay: 5.5s;
}
@keyframes windowFlicker {
0%,
100% {
opacity: 0.3;
}
50% {
opacity: 0.9;
}
}
@keyframes buildingGlow {
0%,
100% {
box-shadow:
inset -2px 0 10px rgba(0, 0, 0, 0.5),
0 0 20px rgba(255, 200, 100, 0.1);
}
50% {
box-shadow:
inset -2px 0 10px rgba(0, 0, 0, 0.5),
0 0 30px rgba(255, 200, 100, 0.2);
}
}
/* Dirt and grime on window */
.window-grime {
position: absolute;
inset: 0;
background:
radial-gradient(
circle at 20% 30%,
rgba(50, 40, 30, 0.2) 0%,
transparent 40%
),
radial-gradient(
circle at 80% 60%,
rgba(40, 35, 25, 0.15) 0%,
transparent 50%
),
radial-gradient(
circle at 50% 80%,
rgba(45, 38, 28, 0.18) 0%,
transparent 45%
);
pointer-events: none;
z-index: 6;
}
/* Glass reflection */
.glass-reflection {
position: absolute;
inset: 0;
background: linear-gradient(
135deg,
rgba(255, 255, 255, 0.1) 0%,
transparent 30%,
transparent 70%,
rgba(255, 255, 255, 0.05) 100%
);
pointer-events: none;
z-index: 7;
}
/* Ambient light from city */
.ambient-light {
position: absolute;
bottom: -50px;
left: 50%;
transform: translateX(-50%);
width: 200%;
height: 200px;
background: radial-gradient(
ellipse at center,
rgba(255, 200, 100, 0.2) 0%,
transparent 70%
);
filter: blur(40px);
animation: ambientPulse 3s ease-in-out infinite;
}
@keyframes ambientPulse {
0%,
100% {
opacity: 0.5;
}
50% {
opacity: 0.8;
}
}

View file

@ -1,3 +1,5 @@
@import "mixins";
@import "partials/global-styles"; @import "partials/global-styles";
@import "partials/neon-sign"; @import "partials/neon-sign";
@ -8,6 +10,7 @@
@import "partials/lavalamp"; @import "partials/lavalamp";
@import "partials/floppy"; @import "partials/floppy";
@import "partials/lcd-display"; @import "partials/lcd-display";
@import "partials/window";
@import "partials/content-screens"; @import "partials/content-screens";
@ -406,6 +409,26 @@ body {
); );
} }
.window {
position: absolute;
top: 0;
left: 20%;
aspect-ratio: 16/9;
width: 350px;
border: 5px solid #c4b89a;
border-top: 0px;
&::after {
content: "";
position: absolute;
bottom: -5px;
left: -3%;
width: 106%;
height: 10px;
background-color: #c4b89a;
}
}
/* Post-it notes and papers on wall */ /* Post-it notes and papers on wall */
.sticky-note { .sticky-note {
font-family: "Caveat", cursive; font-family: "Caveat", cursive;
@ -435,7 +458,7 @@ body {
} }
.note3 { .note3 {
top: 12%; top: 21%;
left: 38%; left: 38%;
transform: rotate(-3deg); transform: rotate(-3deg);
background: #99ff99; background: #99ff99;
@ -653,6 +676,13 @@ body {
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
z-index: 10; z-index: 10;
@include media-down(lg) {
position: relative;
transform: none;
top: auto;
left: auto;
}
} }
/* CRT Monitor bezel */ /* CRT Monitor bezel */
@ -667,6 +697,12 @@ body {
inset 0 2px 4px rgba(255, 255, 255, 0.3), inset 0 2px 4px rgba(255, 255, 255, 0.3),
inset 0 -2px 4px rgba(0, 0, 0, 0.3); inset 0 -2px 4px rgba(0, 0, 0, 0.3);
position: relative; position: relative;
@include media-down(lg) {
width: 100%;
padding: 0px 0px 45px 0px;
border-radius: 0px;
}
} }
/* Brand logo on bezel */ /* Brand logo on bezel */
@ -680,6 +716,10 @@ body {
font-size: 11px; font-size: 11px;
font-weight: bold; font-weight: bold;
letter-spacing: 2px; letter-spacing: 2px;
@include media-down(lg) {
content: "RITUAL.SH";
}
} }
/* Power indicator LED */ /* Power indicator LED */
@ -775,6 +815,10 @@ body {
inset 0 0 40px rgba(0, 255, 100, 0.05), inset 0 0 40px rgba(0, 255, 100, 0.05),
inset 3px 3px 8px rgba(255, 255, 255, 0.1), inset 3px 3px 8px rgba(255, 255, 255, 0.1),
inset -3px -3px 8px rgba(0, 0, 0, 0.5); inset -3px -3px 8px rgba(0, 0, 0, 0.5);
@include media-down(lg) {
border-radius: 0px;
}
} }
/* Screen curvature/glass emboss effect */ /* Screen curvature/glass emboss effect */
@ -1541,8 +1585,7 @@ body {
/* Coffee mug */ /* Coffee mug */
.coffee-mug { .coffee-mug {
bottom: 12%; position: relative;
left: 75%;
width: 55px; width: 55px;
height: 62px; height: 62px;
background: linear-gradient(180deg, #4a2a1a 0%, #3a1a0a 100%); background: linear-gradient(180deg, #4a2a1a 0%, #3a1a0a 100%);
@ -1575,3 +1618,62 @@ body {
/* Import a nice cursive font */ /* Import a nice cursive font */
@import url("https://fonts.googleapis.com/css2?family=Neonderthaw&display=swap"); @import url("https://fonts.googleapis.com/css2?family=Neonderthaw&display=swap");
.navigation {
position: absolute;
bottom: 10%;
left: 0;
right: 0;
z-index: 999;
display: flex;
justify-content: space-evenly;
align-items: center;
@include media-down(lg) {
position: relative;
}
> .time-display {
width: 150px;
z-index: 30;
padding: 0.5em;
background: linear-gradient(180deg, #2a2a2a 0%, #1a1a1a 100%);
border: 1px solid #333;
box-shadow:
0 2px 8px rgba(0, 0, 0, 0.5),
inset 0 1px 2px rgba(255, 255, 255, 0.1);
border-radius: 1em;
cursor: pointer;
&::after {
content: "Interests and Tools";
position: absolute;
width: 150px;
color: white;
font-size: 20px;
font-weight: bold;
z-index: 8000;
transform: rotate(-10deg);
border: 1px solid #0f0;
padding: 2px;
padding-left: 5px;
padding-right: 5px;
border-radius: 5px;
background-color: rgba(0, 0, 0, 0.7);
opacity: 0;
transition: opacity 0.3s ease;
text-align: center;
@include media-down(lg) {
opacity: 1;
transform: rotate(0deg);
bottom: 0;
font-size: 14px;
}
}
&:hover::after {
opacity: 1;
}
}
}

0
content/now.md Normal file
View file

View file

@ -3,6 +3,8 @@
{{ end }}{{ define "main" }} {{ end }}{{ define "main" }}
<div class="wall"></div> <div class="wall"></div>
<div class="window">{{ partial "elements/window.html" . }}</div>
<!-- Neon sign above monitor --> <!-- Neon sign above monitor -->
{{ partial "elements/neon-sign.html" . }} {{ partial "elements/neon-sign.html" . }}
@ -67,122 +69,29 @@
<div class="desk"></div> <div class="desk"></div>
<!-- Desk monitor --> <!-- Desk monitor -->
{{/*
<div class="secondary-screen desk-monitor"> <div class="secondary-screen desk-monitor">
<div class="screen-display large crt"> <div class="screen-display large crt">
<span class="cursor-blink">_</span> <span class="cursor-blink">_</span>
</div> </div>
<div class="monitor-stand-small"></div> <div class="monitor-stand-small"></div>
</div> </div>
*/}}
<!-- Desk clutter --> <!-- Desk clutter -->
{{/*
<div class="desk-item keyboard"></div> <div class="desk-item keyboard"></div>
<div class="desk-item mouse"></div> <div class="desk-item mouse"></div>
<div class="desk-item coffee-mug"></div>
*/}}
<!-- MUSICAL STUFF --> <!-- MUSICAL STUFF -->
<a href="/audio/">
<div class="music">
<div class="music-text">MUSIC&nbsp;&amp;&nbsp;AUDIO&nbsp;GEAR</div>
<div class="ipod-group">
<div class="ipod">
<div class="ipod-wheel"></div>
</div>
<!-- Earbud cables within the group container -->
<svg class="ipod-cables" viewBox="0 0 150 100" style="overflow: visible">
<defs>
<linearGradient
id="cableGradient"
x1="0%"
y1="0%"
x2="100%"
y2="100%"
>
<stop offset="0%" style="stop-color: #6b4fb3" />
<stop offset="100%" style="stop-color: #4169e1" />
</linearGradient>
</defs>
<path
d="M 85,3 C 85,-12 75,-22 55,-22 C 35,-22 25,-15 25,0 C 25,15 28,35 32,50 L 35,65"
stroke="url(#cableGradient)"
stroke-width="2.5"
fill="none"
stroke-linecap="round"
/>
<path
d="M 35,65 C 28,72 20,82 5,88"
stroke="url(#cableGradient)"
stroke-width="1.8"
fill="none"
stroke-linecap="round"
/>
<path
d="M 35,65 C 55,73 95,82 125,83"
stroke="url(#cableGradient)"
stroke-width="1.8"
fill="none"
stroke-linecap="round"
/>
</svg>
<div class="earbud earbud-left"></div>
<div class="earbud earbud-right"></div>
</div>
<div class="vu-meter">
<div class="vu-meter-body">
<div class="vu-meter-screen">
<div class="vu-bars crt">
<div class="vu-bar" style="--delay: 0s; --height: 45%"></div>
<div class="vu-bar" style="--delay: 0.1s; --height: 65%"></div>
<div class="vu-bar" style="--delay: 0.2s; --height: 80%"></div>
<div class="vu-bar" style="--delay: 0.3s; --height: 55%"></div>
<div class="vu-bar" style="--delay: 0.4s; --height: 90%"></div>
<div class="vu-bar" style="--delay: 0.5s; --height: 70%"></div>
<div class="vu-bar" style="--delay: 0.6s; --height: 85%"></div>
<div class="vu-bar" style="--delay: 0.7s; --height: 60%"></div>
<div class="vu-bar" style="--delay: 0.8s; --height: 75%"></div>
<div class="vu-bar" style="--delay: 0.9s; --height: 50%"></div>
<div class="vu-bar" style="--delay: 1s; --height: 65%"></div>
<div class="vu-bar" style="--delay: 1.1s; --height: 40%"></div>
<div class="vu-bar" style="--delay: 1.2s; --height: 55%"></div>
<div class="vu-bar" style="--delay: 1.3s; --height: 70%"></div>
<div class="vu-bar" style="--delay: 1.4s; --height: 45%"></div>
<div class="vu-bar" style="--delay: 1.5s; --height: 35%"></div>
</div>
<!-- Peak indicator line -->
<div class="vu-peak-line"></div>
</div>
<!-- VU Meter LEDs -->
<div class="vu-leds">
<div class="vu-led green"></div>
<div class="vu-led green"></div>
<div class="vu-led yellow"></div>
<div class="vu-led red"></div>
</div>
</div>
</div>
<div class="notes">
<div class="note"></div>
<div class="note"></div>
<div class="note"></div>
<div class="note"></div>
<div class="note"></div>
<div class="note"></div>
</div>
</div>
</a>
<!-- Widgets and gadgets --> <!-- Widgets and gadgets -->
{{/*
<div class="widget router"></div> <div class="widget router"></div>
<div class="widget hard-drive"></div> <div class="widget hard-drive"></div>
*/}}
{{ partial "elements/lavalamp.html" . }}
<!-- CRT Monitor --> <!-- CRT Monitor -->
<div class="crt-container"> <div class="crt-container">
@ -210,7 +119,7 @@
</div> </div>
<!-- Wall-mounted monitors --> <!-- Wall-mounted monitors -->
<div class="secondary-screen wall-monitor-1"> <div class="secondary-screen wall-monitor-1 hidden-xl-down">
<div class="screen-display crt"> <div class="screen-display crt">
> updates -lah<br /> > updates -lah<br />
{{ $pages := where .Site.RegularPages "Kind" "page" }} {{ range first 5 {{ $pages := where .Site.RegularPages "Kind" "page" }} {{ range first 5
@ -226,7 +135,7 @@
</div> </div>
</div> </div>
<div class="secondary-screen wall-monitor-2"> <div class="secondary-screen wall-monitor-2 hidden-xl-down">
<div class="screen-display tiny cyan crt"> <div class="screen-display tiny cyan crt">
<div class="scroll-text"> <div class="scroll-text">
[PKT] 192.168.1.1:443<br /> [PKT] 192.168.1.1:443<br />
@ -308,7 +217,7 @@
</div> </div>
</div> </div>
<div class="secondary-screen wall-monitor-3"> <div class="secondary-screen wall-monitor-3 hidden-xl-down">
<div class="screen-display crt"> <div class="screen-display crt">
PING 8.8.8.8<br /> PING 8.8.8.8<br />
64 bytes: 12ms<br /> 64 bytes: 12ms<br />
@ -318,7 +227,7 @@
</div> </div>
</div> </div>
<div class="secondary-screen wall-monitor-4"> <div class="secondary-screen wall-monitor-4 hidden-xl-down">
<div class="screen-display tiny amber crt"> <div class="screen-display tiny amber crt">
> tail -f /var/log<br /> > tail -f /var/log<br />
[INFO] Process OK<br /> [INFO] Process OK<br />
@ -336,6 +245,39 @@
</div> </div>
</div> </div>
<div class="navigation">
<div class="nav-lamp">{{ partial "elements/lavalamp.html" . }}</div>
<div>
<a href="/audio/">
<div class="music">
<div class="music-text">MUSIC &amp; AUDIO GEAR</div>
{{ partial "elements/ipod.html" . }}
<div class="hidden-md-down">
{{ partial "elements/vu-meter.html" . }}
</div>
<div class="notes">
<div class="note"></div>
<div class="note"></div>
<div class="note"></div>
<div class="note"></div>
<div class="note"></div>
<div class="note"></div>
</div>
</div>
</a>
</div>
<div class="time-display">
{{ partial "elements/lcd-screen.html" (dict "text" "12:03:31" "placeholder"
"00:00:00") }}
</div>
<div class="hidden-xl-down">
<div class="coffee-mug"></div>
</div>
</div>
{{ $pages := where .Site.RegularPages "Kind" "page" }} {{ range first 1 (sort {{ $pages := where .Site.RegularPages "Kind" "page" }} {{ range first 1 (sort
$pages "Lastmod" "desc") }} $pages "Lastmod" "desc") }}

332
layouts/now/single.html Normal file
View file

@ -0,0 +1,332 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Basement Window</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(180deg, #1a1a1a 0%, #0a0a0a 100%);
font-family: "Courier New", monospace;
overflow: hidden;
}
.basement-wall {
width: 100%;
max-width: 800px;
padding: 20px;
background: linear-gradient(135deg, #2a2a2a 0%, #1a1a1a 100%);
box-shadow: inset 0 0 100px rgba(0, 0, 0, 0.8);
position: relative;
}
.window-frame {
position: relative;
width: 100%;
aspect-ratio: 16/9;
background: #3a3a3a;
border: 20px solid #2a2520;
box-shadow:
inset 0 0 20px rgba(0, 0, 0, 0.8),
0 10px 40px rgba(0, 0, 0, 0.9);
overflow: hidden;
}
.window-frame::before {
content: "";
position: absolute;
inset: -20px;
border: 5px solid #1a1510;
pointer-events: none;
z-index: 10;
}
/* Cityscape view */
.cityscape {
width: 100%;
height: 100%;
position: relative;
background: linear-gradient(
180deg,
#1a2332 0%,
#2a3a52 30%,
#4a5a72 60%,
#6a7a92 100%
);
overflow: hidden;
}
/* Sky with slight gradient */
.sky {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 40%;
background: linear-gradient(
180deg,
#0a0f1a 0%,
#1a2a3a 50%,
#2a3a52 100%
);
}
/* Buildings container */
.buildings {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 60%;
display: flex;
align-items: flex-end;
justify-content: space-around;
gap: 20px;
padding: 0 40px;
}
.building {
position: relative;
background: linear-gradient(180deg, #1a1a2e 0%, #0a0a1e 100%);
box-shadow:
inset -2px 0 10px rgba(0, 0, 0, 0.5),
0 0 20px rgba(255, 200, 100, 0.1);
animation: buildingGlow 4s ease-in-out infinite;
}
.building:nth-child(1) {
width: 80px;
height: 280px;
animation-delay: 0s;
}
.building:nth-child(2) {
width: 60px;
height: 200px;
animation-delay: 0.5s;
}
.building:nth-child(3) {
width: 90px;
height: 320px;
animation-delay: 1s;
}
.building:nth-child(4) {
width: 70px;
height: 240px;
animation-delay: 1.5s;
}
.building:nth-child(5) {
width: 85px;
height: 300px;
animation-delay: 2s;
}
/* Building windows */
.building-windows {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
padding: 15px 10px;
height: 100%;
}
.window-light {
background: #ffd700;
opacity: 0;
box-shadow: 0 0 10px #ffd700;
animation: windowFlicker 3s ease-in-out infinite;
}
.window-light:nth-child(odd) {
animation-delay: 0.5s;
}
.window-light:nth-child(3n) {
animation-delay: 1s;
}
.window-light:nth-child(4n) {
animation-delay: 1.5s;
}
@keyframes windowFlicker {
0%,
100% {
opacity: 0.3;
}
50% {
opacity: 0.9;
}
}
@keyframes buildingGlow {
0%,
100% {
box-shadow:
inset -2px 0 10px rgba(0, 0, 0, 0.5),
0 0 20px rgba(255, 200, 100, 0.1);
}
50% {
box-shadow:
inset -2px 0 10px rgba(0, 0, 0, 0.5),
0 0 30px rgba(255, 200, 100, 0.2);
}
}
/* Dirt and grime on window */
.window-grime {
position: absolute;
inset: 0;
background:
radial-gradient(
circle at 20% 30%,
rgba(50, 40, 30, 0.2) 0%,
transparent 40%
),
radial-gradient(
circle at 80% 60%,
rgba(40, 35, 25, 0.15) 0%,
transparent 50%
),
radial-gradient(
circle at 50% 80%,
rgba(45, 38, 28, 0.18) 0%,
transparent 45%
);
pointer-events: none;
z-index: 6;
}
/* Glass reflection */
.glass-reflection {
position: absolute;
inset: 0;
background: linear-gradient(
135deg,
rgba(255, 255, 255, 0.1) 0%,
transparent 30%,
transparent 70%,
rgba(255, 255, 255, 0.05) 100%
);
pointer-events: none;
z-index: 7;
}
/* Ambient light from city */
.ambient-light {
position: absolute;
bottom: -50px;
left: 50%;
transform: translateX(-50%);
width: 200%;
height: 200px;
background: radial-gradient(
ellipse at center,
rgba(255, 200, 100, 0.2) 0%,
transparent 70%
);
filter: blur(40px);
animation: ambientPulse 3s ease-in-out infinite;
}
@keyframes ambientPulse {
0%,
100% {
opacity: 0.5;
}
50% {
opacity: 0.8;
}
}
</style>
</head>
<body>
<div class="basement-wall">
<div class="window-frame">
<!-- Cityscape -->
<div class="cityscape">
<div class="sky"></div>
<div class="buildings">
<div class="building">
<div class="building-windows">
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
</div>
</div>
<div class="building">
<div class="building-windows">
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
</div>
</div>
<div class="building">
<div class="building-windows">
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
</div>
</div>
<div class="building">
<div class="building-windows">
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
</div>
</div>
<div class="building">
<div class="building-windows">
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
<div class="window-light"></div>
</div>
</div>
</div>
<div class="ambient-light"></div>
</div>
<!-- Window effects -->
<div class="window-grime"></div>
<div class="glass-reflection"></div>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,46 @@
<div class="ipod-group">
<div class="ipod">
<div class="ipod-wheel"></div>
</div>
<!-- Earbud cables within the group container -->
<svg
class="ipod-cables hidden-lg-down"
viewBox="0 0 150 100"
style="overflow: visible"
>
<defs>
<linearGradient id="cableGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color: #6b4fb3" />
<stop offset="100%" style="stop-color: #4169e1" />
</linearGradient>
</defs>
<path
d="M 85,3 C 85,-12 75,-22 55,-22 C 35,-22 25,-15 25,0 C 25,15 28,35 32,50 L 35,65"
stroke="url(#cableGradient)"
stroke-width="2.5"
fill="none"
stroke-linecap="round"
/>
<path
d="M 35,65 C 28,72 20,82 5,88"
stroke="url(#cableGradient)"
stroke-width="1.8"
fill="none"
stroke-linecap="round"
/>
<path
d="M 35,65 C 55,73 95,82 125,83"
stroke="url(#cableGradient)"
stroke-width="1.8"
fill="none"
stroke-linecap="round"
/>
</svg>
<div class="earbud earbud-left hidden-lg-down"></div>
<div class="earbud earbud-right hidden-lg-down"></div>
</div>

View file

@ -21,9 +21,8 @@
<div class="lava-lamp-container"> <div class="lava-lamp-container">
<div class="lamp-cap"></div> <div class="lamp-cap"></div>
<div class="lava-lamp" id="lavaLamp"> <div class="lava-lamp" id="lavaLamp">
<div class="blobs-container"></div> <div class="blobs-container"><div class="lamp-text">ABOUT</div></div>
<!-- NEW: wrapper for blobs --> <div class="lamp-text-shadow">ABOUT</div>
<div class="lamp-text">ABOUT</div>
</div> </div>
<div class="lamp-base"></div> <div class="lamp-base"></div>
</div> </div>

View file

@ -1,6 +1,5 @@
{{ $text := .text | default "" }} {{ $placeholder := strings.Repeat (len $text) {{ $text := .text | default "" }} {{ $placeholder := .placeholder | default
"8" }} (strings.Repeat (len $text) "8" ) }}
<div class="lcd-container"> <div class="lcd-container">
<div class="lcd-screen"> <div class="lcd-screen">
<span class="lcd-text" data-placeholder="{{ $placeholder }}" <span class="lcd-text" data-placeholder="{{ $placeholder }}"

View file

@ -0,0 +1,33 @@
<div class="vu-meter">
<div class="vu-meter-body">
<div class="vu-meter-screen">
<div class="vu-bars crt">
<div class="vu-bar" style="--delay: 0s; --height: 45%"></div>
<div class="vu-bar" style="--delay: 0.1s; --height: 65%"></div>
<div class="vu-bar" style="--delay: 0.2s; --height: 80%"></div>
<div class="vu-bar" style="--delay: 0.3s; --height: 55%"></div>
<div class="vu-bar" style="--delay: 0.4s; --height: 90%"></div>
<div class="vu-bar" style="--delay: 0.5s; --height: 70%"></div>
<div class="vu-bar" style="--delay: 0.6s; --height: 85%"></div>
<div class="vu-bar" style="--delay: 0.7s; --height: 60%"></div>
<div class="vu-bar" style="--delay: 0.8s; --height: 75%"></div>
<div class="vu-bar" style="--delay: 0.9s; --height: 50%"></div>
<div class="vu-bar" style="--delay: 1s; --height: 65%"></div>
<div class="vu-bar" style="--delay: 1.1s; --height: 40%"></div>
<div class="vu-bar" style="--delay: 1.2s; --height: 55%"></div>
<div class="vu-bar" style="--delay: 1.3s; --height: 70%"></div>
<div class="vu-bar" style="--delay: 1.4s; --height: 45%"></div>
<div class="vu-bar" style="--delay: 1.5s; --height: 35%"></div>
</div>
<!-- Peak indicator line -->
<div class="vu-peak-line"></div>
</div>
<!-- VU Meter LEDs -->
<div class="vu-leds">
<div class="vu-led green"></div>
<div class="vu-led green"></div>
<div class="vu-led yellow"></div>
<div class="vu-led red"></div>
</div>
</div>
</div>

View file

@ -0,0 +1,14 @@
<div class="window-frame">
<!-- Cityscape -->
<div class="cityscape">
<div class="starfield" id="starfield" data-stars="50"></div>
<div class="buildings-far"></div>
<div class="buildings-mid"></div>
<div class="buildings-near"></div>
<div class="ambient-light"></div>
</div>
<!-- Window effects -->
<div class="window-grime"></div>
<div class="glass-reflection"></div>
</div>