diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz
index 6931566..4ae2fc1 100644
Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ
diff --git a/Caddyfile b/Caddyfile
index 0f94919..4f77dbe 100644
--- a/Caddyfile
+++ b/Caddyfile
@@ -1,6 +1,7 @@
(https_redirect) {
@do_https_redirect {
not header_regexp veryoldbrowser User-Agent Navigator|MSIE|Mosaic|Kindle|^curl|NintendoBrowser/
+ not host *.onion *.*.onion
protocol http
}
redir @do_https_redirect https://{host}{uri}
@@ -205,7 +206,7 @@ Disallow: /"
}
}
}
-matrix.matdoes.dev, matrix.matdoes.dev:8448 {
+matrix.matdoes.dev matrix.matdoes.dev:8448 {
handle /.well-known/matrix/server {
header content-type application/json
respond "{\"m.server\":\"matrix.matdoes.dev\"}"
@@ -229,7 +230,7 @@ fedi.matdoes.dev {
}
}
-f.matdoes.dev {
+f.matdoes.dev media.f.matdoes.dev cache.f.matdoes.dev {
@chrome {
header_regexp chrome User-Agent Chrome\/[0-9./]+\s(Mobile\s)?Safari\/[0-9./]+$
not header User-Agent *Googlebot/*
@@ -241,7 +242,9 @@ f.matdoes.dev {
git.matdoes.dev {
reverse_proxy 127.0.0.1:3000
}
-s.matdoes.dev {
+http://s.matdoes.dev https://s.matdoes.dev {
+ import https_redirect
+
reverse_proxy 127.0.0.1:28019
}
@@ -296,3 +299,19 @@ hetzner.matdoes.dev {
xmpp.matdoes.dev {
respond ""
}
+
+mcassets.matdoes.dev {
+ reverse_proxy 127.0.0.1:10573
+}
+
+www.www.matdoes.dev {
+ header {
+ Content-Type text/html
+ Server "meow"
+ }
+ respond "nyaaaaaaaaaaaaaaaaaaa" 200
+}
+
+www.matdoes.dev {
+ redir https://matdoes.dev{uri}
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 9b0c608..cea77ee 100644
--- a/package.json
+++ b/package.json
@@ -14,38 +14,40 @@
"postinstall": "patch-package"
},
"devDependencies": {
- "@img/sharp-linux-x64": "^0.33.2",
+ "@img/sharp-linux-x64": "^0.33.3",
"@sveltejs/vite-plugin-svelte": "^3.0.2",
"@types/cookie": "^0.6.0",
"@types/html-minifier": "^4.0.5",
- "@typescript-eslint/eslint-plugin": "^7.3.1",
- "@typescript-eslint/parser": "^7.3.1",
- "eslint": "^8.57.0",
+ "@types/matter-js": "^0.19.6",
+ "@typescript-eslint/eslint-plugin": "^7.6.0",
+ "@typescript-eslint/parser": "^7.6.0",
+ "eslint": "^9.0.0",
"eslint-config-prettier": "^9.1.0",
"mdsvex": "^0.11.0",
"prettier": "^3.2.5",
"prettier-plugin-svelte": "^3.2.2",
- "sharp": "^0.33.2",
+ "sharp": "^0.33.3",
"svelte": "4.2.12",
- "svelte-check": "^3.6.7",
+ "svelte-check": "^3.6.9",
"svelte-preprocess": "^5.1.3",
"tslib": "^2.6.2",
- "typescript": "^5.4.2"
+ "typescript": "^5.4.4"
},
"type": "module",
"dependencies": {
"@lukeed/uuid": "^2.0.1",
"@sveltejs/adapter-node": "^5.0.1",
"@sveltejs/adapter-static": "^3.0.1",
- "@sveltejs/kit": "^2.5.4",
+ "@sveltejs/kit": "^2.5.5",
"@types/js-yaml": "^4.0.9",
- "cbor-x": "^1.5.8",
+ "cbor-x": "^1.5.9",
"cookie": "^0.6.0",
"html-minifier": "^4.0.0",
+ "matter-js": "^0.19.0",
"patch-package": "^8.0.0",
"postinstall-postinstall": "^2.1.0",
"svelte-body": "^1.4.0",
- "vite": "5.1.6"
+ "vite": "5.2.8"
},
"engines": {
"node": ">=16"
diff --git a/src/app.css b/src/app.css
index fe4cea0..811fd37 100644
--- a/src/app.css
+++ b/src/app.css
@@ -19,6 +19,12 @@
--text-font: 'Atkinson Hyperlegible', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
}
+*,
+*:before,
+*:after {
+ box-sizing: border-box;
+}
+
html,
body,
#page {
diff --git a/src/lib/gravity.ts b/src/lib/gravity.ts
new file mode 100644
index 0000000..94e8afc
--- /dev/null
+++ b/src/lib/gravity.ts
@@ -0,0 +1,157 @@
+import { browser } from '$app/environment'
+import Matter from 'matter-js'
+
+const GRAVITY_QUERY_SELECTOR = 'p, h1, h2, .button, .icon'
+
+export function initGravity(): () => void {
+ const { Engine, Bodies, Composite, Runner, Mouse, MouseConstraint } = Matter
+
+ console.log('gravity enabled')
+
+ // create an engine
+ const engine = Engine.create({ enableSleeping: true })
+
+ const floorBody = Bodies.rectangle(
+ window.innerWidth / 2,
+ window.innerHeight - 5,
+ window.innerWidth,
+ 10,
+ {
+ isStatic: true,
+ }
+ )
+ Composite.add(engine.world, [floorBody])
+
+ const trackedElements = new Map()
+
+ async function enableGravityOnElement(el: HTMLElement) {
+ await new Promise((resolve) => requestAnimationFrame(resolve))
+
+ let originalTextContent: string | null = null
+ if (el.classList.contains('copyright') || el.id === 'main-title') {
+ el.style.width = 'fit-content'
+ el.style.margin = '0 auto'
+ if (el.id === 'main-title') {
+ originalTextContent = el.textContent
+ el.textContent = 'matdoesdev'
+ }
+ }
+ const bb = el.getBoundingClientRect()
+ if (originalTextContent) el.textContent = originalTextContent
+
+ const body = Bodies.rectangle(
+ bb.left + bb.width / 2,
+ bb.top + bb.height / 2,
+ bb.width,
+ bb.height,
+ { restitution: 1 }
+ )
+ el.style.position = 'absolute'
+ el.style.left = bb.left + 'px'
+ el.style.top = bb.top + 'px'
+ el.style.width = bb.width + 'px'
+ el.style.height = bb.height + 'px'
+ el.style.userSelect = 'none'
+ // el.style.outline = '1px solid red'
+
+ Composite.add(engine.world, [body])
+ trackedElements.set(el, body)
+ }
+
+ function makeAnchorUndraggable(el: HTMLAnchorElement) {
+ // el.style.pointerEvents = 'none'
+ // el.style.cursor = 'pointer'
+ el.draggable = false
+
+ // document.addEventListener('click', (e) => {
+ // el.style.pointerEvents = ''
+ // const clickedEl = document.elementFromPoint(e.clientX, e.clientY)
+ // el.style.pointerEvents = 'none'
+ // // if (clickedEl instanceof HTMLAnchorElement) {
+ // // e.preventDefault()
+ // // goto(clickedEl.href)
+ // // }
+ // if (el.contains(clickedEl)) {
+ // e.preventDefault()
+ // const url = new URL(el.href)
+ // if (url.origin === window.location.origin) {
+ // goto(el.href)
+ // } else {
+ // window.location.href = el.href
+ // }
+ // }
+ // })
+ }
+
+ document.querySelectorAll(GRAVITY_QUERY_SELECTOR).forEach((el) => {
+ enableGravityOnElement(el as HTMLElement)
+ })
+ document.querySelectorAll('a').forEach((el) => {
+ makeAnchorUndraggable(el as HTMLAnchorElement)
+ })
+
+ // update positions every frame
+ Matter.Events.on(engine, 'beforeUpdate', function (event) {
+ trackedElements.forEach((body, el) => {
+ if (body.position.y < 0) {
+ // move up
+ body.position.y = window.innerHeight
+ }
+
+ el.style.left = body.position.x - el.offsetWidth / 2 + 'px'
+ el.style.top = body.position.y - el.offsetHeight / 2 + 'px'
+ el.style.transform = `rotate(${body.angle}rad)`
+
+ // rotate
+ // el.style.transform = ''
+
+ // const [originalWidthStyle, originalHeightStyle] = [el.style.width, el.style.height]
+ // el.style.maxWidth = originalWidthStyle
+ // el.style.maxHeight = originalHeightStyle
+ // el.style.width = ''
+ // el.style.height = ''
+ // const bb = el.getBoundingClientRect()
+ // el.style.transform = `rotate(${body.angle}rad)`
+ // el.style.width = originalWidthStyle
+ // el.style.height = originalHeightStyle
+ // el.style.maxWidth = ''
+ // el.style.maxHeight = ''
+
+ // const fakeBody = Bodies.rectangle(
+ // bb.left + bb.width / 2,
+ // bb.top + bb.height / 2,
+ // bb.width,
+ // bb.height,
+ // {
+ // angle: body.angle,
+ // }
+ // )
+ // body.vertices = fakeBody.vertices
+ })
+ })
+
+ // create runner
+ const runner = Runner.create()
+
+ // run the engine
+ Runner.run(runner, engine)
+
+ // add mouse control
+ var mouse = Mouse.create(document.body),
+ mouseConstraint = MouseConstraint.create(engine, {
+ mouse: mouse,
+ constraint: {
+ stiffness: 0.2,
+ render: {
+ visible: false,
+ },
+ },
+ })
+ Composite.add(engine.world, mouseConstraint)
+
+ console.log('running engine')
+
+ return () => {
+ Runner.stop(runner)
+ }
+}
diff --git a/src/routes/(main)/+layout.svelte b/src/routes/(main)/+layout.svelte
index 877da4f..e07a40c 100644
--- a/src/routes/(main)/+layout.svelte
+++ b/src/routes/(main)/+layout.svelte
@@ -2,6 +2,7 @@
import '../../app.css'
import { fly } from 'svelte/transition'
import type { LayoutData } from '../$types'
+ import { browser } from '$app/environment'
export let data: LayoutData
@@ -11,7 +12,7 @@
let previousPathname = data.pathname
let currentPathName = data.pathname
let flyDirection = 1 // 1 is right, -1 is left
- $: {
+ $: if (browser) {
if (previousPathname !== currentPathName) previousPathname = currentPathName
currentPathName = data.pathname
@@ -19,6 +20,35 @@
if (previousPathname === '/') flyDirection = 1
else if (previousPathname === '/blog' && currentPathName !== '/') flyDirection = 1
else flyDirection = -1
+ onPathChange()
+ }
+
+ let pathChangeTimestamps: number[] = []
+
+ let stopGravity: (() => void) | null = null
+
+ async function onPathChange() {
+ // if we switched paths more than 10 times in the past 5 seconds, import $lib/gravity.js
+ pathChangeTimestamps.push(Date.now())
+ while (pathChangeTimestamps[0] < Date.now() - 5000) pathChangeTimestamps.shift()
+ console.log(pathChangeTimestamps)
+ if (pathChangeTimestamps.length >= 10) {
+ const { initGravity } = await import('$lib/gravity')
+ // wait 200ms for the animation to finish
+ await new Promise((resolve) => setTimeout(resolve, 200))
+ // and an animation frame
+ await new Promise((resolve) => requestAnimationFrame(resolve))
+
+ const lastPathChangeTimestamp = pathChangeTimestamps[pathChangeTimestamps.length - 1]
+ // only if it was over 200ms ago
+ if (lastPathChangeTimestamp < Date.now() - 200) {
+ if (currentPathName === '/') {
+ stopGravity = initGravity()
+ } else {
+ stopGravity?.()
+ }
+ }
+ }
}
@@ -33,15 +63,12 @@
{/key}