diff --git a/assets/leafs.ts b/assets/leafs.ts new file mode 100644 index 0000000..0eea93c --- /dev/null +++ b/assets/leafs.ts @@ -0,0 +1,148 @@ +import leaf1 from "./leafs/tmpleaf.svg" +import leaf2 from "./leafs/tmpleaf2.svg" +import leaf3 from "./leafs/tmpleaf3.svg" + +const DegToRad = Math.PI / 180 +const RadToDeg = 1 / DegToRad +const colors = ["#FFDCA4", "#9CCCBC", "#FFAAAD", "#8DCBDA"] + +function sample(array: T[]): T | undefined { + return array[Math.floor(Math.random() * array.length)] +} + +class LeafImage { + src: string + offset: number; + width: number; + + constructor(src: string, offset: number, width: number) { + this.src = src + this.offset = offset + this.width = width; + } + + offsetInRad() { + return this.offset * DegToRad + } +} + +const leafs = [ + new LeafImage(leaf1, 15, 186.92), + new LeafImage(leaf2, 0, 210.87), + new LeafImage(leaf3, 0, 137.2), +] + +class Wind { + get angle(): number { + return (Math.atan2(this.y, this.x) * RadToDeg + 360) % 360 + } + + get r(): number { + return Math.sqrt(this.x ** 2 + this.y ** 2) + } + + + x: number + y: number + deltaAngle: number = 0 + targetAngle: number + + constructor(x: number, y: number) { + this.x = x; + this.y = y; + this.targetAngle = this.angle + } + + setFromPolar(angle: number, r: number) { + this.x = r * Math.cos(angle * DegToRad) + this.y = r * Math.sin(angle * DegToRad) + } + + updateWind() { + this.deltaAngle *= 1 + (Math.random() - 0.3) * 0.1 + + this.targetAngle += (Math.random() - 0.5) * 10 + this.targetAngle %= 360 + + } + + rotate() { + let angle = this.angle + let r = this.r * (1 + (Math.random() - 0.5) * 0.1) + const diff = ((angle - this.targetAngle) + 180) % 360 - 180 + angle -= diff / 10 + this.setFromPolar(angle, r) + } +} + +class Leaf { + x: number = -100 + y: number + wind: Wind + angle: number = 0 + i: number = 0 + angleOffset: number + + + div: HTMLDivElement; + private svg; + + constructor(leafImage: LeafImage) { + this.angleOffset = leafImage.offsetInRad(); + this.div = document.createElement("div") + this.div.className = "leaf" + this.div.innerHTML = leafImage.src + this.svg = this.div.firstElementChild! as HTMLElement + this.svg.style.width=`${leafImage.width*.5}px` + const fill = this.svg.querySelector(".fill")! as SVGPathElement + fill.style.fill = sample(colors)! + document.body.appendChild(this.div) + this.y = Math.random() * ch + const initial_wind = 4 + Math.random() * 8 + this.wind = new Wind(initial_wind, 0) + } + + animate() { + + this.svg.style.transform = `translate3d(${this.x}px, ${this.y}px,0) rotate(${this.angle + this.angleOffset}rad` + const dx = this.wind.x + const dy = this.wind.y + gravity + this.angle = Math.atan2(dy, dx) //radians + this.x += dx + this.y -= dy + this.i += 1 + this.wind.rotate() + this.wind.updateWind() + if (this.i % 10 == 0) { + } + if (this.x > cw || this.y > ch || this.x < -300 || this.y < -300) { + this.div.remove() + return + } + requestAnimationFrame(this.animate.bind(this)) + + } +} + +const cw = window.innerWidth +const ch = window.innerHeight + +const gravity = -2 +let isSlow = true + +export function addLeaf() { + const leafImage = sample(leafs)! + const l = new Leaf(leafImage) + l.animate() + l.div.addEventListener("click", () => isSlow = false) + let timeout + if (isSlow) { + timeout = 3000 + Math.random() * 10000 + } else { + timeout = Math.random() * 500 + } + setTimeout(addLeaf, timeout) +} + + +// document.getElementById("button")!.addEventListener("click", addLeaf) diff --git a/assets/leafs/tmpleaf.svg b/assets/leafs/tmpleaf.svg new file mode 100644 index 0000000..b598258 --- /dev/null +++ b/assets/leafs/tmpleaf.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/leafs/tmpleaf2.svg b/assets/leafs/tmpleaf2.svg new file mode 100644 index 0000000..01fd517 --- /dev/null +++ b/assets/leafs/tmpleaf2.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/leafs/tmpleaf3.svg b/assets/leafs/tmpleaf3.svg new file mode 100644 index 0000000..bde5bc6 --- /dev/null +++ b/assets/leafs/tmpleaf3.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/main.ts b/assets/main.ts index 5e36bc4..39f9230 100644 --- a/assets/main.ts +++ b/assets/main.ts @@ -7,3 +7,11 @@ initBlurhash() initFeedback() initSearch() initMatomo() + +const articleEl = document.querySelector("article") +if (articleEl && articleEl.id.includes("rainbowroad")) { + console.log("bla") + import("./leafs").then((module) => { + module.addLeaf() + }) +} diff --git a/assets/scss/_leaf.scss b/assets/scss/_leaf.scss new file mode 100644 index 0000000..3deb4a4 --- /dev/null +++ b/assets/scss/_leaf.scss @@ -0,0 +1,12 @@ +.leaf { + cursor: pointer; + + svg { + z-index: 10000; + position: absolute; + top: 0; + left: 0; + transform: translate3d(0, 0, 0); + height: auto; + } +} diff --git a/assets/scss/main.scss b/assets/scss/main.scss index b8005ef..67533d3 100644 --- a/assets/scss/main.scss +++ b/assets/scss/main.scss @@ -31,3 +31,4 @@ @import "others"; @import "pagespecific"; +@import "leaf"; diff --git a/assets/types.ts b/assets/types.ts index 6031c52..6732911 100644 --- a/assets/types.ts +++ b/assets/types.ts @@ -1 +1,6 @@ export type Language = "de" | "en" + +declare module './leafs/tmpleaf.svg' { + const src: string + export default src +} diff --git a/build.ts b/build.ts index 888af8a..3ed9c0f 100644 --- a/build.ts +++ b/build.ts @@ -6,16 +6,19 @@ import * as fs from "fs"; const commonOption: BuildOptions = { entryPoints: ['assets/main.ts', 'assets/redirector.ts', "assets/scss/main.scss", 'assets/katex.css'], target: "esnext", + format: "esm", bundle: true, sourcemap: true, minify: true, outdir: "public/assets", + splitting: true, // @ts-ignore https://github.com/glromeo/esbuild-sass-plugin/issues/109 plugins: [sassPlugin()], loader: { ".ttf": "file", ".woff": "file", ".woff2": "file", + ".svg": "text", ".png": "base64" }, entryNames: "[name]" diff --git a/tsconfig.json b/tsconfig.json index 0ec4f7a..c7f0be0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "target": "ES2020", "strict": true, "isolatedModules": true, "esModuleInterop": true,