commit 1e9f6b7fe035694fa0063182f3a9a49fed804eba Author: Andre Schaf Date: Sun Mar 29 20:46:18 2026 +0200 initial commit diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e611dad --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module schaf.dev + +go 1.25.8 diff --git a/main.go b/main.go new file mode 100644 index 0000000..1dd9373 --- /dev/null +++ b/main.go @@ -0,0 +1,49 @@ +package main + +import ( + "fmt" + "net/http" + "path/filepath" +) + +func main() { + fileServer := http.FileServer(neuteredFs{http.Dir("./static")}) + + http.Handle("/", fileServer) + err := http.ListenAndServe(":3000", nil) + + if err != nil { + fmt.Println(err) + } +} + + +func (nfs neuteredFs) Open(path string) (http.File, error) { + f, err := nfs.fs.Open(path) + if err != nil { + return nil, err + } + + s, err := f.Stat() + if err != nil { + return nil, err + } + + if s.IsDir() { + index := filepath.Join(path, "index.html") + if _, err := nfs.fs.Open(index); err != nil { + closeErr := f.Close() + if closeErr != nil { + return nil, closeErr + } + + return nil, err + } + } + + return f, nil +} + +type neuteredFs struct { + fs http.FileSystem +} diff --git a/static/css/main.css b/static/css/main.css new file mode 100644 index 0000000..4275e35 --- /dev/null +++ b/static/css/main.css @@ -0,0 +1,174 @@ +:root { + --side-length: 30vw; + --side-length-neg: -30vw; + --side-length-half: calc(var(--side-length) / 2); + --side-length-half-neg: calc(var(--side-length-neg) / 2); + --colour-bg-main: #d4c3a3; + --colour-bg-secondary: #4a4a4a; + --colour-primary: #f6e8d4; + --colour-text-main: #fff; + --colour-cube-1: #dd4814; + --colour-cube-2: #0497aa; +} + +@font-face { + font-family: "Montserrat"; + src: url(../fonts/montserrat/Montserrat-Medium.otf) format("truetype"); +} + +html { + font-family: Montserrat, Verdana, Tahoma; + color: var(--colour-text-main); + background-color: var(--colour-bg-main); + font-size: 16px; + color: var(--colour-primary); +} + +body { + margin: 0; + display: flex; + flex-direction: column; + height: 100vh; +} + +header, footer { + padding: 0 3rem; + display: flex; + justify-content: center; + align-items: center; + background-color: var(--colour-bg-secondary); + height: 4rem; +} + +header { + font-size: 2rem; + justify-content: flex-end; +} + +footer { + height: 2.5rem; +} + +main { + flex: 1; + display: flex; + justify-content: center; + align-items: center; +} + +.wrap { + transition: opacity linear 3s; + perspective: 250vw; + perspective-origin: 500% 50vw; + width: var(--side-length); + height: var(--side-length); +} + +.cube { + transform-style: preserve-3d; + width: var(--side-length); + height: var(--side-length); + animation: spin 50s infinite ease-in-out; +} + +.wrap:hover { + opacity: 0.1; +} + +.cube div { + position: absolute; + width: var(--side-length); + height: var(--side-length); + display: flex; + justify-content: center; + align-items: center; +} +.cube div div { + opacity: 0.8; + background-color: var(--colour-bg-secondary); + width: 90%; + height: 90%; +} +.cube div div:hover { + opacity: 0.2; +} + +.front div, .back div { + animation: fb 50s infinite cubic-bezier(0.165, 0.84, 0.44, 1); +} + +.left div, .right div { + animation: rl 50s infinite cubic-bezier(0.165, 0.84, 0.44, 1); +} + +.top div, .bottom div { + animation: tb 50s infinite cubic-bezier(0.165, 0.84, 0.44, 1); +} + +.back { + transform: translateZ(var(--side-length-half-neg)) rotateY(180deg); +} +.right { + transform: rotateY(-270deg) translateX(var(--side-length-half)); + transform-origin: top right; +} +.left { + transform: rotateY(270deg) translateX(var(--side-length-half-neg)); + transform-origin: center left; +} +.top { + transform: rotateX(-90deg) translateY(var(--side-length-half-neg)); + transform-origin: top center; +} +.bottom { + transform: rotateX(90deg) translateY(var(--side-length-half)); + transform-origin: bottom center; +} + +.front { + transform: translateZ(var(--side-length-half)); +} +.cube .front div { + opacity: 0.9; + transform: translateZ(var(--side-length-half)); + background-color: #a39494; +} +.cube .bottom div { + background-color: #7d7d7d; +} + +@keyframes spin { + 0%, 10% { transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg); } + 11%, 20% { transform: rotateX(0deg) rotateY(0deg) rotateZ(180deg); } + 21%, 35% { transform: rotateX(90deg) rotateY(0deg) rotateZ(180deg); } + 36%, 50% { transform: rotateX(90deg) rotateY(90deg) rotateZ(180deg); } + 51%, 65% { transform: rotateX(90deg) rotateY(90deg) rotateZ(360deg); } + 66%, 80% { transform: rotateX(180deg) rotateY(90deg) rotateZ(360deg); } + 81%, 99% { transform: rotateX(180deg) rotateY(360deg) rotateZ(360deg); } + 100% { transform: rotateX(360deg) rotateY(360deg) rotateZ(360deg); } +} + +@keyframes fb { + 0%, 9% { border-radius: 0; } + 10%, 11% { border-radius: 50% } + 12%, 49% { border-radius: 0; } + 50%, 51% { border-radius: 50%; } + 52%, 64% { border-radius: 0; } + 65%, 66% { border-radius: 50%; } + 67%, 100% { border-radius: 0; } +} + +@keyframes rl { + 0%, 19% { border-radius: 0; } + 20%, 21% { border-radius: 50%; } + 22%, 98% { border-radius: 0; } + 99%, 100% { border-radius: 50% } +} + +@keyframes tb { + 0%, 34% { border-radius: 0; } + 35%, 36% { border-radius: 50%; } + 37%, 79% { border-radius: 0; } + 80%, 81% { border-radius: 50%; } + 82%, 100% { border-radius: 0; } +} diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..ffc25eb Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/fonts/montserrat/Montserrat-Medium.otf b/static/fonts/montserrat/Montserrat-Medium.otf new file mode 100644 index 0000000..d2193c6 Binary files /dev/null and b/static/fonts/montserrat/Montserrat-Medium.otf differ diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..73bad2b --- /dev/null +++ b/static/index.html @@ -0,0 +1,33 @@ + + + + + + _schaf.dev + + + + + +
+ _schaf.dev +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + + + diff --git a/static/pp/andre.png b/static/pp/andre.png new file mode 100644 index 0000000..166b9a3 Binary files /dev/null and b/static/pp/andre.png differ diff --git a/static/pp/felix.png b/static/pp/felix.png new file mode 100644 index 0000000..ee83882 Binary files /dev/null and b/static/pp/felix.png differ diff --git a/static/pp/index.html b/static/pp/index.html new file mode 100644 index 0000000..b4166aa --- /dev/null +++ b/static/pp/index.html @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + +
+ +
+ + + diff --git a/static/pp/pp.js b/static/pp/pp.js new file mode 100644 index 0000000..35816ce --- /dev/null +++ b/static/pp/pp.js @@ -0,0 +1,182 @@ +(function() { + var canvas = document.getElementById("pp-canvas"); + var ctx = canvas.getContext("2d"); + + var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); + var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); + var radius = Math.min(w, h) * 2; + var radiusPeople = radius / 6; + + canvas.width = w; + canvas.height = h; + + ctx.translate(w / 2, h / 2); + + var sliceToColor = [ + '#ECEAE0', + '#AC2832', + '#CB8C1D', + ]; + + var sliceToRoom = [ + 'BAD', + 'WOHNI', + 'KÜCHE', + ] + + var imageSrc = [ + './felix.png', + './tobias.png', + './andre.png', + ]; + // Bad, Küche, Wohni + var pathRooms = []; + + function drawBackground(ctx, radius) { + sliceToColor.forEach(function (color, index) { + drawSlice(index, sliceToColor.length, color); + }); + } + + function drawSlice(num, total, color) { + var sliceSize = 360 / total; + var start = Math.PI * 2 * (((num - 1) * sliceSize) / 360); + var end = Math.PI * 2 * ((num * sliceSize) / 360); + let path = new Path2D(); + ctx.beginPath(path) + path.moveTo(0, 0); + path.arc(0, 0, radius, start + 0.52, end + 0.52, false); + path.lineTo(0, 0); + ctx.fillStyle = color; + path.closePath(); + + if (pathRooms.length < total) { + pathRooms.push(path); + } + + ctx.fill(path); + } + + var secondsLoop = 3 * 7 * 24 * 60 * 60; + + function degrees_to_radians(degrees) { + var pi = Math.PI; + return degrees * (pi/180); + } + + function drawPeople() { + var now = Date.now() / 1000 - 4 * 60 * 60 * 24; + var part = now % secondsLoop; + var ang; + var num; + ctx.font = radiusPeople*0.15 + "px arial"; + ctx.textBaseline="middle"; + ctx.textAlign="center"; + ctx.fillStyle = 'black'; + var sliceSize = 360 / sliceToColor.length; + + for(num = 0; num < sliceToColor.length; num++){ + ang = Math.PI * 2 * ((num * sliceSize) / 360); + ang += degrees_to_radians((360 / secondsLoop) * part); + + ctx.rotate(ang); + ctx.translate(0, -radiusPeople*0.85); + ctx.rotate(-ang); + ctx.drawImage(images[num], 0 - images[num].width / 2, 0 - images[num].height / 2, images[num].width, images[num].height); + ctx.rotate(ang); + ctx.translate(0, radiusPeople*0.85); + ctx.rotate(-ang); + } + } + + function drawRoomNames() { + var ang; + var num; + var radiusCaptions = radiusPeople * 1.3; + ctx.font = radiusCaptions*0.15 + "px arial"; + ctx.textBaseline="middle"; + ctx.textAlign="center"; + ctx.fillStyle = 'black'; + var sliceSize = 360 / sliceToColor.length; + + for(num = 0; num < sliceToColor.length; num++){ + ang = Math.PI * 2 * ((num * sliceSize + sliceSize / 2) / 360); + + ctx.rotate(ang); + ctx.translate(0, -radiusCaptions*0.85); + ctx.rotate(-ang); + ctx.fillText(sliceToRoom[num], 0, 0); + ctx.rotate(ang); + ctx.translate(0, radiusCaptions*0.85); + ctx.rotate(-ang); + } + } + + function init() { + if (!isImgLoaded) { + return; + } + + w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); + h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); + radius = Math.min(w, h) * 2; + radiusPeople = radius / 6; + canvas.width = w; + canvas.height = h; + ctx.translate(w / 2, h / 2); + isInitialized = true; + drawBackground(); + drawRoomNames(); + drawPeople(); + + canvas.addEventListener('mousemove', e => { + let bound = canvas.getBoundingClientRect(); + let x = e.pageX - bound.top; + let y = e.pageY - bound.left; + activeRoom = false; + pathRooms.forEach((path, index) => { + if (ctx.isPointInPath(path, x, y)) { + activeRoom = index; + } + }); + }); + } + + window.onresize = init; + + var isInitialized = false; + var isImgLoaded = false; + var images = imageSrc.map(function(){return false;}); + + function preloadImages() { + imageSrc.forEach(function(imgSrc, index) { + var newImg = new Image(); + newImg.indexSrc = index; + + newImg.onload = function() { + var factor = (newImg.width / radius) * 13; + newImg.width = newImg.width / factor; + newImg.height = newImg.height / factor; + images[index] = newImg; + + isImgLoaded = images.reduce(function(acc, cur) { + return acc && cur; + }, true) + init(); + }; + + newImg.src = imgSrc; + }); + } + + preloadImages(); + + setInterval(function() { + if (!isInitialized) { + return; + } + drawBackground(); + drawRoomNames(); + drawPeople(); + }, 1000); +})(); diff --git a/static/pp/tobias.png b/static/pp/tobias.png new file mode 100644 index 0000000..2528154 Binary files /dev/null and b/static/pp/tobias.png differ