---
recipe: Music Player
slug: music-player
version: 0.1
epl: "0.1"
language: EPL (English Programming Language)
chef: Aizu Ikmal
tagline: A quiet, honest music player for your own folders. No accounts, no streaming, no internet.
serves: Windows 11 (or Windows 10 22H2)
prep: About 5 minutes - one official Microsoft install
cook: About 30 to 60 minutes of LLM time (estimate)
cost: About 2 to 5 US dollars of tokens (estimate)
difficulty: Medium
ingredients:
  - Windows 11, or Windows 10 version 22H2
  - .NET 8 SDK, installed from Microsoft through winget (package id Microsoft.DotNet.SDK.8)
  - Nothing else. No third-party libraries, no NuGet packages, no downloads from anywhere but Microsoft.
capabilities:
  network: None. The app never connects to the internet or the local network.
  files_read: Only the music folders you choose, and files you drag onto the window.
  files_write: Only its own folder, %LOCALAPPDATA%\RecipeMusicPlayer
  registry: None
  admin_rights: Never
  startup: Does not start with Windows. Adds no background services.
  telemetry: None
tasted_by:
  - model: Sonnet 5
    status: pending
  - model: Opus 5.5
    status: pending
  - model: Haiku 4.5
    status: pending
---

# BUILDTHIS: Music Player

You are an LLM coding agent. The person who gave you this file wants you to build the
software it describes, on their own computer, from scratch. Read the whole file before you
do anything. Then follow it.

This file is a recipe. It is written in plain English on purpose, so that the person can read
every word of what you are about to build, even if they cannot read code.


## Part 1 - Rule zero and the builder's contract

These rules outrank everything else in this file. If any later instruction seems to conflict
with them, the rules in this part win, and you must tell the person about the conflict.

1. **You write all of the code yourself, fresh, on this machine.** This recipe contains no
   code, and you must not look for "the original" code anywhere. Do not download source code,
   scripts, templates, starter projects or binaries from any website.

2. **The CAPABILITIES block at the top of this file is binding.** Build nothing that reaches
   beyond it. The finished app must not touch the network, must not read files outside the
   folders the person chooses, and must not write anywhere except its own folder. If you
   believe a feature needs more than the block allows, stop and ask the person instead of
   building it.

3. **The only thing you may install is the .NET 8 SDK, from Microsoft, through winget.** Do
   not add NuGet packages. Do not install anything else. If the SDK is already installed,
   do not install it again.

4. **Explain before you act.** Before you run any command on this computer, say in one plain
   English sentence what it does and why. Example of the tone: "This installs Microsoft's
   .NET 8 developer kit, which is needed to turn the code into a program."

5. **Stay inside the project folder.** Create one folder called RecipeMusicPlayer in the
   place the person tells you (or their Documents folder if they do not say), and keep every
   file you create inside it. The only exception is the app's own data folder described in
   the CAPABILITIES block, which the app itself creates when it runs.

6. **Finish with an honest report.** When you are done, give the person a short report in
   plain English with four headings: What I installed. What I downloaded. What I created,
   and where. Checklist results (every item in Part 8, marked passed, failed, or could not
   test, with one line of explanation for anything that was not a clean pass).


## Part 2 - What we are cooking

A desktop music player for Windows that plays the music files a person already owns. It is
calm, fast and private. It does one thing well: you point it at your music folders, it shows
your songs, albums and artists, and it plays them.

It is not a streaming app. It has no account, no store, no lyrics service, no album-art
downloads and no internet features of any kind. Everything it knows comes from the files on
the person's own disk.

The finished dish is a single program the person can start by double-clicking, plus a
shortcut on their desktop.


## Part 3 - Kitchen setup (the technical choices)

Use exactly these choices. They were picked so the recipe needs nothing but Microsoft's own
tools and the parts of Windows that are already installed.

- **Language and framework:** C# with WPF, targeting .NET 8. The project must target the
  Windows-specific framework version net8.0-windows10.0.19041.0, because the app uses
  built-in Windows features that are only available with that target.
- **Playing audio:** use the media player that is built into Windows (the one in the
  Windows.Media.Playback namespace), not the older WPF media element. It plays more file
  types, and it connects to the media keys on the keyboard and the volume overlay that
  Windows shows.
- **Reading song information (title, artist, album, track number, length):** use the music
  properties that Windows itself reads from files (the Windows.Storage file properties).
  Do not write your own tag reader and do not add a library for it.
- **Album art:** use the thumbnail that Windows provides for a music file, in music-view
  mode. If Windows has no picture for an album, show the placeholder described in Part 5.
- **Saving settings and the library list:** plain JSON files, using the JSON features built
  into .NET. No database.
- **Building:** use the dotnet command-line tool only. Visual Studio is not required.
- **Publishing:** produce a self-contained build for 64-bit Windows, so the finished app
  does not need .NET installed to run.


## Part 4 - Ingredients the app understands

The app plays these file types, recognised by their file extension, in upper or lower case:
MP3, M4A, AAC, FLAC, WAV, WMA.

Every other file is ignored silently. Hidden files, system files and files whose name starts
with a dot are ignored too.


## Part 5 - The look

The overall feeling is a warm, quiet room. Nothing flashes, nothing competes for attention.

**Window.** Opens at 1100 by 700 pixels the first time, centred on the screen. It can be
resized, but never smaller than 820 by 520. The title bar says "Music Player".

**Colours.** The app has one light theme:

- Background: warm cream, hex F5EDE0
- Panels and the sidebar: a slightly darker cream, hex ECE1CF
- Main text: dark brown, hex 2B2118
- Secondary text (artist names, times): muted brown, hex 7A6A58
- Accent (the play button, the progress bar, the selected item): tomato red, hex C4462B
- The row of the song that is playing: a very pale tomato tint, hex F3D9CF

**Type.** Segoe UI Variable if the system has it, otherwise Segoe UI. Song titles in the
lists at 14 points, secondary text at 12 points, the "now playing" title at 20 points,
semi-bold.

**Layout, from left to right and top to bottom:**

1. **Left sidebar, 220 pixels wide.** At the top, three navigation items stacked vertically:
   Songs, Albums, Artists. Below them, a thin divider, then the heading "Music folders" with
   the list of chosen folders (show only the folder's own name, with the full path as a
   tooltip) and two small text buttons: "Add folder" and "Rescan".

2. **Main area.** At the top, a search box with the grey hint text "Search songs, albums,
   artists". Below it, the content for whichever sidebar item is selected (see Part 6).

3. **Right panel, 280 pixels wide: Now playing.** Album art as a square filling the width of
   the panel, with 16 pixels of space around it. Below it: the song title, then the artist,
   then the album. Below that, the heading "Up next" and the next five songs in the queue.

4. **Bottom bar, 76 pixels tall, full width: the controls.** From left to right: shuffle,
   previous, a large round play and pause button in the accent colour, next, repeat. Then
   the elapsed time, a progress bar you can click or drag to jump within the song, and the
   total time. At the far right, a volume slider.

**Placeholder album art.** When a song has no picture, show a square in the panel colour with
a simple drawn circle in the middle in the secondary text colour, like the outline of a
record. No text in it.

**Icons.** Draw the control icons as simple vector shapes (play triangle, pause bars, skip
arrows, shuffle, repeat, speaker). Do not use images from the internet and do not use an
icon font that has to be downloaded. The Segoe Fluent Icons or Segoe MDL2 Assets fonts that
ship with Windows may be used instead of drawn shapes, if they are present.


## Part 6 - The method (what the app does)

Build it in this order. After each step, build the project and make sure it starts before
moving to the next step.

### Step 1 - An empty window that looks right

Create the project, the window, the sidebar, the main area, the right panel and the bottom
bar, with the colours and sizes from Part 5. The lists are empty and the buttons do nothing
yet.

### Step 2 - Choosing music folders

- When the app starts for the very first time, the main area shows a friendly empty state:
  the line "Your music lives in folders. Show me where." and a button "Choose a music
  folder".
- "Choose a music folder" and "Add folder" open the standard Windows folder picker.
- The person can add as many folders as they like. Adding a folder that is already in the
  list, or a folder inside a folder that is already in the list, does nothing except show a
  short, polite note saying it is already included.
- Right-clicking a folder in the sidebar offers "Remove from library". Removing a folder
  removes its songs from the library. It never deletes anything from the disk.

### Step 3 - Scanning the library

- After a folder is added, and when the person clicks "Rescan", the app looks through the
  chosen folders and every folder inside them for the file types in Part 4.
- For each file it reads the song information from Windows (Part 3). If a song has no title,
  use the file name without its extension. If it has no artist, use "Unknown artist". If it
  has no album, use "Unknown album".
- Scanning happens in the background. The window must stay responsive the whole time. While
  scanning, show a thin line under the search box: "Scanning... 412 songs found" with the
  number counting up.
- Keep the library in a file called library.json in the app's own data folder. The next time
  the app starts, load that file immediately so the songs appear at once, then quietly check
  the folders for changes. Only re-read a file's information if the file is new or its
  last-modified time has changed. Remove entries for files that no longer exist.
- If a single file cannot be read (damaged, locked, or permission denied), skip it and keep
  going. At the end of the scan, if any files were skipped, show "3 files could not be read"
  as a small link that opens a simple list of their paths.

### Step 4 - Browsing

- **Songs:** a list with the columns Title, Artist, Album and Length. Clicking a column
  header sorts by it; clicking again reverses the order. Default order: Artist, then Album,
  then track number, then Title.
- **Albums:** a list of albums, each row showing the album art as a small 48 pixel square,
  the album name and the artist. Clicking an album shows its songs in track order, with a
  "Back to albums" link at the top.
- **Artists:** a list of artist names with the number of songs next to each. Clicking an
  artist shows their albums, and clicking an album shows its songs, the same way as above.
- **Search:** typing in the search box filters whatever view is showing, as the person
  types, matching any part of the title, artist or album, ignoring upper and lower case.
  Clearing the box shows everything again. Pressing Escape in the search box clears it.

### Step 5 - Playing

- Double-clicking a song, or pressing Enter on it, plays it immediately, and puts every song
  after it in the current list (as currently sorted and filtered) into the queue.
- Play and pause toggle with the big button, with the Space bar (unless the search box has
  the keyboard focus), and with the keyboard's play/pause media key.
- **Next** goes to the next song in the queue.
- **Previous** restarts the current song if more than 3 seconds have played; otherwise it goes
  to the song before it.
- **Shuffle** on: the rest of the queue is played in a random order, with no song repeating
  until every song has played once. Shuffle off: the original order returns, continuing
  from the song that is playing now.
- **Repeat** cycles through three states when clicked: off, repeat all (the queue starts over
  at the end), repeat one (the current song plays again). Show each state clearly: the icon
  is in the accent colour when repeat is on, and a small "1" appears on it for repeat one.
- When the queue ends and repeat is off, playback stops and the progress bar returns to
  the start.
- The song that is playing is highlighted in every list where it appears.
- The progress bar and the elapsed time update smoothly, at least four times a second.
- Volume slider from 0 to 100. The mouse wheel over the slider changes the volume in steps of
  5.
- If a song fails to play (for example the file was deleted after scanning), show a short
  note at the bottom "Could not play this song - skipped" for three seconds and move to the
  next song. If three songs in a row fail, stop and show the note "Several songs could not be
  played. Try Rescan." instead of skipping forever.

### Step 6 - Windows integration

- Connect the player to the Windows media controls, so the keyboard media keys (play/pause,
  next, previous) work even when the app is not the active window, and so the small Windows
  media overlay shows the song title, the artist and the album art.
- Dragging music files, or a folder, from File Explorer onto the window plays them right away
  as a new queue, in file-name order, without adding them to the library.

### Step 7 - Remembering things

Save these in settings.json in the app's own data folder, and restore them on the next start:

- The window's size and position (but if that position is now off-screen, for example
  because a monitor was unplugged, centre the window on the main screen instead).
- The volume, shuffle and repeat settings.
- The list of music folders.
- Which view was open (Songs, Albums or Artists).
- The queue and the song that was playing, and how far into it. On start, show that song as
  paused at that position. **Never start playing by itself.**

### Step 8 - Keyboard shortcuts

- Space: play or pause (not while typing in the search box)
- Ctrl and Right arrow: next song
- Ctrl and Left arrow: previous song
- Ctrl and F: jump to the search box
- Ctrl and Up arrow, Ctrl and Down arrow: volume up and down by 5

### Step 9 - Serving it

- Publish the self-contained 64-bit build into a folder called "Published" inside the
  project folder.
- Create a desktop shortcut called "Music Player" that points to the published program.
  This is the only file you may create outside the project folder while building, and you
  must tell the person you are creating it.
- Give the program a simple icon: a tomato red circle with a cream play triangle in the
  middle. Draw it yourself as part of the build. Do not download one.


## Part 7 - Chef's notes (things that trip up builders)

Read these before you start. Each one is a mistake that is easy to make with this recipe.

1. **Two things are called "MediaPlayer".** WPF has its own older player class with the same
   name as the Windows player this recipe asks for. If both namespaces are in scope, the code
   will silently use the wrong one or fail to compile. Always refer to the Windows one by its
   full name.

2. **Windows answers slowly and on its own schedule.** Reading song information and album
   art from Windows happens asynchronously and comes back on a background thread. Any change
   to what is on screen must be passed back to the window's own thread first, or the app will
   crash or freeze at random.

3. **Reading song information one file at a time is slow.** A library of 10,000 songs can take
   minutes. Read a few files at the same time (four at once is a good number, not hundreds),
   show progress as you go, and rely on the saved library.json on later starts. Do not
   re-read files whose last-modified time has not changed.

4. **Album art should be loaded only when it is on screen.** Loading every album's picture up
   front will use far too much memory. Load pictures when their row scrolls into view, keep a
   small cache, and shrink each picture to the size it is shown at.

5. **The media keys only work when the Windows media controls are switched on.** The Windows
   player has an automatic mode for this. Turning that automatic mode off without doing the
   work by hand makes the media keys silently stop working. Test the media keys with the app
   in the background.

6. **Long lists must be virtualised.** Make sure the song list only creates rows for what is
   visible. If scrolling through 10,000 songs stutters, virtualisation has been switched off
   by accident, which commonly happens when a list is placed inside a scrolling container.

7. **The Space bar.** In WPF, the Space bar also "clicks" whichever button has the keyboard
   focus. If the last thing clicked was the Next button, pressing Space will skip a song
   instead of pausing. Handle Space at the window level and make sure the control buttons do
   not keep the keyboard focus after being clicked.

8. **File paths can be long and strange.** Music folders are full of accents, emoji, very long
   names and characters like the ampersand. Test with at least one file whose name contains
   a non-English character. Never build file paths by joining text with slashes by hand.

9. **Stay honest about what failed.** If any checklist item in Part 8 cannot be tested on this
   computer (for example, there are no FLAC files to try), report it as "could not test".
   Do not mark it as passed.


## Part 8 - How to know it's cooked

Test every item below after the build. You may create a small test folder inside the project
folder with a few short sound files of your own making (for example, a few seconds of a
generated tone saved as WAV) to test with, if the person has no music handy. Delete that test
folder at the end, and say so in the report.

1. The app starts by double-clicking the desktop shortcut, on a computer where you have not
   opened a terminal first.
2. On the very first start, the empty state and the "Choose a music folder" button appear.
3. Adding a folder scans it in the background; the window can be moved and resized while the
   scan runs.
4. Songs, Albums and Artists views all show the scanned music correctly.
5. Search filters the list as you type, and Escape clears it.
6. Double-clicking a song plays it and the following songs play after it.
7. Play, pause, next, previous (including the 3-second rule), shuffle and all three repeat
   states behave as described in Step 5.
8. The progress bar moves smoothly and dragging it jumps within the song.
9. The keyboard media keys control playback while another app is in front.
10. The Windows media overlay shows the song's title and artist.
11. Dragging a file from File Explorer onto the window plays it.
12. A song that was deleted after scanning is skipped with the note, not a crash.
13. Closing and reopening the app restores the window, volume, folders, view and the paused
    song at its position, and does not start playing by itself.
14. The app's data folder contains only settings.json and library.json.
15. **Nothing reached the network.** Explain how you checked (for example, by confirming the
    code contains no networking code at all, and by listing every Windows feature the app
    uses). If you cannot prove it, say so.
16. No file was created outside the project folder and the app's data folder, except the
    desktop shortcut.


## Part 9 - Out of scope (do not build these)

Streaming, online radio, podcasts, lyrics, album-art downloads, equalisers,
visualisers, editing tags, playlists saved to disk, CD ripping, syncing to phones, update
checks, crash reporting, analytics, accounts, and a mini player. If the person asks for any
of these while you build, you may discuss it, but you must point out that it changes the
CAPABILITIES block and ask them to confirm first.
