initial push
This commit is contained in:
parent
1494daaf68
commit
f641a29bd8
64
.gitignore
vendored
64
.gitignore
vendored
|
@ -1,79 +1,105 @@
|
||||||
# ---> Node
|
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
|
|
||||||
logs
|
logs
|
||||||
*.log
|
_.log
|
||||||
npm-debug.log*
|
npm-debug.log_
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
.pnpm-debug.log*
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# Caches
|
||||||
|
|
||||||
|
.cache
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
||||||
|
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||||
|
|
||||||
# Runtime data
|
# Runtime data
|
||||||
|
|
||||||
pids
|
pids
|
||||||
*.pid
|
_.pid
|
||||||
*.seed
|
_.seed
|
||||||
*.pid.lock
|
*.pid.lock
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
|
||||||
lib-cov
|
lib-cov
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
# Coverage directory used by tools like istanbul
|
||||||
|
|
||||||
coverage
|
coverage
|
||||||
*.lcov
|
*.lcov
|
||||||
|
|
||||||
# nyc test coverage
|
# nyc test coverage
|
||||||
|
|
||||||
.nyc_output
|
.nyc_output
|
||||||
|
|
||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
|
||||||
.grunt
|
.grunt
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
|
||||||
bower_components
|
bower_components
|
||||||
|
|
||||||
# node-waf configuration
|
# node-waf configuration
|
||||||
|
|
||||||
.lock-wscript
|
.lock-wscript
|
||||||
|
|
||||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
|
||||||
build/Release
|
build/Release
|
||||||
|
|
||||||
# Dependency directories
|
# Dependency directories
|
||||||
|
|
||||||
node_modules/
|
node_modules/
|
||||||
jspm_packages/
|
jspm_packages/
|
||||||
|
|
||||||
# Snowpack dependency directory (https://snowpack.dev/)
|
# Snowpack dependency directory (https://snowpack.dev/)
|
||||||
|
|
||||||
web_modules/
|
web_modules/
|
||||||
|
|
||||||
# TypeScript cache
|
# TypeScript cache
|
||||||
|
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
|
|
||||||
# Optional npm cache directory
|
# Optional npm cache directory
|
||||||
|
|
||||||
.npm
|
.npm
|
||||||
|
|
||||||
# Optional eslint cache
|
# Optional eslint cache
|
||||||
|
|
||||||
.eslintcache
|
.eslintcache
|
||||||
|
|
||||||
# Optional stylelint cache
|
# Optional stylelint cache
|
||||||
|
|
||||||
.stylelintcache
|
.stylelintcache
|
||||||
|
|
||||||
# Microbundle cache
|
# Microbundle cache
|
||||||
|
|
||||||
.rpt2_cache/
|
.rpt2_cache/
|
||||||
.rts2_cache_cjs/
|
.rts2_cache_cjs/
|
||||||
.rts2_cache_es/
|
.rts2_cache_es/
|
||||||
.rts2_cache_umd/
|
.rts2_cache_umd/
|
||||||
|
|
||||||
# Optional REPL history
|
# Optional REPL history
|
||||||
|
|
||||||
.node_repl_history
|
.node_repl_history
|
||||||
|
|
||||||
# Output of 'npm pack'
|
# Output of 'npm pack'
|
||||||
|
|
||||||
*.tgz
|
*.tgz
|
||||||
|
|
||||||
# Yarn Integrity file
|
# Yarn Integrity file
|
||||||
|
|
||||||
.yarn-integrity
|
.yarn-integrity
|
||||||
|
|
||||||
# dotenv environment variable files
|
# dotenv environment variable files
|
||||||
|
|
||||||
.env
|
.env
|
||||||
.env.development.local
|
.env.development.local
|
||||||
.env.test.local
|
.env.test.local
|
||||||
|
@ -81,52 +107,72 @@ web_modules/
|
||||||
.env.local
|
.env.local
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
.cache
|
|
||||||
.parcel-cache
|
.parcel-cache
|
||||||
|
|
||||||
# Next.js build output
|
# Next.js build output
|
||||||
|
|
||||||
.next
|
.next
|
||||||
out
|
out
|
||||||
|
|
||||||
# Nuxt.js build / generate output
|
# Nuxt.js build / generate output
|
||||||
|
|
||||||
.nuxt
|
.nuxt
|
||||||
dist
|
dist
|
||||||
|
|
||||||
# Gatsby files
|
# Gatsby files
|
||||||
.cache/
|
|
||||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
|
||||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
|
||||||
# public
|
# public
|
||||||
|
|
||||||
# vuepress build output
|
# vuepress build output
|
||||||
|
|
||||||
.vuepress/dist
|
.vuepress/dist
|
||||||
|
|
||||||
# vuepress v2.x temp and cache directory
|
# vuepress v2.x temp and cache directory
|
||||||
|
|
||||||
.temp
|
.temp
|
||||||
.cache
|
|
||||||
|
|
||||||
# Docusaurus cache and generated files
|
# Docusaurus cache and generated files
|
||||||
|
|
||||||
.docusaurus
|
.docusaurus
|
||||||
|
|
||||||
# Serverless directories
|
# Serverless directories
|
||||||
|
|
||||||
.serverless/
|
.serverless/
|
||||||
|
|
||||||
# FuseBox cache
|
# FuseBox cache
|
||||||
|
|
||||||
.fusebox/
|
.fusebox/
|
||||||
|
|
||||||
# DynamoDB Local files
|
# DynamoDB Local files
|
||||||
|
|
||||||
.dynamodb/
|
.dynamodb/
|
||||||
|
|
||||||
# TernJS port file
|
# TernJS port file
|
||||||
|
|
||||||
.tern-port
|
.tern-port
|
||||||
|
|
||||||
# Stores VSCode versions used for testing VSCode extensions
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
|
||||||
.vscode-test
|
.vscode-test
|
||||||
|
|
||||||
# yarn v2
|
# yarn v2
|
||||||
|
|
||||||
.yarn/cache
|
.yarn/cache
|
||||||
.yarn/unplugged
|
.yarn/unplugged
|
||||||
.yarn/build-state.yml
|
.yarn/build-state.yml
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
|
# IntelliJ based IDEs
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Finder (MacOS) folder config
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
dist
|
||||||
|
src/web/dist.js
|
|
@ -1,2 +1,4 @@
|
||||||
# website
|
# sophie's website
|
||||||
|
this website is very simple it is located in src/web.
|
||||||
|
there is a very sophisticated build script in src/build.ts !
|
||||||
|
it even supports HMR!
|
12
global.d.ts
vendored
Normal file
12
global.d.ts
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import P5 from "p5"
|
||||||
|
import * as p5Sound from 'p5/lib/addons/p5.sound'
|
||||||
|
import * as p5Global from 'p5/global'
|
||||||
|
|
||||||
|
export = P5;
|
||||||
|
export as namespace p5;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
p5: typeof P5,
|
||||||
|
}
|
||||||
|
}
|
24
package.json
Normal file
24
package.json
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"name": "sophie",
|
||||||
|
"module": "index.ts",
|
||||||
|
"type": "module",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"@types/node": "^20.11.30",
|
||||||
|
"@types/p5": "^1.7.6",
|
||||||
|
"@types/serve-handler": "^6.1.4",
|
||||||
|
"esbuild": "0.20.2",
|
||||||
|
"micro": "^10.0.1",
|
||||||
|
"serve-handler": "^6.1.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5.0.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"dev": "bun src/build.ts --dev",
|
||||||
|
"build": "bun src/build.ts --build"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ws": "^8.16.0"
|
||||||
|
}
|
||||||
|
}
|
102
src/build.ts
Normal file
102
src/build.ts
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
import * as esbuild from "esbuild"
|
||||||
|
import {watch, cpSync, rmdirSync, createReadStream, readFileSync, ReadStream} from "node:fs"
|
||||||
|
import { serve } from 'micro';
|
||||||
|
import {Server} from "node:http"
|
||||||
|
import handler from "serve-handler"
|
||||||
|
import { Readable } from "node:stream";
|
||||||
|
import { WebSocketServer } from 'ws';
|
||||||
|
|
||||||
|
const argv = process.argv.slice(2)
|
||||||
|
|
||||||
|
function buildTs() {
|
||||||
|
console.log("[dev] Building file..")
|
||||||
|
esbuild.build({
|
||||||
|
entryPoints: ["./src/web/ts/index.ts"],
|
||||||
|
outfile: "./src/web/dist.js"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
buildTs();
|
||||||
|
|
||||||
|
if(argv[0] == "--build") {
|
||||||
|
try{rmdirSync("./dist")}catch{}
|
||||||
|
cpSync("./src/web/", "./dist/", {recursive:true})
|
||||||
|
rmdirSync("./dist/ts",{recursive:true})
|
||||||
|
console.log("[dev] View the dist folder")
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argv[0] == "--dev") {
|
||||||
|
const scriptName = Math.random().toFixed(10).replace("0.","")
|
||||||
|
|
||||||
|
const wss = new WebSocketServer({ port: 8081 });
|
||||||
|
let allConnections: any[] = [];
|
||||||
|
|
||||||
|
wss.on('connection', function connection(ws) {
|
||||||
|
//@ts-ignore
|
||||||
|
ws.id = Math.random();
|
||||||
|
//@ts-ignore
|
||||||
|
|
||||||
|
allConnections.push(ws);
|
||||||
|
|
||||||
|
ws.on('error', console.error);
|
||||||
|
ws.on("close", () => {
|
||||||
|
//@ts-ignore
|
||||||
|
allConnections = allConnections.filter(z => z.id != ws.id);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const server = new Server(
|
||||||
|
serve(async (req, res) => {
|
||||||
|
if(req.url == `/${scriptName}.js`) {
|
||||||
|
const body = `let t;function rr() {console.log("connecting to dev server")
|
||||||
|
let a = new WebSocket("ws://localhost:8081");
|
||||||
|
a.addEventListener("message", g => {
|
||||||
|
if(g.data == "refresh"){
|
||||||
|
location.reload()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
a.addEventListener("open", () => {
|
||||||
|
console.log("connected")
|
||||||
|
})
|
||||||
|
a.addEventListener("close", () => {
|
||||||
|
console.log("socket closed, restarting in 1s")
|
||||||
|
clearInterval(t)
|
||||||
|
t = setTimeout(()=>{
|
||||||
|
rr()
|
||||||
|
},1000)
|
||||||
|
})};rr();`;
|
||||||
|
res
|
||||||
|
.writeHead(200, {
|
||||||
|
'Content-Length': Buffer.byteLength(body),
|
||||||
|
'Content-Type': 'text/plain',
|
||||||
|
})
|
||||||
|
.end(body);
|
||||||
|
}
|
||||||
|
if(req.url == "/" || req.url?.endsWith(".html")) {
|
||||||
|
await handler(req, res, {
|
||||||
|
directoryListing: false,
|
||||||
|
public: "src/web/"
|
||||||
|
}, {
|
||||||
|
createReadStream(path, options) {
|
||||||
|
let sx = readFileSync(path).toString("utf8");
|
||||||
|
sx = sx.replaceAll("</head>", `<script src="/${scriptName}.js"></script></head>`)
|
||||||
|
return Readable.from([sx]) as ReadStream
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await handler(req, res, {
|
||||||
|
directoryListing: false,
|
||||||
|
public: "src/web/"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
server.listen(8080)
|
||||||
|
console.log('[http] Listening HTTP on 8080.')
|
||||||
|
const watcher = watch("./src/web", {
|
||||||
|
recursive: true,
|
||||||
|
}, (e,f) => {
|
||||||
|
if(f == "dist.js") return;
|
||||||
|
console.log("[dev] Noticed update in " + f + ", of type " + e +".")
|
||||||
|
allConnections.forEach(z => z.send("refresh"));
|
||||||
|
buildTs();
|
||||||
|
})
|
||||||
|
}
|
BIN
src/web/Screenshot_2023-02-04_16-45-32.png
Executable file
BIN
src/web/Screenshot_2023-02-04_16-45-32.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 937 KiB |
109
src/web/index.html
Normal file
109
src/web/index.html
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.2/p5.min.js"
|
||||||
|
integrity="sha512-eu9vkh+EbAsW3fMmPTj/DP5W3UegIdu0Z/OABMocvoofx43MYBkcQ9hRIVxZndV1vcCYQwBg+U1PkWl04TD0Jg=="
|
||||||
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://rsms.me/">
|
||||||
|
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
|
||||||
|
|
||||||
|
<!-- Primary Meta Tags -->
|
||||||
|
<title>sophie's personal site</title>
|
||||||
|
<meta name="title" content="sophie's personal site" />
|
||||||
|
<meta name="description" content="Wow! :3 Meowww.. Nyaaa! sad.ovh, yourfriend.lol v2. Has a blog too . (maybe)
|
||||||
|
Nyaaaaaa Kitty website :3" />
|
||||||
|
|
||||||
|
<!-- Open Graph / Facebook -->
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:url" content="https://sad.ovh" />
|
||||||
|
<meta property="og:title" content="sophie's personal site" />
|
||||||
|
<meta property="og:description" content="Wow! :3 Meowww.. Nyaaa! sad.ovh, yourfriend.lol v2. Has a blog too . (maybe)
|
||||||
|
Nyaaaaaa Kitty website :3" />
|
||||||
|
<meta property="og:image" content="https://sad.ovh/Screenshot_2023-02-04_16-45-32.png" />
|
||||||
|
|
||||||
|
<!-- Twitter -->
|
||||||
|
<meta property="twitter:card" content="summary_large_image" />
|
||||||
|
<meta property="twitter:url" content="https://sad.ovh" />
|
||||||
|
<meta property="twitter:title" content="sophie's personal site" />
|
||||||
|
<meta property="twitter:description" content="Wow! :3 Meowww.. Nyaaa! sad.ovh, yourfriend.lol v2. Has a blog too . (maybe)
|
||||||
|
Nyaaaaaa Kitty website :3" />
|
||||||
|
<meta property="twitter:image" content="https://sad.ovh/Screenshot_2023-02-04_16-45-32.png" />
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<script src="dist.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body[data-theme="light"] {
|
||||||
|
color: #31363F;
|
||||||
|
}
|
||||||
|
|
||||||
|
body[data-theme="dark"] {
|
||||||
|
color: #eeeeee;
|
||||||
|
}
|
||||||
|
|
||||||
|
body[data-theme="dark"]>.center>a {
|
||||||
|
color: #eeeeee !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body[data-theme="light"]>.center>a {
|
||||||
|
color: #31363F !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
font-family: Inter, sans-serif;
|
||||||
|
font-feature-settings: 'liga' 1, 'calt' 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports (font-variation-settings: normal) {
|
||||||
|
:root {
|
||||||
|
font-family: InterVariable, sans-serif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<span class="center">
|
||||||
|
<div>
|
||||||
|
<button class="selected" id="home-button">home</button> | <button id="donations-button">donations</button>
|
||||||
|
</div>
|
||||||
|
<span id="home">
|
||||||
|
I'm Latvian, 17. My name's Sophie. I love listening to music, I have <span id="songplays"><loading...></span> song plays.
|
||||||
|
<br>
|
||||||
|
I am a JS/TS developer, mostly specializing in backend work.
|
||||||
|
<br>
|
||||||
|
I play minecraft, and upgun with friends. I have developed many bukkit plugins for Paper/Folia/Spigot before, and am pretty well versed in them.
|
||||||
|
<br>
|
||||||
|
Contact me at <a href="https://matrix.to/#/@yourfriend:bark.lgbt">matrix</a>, <a href="https://discord.com/users/845374523263811614">discord</a>, <a href="https://github.com/fucksophie">github (view projects here)</a>, <a href="https://git.sad.ovh/sophie">sadgit</a>, or <a href="https://bark.lgbt/@yourfriend">mastodon</a>
|
||||||
|
</span>
|
||||||
|
<span id="donations" style="display:none">
|
||||||
|
<ul>
|
||||||
|
<li>BTC bc1q83jdukjn4a2qm0rmn9tqcfkcq60la22lqy2shx</li>
|
||||||
|
<li>ETH/BSC/<strong>USDT</strong>/USDC (send via BSC) 0xc691cd8950Fdf96Faa2aCA1CA9b4B3Fd5B2a44BB</li>
|
||||||
|
<li>SOL 79NKoiXaPzbwbsD5MFKKwmoeEPKtTsoQFfx64MHmULF7</li>
|
||||||
|
<li><strong>XMR 42iW3icQrybKYieQNSrm76dXetuXD6HaxZDijajXkge7GTSKVG4NefxBj3mbWudpY62dxRTihm4beJgy36X8xFKCTWpVAjS</strong></li>
|
||||||
|
</ul>
|
||||||
|
OR <a href="https://ko-fi.com/sophskofi">kofi</a>
|
||||||
|
<br>
|
||||||
|
<img src="/sticker.webp" alt="monero-chan" style="width:128px;">
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span style="position:absolute;left:10px;bottom:10px">
|
||||||
|
Click <kbd>spacebar</kbd> to change the themes.
|
||||||
|
</span>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
BIN
src/web/sticker.webp
Normal file
BIN
src/web/sticker.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
370
src/web/ts/index.ts
Normal file
370
src/web/ts/index.ts
Normal file
|
@ -0,0 +1,370 @@
|
||||||
|
/*
|
||||||
|
The original version of this Processing script was written by
|
||||||
|
Jason Labbe (available here: https://openprocessing.org/sketch/377231/)
|
||||||
|
|
||||||
|
This is a highly modified version by Sophie, firstly re-written using JS, and then
|
||||||
|
improved using newer techniques (no more pGraphics, using font toPoints now as an example).
|
||||||
|
Jason Labbe's version is licensed under CC BY-SA 3.0 DEED, and so is this version.
|
||||||
|
|
||||||
|
https://creativecommons.org/licenses/by-sa/3.0/deed.en
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
let particles: Particle[] = [];
|
||||||
|
let font: p5.Font;
|
||||||
|
let bgColor: p5.Color;
|
||||||
|
|
||||||
|
let darkMode = false;
|
||||||
|
|
||||||
|
let darkTheme: p5.Color;
|
||||||
|
let lightTheme: p5.Color;
|
||||||
|
|
||||||
|
interface Bounds {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
w: number;
|
||||||
|
h: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateRandomPos(x: number, y: number, mag: number) {
|
||||||
|
let randomDir = createVector(random(0, width), random(0, height));
|
||||||
|
|
||||||
|
let pos = createVector(x, y);
|
||||||
|
pos.sub(randomDir);
|
||||||
|
pos.normalize();
|
||||||
|
pos.mult(mag);
|
||||||
|
pos.add(x, y);
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTextSize(text: string, font: p5.Font) {
|
||||||
|
let fontSize = 1200; // Wait, doesn't this impact performance heavily?
|
||||||
|
// Nope, a single iteration (once warmed up) only takes around
|
||||||
|
// 0.04799999999254942ms. This means, that for a 8K screen it'd take
|
||||||
|
// 11ms, and for normal 1080P screen it takes 20-40ms (891 iterations).
|
||||||
|
// This can be optimized further, but it's a single run of this function
|
||||||
|
// every time the word is rerendered. I don't think it matters nearly as much..
|
||||||
|
// Pouring too much time into this single number.. what the hell
|
||||||
|
|
||||||
|
let bounds: Bounds;
|
||||||
|
|
||||||
|
//let iters = 0;
|
||||||
|
//let time = 0;
|
||||||
|
do {
|
||||||
|
//const loopstart = performance.now();
|
||||||
|
fontSize--;
|
||||||
|
bounds = font.textBounds(text, 0, 0, fontSize) as Bounds;
|
||||||
|
// const loopend = performance.now();
|
||||||
|
// time += loopend - loopstart;
|
||||||
|
// iters += 1;
|
||||||
|
} while (bounds.w > windowWidth - 100);
|
||||||
|
//console.log("Took " + time + "ms for " + iters + " iterations");
|
||||||
|
return fontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Particle {
|
||||||
|
pos: p5.Vector;
|
||||||
|
vel: p5.Vector;
|
||||||
|
acc: p5.Vector;
|
||||||
|
|
||||||
|
target: p5.Vector;
|
||||||
|
|
||||||
|
closeEnoughTarget: number;
|
||||||
|
maxSpeed: number;
|
||||||
|
maxForce: number;
|
||||||
|
particleSize: number;
|
||||||
|
isKilled: boolean;
|
||||||
|
startColor: p5.Color;
|
||||||
|
targetColor: p5.Color;
|
||||||
|
colorWeight: number;
|
||||||
|
colorBlendRate: number;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.pos = createVector(0, 0);
|
||||||
|
this.vel = createVector(0, 0);
|
||||||
|
this.acc = createVector(0, 0);
|
||||||
|
this.target = createVector(0, 0);
|
||||||
|
|
||||||
|
this.closeEnoughTarget = 50;
|
||||||
|
this.maxSpeed = 4.0;
|
||||||
|
this.maxForce = 0.1;
|
||||||
|
this.particleSize = 5;
|
||||||
|
this.isKilled = false;
|
||||||
|
|
||||||
|
this.startColor = color(0);
|
||||||
|
this.targetColor = color(0);
|
||||||
|
this.colorWeight = 0;
|
||||||
|
this.colorBlendRate = 0.025;
|
||||||
|
}
|
||||||
|
|
||||||
|
move() {
|
||||||
|
// Check if particle is close enough to its target to slow down
|
||||||
|
let proximityMult = 1.0;
|
||||||
|
let distance = dist(this.pos.x, this.pos.y, this.target.x, this.target.y);
|
||||||
|
if (distance < this.closeEnoughTarget) {
|
||||||
|
proximityMult = distance / this.closeEnoughTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
//.push force towards target
|
||||||
|
let towardsTarget = createVector(this.target.x, this.target.y);
|
||||||
|
towardsTarget.sub(this.pos);
|
||||||
|
towardsTarget.normalize();
|
||||||
|
towardsTarget.mult(this.maxSpeed * proximityMult);
|
||||||
|
|
||||||
|
let steer = createVector(towardsTarget.x, towardsTarget.y);
|
||||||
|
steer.sub(this.vel);
|
||||||
|
steer.normalize();
|
||||||
|
steer.mult(this.maxForce);
|
||||||
|
this.acc.add(steer);
|
||||||
|
|
||||||
|
// Move particle
|
||||||
|
this.vel.add(this.acc);
|
||||||
|
this.pos.add(this.vel);
|
||||||
|
this.acc.mult(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
draw() {
|
||||||
|
// Draw particle
|
||||||
|
let currentColor = lerpColor(
|
||||||
|
this.startColor,
|
||||||
|
this.targetColor,
|
||||||
|
this.colorWeight
|
||||||
|
);
|
||||||
|
|
||||||
|
noStroke();
|
||||||
|
fill(currentColor);
|
||||||
|
ellipse(this.pos.x, this.pos.y, this.particleSize, this.particleSize);
|
||||||
|
|
||||||
|
// Blend towards its target color
|
||||||
|
if (this.colorWeight < 1.0) {
|
||||||
|
this.colorWeight = min(this.colorWeight + this.colorBlendRate, 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kill() {
|
||||||
|
if (!this.isKilled) {
|
||||||
|
// Set its target outside the scene
|
||||||
|
let randomPos = generateRandomPos(
|
||||||
|
width / 2,
|
||||||
|
height / 2,
|
||||||
|
(width + height) / 2
|
||||||
|
);
|
||||||
|
this.target.x = randomPos.x;
|
||||||
|
this.target.y = randomPos.y;
|
||||||
|
|
||||||
|
// Begin blending its color to black
|
||||||
|
this.startColor = lerpColor(
|
||||||
|
this.startColor,
|
||||||
|
this.targetColor,
|
||||||
|
this.colorWeight
|
||||||
|
);
|
||||||
|
this.targetColor = color(0);
|
||||||
|
this.colorWeight = 0;
|
||||||
|
|
||||||
|
this.isKilled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function preload() {
|
||||||
|
font = loadFont("https://rsms.me/inter/font-files/InterVariable.ttf");
|
||||||
|
darkTheme = color(34, 40, 49, 255);
|
||||||
|
lightTheme = color(238, 238, 238, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextWord(word: string) {
|
||||||
|
const fontSize = getTextSize(word, font);
|
||||||
|
const bounds = font.textBounds(word, 0, 0, fontSize) as Bounds;
|
||||||
|
let sampleFactor = 0.2;
|
||||||
|
|
||||||
|
if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)){
|
||||||
|
sampleFactor = 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let points = font.textToPoints(
|
||||||
|
word,
|
||||||
|
(windowWidth - 25 - bounds.w) / 2,
|
||||||
|
(windowHeight + bounds.h / 2) / 2,
|
||||||
|
fontSize,
|
||||||
|
{
|
||||||
|
sampleFactor,
|
||||||
|
simplifyThreshold: 0,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let newColor = color(
|
||||||
|
random(0.0, 255.0),
|
||||||
|
random(0.0, 255.0),
|
||||||
|
random(0.0, 255.0)
|
||||||
|
);
|
||||||
|
|
||||||
|
let particleCount = particles.length;
|
||||||
|
let particleIndex = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i < points.length; i++) {
|
||||||
|
let randomIndex = Math.floor(random(0, points.length));
|
||||||
|
const point = points[randomIndex];
|
||||||
|
|
||||||
|
let newParticle;
|
||||||
|
|
||||||
|
if (particleIndex < particleCount) {
|
||||||
|
newParticle = particles[particleIndex];
|
||||||
|
newParticle.isKilled = false;
|
||||||
|
particleIndex += 1;
|
||||||
|
} else {
|
||||||
|
newParticle = new Particle();
|
||||||
|
|
||||||
|
let randomPos = generateRandomPos(
|
||||||
|
width / 2,
|
||||||
|
height / 2,
|
||||||
|
(width + height) / 2
|
||||||
|
);
|
||||||
|
newParticle.pos.x = randomPos.x;
|
||||||
|
newParticle.pos.y = randomPos.y;
|
||||||
|
|
||||||
|
newParticle.maxSpeed = random(2.0, 5.0);
|
||||||
|
newParticle.maxForce = newParticle.maxSpeed * 0.025;
|
||||||
|
newParticle.particleSize = random(3, 6);
|
||||||
|
newParticle.colorBlendRate = random(0.0025, 0.03);
|
||||||
|
|
||||||
|
particles.push(newParticle);
|
||||||
|
}
|
||||||
|
|
||||||
|
newParticle.startColor = lerpColor(
|
||||||
|
newParticle.startColor,
|
||||||
|
newParticle.targetColor,
|
||||||
|
newParticle.colorWeight
|
||||||
|
);
|
||||||
|
newParticle.targetColor = newColor;
|
||||||
|
newParticle.colorWeight = 0;
|
||||||
|
|
||||||
|
newParticle.target.x = point.x;
|
||||||
|
newParticle.target.y = point.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (particleIndex < particleCount) {
|
||||||
|
for (let i = particleIndex; i < particleCount; i++) {
|
||||||
|
let particle = particles[i];
|
||||||
|
particle.kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function windowResized() {
|
||||||
|
resizeCanvas(windowWidth, windowHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
// selection
|
||||||
|
let pages = ["home", "donations"];
|
||||||
|
let selected = "home";
|
||||||
|
pages.forEach(z => {
|
||||||
|
const buttonElement = document.getElementById(z+"-button")!;
|
||||||
|
const element = document.getElementById(z)!;
|
||||||
|
buttonElement.addEventListener("click", _ => {
|
||||||
|
if(z !== selected) {
|
||||||
|
const selectedElement = document.getElementById(selected)!
|
||||||
|
const selectedButton = document.getElementById(selected+"-button")!
|
||||||
|
selectedElement.style.display = "none";
|
||||||
|
element.style.display = "block";
|
||||||
|
selectedButton.className = ""
|
||||||
|
buttonElement.className = "selected";
|
||||||
|
selected = z;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// lastfm
|
||||||
|
(async () => {
|
||||||
|
const lastfm = await fetch(
|
||||||
|
"https://ws.audioscrobbler.com/2.0/?method=user.getinfo&user=yourfriendoss&api_key=8d983789c771afaeb7412ac358d4bad0&format=json"
|
||||||
|
);
|
||||||
|
const json = await lastfm.json();
|
||||||
|
document.getElementById("songplays")!.innerText = json.user.playcount;
|
||||||
|
})();
|
||||||
|
|
||||||
|
const theme = localStorage.getItem("theme");
|
||||||
|
if (theme == "dark") {
|
||||||
|
bgColor = darkTheme;
|
||||||
|
darkMode = true;
|
||||||
|
} else {
|
||||||
|
bgColor = lightTheme;
|
||||||
|
darkMode = false;
|
||||||
|
}
|
||||||
|
document.body.setAttribute("data-theme", darkMode ? "dark" : "light");
|
||||||
|
const canvas = createCanvas(windowWidth, windowHeight);
|
||||||
|
canvas.position(0, 0);
|
||||||
|
canvas.style("zIndex", "-1");
|
||||||
|
background(bgColor);
|
||||||
|
const p = "sad.ovh"
|
||||||
|
nextWord(p);
|
||||||
|
|
||||||
|
let ticks = 0;
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
const a = particles.filter(z => {
|
||||||
|
const x = Math.abs(Math.floor(z.vel.x))
|
||||||
|
const y = Math.abs(Math.floor(z.vel.y))
|
||||||
|
if (x == 1 || y == 1 || x == 0 || y == 0) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}).length;
|
||||||
|
|
||||||
|
if (a == 0) ticks++;
|
||||||
|
if (a != 0) ticks = 0;
|
||||||
|
|
||||||
|
if (ticks == 60 * 8) {
|
||||||
|
ticks = 0;
|
||||||
|
nextWord(p)
|
||||||
|
}
|
||||||
|
}, 1)
|
||||||
|
}
|
||||||
|
function keyPressed(a: KeyboardEvent) {
|
||||||
|
if (a.code == "Space") {
|
||||||
|
if (darkMode) {
|
||||||
|
bgColor = lightTheme;
|
||||||
|
} else {
|
||||||
|
bgColor = darkTheme;
|
||||||
|
}
|
||||||
|
darkMode = !darkMode;
|
||||||
|
document.body.setAttribute("data-theme", darkMode ? "dark" : "light");
|
||||||
|
localStorage.setItem("theme", darkMode ? "dark" : "light");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function draw() {
|
||||||
|
fill(bgColor);
|
||||||
|
noStroke();
|
||||||
|
rect(0, 0, width * 2, height * 2);
|
||||||
|
|
||||||
|
for (let x = particles.length - 1; x > -1; x--) {
|
||||||
|
let particle = particles[x];
|
||||||
|
particle.move();
|
||||||
|
particle.draw();
|
||||||
|
|
||||||
|
if (particle.isKilled) {
|
||||||
|
if (
|
||||||
|
particle.pos.x < 0 ||
|
||||||
|
particle.pos.x > width ||
|
||||||
|
particle.pos.y < 0 ||
|
||||||
|
particle.pos.y > height
|
||||||
|
) {
|
||||||
|
particles.splice(x, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseDragged() {
|
||||||
|
if (mouseButton == LEFT) {
|
||||||
|
for (const particle of particles) {
|
||||||
|
if (dist(particle.pos.x, particle.pos.y, mouseX, mouseY) < 50) {
|
||||||
|
particle.kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
tsconfig.json
Normal file
27
tsconfig.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
// Enable latest features
|
||||||
|
"lib": ["ESNext", "DOM"],
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"allowJs": true,
|
||||||
|
|
||||||
|
// Bundler mode
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
// Best practices
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
|
||||||
|
// Some stricter flags (disabled by default)
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"noPropertyAccessFromIndexSignature": false
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue