Skip to content

Repository files navigation

Sorbellar

Thoughts in orbit. Powered by Astro.

A polished, feature-rich personal blog and knowledge base template. Built with Astro 6 and Tailwind CSS 4 — static by default, interactive where it counts.

Node.js >= 18 Astro 6 Tailwind CSS 4 TypeScript License

Live reference: soren-s-blog-base.pages.dev

README Languages: English / 中文 / 日本語 / 繁體中文

From blog posts and knowledge base articles to interactive music listening, this template brings together everything you need for a personal web presence. Whether you're writing LaTeX-heavy notes, organizing learning materials, or enjoying high-fidelity audio, it's all here in one polished, zero-cost static site.


Features

Homepage

  • Full-screen Hero cover with two-stage loading: pure wallpaper → typewriter title + particles + navbar fade-in
  • Scroll-bound wave transition — canvas color extraction from wallpaper, backdrop-filter blur, flowing SVG layers
  • Independent hero wallpaper carousel (8-10s crossfade) from public/assets/hero-wallpaper/
  • Classic typewriter effect with blinking cursor on site title
  • Time-aware subtitle carousel (morning / afternoon / evening phrases)
  • Multi-layer particle engine (starlight + glow dots + light rays, 3 canvas layers)
  • Parallax scroll collapse: hero fades out, navbar transitions transparent → glass
  • Hero now-playing bar (glassmorphism music status)
  • Mobile: 50dvh hero, reduced particles, disabled parallax

Design & Interface

  • Built with Astro 6 + Tailwind CSS 4 with OKLCH color space
  • Smooth page transitions via Astro View Transitions (SPA)
  • Light/dark theme switching with system preference detection
  • Dynamic hue slider — change the entire site's accent color with one CSS variable
  • Featured articles magazine grid (staggered layout, tilt effect)
  • Fullscreen wallpaper carousel with glassmorphism card effects
  • Sakura particle animation (Canvas, toggleable)
  • Fully responsive design for all devices

Gallery

  • Polaroid-style photo grid with randomized tilt
  • Round glass lightbox — click cards to view full images, not navigate away
  • Keyboard navigation (← → arrows, Esc to close)
  • Scroll-safe: locks body overflow, restores scroll position on close

Music Player

  • Web Audio API DSP signal chain: ReplayGain → Compressor → Crossfeed → Analyser
  • 20+ audio formats: FLAC, ALAC, WAV, AIFF, WavPack, APE, TAK, TTA, MP3, AAC, Opus, OGG, etc.
  • Auto quality classification: Studio Master / Hi-Res / CD Quality / Standard Lossless
  • Roon-inspired immersive full-screen playback with blurred cover background
  • Apple Music-style library browser: browse by album, artist, genre, year
  • NetEase Cloud Music integration — import playlists, liked songs; merged with local library
  • Album cover auto-extraction from audio file metadata
  • ReplayGain (track/album gain normalization)
  • EQ presets: Off, Classical, Rock, Jazz, Headphones, Voice
  • Recent play history with stale-entry auto-cleanup

Archive

  • Dual-view: Card grid + Time River (SVG wavy river with animated particles)
  • Category tabs with color-coded cards
  • Drag-to-scroll on Time River view
  • Sparkle dots, ripple nodes, flowing particles along the river

Content & Search

  • Markdown/MDX writing with Zod-typed content collections
  • Enhanced code blocks via Expressive Code: line numbers, copy button, collapsible sections
  • LaTeX math: KaTeX (server-side) + MathJax 3 (client fallback)
  • Mermaid diagrams with auto light/dark theme switching
  • GitHub-flavored admonitions: :::note, :::tip, :::important, :::caution, :::warning
  • GitHub repository cards via :github[user/repo] syntax
  • Image width control and centering: ![desc w-400 center](url)
  • Static full-text search via Pagefind with CJK support
  • Reading time estimation (Chinese 400 cpm, English 200 wpm)
  • Floating table of contents with scroll tracking
  • RSS 2.0 feed

Technical Features

  • Zero-JS-by-default output (Islands Architecture)
  • PWA support with offline access and installable app
  • JSON-LD structured data for SEO
  • Content collections with draft system (visible in dev, hidden in production)
  • Auto-generated OG images via Satori
  • Back-to-top button with scroll progress ring
  • Custom remark/rehype plugin pipeline (12 plugins)
  • NetEase Cloud Music API proxy (NCM login, playlist sync, song URL resolution)
  • Wallpaper auto-resize integration (responsive images per viewport)
  • Chinese and English i18n
  • Vercel Analytics ready

Quick Start

Prerequisites

Dependency Version
Node.js >= 18 (LTS recommended)
npm >= 9

Installation

# 1. Clone the repository
git clone https://github.com/your-username/sorbellar.git
cd sorbellar

# 2. Install dependencies
npm install

> [!IMPORTANT]
> **`.npmrc` — why `legacy-peer-deps=true` is required**
>
> `@vite-pwa/astro@1.2.0` (latest) only supports Astro `^1.0 – ^5.0` as a peer dependency, but this project uses **Astro 6**. Until upstream releases a compatible version, the project ships a `.npmrc` file that enables `legacy-peer-deps` to suppress the peer conflict.
>
> This has no impact on PWA functionality — the plugin works correctly with Astro 6 despite the unresolved peer range. If you remove `.npmrc`, `npm ci` will fail on CI and fresh installs.

# 3. (Optional) Add hero wallpapers
# Place images in public/assets/hero-wallpaper/desktop/ and mobile/
# Supported: .webp, .jpg, .png

# 4. (Optional) Add your music files
# Place audio files in public/assets/music/url/
# Supported: .mp3 .flac .m4a .ogg .wav .wma .aiff .ape .wv .opus .aac .mpc .mp4 .alac .tak .tta .ac3 .dts
# Note: DSD (.dsf/.dff) is NOT supported — they are automatically skipped by the scanner

# 5. Scan music and generate playlist
npm run scan-music

# 6. Start the dev server
npm run dev

Open http://localhost:3000 in your browser.


Article Frontmatter

---
title: "Article Title"               # Required
published: 2026-06-10                # Required
updated: 2026-06-10                  # Optional
description: "SEO description"       # Recommended
image: "/assets/posts_picture/1.webp"  # Optional cover image
imagePosition: "center"              # CSS object-position (e.g. "top", "bottom 20%")
tags: ["tag1", "tag2"]               # Default: []
category: "Tech"                     # Optional
draft: false                         # true = hidden in production
pinned: false                        # true = pinned to top
---

Draft System

Draft posts are visible during development (npm run dev) but automatically hidden in production builds. Use this to work on posts before publishing.

Post Images

Place cover images in public/assets/posts_picture/ with sequential numeric names (e.g. 1.webp, 2.webp). Use the imagePosition field to control which part of the image is visible as the cover crop.

Knowledge Base

Add .md or .mdx files to src/content/docs/ for long-form articles and documentation. They appear under the /docs section with a sidebar navigation tree.


Commands

Command Description
npm run dev Scan music + start dev server at localhost:3000
npm run build Scan music + production build + Pagefind search index
npm run preview Preview production build locally
npm run scan-music Scan music files and generate playlist
npm run lint Lint source files with ESLint
npm run format Format code with Prettier
npm test Run tests with Vitest

Music Player

Signal Chain

MediaElement → Gain(ReplayGain) → DynamicsCompressor → Crossfeed → Analyser → Destination

Quality Tiers

Tier Criteria Badge
Studio Master > 96kHz / 24bit SM
Hi-Res Lossless > 48kHz / 24bit HR
CD Quality 44.1kHz / 16bit CD
Standard Lossless 44.1kHz / 16bit
High-bitrate Lossy > 256kbps
Standard Lossy > 128kbps
Low-bitrate Lossy < 128kbps

Adding Music

  1. Place audio files in public/assets/music/url/
  2. Run npm run scan-music
  3. Covers are auto-extracted to public/assets/music/cover/
  4. Playlist is generated at public/api/music-playlist.json

The scanner reads embedded metadata (title, artist, album, year, genre, composer, track number, ReplayGain) using the music-metadata library. Format detection uses magic bytes — file extensions don't matter.

NetEase Cloud Music

Log in via the music library sidebar to import your NetEase Cloud Music playlists. Imported playlists can be merged into the local library, making NCM tracks appear alongside local files in Browse, Artists, Albums, and Years views. Song URLs are resolved on-demand when playback starts.


Configuration

Personalize your site by editing these files:

File Purpose
src/config/siteConfig.ts Title, subtitle, URL, theme hue, layout options
src/config/profileConfig.ts Your name, bio, avatar, social links
src/config/navBarConfig.ts Navigation bar visibility toggles
src/config/musicPlayerConfig.ts Music player on/off
astro.config.ts Production site URL, PWA manifest

Assets to replace:

Path What it is
public/assets/avatar.png Your avatar (or remove — a letter placeholder will appear)
public/assets/wallpaper/ Homepage banner wallpapers (.webp, 1920×1080)
public/assets/hero-wallpaper/ Hero section background carousel
public/assets/music/url/ Local audio files for the music player
public/assets/posts_picture/ Post cover images

CSS Design Tokens

All colors derive from a single --hue CSS variable using OKLCH color space. Change one number to recolor the entire site:

:root {
  --hue: 250; /* Purple-blue by default */
  --primary: oklch(65% 0.25 var(--hue));
}

Project Structure

sorbellar/
├── public/
│   ├── assets/
│   │   ├── font/                    # Self-hosted fonts (woff2)
│   │   ├── hero-wallpaper/          # Hero wallpapers (desktop/ + mobile/)
│   │   ├── music/
│   │   │   ├── url/                 # Audio files (place your music here)
│   │   │   └── cover/               # Cover art (auto-extracted)
│   │   ├── posts_picture/           # Blog post cover images
│   │   └── wallpaper/               # Page wallpaper carousel
│   ├── api/
│   │   └── music-playlist.json      # Playlist API (auto-generated)
│   └── js/                          # Client-side scripts (public, not bundled)
│       ├── hero.js                  # Hero timing, typewriter, parallax
│       ├── hero-wave-colors.js      # Canvas color extraction → wave tint
│       ├── particles-multi.js       # Multi-layer particle engine (3 canvases)
│       ├── music-player.js          # Web Audio API engine
│       ├── music-player-library.js  # Library browser UI
│       ├── gallery-lightbox.js      # Image lightbox
│       ├── sakura.js                # Cherry blossom particles
│       └── ...
├── scripts/                         # Build helpers
│   ├── scan-music.mjs               # Music metadata scanner
│   ├── generate-responsive-wallpapers.mjs
│   └── ...
├── src/
│   ├── __tests__/                   # Test files (Vitest)
│   ├── components/                  # Astro components
│   │   ├── archive/                 # Archive page components
│   │   ├── music/                   # Music player components
│   │   ├── HeroSection.astro        # Hero full-screen cover
│   │   ├── Navbar.astro             # Navigation bar
│   │   ├── Footer.astro             # Page footer
│   │   ├── MusicPlayer.astro        # Music player shell
│   │   └── ...
│   ├── config/                      # Site configuration files
│   ├── content/                     # Blog posts and docs (Markdown / MDX)
│   ├── i18n/                        # UI translation strings (zh-CN, en)
│   ├── integrations/                # Astro integrations (wallpaper gen, NCM server)
│   ├── layouts/                     # Page layouts
│   ├── pages/                       # Route pages
│   ├── plugins/                     # Remark / Rehype plugins (12 files)
│   ├── scripts/                     # Client-side TypeScript modules (Vite-bundled)
│   │   ├── archive/                 # Archive logic (river-math, drag, tabs)
│   │   ├── music-player/            # Music player UI, progress bar
│   │   ├── modules/                 # NCM integration
│   │   └── client/                  # Client app entry point
│   ├── styles/                      # CSS design system
│   ├── types/                       # TypeScript type definitions
│   └── utils/                       # Utility functions (dates, slugs, links)
├── astro.config.ts
├── package.json
└── package-lock.json

Markdown Extensions

Beyond standard GitHub Flavored Markdown, this template supports:

Extension Syntax Description
Admonitions :::note / :::warning etc. 5 types of callout boxes
Math $E=mc^2$ / $$\int$$ LaTeX via KaTeX + MathJax
Diagrams ```mermaid Flowcharts, sequence, Gantt
GitHub Cards :github[user/repo] Repository info cards
Image Width ![desc w-400 center](url) Custom width + centering
Code Blocks ```lang Line numbers, copy, collapse

Deployment

Vercel

Push to GitHub and import the repo into Vercel. No configuration required.

GitHub Pages

npm run build
# Deploy dist/ to the gh-pages branch

Update site in astro.config.ts and siteURL in src/config/siteConfig.ts to match your GitHub Pages URL.

Cloudflare Pages

npm run build
# Deploy the dist/ directory via Cloudflare dashboard or wrangler CLI

No environment variables required. The project works out of the box with zero configuration for deployment.


Acknowledgements

  • Built with Astro — the best static site framework
  • Fonts: LXGW WenKai (Chinese), JetBrains Mono Nerd Font (code)
  • Math: KaTeX + MathJax
  • Search: Pagefind
  • Inspiration: Roon (music UI), Apple Music (library browser), foobar2000 (DSP), Kirameku (archive river)

License

Code: MIT — use it, modify it, learn from it.


If you find this project helpful, please consider giving it a star!

About

My personal blog template. Built with Astro.

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages