home to your local SPACEGIRL 💫 arimelody.space
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

funny cursor teehee

+318
+273
public/script/cursor.js
··· 1 + const CURSOR_TICK_RATE = 1000/30; 2 + const CURSOR_LERP_RATE = 1/100; 3 + const CURSOR_CHAR_MAX_LIFE = 5000; 4 + const CURSOR_MAX_CHARS = 50; 5 + /** @type HTMLElement */ 6 + let cursorContainer; 7 + /** @type Cursor */ 8 + let myCursor; 9 + /** @type Map<number, Cursor> */ 10 + let cursors = new Map(); 11 + /** @type Array<FunChar> */ 12 + let chars = new Array(); 13 + 14 + let lastCursorUpdateTime = 0; 15 + let lastCharUpdateTime = 0; 16 + 17 + class Cursor { 18 + /** @type number */ id; 19 + 20 + // real coordinates (canonical) 21 + /** @type number */ x; 22 + /** @type number */ y; 23 + 24 + // update coordinates (interpolated) 25 + /** @type number */ rx; 26 + /** @type number */ ry; 27 + 28 + /** @type HTMLElement */ 29 + #element; 30 + /** @type HTMLElement */ 31 + #char; 32 + 33 + /** 34 + * @param {number} id 35 + * @param {number} x 36 + * @param {number} y 37 + */ 38 + constructor(id, x, y) { 39 + this.id = id; 40 + this.x = x; 41 + this.y = y; 42 + this.rx = x; 43 + this.ry = y; 44 + 45 + const element = document.createElement("i"); 46 + element.classList.add("cursor"); 47 + element.id = "cursor" + id; 48 + const colour = randomColour(); 49 + element.style.borderColor = colour; 50 + element.style.color = colour; 51 + element.innerText = "0x" + navigator.userAgent.hashCode(); 52 + 53 + const char = document.createElement("p"); 54 + char.className = "char"; 55 + element.appendChild(char); 56 + 57 + this.#element = element; 58 + this.#char = char; 59 + cursorContainer.appendChild(this.#element); 60 + } 61 + 62 + destroy() { 63 + this.#element.remove(); 64 + } 65 + 66 + /** 67 + * @param {number} x 68 + * @param {number} y 69 + */ 70 + move(x, y) { 71 + this.x = x; 72 + this.y = y; 73 + } 74 + 75 + /** 76 + * @param {number} deltaTime 77 + */ 78 + update(deltaTime) { 79 + this.rx += (this.x - this.rx) * CURSOR_LERP_RATE * deltaTime; 80 + this.ry += (this.y - this.ry) * CURSOR_LERP_RATE * deltaTime; 81 + this.#element.style.left = this.rx + "px"; 82 + this.#element.style.top = this.ry + "px"; 83 + } 84 + 85 + /** 86 + * @param {string} text 87 + */ 88 + print(text) { 89 + if (text.length > 1) return; 90 + this.#char.innerText = text; 91 + } 92 + } 93 + 94 + class FunChar { 95 + /** @type number */ x; y; 96 + /** @type number */ xa; ya; 97 + /** @type number */ r; ra; 98 + /** @type HTMLElement */ element; 99 + /** @type number */ life; 100 + 101 + /** 102 + * @param {number} x 103 + * @param {number} y 104 + * @param {number} xa 105 + * @param {number} ya 106 + * @param {string} text 107 + */ 108 + constructor(x, y, xa, ya, text) { 109 + this.x = x; 110 + this.y = y; 111 + this.xa = xa + Math.random() * .2 - .1; 112 + this.ya = ya + Math.random() * -.25; 113 + this.r = this.xa * 100; 114 + this.ra = this.r * 0.01; 115 + this.life = 0; 116 + 117 + const char = document.createElement("i"); 118 + char.className = "funchar"; 119 + char.innerText = text; 120 + char.style.left = x + "px"; 121 + char.style.top = y + "px"; 122 + char.style.transform = `rotate(${this.r}deg)`; 123 + this.element = char; 124 + cursorContainer.appendChild(this.element); 125 + } 126 + 127 + /** 128 + * @param {number} deltaTime 129 + */ 130 + update(deltaTime) { 131 + this.life += deltaTime; 132 + if (this.life > CURSOR_CHAR_MAX_LIFE || 133 + this.y > window.outerHeight || 134 + this.x < 0 || 135 + this.x > window.outerWidth 136 + ) { 137 + this.destroy(); 138 + return; 139 + } 140 + 141 + this.x += this.xa * deltaTime; 142 + this.y += this.ya * deltaTime; 143 + this.r += this.ra * deltaTime; 144 + this.ya = Math.min(this.ya + 0.0005 * deltaTime, 10); 145 + 146 + this.element.style.left = this.x + "px"; 147 + this.element.style.top = this.y + "px"; 148 + this.element.style.transform = `rotate(${this.r}deg)`; 149 + } 150 + 151 + destroy() { 152 + chars = chars.filter(char => char !== this); 153 + this.element.remove(); 154 + } 155 + } 156 + 157 + String.prototype.hashCode = function() { 158 + var hash = 0; 159 + if (this.length === 0) return hash; 160 + for (let i = 0; i < this.length; i++) { 161 + const chr = this.charCodeAt(i); 162 + hash = ((hash << 5) - hash) + chr; 163 + hash |= 0; // convert to 32-bit integer 164 + } 165 + return Math.round(Math.abs(hash)).toString(16).slice(0, 8).padStart(8, '0'); 166 + }; 167 + 168 + /** 169 + * @returns string 170 + */ 171 + function randomColour() { 172 + const min = 128; 173 + const range = 100; 174 + const red = Math.round((min + Math.random() * range)).toString(16); 175 + const green = Math.round((min + Math.random() * range)).toString(16); 176 + const blue = Math.round((min + Math.random() * range)).toString(16); 177 + 178 + return "#" + red + green + blue; 179 + } 180 + 181 + /** 182 + * @param {MouseEvent} event 183 + */ 184 + function handleMouseMove(event) { 185 + if (!myCursor) return; 186 + myCursor.move(event.x, event.y); 187 + } 188 + 189 + /** 190 + * @param {KeyboardEvent} event 191 + */ 192 + function handleKeyDown(event) { 193 + if (event.key.length > 1) return; 194 + if (event.metaKey || event.ctrlKey) return; 195 + if (window.cursorFunMode === true) { 196 + const yOffset = -20; 197 + const accelMultiplier = 0.002; 198 + if (chars.length < CURSOR_MAX_CHARS) 199 + chars.push(new FunChar( 200 + myCursor.x, myCursor.y + yOffset, 201 + (myCursor.x - myCursor.rx) * accelMultiplier, (myCursor.y - myCursor.ry) * accelMultiplier, 202 + event.key)); 203 + } else { 204 + myCursor.print(event.key); 205 + } 206 + } 207 + 208 + function handleKeyUp() { 209 + if (!window.cursorFunMode) { 210 + myCursor.print(""); 211 + } 212 + } 213 + 214 + /** 215 + * @param {number} time 216 + */ 217 + function updateCursors(time) { 218 + const deltaTime = time - lastCursorUpdateTime; 219 + 220 + cursors.forEach(cursor => { 221 + cursor.update(deltaTime); 222 + }); 223 + 224 + lastCursorUpdateTime = time; 225 + requestAnimationFrame(updateCursors); 226 + } 227 + 228 + /** 229 + * @param {number} time 230 + */ 231 + function updateChars(time) { 232 + const deltaTime = time - lastCharUpdateTime; 233 + 234 + chars.forEach(char => { 235 + char.update(deltaTime); 236 + }); 237 + 238 + lastCharUpdateTime = time; 239 + requestAnimationFrame(updateChars); 240 + } 241 + 242 + function cursorSetup() { 243 + window.cursorFunMode = false; 244 + cursorContainer = document.createElement("div"); 245 + cursorContainer.id = "cursors"; 246 + document.body.appendChild(cursorContainer); 247 + myCursor = new Cursor(0, window.innerWidth / 2, window.innerHeight / 2); 248 + cursors.set(0, myCursor); 249 + document.addEventListener("mousemove", handleMouseMove); 250 + document.addEventListener("keydown", handleKeyDown); 251 + document.addEventListener("keyup", handleKeyUp); 252 + requestAnimationFrame(updateCursors); 253 + requestAnimationFrame(updateChars); 254 + console.debug(`Cursor tracking @ ${window.location.pathname}`); 255 + } 256 + 257 + function cursorDestroy() { 258 + document.removeEventListener("mousemove", handleMouseMove); 259 + document.removeEventListener("keydown", handleKeyDown); 260 + document.removeEventListener("keyup", handleKeyUp); 261 + cursors.forEach(cursor => { 262 + cursor.destroy(); 263 + }); 264 + cursors.clear(); 265 + chars.forEach(cursor => { 266 + cursor.destroy(); 267 + }); 268 + chars = new Array(); 269 + myCursor = null; 270 + console.debug(`Cursor no longer tracking.`); 271 + } 272 + 273 + cursorSetup();
+1
public/script/main.js
··· 1 1 import "./header.js"; 2 2 import "./config.js"; 3 + import "./cursor.js"; 3 4 4 5 function type_out(e) { 5 6 const text = e.innerText;
+43
public/style/cursor.css
··· 1 + #cursors i.cursor { 2 + position: fixed; 3 + padding: 4px; 4 + 5 + display: block; 6 + z-index: 1000; 7 + 8 + background: #0008; 9 + border: 2px solid #808080; 10 + border-radius: 2px; 11 + 12 + font-style: normal; 13 + font-size: 10px; 14 + font-weight: bold; 15 + white-space: nowrap; 16 + 17 + user-select: none; 18 + pointer-events: none; 19 + } 20 + 21 + #cursors i.cursor .char { 22 + position: absolute; 23 + transform: translateY(-44px); 24 + margin: 0; 25 + font-size: 20px; 26 + color: var(--on-background); 27 + } 28 + 29 + #cursors .funchar { 30 + position: fixed; 31 + margin: 0; 32 + 33 + display: block; 34 + z-index: 1000; 35 + 36 + font-style: normal; 37 + font-size: 20px; 38 + font-weight: bold; 39 + color: var(--on-background); 40 + 41 + user-select: none; 42 + pointer-events: none; 43 + }
+1
public/style/main.css
··· 2 2 @import url("/style/header.css"); 3 3 @import url("/style/footer.css"); 4 4 @import url("/style/prideflag.css"); 5 + @import url("/style/cursor.css"); 5 6 6 7 @font-face { 7 8 font-family: "Monaspace Argon";