Native prototype embedding¶
The automobile:prototype/native resource turns a shown or saved prototype into files a real app
can build: the spec, a short host file and the asset list. The renderer is not generated; the host
file calls the published library (auto-mobile-prototype-compose on Android, the
AutoMobilePrototype Swift package on iOS), so every spec feature the library supports works
embedded without per-feature code generation.
Resolution¶
src/features/prototype/nativePrototype.ts resolves the id in this order:
- The spec a device is showing (
PrototypeShownSpecs), when exactly one device shows it ordeviceIdnames one. A show still in flight is an error, never a fallback to an older saved spec. - The saved prototype mirror for
deviceId. WithoutdeviceId, a saved-only id is an error, because the resource cannot pick a device.
The platform comes from the platform parameter, else the device that showed the prototype.
Generated names¶
Ids are opaque strings up to 256 characters, but they become directory, file and type names:
- Directory and asset file stems keep the id when it is
[A-Za-z0-9_-]and at most 64 characters. Otherwise they are the sanitized id cut to fit, plus an 8-character SHA-256 prefix of the original id, so ids that sanitize alike (hero/a,hero?a) or share a long prefix stay distinct. - The host type name is the id in PascalCase plus
Prototype, with the same hash suffix unless the id is plain alphanumeric and short. - iOS exports refuse asset ids that are canonically equivalent in Unicode (
éwritten two ways), because Swift compares dictionary keys that way and the generated literal would trap at launch. Android keeps both, since JVM strings compare by code unit.
String literals are escaped per language (nativePrototypeTemplates.ts): Kotlin uses \uXXXX code
units and escapes $; Swift uses \u{X} scalars.
Host file contract¶
- Android reads the spec and assets from
assets/prototypes/<directory>/withrunCatching, so a missing file falls back to the renderer’s load-error view or image placeholder instead of crashing composition. The template is ktfmt-stable, so generated hosts pass the Kotlin format check unchanged. - iOS reads them once into
static letvalues from the app bundle’sPrototypes/<directory>/folder reference. - Both hosts pass only
onEventandonDismiss; error views use the renderer defaults until the app edits the host. - A
storageblock opts the host in to file-backed storage. Requests use the embedded routing decision indocs/decisions/prototype-embedded-request-routing.md.
Samples and checks¶
test/fixtures/prototype-embedding/sample.jsonis rendered through the resource byscripts/prototype/generateEmbeddingSamples.tsintosamples/prototype-embedding/and, for the SwiftUI host, theEmbedConsumerfixture underios/prototype-agent/Fixtures/.nativePrototypeSamples.test.ts(and the script’s--check) fail when they drift from the output.- The samples are pinned to LF in
.gitattributesand excluded from oxfmt, so neither a Windows checkout nor the formatter can make them differ from the resource output. scripts/android/validate-prototype-compose-consumer.shcompiles the Android sample against the locally published renderer in a minified consumer app; the iOS library build compilesEmbedConsumer.