3D iPod with Live Music Data

Sept. - Oct. 2024

Embed this on Your Website

(Check the comments for instructions)

Rationale:

Listening to music has been a hobby of mine for as long as I can remember. According to Spotify, I listened to 2126 hours in 2021, 2198 hours in 2022, 1500 hours in 2023, and 1170 hours in 2024. I've always dedicated time to social aspects of music like seeing what others are listening to and comparing playlists with one another. While designing my website, I wanted something to reflect this long-standing enthusiasm for music. I've also always had an inexplicable nostalgia for old technologies like the iPhone 3GS, Nintendo DS, and the iPod. With this in mind, I set out to create an interactive iPod model for my website that displays what I am listening to in real-time.

Initial Goals:

  • Final model has features resembling an iPod

  • Updates in Real-Time (using API)

    • Shows real-time, now playing music metadata such as song and album cover (last played song if nothing is currently playing)

    • Has a live progress bar with timestamps

    • Shows the total number of plays

    • Displays the current time

  • Has interactive 3D features

Choosing the Modeling Software:

The first software that came to mind was Blender. I had some prior experience with it and it does have some kind of API compatibility. However, upon looking into it, Blender's web integration is not great (uses many plugins and workarounds) and their API usage is limited. Additionally, pushing edits from the model to the website would have been tedious.


Then, I came across Spline 3D, a similar modeling software tailored specifically toward web developers and applications. It has a great web integration (HTML/CSS, React, Three JS, etc.), a seamless and well-documented API, and a plethora of online tutorials. With that, I began the process of creating my interactive iPod rendering.


Part 1: Crafting the Model

The first part of the project was creating the model itself. I drew inspiration from many different iterations of the iPod such as the mini, the class, and the nano, drawing from features like the screen

Pictures I drew ideas from

The model in various stages


The longest part of the process was learning a 3D software I had no experience with. Spline was great in that it was extremely intuitive (felt like Figma in 3D) and I could paste pictures for references while I modeled the iPod. I began crafting it with a matte silver finish in mind however through a meticulous and well-ordered process of discovery (messing around with as many settings as possible), I found the glossy black look far more suitable for the color scheme of my website. Here is my Spline model online for your reference.


Part 2: Configuring & Integrating the API

My first choice was to use Spotify's API since the music data would be coming directly from the source. However, it has a pedantic OAuth 2.0 flow that requires exchanging a client secret for a token that is only valid for an hour. Spline's API integration also only allows a single method (GET, POST, DELETE, etc.) paired with one link and its headers, not any kind of code or logic that could make use of Spotify's API.


Having been a long-time user of last.fm (one of the largest online music databases), I knew that its API could solve this issue. It would function similarly to Spotify's API since my Spotify account is connected to last.fm, only I could retrieve the data I wanted using GET from the method user.getRecentTracks (outlined in their API documentation):


https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user={USERNAME}&api_key={API_KEY}&format=json


This returns a wealth of useful data including the last 50 songs I listened to, the song I am currently listening to, the artist who made it, links to the images of album covers, and my total all-time plays on last.fm. All that was left to do was parse the data and assign it to variables on the model.


Part 3: Variable Setup & Timing

I wanted a six key variables on the model:


  1. Text reads either "Now Playing" or "Last Played"

  2. The track that was currently playing (or last played)

  3. The artist that made the track

  4. The album cover of the track playing (or last played)

  5. A live progress bar on the track (or where it was last)

  6. The current time in my timezone


The logic for setting up 1, 2, 3 and 6 were fairly simple. Create variables named Artist, Track, NowPlaying, and Time. Time is just the current time and updates automatically from Spline.



The logic was quite simple: on start, make an API request to getRecentTracks and then set variable Track to the track name from getRecentTracks. Similar logic follows for the artist. I also just needed to create a text variable and bind it to Time to display the time. The API response also contained a boolean nowplaying which meant I just needed to check if it was true or false and set the text accordingly.



Now, to keep the Track, Artist, and NowPlaying updating, I had to setup logic such that whenever the Time variable changed (every second), I would make another API request and update the variables accordingly.



For variables 4 and 5 (the album covers and progress bar), I ran into technical roadblocks. Spline doesn't currently support dynamic images and variables so unfortunately I had to scrap this goal. With the progress bar, last.fm's API call doesn't specifically give me this information and I could only make a single API call at a time so this had to be scrapped as well.


However, in the end, I had a great model of an iPod that displays track, artist, nowplaying, and time data in real-time.


Part 4: Optimization & Web Integration

When I set out to export the model and begin testing it, I ran into performance issues with load times and lag. I ran a test on it and found that there were too many polygons and textures. I assumed this was due to the level of detail I used on the iPod. Attempting to render the curvatures of the edges and the headphone jack likely slowed down the time it took for it to completely load.

To solve this, I simply reduced the level of subdivisions on the iPod and removed the headphone jack. Though it compromised the aesthetics slightly, the load times were significantly faster and it was ready to be embedded on the web. Spline's export features made it simple to embed on a website in its native viewer. All I had to do was create an embed shape in Framer and paste in the HTML code.


And voila! The embedded iPod model was ready to be viewed on my website!


Part 5: Reflection & Limitations

Overall this project was unexpectedly fun. Figuring out workarounds every time I hit a roadblock was exhilarating and seeing it come to fruition was a feeling like no other. I learned how to use Spline 3D, last.fm's API, and how to integrate and optimize both.


However, the project, like any other, comes with its set of limitations. The most significant (and most annoying) is the text overflow that happens when the song title or artist are too long. Similarly, on the topic of fonts, when I listen to songs that don't use the Latin character set, the font occasionally won't render in.



For the text overflow, I considered nearly every solution. There is no support for text truncation in Spline's native software, so I had to rule that out. I thought about making a variable that changes based on the length of the track and creating logic that adjusts the size of NowPlayingTrack font but Spline also doesn't support this. I thought about a solution that mimics the actual iPod wherein long text loops around (marquee text effect) but again, this needs logic to work. Long story short, there seems to be no solution in Spline at the moment.


There is one solution where I would program my own backend that handles the last.fm API request and truncates the text automatically and then, it would forward that request to Spline. However, this adds completely new layer to my project and the goal is optimization, not to mention I would have to pay to host my own backend. Similarly, for non-Latin characters, setting up my own backend would be the most straightforward solution. I would pass it through a translator API, but then again, I do not wish to go down this route.


Either case are quite rare though; the character limit for overflow is ~45 characters (give or take) and I don't listen to songs without the Latin character set very frequently either. In fact, sometimes the text is automatically translated (from last.fm's API I presume), so it does not seem worthwhile to fix these limitations for the time being.


Part 6: Reiteration and Tweaks

The text overflow and the lack of support for the non-Latin character set ended up irking me far more than I thought. The most straightfoward solution seemed to be hosting my own web service with text truncation and transliteration logic. With my own service, I could also parse multiple API calls simultaneously which last.fm's API did not support. I could also add a new feature: displaying how many plays I have on a specific song. Since this data isn't part of the user.getRecentTracks method, I could not achieve this with my previous approach. However, with my own hosted web service, I can integrate these features along with any other logic I might need. I also found mulitple services that allow me to do this for free.


New Goals

  • Make any necessary aesthetic adjustments

  • Create a web service / backend with the following features:

    • Maintains all previous features

    • Text truncation logic that prevents messy overflow

    • Transliteration logic that allows non-Latin characters to be displayed

    • Merges multiple API calls (user.getRecentTracks, track.getInfo, etc.)

    • On-demand fetching for efficiency and modularity

    • No associated cost (ideally)


Aesthetic Changes

Until this point, I had been using a matte finish on the iPod. The model overall bore resemblance to the iPod but lacked some texture or finish that made the model feel unnatural. I could not figure out what it was until I browsed other models on Spline and figured it out: it needed a matcap finish.


Once I added the texture, the new model had a much glossier, Apple-like finish.


Old, matte finish

New, glossy finish


Setting Up the Backend

To make my hosted web service, I first needed to choose a framework that allows me to parse API calls, apply my own logic and transforms to them, and return them in the same JSON format. I chose Node.js to implement my API endpoint backend. It's asynchronous, simple, and scalable. It worked perfectly for what I needed to do and didn't require any complex dependencies nor did it have a difficult learning curve.


I won't go too far in-depth about the code, but simply put, I had two functions: Truncate Text and Fetch Track Details. As the name implies, Fetch Track Details retrieves the information from last.fm's API, including the title, artist, album, playcount, and a lot of other metadata. Truncate Text transliterates and truncates the text to be properly displayed. The cutoff was set at 43 characters. Here is my github repo if you would like to see more.


After the code worked successfully in local testing, I moved on to finding a hosting service. Render.com was the ideal option as it offered a free plan for the services I needed. It offered a seamless connection to my GitHub repository and was super easy to deploy.



You can check out the web service in real-time at:


https://ipod-backend.onrender.com/current-track


Finally, I updated the Spline 3D model with this API link and assigned the proper variables after parsing the JSON file.


The Final Product