Compare commits

...

35 commits

Author SHA1 Message Date
d458f440ba Tons of little touch ups for 600 commits :) 2024-06-26 20:47:21 -05:00
179ca1fc66 Update default commit count 2024-06-26 20:11:41 -05:00
a073df8ea3 add "page embeds" as a highlighted word with a link 2024-06-26 20:10:26 -05:00
9f137d70ef Highlights can now have links 2024-06-26 20:07:02 -05:00
7ad9b489cf Bio update 2024-06-26 19:24:19 -05:00
e1de101cc7 Subpage 2.0! 2024-06-26 19:18:44 -05:00
c6d72516d5 Disable pointer events 2024-06-26 18:18:14 -05:00
b9f830a23b Javascript particle alternatives 2024-06-26 18:16:19 -05:00
ff3d4e4d04 Remove debug lines 2024-06-26 05:13:13 -05:00
e05884f41f Dont change text of elemets that had their text changed during delay? 2024-06-26 05:12:31 -05:00
0e1f6f09b3 Generate JS on run instead of load 2024-06-26 05:09:19 -05:00
352ea02d6d Fix color being incorrect without javascript 2024-06-26 04:59:01 -05:00
99b3b75058 Coder theme 2024-06-26 04:56:54 -05:00
b0f6cdb1a5 Switch to development build of jquery 2024-06-26 03:54:51 -05:00
207847781a Make width consistent 2024-06-25 19:33:49 -05:00
2937ab2abb Increase Z index of video so it can be clicked 2024-06-25 19:06:23 -05:00
a72ce104f5 more stats 2024-06-25 19:02:29 -05:00
e8e78a07aa Replace min with min slim 2024-06-25 18:54:22 -05:00
67d8e3bec2 Javascript compression now caches 2024-06-25 18:41:15 -05:00
0364cca624 Add jquery (needs optimizing lol) 2024-06-25 18:35:58 -05:00
c6ddb7fe40 make html safe (I have no idea how this works 2024-06-25 18:10:22 -05:00
e3dcd08714 World outlines ? 2024-06-25 13:39:56 -05:00
df19fcfebb my name is no longer highlighted in socials section 2024-06-25 13:16:22 -05:00
21fbd54b77 Remove blur 2024-06-25 12:56:22 -05:00
72c7d306d8 Show time of last pregeneration on site 2024-06-25 01:35:22 -05:00
ba79d970a1 VASTLY decreased the amount of pregenerations done by the site, greatly improving performance 2024-06-25 01:32:39 -05:00
ae1397d84a properly updated connected variable 2024-06-25 01:05:18 -05:00
74f2911244 seperate API & pageUpdater files 2024-06-25 01:02:28 -05:00
6057503e06 some box shadow :D (I cant see rn will color better later) 2024-06-23 19:24:06 -05:00
0ce5245843 Transparent card with magic theme 2024-06-23 19:19:18 -05:00
89e8b1523e Use month day instead of week day 2024-06-23 19:06:49 -05:00
1f8f058a30 New magic-like theme 2024-06-23 19:03:11 -05:00
beaa2406d1 Optimize rain, fix crash 2024-06-23 16:09:39 -05:00
01e6f8abd4 Minor spelling mistake *hollow purple* 2024-06-20 23:36:07 -05:00
9c6dff4bea Bring back old spinning 2024-06-20 23:34:24 -05:00
21 changed files with 11348 additions and 216 deletions

72
api.js Normal file
View file

@ -0,0 +1,72 @@
const path = require("path"),
fs = require("fs"),
WebSocket = require('ws'),
EventEmitter = require("events").EventEmitter
const events = new EventEmitter();
const constants = JSON.parse(fs.readFileSync(path.join(__dirname, "constants.json")))
var lastPong = 0
module.exports = {
"lanyard": constants.fallbackLanyard,
"connected": false,
"lastLanyardUpdate": Date.now(),
"events": events,
"spins": 0,
}
function socketeer() {
var lanyard = new WebSocket('https://api.violets-purgatory.dev')
lanyard.on("error", (error) => {
console.log(error)
})
lanyard.on("close", () => {
console.log("Connection Closed. Attempting Reconnect in 30 seconds.")
module.exports.lanyard = constants.fallbackLanyard
module.exports.connected = false
setTimeout(() => {
socketeer()
}, 30000);
})
function ping(dur) {
lanyard.send(JSON.stringify({
op: 3
}))
setTimeout(() => {
ping(dur)
if (Date.now() - lastPong > 120000) {
lanyard.close()
console.log("Max duration since last pong exceeded- Closing socket.")
}
}, dur);
}
lanyard.addEventListener("message", async (res) => {
var data = JSON.parse(res.data)
// console.log(data.op)
if (data.op == 1) {
console.log("Connected to Discord Websocket!")
module.exports.connected = true
ping(30000)
lastPong = Date.now()
events.emit("lanyardConnect")
} else if (data.op == 3) {
lastPong = Date.now()
} else if (data.op == 0) {
module.exports.lanyard = data.d
module.exports.lastLanyardUpdate = Date.now()
events.emit("lanyardUpdate")
} else if (data.op == 4) {
module.exports.spins = data.spins
}
})
}
socketeer()

View file

@ -18,16 +18,26 @@
} }
}, },
"quotes": [ "quotes": [
"World's Worst Developer",
"The worst git user to exist",
"These birds are Pissing me off... I'm the original        Starwalker", "These birds are Pissing me off... I'm the original        Starwalker",
"The developer the city did not want nor need",
"Make sure to check out <a href='https://univerter.dev'>Univerter!</a>", "Congratulations Nick, Enjoy your Dota.",
"Check out <a href='https://asahixp.pages.gay'>Asahi's website! &lt;3</a>", "Can we go back to Skype already",
"Check out <a href='https://sylvie.loveh.art/'>Sylvie's website! &lt;3</a>" "I keep forgetting I have a Matrix",
"Pregeneration! Page Pregeneration! It's here! Yippee!!!",
"Can you even call this highlighting anymore it does like 300 other things now",
"If you dont convert your HTML to JSON and then back to HTML did you even really make a Server-Side renderer???",
"I finally know what SSR means. Yeah that. I made one of those (I think).",
"The optimization update coming out in January 2068!",
"Now with... <em>bleh...</em> JQuery...",
"Louis do NOT make a server side renderer. Worst mistake of my life.",
"Univerter Supremacy",
"Violet's Limbo update soon... I swear...",
"Univerter update: Coming. someday. some year. :)",
"I love this font, but emoticons have never looked worse... :( </3",
"<a href='https://youtu.be/O3AlP6FtPw4?t=3'>IT'S 2015!!!</a> /ref",
"<a href='https://youtu.be/O3AlP6FtPw4?t=620'>I'm throwin SNOWBALLS atcha...</a> /ref"
], ],
"titles": [ "titles": [
"Boykisser",
"World's Worst Developer" "World's Worst Developer"
], ],
"thumborInstances": [ "thumborInstances": [
@ -36,6 +46,84 @@
"https://unusual-back-production.up.railway.app/", "https://unusual-back-production.up.railway.app/",
"https://axiomatic-hair-production.up.railway.app/" "https://axiomatic-hair-production.up.railway.app/"
], ],
"fallbackLanyard": {
"kv": {},
"spotify": null,
"discord_user": {
"id": "534132311781015564",
"username": "bingus_violet",
"avatar": "f3fe0d6a1dd2fe301f437e02333e602d",
"discriminator": "0",
"bot": false,
"clan": null,
"global_name": "Violet",
"avatar_decoration_data": null,
"display_name": "Violet",
"public_flags": 0
},
"activities": [],
"discord_status": "offline",
"active_on_discord_web": false,
"active_on_discord_desktop": false,
"active_on_discord_mobile": false,
"listening_to_spotify": false,
"socials": {
"Social Media": {
"Fedi": {
"name": "bingus_violet@floofy.city",
"url": "https://floofy.city/@bingus_violet"
},
"Youtube": {
"name": "Violet's Fiasco",
"url": "https://www.youtube.com/channel/UChcrBJNJLZucy3TPyGyAY2g"
},
"Liberapay": {
"name": "bingus_violet",
"url": "https://en.liberapay.com/bingus_violet/"
}
},
"Messaging": {
"Matrix": {
"name": "@bingus_violet:matrix.violets-purgatory.dev",
"url": "https://matrix.to/#/@bingus_violet:matrix.violets-purgatory.dev"
},
"Discord": {
"name": "bingus_violet"
},
"Revolt": {
"name": "BingusViolet#5573"
}
},
"Coding": {
"Forgejo": {
"name": "bingus_violet@git.violets-purgatory.dev",
"url": "https://git.violets-purgatory.dev/bingus_violet/"
},
"Codeberg": {
"name": "bingus_violet",
"url": "https://codeberg.org/Bingus_violet"
},
"Docker": {
"name": "bingusviolet",
"url": "https://hub.docker.com/u/bingusviolet"
},
"Github": {
"name": "violets-puragtory",
"url": "https://github.com/violets-puragtory"
}
},
"Games": {
"Steam": {
"name": "Violet",
"url": "https://steamcommunity.com/id/violet-The-Thigh-high-obtainer/"
},
"Roblox": {
"name": "@bingus_violet",
"url": "https://www.roblox.com/users/28347789/profile"
}
}
}
},
"highlightedWords": { "highlightedWords": {
"birds": { "birds": {
"color": "yellow" "color": "yellow"
@ -55,6 +143,12 @@
"Javascript": { "Javascript": {
"color": "yellow" "color": "yellow"
}, },
"JSON": {
"color": "yellow"
},
"JQuery": {
"color": "yellow"
},
"NodeJS": { "NodeJS": {
"color": "limegreen" "color": "limegreen"
}, },
@ -64,6 +158,9 @@
"Purgatory": { "Purgatory": {
"color": "rgb(200, 150, 255)" "color": "rgb(200, 150, 255)"
}, },
"Limbo": {
"color": "rgb(200, 150, 255)"
},
"Asahi": { "Asahi": {
"color": "rgb(255, 175, 175)", "color": "rgb(255, 175, 175)",
"caseInsensitive": true "caseInsensitive": true
@ -108,6 +205,7 @@
"color": "lightgray" "color": "lightgray"
}, },
"Univerter": { "Univerter": {
"link": "https://univerter.dev/",
"color": "rgb(200, 175, 255)" "color": "rgb(200, 175, 255)"
}, },
"Ko-fi": { "Ko-fi": {
@ -122,11 +220,9 @@
"SearXNG": { "SearXNG": {
"color": "rgb(100, 100, 255)" "color": "rgb(100, 100, 255)"
}, },
"Highlighting": { "highlight": {
"color": "yellow" "color": "yellow",
}, "caseInsensitive": true
"highlighted": {
"color": "yellow"
}, },
"Forgejo": { "Forgejo": {
"color": "orange" "color": "orange"
@ -177,6 +273,15 @@
"bold": true, "bold": true,
"italicized": true, "italicized": true,
"caseInsensitive": true "caseInsensitive": true
},
"Pokerogue": {
"caseInsensitive": true,
"color": "#366383",
"outline": "#d43131",
"bold": true
},
"page embed": {
"link": "/faq#embeds"
} }
} }
} }

View file

@ -1,7 +1,6 @@
const express = require('express'), const express = require('express'),
path = require('path'), path = require('path'),
fs = require('fs'), fs = require('fs'),
pageUpdater = require('./pageUpdater.js'),
WebSocket = require("ws") WebSocket = require("ws")
var app = express() var app = express()
@ -28,6 +27,8 @@ if (!fs.existsSync(announcementFile)) {
fs.writeFileSync(announcementFile, ``) fs.writeFileSync(announcementFile, ``)
} }
const pageUpdater = require('./pageUpdater.js')
var constants = JSON.parse(fs.readFileSync(path.join(__dirname, 'constants.json'))) var constants = JSON.parse(fs.readFileSync(path.join(__dirname, 'constants.json')))
app.listen(PORT, () => { app.listen(PORT, () => {

View file

@ -1,13 +1,13 @@
const path = require('path'), const path = require('path'),
fs = require('fs'), fs = require('fs'),
WebSocket = require('ws'),
minify = require('@node-minify/core'), minify = require('@node-minify/core'),
uglifyJs = require("@node-minify/uglify-js"), uglifyJs = require("@node-minify/uglify-js"),
htmlMinifier = require("minify-html"), htmlMinifier = require("minify-html"),
activityToHTML = require("./overcomplicatedStatuses.js"), activityToHTML = require("./overcomplicatedStatuses.js"),
randomThemer = require("./randomThemer.js"), randomThemer = require("./randomThemer.js"),
himalaya = require("himalaya"), himalaya = require("himalaya"),
glob = require("glob") glob = require("glob"),
api = require("./api.js")
var constants = JSON.parse(fs.readFileSync(path.join(__dirname, 'constants.json'))) var constants = JSON.parse(fs.readFileSync(path.join(__dirname, 'constants.json')))
@ -17,14 +17,15 @@ var titles = constants.titles
var globalSpins = 0 var globalSpins = 0
var commitCount = "500+" var commitCount = "600+"
var lanyardData = undefined
var uptime = Date.now() var uptime = Date.now()
var lastPregen = 0
var pregenFiles = [] var pregenFiles = []
var javascriptCache = {}
var globResult = glob.globSync("**/static/**/*.html", { absolute: true }) var globResult = glob.globSync("**/static/**/*.html", { absolute: true })
for (var i = 0; i < globResult.length; i++) { for (var i = 0; i < globResult.length; i++) {
var result = globResult[i] var result = globResult[i]
@ -35,10 +36,24 @@ for (var i = 0; i < globResult.length; i++) {
}) })
} }
(async function() {
globResult = glob.globSync("**/static/**/*.js", { absolute: true })
for (var i = 0; i < globResult.length; i++) {
javascriptCache[globResult[i]] = await minify({
compressor: uglifyJs,
content: fs.readFileSync(globResult[i]).toString()
})
}
})()
function firstToUpper(str) { function firstToUpper(str) {
return str.charAt(0).toUpperCase() + str.slice(1) return str.charAt(0).toUpperCase() + str.slice(1)
} }
function makeHtmlSafe(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
function timeFormatter(seconds) { function timeFormatter(seconds) {
seconds = Math.ceil(seconds) seconds = Math.ceil(seconds)
var minutes = Math.ceil(seconds / 60) var minutes = Math.ceil(seconds / 60)
@ -112,6 +127,7 @@ function highlighter(json, full = true) {
var style = termProps.style || "" var style = termProps.style || ""
var classes = termProps.classes || "" var classes = termProps.classes || ""
var link = termProps.link || ""
if (termProps.color) { if (termProps.color) {
style += `color: ${termProps.color};` style += `color: ${termProps.color};`
@ -121,6 +137,13 @@ function highlighter(json, full = true) {
style += "font-style: italic;" style += "font-style: italic;"
} }
if (termProps.outline) {
var width = 2
// style += `text-shadow: -1px -1px 0 ${termProps.outline}, 1px -1px 0 ${termProps.outline}, -1px 1px 0 ${termProps.outline}, 1px 1px 0 ${termProps.outline};`
style += `-webkit-text-stroke: 1px ${termProps.outline};`
// ^ Not in use because it looks bad :30
}
if (termProps.bold) { if (termProps.bold) {
classes += "bold" classes += "bold"
} }
@ -133,7 +156,11 @@ function highlighter(json, full = true) {
classes = `class="${classes}"` classes = `class="${classes}"`
} }
var replacement = `<span ${style} ${classes}>${startContent + highTable[index] + endContent}</span>` var replacement = `<span ${style} ${classes} ${link}>${startContent + highTable[index] + endContent}</span>`
if (link) {
replacement = `<a href="${link}">${replacement}</a>`
}
element.content = element.content.substring(0, spanStart) + replacement + element.content.substring(spanEnd) element.content = element.content.substring(0, spanStart) + replacement + element.content.substring(spanEnd)
} }
@ -168,17 +195,20 @@ function converter(html, dynamic = true) {
"COMMIT_COUNT": commitCount, "COMMIT_COUNT": commitCount,
"QUOTE_COUNT": quotes.length, "QUOTE_COUNT": quotes.length,
"DISCORD_STATUS": () => { "DISCORD_STATUS": () => {
if (lanyardData) { return `<span style="color: ${constants.discStatuses[api.lanyard.discord_status].color};" class="statusColor">${constants.discStatuses[api.lanyard.discord_status].text}</span>` +
return `<span style="color: ${constants.discStatuses[lanyardData.discord_status].color};" class="statusColor">${constants.discStatuses[lanyardData.discord_status].text}</span>` + `<style>.pfp { border-color: ${constants.discStatuses[api.lanyard.discord_status].color} }</style>`;
`<style>.pfp { border-color: ${constants.discStatuses[lanyardData.discord_status].color} }</style>`;
}
return ""; return "";
}, },
"TOPBAR": `<div id="topbar"><h3><a href="/socials">Socials</a></h3></div>`, "TOPBAR": `<div id="topbar">
<h3><a class="chip" href="/">Home</a>
<a class="chip" href="/socials">Socials</a>
<a class="chip" href="/stats">Stats</a>
<a class="chip" href="/faq">Nerd FAQ</a></h3>
</div>`,
"CUSTOM_STATUS": () => { "CUSTOM_STATUS": () => {
if (lanyardData && lanyardData.activities[0] && lanyardData.activities[0].type == 4) { if (api.lanyard.activities[0] && api.lanyard.activities[0].type == 4) {
var status = lanyardData.activities[0] var status = api.lanyard.activities[0]
var addedHTML = "<hr/><p>" var addedHTML = "<hr/><p>"
if (status.emoji) { if (status.emoji) {
if (status.emoji.id) { if (status.emoji.id) {
@ -187,7 +217,8 @@ function converter(html, dynamic = true) {
addedHTML += status.emoji.name + " " addedHTML += status.emoji.name + " "
} }
} }
addedHTML += status.state
addedHTML += makeHtmlSafe(status.state)
addedHTML += "</p>" addedHTML += "</p>"
return addedHTML return addedHTML
} }
@ -205,8 +236,8 @@ function converter(html, dynamic = true) {
"WEATHER_TEXT": "", "WEATHER_TEXT": "",
"ANNOUNCEMENT": fs.readFileSync(path.join(__dirname, "config/announcement.html")), "ANNOUNCEMENT": fs.readFileSync(path.join(__dirname, "config/announcement.html")),
"SOCIALS": () => { "SOCIALS": () => {
if (lanyardData && lanyardData.socials) { if (api.lanyard.socials) {
var socials = lanyardData.socials var socials = api.lanyard.socials
var html = "" var html = ""
var socialsTable = Object.keys(socials) var socialsTable = Object.keys(socials)
for (var i = 0; i < socialsTable.length; i++) { for (var i = 0; i < socialsTable.length; i++) {
@ -218,7 +249,7 @@ function converter(html, dynamic = true) {
var siteName = sitesTable[x] var siteName = sitesTable[x]
var siteData = sites[siteName] var siteData = sites[siteName]
if (siteData.url) { if (siteData.url) {
html += `<a class="chip" href="${siteData.url}">${siteName}: ${siteData.name}</a>` html += `<a class="chip" href="${siteData.url}">${siteName}: ${siteData.name.replaceAll("Violet", "{Violet}")}</a>`
} }
} }
html += "</div></div>" html += "</div></div>"
@ -229,12 +260,14 @@ function converter(html, dynamic = true) {
} }
var realtimeReplacers = { var realtimeReplacers = {
"ACTIVITIES": activityToHTML.activitiesToHTML(lanyardData), "API_CONNECTED": api.connected.toString(),
"ACTIVITIES": activityToHTML.activitiesToHTML(api.lanyard),
"SPINCOUNT": globalSpins, "SPINCOUNT": globalSpins,
"UPTIME": timeFormatter((Date.now() - uptime) / 1000), "UPTIME": timeFormatter((Date.now() - uptime) / 1000),
"LAST_LANYARD": timeFormatter((Date.now() - lastLanyardUpdate) / 1000), "LAST_LANYARD": timeFormatter((Date.now() - api.lastLanyardUpdate) / 1000),
"RANDOM_TITLE": titles[Math.floor(Math.random() * titles.length)], "RANDOM_TITLE": titles[Math.floor(Math.random() * titles.length)],
"RANDOM_QUOTE": quotes[Math.floor(Math.random() * quotes.length)], "RANDOM_QUOTE": quotes[Math.floor(Math.random() * quotes.length)],
"LAST_PREGEN": timeFormatter((Date.now() - lastPregen) / 1000)
} }
if (dynamic) { if (dynamic) {
@ -283,7 +316,7 @@ function converter(html, dynamic = true) {
module.exports = { module.exports = {
getActivities: function () { getActivities: function () {
return htmlMinifier.minify(converter(activityToHTML.activitiesToHTML(lanyardData))) return htmlMinifier.minify(converter(activityToHTML.activitiesToHTML(api.lanyard)))
}, },
middleWare: async function (req, res, next) { middleWare: async function (req, res, next) {
@ -318,10 +351,7 @@ module.exports = {
if (!filePath.includes(".js")) { if (!filePath.includes(".js")) {
data = htmlMinifier.minify(data) data = htmlMinifier.minify(data)
} else { } else {
data = await minify({ data = javascriptCache[filePath]
compressor: uglifyJs,
content: data
})
} }
res.send(data) res.send(data)
@ -355,10 +385,9 @@ updateCommits()
// Lanyard Stuffs // Lanyard Stuffs
var lastLanyardUpdate = Date.now()
var lastPong = 0
function pregenerate() { function pregenerate() {
lastPregen = Date.now()
for (var i = 0; i < pregenFiles.length; i++) { for (var i = 0; i < pregenFiles.length; i++) {
var startTime = Date.now() var startTime = Date.now()
pregenFiles[i].html = converter(fs.readFileSync(pregenFiles[i].absolutePath).toString(), false) pregenFiles[i].html = converter(fs.readFileSync(pregenFiles[i].absolutePath).toString(), false)
@ -368,49 +397,15 @@ function pregenerate() {
pregenerate() pregenerate()
function socketeer() { api.events.on("lanyardConnect", pregenerate)
var lanyard = new WebSocket('https://api.violets-purgatory.dev')
lanyard.on("error", (error) => {
console.log(error)
})
lanyard.on("close", () => {
console.log("Connection Closed. Attempting Reconnect in 30 seconds.")
setTimeout(() => {
socketeer()
}, 30000);
})
function ping(dur) {
lanyard.send(JSON.stringify({
op: 3
}))
setTimeout(() => {
ping(dur)
if (Date.now() - lastPong > 120000) {
lanyard.close()
console.log("Max duration since last pong exceeded- Closing socket.")
}
}, dur);
}
lanyard.addEventListener("message", async (res) => {
var data = JSON.parse(res.data)
// console.log(data.op)
if (data.op == 1) {
console.log("Connected to Discord Websocket!")
ping(30000)
lastPong = Date.now()
} else if (data.op == 3) {
lastPong = Date.now()
} else if (data.op == 0) {
lanyardData = data.d
lastLanyardUpdate = Date.now()
api.events.on("lanyardUpdate", async () => {
if (!api.lanyard.activityChanged) {
pregenerate() pregenerate()
for (var i = 0; i < lanyardData.activities.length; i++) { }
var activity = lanyardData.activities[i]
for (var i = 0; i < api.lanyard.activities.length; i++) {
var activity = api.lanyard.activities[i]
if (activity.type == 4 && activity.emoji) { if (activity.type == 4 && activity.emoji) {
if (activity.emoji.id) { if (activity.emoji.id) {
@ -423,10 +418,4 @@ function socketeer() {
} }
} }
} }
} else if (data.op == 4) {
globalSpins = data.spins
}
}) })
}
socketeer()

View file

@ -1,8 +1,8 @@
function rain() { function rain() {
var html = "" var html = ""
html += `<link rel="stylesheet" type="text/css" href="/themes/rain/style.css"> <script src="/themes/rain/script.js"></script>`
html += `<div class="rainStuff"><div class="rainContainer">` html += `<div class="rainStuff"><div class="rainContainer">`
html += `<link rel="stylesheet" type="text/css" href="/themes/rain.css">`
var amount = 7 var amount = 7
@ -13,39 +13,40 @@ function rain() {
for (let index = 0; index < amount; index++) { for (let index = 0; index < amount; index++) {
html += ` html += `
.rainDrop:nth-of-type(${index + 1}) { .rainDrop:nth-of-type(${index + 1}) {
animation: rainAnim${index} ${(Math.random() * 0.3) + (2)}s linear; animation: rainAnim${index} ${((Math.round(Math.random() * 10) / 10) * 0.3) + 0.6}s linear;
animation-delay: ${Math.round(Math.random() * 200) / 100}s;
animation-iteration-count: infinite; animation-iteration-count: infinite;
animation-delay: ${Math.round(Math.random() * 100) / 100}s; animation-timing-function: cubic-bezier(0.47, 0, 0.745, 0.715);
} }
` `
var randos = []
for (let index = 0; index < 11; index++) { var pos = 0
randos.push(Math.round(Math.random() * 100))
if (index % 2 == 0) {
pos = Math.random() * 30
} else {
pos = (Math.random() * 30) + 70
} }
pos = Math.round(pos)
html += `@keyframes rainAnim${index} { ` html += `@keyframes rainAnim${index} { `
for (let index = 0; index < 5; index++) {
html += ` html += `
${index * 3}0% { 0% {
top: 110vh; top: -20vh;
right: ${randos[index]}%; right: ${pos}%;
visibility: hidden;
}
${index * 3}0.1% {
top: -10vh;
right: ${randos[index + 1]}%;
visibility: hidden;
}
${index * 3}0.2% {
visibility: visible; visibility: visible;
} }
`
}
// console.log(html)
html += `90.3% { visibility: hidden; }` 90% {
top: 110vh;
right: ${pos}%;
visibility: visible;
}
90.1% {
visibility: hidden;
}
`
html += `}` html += `}`
@ -56,20 +57,77 @@ function rain() {
return html return html
} }
function night() { function purpleMagic() {
var html = ""
html += `<link rel="stylesheet" type="text/css" href="/themes/magic/style.css"> <script src="/themes/magic/script.js"></script>`
html += `<div class="magicStuff"><div class="magicContainer">`
var amount = 15
for (let index = 0; index < amount; index++) {
html += `<div class="particle"></div>`
}
html += "<style>"
for (let index = 0; index < amount; index++) {
html += `
.particle:nth-of-type(${index + 1}) {
animation: magic${index} ${((Math.round(Math.random() * 10) / 10) * 0.3) + 20}s linear, sway 4s cubic-bezier(0.445, 0.05, 0.55, 0.95) alternate;
animation-delay: ${Math.round(Math.random() * 100) / 100 * 20}s;
animation-iteration-count: infinite;
}
`
if (index % 2 == 0) {
html.replace("alternate", "alternate-reverse")
}
var pos = Math.round(Math.random() * 100)
html += `@keyframes magic${index} { `
html += `
0% {
top: 110vh;
right: ${pos}%;
visibility: visible;
}
90% {
top: -10vh;
right: ${pos}%;
visibility: visible;
}
90.1% {
visibility: hidden;
}
`
html += `}`
}
html += "</style>"
html += "</div></div>"
return html
}
function code() {
return '<link rel="stylesheet" type="text/css" href="/themes/code/style.css"> <script src="/themes/code/script.js"></script>'
} }
var events = [ var events = [
code(),
purpleMagic(),
rain(), rain(),
"", "",
] ]
module.exports = { module.exports = {
returnTheme: function() { returnTheme: function() {
var time = new Date() var time = new Date()
return events[time.getUTCDay() % events.length] return events[time.getDate() % events.length]
}, },
} }

View file

@ -8,6 +8,9 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="../jquery.js"></script>
<script src="../main.js"></script>
<title>Violet's Purgatory</title> <title>Violet's Purgatory</title>
<meta name="darkreader-lock"> <meta name="darkreader-lock">
@ -22,6 +25,7 @@
<body> <body>
{WEATHER_MODIFIER} {WEATHER_MODIFIER}
{TOPBAR}
<h1 class="animatedTitle">Welcome to my<span class="mainTitle" style="color: rgb(200, 150, 255)">Humble Abode</span> <h1 class="animatedTitle">Welcome to my<span class="mainTitle" style="color: rgb(200, 150, 255)">Humble Abode</span>
</h1> </h1>
<main class="animatedMain"> <main class="animatedMain">

View file

@ -5,6 +5,9 @@
<link rel="stylesheet" type="text/css" href="/style.css"> <link rel="stylesheet" type="text/css" href="/style.css">
<link rel="stylesheet" type="text/css" href="/subpage.css"> <link rel="stylesheet" type="text/css" href="/subpage.css">
<script src="../jquery.js"></script>
<script src="../main.js"></script>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@ -21,9 +24,7 @@
<body> <body>
{WEATHER_MODIFIER} {WEATHER_MODIFIER}
<a href="../" class="chip">Home</a> {TOPBAR}
<a href="../socials" class="chip">Socials</a>
<a href="../stats" class="chip">Stats</a>
<h1>FAQ (and more!)</h1> <h1>FAQ (and more!)</h1>
<div class="mainDiv"> <div class="mainDiv">
<h2><br>1. Questions & Answers<hr></h2> <h2><br>1. Questions & Answers<hr></h2>
@ -31,9 +32,10 @@
<h3>Why are so many words colored?</h3> <h3>Why are so many words colored?</h3>
<p>I like the way it looks to have certain words be highlighted, makes it look fancier and easier to read (imo). So, when I remade this site, I went ahead and added an <em>Automatic Word Highlighting System!</em> This allows me have words automatically highlighted, on the server side, without having to do it in the code manually. Here's the current list of highlighted words:</p> <p>I like the way it looks to have certain words be highlighted, makes it look fancier and easier to read (imo). So, when I remade this site, I went ahead and added an <em>Automatic Word Highlighting System!</em> This allows me have words automatically highlighted, on the server side, without having to do it in the code manually. Here's the current list of highlighted words:</p>
<p class="textBlock">{ALL_HIGHLIGHTS}</p> <p class="textBlock">{ALL_HIGHLIGHTS}</p>
<p>As time continues, more words are added to the highlighting list, and I'm slowly adding more features, like disabling case sensitivity, boldness, italics, outlines, and more.</p>
<br> <br>
<h3>I thought the site doesn't use Javascript? So why is it there?</h3> <h3>I thought the site doesn't use Javascript? So why is it there?</h3>
<p>Originally, all my sites were completely Javascript free. As of late, though, I decided to add Javascript to this one. Javascript will <b><em>NEVER</em></b> be a requirement on this site. Javascript will ONLY be used where nessacary, and I will do everything possible to make the experience indistinguishable.</p> <p>Originally, all my sites were completely Javascript free. As of late, though, I decided to add Javascript to this one. Javascript will <b><em>NEVER</em></b> be a requirement on this site. Javascript will ONLY be used where necessary, and I will do everything possible to make the experience indistinguishable.</p>
</main> </main>
<p>For example, things such as the song duration bar on my activities are pure HTML, using some mathy NodeJS-generated CSS animations! The only thing the site uses Javascript for right now, is setting the scroll to the top of the page on reload, and real time updating discord activities.</p> <p>For example, things such as the song duration bar on my activities are pure HTML, using some mathy NodeJS-generated CSS animations! The only thing the site uses Javascript for right now, is setting the scroll to the top of the page on reload, and real time updating discord activities.</p>
<h3>Why are there 4 CSS files?</h3> <h3>Why are there 4 CSS files?</h3>
@ -45,6 +47,10 @@
</ol> </ol>
<p>Slowly, though, they're slowly all merging into one CSS file, so I can't be sure it'll stay this way for long.</p> <p>Slowly, though, they're slowly all merging into one CSS file, so I can't be sure it'll stay this way for long.</p>
<p>As for the "unused" style.css, though, that exists for compatibility reasons- many of my older sites just grabbed CSS from the site for their css. This has been <b>mostly</b> fixed, but the FileShare still does, so it'll stay until I finally give the FileShare its own CSS.</p> <p>As for the "unused" style.css, though, that exists for compatibility reasons- many of my older sites just grabbed CSS from the site for their css. This has been <b>mostly</b> fixed, but the FileShare still does, so it'll stay until I finally give the FileShare its own CSS.</p>
<h3 id="embeds">Why/How are certain segments of pages "embedded" on others?</h3>
<p>On the main page, you may notice certain other pages contained inside it, such as this page, the stats page, and socials page. And, most notably with this page, it's not the full page, either. <br>
This is because of a feature I created called "page embeds", which allow me to embed a portion of content from another page, without the use of any sort of iframes. This was made so I could keep information on multiple pages up to date.<br>
It's much more performant and scalable than an I-frame as well.</p>
</div> </div>
</body> </body>

View file

@ -8,6 +8,7 @@
<link rel="stylesheet" href="./noScript.css"> <link rel="stylesheet" href="./noScript.css">
</noscript> </noscript>
<script src="./jquery.js"></script>
<script src="./main.js"></script> <script src="./main.js"></script>
<meta charset="UTF-8"> <meta charset="UTF-8">
@ -45,19 +46,19 @@
</div> </div>
</div> </div>
</div> </div>
<p class="noscript">Violet has been spun {SPINCOUNT} times!</p> <!-- <p class="noscript">Violet has been spun {SPINCOUNT} times!</p> -->
<p class="spinnyCount" style="display: none;">You have spun Violet <span class="localSpins">4</span> times!<br> <p class="spinnyCount" style="display: none;">You have spun Violet <span class="localSpins">4</span> times!<br>
Everyone has spun Violet <span class="globalSpins">{SPINCOUNT}</span> times!</p> Everyone has spun Violet <span class="globalSpins">{SPINCOUNT}</span> times!</p>
<hr> <hr>
<div> <div>
<p style="padding: 10px;">Hi! I'm Violet, a 15 year old web and game developer. I make server-sided dynamic websites, with no Javascript required! I'm currently making games in the Godot Engine, and my dynamic sites in NodeJS.</p> <p style="padding: 10px;">Hi! I'm Violet, a 15 year old web and game developer. I make server-sided dynamic websites, with majority of rendering being done on the server, no Javascript needed! I'm currently making games in the Godot Engine, and my dynamic sites in NodeJS.</p>
<div class="linkContainer"> <div class="linkContainer">
<a class="chip" href="./socials/">Socials</a> <a class="chip" href="./socials/">Socials</a>
<a class="chip" href="https://blog.violets-purgatory.dev">Blog</a> <a class="chip" href="./stats">Stats</a>
<!-- <a class="chip" href="./stats">Stats</a> -->
<a class="chip" href="./faq">Nerd FAQ</a> <a class="chip" href="./faq">Nerd FAQ</a>
<a class="chip" href="https://{BRANCH_SUB}violets-purgatory.dev">{BRANCH_NAME} site</a> <a class="chip" href="https://{BRANCH_SUB}violets-purgatory.dev">{BRANCH_NAME} site</a>
<a class="chip" href="https://blog.violets-purgatory.dev">Blog</a>
<a class="chip" href="https://fs.violets-purgatory.dev">FileShare</a> <a class="chip" href="https://fs.violets-purgatory.dev">FileShare</a>
</div> </div>
<div class="customStatus"> <div class="customStatus">

10716
static/jquery.js vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -39,6 +39,7 @@ if (teto) {
} }
music.loop = true music.loop = true
music.preservesPitch = false
var sock var sock
@ -65,32 +66,39 @@ function spinLoop() {
setTimeout(() => { setTimeout(() => {
spinWaiting = false spinWaiting = false
if (spinning) { if (spinning) {
music.volume = 0.5 // music.volume = 0.5
if (music.currentTime > 6.5 && teto) { if (music.currentTime > 6.5 && teto) {
spinFactor = 0.25 spinFactor = 0.25
} else { } else {
spinFactor = 3 spinFactor = 3
} }
// music.playbackRate = lerp(music.playbackRate, 1, 1/spinSpeed) if (!teto) {
if (spins > 1) { music.playbackRate = lerp(music.playbackRate, 1, 1/spinSpeed)
document.querySelector(".spinnyCount").style.display = "block" music.volume = lerp(music.volume, 0.5, 1/spinSpeed)
document.querySelector(".localSpins").innerHTML = Math.ceil(spins - 1);
} }
spins += 1/spinSpeed / spinFactor spins += 1/spinSpeed / spinFactor
if (Math.floor(spins) != lastSent && sock && sock.OPEN) { if (Math.floor(spins) != lastSent && sock && sock.OPEN) {
document.querySelector(".globalSpins").innerHTML = globalSpins + 1 $(".globalSpins").innerHTML = globalSpins + 1
lastSent = Math.floor(spins) lastSent = Math.floor(spins)
// resetPFP() // resetPFP()
sock.send(`{"op": 4}`) sock.send(`{"op": 4}`)
console.log("Spin Sent!") if (spins > 1) {
$(".spinnyCount").css("display", "block")
$(".localSpins").html(lastSent);
}
} }
} else { } else {
// music.playbackRate = lerp(music.playbackRate, 0.5, 1/spinSpeed) if (!teto) {
music.playbackRate = lerp(music.playbackRate, 0.5, 1/spinSpeed)
music.volume = lerp(music.volume, -0, 3/spinSpeed)
} else {
music.pause() music.pause()
music.currentTime = 1.5 music.currentTime = 1.5
}
spins = lerp(spins, Math.round(spins), 1 / spinSpeed * 3) spins = lerp(spins, Math.round(spins), 1 / spinSpeed * 3)
} }
document.querySelector(".pfp").style.rotate = (spins * 360) + "deg" $(".pfp").css("rotate", (spins * 360) + "deg")
spinLoop() spinLoop()
}, 1/spinSpeed * 1000); }, 1/spinSpeed * 1000);
} }
@ -100,13 +108,13 @@ window.onbeforeunload = function () {
} }
window.onload = function () { window.onload = function () {
window.scrollTo(0, 0); $("#jsEnabled").text("true")
pfp = document.querySelector(".pfp") pfp = $(".pfp")
spinLoop() spinLoop()
pfp.addEventListener("mousedown", () => { pfp.on("mousedown", () => {
// if (!spinWaiting) { // if (!spinWaiting) {
// spinLoop(); // spinLoop();
// } // }
@ -114,9 +122,9 @@ window.onload = function () {
spinning = true spinning = true
pfp.style.transition = "" pfp.css("transition", "")
pfp.style.scale = "1.1" pfp.css("scale", "1.1")
}) })
document.body.onmouseup = () => { document.body.onmouseup = () => {
@ -131,7 +139,7 @@ window.onload = function () {
// pfp.style.transition = "all 3s cubic-bezier(0.39, 0.575, 0.565, 1)" // pfp.style.transition = "all 3s cubic-bezier(0.39, 0.575, 0.565, 1)"
pfp.style.scale = "1" pfp.css("scale", "1")
} }
} }
socketeer() socketeer()
@ -165,6 +173,7 @@ function socketeer() {
sock.addEventListener("close", () => { sock.addEventListener("close", () => {
console.log("Connection Closed. Attempting Reconnect in 30 seconds.") console.log("Connection Closed. Attempting Reconnect in 30 seconds.")
$("#apiConnected").text("false")
setTimeout(() => { setTimeout(() => {
socketeer() socketeer()
}, 30000); }, 30000);
@ -174,23 +183,24 @@ function socketeer() {
data = data.data data = data.data
data = JSON.parse(data) data = JSON.parse(data)
if (data.op == 4) { if (data.op == 4) {
$("#apiConnected").text("true")
globalSpins = data.spins globalSpins = data.spins
if (firsttimeDebounce == true) { if (firsttimeDebounce == true) {
firsttimeDebounce = false firsttimeDebounce = false
document.querySelector(".globalSpins").innerHTML = globalSpins + 1; $(".globalSpins").innerHTML = globalSpins + 1;
} else { } else {
document.querySelector(".globalSpins").innerHTML = globalSpins; $(".globalSpins").innerHTML = globalSpins;
} }
} else if (data.op == 0) { } else if (data.op == 0) {
var lanyard = data.d var lanyard = data.d
var statusInfo = discStatuses[lanyard.discord_status] var statusInfo = discStatuses[lanyard.discord_status]
var lastStatus = document.querySelector(".statusColor") var lastStatus = $(".statusColor")
if (lastStatus.innerHTML != statusInfo.text) { if (lastStatus.innerHTML != statusInfo.text) {
lastStatus.innerHTML = statusInfo.text lastStatus.innerHTML = statusInfo.text
lastStatus.style.color = statusInfo.color lastStatus.css("color", statusInfo.color)
pfp.style.borderColor = lastStatus.style.color pfp.css("borderColor", statusInfo.color)
resetPFP() resetPFP()
} }
@ -202,7 +212,7 @@ function socketeer() {
// } // }
var discFetch = await (await fetch("/discHTML")).text() var discFetch = await (await fetch("/discHTML")).text()
document.querySelector("#activityHtml").innerHTML = discFetch $("#activityHtml").html(discFetch)
} else if (data.op == 3) { } else if (data.op == 3) {
lastPong = Date.now() lastPong = Date.now()
} else { } else {

View file

@ -21,7 +21,7 @@
position: relative; position: relative;
border-radius: 12px; border-radius: 12px;
box-shadow: outset rgb(35, 20, 60) 0px 0px 20px; box-shadow: 0px 5px 50px 0px rgba(0, 0, 0, .25);
} }
.linkContainer { .linkContainer {

View file

@ -4,6 +4,8 @@
<head> <head>
<link rel="stylesheet" type="text/css" href="../style.css"> <link rel="stylesheet" type="text/css" href="../style.css">
<link rel="stylesheet" type="text/css" href="../subpage.css"> <link rel="stylesheet" type="text/css" href="../subpage.css">
<script src="../jquery.js"></script>
<script src="../main.js"></script> <script src="../main.js"></script>
<meta charset="UTF-8"> <meta charset="UTF-8">
@ -22,9 +24,10 @@
<body> <body>
{WEATHER_MODIFIER} {WEATHER_MODIFIER}
<a href="../" class="chip">Home</a> {TOPBAR}
<!-- <a href="../" class="chip">Home</a>
<a href="../faq" class="chip">FAQ</a> <a href="../faq" class="chip">FAQ</a>
<a href="../stats" class="chip">Stats</a> <a href="../stats" class="chip">Stats</a> -->
<h1>Socials</h1> <h1>Socials</h1>
<div class="mainDiv"> <div class="mainDiv">
<hr> <hr>

View file

@ -4,6 +4,8 @@
<head> <head>
<link rel="stylesheet" type="text/css" href="../style.css"> <link rel="stylesheet" type="text/css" href="../style.css">
<link rel="stylesheet" type="text/css" href="../subpage.css"> <link rel="stylesheet" type="text/css" href="../subpage.css">
<script src="../jquery.js"></script>
<script src="../main.js"></script> <script src="../main.js"></script>
<meta charset="UTF-8"> <meta charset="UTF-8">
@ -14,33 +16,54 @@
<meta name="darkreader-lock"> <meta name="darkreader-lock">
<meta content="Stats - Violet's Purgatory" property="og:title" /> <meta content="Stats - Violet's Purgatory" property="og:title" />
<meta content="This page just does a semi-intensive speed test on the site, and displays related statistics." property="og:description" /> <meta content="This page just does a semi-intensive speed test on the site, and displays related statistics."
property="og:description" />
<meta content="https://api.violets-purgatory.dev/v1/pfp" property="og:image" /> <meta content="https://api.violets-purgatory.dev/v1/pfp" property="og:image" />
<meta content="#a200ff" data-react-helmet="true" name="theme-color" /> <meta content="#a200ff" data-react-helmet="true" name="theme-color" />
</head> </head>
<body> <body>
{WEATHER_MODIFIER} {WEATHER_MODIFIER}
<a href="../" class="chip">Home</a>
<a href="../socials" class="chip">Socials</a> {TOPBAR}
<a href="../faq" class="chip">FAQ</a>
<h1>Stats</h1> <h1>Stats</h1>
<p>This is the <em>full</em> stats page! This page exists for testing the speed of site generation, and contains every keyword on Violet's Purgatory in a hidden div.</p> <div class="mainDiv">
<p>Welcome to the stats page! This page is now "deprecated"... sorta.<br>
<div style="display: none"> Feel free to read more about it at the bottom of the page.</p>
{ALL_KEYWORDS} {ALL_KEYWORDS} {ALL_KEYWORDS} {ALL_KEYWORDS} {ALL_KEYWORDS}
</div>
<main> <main>
<h1><hr>Stats</h1> <h1>
<hr>Stats
</h1>
<br> <br>
<ul> <ul>
<li>Page generation time: {LOAD_TIME}</li> <li>Page generation time: {LOAD_TIME}</li>
<li>Pregeneration time: {PREGEN_TIME}ms</li> <li>Pregeneration time: {PREGEN_TIME}ms</li>
<li>Uptime: {UPTIME}</li> <li>Uptime: {UPTIME}</li>
<li>Last Lanyard update: {LAST_LANYARD}</li> <li>Last Lanyard update: {LAST_LANYARD}</li>
<li>Last Pregeneration: {LAST_PREGEN}</li>
<li>Server connected to API: {API_CONNECTED}</li>
<li>Javascript Loaded/Enabled: <span id="jsEnabled">false</span></li>
<li>Client connected to API: <span id="apiConnected">false</span></li>
</ul> </ul>
</main> </main>
<h2><hr>Why does this page exist?</h2>
<p>Originally, the stats page served the purpose of putting heavy load on the server for testing page generation times. This had a number of problems, though:</p>
<ol>
<li>Anyone could freely use this page and put the server under heavy load, with no limits, including malicious actors.</li>
<li>The page itself failed to serve its original function, as it was not an accurate display of what kind of loads or processing would be caused by a <em>real</em> page on the site, as it did not contain things such as page embeds, and otherwise had a lack of content.</li>
<li>It didn't provide any information the main page did not.</li>
</ol>
<p>The list could probably go on and on, but by now I suspect you begin to get the idea. So, overall, this page is pretty useless :3</p>
<h2><hr>Why does it still exist then?</h2>
<p>Mainly for the aforementioned <a>page embeds</a>. The main page, and others, can embed the stats page on themselves to easily collect statistics! Currently, this is only used on the main page but, the code is still more organized and much more modular than if I had smacked the code into the main page and called it a day.</p>
<h2><hr>The future of the stats page</h2>
<p>I have a few different ideas at the moment, one of them being an actual stats monitor. E.G, I could record stats such as:</p>
<ul>
<li>Programs connected to the api (This would includes sites AND users)</li>
<li>Average CPU, RAM, etc loads</li>
<li>Uptime monitor (Would probably pull from something like Uptime Kuma)</li>
</ul>
<p>But, only time can tell :)</p>
</div> </div>
</body> </body>

View file

@ -35,14 +35,15 @@
} }
#topbar { #topbar {
background-color: rgb(75, 50, 125); background-color: rgb(75, 50, 125, 0.5);
width: 100%; width: 100%;
padding: 1vh 0px; padding: 1vh 0px;
position: sticky; margin-bottom: 1vh;
/* position: sticky; */
left: 0px; left: 0px;
top: 0px; top: 0px;
z-index: 10; z-index: 10;
opacity: 0.5; /* opacity: 0.5; */
transform: scale(1); transform: scale(1);
transition: all 2s cubic-bezier(0.075, 0.82, 0.165, 1); transition: all 2s cubic-bezier(0.075, 0.82, 0.165, 1);
} }
@ -57,7 +58,7 @@
font-size: 1.5rem; font-size: 1.5rem;
} }
main:nth-of-type(1) { main:nth-of-type(1), .mainDiv {
width: 95%; width: 95%;
max-width: 1000px; max-width: 1000px;
margin: auto; margin: auto;
@ -250,11 +251,13 @@ br {
} }
ul, ol { ul, ol {
display: inline-block display: inline-block;
max-width: 90%;
} }
li { li {
font-size: 1.2rem; font-size: 1.2rem;
padding: 5px 0;
text-align: left; text-align: left;
} }
@ -283,6 +286,10 @@ li {
text-align: center; text-align: center;
} }
span {
color: inherit
}
.lengthBar>span { .lengthBar>span {
margin: 0; margin: 0;
padding: 0; padding: 0;
@ -299,6 +306,7 @@ video {
border: 2px rgb(125, 100, 155) solid; border: 2px rgb(125, 100, 155) solid;
border-radius: 15px; border-radius: 15px;
transition: all 5s cubic-bezier(0.39, 0.575, 0.565, 1); transition: all 5s cubic-bezier(0.39, 0.575, 0.565, 1);
z-index: 5;
} }
video:active { video:active {

View file

@ -9,25 +9,10 @@ h1:nth-of-type(1) {
} }
body { /* body {
padding: 5vh 0; padding: 5vh 0;
} } */
.mainDiv { .mainDiv {
animation: fadeUp 1s cubic-bezier(0.075, 0.82, 0.165, 1);
padding: 0 2.5vw;
max-width: 800px;
margin: auto; margin: auto;
} }
@keyframes fadeUp {
0% {
transform: translateY(50vw);
opacity: 0;
}
100% {
transform: none;
opacity: 1;
}
}

View file

@ -0,0 +1,29 @@
function typeWriter(elem, delay) {
var elemText = elem.text().split('')
elem.text('_'.repeat(elemText.length))
var i = 0
function nextLetter() {
elem.text(elemText.slice(0, i).join('') + '_'.repeat(elemText.length - i))
if (i < elemText.length) {
setTimeout(() => {
i++
nextLetter()
}, 20)
}
}
setTimeout(() => {
if (elem.text() == '_'.repeat(elemText.length)) {
nextLetter()
}
}, delay);
}
$(document).ready(() => {
var i = 0
var arr = $("span").each((_, item) => {
if ($(item).text().length > 0) {
i++
typeWriter($(item), i * 450)
}
})
})

View file

@ -0,0 +1,16 @@
* {
font-family: "Consolas", "Monaco", "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New";
}
body {
background: black;
}
.mainTitle, .mainTitle > span {
color: limegreen !important;
}
.mainTitle {
animation: typer 2s linear;
margin: auto;
}

View file

@ -0,0 +1,34 @@
$(document).ready(() => {
function particle() {
var particle = $("<div></div>")
particle.addClass("particle")
particle.css("left", (Math.random() * 100).toString() + "%")
particle.css("visibility", "visible")
particle.css("top", "100%")
var anim = "sway 4s infinite cubic-bezier(0.445, 0.05, 0.55, 0.95)"
if (Math.round(Math.random()) == 1) {
anim += " alternate"
} else {
anim += " alternate-reverse"
}
particle.css("animation", anim)
particle.animate({
"top": "-5%"
}, (((Math.round(Math.random() * 10) / 10) * 0.3) + 20) * 1000, () => {
particle.remove()
})
$(".magicContainer").append(particle)
}
$(".magicContainer > *").remove()
function loop() {
particle()
setTimeout(() => {
loop()
}, 1000);
}
loop()
})

View file

@ -0,0 +1,44 @@
#card {
background-color: rgba(20, 5, 90, 0.5);
/* backdrop-filter: blur(5px); */
}
.magicStuff {
position: sticky;
top: 0;
height: 0;
z-index: 0;
pointer-events: none;
}
.magicContainer {
height: 100vh;
width: 100vw;
top: 0px;
left: 0vw;
position: absolute;
overflow: hidden;
}
.particle {
position: absolute;
width: 5px;
aspect-ratio: 1/1;
background-color: rgb(100, 70, 255);
/* background-image: radial-gradient(rgba(175, 0, 255, 1) 0% 25%, rgba(175, 0, 255, 0.6) 25% 50%, rgba(175, 0, 255, 0.3) 50% 75%, rgba(0, 0, 255, 0)); */
border-radius: 50%;
visibility: hidden;
}
body {
background: linear-gradient(black, rgb(50, 0, 90));
}
@keyframes sway {
from {
transform: translateX(-30px);
}
to {
transform: translateX(30px);
}
}

View file

@ -0,0 +1,28 @@
$(document).ready(() => {
function particle() {
var particle = $("<div></div>")
particle.addClass("rainDrop")
particle.css("left", (Math.random() * 100).toString() + "%")
particle.css("visibility", "visible")
particle.css("top", "-10%")
particle.animate({
"top": "110%",
"easing": "linear"
}, 600, () => {
particle.remove()
})
$(".rainContainer").append(particle)
}
$(".rainContainer > *").remove()
function loop() {
particle()
setTimeout(() => {
loop()
}, 100 * (Math.random() + 0.25));
}
loop()
})

View file

@ -1,20 +1,21 @@
#card { #card {
background-color: rgba(50, 0, 90, 0.5); background-color: rgba(50, 0, 90, 0.5);
backdrop-filter: blur(5px); /* backdrop-filter: blur(5px); */
} }
.rainStuff { .rainStuff {
position: sticky; position: sticky;
top: 0; top: 0;
height: 0; height: 0;
z-index: -5; z-index: 0;
pointer-events: none;
} }
.rainContainer { .rainContainer {
height: 100vh; height: 100vh;
width: 80vw; width: 95vw;
top: 0px; top: 0px;
left: 10vw; left: 2.5vw;
position: absolute; position: absolute;
overflow: hidden; overflow: hidden;
} }
@ -22,7 +23,6 @@
.rainDrop { .rainDrop {
position: absolute; position: absolute;
width: 5px; width: 5px;
backdrop-filter: blur(5px);
background-color: rgba(0, 0, 255, 0.2); background-color: rgba(0, 0, 255, 0.2);
height: 10vh; height: 10vh;
visibility: hidden; visibility: hidden;