This document provides essential context for AI coding agents (Claude, Gemini, GitHub Copilot, etc.) working on this project.
brylie.music is a personal music website built with modern web technologies, featuring:
- Music releases with Creative Commons licensing
- Blog posts about music and technology
- Interactive musical applications (Svelte-based)
- High performance (100/100 Lighthouse score)
- SEO-optimized with dark theme design
- Astro 5.x: Static site generator with content collections
- File-based routing in
src/pages/ - Type-safe content collections in
src/content/ - MDX support for enhanced markdown
- Server-side rendering capabilities
- File-based routing in
- Svelte 5: Interactive components with runes (modern reactive patterns)
- Use
$state,$derived,$effectrunes - Components in
src/components/andsrc/apps/
- Use
- Tailwind CSS 4.x: Utility-first CSS framework
- Modern Vite integration (
@tailwindcss/vite) - Typography plugin for markdown styling
- Custom configuration in
tailwind.config.js
- Modern Vite integration (
- TypeScript 5.x: Type-safe development
- Strict mode enabled
- Configuration in
tsconfig.json
- Vitest: Fast unit testing framework
- Tests adjacent to implementation (e.g.,
bpm.test.ts) - UI mode available:
npm run test:ui - Configuration in
vitest.config.ts
- Tests adjacent to implementation (e.g.,
---
// TypeScript in frontmatter for SSR logic
import type { Props } from './types';
import ComponentName from './ComponentName.astro';
const { prop1, prop2 } = Astro.props;
---
<div class="container">
<!-- Component JSX -->
</div>
<style>
/* Component-scoped styles (or use Tailwind) */
</style><script lang="ts">
// Use runes for reactive state
let count = $state(0);
let doubled = $derived(count * 2);
$effect(() => {
// Side effects here
console.log('Count changed:', count);
});
</script>
<button onclick={() => count++}>
Count: {count} (Doubled: {doubled})
</button>- Use explicit types for function parameters and return values (including
: void) - Prefer
interfaceovertypefor object shapes - Use
constby default,letwhen mutation is needed - Avoid
any; useunknownif type is truly unknown
- Prefer Tailwind utilities over custom CSS
- Use semantic class names when combining multiple utilities
- Dark theme optimized: use
dark:variants sparingly - Component-specific styles: use Astro's scoped
<style>tags if needed
src/
├── components/ # Reusable Astro/Svelte components
│ └── *.astro # Layout components
├── content/ # Content collections (type-safe)
│ ├── blog/ # Blog posts (MDX)
│ ├── releases/ # Music releases (MD)
│ └── apps/ # App metadata (MDX)
├── layouts/ # Page layouts
├── pages/ # File-based routing
│ ├── apps/ # Musical apps routes
│ ├── blog/ # Blog routes
│ └── releases/ # Release routes
├── styles/ # Global CSS
└── apps/ # Interactive musical apps (Svelte + Logic + Tests)
Content collections use Zod schemas in src/content.config.ts:
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const blog = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(),
}),
});- Test utility functions in isolation
- Place tests adjacent to implementation:
bpm.ts→bpm.test.ts - Use descriptive test names:
test('converts BPM to whole note duration', ...) - Run with
npm run testornpm run test:ui
import { describe, test, expect } from 'vitest';
import { functionName } from './module';
describe('functionName', () => {
test('should handle normal case', () => {
expect(functionName(input)).toBe(expectedOutput);
});
test('should handle edge case', () => {
expect(functionName(edgeInput)).toBe(edgeOutput);
});
});Interactive musical applications are built with Svelte and documented in src/apps/README.md.
- Component:
src/apps/AppName.svelte(interactive UI) - Logic:
src/apps/appName.ts(business logic) - Tests:
src/apps/appName.test.ts(unit tests) - Metadata:
src/content/apps/app-name.mdx(description, documentation)
- Separation of Concerns: Business logic in
.tsfiles, UI in Svelte components, both co-located insrc/apps/ - Type Safety: TypeScript for all logic functions
- Testing: Unit tests for all utility functions
- Accessibility: WCAG 2.1 AA compliance (semantic HTML, ARIA labels)
- Performance: Keep components lightweight, lazy-load when possible
main: Production-ready code- Feature branches:
feature/descriptionorfix/description - Create PR for review before merging
Follow conventional commits:
feat(apps): add BPM calculator with millisecond subdivisions
fix(blog): correct date formatting in post metadata
docs(readme): update installation instructions
test(utils): add edge cases for bpm calculations
- Type Safety: Ensure TypeScript types are properly defined
- Performance: Check for unnecessary re-renders, large bundle sizes
- Accessibility: Verify semantic HTML and ARIA attributes
- Testing: Require tests for new utility functions
- Conventions: Follow established patterns in existing code
- Documentation: Update README/docs for significant changes
- ❌ Don't use React hooks in Astro components (use Svelte or vanilla JS)
- ❌ Don't import client components without proper directives
- ✅ Use
client:load,client:visible, etc. for interactive islands
- ❌ Don't use legacy
$:reactive statements (use$derivedinstead) - ❌ Don't use
onMountfor simple effects (use$effectinstead) - ✅ Embrace runes:
$state,$derived,$effect,$props
- ❌ Don't use
anytype - ❌ Don't ignore TypeScript errors (fix them properly)
- ✅ Use explicit return types for functions
- ✅ Leverage type inference when appropriate
- ❌ Don't create duplicate utility classes in custom CSS
- ❌ Don't use overly complex class strings (consider component extraction)
- ✅ Use Tailwind's built-in responsive and dark mode utilities
- Image Optimization: Use Astro's
<Image>component withsharp - Bundle Size: Keep JavaScript minimal; prefer static HTML
- Lazy Loading: Use
client:visiblefor below-fold interactive components - CSS: Tailwind automatically purges unused styles
- Caching: Leverage Astro's built-in static generation
All pages should include:
- Canonical URLs
- OpenGraph metadata
- Twitter card metadata
- Descriptive page titles and meta descriptions
- Structured schema.org data where applicable
Implemented via BaseHead.astro component.
- Content (blog posts, releases, images): Creative Commons CC-BY-4.0
- Source Code: See LICENSE file
Note for AI Agents: This document is authoritative for coding standards in this project. When in doubt, refer to existing code patterns and this documentation. Always prioritize type safety, accessibility, and performance.