Inspiration

Junk started with my girlfriend making a physical junk journal.

I loved the idea of collecting random little pieces of your life and turning them into something personal, relaxing, and beautiful. But we were in a long-distance relationship, so I kept thinking about how nice it would be if we could make one together, instantly, even when we weren't in the same place.

That became Junk: a shared space for the photos, screenshots, jokes, memories, and little moments that don't really belong anywhere else.

What it does

Junk is an infinite collaborative scrapbook.

You can create as many boards as you want and fill them with photos, cutouts, stickers, frames, text, and whatever else you want to throw onto the canvas. Everything can be moved, resized, rotated, layered and edited freely.

Boards can be shared and edited together in real time, so instead of sending someone a finished collage, you slowly build something together.

And when you do want to share what you've made outside Junk, a board can be exported as a swipeable carousel formatted for Instagram or TikTok.

I wanted Junk to feel deliberately low-pressure. There is no perfect post to make, no grid to respect and no blank-page pressure. You just add something, move it around, let someone else add something, and see where the board goes.

But underneath that simplicity, I wanted the editor to be genuinely powerful.

How I built it

My background is in product management, and before Junk I had never built a complete Swift app of this complexity.

I built it myself over about four months, learning a huge amount of iOS development along the way.

The app is mainly built in Swift with SwiftUI and UIKit, with Core Image and Metal for visual processing and rendering. The backend uses TypeScript, PostgreSQL and Cloudflare infrastructure, with WebSockets and Durable Objects powering real-time collaboration. RevenueCat handles subscriptions.

The interesting part wasn't really the number of technologies, though. It was getting all of them to disappear behind interactions that feel simple.

The infinite canvas, for example, has to remain sharp and responsive at very different zoom levels while constantly loading, caching and rendering images.

Real-time editing also means local changes, server state and another person's changes can all arrive at different times. Junk has to reconcile those without moving an object backwards, duplicating it or making something the user just added disappear.

I spent a lot of time thinking about these invisible details because the experience only feels relaxing when the machinery underneath it is reliable.

Challenges I ran into

Making two screens feel like one place

One of the hardest things I built was the transition between Home and a board.

On Home, every board is already interactive: you can move horizontally through it just like you can inside the full editor.

When you tap one, I didn't want a normal navigation transition. The board expands seamlessly into the editor so it feels like you never changed screens at all.

That sounds simple, but Home and the editor have very different lifecycles.

A photo might already be visible but still uploading. A cutout might have changed locally but not reached the server yet. One image resolution might be cached while another still has to decode. An old network request might return after the user has already moved an object.

Getting the transition right meant coordinating cached board data, decoded images, rendered effects, pending changes and the exact board coordinate currently under the center of the screen.

For a while I had bugs where items would briefly vanish, jump back to an old position, appear without their effects, or disappear if you returned Home too quickly after adding them.

Making that handoff feel completely uneventful ended up being one of the most complicated parts of the app.

Building a sticker bazaar

I also wanted Junk to come with a large library of stickers without having them fall apart visually when users zoomed in.

Finding enough good assets was already difficult, so I ended up building a small internal tool for myself.

It can ingest packs of sticker sheets, separate them into individual assets, process them and upscale rasterized sources so they hold up better inside the canvas.

It is one of those pieces nobody using Junk will ever know exists, but it made a big difference to how rich the editor feels.

Throwing things in the trash

Deleting an object was another feature that got wildly more complicated than it needed to be.

And I'm very happy about that.

Instead of tapping Delete, you can drag an object below the canvas. As it leaves the board, it physically crumples into a paper ball in your hand. Release it and it gets thrown into a trash can.

The effect isn't a prerecorded animation. The item itself becomes the paper.

Its rendered appearance is captured, split into a triangular mesh, progressively folded toward an irregular 3D sphere and projected back into SwiftUI's 2D Canvas. Crease shadows and highlights make the deformation readable, while a spring simulation makes the ball lag slightly behind your finger.

Release it and the ball follows a Bézier trajectory into the bin, with layering, movement and haptics finishing the illusion.

Text gets its own treatment: instead of becoming a paper ball, it can collapse into simulated strands and get slurped into the trash.

Absolutely unnecessary.

Also one of my favorite parts of Junk.

Accomplishments that I'm proud of

Honestly, just getting Junk working well and accepted on the App Store feels like a huge accomplishment for my first iOS app.

But beyond that, I'm proud that Junk doesn't just function, it feels like it has its own personality.

Building a creative tool that feels playful

One of my biggest goals was to make something that feels cute, expressive and low-pressure without sacrificing capability.

Junk lets people move, resize, rotate, layer, duplicate and remix things very freely, but I never wanted it to feel like intimidating design software. I'm proud that the editor feels playful on the surface while still being genuinely powerful underneath.

Creating memorable interaction moments

I'm especially proud of the moments in Junk that feel a bit surprising or magical.

The Home → board transition makes the app feel like one continuous space. The infinite canvas keeps extending as you explore it. The free version eventually reaches a literal wall that disappears when you upgrade. And dragging something off the canvas turns deletion into a physical interaction instead of a boring button tap.

Those details are not strictly necessary, but they're a big part of what makes Junk feel special.

Extending the board beyond the editor

I also like that Junk doesn't stop at creation.

Boards can be shared in real time, previews can appear in iMessage invites, collaboration can surface through Live Activities, updates can show up in widgets, and boards can even be exported as swipeable carousels for Instagram or TikTok.

I'm proud that the product feels alive both inside and outside the app.

Shipping a strong first version

For a first app, I'm proud of the overall level of finish: the design system, the custom interactions, the real-time collaboration, the infinite canvas, the iOS integrations, and the fact that all of it made it into a real shipped product rather than staying as ideas or prototypes.

The demo video

I'm also proud of the presentation work around Junk.

For the demo video, I used AI-assisted video tools to transform footage of myself using the app into a stylized short film, replacing me with characters while preserving the real phone interactions. Creating the right ambiance and continuity without letting the phone content hallucinate was a lot of work, but it felt worth it because the presentation became an extension of the product's identity.

Overall, I think the accomplishment I'm most proud of is that Junk feels like more than a utility. It feels like a small world with its own mood, interactions and point of view.

What I learned

The biggest thing I learned is just how much AI changes what one person can build.

Four months ago, I had never built an iOS app of this complexity. With AI, ideas that I would previously have dismissed as "probably too difficult" became things I could actually attempt: real-time collaboration, custom rendering, an infinite canvas, shaders, physics-driven animations, Live Activities, widgets, and a backend to support all of it.

It changed my relationship with ideas. Instead of asking "Can I build this?", I found myself asking "How far can I take it?"

But I also learned where AI stops helping.

Getting something to work is often surprisingly fast. Getting it to feel genuinely great is not.

The first 90% of an interaction can sometimes appear almost magically. Then you notice the image flashing for one frame, the animation doesn't quite preserve momentum, a board opens a few pixels away from where it should, or something feels subtly wrong when you use it repeatedly.

That last 10% can take 90% of the time.

And AI doesn't make those decisions for you. You still have to notice what feels wrong, understand why, care enough to keep iterating, and decide when something finally feels right.

That's probably the biggest thing Junk taught me: AI makes ambitious ideas dramatically more achievable, but craft is still in the last 10%.

What's next for Junk

I want to keep building Junk.

The next step is making the editor even more powerful while expanding the social side of the product so boards feel more alive between the people who share them.

I don't want Junk to become another social network built around posting polished content. I want it to become a much more creative, private and playful way of making things with other people.

I have a lot of ideas for where that can go, and I'd like Junk to grow beyond a side project into a real company.

I'm also starting to think about finding someone strong in design and marketing to join the project. Building the product, designing it and creating all the content around it alone is a lot, and I'd love to have someone equally excited about the idea to help move faster.

The long-term goal is simple:

Make Junk the best place for the moments that are too small, weird, personal or messy for anywhere else.

Built With

  • avfoundation
  • cloudflare-durable-objects
  • cloudflare-hyperdrive
  • cloudflare-r2
  • cloudflare-workers
  • core-image
  • drizzle-orm
  • firebase-authentication
  • firebase-cloud-messaging
  • firebase-crashlytics
  • hono
  • ios
  • metal
  • neon
  • openapi
  • postgresql
  • posthog
  • revenuecat
  • sweetpad
  • swift
  • swiftui
  • typescript
  • uikit
  • visual-studio-code
  • websockets
Share this project:

Updates

Submission history