Tech News
← Back to articles

I used Claude Code to write a piano web app

read original related products more articles

I recently grabbed myself a Claude Max subscription in hopes to enhance my workflow after spending a year using OpenAI tokens here and there to get assistance with specific problems. Having a new tool at my disposal, I wanted to try to make a start to finish project with it to put it through its paces. I decided I'd have it help me write a piano web app. Below are the exact prompts that I used to have the piano made. I did omit a few where I changed the database engine because Postgres was giving me a hard time on my VPS, but that is another story.

To start, I created a new Rails application by running rails new PianoWebApp . I popped open VS Code and opened the newly formed directory then got started with Claude. I told it that it was in an empty Rails application, then explained what I wanted and gave it some basic scaffolding for database structure and let it get to work.

This is an empty rails app, I want to make an piano webapp in it. Add the ability for users to record their songs. To do this create a database table called “recordings”, and another table called “notes”. The recordings table will have an “id” column. The notes table will have an “id”, “recording_id”, “note”, and “ms” columns. The note column will be which note was played, and the ms column will be how long in milliseconds after the recording started the user played the note. Allow users to visit their past recordings by navigating to /play/:id. This end point will have play/pause/stop controls to play back the recording based on which note was played and when.

This alone gave me 90% of the finished product. It generated a simple UI that looked like a keyboard, it generated the javascript code to capture clicks and keypresses to play the appropriate note. It created the appropriate database migrations, routes, controllers, and models for saving recordings and playing them back. I was gobsmacked that a couple of sentences could result in almost exactly what I was looking for. There were a couple of changes and enhancements that I wanted to add though.

The originally generated code displayed the recording ID as the main header on the playback page. This felt half-baked so I asked it to give the user the ability to name their recording. I didn't bother telling it where to store the name, or what to call the column. It generated another migration to save the name, added the ability to give recordings a name, and displayed the name of the recording on the playback page.

Add the ability for users to name their recording, if they to not give their recording a name just name it the id of the recording.

It did however show the option to name the recording before a recording was created though, which felt like bad UX. As a user why would I want to name a recording that doesn't exist? So I asked Claude to make the text field to name the recording hidden until recording was completed.

Don’t show the recording name option until after the user finished recording.

It did, perfectly. I then figured no reason to keep the code hidden, so I asked it to put a link to the GitHub repository on the page in the footer, and asked for it to include the Octocat logo. I wasn't sure how it would go about adding the logo, but figured it'd be an interesting test at the least.

Add a link to the github repository (https://github.com/Jeremy1026/web-piano) in the footer of the site. Include the github logo and have the link text say “View on Github”

... continue reading