Files
vnidrop/packaging/apple/studio/README.md
cdricms 98661cef15 feat(studio): iPad screenshot support + cleanup
Generalize the studio into a Platform/DeviceModel abstraction so it renders
both iPhone and iPad sets from one code path.

- Platform: per-target canvas (iPad 2064x2752), 3D model, capture sim, and
  output subfolder (iPad -> <Language>/iPad/). PLATFORM=iphone|ipad.
- DeviceModel: screen material, orientation (yaw) fix, optional glass mesh,
  graphite recolor — the per-model quirks the renderer needs.
- SceneKit renderer: auto-generates planar UVs for screen meshes that ship
  without them; textures every material matching the screen name; zFar scaled
  for large-unit models; body recolor skips the real screen material.
- iPad uses a CC BY 4.0 model (commercial-safe) with real bezel geometry;
  first-pass iPad layouts for all four screens. capture.sh is PLATFORM-aware.

Remove now-dead code: the 2D mockup fallback (ClipDeviceRenderer,
MockupGeometry), the orbit ring and binary-tunnel (superseded by the route arc
and the encryption-flow), unused DeviceModel UV/inset workarounds; refresh the
README and .gitignore to match.
2026-08-09 18:20:53 +02:00

63 lines
3.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# App Store screenshot studio
Code-driven, fully local App Store screenshots — composed natively with **SwiftUI +
`ImageRenderer`** and **SceneKit** (no Typst, no ImageMagick). Each marketing screen is a
SwiftUI view (gradient + 3D device + captions + generated artwork) rendered off-screen to
an exact-size PNG. Captions come from `strings.json` (9 locales); the app screenshots on
the device screens are captured from the real app.
## Requirements
- Xcode / Swift toolchain (macOS 26+). That's it.
## Run
```sh
swift run studio # all locales × screens -> generated/<Language>/
swift run studio --publish # -> ../<Language>/ (ships to App Store)
LOCALES="fr de" SCREENS="share-securely" swift run studio # subset
PLATFORM=ipad swift run studio # iPad set -> generated/<Language>/iPad/
```
Run from this directory (it reads `strings.json` and `assets/` relative to cwd).
## Full pipeline
```sh
./capture.sh # real localized app screens -> generated/shots/<platform>/<locale>/
swift run studio # composite everything -> generated/<Language>/[iPad/]
./generate.sh # capture + composite in one shot (forwards PLATFORM / --publish)
```
`capture.sh` drives the app into each screen via the DEBUG `-VniScreenshot` launch
argument (see `apple/VniDrop/App/ScreenshotSupport.swift`), once per locale via
`-AppleLanguages`, in dark mode with a 9:41 status bar. Screenshots are transient
(git-ignored, regenerated per run) — during layout iteration, capture once then re-run
`swift run studio` on its own.
## Platforms
`PLATFORM=iphone` (default) or `ipad`. Each `Platform` (`Sources/studio/Platform.swift`)
carries its canvas size, capture simulator, output subfolder, and a `DeviceModel` — the
`.usdz`, its screen material, the orientation fix (yaw so the screen faces the camera),
optional front-glass mesh to hide, and whether to tint the body graphite. Adding a device
(e.g. Mac) is a new `DeviceModel` + `Platform` case + a layout set.
## Device rendering
`SceneKitDeviceRenderer` textures the captured screenshot onto the model's screen mesh and
renders it off-screen. Curvature, bezel and body are the model's real geometry; poses
(pitch/yaw/roll) and a studio environment (IBL + bloom) are applied in the scene. It
auto-generates planar UVs for screen meshes that ship without them.
## Assets (`assets/`)
- `iphone-17-pro-max.usdz`, `ipad-pro.usdz` — the 3D devices (committed; CC BY 4.0, see
`ATTRIBUTION.md`).
- `globe.png` — for the send-anywhere hero (committed).
- `generated/shots/<platform>/<locale>/*.png` — captured app screens (transient).
## Layout & tuning
- `Sources/studio/ScreenSpec.swift` — per-platform layouts (`iphone` / `ipad`): gradient,
device pose/position/size, globe + route (send-anywhere), the encryption flow
(stay-private: `beams``lock``stream` + `banners`), caption placement.
- `Sources/studio/ScreenFrame.swift` — the composition (layer order, caption fitting,
generated artwork).
## Screens
`share-securely`, `choose-receivers`, `send-anywhere` (globe + Paris→LA route arc,
reuses the share screenshot), `stay-private` (two stacked phones + encryption beams →
padlock → binary protection stream, with localized CHIFFREMENT/PROTECTION banners).