Summary
Create a pure Swift shell over SwiftUsd so application and feature targets can use OpenUSD functionality without importing raw Swift/C++ interop types or enabling C++ interop themselves.
The goal is not to replace SwiftUsd. SwiftUsd remains the runtime binding and engine layer over OpenUSD. SwiftUsdShell becomes the stable pure Swift SDK surface: handles, values, DTOs, protocols, semantic requests, and results.
Productization Goal
The main goal is to productize OpenUSD as an SDK capability that is painless for host applications:
- Hosts should not import
OpenUSD, raw SwiftUsd/OpenUSD C++ interop modules, or USDInteropCxx.
- Hosts should not need Swift/C++ interop enabled just to inspect, validate, or edit USD assets.
- Hosts should avoid paying large build-time and invalidation costs from raw OpenUSD headers in app and feature targets.
- Common workflows should be driven through pure Swift APIs and stable DTOs.
Architectural Clarification
The intended final layering is:
OpenUSD
Native USD engine and C++ implementation.
SwiftUsd
Swift runtime/binding layer over OpenUSD.
Owns direct OpenUSD interaction wherever possible.
Generic missing authoring/inspection primitives should be added here first.
SwiftUsdShell
Pure Swift public SDK surface.
No OpenUSD import.
No Swift/C++ interop.
Defines handles, paths, tokens, values, DTOs, protocols, semantic requests, and results.
First-party USD packages, such as USDTools
Product/domain workflows over SwiftUsdShell APIs.
Keep raw runtime details private and transitional.
Public APIs must stay pure Swift and shell-facing.
Application and external consumers
Import SwiftUsdShell and pure Swift domain APIs.
Do not import OpenUSD, USDInteropCxx, or raw SwiftUsd/OpenUSD interop surfaces.
SwiftUsdShellRuntime should not become a renamed USDInterop. If a runtime implementation target exists, it should prefer SwiftUsd as its implementation dependency and only drop to raw OpenUSD for explicitly documented gaps that cannot yet be expressed through SwiftUsd. Those gaps should be candidates for moving down into SwiftUsd.
USDInterop Policy
USDInterop is transitional scaffolding, not the final SDK boundary.
- Do not grow
USDInterop as the long-term productized runtime layer.
- Generic OpenUSD-safe operations currently in
USDInterop should be classified and migrated:
- runtime/binding primitives belong in SwiftUsd where possible;
- pure Swift API contracts belong in SwiftUsdShell;
- product workflow logic belongs in USDTools or another domain package.
- New work should avoid adding broad new public concepts to
USDInterop unless needed to unblock an immediate migration or bug.
- Consumers must never be required to depend on
USDInterop or USDInteropCxx for common workflows.
Problem
SwiftUsd already ships native OpenUSD libraries as binaries, but consumers still pay large compile-time and invalidation costs when they import the raw OpenUSD C++ API surface through Swift/C++ interop.
The cost leaks whenever public APIs expose imported C++ types such as:
UsdStage
UsdStageRefPtr
UsdPrim
UsdAttribute
UsdShadeShader
UsdShadeMaterial
SdfPath
TfToken
VtValue
Gf*
OpenUSD.*
pxrInternal_*
This prevents clean productization because downstream consumers must still understand the heavy C++ interop surface.
Non-Goals
- Do not hand-write a
.usda parser.
- Do not replace SwiftUsd/OpenUSD.
- Do not expose raw OpenUSD escape hatches in public APIs.
- Do not make
USDInterop the permanent SDK runtime layer.
- Do not attempt to complete every OpenUSD schema before proving the boundary.
- Do not binary-package the runtime before the public API is pure Swift.
Hard Rules
SwiftUsdShell must never import OpenUSD, SwiftUsd raw interop modules, USDInterop, USDInteropCxx, or any C++ interop target.
- Public shell APIs must not mention raw SwiftUsd/OpenUSD types.
- Runtime implementation should use SwiftUsd first. Direct OpenUSD use is allowed only as private implementation debt for missing SwiftUsd capabilities.
- Any public API that exposes
Usd*, Sdf*, Tf*, Vt*, Gf*, OpenUSD.*, or pxrInternal_* is a shelling failure unless the type is a pure Swift shell type.
- Migration must be measurable by removing raw USD imports or C++ interop requirements from at least one downstream consumer.
USDInterop dependencies in first-party packages must be treated as migration debt, not final architecture.
Phase 0: Package Bootstrap
Exit criteria:
SwiftUsdShell has zero OpenUSD imports.
SwiftUsdShell has zero USDInterop or USDInteropCxx imports.
SwiftUsdShell has zero .interoperabilityMode(.Cxx).
- A trivial consumer can import
SwiftUsdShell without C++ interop.
Phase 1: Runtime Capability Inventory
Before creating a runtime target, inventory the real missing capabilities.
Exit criteria:
- Runtime gaps are explicitly classified.
- Any direct OpenUSD or USDInterop dependency has a documented migration target.
Phase 2: Mid-Weight Pilot In USDToolsMaterials
Use USDToolsMaterials as the first serious proof. It is large enough to be meaningful and small enough to complete.
Initial focus: read-only material inspection and detection, not mutation.
Exit criteria:
USDToolsMaterials has a complete read-only material inspection API that does not expose raw USD types.
- At least one downstream consumer can call material inspection through shell handles.
- Remaining raw public APIs are documented as migration debt.
Phase 3: Migrate One Real Consumer
Use Preflight as the internal proving ground, but do not make this package Preflight-specific.
Exit criteria:
- One real product path uses
SwiftUsdShell APIs instead of raw SwiftUsd/OpenUSD APIs.
- The migration reveals concrete remaining raw USD dependencies instead of hiding them.
Phase 4: Expand Shell Core Types
Add pure Swift representations as needed by real APIs:
Exit criteria:
- Common read-only inspection results can be represented without
VtValue, TfToken, or SdfPath leaking.
Phase 5: Material Mutation Shell
After read-only material inspection works, migrate material edits.
Exit criteria:
- Material inspection and material edit planning/mutation can be driven through pure Swift public APIs.
- Preflight can perform common material edits without importing raw OpenUSD or USDInterop in app/feature targets.
- Remaining USDInterop use is private, documented, and targeted for removal or movement into SwiftUsd.
Phase 6: Broader USDTools Shelling
Apply the pattern to other first-party packages in priority order:
USDToolsMaterials
USDToolsInspection
USDToolsTransformSupport
USDAnalysis
USDToolsSession
USDToolsSurgery
AppleUSDSchemasUSD
For each package:
Exit criteria:
- First-party public APIs no longer require downstream consumers to import raw OpenUSD, USDInterop, or C++ interop targets for common workflows.
Phase 7: Code Generation
Once the manual shell shape is validated, introduce code generation.
Potential inputs:
- SwiftUsd symbols and APIs
- OpenUSD schema information, where needed
- Apple
SwiftUsd-ast-answerer ideas
- symbol graphs where useful
Generate:
- pure Swift shell wrappers
- SwiftUsd-backed bridge methods where appropriate
- schema wrappers
- token sets
- enum/value mappings
Exit criteria:
- Repetitive schema/value wrapper work is generated, not hand-maintained.
- Generated public APIs remain pure Swift.
Phase 8: Binary Or Service Productization
Only after public APIs are pure Swift:
Exit criteria:
- Consumers can use meaningful USD functionality without rebuilding/reimporting SwiftUsd in most app/feature targets.
Phase 9: External Consumer Proof With Bismuth
Use Bismuth as an external proof after internal shelling works.
Exit criteria:
- Bismuth can import static USD scene data through shell APIs without taking a direct raw SwiftUsd/OpenUSD dependency in its core renderer/DSL.
Completion Definition
The whole SwiftUsd shelling effort is complete when:
SwiftUsdShell is a standalone pure Swift package.
- SwiftUsd remains the preferred runtime binding layer over OpenUSD.
- Public shell APIs cover the main read/write workflows needed by first-party packages.
- First-party packages expose pure Swift APIs for common workflows.
- Raw SwiftUsd/OpenUSD and USDInterop types are no longer part of app-facing public APIs.
- At least one real app/feature consumer uses shell APIs without direct raw OpenUSD, USDInterop, or C++ interop imports.
- Build impact has been measured before and after.
- Binary or service packaging has been evaluated after the API boundary is clean.
- Bismuth or another external consumer can use the shell without becoming tied to raw SwiftUsd/OpenUSD.
Initial Implementation Note
The first concrete pilot should be USDToolsMaterials, specifically the read-only material inspection surface. This is intentionally more meaningful than a trivial stage-cache handle proof, but still smaller than shelling all of USDTools at once.
For mutation work, prefer adding missing generic runtime primitives to SwiftUsd, then representing them through SwiftUsdShell pure Swift contracts. Use USDInterop only as temporary compatibility scaffolding while migrating existing USDTools behavior.
Summary
Create a pure Swift shell over SwiftUsd so application and feature targets can use OpenUSD functionality without importing raw Swift/C++ interop types or enabling C++ interop themselves.
The goal is not to replace SwiftUsd. SwiftUsd remains the runtime binding and engine layer over OpenUSD.
SwiftUsdShellbecomes the stable pure Swift SDK surface: handles, values, DTOs, protocols, semantic requests, and results.Productization Goal
The main goal is to productize OpenUSD as an SDK capability that is painless for host applications:
OpenUSD, raw SwiftUsd/OpenUSD C++ interop modules, orUSDInteropCxx.Architectural Clarification
The intended final layering is:
SwiftUsdShellRuntimeshould not become a renamedUSDInterop. If a runtime implementation target exists, it should prefer SwiftUsd as its implementation dependency and only drop to raw OpenUSD for explicitly documented gaps that cannot yet be expressed through SwiftUsd. Those gaps should be candidates for moving down into SwiftUsd.USDInterop Policy
USDInteropis transitional scaffolding, not the final SDK boundary.USDInteropas the long-term productized runtime layer.USDInteropshould be classified and migrated:USDInteropunless needed to unblock an immediate migration or bug.USDInteroporUSDInteropCxxfor common workflows.Problem
SwiftUsd already ships native OpenUSD libraries as binaries, but consumers still pay large compile-time and invalidation costs when they import the raw OpenUSD C++ API surface through Swift/C++ interop.
The cost leaks whenever public APIs expose imported C++ types such as:
UsdStageUsdStageRefPtrUsdPrimUsdAttributeUsdShadeShaderUsdShadeMaterialSdfPathTfTokenVtValueGf*OpenUSD.*pxrInternal_*This prevents clean productization because downstream consumers must still understand the heavy C++ interop surface.
Non-Goals
.usdaparser.USDInteropthe permanent SDK runtime layer.Hard Rules
SwiftUsdShellmust never importOpenUSD, SwiftUsd raw interop modules,USDInterop,USDInteropCxx, or any C++ interop target.Usd*,Sdf*,Tf*,Vt*,Gf*,OpenUSD.*, orpxrInternal_*is a shelling failure unless the type is a pure Swift shell type.USDInteropdependencies in first-party packages must be treated as migration debt, not final architecture.Phase 0: Package Bootstrap
SwiftUsdShellas a standalone package.USDStageHandleUSDPrimHandleUSDPathUSDTokenUSDAssetPathUSDLoadPolicySwiftUsdShellErrorHashable,Sendable, andCodablewhere appropriate.SwiftUsdShellbuilds without Swift/C++ interop.Exit criteria:
SwiftUsdShellhas zeroOpenUSDimports.SwiftUsdShellhas zeroUSDInteroporUSDInteropCxximports.SwiftUsdShellhas zero.interoperabilityMode(.Cxx).SwiftUsdShellwithout C++ interop.Phase 1: Runtime Capability Inventory
Before creating a runtime target, inventory the real missing capabilities.
URLExit criteria:
Phase 2: Mid-Weight Pilot In
USDToolsMaterialsUse
USDToolsMaterialsas the first serious proof. It is large enough to be meaningful and small enough to complete.Initial focus: read-only material inspection and detection, not mutation.
SwiftUsdShelldependency toUSDToolsMaterials.detectShaderSystems(in: USDStageHandle)detectOrigin(in: USDStageHandle)detectMaterialOutputs(in: USDStageHandle, materialPath:)detectMaterialMode(in: USDStageHandle, materialPath:)editableMaterialContract(in: USDStageHandle, materialPath:)inspectMaterialSources(in: USDStageHandle, materialPath:)Exit criteria:
USDToolsMaterialshas a complete read-only material inspection API that does not expose raw USD types.Phase 3: Migrate One Real Consumer
Use Preflight as the internal proving ground, but do not make this package Preflight-specific.
PreflightUSDInterop.UsdStageRefPtrmaterial calls with shell handle calls.OpenUSD,USDInterop, or C++ interop dependency for that path.Exit criteria:
SwiftUsdShellAPIs instead of raw SwiftUsd/OpenUSD APIs.Phase 4: Expand Shell Core Types
Add pure Swift representations as needed by real APIs:
USDValueUSDTimeCodeUSDAttributeSummaryUSDRelationshipSummaryUSDPrimSummaryUSDMaterialSummaryUSDConnectionExit criteria:
VtValue,TfToken, orSdfPathleaking.Phase 5: Material Mutation Shell
After read-only material inspection works, migrate material edits.
UsdShade*,Sdf*,Tf*,VtValue, or raw OpenUSD types.Exit criteria:
Phase 6: Broader USDTools Shelling
Apply the pattern to other first-party packages in priority order:
USDToolsMaterialsUSDToolsInspectionUSDToolsTransformSupportUSDAnalysisUSDToolsSessionUSDToolsSurgeryAppleUSDSchemasUSDFor each package:
USDInteropdependencies as migration debt.Exit criteria:
Phase 7: Code Generation
Once the manual shell shape is validated, introduce code generation.
Potential inputs:
SwiftUsd-ast-answererideasGenerate:
Exit criteria:
Phase 8: Binary Or Service Productization
Only after public APIs are pure Swift:
Exit criteria:
Phase 9: External Consumer Proof With Bismuth
Use Bismuth as an external proof after internal shelling works.
BismuthUSDoptional module.SwiftUsdShellAPIs.Entity,MeshResource, and material types.Exit criteria:
Completion Definition
The whole SwiftUsd shelling effort is complete when:
SwiftUsdShellis a standalone pure Swift package.Initial Implementation Note
The first concrete pilot should be
USDToolsMaterials, specifically the read-only material inspection surface. This is intentionally more meaningful than a trivial stage-cache handle proof, but still smaller than shelling all of USDTools at once.For mutation work, prefer adding missing generic runtime primitives to SwiftUsd, then representing them through SwiftUsdShell pure Swift contracts. Use USDInterop only as temporary compatibility scaffolding while migrating existing USDTools behavior.