Sailventory

sailventory.com

Replaces the paper sticker on a roll of sailcloth with an NFC chip. Photograph the mill label, confirm what was read, write it to the chip. Tap the roll later to see what cloth it is, and enter cuts so the metres left on the chip go down.

Android · React Native · on-device, no server

On the chip

77 bytes

Tests

132

Source

6.7k lines

Release APK

51.8 MB

Servers

0

The record

One NDEF message, nine values, no field names

The chip is the source of truth — there is no database behind it. The record is written by position rather than by key, and the mill, shade and grade are written as their index in a fixed list, which is what takes a roll from 215 bytes to 77.

[2,1,"Superlite 50",1,40,2,"6114308",150,40]
version 2 mill Contender article Superlite 50 shade natural length 40 m grade Seconds lot 6114308 width 150 cm left 40 m

Fits the cheap tag

An NTAG213 holds 137 bytes and is the sticker every shop stocks. The record fits it with room to spare, so the tag someone buys by accident is the right one.

No cut history

The loft only needs what is left right now. Dropping history made the record a fixed size, so a write can only ever fail on the very first one.

Verified after write

Every write is read back and compared before success is shown. A half-written tag is never reported as written.

The flow

Label to chip, then chip to cut

Photograph

Three frames of the mill label, a fraction of a second apart.

Confirm

Every field the reader was unsure of is signed off before anything is written.

Write

Held against the chip, written, read back and verified.

Tap

Holding a phone to a tagged roll opens the app on that roll, even when closed.

Cut

The cut is saved to the phone first, then written to the chip — so metres survive a crash.

Reading a label

Glare is the problem, not the text

Three frames

A laminated label reflects, and the glare moves when the phone does. Three frames rarely lose the same words; agreement raises confidence, disagreement forces a confirmation.

The flash stays off

Fired at a glossy label it puts a hotspot exactly where the text is. There is a torch button instead, so the operator can see whether light helps.

Confidence is derived

ML Kit returns no per-token confidence, so it is inferred from how a value was found — anchored to a caption, right shape, unambiguous, free of letter-for-digit confusion.

Plausibility is separate

A width misread as 1500 cm is a clean, well-anchored read of an impossible number. Confidence cannot see that; range checks can.

Tolerant captions

The Contender stencil reads M as H, so GROSS METERS comes back GROSS HETERS. The patterns expect it.

5 MP, not full sensor

The label fills the frame, so more pixels buy nothing — and three full-resolution frames were enough for Android to kill the app.

Built with

Standard React Native, nothing exotic

Runtime

React Native
0.86.2
React
19.2.3
TypeScript
5.8
react-native-nfc-managerNDEF read, write, erase; Android reader mode
3.17
ML Kit text recognitionon-device OCR of the mill label
2.0
Vision Camerathe three-frame capture
5.2
Nitro Modules / Nitro ImageVision Camera peer deps — must stay explicit
0.36 / 0.15
React Navigationnative stack
7.3
AsyncStorageroll list and pending cuts
3.1
Share / SVG
12.3 / 15.15

Toolchain

Node
24.19
JDKAndroid Studio's bundled runtime
21
Gradle
9.3.1
Kotlin
2.1.20
Android NDK
27.1
SDKmin / compile / target
24 / 36 / 36
Metro + Babelbundler
0.86.2
Jest132 tests, ~1.4 s, no device
29
ESLint + Prettier
8 / 2.8
Claude Codethe whole build
Opus

Deliberately absent

The audience is lofts under five people

Everything runs on the phone. The only network call is an optional JSON file of the loft's own ads, cached so it works with no signal and falling back to ads bundled in the app. Nothing identifies or tracks anyone — which is why there is no consent dialog and no privacy policy to write.

CSV export through the share sheet is the way out for anyone who wants more. It defaults to semicolons and comma decimals, because a comma-separated file lands in column A of a Danish Excel with the numbers as text.

Where it stands

Working on hardware, with known gaps

Working

Read, write, verify, cut, erase and the stock list, on an Android phone against real chips.

Untested

A locked tag, a write interrupted mid-flight, and a tag written by the other platform. Each needs a failure that has to be staged.

Blocked

iOS. Entitlements, usage strings and the bundle id are in place, but Core NFC needs a capability no free Apple team has. $99/year, unavoidable.

Deferred

Code shrinking would take 10–15 MB off the APK, but it strips code it believes unused and the NFC, camera and Nitro modules all use reflection. Worth doing once the feature set settles.