<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kirby Robinson</title>
    <description>The latest articles on DEV Community by Kirby Robinson (@36dunes).</description>
    <link>https://dev.to/36dunes</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F128193%2F4d34f738-bb8f-4ffc-b17e-86d3839ea97a.png</url>
      <title>DEV Community: Kirby Robinson</title>
      <link>https://dev.to/36dunes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/36dunes"/>
    <language>en</language>
    <item>
      <title>Building PhotoNester: My Journey to Organize a Million Memories</title>
      <dc:creator>Kirby Robinson</dc:creator>
      <pubDate>Tue, 24 Jun 2025 00:08:17 +0000</pubDate>
      <link>https://dev.to/36dunes/building-photonester-my-journey-to-organize-a-million-memories-3nk2</link>
      <guid>https://dev.to/36dunes/building-photonester-my-journey-to-organize-a-million-memories-3nk2</guid>
      <description>&lt;p&gt;Like many iPhone users, I’ve spent years snapping photos—of family, friends, travel, food, and the occasional blurry pet mid-jump. My photo library had become a sprawling, unsearchable archive of life. That’s when I decided to build &lt;a href="https://photonester.com" rel="noopener noreferrer"&gt;PhotoNester&lt;/a&gt;—a smart, on-device photo classification app that automatically organizes your photo library into clean, scrollable albums.&lt;/p&gt;

&lt;p&gt;Here’s how I went from a rough idea to a working, App Store–ready product.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Spark: Organizing Chaos&lt;/strong&gt;&lt;br&gt;
The idea came from a personal pain point. I had thousands of photos backed up from iCloud, but no good way to make sense of them. I’d tried Apple’s Memories feature, third-party gallery apps, and even manual sorting (briefly—never again). Nothing gave me the control or structure I wanted without compromising privacy.&lt;/p&gt;

&lt;p&gt;That was the moment it clicked: What if I could use AI to group photos by content—travel, pets, nature, documents—right on the device, with no cloud processing involved?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choosing the Brains: CLIP as My Visual Engine&lt;/strong&gt;&lt;br&gt;
I needed a robust model that could understand visual content well enough to group similar images together without hardcoded labels. I chose OpenAI’s CLIP model, which generates high-quality embeddings from images. These embeddings are like fingerprints—vectors that describe the semantic content of a photo.&lt;/p&gt;

&lt;p&gt;To run CLIP on iOS, I converted the PyTorch model into Core ML format using &lt;code&gt;coremltools&lt;/code&gt;, optimizing it for on-device performance. I then tested it across a variety of image sets—vacations, work screenshots, family albums—to ensure the embeddings were consistent and meaningful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core ML and Swift: The Technical Build&lt;/strong&gt;&lt;br&gt;
I built the app in Swift, using SwiftUI for the interface and Core ML to run the model. I wanted the experience to be clean, responsive, and native. One of the key challenges was batching and optimizing image processing. Running neural inference across thousands of photos on a phone can tank performance (and battery).&lt;/p&gt;

&lt;p&gt;So, I implemented:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Batch processing with memory safeguards (processing 100 images at a time)&lt;/li&gt;
&lt;li&gt;Progress tracking with visual feedback to the user&lt;/li&gt;
&lt;li&gt;Persistent state, so users can stop and resume without losing progress&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The classification is unsupervised—images are grouped based on visual similarity. Then, using k-means clustering on the embeddings, I sort them into labeled albums like “Travel,” “Pets,” “Food,” etc., which users can rename or merge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keeping It Private&lt;/strong&gt;&lt;br&gt;
A big goal was to ensure privacy. PhotoNester never sends photos to a server or uses the cloud. Everything—classification, clustering, album generation—runs directly on the device. This was not just a security decision but a performance one too. Users see near-instant results, and their content stays theirs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The App Store Hurdles&lt;/strong&gt;&lt;br&gt;
Submitting to the App Store was its own journey. Apple initially rejected the app for a crash on iPadOS 18.5. After digging through logs, I found that the MPSGraph backend was unavailable on that iPadOS version, and the model fallback wasn’t configured correctly. The fix? Explicitly set MLModelConfiguration().computeUnits = .all to allow CPU/GPU fallback.&lt;/p&gt;

&lt;p&gt;Once that was resolved, I finalized the App Store metadata, created visuals for the feature list, and submitted again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What PhotoNester Does Now&lt;/strong&gt;&lt;br&gt;
Today, PhotoNester automatically groups your entire photo library into intelligent albums—Travel, Pets, Food, Nature, Selfies, Documents, and more. It works offline, respects your privacy, and feels like magic when it turns a jumbled camera roll into organized memories in just minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s Next&lt;/strong&gt;&lt;br&gt;
There’s more coming—custom category creation, time-based filtering, smart tagging, and better album suggestions. But for now, I’m proud of what PhotoNester has become: a fast, private, beautiful way to rediscover your photos.&lt;/p&gt;

&lt;p&gt;If you're tired of endless scrolling to find that one beach pic or that concert selfie, give PhotoNester a try. It’s the photo app I always wished someone else had built—so I did it myself.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ai</category>
      <category>machinelearning</category>
      <category>ios</category>
    </item>
  </channel>
</rss>
