This commit is contained in:
parent
199c85a262
commit
6af6c3ea79
16 changed files with 216 additions and 500 deletions
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
18
global.d.ts
vendored
18
global.d.ts
vendored
|
@ -1,15 +1,5 @@
|
|||
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,
|
||||
setup: () => void,
|
||||
preload: () => void,
|
||||
draw: () => void
|
||||
}
|
||||
}
|
||||
let __BLOG_POSTS__: string[]
|
||||
let __STICKERS__: string[]
|
||||
}
|
||||
export { };
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
"esbuild": "^0.23.0",
|
||||
"marked": "^13.0.2",
|
||||
"mime-types": "^2.1.35",
|
||||
"nano-jsx": "^0.1.0",
|
||||
"p5": "^1.9.4"
|
||||
"nano-jsx": "^0.1.0"
|
||||
}
|
||||
}
|
|
@ -66,6 +66,9 @@ export default class DevPlugin extends Plugin {
|
|||
}
|
||||
return new Response(rawFile, {
|
||||
headers: {
|
||||
"Cache-Control": "no-cache, no-store, must-revalidate",
|
||||
"Pragma": "no-cache",
|
||||
"Expires": "0",
|
||||
"Content-Type": (mime.lookup(type) || "application/octet-stream") + "; charset=utf-8",
|
||||
},
|
||||
});
|
||||
|
|
|
@ -15,6 +15,9 @@ export default class Variables extends Plugin {
|
|||
this.variables["__BLOG_POSTS__"] = JSON.stringify(
|
||||
fs.readdirSync("./website/blogs").map((z) => z.replace(".md", ""))
|
||||
);
|
||||
this.variables["__STICKERS__"] = JSON.stringify(
|
||||
fs.readdirSync("./website/assets/stickers")
|
||||
);
|
||||
const templatePath = path.resolve(__dirname, "../../website/templates");
|
||||
if (fs.existsSync(templatePath)) {
|
||||
for (const file of fs.readdirSync(templatePath)) {
|
||||
|
|
BIN
website/assets/stickers/meow_sticker.webp
Normal file
BIN
website/assets/stickers/meow_sticker.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
BIN
website/assets/stickers/monero2_sticker.webp
Normal file
BIN
website/assets/stickers/monero2_sticker.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
website/assets/stickers/monero3_sticker.webp
Normal file
BIN
website/assets/stickers/monero3_sticker.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
BIN
website/assets/stickers/ovpn_sticker.webp
Normal file
BIN
website/assets/stickers/ovpn_sticker.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
|
@ -1,36 +1,127 @@
|
|||
body[data-theme="light"] {
|
||||
color: #31363F;
|
||||
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@100..900&family=Noto+Emoji:wght@300..700&display=swap");
|
||||
|
||||
body {
|
||||
font-family: "Inter", sans-serif;
|
||||
font-optical-sizing: auto;
|
||||
font-style: normal;
|
||||
font-variation-settings: "slnt" 0;
|
||||
scrollbar-color: #ffffffae #000000a1;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
body[data-theme="dark"] {
|
||||
color: #eeeeee;
|
||||
.order {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"one two"
|
||||
"four blog"
|
||||
"three blog";
|
||||
grid-gap: 5px;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
height: 98vh;
|
||||
}
|
||||
@media only screen and (max-width: 600px) {
|
||||
.order {
|
||||
grid-template-areas:
|
||||
"one "
|
||||
"two "
|
||||
"blog "
|
||||
"blog ";
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.three {
|
||||
display: none !important;
|
||||
}
|
||||
body {
|
||||
scrollbar-width: auto !important;
|
||||
}
|
||||
}
|
||||
.emoji {
|
||||
font-family: "Noto Emoji", sans-serif;
|
||||
font-optical-sizing: auto;
|
||||
font-style: normal;
|
||||
font-variation-settings: "slnt" 0;
|
||||
}
|
||||
.paper > h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
h6s {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.paper {
|
||||
color: white;
|
||||
background-color: #000000de;
|
||||
padding: 15px;
|
||||
border: 1px black solid;
|
||||
border-radius: 5px;
|
||||
word-wrap: break-word;
|
||||
overflow: auto;
|
||||
}
|
||||
.blog {
|
||||
grid-area: blog;
|
||||
}
|
||||
.one {
|
||||
grid-area: one;
|
||||
}
|
||||
.two {
|
||||
grid-area: two;
|
||||
}
|
||||
.three {
|
||||
grid-area: three;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 20px;
|
||||
}
|
||||
.three > img,
|
||||
.three > video {
|
||||
height: 100%;
|
||||
}
|
||||
.four {
|
||||
grid-area: four;
|
||||
}
|
||||
.e-mail {
|
||||
font-size: small;
|
||||
}
|
||||
/*https://danmarshall.github.io/google-font-to-svg-path/*/
|
||||
/*https://yoksel.github.io/url-encoder/*/
|
||||
.repeating-bg {
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='99.612' height='99.612' viewBox='0 0 99.612 99.612' xmlns='http://www.w3.org/2000/svg'%3E%3Cg id='svgGroup' stroke-linecap='round' fill-rule='evenodd' font-size='9pt' stroke='%23000' stroke-width='0.25mm' fill='%23000' style='stroke:%23000;stroke-width:0.25mm;fill:%23000'%3E%3Cpath d='M 30.47 95.753 A 48.715 48.715 0 0 0 49.806 99.611 Q 60.109 99.611 69.142 95.729 Q 78.175 91.847 85.011 85.011 Q 91.847 78.175 95.729 69.142 Q 99.611 60.109 99.611 49.806 Q 99.611 39.503 95.729 30.47 Q 91.847 21.437 85.011 14.601 Q 78.175 7.765 69.142 3.883 Q 60.109 0.001 49.806 0.001 A 48.715 48.715 0 0 0 30.47 3.859 Q 21.437 7.716 14.576 14.576 Q 7.716 21.437 3.859 30.445 A 46.98 46.98 0 0 0 3.169 32.146 A 48.984 48.984 0 0 0 0.001 49.806 A 48.715 48.715 0 0 0 3.859 69.142 Q 7.716 78.175 14.576 85.035 Q 21.437 91.896 30.47 95.753 Z M 49.806 97.657 A 46.875 46.875 0 0 0 68.409 93.946 Q 77.101 90.236 83.668 83.668 Q 90.236 77.101 93.946 68.409 A 46.875 46.875 0 0 0 97.657 49.806 A 46.875 46.875 0 0 0 93.946 31.202 Q 90.236 22.511 83.668 15.944 Q 77.101 9.376 68.409 5.665 A 46.875 46.875 0 0 0 49.806 1.954 A 46.875 46.875 0 0 0 31.202 5.665 Q 22.511 9.376 15.944 15.944 Q 9.376 22.511 5.665 31.202 A 46.875 46.875 0 0 0 1.954 49.806 A 46.875 46.875 0 0 0 5.665 68.409 Q 9.376 77.101 15.944 83.668 Q 22.511 90.236 31.202 93.946 A 46.875 46.875 0 0 0 49.806 97.657 Z M 25.636 75.441 L 23.976 74.464 Q 26.271 70.314 30.299 67.213 Q 34.327 64.112 39.381 62.355 A 31.511 31.511 0 0 1 49.806 60.597 A 31.511 31.511 0 0 1 60.231 62.355 A 31.668 31.668 0 0 1 69.313 67.237 A 24.816 24.816 0 0 1 74.121 72.115 A 22.347 22.347 0 0 1 75.636 74.464 L 73.976 75.441 A 21.687 21.687 0 0 0 69.296 69.752 A 25.564 25.564 0 0 0 68.043 68.727 A 29.994 29.994 0 0 0 59.547 64.186 Q 54.835 62.55 49.806 62.55 Q 44.777 62.55 40.04 64.186 A 30.049 30.049 0 0 0 32.025 68.342 A 28.374 28.374 0 0 0 31.544 68.702 A 22.453 22.453 0 0 0 26.811 73.573 A 20.69 20.69 0 0 0 25.636 75.441 Z M 29.355 43.927 A 4.755 4.755 0 0 0 32.618 45.216 Q 34.913 45.216 36.549 43.263 A 6.833 6.833 0 0 0 37.75 41.187 A 7.624 7.624 0 0 0 38.185 38.575 A 8.876 8.876 0 0 0 38.177 38.195 A 6.983 6.983 0 0 0 36.549 33.888 A 6.828 6.828 0 0 0 36.126 33.427 A 4.823 4.823 0 0 0 32.618 31.935 A 4.64 4.64 0 0 0 30.025 32.707 A 6.163 6.163 0 0 0 28.712 33.888 Q 27.052 35.841 27.052 38.575 A 8.824 8.824 0 0 0 27.056 38.841 A 6.945 6.945 0 0 0 28.712 43.263 A 6.831 6.831 0 0 0 29.355 43.927 Z M 63.73 43.927 A 4.755 4.755 0 0 0 66.993 45.216 Q 69.288 45.216 70.924 43.263 A 6.833 6.833 0 0 0 72.125 41.187 A 7.624 7.624 0 0 0 72.56 38.575 A 8.876 8.876 0 0 0 72.552 38.195 A 6.983 6.983 0 0 0 70.924 33.888 A 6.828 6.828 0 0 0 70.501 33.427 A 4.823 4.823 0 0 0 66.993 31.935 A 4.64 4.64 0 0 0 64.4 32.707 A 6.163 6.163 0 0 0 63.087 33.888 Q 61.427 35.841 61.427 38.575 A 8.824 8.824 0 0 0 61.431 38.841 A 6.945 6.945 0 0 0 63.087 43.263 A 6.831 6.831 0 0 0 63.73 43.927 Z' vector-effect='non-scaling-stroke'/%3E%3C/g%3E%3C/svg%3E");
|
||||
background-position: 20px 20px;
|
||||
}
|
||||
|
||||
body[data-theme="dark"]>.center>a {
|
||||
color: #eeeeee !important;
|
||||
a {
|
||||
color: white;
|
||||
}
|
||||
.fake-input > .input {
|
||||
border: none;
|
||||
border-bottom: 2px solid black;
|
||||
}
|
||||
.fake-input > .input:focus {
|
||||
border-bottom: 2px solid red;
|
||||
outline: none;
|
||||
}
|
||||
.fake-input {
|
||||
border-radius: 6px;
|
||||
border: 3px solid black;
|
||||
padding: 2px;
|
||||
}
|
||||
.button {
|
||||
background-color: transparent;
|
||||
border-radius: 6px;
|
||||
border: 3px dotted black;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
body[data-theme="light"]>.center>a {
|
||||
color: #31363F !important;
|
||||
.body-center {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
: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;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
__TEMPLATE_HEAD__
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kimeiga/bahunya/dist/bahunya.min.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="scripts/blog.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,54 +1,83 @@
|
|||
__TEMPLATE_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>
|
||||
|
||||
<script type="module" src="scripts/blog.js"></script>
|
||||
<script>
|
||||
window.addEventListener("load", () => {
|
||||
const stickers = document.getElementById("stickers");
|
||||
if (!stickers) return;
|
||||
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
<script src="scripts/index.js"></script>
|
||||
for (const sticker of __STICKERS__) {
|
||||
const img = document.createElement("img");
|
||||
img.src = "assets/stickers/" + sticker;
|
||||
stickers.appendChild(img);
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<span class="center">
|
||||
<div>
|
||||
<button class="selected" id="home-button">home</button> | <button id="donations-button">donations</button> |
|
||||
<a href="/blog.html"><button>blog</button></a>
|
||||
<body class="repeating-bg">
|
||||
<div class="order">
|
||||
<div class="paper one">
|
||||
<h1><span class="emoji">☹️☹️☹️</span>.ovh</h1>
|
||||
<p>I'm Latvian, 17. My name's Sophie <small>meows a lot</small>. I love listening to music.</p>
|
||||
|
||||
<p>I love to play games with peeps! My favorite games recently have been Minecraft and Stardew Valley! DM me
|
||||
if you wanna play with me ^w^</p>
|
||||
|
||||
<p>
|
||||
DNI:
|
||||
<br>
|
||||
Interact: Any person ever
|
||||
</p>
|
||||
<p>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>
|
||||
|
||||
</p>
|
||||
<p>E-mail: (run in JS) <span class="e-mail">new TextDecoder().decode(new Uint8Array([115, 111, 102, 105,
|
||||
106, 97, 64,
|
||||
100, 117, 99, 107, 46, 99, 111, 109]))</span></p>
|
||||
<a href="assets/key.txt">Signing PGP key downloadable here.</a>
|
||||
</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>
|
||||
<br>
|
||||
<a href="assets/key.txt">Here's my PGP key.</a>
|
||||
</span>
|
||||
<span id="donations" style="display:none">
|
||||
<div class="paper two">
|
||||
<h1>donations</h1>
|
||||
<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>BTC <strong>bc1q83jdukjn4a2qm0rmn9tqcfkcq60la22lqy2shx</strong>
|
||||
</li>
|
||||
<li>ETH/BSC/USDT/USDC (send via BSC) <strong>0xc691cd8950Fdf96Faa2aCA1CA9b4B3Fd5B2a44BB</strong>
|
||||
</li>
|
||||
<li>SOL <strong>79NKoiXaPzbwbsD5MFKKwmoeEPKtTsoQFfx64MHmULF7</strong>
|
||||
</li>
|
||||
<li>XMR
|
||||
<strong>
|
||||
42iW3icQrybKYieQNSrm76dXetuXD6HaxZDijajXkge7GTSKVG4NefxBj3mbWudpY62dxRTihm4beJgy36X8xFKCTWpVAjS
|
||||
</strong>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://ko-fi.com/sophskofi">Ko-fi</a>, Paypal (DM or Email me)
|
||||
</li>
|
||||
</ul>
|
||||
OR <a href="https://ko-fi.com/sophskofi">kofi</a> OR, dm for paypal
|
||||
<br>
|
||||
<img src="assets/sticker.webp" alt="monero-chan" style="width:128px;">
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="paper four">
|
||||
<h1>Skills</h1>
|
||||
<!--replace this with Code::Stats once I've actually gotten some time on there-->
|
||||
<ul>
|
||||
<li>Around 8 years of near constant JS/TS development. Full-Stack, including discord bots.</li>
|
||||
<li>3 years of TSX</li>
|
||||
<li>SQL and PostgreSQL(pSQL) since I started development.</li>
|
||||
<li>Lots of webdev build tools and more. <a href="https://git.sad.ovh/sophie/website">This site uses my
|
||||
own build tools.</a></li>
|
||||
<li>9 years of Java development. Mostly Minecraft plugins and MC related projects.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paper blog" id="root"></div>
|
||||
<div class="paper three" id="stickers"></div>
|
||||
|
||||
<span style="position:absolute;left:10px;bottom:10px">
|
||||
Click <kbd>spacebar</kbd> to change the themes.
|
||||
</span>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -10,7 +10,6 @@ export interface Metadata {
|
|||
filename: string;
|
||||
}
|
||||
|
||||
//@ts-expect-error
|
||||
const blog_posts = __BLOG_POSTS__ as string[];
|
||||
|
||||
const fetchBlogPosts = async () => {
|
||||
|
@ -55,34 +54,31 @@ class Main extends Component {
|
|||
}
|
||||
|
||||
render(blogPosts: Metadata[]) {
|
||||
|
||||
const pageOpen = useState<Metadata | undefined>(undefined, "pageOpen");
|
||||
const md = new URLSearchParams(location.search).get("md");
|
||||
let pageOpenValueRender = pageOpen[0];
|
||||
|
||||
if (blogPosts) {
|
||||
const found = blogPosts.find(z => z.filename == md);
|
||||
if (found) {
|
||||
pageOpen[1](found);
|
||||
//@ts-expect-error
|
||||
pageOpen[0] = found;
|
||||
pageOpenValueRender = found;
|
||||
}
|
||||
}
|
||||
|
||||
if (pageOpen[0]) {
|
||||
return <div><BlogPage metadata={pageOpen[0]} updateParent={this.handleSelfUpdate.bind(this)}
|
||||
></BlogPage></div>
|
||||
if (pageOpenValueRender) {
|
||||
return <div><BlogPage metadata={pageOpenValueRender} updateParent={this.handleSelfUpdate.bind(this)}></BlogPage></div>
|
||||
}
|
||||
|
||||
|
||||
return <div>
|
||||
<h1> sophie's blog </h1>
|
||||
|
||||
<a style="font-size:xx-large;" href="/">back to main page?</a>
|
||||
{() => {
|
||||
if (blogPosts) return this.list(blogPosts)
|
||||
else return <h3>Loading...</h3>
|
||||
}}
|
||||
<Giscus searchTerm="main"></Giscus>
|
||||
</div>
|
||||
return <>
|
||||
<h1> blog </h1>
|
||||
{() => {
|
||||
if (blogPosts) return this.list(blogPosts)
|
||||
else return <h3>Loading...</h3>
|
||||
}}
|
||||
<Giscus searchTerm="main"></Giscus>
|
||||
</>
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export function Giscus({searchTerm}: {searchTerm: string}) {
|
||||
export function Giscus({ searchTerm }: { searchTerm: string }) {
|
||||
let config: Record<string, string> = {
|
||||
"repo": "fucksophie/blog_comments",
|
||||
"repo-id": "R_kgDOMY4cfw",
|
||||
|
@ -14,9 +14,9 @@ export function Giscus({searchTerm}: {searchTerm: string}) {
|
|||
"lang": "en",
|
||||
"loading": "lazy",
|
||||
}
|
||||
for(const x of Object.entries(config)) {
|
||||
for (const x of Object.entries(config)) {
|
||||
delete config[x[0]];
|
||||
config["data-"+x[0]] = x[1];
|
||||
config["data-" + x[0]] = x[1];
|
||||
}
|
||||
return <div>
|
||||
<script src="https://giscus.app/client.js" {...config} crossorigin="anonymous" async></script>
|
||||
|
|
|
@ -1,385 +0,0 @@
|
|||
/*
|
||||
The original version of this ProcessingJava 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
|
||||
*/
|
||||
|
||||
import type { Keyboard } from "puppeteer";
|
||||
|
||||
/*
|
||||
You won't believe what they say about us, bad PR
|
||||
Bad chemistry between the 9 and 3-Star
|
||||
Only real fanatics know, TL;DR
|
||||
In the ER, at the hotel, two key-cards
|
||||
GTB, they still want to hear "GT-R"
|
||||
Black Discharge top, G-Star Raw's
|
||||
Sing Peroxide on the stage in B-sharp
|
||||
black windows on the strip, black Dodge Charge
|
||||
*/
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.preload = function() {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.windowResized = function() {
|
||||
resizeCanvas(windowWidth, windowHeight);
|
||||
}
|
||||
|
||||
window.setup = function() {
|
||||
// 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)
|
||||
}
|
||||
window.keyPressed = function (a) {
|
||||
if(!a) return;
|
||||
const event = a as KeyboardEvent;
|
||||
if (event.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");
|
||||
}
|
||||
}
|
||||
window.draw = function () {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.mouseDragged = function () {
|
||||
if (mouseButton == LEFT) {
|
||||
for (const particle of particles) {
|
||||
if (dist(particle.pos.x, particle.pos.y, mouseX, mouseY) < 50) {
|
||||
particle.kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue