A loyalty card manager that feels alive. Cards aren't rows in a database — they're objects you hold, flip, and fan through. Built with wallet-style interactions, spring physics, and haptic feedback.
Local-first. Zero cloud. Zero bloat. Open source.
Tesserone is an independent project. It is not affiliated with, endorsed by, or sponsored by any of the brands, merchants, or platform owners referenced in the app or its source. See Trademarks & Attribution for details.
Tesserone is a side project, maintained on a best-effort basis by the Chipcolate team. Issues and pull requests are welcome and will be reviewed as time allows.
- Wallet-style card stack — scroll, tap to bring a card forward with its barcode, tap again or swipe up to send it back
- Brightness boost — screen brightness maxes out when viewing a barcode, restores when you're done
- Barcode scanning — scan loyalty cards with the camera, or enter details manually
- Brand recognition — type a store name and Tesserone matches it to a curated brand database with logos and colors
- Custom logos — upload your own logo from the gallery or take a photo
- Drag to reorder — wobble mode with long-press drag, like rearranging your home screen
- Import/Export — back up your cards as JSON, import from a backup file with conflict resolution
- Dark/Light/System themes — neutral chrome, the cards bring the color
- Haptic feedback — tactile responses on every interaction
- Fully offline — all data stays on your device
EAN-13, EAN-8, Code 128, Code 39, QR, UPC-A, UPC-E, PDF417, Aztec, Data Matrix, ITF-14
| Layer | Choice |
|---|---|
| Framework | Expo SDK 55, React Native 0.83 |
| Animation | react-native-reanimated 4.x |
| Gestures | react-native-gesture-handler 2.x |
| Navigation | expo-router (file-based) |
| State | zustand + AsyncStorage |
| Barcode scan | expo-camera |
| Barcode render | @kichiyaki/react-native-barcode-generator, react-native-qrcode-svg |
| Haptics | expo-haptics |
| Brightness | expo-brightness |
Common
- Bun for package management (npm or yarn work too, but
bun.lockis the checked-in lockfile) - Node.js 20+ (needed for
npx— some Expo CLI commands shell out to it) eas-cliinstalled globally
For iOS builds
- macOS (required — iOS builds don't run on Linux or Windows)
- Xcode with iOS simulators and command line tools
- A physical iOS device (Expo Go is not supported)
For Android builds
- Android Studio with the Android SDK and platform tools
- JDK 17
- A physical Android device with USB debugging enabled, or a running emulator
adbon your PATH (comes with Android SDK platform-tools)
git clone https://github.com/chipcolate/tesserone.git
cd tesserone
bun installiOS
npx expo run:ios --deviceAndroid
npx expo run:android --deviceiOS
# Ad-hoc build for your provisioned devices
eas build --platform ios --local --profile preview
# Install the resulting .ipa on a connected device
xcrun devicectl device install app --device <DEVICE_UUID> <path-to-ipa>
# Production build for App Store submission
eas build --platform ios --local --profile productionAndroid
# Preview APK for direct install / sharing with testers
eas build --platform android --local --profile preview
# Install the APK via adb
adb install <path-to-apk>
# Production Android App Bundle for Play Store submission
eas build --platform android --local --profile productionTesserone ships with a curated set of store logos. To add a new brand:
- Add a PNG logo to
assets/logos/(white/light logo on transparent background works best) - Register the asset in
src/services/logos.tsin theBUNDLED_LOGOSmap - Add the brand entry to
data/brand-index.jsonwith name, aliases, colors, and logo filename
Users can also upload custom logos from their photo gallery when adding a card.
Cards are stored locally via AsyncStorage and can be exported as JSON:
{
"cards": [
{
"id": "card-1234567890-abc123",
"name": "Example Store",
"code": "1234567890128",
"format": "EAN13",
"color": "#1456A2",
"logoSlug": null,
"notes": "Family card",
"sortIndex": 0,
"createdAt": "2026-04-13T10:00:00.000Z",
"updatedAt": "2026-04-13T10:00:00.000Z"
}
],
"settings": { "themeMode": "system", "sortMode": "manual" },
"exportedAt": "2026-04-13T12:00:00.000Z",
"version": "2.0.0"
}Import is tolerant of older export shapes — lowercase barcode enums are normalized and missing fields get sensible defaults.
Licensed under the Apache License, Version 2.0. See NOTICE for attribution and trademark information that must be preserved in redistributions.
Tesserone is an independent, open-source project. It is not affiliated with, endorsed by, or sponsored by any of the brands, merchants, or platform owners referenced in the app or its source.
- All third-party brand names, logos, and trademarks — including merchant logos bundled under
assets/logos/and indexed indata/brand-index.json, as well as any platform, framework, or tool names mentioned for descriptive purposes — are the property of their respective owners. Any references are descriptive (nominative fair use) and do not imply endorsement, affiliation, or partnership. - Bundled merchant logos are included solely to help users visually identify the merchant that issued a loyalty card.
- If you are a rights holder and would like a logo or brand entry removed from the bundled set, please open an issue on the repository.
- Custom logos uploaded by end users are the responsibility of the user; you must have the right to use any image you add to the app.
