Imported from dingyi222666/aura-music (
AGENTS.md). Install upstream withnpx skills add dingyi222666/aura-music. Copyright stays with the author.
Agent Instructions for aura-music
This file defines how agentic tools should work in this repository. It applies to the entire tree under the repo root.
- ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE.
- Prefer automation: execute requested actions without extra confirmation unless blocked by missing info or safety/irreversibility.
Repo & Branches
- Frontend-only React + Vite + TypeScript application.
- Default branch is
main; usemainororigin/mainfor diffs. - Bun monorepo: main application in
apps/web-player; reusable source packages inpackages/{core,player,view,lyrics,background,visualizer}. - Import another workspace through its declared
@aura-music/*exports. Libraries must not import the app. - There are currently no
.cursor/rules,.cursorrules, or.github/copilot-instructions.mdfiles. If they are added later, follow them in addition to this file. - App alias
@resolves toapps/web-player/src; libraries use package exports or relative imports.
Tooling & Commands
Install
- Use a recent Node.js (>= 18) and Bun installed globally.
- Install dependencies with one of:
bun install
Dev server
- Start the React dev server (Vite):
bun run dev
Build & preview
- Production build:
bun run build
- Preview a production build locally:
bun run preview
Tests (Bun)
Tests live under tests/ and use bun:test (import { test, expect } from "bun:test").
- Run the full test suite from the repo root:
bun test tests- or via npm script:
npm test(which runsbun test tests).
- Run a single test file (preferred pattern for agents):
bun test tests/yrc.test.tsbun test tests/enhance_lrc.test.ts
- Run tests matching a name pattern (example; see
bun test --helpfor details):bun test tests --filter "YRC enrichment"- Use the full or partial test description string from the
test("...")call.
- Avoid introducing other test runners (Jest, Vitest, etc.) unless explicitly requested; keep tests on Bun.
Linting & formatting commands
- There is currently no ESLint or Prettier configuration in this repo.
- Do not add new linters/formatters or config files without an explicit request from the user.
- Rely on TypeScript and the existing code style as the primary source of truth for correctness and style.
Browser Verification
- Prefer Chrome DevTools MCP for browser checks, page JavaScript, screenshots, and renderer comparisons.
- Reuse the fixed profile at
~/.cache/chrome-devtools-mcp/chrome-profile; do not use an isolated or temporary profile.
Testing Guidelines
- New tests should be placed under
tests/and use Bun's test API:import { test, expect } from "bun:test";
- Prefer focused, integration-style tests over heavy mocking.
- Example: use real lyrics parsing through
parseLyricsrather than re-implementing its logic inside tests.
- Example: use real lyrics parsing through
- Reuse the existing patterns in files like
tests/yrc.test.tsandtests/enhance_lrc.test.tsfor naming, structure, and expectations. - Test data lives in
tests/resources/; prefer adding new fixtures there instead of inlining very large strings directly in tests. - When debugging or narrowing failures, run only the relevant test file or filtered tests as described above.
General TypeScript Style
- Use modern ES modules with TypeScript (
.ts/.tsx). - Keep related logic in a single function unless splitting clearly improves reuse or readability.
- Prefer
constoverletand avoidvar. - Prefer early returns over deep nesting and
elsechains. - Avoid
anywhere possible; if you must use it (for interop with third-party globals likejsmediatagsorColorThief), keep theanyas localized as possible. - Use interfaces/types for exported shapes, especially in shared files like
types.tsandservices/lyrics/types.ts. - Use TypeScript's type inference where it keeps the code clear; avoid redundant type annotations for obvious local variables.
- Prefer functional array methods (
map,filter,flatMap,reduce) over manual loops; use type guards infilterto preserve downstream type inference. - Avoid unnecessary destructuring; prefer dot notation when it keeps context clearer (see examples below).
Imports
- Use ESM import syntax at the top of the file.
- Group imports roughly in this order:
- Node/built-in modules (
node:path,node:fs, etc.). - Third-party packages (
react,@react-spring/web). - Absolute project imports via
@/.... - Relative imports (
../services/...,./components/...).
- Node/built-in modules (
- Keep React imports explicit when needed (e.g.
import React, { useState } from "react";). - For deep cross-tree imports, prefer the
@alias over long../../..chains where it improves clarity.
React Components & Hooks
- Use function components (
const Component: React.FC<Props> = (...) => { ... }). - Define props with an
interfaceortypenear the top of the file. - Use hooks for state and side effects as in
App.tsxandLyricsView.tsx. - Keep components focused; pull out complex behavior into hooks under
hooks/or utilities underservices/when it improves reuse. - Prefer controlled components and prop-driven behavior over global state where possible.
- For UI styling, this project uses Tailwind-style utility class strings
directly in
className(e.g."h-[85vh] flex"); follow the existing patterns when editing or adding UI.
Naming Conventions
- Use PascalCase for React components, types, and enums (
LyricsView,PlayState). - Use camelCase for variables, functions, hooks, and non-component exports.
- Hooks should start with
use(useLyricsPhysics,usePlaylist). - Files containing React components should use PascalCase names ending in
.tsx(e.g.LyricsView.tsx). - For new TypeScript locals, parameters, and small helpers, prefer single
word names when they stay clear.
- Multi-word names are fine when a single word would be confusing
(
activeIndex,matchStatus,currentTime).
- Multi-word names are fine when a single word would be confusing
(
- Before finishing edits, quickly scan new names and shorten them if a clear single-word alternative exists.
Naming Enforcement (Read This)
THIS RULE IS MANDATORY FOR AGENT-WRITTEN CODE.
- Use single word names by default for new locals, params, and helper functions.
- Multi-word names are allowed only when a single word would be unclear or ambiguous.
- Do not introduce new camelCase compounds when a short single-word alternative is clear.
- Before finishing edits, review touched lines and shorten newly introduced identifiers where possible.
- Good short names to prefer:
pid,cfg,err,opts,dir,root,child,state,timeout. - Examples to avoid unless truly required:
inputPID,existingClient,connectTimeout,workerPath.
// Good
const foo = 1;
function journal(dir: string) {}
// Bad
const fooBar = 1;
function prepareJournal(dir: string) {}
Reduce total variable count by inlining when a value is only used once.
// Good
const fullName = `${user.firstName} ${user.lastName}`;
// Bad
const first = user.firstName;
const last = user.lastName;
const fullName = `${first} ${last}`;
Destructuring
Avoid unnecessary destructuring. Use dot notation to preserve context.
// Good
user.profile.name;
user.profile.avatarUrl;
// Bad
const { name, avatarUrl } = user.profile;
Variables
Prefer const over let. Use ternaries or early returns instead of
reassignment.
// Good
const value = condition ? 1 : 2;
// Bad
let value;
if (condition) value = 1;
else value = 2;
Control Flow
Avoid else statements when a simple early return works.
// Good
function foo(condition: boolean) {
if (condition) return 1;
return 2;
}
// Bad
function foo(condition: boolean) {
if (condition) return 1;
else return 2;
}
Schema Definitions (Drizzle)
If you add Drizzle ORM schema definitions in the future, use snake_case for
field names so column names don't need to be redefined as strings.
// Good
const table = sqliteTable("session", {
id: text().primaryKey(),
project_id: text().notNull(),
created_at: integer().notNull(),
});
// Bad
const table = sqliteTable("session", {
id: text("id").primaryKey(),
projectID: text("project_id").notNull(),
createdAt: integer("created_at").notNull(),
});
Error Handling
- For network and I/O helpers (for example in
services/utils.ts):- Use
try/catcharound external calls (fetch,jsmediatags.read,ColorThief) and log viaconsole.warnorconsole.error. - Return safe fallbacks (
[],{},null) when the UI can recover.
- Use
- Avoid swallowing errors silently; either log them or let them propagate to the caller where they can be handled.
- Do not introduce global error handlers or error boundaries without checking with the user; keep behavior consistent with the current app.
Formatting
- Use 2-space indentation for new or heavily edited code.
- Use double quotes (
"") for strings in TypeScript and JSX; the existing codebase mixes quotes, but move toward double quotes when you touch a line. - Always terminate statements with semicolons.
- Prefer trailing commas in multi-line object/array literals where supported.
- Keep lines to a reasonable length; break up long expressions or JSX props instead of letting lines grow excessively wide.
- Keep JSX easy to scan: one prop per line for complex components, and nested conditional rendering kept simple.
Vite, Env, and Paths
- Vite config lives in
apps/web-player/vite.config.tsand usesloadEnvto inject environment variables. - Only public
VITE_environment variables are loaded; never expose secrets in the client bundle. - When adding new env variables, wire them through Vite's
loadEnvand document them in this file or in README. - Use the
@alias if it improves readability, e.g.@/services/lyrics.
Agent-Specific Tips
- Prefer making small, focused changes that match existing patterns in the surrounding code.
- When adding features, update or add Bun tests under
tests/instead of creating new test directories or runners. - Do not introduce backend code or separate servers unless explicitly asked; this project is a client-side React app.
- When in doubt about style, look at
App.tsx,components/LyricsView.tsx, andservices/utils.tsand match their patterns.