Skip to content

Repository files navigation

Yamki · 얌키

A food diary you look at instead of read. Photograph a meal, and the food alone is cut out of the picture and becomes a sticker you arrange on a board of your own.

Everything stays on the device: no account, no server, no analytics, no ads.

The store name differs per language because another developer holds "Yumkie": 얌키 (ko) · Yamki Food Sticker Diary (en) · ヤムキー ごはんステッカー日記 (ja) · 雅米吉 美食贴纸日记 (zh-Hans).

What it does

  • Cuts the food out of a photo on device with Vision. Several dishes in one shot come out as separate stickers, and each dish becomes its own entry.
  • A board you arrange yourself — the whole screen is the canvas. Drag a sticker anywhere; drop it on the tray to take it off the board (which is not the same as deleting it).
  • Your own tags, and a star rating, shown everywhere the dish appears.
  • A drawer holding every sticker ever saved. Deleting from the drawer is the only delete that is permanent.
  • A map of where each meal was eaten, from the photo's own EXIF.
  • A recap card that turns the board into one shareable image, with a closing line written by Apple Intelligence on device where the device supports it.
  • A food world cup to decide what to eat, and a Game Center version where everyone votes within five seconds.
  • Streaks, badges, and a home screen widget.

Layout

Tuist generates the project; the app is split into three static frameworks so the layers cannot import each other backwards.

Target What lives there
Models SwiftData entities and the Sendable snapshots that cross actors
ClientKit dependency clients — persistence, cutouts, place search, Game Center, captions
FeatureKit TCA reducers and SwiftUI views, one folder per feature
FoodDiary the app target: assets, Localizable.strings, entitlements
FoodDiaryWidget the widget extension

State is TCA; storage is SwiftData behind a @ModelActor, so the UI only ever sees value-type snapshots.

Four languages ship: Korean (base), English, Japanese, Simplified Chinese. Localizable keys are the Korean source text.

Getting set up

brew install tuist
bash Scripts/setup.sh      # tuist install && tuist generate
open FoodDiary.xcworkspace

Configurations/Secrets.xcconfig is gitignored — copy Configurations/Secrets.example.xcconfig to it. The app builds without any values filled in.

Tests

xcodebuild test -workspace FoodDiary.xcworkspace -scheme FoodDiary \
  -destination "id=<simulator udid>" -skipMacroValidation

Cutouts come from Vision, which does not run in the Simulator — test the capture flow on a device.

Store screenshots

The screenshots are rendered with ImageRenderer, not captured from a simulator, so the pixel size is exact and the boards are full of real food.

swift Scripts/make-cutouts.swift ~/path/to/food/photos   # → fastlane/cutout-sources/
bash Scripts/screenshots.sh                              # → fastlane/screenshots/<locale>/

Ten posters per language at 1320 × 2868 (iPhone 6.9"), RGB with no alpha channel — the store rejects anything else. Both folders are gitignored: they are built from personal photos.

Shipping

Build → TestFlight runs on GitHub Actions (.github/workflows/release.yml, workflow_dispatch or a v* tag). Signing is cloud-managed through an App Store Connect API key, so no certificates are stored in the repo.

gh workflow run release.yml --ref main

Metadata and screenshots go up separately, so text changes need no build:

LANG=en_US.UTF-8 \
APPSTORE_KEY_ID=<key id> \
APPSTORE_ISSUER_ID=<issuer id> \
AUTH_KEY_PATH=~/.appstoreconnect/private_keys/AuthKey_<key id>.p8 \
BUNDLE_PATH=vendor/bundle bundle exec fastlane metadata

Store text lives in fastlane/metadata/<locale>/ and is version-controlled; Gemfile.lock deliberately is not — the macOS system bundler writes a version that breaks Ruby 3.3 on CI.

About

먹은 걸 스티커로 모으는 밥일기 · A food diary you look at instead of read — Vision cutouts, an arrangeable board, all on device

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages