Music website for Jade Three — a chronological showcase of releases with Spotify embeds, platform links, and song notes.
Built with Astro and Tailwind CSS. Deployed on Netlify at jadethreemusic.com.
npm install
npm run dev # dev server at localhost:4321
npm run build # production build
npm run preview # preview production build| Path | Purpose |
|---|---|
src/data/releases.json | All release data — platform links, track data |
src/content/songs/*.md | Per-song notes and metadata |
src/content/artist/profile.md | Artist bio/profile |
src/components/ | Astro UI components |
clips.yaml | Approved/sent Bluesky clips |
scripts/ | Data-fetching and posting scripts |
Run the /new-release skill in Claude Code. It walks through the full workflow:
- Syncs release data from iTunes (
npm run fetch-releases) - Identifies which releases don't have a song page yet
- Asks for any missing platform URLs (Spotify, YouTube)
- Creates
src/content/songs/<slug>.mdwith frontmatter - Conducts a short interview and writes the answers into the file
- Generates Bluesky clips for the new song
To start: open Claude Code in this directory and type /new-release.
To pull the latest iTunes data without going through the full workflow:
npm run fetch-releases # syncs from iTunes (no credentials required)This preserves any existing Spotify/YouTube/Amazon links in releases.json.
npm test# Playwright end-to-end tests
npm run test:scripts # unit tests for post-clip.mjsscripts/post-clip.mjs picks a random approved, unsent clip from clips.yaml and posts it to Bluesky with a link card. A launchd job (scripts/com.jade.jade3-to-bluesky.plist) runs this automatically on Tue/Thu/Sat at 1:14 PM.
scripts/generate-clips.mjs uses Claude to generate social media clips for each song from its markdown notes in src/content/songs/. Output is written to clips.yaml.
node scripts/generate-clips.mjs # all songs
node scripts/generate-clips.mjs stinger # one song by slugRe-running skips songs that already have entries in clips.yaml. To regenerate a song, delete its entry first.
- Log into Bluesky
- Go to Settings → Privacy and Security → App Passwords
- Create a new app password and copy it
export BLUESKY_HANDLE=yourhandle.bsky.social
export BLUESKY_APP_PASSWORD=xxxx-xxxx-xxxx-xxxxEach clip has two flags:
- approved: false # set to true to make eligible for postingsent: false # updated automatically after posting — don't change by handtext: | Your post text here. https://jadethreemusic.com/releases/your-songSet approved: true on any clips you want to post. Leave sent alone — the script flips it to true automatically after a successful post.
node scripts/post-clip.mjs --dry-runPrints the clip that would be posted without sending anything.
node scripts/post-clip.mjsPicks one eligible clip at random, posts it to Bluesky with a link card, then marks it sent: true in clips.yaml. Commit the updated clips.yaml afterward to keep the record in sync.