@ondeinference / klepon / commits / cf5a0b1

Add tvOS App Store metadata, screenshots, and icon assets

- Add English metadata and review notes for tvOS - Add tvOS screenshots folder and README shot list - Add tvOS App Store icon and top shelf assets - Align tvOS bundle identifier with main app - Update release and TestFlight checklists for tvOS - Fix AskSheetView keyboard shortcut for tvOS - Update docs for tvOS target and App Store submission

Seto Elkahfi committed May 15, 2026 at 13:22 UTC cf5a0b1c9173b256efed3d639aca32a649565d27
44 files changed +307 -18
AppStore/README.md
+3
@@ -6,15 +6,18 @@ This folder keeps the App Store-facing copy and planning docs for Klepon.
6
7 - `metadata/en-US/` — English metadata copy for the iPhone app
8 - `metadata-macos/en-US/` — English metadata copy for the macOS app
9 +- `metadata-tvos/en-US/` — English metadata copy for the tvOS app
10 - `metadata-visionos/en-US/` — English metadata copy for the visionOS app
11 - `screenshots/iphone/` — iPhone screenshot exports
12 - `screenshots/macos/` — macOS screenshot exports
13 +- `screenshots/tvos/` — tvOS screenshot exports
14 - `screenshots/visionos/` — visionOS screenshot exports
15 - `screenshots/watch/` — watchOS screenshot exports
16 - `screenshots/README.md` — screenshot shot list and titles
17 - `testflight-checklist.md` — pre-TestFlight checklist
18 - `release-checklist.md` — broader release checklist
19 - `macos-appstore-notes.md` — macOS-specific submission notes
20 +- `tvos-appstore-notes.md` — tvOS-specific submission notes
21 - `visionos-appstore-notes.md` — visionOS-specific submission notes
22
23 The screenshot folders are intentionally empty in Git until real exports are added.
AppStore/metadata-tvos/en-US/description.txt new
+16
@@ -0,0 +1,16 @@
1 +Discover Indonesian food on Apple TV with warmth, clarity, and privacy.
2 +
3 +Klepon helps you explore dishes, ingredients, and food traditions from across Indonesia in a simple living-room experience that feels calm, readable, and easy to browse.
4 +
5 +Browse curated guides to iconic dishes, regional favorites, sweet treats, and essential ingredients. Learn what a dish is, what it tastes like, what usually goes into it, and what to try next.
6 +
7 +When you want a little more context, Klepon can answer short follow-up questions privately on device with an optional local guide.
8 +
9 +What you can do in Klepon:
10 +- Explore curated Indonesian food guides
11 +- Learn dishes, ingredients, and traditions
12 +- Search quickly when you spot an unfamiliar name
13 +- Save dishes you want to remember
14 +- Ask short follow-up questions privately on device
15 +
16 +Klepon is for curious eaters, travelers, diaspora families, and anyone who wants a more thoughtful way to discover Indonesian food.
AppStore/metadata-tvos/en-US/keywords.txt new
+1
@@ -0,0 +1 @@
1 +indonesian food,dishes,ingredients,cuisine,guide,travel
AppStore/metadata-tvos/en-US/name.txt new
+1
@@ -0,0 +1 @@
1 +Klepon: Taste of Indonesia
AppStore/metadata-tvos/en-US/promotional_text.txt new
+1
@@ -0,0 +1 @@
1 +A calm Apple TV guide to Indonesian dishes, ingredients, and food traditions.
AppStore/metadata-tvos/en-US/review_notes.txt new
+5
@@ -0,0 +1,5 @@
1 +This tvOS app is a browse-first guide and is fully usable without enabling the private guide.
2 +
3 +The private guide is optional. If the user chooses to enable it, the app downloads a local on-device model and uses it for short follow-up answers inside the guide.
4 +
5 +The tvOS target uses the same main app bundle identifier as the iPhone app and uses the shared app group container for local model storage when available.
AppStore/metadata-tvos/en-US/subtitle.txt new
+1
@@ -0,0 +1 @@
1 +Indonesian food guide
AppStore/release-checklist.md
+4
@@ -4,6 +4,7 @@
4
5 - [ ] iPhone app builds cleanly
6 - [ ] macOS app builds cleanly
7 +- [ ] tvOS app builds cleanly
8 - [ ] visionOS app builds cleanly
9 - [ ] watchOS companion builds cleanly
10 - [ ] README is current
@@ -18,6 +19,7 @@
19 - [ ] Ask flow works on device with acceptable latency
20 - [ ] Watch app content is readable and useful at a glance
21 - [ ] macOS window flows feel native and polished enough for v1
22 +- [ ] tvOS focus and remote navigation feel polished enough for v1
23 - [ ] visionOS window flows feel polished enough for a simple v1
24 - [ ] No obvious sample-app copy remains
25
@@ -25,6 +27,7 @@
27
28 - [ ] iPhone bundle identifier is correct
29 - [ ] macOS bundle identifier is correct
30 +- [ ] tvOS bundle identifier is correct
31 - [ ] visionOS bundle identifier is correct
32 - [ ] watch bundle identifier is correct
33 - [ ] App Group entitlement is correct for the shipping account
@@ -35,6 +38,7 @@
38
39 - [ ] TestFlight build installed on at least one real iPhone
40 - [ ] macOS archive validates cleanly for App Store submission
41 +- [ ] tvOS archive validates cleanly for App Store submission
42 - [ ] visionOS archive validates cleanly for App Store submission
43 - [ ] Watch companion installed and tested on at least one real Apple Watch
44 - [ ] Release notes are written
AppStore/screenshots/README.md
+9
@@ -24,6 +24,15 @@
24 3. `Ask privately on device`
25 - Show the ask flow with a grounded answer card and source chips.
26
27 +## tvOS screenshots
28 +
29 +1. `A calm guide on Apple TV`
30 + - Show the Discover screen with focus on the featured dish and one visible collection rail.
31 +2. `Browse and save from the couch`
32 + - Show a readable Search or Saved view with a realistic shortlist.
33 +3. `Ask privately on device`
34 + - Show the ask flow with a grounded answer card and focus-friendly suggestions.
35 +
36 ## visionOS screenshots
37
38 1. `A calm guide in your space`
AppStore/screenshots/tvos/.gitkeep
AppStore/testflight-checklist.md
+2
@@ -13,6 +13,7 @@
13 - [ ] iPhone target builds on simulator
14 - [ ] iPhone target runs on a real device
15 - [ ] macOS target builds on the release Xcode version
16 +- [ ] tvOS target builds on the release Xcode version
17 - [ ] visionOS target builds on the release Xcode version
18 - [ ] Watch target builds on simulator
19 - [ ] Watch target runs with the paired iPhone app
@@ -39,4 +40,5 @@
40 - [ ] No local machine junk files are staged
41 - [ ] Bundle identifiers and App Group values are intentional for the release build
42 - [ ] macOS release signing uses the sandboxed entitlements file
43 +- [ ] tvOS release signing uses the shared app identifier and App Group entitlement
44 - [ ] visionOS release signing uses the shared app identifier and App Group entitlement
AppStore/tvos-appstore-notes.md new
+62
@@ -0,0 +1,62 @@
1 +# tvOS App Store notes
2 +
3 +## Bundle identifier
4 +
5 +The tvOS target uses the same bundle identifier as the iPhone app:
6 +
7 +- `ai.splitfire.klepon`
8 +
9 +That keeps the main Apple-platform app identity aligned across iPhone, Apple TV, Mac, and visionOS. The watch companion still uses its own watch bundle identifier, which Apple requires for the companion app target.
10 +
11 +## App shape
12 +
13 +The current tvOS target is intentionally simple for v1.
14 +
15 +- It is a focus-friendly SwiftUI app
16 +- It uses tabs and navigation stacks
17 +- It keeps the private guide inside the existing browse-first experience
18 +
19 +This is deliberate. The goal is a clean, stable App Store MVP for Apple TV without overbuilding the first release.
20 +
21 +## Required configuration
22 +
23 +The tvOS target uses:
24 +
25 +- `KleponTV/Info.plist`
26 +- `KleponTV/KleponTV.entitlements`
27 +
28 +Important settings:
29 +
30 +- `ITSAppUsesNonExemptEncryption = false`
31 +- `com.apple.security.application-groups = group.com.ondeinference.apps`
32 +
33 +The App Group keeps local model storage aligned with the other Apple targets.
34 +
35 +## Build and archive
36 +
37 +Generate the project:
38 +
39 +```/dev/null/sh#L1-1
40 +xcodegen generate
41 +```
42 +
43 +Build the tvOS target locally:
44 +
45 +```/dev/null/sh#L1-1
46 +xcodebuild build -project Klepon.xcodeproj -scheme 'Klepon TV' -destination 'generic/platform=tvOS Simulator'
47 +```
48 +
49 +Archive the tvOS target:
50 +
51 +```/dev/null/sh#L1-1
52 +xcodebuild archive -project Klepon.xcodeproj -scheme 'Klepon TV' -destination 'generic/platform=tvOS' -archivePath build/KleponTV.xcarchive
53 +```
54 +
55 +## Submission checklist
56 +
57 +Before upload, confirm:
58 +
59 +- the signing profile is for `ai.splitfire.klepon`
60 +- the App Group capability exists for the shipping team
61 +- the app feels clean and navigable with the Siri Remote focus model
62 +- tvOS screenshots and metadata are ready in `AppStore/screenshots/tvos/` and `AppStore/metadata-tvos/en-US/`
Klepon.xcodeproj/project.pbxproj
+2 -2
@@ -1276,7 +1276,7 @@
1276 "@executable_path/Frameworks",
1277 );
1278 MARKETING_VERSION = 1.0.0;
1279 - PRODUCT_BUNDLE_IDENTIFIER = ai.splitfire.klepon.tv;
1279 + PRODUCT_BUNDLE_IDENTIFIER = ai.splitfire.klepon;
1280 PRODUCT_NAME = Klepon;
1281 SDKROOT = appletvos;
1282 SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -1441,7 +1441,7 @@
1441 "@executable_path/Frameworks",
1442 );
1443 MARKETING_VERSION = 1.0.0;
1444 - PRODUCT_BUNDLE_IDENTIFIER = ai.splitfire.klepon.tv;
1444 + PRODUCT_BUNDLE_IDENTIFIER = ai.splitfire.klepon;
1445 PRODUCT_NAME = Klepon;
1446 SDKROOT = appletvos;
1447 SWIFT_OPTIMIZATION_LEVEL = "-O";
Klepon/Assets.xcassets/AppIconTV.appiconset/AppIconTV-Large.png
Binary files a/Klepon/Assets.xcassets/AppIconTV.appiconset/AppIconTV-Large.png and /dev/null differ
Klepon/Assets.xcassets/AppIconTV.appiconset/AppIconTV-Large@2x.png
Binary files a/Klepon/Assets.xcassets/AppIconTV.appiconset/AppIconTV-Large@2x.png and /dev/null differ
Klepon/Assets.xcassets/AppIconTV.appiconset/AppIconTV-Small.png
Binary files a/Klepon/Assets.xcassets/AppIconTV.appiconset/AppIconTV-Small.png and /dev/null differ
Klepon/Assets.xcassets/AppIconTV.appiconset/AppIconTV-Small@2x.png
Binary files a/Klepon/Assets.xcassets/AppIconTV.appiconset/AppIconTV-Small@2x.png and /dev/null differ
Klepon/Assets.xcassets/AppIconTV.appiconset/Contents.json deleted
-12
@@ -1,12 +0,0 @@
1 -{
2 - "images" : [
3 - { "idiom" : "tv", "size" : "400x240", "scale" : "1x", "filename" : "AppIconTV-Small.png" },
4 - { "idiom" : "tv", "size" : "400x240", "scale" : "2x", "filename" : "AppIconTV-Small@2x.png" },
5 - { "idiom" : "tv", "size" : "1280x768", "scale" : "1x", "filename" : "AppIconTV-Large.png" },
6 - { "idiom" : "tv", "size" : "1280x768", "scale" : "2x", "filename" : "AppIconTV-Large@2x.png" }
7 - ],
8 - "info" : {
9 - "author" : "xcode",
10 - "version" : 1
11 - }
12 -}
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS - App Store.imagestack/Back.imagestacklayer/Content.imageset/Back.png
Binary files /dev/null and b/Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS - App Store.imagestack/Back.imagestacklayer/Content.imageset/Back.png differ
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json new
+12
@@ -0,0 +1,12 @@
1 +{
2 + "images" : [
3 + {
4 + "filename" : "Back.png",
5 + "idiom" : "tv"
6 + }
7 + ],
8 + "info" : {
9 + "author" : "xcode",
10 + "version" : 1
11 + }
12 +}
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS - App Store.imagestack/Back.imagestacklayer/Contents.json new
+6
@@ -0,0 +1,6 @@
1 +{
2 + "info" : {
3 + "author" : "xcode",
4 + "version" : 1
5 + }
6 +}
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS - App Store.imagestack/Contents.json new
+14
@@ -0,0 +1,14 @@
1 +{
2 + "info" : {
3 + "author" : "xcode",
4 + "version" : 1
5 + },
6 + "layers" : [
7 + {
8 + "filename" : "Front.imagestacklayer"
9 + },
10 + {
11 + "filename" : "Back.imagestacklayer"
12 + }
13 + ]
14 +}
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json new
+12
@@ -0,0 +1,12 @@
1 +{
2 + "images" : [
3 + {
4 + "filename" : "Front.png",
5 + "idiom" : "tv"
6 + }
7 + ],
8 + "info" : {
9 + "author" : "xcode",
10 + "version" : 1
11 + }
12 +}
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS - App Store.imagestack/Front.imagestacklayer/Content.imageset/Front.png
Binary files /dev/null and b/Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS - App Store.imagestack/Front.imagestacklayer/Content.imageset/Front.png differ
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS - App Store.imagestack/Front.imagestacklayer/Contents.json new
+6
@@ -0,0 +1,6 @@
1 +{
2 + "info" : {
3 + "author" : "xcode",
4 + "version" : 1
5 + }
6 +}
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS.imagestack/Back.imagestacklayer/Content.imageset/Back.png
Binary files /dev/null and b/Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS.imagestack/Back.imagestacklayer/Content.imageset/Back.png differ
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS.imagestack/Back.imagestacklayer/Content.imageset/Back@2x.png
Binary files /dev/null and b/Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS.imagestack/Back.imagestacklayer/Content.imageset/Back@2x.png differ
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS.imagestack/Back.imagestacklayer/Content.imageset/Contents.json new
+18
@@ -0,0 +1,18 @@
1 +{
2 + "images" : [
3 + {
4 + "filename" : "Back.png",
5 + "idiom" : "tv",
6 + "scale" : "1x"
7 + },
8 + {
9 + "filename" : "Back@2x.png",
10 + "idiom" : "tv",
11 + "scale" : "2x"
12 + }
13 + ],
14 + "info" : {
15 + "author" : "xcode",
16 + "version" : 1
17 + }
18 +}
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS.imagestack/Back.imagestacklayer/Contents.json new
+12
@@ -0,0 +1,12 @@
1 +{
2 + "info" : {
3 + "author" : "xcode",
4 + "version" : 1
5 + },
6 + "properties" : {
7 + "frame-size" : {
8 + "height" : 240,
9 + "width" : 400
10 + }
11 + }
12 +}
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS.imagestack/Contents.json new
+14
@@ -0,0 +1,14 @@
1 +{
2 + "info" : {
3 + "author" : "xcode",
4 + "version" : 1
5 + },
6 + "layers" : [
7 + {
8 + "filename" : "Front.imagestacklayer"
9 + },
10 + {
11 + "filename" : "Back.imagestacklayer"
12 + }
13 + ]
14 +}
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS.imagestack/Front.imagestacklayer/Content.imageset/Contents.json new
+18
@@ -0,0 +1,18 @@
1 +{
2 + "images" : [
3 + {
4 + "filename" : "Front.png",
5 + "idiom" : "tv",
6 + "scale" : "1x"
7 + },
8 + {
9 + "filename" : "Front@2x.png",
10 + "idiom" : "tv",
11 + "scale" : "2x"
12 + }
13 + ],
14 + "info" : {
15 + "author" : "xcode",
16 + "version" : 1
17 + }
18 +}
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS.imagestack/Front.imagestacklayer/Content.imageset/Front.png
Binary files /dev/null and b/Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS.imagestack/Front.imagestacklayer/Content.imageset/Front.png differ
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS.imagestack/Front.imagestacklayer/Content.imageset/Front@2x.png
Binary files /dev/null and b/Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS.imagestack/Front.imagestacklayer/Content.imageset/Front@2x.png differ
Klepon/Assets.xcassets/AppIconTV.brandassets/App Icon - tvOS.imagestack/Front.imagestacklayer/Contents.json new
+12
@@ -0,0 +1,12 @@
1 +{
2 + "info" : {
3 + "author" : "xcode",
4 + "version" : 1
5 + },
6 + "properties" : {
7 + "frame-size" : {
8 + "height" : 240,
9 + "width" : 400
10 + }
11 + }
12 +}
Klepon/Assets.xcassets/AppIconTV.brandassets/Contents.json new
+32
@@ -0,0 +1,32 @@
1 +{
2 + "assets" : [
3 + {
4 + "filename" : "App Icon - tvOS - App Store.imagestack",
5 + "idiom" : "tv",
6 + "role" : "primary-app-icon",
7 + "size" : "1280x768"
8 + },
9 + {
10 + "filename" : "App Icon - tvOS.imagestack",
11 + "idiom" : "tv",
12 + "role" : "primary-app-icon",
13 + "size" : "400x240"
14 + },
15 + {
16 + "filename" : "Top Shelf Image.imageset",
17 + "idiom" : "tv",
18 + "role" : "top-shelf-image",
19 + "size" : "1920x720"
20 + },
21 + {
22 + "filename" : "Top Shelf Image Wide.imageset",
23 + "idiom" : "tv",
24 + "role" : "top-shelf-image-wide",
25 + "size" : "2320x720"
26 + }
27 + ],
28 + "info" : {
29 + "author" : "xcode",
30 + "version" : 1
31 + }
32 +}
Klepon/Assets.xcassets/AppIconTV.brandassets/Top Shelf Image Wide.imageset/Contents.json new
+18
@@ -0,0 +1,18 @@
1 +{
2 + "images" : [
3 + {
4 + "filename" : "TopShelfImageWide.png",
5 + "idiom" : "tv",
6 + "scale" : "1x"
7 + },
8 + {
9 + "filename" : "TopShelfImageWide@2x.png",
10 + "idiom" : "tv",
11 + "scale" : "2x"
12 + }
13 + ],
14 + "info" : {
15 + "author" : "xcode",
16 + "version" : 1
17 + }
18 +}
Klepon/Assets.xcassets/AppIconTV.brandassets/Top Shelf Image Wide.imageset/TopShelfImageWide.png
Binary files /dev/null and b/Klepon/Assets.xcassets/AppIconTV.brandassets/Top Shelf Image Wide.imageset/TopShelfImageWide.png differ
Klepon/Assets.xcassets/AppIconTV.brandassets/Top Shelf Image Wide.imageset/TopShelfImageWide@2x.png
Binary files /dev/null and b/Klepon/Assets.xcassets/AppIconTV.brandassets/Top Shelf Image Wide.imageset/TopShelfImageWide@2x.png differ
Klepon/Assets.xcassets/AppIconTV.brandassets/Top Shelf Image.imageset/Contents.json new
+18
@@ -0,0 +1,18 @@
1 +{
2 + "images" : [
3 + {
4 + "filename" : "TopShelfImage.png",
5 + "idiom" : "tv",
6 + "scale" : "1x"
7 + },
8 + {
9 + "filename" : "TopShelfImage@2x.png",
10 + "idiom" : "tv",
11 + "scale" : "2x"
12 + }
13 + ],
14 + "info" : {
15 + "author" : "xcode",
16 + "version" : 1
17 + }
18 +}
Klepon/Assets.xcassets/AppIconTV.brandassets/Top Shelf Image.imageset/TopShelfImage.png
Binary files /dev/null and b/Klepon/Assets.xcassets/AppIconTV.brandassets/Top Shelf Image.imageset/TopShelfImage.png differ
Klepon/Assets.xcassets/AppIconTV.brandassets/Top Shelf Image.imageset/TopShelfImage@2x.png
Binary files /dev/null and b/Klepon/Assets.xcassets/AppIconTV.brandassets/Top Shelf Image.imageset/TopShelfImage@2x.png differ
Klepon/Features/Ask/AskSheetView.swift
+6 -2
@@ -34,7 +34,9 @@ struct AskSheetView: View {
34 Button("Close") {
35 dismiss()
36 }
37 - .keyboardShortcut(.cancelAction)
37 + #if os(macOS)
38 + .keyboardShortcut(.cancelAction)
39 + #endif
40 }
41 #endif
42
@@ -187,7 +189,9 @@ struct AskSheetView: View {
189 Button("Close") {
190 dismiss()
191 }
190 - .keyboardShortcut(.cancelAction)
192 + #if os(macOS)
193 + .keyboardShortcut(.cancelAction)
194 + #endif
195 .tint(KleponColor.accent)
196 }
197 }
README.md
+1 -1
@@ -68,7 +68,7 @@ python3 Scripts/validate_content.py
68
69 If you run your own fork, change the bundle identifier and App Group to values you control.
70
71 -The macOS and visionOS targets use the same main app bundle identifier as iPhone. The macOS target also uses a sandboxed entitlements file for App Store distribution.
71 +The macOS, tvOS, and visionOS targets use the same main app bundle identifier as iPhone. The macOS target also uses a sandboxed entitlements file for App Store distribution.
72
73 ## License
74
project.yml
+1 -1
@@ -322,7 +322,7 @@ targets:
322 echo "Updated CFBundleVersion to ${BUNDLE_VERSION}"
323 settings:
324 base:
325 - PRODUCT_BUNDLE_IDENTIFIER: ai.splitfire.klepon.tv
325 + PRODUCT_BUNDLE_IDENTIFIER: ai.splitfire.klepon
326 PRODUCT_NAME: Klepon
327 MARKETING_VERSION: "1.0.0"
328 CURRENT_PROJECT_VERSION: 1