RORK LABJP
PRICE — Rork Max spans $200 to $1,800 per month, with the upper tiers aimed at heavier builders and teamsFREE — The free tier lands at roughly five prompts per week, enough to try it but not to build on continuouslySHIP — App Store publishing is automated through builds, certificates, and submission, so you can ship an iOS app without a Mac or XcodeSIM — A browser-streamed simulator lets you watch your app run in a real Apple environment from your own browserNATIVE — It reaches HealthKit, ARKit and LiDAR, NFC, Dynamic Island, and Metal 3D — territory React Native cannot touchFUNDING — Rork raised a $15M seed led by Left Lane Capital, announced April 9, 2026, and acquired app builder PaperlinePRICE — Rork Max spans $200 to $1,800 per month, with the upper tiers aimed at heavier builders and teamsFREE — The free tier lands at roughly five prompts per week, enough to try it but not to build on continuouslySHIP — App Store publishing is automated through builds, certificates, and submission, so you can ship an iOS app without a Mac or XcodeSIM — A browser-streamed simulator lets you watch your app run in a real Apple environment from your own browserNATIVE — It reaches HealthKit, ARKit and LiDAR, NFC, Dynamic Island, and Metal 3D — territory React Native cannot touchFUNDING — Rork raised a $15M seed led by Left Lane Capital, announced April 9, 2026, and acquired app builder Paperline
Articles/App Dev
App Dev/2026-07-29Advanced

The same wallpaper appeared twice in my catalog — measuring perceptual hash thresholds across 324 images

Four approaches to image catalog deduplication measured end to end: SHA-256, dHash, a hue signature, and a block signature. dHash alone scored 0.9% precision. Here is why perceptual hashes collapse on smooth images, and how the ground truth turned out to be the thing that was wrong.

image processing2perceptual hashingdHashdeduplicationasset managementNode.js2sharpindie development34

Premium Article

I was scrolling my own wallpaper app one morning when my thumb stopped.

The same artwork appeared twice, a dozen rows apart.

One came from the original launch batch, the other from a later import. Different filenames, different upload dates, so nothing in the catalog table had ever flagged it. When you maintain a few thousand image assets as an indie developer, this kind of drift accumulates quietly.

Nobody had complained in an App Store review. It still felt wrong that a paying user would scroll past the same picture twice.

Reviewing several thousand images by hand was not an option, so I built something to find them mechanically.

The design I sketched at the start was wrong twice over. Here is what the measurements actually showed.

Building a verification set I could re-run

Experimenting directly on the production catalog would have left me with no way to check my own results. Instead I synthesized a set with the same characteristics.

160 source images at 1290×2796, the iPhone portrait resolution — 40 each of gradients, blurred blobs, stripes, and noise clouds. That mix mirrors what a wallpaper catalog tends to contain.

From those I generated five kinds of derivative:

DerivativeCountGround truth
Re-encoded at JPEG quality 92 → 7454Duplicate
Resized 1290×2796 → 828×179232Duplicate
Brightness raised 6%23Duplicate
Cropped 2% on each edge, scaled back15Duplicate
Hue rotated 80 degrees40Distinct

324 images in total. Labeling the hue variants as distinct is the pivot of the whole exercise. In a wallpaper catalog the color variant is the product, and merging it would delete inventory.

Everything below was measured on Node 22.22.3 with sharp 8.18.3 (libvips).

SHA-256 gets you almost nothing

I started with a SHA-256 over the raw file bytes. A few lines of code, and it seemed reasonable to sweep the exact matches first.

It found 3 of the 124 real duplicates. A recall rate of 2.4%.

In hindsight the result is obvious. Re-encoding a JPEG changes every byte. So does resizing, brightness adjustment, and cropping. Byte equality only catches the case where the identical file was uploaded twice — and an upload-time guard had already been handling that case for years.

What remained in the catalog was precisely the category exact hashing cannot see: visually identical, byte-wise different.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
SHA-256 byte matching found 3 of 124 real duplicates — a 2.4% recall rate. The measured breakdown shows exactly which transformations defeat exact hashing and why re-encoding alone is enough
dHash at a Hamming threshold of 10 scored 97.5% recall against 0.9% precision, with 16,570 false pairs. The cause: 80 of 160 source images collapsed to an identical, information-free hash. A popcount gate brings false positives to zero
Complete implementation of a three-band classifier (auto-merge, human review, distinct) with 96.9% precision in the auto band, zero missed duplicates, and 20.6 ms per image across 324 files
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

App Dev2026-07-31
My generated wallpaper catalog hashed differently on every run — isolating five sources of nondeterminism
The same image folder refused to produce the same catalog.json twice. Directory enumeration order, JSON.stringify key reordering, collation, Unicode normalization, and async completion order — measured one at a time across 1,225 files until the output settled on a single hash.
App Dev2026-04-06
Rork App Monetization Complete Strategy: Building Revenue from Zero with AdMob, Subscriptions, and In-App Purchases
A complete guide to monetizing apps built with Rork. Covers AdMob ad design, subscription setup, and in-app purchases — with practical insights from an indie developer generating over ¥1M/month. Full content, free.
App Dev2026-08-15
TestFlight External Testing or Phased Release: Where a Solo Developer's Time Actually Pays Off
When you ship a Rork-built app to other people, you can recruit external testers or let a phased release absorb the risk. Here is how I split my limited time between the two, based on where distribution actually stalls and which three areas still deserve pre-release checks.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →