App Clip (Warden demo) + Beta skin — design
App Clip (Warden demo) + Beta skin — design
Section titled “App Clip (Warden demo) + Beta skin — design”Status: approved in brainstorm with Chris, 2026-10-14. Target: 1.2 (an App Clip ships inside an app version’s build, so it lands with whichever version it is ready for; not 1.1, freeze 10-17).
Retargeted to 1.1 under a hard drop rule (Chris, 2026-10-15): if the clip is not green on Chris’s iPhone by the 2026-10-17 feature freeze it comes out of 1.1 and follows in 1.1.1. The “Target: 1.2” line above is superseded.
The web demo already offers “try before install”, but a native clip feels like the game is already installed: polished, full-speed Metal, haptics, and a one-tap install that continues straight into the full game. The clip is a short spectacle — swarm, rapid power growth, Warden fight — that ends on a “continue playing” card.
In this spec:
- The App Clip — Warden run, end card, install overlay, “Beta skin earned” handoff flag.
- The Beta skin — a cosmetic skin layer in the full app, four candidate looks to A/B, unlocked from the clip flag.
- Branded launch screen + boot splash — shared by the full app and the clip. Independent of the clip; can ship earlier (e.g. 1.1) on its own.
Out of scope (follow-on spec): Game Center in the full app, with unlocks (Beta skin included)
associated to the player’s Game Center id server-side so they follow the player across devices.
Builds on the account-shaped cloud-save backup (2026-10-04-cloud-save-backup-design.md). Game Center
is NOT used inside the clip (friction in a 2-minute session; GameKit availability inside App Clips
unverified).
Later, once internet multiplayer is live: Beta nameplate badge, Beta drone colour, Beta-only spawn-in warp effect.
Feasibility spike (2026-10-14, throwaway)
Section titled “Feasibility spike (2026-10-14, throwaway)”- A copy of the iOS shell converted to an App Clip target (product type
com.apple.product-type.application.on-demand-install-capable, entitlementscom.apple.developer.on-demand-install-capable+parent-application-identifiers,NSAppClipplist dict, iOS 17.0 deployment target) built, signed, installed and booted on iPhone 15 Pro Max (tutorial and menu both reached). Signing registered App IDdigital.lumara.bulletheaven.dev.Clip. - Limit: 100 MB uncompressed, iOS 17+, digital invocation only (Safari banner, Messages, Maps, Spotlight, App Store). Physical invocations (QR/NFC/App Clip Code) cap at 15 MB except via the App Store Connect demo link.
- Measured sizes (BUILD ~325):
Part Full iOS build Clip estimate Engine binary (stripped; unstripped 79 MB) 54 MB 54 MB .pck95 MB (60 music, 18.7 shader cache, 14.6 SFX) ~33-36 MB Frameworks (Sentry 7 MB + haptics) 7.3 MB ~0.3 MB Assets/plist ~1 MB ~1 MB Total ~89-92 MB - Shader cache is ~85% 2D
CanvasShaderRD(used); only ~3 MB of 3DSceneForwardMobileShaderRDcan go. - Headroom lever if needed later: a fork engine build with 3D disabled (shrinks the 54 MB binary). Optional, not a blocker.
Player experience
Section titled “Player experience”- Launch — branded black launch screen with key art, seamless handoff to a matching engine boot splash. No grey, no Godot logo.
- No menu, no tutorial — straight into a 3-2-1 countdown on Cobalt. One controls hint line for the first 5 s.
- Ramp (~45 s) — dense swarm, ~3x XP, about 3 level-ups (was ~5x; Chris 2026-10-16: “way too many upgrades, need about 1/3”). Offers drawn ONLY from a curated showpiece pool (evolutions, Rift Bolt, Supernova, etc.) so every pick is a visible jump.
- Warden (~60-90 s) — spawn growl, boss theme, tuned so a typical player wins in ~75 s; losing is possible.
- Handoff, win or lose — “Warden destroyed. Beta skin unlocked.” / “So close. Beta skin unlocked anyway.” Then the “continue playing” card: full-game highlights (more bosses, areas, hulls) and Apple’s install overlay. The skin is granted on BOTH outcomes.
- Replay — secondary “Fight again”.
Total session ~2-2.5 min.
Architecture
Section titled “Architecture”Build: one codebase, a new preset + mode
Section titled “Build: one codebase, a new preset + mode”- New export preset
iOS-Clipinplatform/tvos/export_presets.cfgwith feature tagapp_clipand a content-strippingexclude_filter(all music exceptboss_theme;audio/candidates; SFX not used by the clip run; Sentry addon; 3D shader cache if excludable). main.gdon boot:OS.has_feature("app_clip")→_on_mode_chosen("clip")directly, bypassing the start menu, tutorial and survival intro.
ClipDirector (new, /sim, extends RefCounted)
Section titled “ClipDirector (new, /sim, extends RefCounted)”- Drives ramp → Warden spawn → end state; exposes
phaseandoutcomefor the render/UI to read. - Console tunables (registry +
tools/tunable_docs/docs.d/*.jsonlabel + LiveScope hook, perbh-tunable-batch):clip_xp_mult,clip_ramp_s,clip_warden_hp_scale,clip_swarm_density. Simhas no mode field today (main.gdholds_mode): the run setup attaches aClipDirectorto the sim only in clip mode; null everywhere else.- Curated offer pool:
UpgradeSystem.roll_upgrade_choicesfilters to the clip pool when aClipDirectoris attached, still drawing fromupgrade_rng. - Warden spawned through the normal spawn path with
biomass_vpassed explicitly (XP trap in root CLAUDE.md). - Everything gated on clip mode: survival/coop/determinism baselines must not move (pinned tests).
Native bridge: addons/dc_appclip (new GDExtension, built like dc_haptics)
Section titled “Native bridge: addons/dc_appclip (new GDExtension, built like dc_haptics)”group_container_path() -> Stringfor App Groupgroup.digital.lumara.bulletheaven(both targets).present_install_overlay()→SKOverlaywithAppClipConfiguration.- iOS-only; excluded from every non-iOS preset.
- Handoff file:
<group>/clip_rewards.json{ "beta_skin": true, "earned_at": <unix> }. Clip writes it at end state; the full app reads it on launch, grants the skin intoMetaState, and marks it consumed (idempotent re-grant is harmless).
Xcode: scripted, never hand-edited
Section titled “Xcode: scripted, never hand-edited”scripts/release/add-app-clip-target.shadds the clip target tobuild-ios(product type, entitlements incl. App Group,NSAppClipdict, iOS 17 target, embeds the clip in the parent’sAppClips/, bundles the clip.pck, links the samelibgodot.a). Idempotent; re-run after any full export, likeapply-ios-metrickit.sh. Tracked inputs live inplatform/tvos/patches/.- Parent app gains the App Group entitlement too.
- Clip bundle ids: store
digital.lumara.bulletheaven.Clip, Devdigital.lumara.bulletheaven.dev.Clip.
Size gate (structural)
Section titled “Size gate (structural)”- The clip build fails if the thinned clip exceeds 95 MB (App Thinning size report from the archive/export).
Beta skin (full app)
Section titled “Beta skin (full app)”- Skins are a NEW render-only concept, separate from hulls (hulls carry stats in
sim/ship_bonuses.gd).MetaState.owned_skins: Array[String]+equipped_skin: String; aShipSkinlayer in the player renderer applied over any hull. Never touches/simstats. - Four candidates behind a live console tunable
ship_skin(0 off, 1-4):- Prototype wireframe — glowing cyan edge lines over near-black fill, slow scanline sweep.
- Holo-film — oil-slick iridescence that shifts hue with banking; reuses the Supernova thin-film work.
- Glitch build — RGB channel split, brief corruption jitter on warp/hit; must not read as a bug.
- Void chrome — black mirror-chrome, single white-hot rim, faint violet afterimage trail.
- Chris A/Bs on device; the winner becomes “Beta”. Soft/glow draws use covered saved materials with
the
hdr_alpharemap (root CLAUDE.md); review in both SDR and HDR. - Equip UI: a skin row in the hull picker (fit-tested at iPad/iPhone/TV profiles).
Launch screen + boot splash
Section titled “Launch screen + boot splash”- Replace the iOS
Launch Screen.storyboard(currently grey 0.14 + Godot’s stockSplashImage) with a black background + Dark Cosmos key art; tracked copy inpatches/. - Set
application/boot_splash/*(image + black bg) inplatform/tvos/project.godotto match, so the native → engine handoff is seamless. Also tvOS’s launch image.
Testing
Section titled “Testing”- GUT: clip-mode XP multiplier; offers restricted to the curated pool; Warden spawns at ramp end via
the real spawn → kill →
_sweep_deadpath (awarded XP asserted); end state fires on win AND loss; handoff read/write through an injectable path; skin grant idempotent. - Determinism: the three pinned baseline tests stay green untouched.
- Shaders (skins): windowed compile under
mobileandgl_compatibility; baked iPhone Dev install check (A17 baker bug). - Device: App Clip local experience on iPhone (Settings → Developer → Local Experiences); fresh
install via
bh-fresh-install-stall-check; install-from-clip → full app grants the skin. - Size gate passes.
Open items
Section titled “Open items”- Curated showpiece pool contents (pick in implementation with Chris).
- Beta skin winner (after the A/B).
- App Store Connect: App Clip experience metadata (header image, subtitle, action “Play”), Safari
Smart App Banner on darkcosmos site (
~/Claude/bullet-heaven-site) — outward-facing, Chris’s OK.