Bolt Hackathon - Week 4

A last-minute custom worksheets feature addition! Dramatic video making! Hackathon submission drama! And some thoughts after dragging my feet on this post for 2 weeks.

Bolt Hackathon - Week 4

Week 1, Week 2, Week 3, Week 4

TL;DR

A last-minute custom worksheets feature addition! Dramatic video making! Hackathon submission drama! And some thoughts after dragging my feet on this post for 2 weeks. Also see the project page here.


Hey there, long time no see. πŸ‘‹ After the mad rush of the final week of the hackathon, it took me a moment to find the time to complete this write-up. Especially since I can't seem to keep these short. So without further ado, let's travel back in time to the week commencing on the 23rd of June (yes, a Monday, the only correct first day of the week :P).

The previous progress blog post had bled into the beginning of the week, so rather than coding, I was still knee-deep in retrospections. Once the post was published, I was looking forward to a sprint (or multiple) in the final week of development.

Sadly, life had a few other ideas:

  • first kiddo's sports day at school (Tuesday)
  • second kiddo's sports day at school (Wednesday)
  • long-awaited transport to the skip (Thursday)

The last item only took about one hour, but required half a day of garden and garage cleanup as prep, so there was something to take. Unfortunately, British weather does not let me put out things in the front garden ahead of time to await transport, so it had to be done that day.

In the end, as my free time is dependent on kids being out of the house, most of the development happened late at night in small bursts or as a sprint in the later part of the week.

On Tuesday, I read up on the competition rules again (and more thoroughly) and added the Bolt badge to the site. πŸŽ‰ Yay for small wins. I was also looking at other people's projects and hackathon chitchat, and mid-week I concluded that my project wasn't very impressive with just the lined paper generator. So I decided to go ahead and implement the custom worksheets tool too. πŸ™ˆ

Off to the drawing design board we go then...

Custom Worksheets Tool

Design

I took the previous Figma designs and iterated on the content area for the new tool. With each version, I got a better understanding of what features were needed, as well as what would work in a mobile setting and what wouldn't.

πŸ“
Figma really didn't make it easy to do the fancy overlap of tabs over the header image. I didn't bother readjusting the content in the iterations, focusing on the page content instead as that would be what went into the screenshot for the AI.

Being the sole designer, developer, and product person on the project did mean I got a bit sloppy in places and didn't polish the designs and prototypes as much as I would have if there were other people involved (or this wasn't a mad rush to the finish line in a hackathon...). However, the benefit of keeping things rough was that I didn't feel too pressured to come back to the designs and redo them every time the implementation started to diverge. The mockups were great for quick experimentation and getting the feel right, but not where I wanted to spend most of my time.

Prompt Prep

Final mockup:

Once I settled on the design, I looked for shadcn/ui components that were needed for the new elements. Some form components were already present from the Line Generator work, but a few more were needed:

  • accordion for the config section switching
  • toggle for the sections on/off button
  • slider for the fold width percentage
  • dialog for the extra element selection

To help keep Bolt focused, I created the stub files for the new page and component first, so that I could lock the AI editable files to only the relevant ones.

I've also taken my experience with making the Paper Template and applied what I had learned to writing a comprehensive prompt for this feature.

Here's the prompt I gave to Bolt (feel free to skip ahead, as it is pretty long).

Change the content of the worksheet-generator.astro page using the custom-paper.astro page as a template. Retain the Hero component config from the current page, but the content will be replaced by the feature below

## ✏️ **Feature Spec: Daily Worksheet Generator (/tools/worksheets)**

### **Overview**

This tool allows users to generate printable daily spelling worksheets with configurable layout options. The UI will follow the layout from the Figma mockup and reuse core UI components (from ShadCN via cli and the existing paper tool).

This is **a standalone Astro Island page** like the existing paper generator (custom-paper.astro).

### **Core Requirements**

#### **Tabs**

- **Worksheet** (default, fully functional)
- **Premades** (static Coming Soon block)

### **Overview**
 
This tool allows users to generate printable daily spelling worksheets with configurable layout options. The UI will follow the layout from the Figma mockup and reuse core UI components (from ShadCN via cli and the existing paper tool).

This is **a standalone Astro Island page** like the existing paper generator (custom-paper.astro).

### **Core Requirements**

#### **Tabs**

- **Worksheet** (default, fully functional)
- **Premades** (static Coming Soon block)

### **Custom Tab UI Structure**

#### **Accordion Structure (Single open section, collapsible, first open by default)**

1. **Worksheet Config (first accordion section)**
   - Toggle: **Spelling Fold**        
   - inline slider shows when Spelling fold is toggled: β€”SLIDERβ€” SLIDER_VALUE% width of the page    
       - Range: **40% to 60%**, **step: 5%**, **default: 50%**            
       - Label updates live
   - Toggle: **Today Is**
   - Toggle: Write β€”NO_OF_SENTENCESβ€” sentences, over β€” NO_OF_LINESβ€” lines (values are inputs)

2. **Line Config (second accordion section)**
   - Only shown if **either of the above toggles is ON**
   - Uses existing **line config UI** from paper tool (copy of the components, do not reuse, we do not want the functionality mixing)
   - Customization options:
       - Line height
       - Line gap
       - No Number of lines - this will be determined by the various blocks
       - Baseline toggle
       - Midline toggle
       - Colors (all 3 pickers remain as-is from paper tool)

### **Preview Section**
- **Always visible**
- Appears **below accordion** and outside the config card
- Shows a **stacked vertical preview of both pages (Page 1 + Page 2)** and a Parent Page with instructions for each of the present elements as well as solutions to added puzzles.
    (mimic mobile responsive stacking at smaller viewports)
- The preview **will include the spelling fold and today is layout when these are toggled on**
- Scale down **all line measurements and layouts to 25% size for preview on small/medium screens**
- The unused area on Page 1 & 2 is a clickable '+ Elements' box 
- When clicked a drawer/modal opens with an 'options coming soon' text (stub for puzzle selection in the future)   

### **Print Button**
- Always visible
- Placed to the right of the tabs
- Logic: **Leave stubbed / unimplemented for now**

### **Premades Tab**

Static "Coming soon" placeholder block     

### **Styling & Components**
- **Use ShadCN accordion**, **Switch**, **Slider**, **Input**, **Select**, **Dialog**, **Button**, etc. (npm cli install)    
- Global scaling for preview sizing on small screens (mobile-first responsiveness) 
- Fold line = **CSS dashed vertical line**, styled to match the mock.
- All user-selected options (e.g., fold width) **will appear in the preview and the eventual printout**    
- Use **same font system**, border-radius, and padding spacing scale from paper tool.  
- Text inside the lines uses Playwright Joined Google Font, Instructions use the same font as the rest of the site - Legend

### **State Handling**
- State lives in **one single config object** (similar structure to existing PaperConfig, with extra fields for worksheet-specific toggles and fold width)

```
interface WorksheetConfig {
  // ... interface def
}
``` 

### **Responsiveness & Behavior**

- On **mobile/small screens**, preview auto-scales.
- Accordion allows **all sections closed**, but **first is open by default**.
- Only one accordion section open at a time.    
- **Line Config accordion option only visible** if **at least one toggle in Worksheet Config is ON**.

Results

Again, I was impressed with how much grunt work the AI had done. While not perfect, it used the right components, adjusted colours where needed, copied relevant parts from the other component, and generated a working prototype.

To improve the look of the config, I asked Bolt to add icons to the accordion options.

Well, it overdelivered on that one. 🀣

After a bit of tweaking though, I did get to a config layout I was happy with.

With that out of the way, it was time to move to the print preview the config controlled.

Here I used mostly Bolt's code editor with targeted change requests. Lining up all the components so that the lines don't end up offset was pretty fiddly. Especially the text inside the lines gave me a pause.

I probably could have delegated a bit more here, but the responses tended to be hit and miss and occasionally reverted hand-crafted tweaks. The dwindling token count and looming deadline did not encourage me to experiment. It was also a bit of a case where it takes longer to explain what I want via a detailed prompt than it takes for me to edit the file (even with the limited Bolt editor).

πŸ’‘
A fun little TIL I ran into is that the difference between line-height and font size is always spread equally above and below the letters. I was hoping to be able to use custom values with some fancy CSS, but alas there was no such option I could find. So I ended up shifting the whole text <div> up by th

Once I was happy with the previews, it was time to tackle the actual printing. 😬

Well, that wasn't great, but then again I didn't actually expect things to work out of the box. I mean, it would have been a nice surprise, but I was being realistic. Especially since up to this point I deliberately steered the AI away from dealing with print handling. The initial print implementation duplicated a lot of the display code, and it was easier to iterate over the layout and content in one place.

So only after I was happy with the mini previews did I start looking at the print preview code. Without getting too technical, I had success getting rid of the component duplication, handling most of the differences with a few variables, but unfortunately at the time of the hackathon submission, Tailwind was still not cooperating, so the CSS classes on the print output page remained hardcoded.

I had to take a few other shortcuts to meet the deadline:

  • the printouts work best with A4 paper in landscape mode
  • the uploaded challenge image doesn't scale right when it's too big
  • the number of lines you get in the spelling fold is calculated roughly based on how many fit on a landscape A4 page (need to find a better way to handle this)

Custom words were a late-ish addition. Originally, I wanted to do an empty sheet first, letting users write in the words they picked by hand. But then I thought that I didn't really want to do that myself, so I vibe coded the Spelling Words input.

Similarly, while eventually the Elements dialog is meant to contain a selection of various ready-made or configurable elements like mazes, puzzles, challenges, etc., I didn't want to leave the area as a stub, so right now it allows for uploading a custom image.

The site does not store any of the user added content, as to do so sensibly would have required too much planning and then careful implementation. However, it is one of the features I am considering for logged in users in the future.

Final Touches

As I still had to write the submission post, prep for and record a 3 minute video, I planned on wrapping up development on Friday, leaving the weekend for 'the paperwork'. During that final check-over of the site, I cleaned up a bunch of small issues:

  • added favicons
  • cleaned up inconsistent breadcrumbs
  • cleaned up inconsistent next link/button icons
  • fixed a few TypeScript errors
  • fixed a bug with the Bolt logo and sticky header
  • cleaned up the footer
  • cleaned up the mobile view

As I was making these tweaks, I ran into the dreaded 'sync with GitHub' timeout issue on Bolt. One suggested way of dealing with this problem was to duplicate the project. From reading the rules earlier, it also seemed I needed to duplicate my project to be able to change the visibility setting from 'private' to 'secret' (needed for judges to have access to the project). I only delayed this long to keep the GitHub integration working, so with that gone, there really was no reason to wait any further.

I clicked the Duplicate button and then panic set in as the action failed with an error that didn't let me do anything else. 😬 Eventually, I found someone in a similar position on Discord who recommended switching to StackBlitz from within Bolt and cloning there. That worked and I was able to return to Bolt from the cloned project. It was not a fun 30 minutes sorting all this out.

With GitHub connection gone, my anxiety would not let me vibe-code without a safety net, so I ended up copying back changes from Bolt into a local project to commit them. It was also a good push to wind down the scope of the changes to only minor tweaks... and content.

Bolt's editor is not the most comfortable for writing blog posts, so I switched to Obsidian to write up the About page. I copied the text into the local project and Bolt, but ended up getting distracted and didn't realise that I had not deployed that big change to Netlify πŸ€¦β€β™€οΈ The last leg of this project before submission really was a perfect example of why development shouldn't be rushed...

Custom Domain and the Failed Launch Plan

I wanted to put my best foot forward during launch, so I deployed everything to the actual site: mydragonlibrary.com. This project had always been intended as more than just a hackathon exercise, so I was eager to gain some exposure on submission day.

Well, this came back to bite me.

The Deployment Mess

Originally, I pointed the domain to the Netlify project linked to GitHub (for automatic deployments after each commit). Later, I realised I should have used the project linked to the Bolt deployment instead. But by then, I had already submitted my site on Devpost using the custom domain as both the public project address and the URL for the judges. πŸ™ˆ

To stay compliant with the rules, I had to point the domain to the Netlify project linked to Bolt. Knowing what I know now, I should have used the Netlify subdomain as the URL for the judges.

graph TD A["❌ What I Did"] --> B[Public] A --> C[Judges] B --> D[mydragonlibrary.com] C --> D E["βœ… What I Should Have Done"] --> F[Public] E --> G[Judges] F --> H[mydragonlibrary.com] G --> I[mydragonlibrary.netlify.app] style A fill:#ffcccc style E fill:#ccffcc

The Frozen Site Problem

As a result, I'm now forced to keep the frozen-in-time version of the site public until the hackathon results are announced. Most annoyingly, I missed deploying the About content, so while it's visible in the site preview, it doesn't show to users visiting the custom domain. πŸ€¦β€β™€οΈ

Since there were mixed opinions on what would constitute a change and what wouldn't, I'm now not touching the site in any way - including not adding blog posts or worksheets to the live version. Which sucks, but it's not the end of the world.

I just wish Bolt had a bit more noticeable notification when there have been changes in the project since the last deploy. Then again, outside of the weird setup for the hackathon, I would always be using a git repository, and then the project syncs automatically on every change πŸ€·β€β™€οΈ

In the end, I was glad to discover the Netlify script injection option. It allowed me to add a little notification bar with links to the version with updated content and the beta build I had been using to make fixes and add content.

But I am getting ahead of myself a bit. Let's not skip the most horrific part of the hackathon - filling out the submission form...

Project Submission

The 'Paperwork'

Okay, I may be exaggerating a little. The form itself wasn't too bad, and the walk-through videos helped quite a bit with a few of the tricky fields. Having written the weekly update posts, I had a good reference for the submission blog post too. It was handy to have something to link to for a more detailed description of my process rather than having to remember everything from scratch.

Still. I'm a pretty slow typist, so even knowing what to write, it took me a few hours to put things together.

As mentioned already, I also inadvertently, through a mix of overthinking and not planning enough ahead of time (all at once...), filled out the website link fields in a suboptimal manner.

And then came the video. 😭

3 minutes is both a lot and not that much. I did have a few brainstorming sessions with ChatGPT on making a sensibly timed script given the presentation requirements. I didn't use it exactly in the end, but it served as a good skeleton.

As there was no time to learn the skills required for slick video making, I decided to lean into the home-made vibe with a dash of humour. Though, as my sister put it, it still ended up sounding like an infomercial. πŸ˜‚ Tough crowd.

Behind the Scenes

Once I had a rough outline of a script and a few visuals in mind, it was time to record some B-roll footage (look at me using some fancy jargon 😎).

Let's just say that throwing books on the floor with one hand while trying to keep everything in frame and camera steady for over 20 minutes was exhausting. I really wished I had a fancy over-the-neck phone holder at that moment...

With the videos recorded, I then ended up trying to learn how to use CapCut in just a few hours. Mostly by trial and error. I was very glad I left myself a whole weekend for getting it done. It was quite a humbling experience as I definitely hit the taste gap (what I was able to produce did not meet my own quality standards). But hey, if I didn't finish the video, I wouldn't be able to submit the project, so I forced myself to wrap things up and not dwell too much on the completely out-of-sync audio tracks. πŸ™ˆ

I even ended up being sensible and uploading a rough version of the video earlier in the day. It was the final piece of the submission form, so I was able to send in my project on time.

However, after watching some of the other project videos, I decided to clean up mine and add a few slides before the time ran out. Submission edits were allowed until the deadline. I rushed to finish the changes in the few hours left and I did finish just in time - with 3 minutes to spare. And wouldn't you know it - Devpost crashed and I (along with plenty of other people) was not able to update the video link. But at least I had submitted the project πŸ˜… In the end, Bolt and Devpost extended the deadline and I did make my updates, but that was a valuable lesson in not leaving things last minute.

Sadly, in the rush, I did end up uploading the video to the wrong YouTube account. πŸ™ˆπŸ™ˆπŸ™ˆ So I had to switch links a third time the next day. Final version below.

It was around that time it dawned on me that I can't really update my live site as I've used the custom domain as a link for the judges. Or should I say I stressed over this for about 3 days, because Devpost does not email you a confirmation of the submission details you entered, nor allows you to view them (read-only would have been fine) anywhere on the site. And since I went back and forth about which URLs to use, in the end I wasn't sure what I sent to the judges and had to wait for support to confirm it.

To Devpost's credit, support has been very helpful. Once I emailed my query, they responded pretty quickly with the details confirming I had been over-eager to launch the site and indeed used the same link for both public page and the judges.

And in case you are curious, here's the project page on Devpost.

The Day (Week) After

As this post is already pretty long, I will leave a more in-depth post-mortem for another day. I did find it interesting how the blog post hanging over my head and no clear next steps did make me wander aimlessly for the last week and a bit. Something I had noticed a while back - I really struggle with transitioning from one project to another. Once I'm working on something, it's full speed ahead, but the in-between time is such a procrastination danger zone.

In more general news, I've been using the site daily for worksheets, which tells me the core concept works. But making that video really exhausted my willpower for social media posts, so I've got a backlog of worksheets to add to the website. The fact that they can only go on the 'beta' site right now has pushed this task down my priority list. And figuring out a social media strategy that will work for me is a whole other challenge.

I've made some minor code tweaks too - jumping into Cursor for guided refactoring has become my personal meditation zone. And I've identified several features to tackle next. But I purposefully stopped myself from doing more until the blog post is done, as it's so easy to get distracted by the fun side of the project.

In terms of tokens, I ended up upgrading to the next subscription level at the start of the week as I had less than 3M tokens left. With the top-up and the free token giveaway from Bolt during the final hackathon weekend, I had a comfortable amount left in the end.

The whole experience has been a fascinating experiment in vibe coding. While I definitely hit some frustrating moments (it's a toss up between dealing with print styles and video editing for the top spot), the overall speed of iteration was impressive. It definitely takes a bit of a mental shift for a developer thought. But if nothing else, it did force me to keep working on the project which is a win in my book.

As always, thanks for reading this far! ❀️ And you can find the (soon to be updated) site here: mydragonlibrary.com