Transcript: Vibe Coding a Crystal Ball

Transcripts are meant to be a reflection on a specific LLM interaction, exploring the context, learnings, and providing a concrete example of making something with AI
What I Made
Riding the high of my coming back post, I came across this reddit post, and I had the goofy idea to make a website to do this. I dunno why, just cause. So I did pure vibe coding in less than an hour. Introducing: Crystal Ball
A Tangent on Vibe Coding
If you’re new to the phrase vibe coding:
Vibe coding (also written as vibecoding) is a recently-coined term for the practice of writing code, making web pages, or creating apps, by just telling an AI program what you want, and letting it create the product for you. In vibe coding the coder does not need to understand how or why the code works, and often will have to accept that a certain number of bugs and glitches will be present. The verb form of the word is vibe code.
We use ‘vibe coding’ in a derogatory/derisive way, but it’s specific to this discovery period. We’re all playing around with these tools, trying to reinvent how we work, and many of us are failing and making mistakes as we go. There have been leaks of OpenAI API keys from vibe coders who had probably never dealt with integrating a third-party tool (which is not that uncommon) or who failed to properly review the work done by the LLM (which is easy to do if you don’t have the effective workflows in place).
Just this week, one of my friends called me a vibe coder when I mentioned I hadn’t written any code in weeks. I felt defensive because I wanted to think I was working with more structure than other vibe coders. But everyone labeled a ‘vibe coder’ is a person failing, publicly, to use a tool that we collectively don’t know how to use yet, and that’s equally threatening to change the fabric of our work. Cheers to vibe coding in public 🥂
What I Learned
Whimsy
It’s much easier for me to follow my whimsy. I’ve always enjoyed the silly things people make just cause they want to, but building a simple website has always been challenging for me. There are a lot of details to create even something simple, and I tend to think more about the shapes, structures, and systems of things rather than the focused details. Even in college, I was the integrator. The one who got all the pieces to work together after everyone else wrote them. Using an LLM meant I could build something whimsical by just expressing the shape of what I wanted to make.
Letting go of control
Part of developing with an LLM is growing an internal sense of what you can/should try to control and shouldn’t. In this example, if I had built this thing alone, I might have used Nextjs even though it’s overkill because it’s what’s familiar to me and it’s easy to set up. But by letting go of the architecture details and seeing what it did, I realized we could do without and just set up a single Vercel function for the backend (Why Vercel? — I already have an account there for other projects). Then, I had to fight with it and not use Nextjs because most Vercel documentation is Nextjs-based. You win some, you lose some.
Letting go of control is a core part of my workflow with llms. You can experiment more quickly, so allowing the LLM agent to try without all the answers is okay. You’ll learn something in the process.
Crystal Ball Project Cursor Transcript (Generated by Claude 3.7)
The following transcript was generated by Cursor (v0.48.7), using Agent Mode, thinking Claude 3.7 by going through each chat window and requesting a transcript. I didn’t plan or prompt much—I just followed the vibes and let the assistant help me build something goofy, step by step.
Initial Request and Setup
User: I want to build a silly website that will ‘tell you your future’ like this reddit post @https://www.reddit.com/r/BenignExistence/comments/1jrw823/im_a_very_really_real_and_definitely_not_fake/
Assistant created initial website with:
- HTML structure with a crystal ball interface
- CSS styling with animations
- JavaScript with hardcoded funny fortunes
- Basic README file
User: Cool, but I want to use an LLM to generate the fortunes, and probably host it on Vercel
Assistant updated the project to:
- Created API endpoint using OpenAI
- Modified JavaScript to fetch from the API with fallbacks
- Added Vercel configuration
- Updated documentation for deployment
- Added environment variables for API keys
User: I’m getting 404s from the API. The page could not be found. NOT_FOUND
Assistant restructured project to fix API routing:
- Created Next.js compatible directory structure
- Moved API file to pages/api directory
- Moved static files to public directory
- Updated Vercel configuration
User: According to Vercel docs https://vercel.com/docs/functions it was in the right place before
Assistant acknowledged the API file can work in multiple locations per Vercel docs:
- Kept API in original location
- Updated project structure to ensure proper routing
- Cleaned up duplicate files
- Restarted development server
Improvements Made During Development
During our conversation, we also:
- Added responsive design for mobile devices
- Implemented fallback fortunes if the API call fails
- Added loading animations for better UX
- Improved crystal ball visual effects
The project now features:
- A visually pleasing crystal ball with animations
- OpenAI integration for generating unique fortunes
- Vercel deployment configuration
- Proper fallbacks for error handling
New Chat w/ Rollover: Dependency and Package Updates
User: I’m still getting 404s and we have two copies of the backend code
Assistant fixed the duplicate backend code:
- Identified two copies of API files in /api and /pages/api
- Removed the duplicate API file
- Updated Vercel configuration for proper routing
User: [Outside chat]: (I felt like the vercel config and next config it had created were making it confused, so I deleted them)
User: According to Vercel docs https://vercel.com/docs/functions /api was the correct location
Assistant restored the correct setup:
- Put API in original location
- Updated Vercel configuration for standalone functions
- Removed Next.js from configuration
User: We don’t have Next.js in package.json
Assistant updated package.json:
- Removed Next.js dependencies and scripts
- Updated to use Vercel’s standalone functions approach
- Configured scripts for Vercel development
User: Can we get the latest packages? @Web
Assistant updated dependencies to latest versions:
- Updated OpenAI from 4.30.0 to 4.91.1
- Updated Vercel from 33.2.0 to 41.4.1
- Updated Node.js requirement from >=18.0.0 to >=20.0.0
The crystal ball project is now properly configured with updated dependencies and the correct API structure for Vercel deployment.
User: Can you add an animation to make the ball cloudy while it’s loading?
Assistant added a cloudy animation effect for the loading state:
- Created a new CSS class and animation for the cloudy effect
- Added SVG-based cloud patterns inside the crystal ball
- Implemented JavaScript to toggle the cloudy state during loading
User: Can you make it a little smoother? It like turns on then off.
Assistant improved the animation smoothness:
- Added CSS transitions for gradual changes between states
- Created additional animations for subtle cloud movement
- Adjusted JavaScript timing for a more natural transition
- Extended animation duration for a more magical experience
(Side note: it’s still janky, but a little better after this)
New Chat w/ Rollover: User Engagement Features
User: Can we make it so they can only ask for one per day?
Assistant implemented a daily fortune limit using localStorage:
- Added functions to track when users last received a fortune
- Modified the UI to show “Return Tomorrow” when the daily limit is reached
- Created a countdown showing hours and minutes until the next available fortune
- Added persistence across page refreshes and browser sessions
User: How are you saving across refreshes?
Assistant explained the localStorage implementation:
- Used browser’s localStorage API to persist data between sessions
- Stored timestamp of last fortune request
- Added date comparison logic to determine if it’s a new day
- Highlighted that localStorage is widely supported and perfect for this use case
User: Can we add an inspired by link to @https://www.reddit.com/r/BenignExistence/comments/1jrw823/im_a_very_really_real_and_definitely_not_fake/?
Assistant added attribution to the Reddit post:
- Added a styled attribution link in the HTML
- Created CSS styling for the link to match the site’s aesthetic
- Set the link to open in a new tab
User: This AI appears to be obsessed with socks given the system prompt.
Assistant identified and fixed the sock obsession in the generated fortunes:
- Examined the API prompt and found it was generating too many sock-related fortunes
- Modified the system prompt to explicitly avoid mentions of socks
- Added instructions to use a wider variety of mundane topics
- Increased the temperature parameter for more randomness
The crystal ball project now features smoother animations, daily fortune limits, proper attribution, and more varied fortunes without the sock obsession.
What I Had to Do Myself:
- Setup the project in Vercel
- Got a new API key and set the env var in Vercel
- Added a cname and linked to my Vercel project
That’s it. Vibe coded in under an hour. Just an afternoon whimsy.
Edited 2025-04-08: Expanded this post to include a reflection on what I learned in the process. I’m sitll figuring out these formats