chore: add Biome and format codebase with biome.json

This commit is contained in:
2025-12-12 23:37:56 +08:00
parent 675b51da17
commit f768ac7827
14 changed files with 105 additions and 61 deletions

View File

@@ -1,7 +1,7 @@
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';
import cloudflare from "@astrojs/cloudflare";
import { defineConfig } from "astro/config";
// https://astro.build/config
export default defineConfig({
adapter: cloudflare()
adapter: cloudflare(),
});

View File

@@ -15,7 +15,8 @@
"**",
"!**/src/public/**/*",
"!**/dist/**/*",
"!**/node_modules/**/*"
"!**/node_modules/**/*",
"!**/.astro/**/*"
]
},
"assist": {
@@ -27,9 +28,17 @@
}
},
"html": {
"formatter": { "enabled": true, "indentScriptAndStyle": true },
"formatter": {
"enabled": true,
"indentScriptAndStyle": true
},
"experimentalFullSupportEnabled": true
},
"css": {
"parser": {
"cssModules": true
}
},
"overrides": [
{
"includes": ["**/*.svelte", "**/*.astro", "**/*.vue"],
@@ -42,6 +51,9 @@
"correctness": {
"noUnusedVariables": "off",
"noUnusedImports": "off"
},
"suspicious": {
"noDuplicateProperties": "off"
}
}
}

View File

@@ -8,6 +8,9 @@
"@astrojs/cloudflare": "^12.6.12",
"astro": "^5.0.0",
},
"devDependencies": {
"@biomejs/biome": "2.3.8",
},
},
},
"packages": {
@@ -33,6 +36,24 @@
"@babel/types": ["@babel/types@7.28.5", "https://registry.npmmirror.com/@babel/types/-/types-7.28.5.tgz", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="],
"@biomejs/biome": ["@biomejs/biome@2.3.8", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.8", "@biomejs/cli-darwin-x64": "2.3.8", "@biomejs/cli-linux-arm64": "2.3.8", "@biomejs/cli-linux-arm64-musl": "2.3.8", "@biomejs/cli-linux-x64": "2.3.8", "@biomejs/cli-linux-x64-musl": "2.3.8", "@biomejs/cli-win32-arm64": "2.3.8", "@biomejs/cli-win32-x64": "2.3.8" }, "bin": { "biome": "bin/biome" } }, "sha512-Qjsgoe6FEBxWAUzwFGFrB+1+M8y/y5kwmg5CHac+GSVOdmOIqsAiXM5QMVGZJ1eCUCLlPZtq4aFAQ0eawEUuUA=="],
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HM4Zg9CGQ3txTPflxD19n8MFPrmUAjaC7PQdLkugeeC0cQ+PiVrd7i09gaBS/11QKsTDBJhVg85CEIK9f50Qww=="],
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-lUDQ03D7y/qEao7RgdjWVGCu+BLYadhKTm40HkpJIi6kn8LSv5PAwRlew/DmwP4YZ9ke9XXoTIQDO1vAnbRZlA=="],
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-Uo1OJnIkJgSgF+USx970fsM/drtPcQ39I+JO+Fjsaa9ZdCN1oysQmy6oAGbyESlouz+rzEckLTF6DS7cWse95g=="],
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-PShR4mM0sjksUMyxbyPNMxoKFPVF48fU8Qe8Sfx6w6F42verbwRLbz+QiKNiDPRJwUoMG1nPM50OBL3aOnTevA=="],
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.8", "", { "os": "linux", "cpu": "x64" }, "sha512-QDPMD5bQz6qOVb3kiBui0zKZXASLo0NIQ9JVJio5RveBEFgDgsvJFUvZIbMbUZT3T00M/1wdzwWXk4GIh0KaAw=="],
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.8", "", { "os": "linux", "cpu": "x64" }, "sha512-YGLkqU91r1276uwSjiUD/xaVikdxgV1QpsicT0bIA1TaieM6E5ibMZeSyjQ/izBn4tKQthUSsVZacmoJfa3pDA=="],
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-H4IoCHvL1fXKDrTALeTKMiE7GGWFAraDwBYFquE/L/5r1927Te0mYIGseXi4F+lrrwhSWbSGt5qPFswNoBaCxg=="],
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.8", "", { "os": "win32", "cpu": "x64" }, "sha512-RguzimPoZWtBapfKhKjcWXBVI91tiSprqdBYu7tWhgN8pKRZhw24rFeNZTNf6UiBfjCYCi9eFQs/JzJZIhuK4w=="],
"@capsizecss/unpack": ["@capsizecss/unpack@3.0.1", "https://registry.npmmirror.com/@capsizecss/unpack/-/unpack-3.0.1.tgz", { "dependencies": { "fontkit": "^2.0.2" } }, "sha512-8XqW8xGn++Eqqbz3e9wKuK7mxryeRjs4LOHLxbh2lwKeSbuNR4NFifDZT4KzvjU6HMOPbiNTsWpniK5EJfTWkg=="],
"@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "https://registry.npmmirror.com/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.0.tgz", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="],

View File

@@ -8,6 +8,9 @@
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"format": "biome format --write .",
"lint": "biome lint --write .",
"check": "biome check --write .",
"astro": "astro"
},
"dependencies": {

View File

@@ -1,7 +1,3 @@
---
---
<footer class="footer">
<div class="controls">
<button id="zoom-out" aria-label="Zoom Out">

View File

@@ -1,26 +1,26 @@
---
import titleSvg from "../assets/title.svg?raw";
import Footer from "./Footer.astro";
import Navbar from "./Navbar.astro";
import Particles from "./Particles.astro";
import Footer from "./Footer.astro";
---
<Navbar />
<Particles />
<Navbar/>
<Particles/>
<div class="halo"></div>
<div class="grain"></div>
<div id="marble-field"></div>
<Footer />
<Footer/>
<div class="content">
<div class="title-card">
<div class="title-svg-container" set:html={titleSvg} />
<div class="title-svg-container" set:html={titleSvg}/>
</div>
</div>
<script>
import { MarbleSystem } from "../utils/marbleSystem";
import { fetchUsers } from "../data/users";
import { MarbleSystem } from "../utils/marbleSystem";
const titleCard = document.querySelector(".title-card") as HTMLElement;
const navbar = document.querySelector(".navbar") as HTMLElement;
@@ -154,7 +154,6 @@ import Footer from "./Footer.astro";
max-width: 80vw;
position: relative;
overflow: hidden;
overflow: hidden;
pointer-events: auto;
z-index: 6;
opacity: 0;

View File

@@ -9,7 +9,7 @@ import titleImg from "../assets/title.svg";
class="nav-title"
height="32"
style="height: 32px; width: auto;"
/>
>
<a
href="https://github.com/101island"
target="_blank"

View File

@@ -5,12 +5,12 @@ import MainView from "../components/MainView.astro";
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>lolisland.us</title>
</head>
<body>
<MainView />
<MainView/>
</body>
</html>
@@ -32,7 +32,8 @@ import MainView from "../components/MainView.astro";
min-height: 100vh;
min-height: 100dvh;
overflow: hidden;
background: radial-gradient(
background:
radial-gradient(
120% 120% at 20% 25%,
rgba(255, 127, 209, 0.35),
transparent 55%
@@ -46,15 +47,9 @@ import MainView from "../components/MainView.astro";
130% 140% at 50% 85%,
rgba(255, 209, 102, 0.22),
transparent 55%
),
linear-gradient(150deg, var(--bg0), var(--bg1) 45%, var(--bg2));
), linear-gradient(150deg, var(--bg0), var(--bg1) 45%, var(--bg2));
color: var(--text);
font-family:
"Space Grotesk",
"Inter",
system-ui,
-apple-system,
sans-serif;
font-family: "Space Grotesk", "Inter", system-ui, -apple-system, sans-serif;
letter-spacing: 0.02em;
background-repeat: no-repeat;
background-size: cover;
@@ -62,7 +57,8 @@ import MainView from "../components/MainView.astro";
@media (max-width: 720px) {
body {
background: radial-gradient(
background:
radial-gradient(
140% 140% at 25% 15%,
rgba(255, 127, 209, 0.38),
transparent 55%
@@ -76,8 +72,7 @@ import MainView from "../components/MainView.astro";
150% 150% at 50% 90%,
rgba(255, 209, 102, 0.24),
transparent 60%
),
linear-gradient(160deg, var(--bg0), var(--bg1) 40%, var(--bg2));
), linear-gradient(160deg, var(--bg0), var(--bg1) 40%, var(--bg2));
background-repeat: no-repeat;
background-size: cover;
}

View File

@@ -1,13 +1,11 @@
// Unified export
export { MarbleSystem } from "./marbleSystem";
export { MarblePhysics } from "./marblePhysics";
export { MouseInteraction } from "./mouseInteraction";
export { MarbleFactory } from "./marbleFactory";
export { AnimationLoop } from "./animationLoop";
export type { Marble } from "./mouseInteraction";
export type { PhysicsConfig } from "./marblePhysics";
export type { MouseInteractionConfig } from "./mouseInteraction";
export type { UpdateCallback } from "./animationLoop";
export { AnimationLoop } from "./animationLoop";
export { MarbleFactory } from "./marbleFactory";
export type { PhysicsConfig } from "./marblePhysics";
export { MarblePhysics } from "./marblePhysics";
export type { MarbleSystemConfig } from "./marbleSystem";
export { MarbleSystem } from "./marbleSystem";
export type { Marble, MouseInteractionConfig } from "./mouseInteraction";
export { MouseInteraction } from "./mouseInteraction";

View File

@@ -1,8 +1,8 @@
// Marble factory: Responsible for creating and initializing marble instances
import type { Marble } from "./mouseInteraction";
import type { UserEntry } from "../config/marbleConfig";
import { MARBLE_CONFIG, AVATAR_BASE_URL } from "../config/marbleConfig";
import { AVATAR_BASE_URL, MARBLE_CONFIG } from "../config/marbleConfig";
import type { Marble } from "./mouseInteraction";
export class MarbleFactory {
private container: HTMLElement;
@@ -19,7 +19,8 @@ export class MarbleFactory {
// Calculate marble size (responsive)
private calculateMarbleSize(): number {
const { base, min, maxScreenRatio } = MARBLE_CONFIG.size;
const quarter = Math.min(window.innerWidth, window.innerHeight) * maxScreenRatio;
const quarter =
Math.min(window.innerWidth, window.innerHeight) * maxScreenRatio;
const capped = Math.min(base, quarter || base);
return Math.max(min, Math.floor(capped)) * this.zoomLevel;
}
@@ -30,7 +31,11 @@ export class MarbleFactory {
}
// Create marble DOM node wrapper
private createMarbleWrapper(entry: UserEntry, size: number, url: string): HTMLElement {
private createMarbleWrapper(
entry: UserEntry,
size: number,
url: string,
): HTMLElement {
const wrapper = document.createElement("div");
wrapper.className = "marble-wrapper";
wrapper.style.width = `${size}px`;
@@ -125,7 +130,9 @@ export class MarbleFactory {
// Batch create marbles
public async createMarbles(entries: UserEntry[]): Promise<Marble[]> {
const results = await Promise.allSettled(entries.map((entry) => this.createMarble(entry)));
const results = await Promise.allSettled(
entries.map((entry) => this.createMarble(entry)),
);
const marbles: Marble[] = [];
for (let i = 0; i < results.length; i++) {
@@ -133,7 +140,10 @@ export class MarbleFactory {
if (result.status === "fulfilled") {
marbles.push(result.value);
} else {
console.warn(`Failed to create marble for ${entries[i].name}:`, result.reason);
console.warn(
`Failed to create marble for ${entries[i].name}:`,
result.reason,
);
}
}

View File

@@ -34,7 +34,7 @@ export class MarblePhysics {
for (const m of marbles) {
// Apply air resistance
if (damping !== undefined && damping < 1) {
const dampingFactor = Math.pow(damping, dt * 60); // Frame rate independent
const dampingFactor = damping ** (dt * 60); // Frame rate independent
m.vx *= dampingFactor;
m.vy *= dampingFactor;
}
@@ -82,7 +82,8 @@ export class MarblePhysics {
if (relativeVelocity < 0) {
// Calculate impulse using restitution coefficient
const impulse = ((1 + restitution) * relativeVelocity) / (a.mass + b.mass);
const impulse =
((1 + restitution) * relativeVelocity) / (a.mass + b.mass);
a.vx -= impulse * b.mass * nx;
a.vy -= impulse * b.mass * ny;
b.vx += impulse * a.mass * nx;

View File

@@ -1,12 +1,12 @@
// Marble system manager: Integrates all subsystems and provides a unified API
import type { Marble, MouseInteractionConfig } from "./mouseInteraction";
import type { UserEntry } from "../config/marbleConfig";
import { MouseInteraction } from "./mouseInteraction";
import { MarblePhysics } from "./marblePhysics";
import { MarbleFactory } from "./marbleFactory";
import { AnimationLoop } from "./animationLoop";
import { MARBLE_CONFIG } from "../config/marbleConfig";
import { AnimationLoop } from "./animationLoop";
import { MarbleFactory } from "./marbleFactory";
import { MarblePhysics } from "./marblePhysics";
import type { Marble, MouseInteractionConfig } from "./mouseInteraction";
import { MouseInteraction } from "./mouseInteraction";
export interface MarbleSystemConfig {
container: HTMLElement;
@@ -45,11 +45,14 @@ export class MarbleSystem {
config.mouseInteractionConfig?.attractRadius ??
MARBLE_CONFIG.mouseInteraction.attractRadius,
repelRadius:
config.mouseInteractionConfig?.repelRadius ?? MARBLE_CONFIG.mouseInteraction.repelRadius,
config.mouseInteractionConfig?.repelRadius ??
MARBLE_CONFIG.mouseInteraction.repelRadius,
repelForce:
config.mouseInteractionConfig?.repelForce ?? MARBLE_CONFIG.mouseInteraction.repelForce,
config.mouseInteractionConfig?.repelForce ??
MARBLE_CONFIG.mouseInteraction.repelForce,
attractForce:
config.mouseInteractionConfig?.attractForce ?? MARBLE_CONFIG.mouseInteraction.attractForce,
config.mouseInteractionConfig?.attractForce ??
MARBLE_CONFIG.mouseInteraction.attractForce,
};
this.mouseInteraction = new MouseInteraction(mouseConfig);
this.mouseInteraction.init();
@@ -66,7 +69,11 @@ export class MarbleSystem {
});
// MarbleFactory Init
this.factory = new MarbleFactory(this.container, this.fieldWidth, this.fieldHeight);
this.factory = new MarbleFactory(
this.container,
this.fieldWidth,
this.fieldHeight,
);
// AnimationLoop Init
this.animationLoop = new AnimationLoop(
@@ -190,7 +197,8 @@ export class MarbleSystem {
// Calculate marble size
private calculateMarbleSize(zoomLevel: number): number {
const { base, min, maxScreenRatio } = MARBLE_CONFIG.size;
const quarter = Math.min(window.innerWidth, window.innerHeight) * maxScreenRatio;
const quarter =
Math.min(window.innerWidth, window.innerHeight) * maxScreenRatio;
const capped = Math.min(base, quarter || base);
return Math.max(min, Math.floor(capped)) * zoomLevel;
}

View File

@@ -103,7 +103,8 @@ export class MouseInteraction {
public applyForce(marble: Marble, dt: number): void {
// Fix state at the start of function to avoid state change during execution
const isAttractMode = this.isShiftPressed;
const { attractRadius, repelRadius, repelForce, attractForce } = this.config;
const { attractRadius, repelRadius, repelForce, attractForce } =
this.config;
const dx = marble.x - this.mouseX;
const dy = marble.y - this.mouseY;