peachsim 0.1.1644 → 0.1.1653
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/cli/app-catalog.ts +1 -1
- package/cli/app-fonts.ts +11 -80
- package/cli/app-splash.ts +18 -12
- package/cli/bridge-flow-runner.ts +11 -7
- package/cli/cloud-client.ts +10 -13
- package/cli/command-registry.ts +13 -4
- package/cli/commands/box.ts +4 -4
- package/cli/commands/control.ts +93 -53
- package/cli/commands/coverage-parser.ts +67 -0
- package/cli/commands/coverage.ts +550 -0
- package/cli/commands/debug.ts +9 -18
- package/cli/commands/desktop.ts +19 -7
- package/cli/commands/device.ts +14 -9
- package/cli/commands/guest-host.ts +6 -10
- package/cli/commands/inspect/core.ts +81 -17
- package/cli/commands/inspect.ts +13 -8
- package/cli/commands/kotlin.ts +2 -2
- package/cli/commands/maestro-compare.ts +1 -1
- package/cli/commands/platform.ts +20 -11
- package/cli/commands/preview.ts +16 -18
- package/cli/commands/runtime.ts +3 -2
- package/cli/commands/screenshot-layers.ts +1 -1
- package/cli/commands/screenshot.ts +1 -1
- package/cli/commands/serve.ts +5 -1
- package/cli/commands/support.ts +4 -4
- package/cli/commands/three-mode.ts +22 -15
- package/cli/commands/upload.ts +44 -45
- package/cli/current-sim.ts +38 -0
- package/cli/desktop-companion.ts +36 -8
- package/cli/device-option.ts +1 -1
- package/cli/drivers/playwright.ts +1 -0
- package/cli/drivers/types.ts +4 -0
- package/cli/help-core.ts +1 -1
- package/cli/internal-child.ts +2 -1
- package/cli/main.ts +9 -3
- package/cli/outbound-endpoints.ts +11 -3
- package/cli/output-redaction.ts +39 -14
- package/cli/remote-simulators.ts +4 -1
- package/cli/scene-video.ts +5 -2
- package/cli/send-to-box.ts +7 -10
- package/cli/telemetry.ts +1 -1
- package/cli/ws-bridge.ts +8 -1
- package/detox/attempt-events.cjs +3 -1
- package/detox/attempt-events.d.cts +1 -1
- package/detox/expectations.ts +108 -99
- package/detox/frame-offset.d.mts +6 -0
- package/detox/frame-offset.mjs +35 -0
- package/detox/gestures.ts +6 -18
- package/detox/index.ts +169 -101
- package/detox/jest-preset.cjs +1 -3
- package/detox/jest-transform.cjs +4 -0
- package/detox/matchers.ts +3 -0
- package/detox/motion-change.cjs +46 -114
- package/detox/motion-change.d.cts +5 -27
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +65 -1
- package/dist-lib/bridge-contract-input.mjs +63 -1
- package/dist-lib/bridge-contract.cjs +19 -1
- package/dist-lib/bridge-contract.mjs +17 -1
- package/dist-lib/bundle-channel.cjs +38091 -14846
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/config.mjs +5 -3
- package/dist-lib/detox/index.cjs +1244 -4509
- package/dist-lib/detox/jest-preset.cjs +1 -3
- package/dist-lib/detox/jest-transform.cjs +4 -0
- package/dist-lib/dev-bundle-resolution.cjs +28 -24
- package/dist-lib/expo-swift-bundle.cjs +35049 -13125
- package/dist-lib/expo-swift-metadata.cjs +1 -1
- package/dist-lib/expo-swift-metadata.mjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +45112 -63143
- package/dist-lib/host/fetch-proxy-handler.cjs +3544 -11
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +1909 -2029
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +2 -2
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +380 -522
- package/dist-lib/native-app-identity-project.cjs +39 -252
- package/dist-lib/native-app-identity-project.mjs +1174 -11
- package/dist-lib/native-app-identity.cjs +8 -3
- package/dist-lib/native-app-identity.mjs +8 -3
- package/dist-lib/native-firebase-metadata.cjs +1 -1
- package/dist-lib/native-firebase-metadata.mjs +1 -1
- package/dist-lib/plist.cjs +2 -244
- package/dist-lib/plist.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/public-origins-lib-esm.json +290 -0
- package/dist-lib/public-origins-lib-static.json +1 -0
- package/dist-lib/public-origins-lib.json +1852 -0
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +14 -253
- package/dist-lib/sdk.cjs +83 -16
- package/dist-lib/sdk.mjs +81 -15
- package/dist-lib/skills.cjs +50546 -75098
- package/dist-lib/swift-compile.cjs +25897 -1070
- package/dist-lib/swift-compile.mjs +25866 -1033
- package/dist-lib/swift-package.cjs +79 -1
- package/dist-lib/swift-package.mjs +75 -1
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift-toolchain.cjs +1 -1
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +34273 -12349
- package/dist-lib/vite.cjs +373 -298
- package/dist-lib/worklet-executable.cjs +1 -1
- package/dist-lib/worklet-executable.mjs +1 -1
- package/dist-types/packages/peach-compat/src/engine-config.d.ts +2 -0
- package/dist-types/packages/peach-compat/src/stubs/form-sheet-spring.d.ts +9 -0
- package/dist-types/packages/peach-compat/src/stubs/native-evaluation-lease.d.ts +47 -0
- package/dist-types/packages/peach-compat/src/stubs/native-seams/react-native-cookies.d.ts +113 -0
- package/dist-types/packages/peach-compat/src/stubs/native-seams/react-native-gesture-handler.d.ts +154 -0
- package/dist-types/packages/peach-compat/src/stubs/screen-transition-math.d.ts +756 -0
- package/dist-types/packages/peach-compat/src/stubs/transition-scalar.d.ts +25 -0
- package/dist-types/packages/peach-engine/src/billing/plans.d.ts +64 -0
- package/dist-types/packages/peach-engine/src/browser-page-target.d.ts +2 -0
- package/dist-types/packages/peach-engine/src/bundle-platform-url.d.ts +3 -0
- package/dist-types/packages/peach-engine/src/capture/browser-accessibility-host.d.ts +3 -0
- package/dist-types/packages/peach-engine/src/capture/browser-composite.d.ts +55 -0
- package/dist-types/packages/peach-engine/src/capture/browserAccessibilityContract.d.ts +27 -0
- package/dist-types/packages/peach-engine/src/capture/nativeScreenCaptureContract.d.ts +22 -0
- package/dist-types/packages/peach-engine/src/cli-companion.d.ts +36 -0
- package/dist-types/packages/peach-engine/src/components/native-ui/webview-frame-bridge.d.ts +34 -0
- package/dist-types/packages/peach-engine/src/config.d.ts +5 -0
- package/dist-types/packages/peach-engine/src/engine/android-stretch-effect.d.ts +57 -0
- package/dist-types/packages/peach-engine/src/engine/animated-driven-style.d.ts +47 -0
- package/dist-types/packages/peach-engine/src/engine/animated-value.d.ts +5 -0
- package/dist-types/packages/peach-engine/src/engine/animated.d.ts +195 -0
- package/dist-types/packages/peach-engine/src/engine/animation-clockContract.d.ts +15 -0
- package/dist-types/packages/peach-engine/src/engine/animation-graph.d.ts +148 -0
- package/dist-types/packages/peach-engine/src/engine/app-catalog-wire.d.ts +10 -0
- package/dist-types/packages/peach-engine/src/engine/app-font-registry.d.ts +87 -0
- package/dist-types/packages/peach-engine/src/engine/attributed-paragraph-paint.d.ts +7 -0
- package/dist-types/packages/peach-engine/src/engine/attributed-paragraph.d.ts +123 -0
- package/dist-types/packages/peach-engine/src/engine/audioContract.d.ts +16 -0
- package/dist-types/packages/peach-engine/src/engine/canvaskit-api.d.ts +93 -0
- package/dist-types/packages/peach-engine/src/engine/canvaskit-renderer.d.ts +216 -0
- package/dist-types/packages/peach-engine/src/engine/config-plugin-fonts.d.ts +40 -0
- package/dist-types/packages/peach-engine/src/engine/config-plugin-splash.d.ts +25 -0
- package/dist-types/packages/peach-engine/src/engine/cull-visibility.d.ts +44 -0
- package/dist-types/packages/peach-engine/src/engine/damage-rect.d.ts +19 -0
- package/dist-types/packages/peach-engine/src/engine/engine-resource.d.ts +6 -0
- package/dist-types/packages/peach-engine/src/engine/expo-manifest.d.ts +5 -0
- package/dist-types/packages/peach-engine/src/engine/fiber-debug-metadata.d.ts +30 -0
- package/dist-types/packages/peach-engine/src/engine/font-config.d.ts +139 -0
- package/dist-types/packages/peach-engine/src/engine/generated/sf-pro-font.d.ts +1 -0
- package/dist-types/packages/peach-engine/src/engine/glass-material.d.ts +31 -0
- package/dist-types/packages/peach-engine/src/engine/host-composite.d.ts +100 -0
- package/dist-types/packages/peach-engine/src/engine/hosted-semantics.d.ts +49 -0
- package/dist-types/packages/peach-engine/src/engine/image-audit.d.ts +70 -0
- package/dist-types/packages/peach-engine/src/engine/image-loader.d.ts +350 -0
- package/dist-types/packages/peach-engine/src/engine/inspect-info.d.ts +27 -0
- package/dist-types/packages/peach-engine/src/engine/inspect-outline.d.ts +14 -0
- package/dist-types/packages/peach-engine/src/engine/inspect-visibility.d.ts +33 -0
- package/dist-types/packages/peach-engine/src/engine/ios-fast-scroll.d.ts +16 -0
- package/dist-types/packages/peach-engine/src/engine/layout-sab.d.ts +43 -0
- package/dist-types/packages/peach-engine/src/engine/liquid-glass-rect.d.ts +23 -0
- package/dist-types/packages/peach-engine/src/engine/liquid-glass-shaders.d.ts +9 -0
- package/dist-types/packages/peach-engine/src/engine/liquid-glass.d.ts +283 -0
- package/dist-types/packages/peach-engine/src/engine/live-object-counts.d.ts +6 -0
- package/dist-types/packages/peach-engine/src/engine/lottie-runtime.d.ts +32 -0
- package/dist-types/packages/peach-engine/src/engine/lottie-types.d.ts +138 -0
- package/dist-types/packages/peach-engine/src/engine/memory-counts.d.ts +27 -0
- package/dist-types/packages/peach-engine/src/engine/metalDirectContract.d.ts +108 -0
- package/dist-types/packages/peach-engine/src/engine/metalShaderContract.d.ts +217 -0
- package/dist-types/packages/peach-engine/src/engine/native-animation-driver.d.ts +112 -0
- package/dist-types/packages/peach-engine/src/engine/native-animation-graph.d.ts +62 -0
- package/dist-types/packages/peach-engine/src/engine/native-layout.d.ts +133 -0
- package/dist-types/packages/peach-engine/src/engine/native-resources.d.ts +26 -0
- package/dist-types/packages/peach-engine/src/engine/nativeReanimatedContract.d.ts +25 -0
- package/dist-types/packages/peach-engine/src/engine/nativeReplayContract.d.ts +64 -0
- package/dist-types/packages/peach-engine/src/engine/node.d.ts +589 -0
- package/dist-types/packages/peach-engine/src/engine/paint-boundary-types.d.ts +112 -0
- package/dist-types/packages/peach-engine/src/engine/paint-boundary.d.ts +57 -0
- package/dist-types/packages/peach-engine/src/engine/portalContract.d.ts +21 -0
- package/dist-types/packages/peach-engine/src/engine/portals.d.ts +20 -0
- package/dist-types/packages/peach-engine/src/engine/render-damage.d.ts +107 -0
- package/dist-types/packages/peach-engine/src/engine/riveContract.d.ts +420 -0
- package/dist-types/packages/peach-engine/src/engine/rn-spring.d.ts +51 -0
- package/dist-types/packages/peach-engine/src/engine/scene-table.d.ts +379 -0
- package/dist-types/packages/peach-engine/src/engine/scroll-momentum-math.d.ts +152 -0
- package/dist-types/packages/peach-engine/src/engine/scroll-pan-contacts.d.ts +10 -0
- package/dist-types/packages/peach-engine/src/engine/scroll-platform.d.ts +75 -0
- package/dist-types/packages/peach-engine/src/engine/scroll-range.d.ts +14 -0
- package/dist-types/packages/peach-engine/src/engine/scroll-velocity.d.ts +14 -0
- package/dist-types/packages/peach-engine/src/engine/scroll.d.ts +320 -0
- package/dist-types/packages/peach-engine/src/engine/signal.d.ts +7 -0
- package/dist-types/packages/peach-engine/src/engine/snapshot-cache-policy.d.ts +6 -0
- package/dist-types/packages/peach-engine/src/engine/svg-geometry.d.ts +41 -0
- package/dist-types/packages/peach-engine/src/engine/text-attachment-paragraphs.d.ts +10 -0
- package/dist-types/packages/peach-engine/src/engine/text-decoration.d.ts +11 -0
- package/dist-types/packages/peach-engine/src/engine/text-line-break.d.ts +22 -0
- package/dist-types/packages/peach-engine/src/engine/text-paint-receipt.d.ts +98 -0
- package/dist-types/packages/peach-engine/src/engine/text-paragraph.d.ts +11 -0
- package/dist-types/packages/peach-engine/src/engine/text-paragraphContract.d.ts +34 -0
- package/dist-types/packages/peach-engine/src/engine/text-transform.d.ts +1 -0
- package/dist-types/packages/peach-engine/src/engine/types.d.ts +657 -0
- package/dist-types/packages/peach-engine/src/engine/visible-frame.d.ts +54 -0
- package/dist-types/packages/peach-engine/src/engine/webrtcContract.d.ts +74 -0
- package/dist-types/packages/peach-engine/src/graphite-stats-fields.d.ts +184 -0
- package/dist-types/packages/peach-engine/src/guest-import-meta.d.ts +12 -0
- package/dist-types/packages/peach-engine/src/guest-module-overrides.d.ts +7 -0
- package/dist-types/packages/peach-engine/src/ios/app-card-types.d.ts +7 -0
- package/dist-types/packages/peach-engine/src/ios/apps/canvas-map-data.d.ts +177 -0
- package/dist-types/packages/peach-engine/src/ios/aux-home-scene.d.ts +54 -0
- package/dist-types/packages/peach-engine/src/ios/chrome-metrics.d.ts +47 -0
- package/dist-types/packages/peach-engine/src/ios/constants.d.ts +21 -0
- package/dist-types/packages/peach-engine/src/ios/duo-housing.d.ts +37 -0
- package/dist-types/packages/peach-engine/src/ios/home/types.d.ts +29 -0
- package/dist-types/packages/peach-engine/src/ios/home-app-catalog.d.ts +43 -0
- package/dist-types/packages/peach-engine/src/ios/photo-store.d.ts +73 -0
- package/dist-types/packages/peach-engine/src/ios/photoLibraryContract.d.ts +166 -0
- package/dist-types/packages/peach-engine/src/ios/shell-controller-types.d.ts +21 -0
- package/dist-types/packages/peach-engine/src/ios/shell-transition-debug.d.ts +18 -0
- package/dist-types/packages/peach-engine/src/metro-asset-path.d.ts +21 -0
- package/dist-types/packages/peach-engine/src/metro-fingerprint-registry-client.d.ts +11 -0
- package/dist-types/packages/peach-engine/src/metro-fingerprint.d.ts +38 -0
- package/dist-types/packages/peach-engine/src/native-preview-bundle.d.ts +44 -0
- package/dist-types/packages/peach-engine/src/observability/types.d.ts +74 -0
- package/dist-types/packages/peach-engine/src/peach-warm-manifest.d.ts +32 -0
- package/dist-types/packages/peach-engine/src/permissions/app-settings-client.d.ts +25 -0
- package/dist-types/packages/peach-engine/src/permissions/system-permission-types.d.ts +20 -0
- package/dist-types/packages/peach-engine/src/platform/android-back-panel.d.ts +131 -0
- package/dist-types/packages/peach-engine/src/platform/android-gesture-exclusion.d.ts +28 -0
- package/dist-types/packages/peach-engine/src/platform/android-predictive-back.d.ts +33 -0
- package/dist-types/packages/peach-engine/src/platform/system-bars-state.d.ts +14 -0
- package/dist-types/packages/peach-engine/src/playwright-sim-host.d.ts +1 -0
- package/dist-types/packages/peach-engine/src/preview/bundle-layout.d.ts +8 -0
- package/dist-types/packages/peach-engine/src/preview/bundle-variantContract.d.ts +24 -0
- package/dist-types/packages/peach-engine/src/preview/capture-bundle.d.ts +26 -0
- package/dist-types/packages/peach-engine/src/preview/compress-node.d.ts +2 -0
- package/dist-types/packages/peach-engine/src/preview/compress.d.ts +2 -0
- package/dist-types/packages/peach-engine/src/preview/presigned-upload.d.ts +60 -0
- package/dist-types/packages/peach-engine/src/preview/trace.d.ts +144 -0
- package/dist-types/packages/peach-engine/src/preview/upload-protocol.d.ts +152 -0
- package/dist-types/packages/peach-engine/src/profiler/animation-recording-loader.d.ts +1 -0
- package/dist-types/packages/peach-engine/src/profiler/profile-trace.d.ts +4 -0
- package/dist-types/packages/peach-engine/src/react-bridge.d.ts +3 -0
- package/dist-types/packages/peach-engine/src/react-native/AppState.d.ts +45 -0
- package/dist-types/packages/peach-engine/src/react-native/Appearance.d.ts +34 -0
- package/dist-types/packages/peach-engine/src/react-native/framework-colors-data.d.ts +2 -0
- package/dist-types/packages/peach-engine/src/react-native/host-services.d.ts +42 -0
- package/dist-types/packages/peach-engine/src/react-native/layout-animation.d.ts +22 -0
- package/dist-types/packages/peach-engine/src/react-native/platform-colors.d.ts +17 -0
- package/dist-types/packages/peach-engine/src/remote-stream/client-config.d.ts +10 -0
- package/dist-types/packages/peach-engine/src/remote-stream/cloud-display.d.ts +58 -0
- package/dist-types/packages/peach-engine/src/remote-stream/scene-recording.d.ts +45 -0
- package/dist-types/packages/peach-engine/src/render-worker/animated-drive-output.d.ts +35 -0
- package/dist-types/packages/peach-engine/src/render-worker/app-load.d.ts +16 -0
- package/dist-types/packages/peach-engine/src/render-worker/aux-surface-types.d.ts +2 -0
- package/dist-types/packages/peach-engine/src/render-worker/canvaskit-shared.d.ts +42 -0
- package/dist-types/packages/peach-engine/src/render-worker/canvaskit-webgpu.d.ts +434 -0
- package/dist-types/packages/peach-engine/src/render-worker/canvaskit-worker-init.d.ts +12 -0
- package/dist-types/packages/peach-engine/src/render-worker/compositor-backend.d.ts +31 -0
- package/dist-types/packages/peach-engine/src/render-worker/compositor-gpu.d.ts +202 -0
- package/dist-types/packages/peach-engine/src/render-worker/compositor-protocol.d.ts +1945 -0
- package/dist-types/packages/peach-engine/src/render-worker/compositor-runtime/scroll-drag-resample.d.ts +44 -0
- package/dist-types/packages/peach-engine/src/render-worker/css-keyframes-drive.d.ts +36 -0
- package/dist-types/packages/peach-engine/src/render-worker/edit-menu-geometry.d.ts +8 -0
- package/dist-types/packages/peach-engine/src/render-worker/engine-resource-relay.d.ts +21 -0
- package/dist-types/packages/peach-engine/src/render-worker/expo-widgetContract.d.ts +16 -0
- package/dist-types/packages/peach-engine/src/render-worker/gesture-seam-protocol.d.ts +152 -0
- package/dist-types/packages/peach-engine/src/render-worker/graph-linked-value.d.ts +29 -0
- package/dist-types/packages/peach-engine/src/render-worker/graphite-pipeline-compiler-contract.d.ts +49 -0
- package/dist-types/packages/peach-engine/src/render-worker/graphite-pipeline-compiler.d.ts +12 -0
- package/dist-types/packages/peach-engine/src/render-worker/host-service-protocol.d.ts +756 -0
- package/dist-types/packages/peach-engine/src/render-worker/image-lifecycle-event.d.ts +22 -0
- package/dist-types/packages/peach-engine/src/render-worker/image-pixel-contract.d.ts +48 -0
- package/dist-types/packages/peach-engine/src/render-worker/live-frame-mirror.d.ts +34 -0
- package/dist-types/packages/peach-engine/src/render-worker/map-command-channel.d.ts +189 -0
- package/dist-types/packages/peach-engine/src/render-worker/mapNativeContract.d.ts +101 -0
- package/dist-types/packages/peach-engine/src/render-worker/native-dynamic-synchronizable.d.ts +22 -0
- package/dist-types/packages/peach-engine/src/render-worker/native-menu-gesture.d.ts +9 -0
- package/dist-types/packages/peach-engine/src/render-worker/native-ui-commandContract.d.ts +23 -0
- package/dist-types/packages/peach-engine/src/render-worker/native-ui-protocol.d.ts +1087 -0
- package/dist-types/packages/peach-engine/src/render-worker/native-widgetContract.d.ts +100 -0
- package/dist-types/packages/peach-engine/src/render-worker/nativeAnimMirrorContract.d.ts +174 -0
- package/dist-types/packages/peach-engine/src/render-worker/nativeSyncReplyContract.d.ts +11 -0
- package/dist-types/packages/peach-engine/src/render-worker/one-native-contentContract.d.ts +54 -0
- package/dist-types/packages/peach-engine/src/render-worker/pointerSampleContract.d.ts +14 -0
- package/dist-types/packages/peach-engine/src/render-worker/protocol.d.ts +880 -0
- package/dist-types/packages/peach-engine/src/render-worker/reanimated-css-contract.d.ts +63 -0
- package/dist-types/packages/peach-engine/src/render-worker/reanimated-readiness.d.ts +29 -0
- package/dist-types/packages/peach-engine/src/render-worker/resilient-frame-clock.d.ts +22 -0
- package/dist-types/packages/peach-engine/src/render-worker/retained-app-load.d.ts +20 -0
- package/dist-types/packages/peach-engine/src/render-worker/screen-edge-swipe-commit-protocol.d.ts +1 -0
- package/dist-types/packages/peach-engine/src/render-worker/screen-form-sheet-commit-protocol.d.ts +26 -0
- package/dist-types/packages/peach-engine/src/render-worker/scroll-mirror-tenant.d.ts +37 -0
- package/dist-types/packages/peach-engine/src/render-worker/scroll-mirror.d.ts +164 -0
- package/dist-types/packages/peach-engine/src/render-worker/shell-event-registry.d.ts +119 -0
- package/dist-types/packages/peach-engine/src/render-worker/shell-gesture-regions.d.ts +41 -0
- package/dist-types/packages/peach-engine/src/render-worker/shell-protocol.d.ts +603 -0
- package/dist-types/packages/peach-engine/src/render-worker/shell-scene-schema.d.ts +101 -0
- package/dist-types/packages/peach-engine/src/render-worker/shell-tree-inline-sources.d.ts +13 -0
- package/dist-types/packages/peach-engine/src/render-worker/shell-tree-wire.d.ts +87 -0
- package/dist-types/packages/peach-engine/src/render-worker/test-bridge-protocol.d.ts +47 -0
- package/dist-types/packages/peach-engine/src/render-worker/text-inputContract.d.ts +93 -0
- package/dist-types/packages/peach-engine/src/render-worker/tree-sync-port.d.ts +102 -0
- package/dist-types/packages/peach-engine/src/render-worker/webgpu-frame-transaction.d.ts +292 -0
- package/dist-types/packages/peach-engine/src/render-worker/webgpu-readback-scheduler.d.ts +107 -0
- package/dist-types/packages/peach-engine/src/render-worker/webview-capture-protocol.d.ts +16 -0
- package/dist-types/packages/peach-engine/src/render-worker/worker-input-runtime.d.ts +211 -0
- package/dist-types/packages/peach-engine/src/render-worker/worker-storage.d.ts +33 -0
- package/dist-types/packages/peach-engine/src/render-worker/worklet-runtime.d.ts +987 -0
- package/dist-types/packages/peach-engine/src/render-worker/worklet-sab.d.ts +24 -0
- package/dist-types/packages/peach-engine/src/rolldown-bundle-inventory.d.ts +84 -0
- package/dist-types/packages/peach-engine/src/rolldown-production-fingerprint.d.ts +31 -0
- package/dist-types/packages/peach-engine/src/screenshots/timeline-assets.d.ts +10 -0
- package/dist-types/packages/peach-engine/src/screenshots/tokens.d.ts +9 -0
- package/dist-types/packages/peach-engine/src/settings/devices.d.ts +70 -0
- package/dist-types/packages/peach-engine/src/settings/duo-fold-bus.d.ts +87 -0
- package/dist-types/packages/peach-engine/src/settings/interface-rotation.d.ts +30 -0
- package/dist-types/packages/peach-engine/src/settings/react-native-configuration.d.ts +12 -0
- package/dist-types/packages/peach-engine/src/settings/scene-geometryContract.d.ts +40 -0
- package/dist-types/packages/peach-engine/src/settings/store.d.ts +37 -0
- package/dist-types/packages/peach-engine/src/shell-events.d.ts +203 -0
- package/dist-types/packages/peach-engine/src/shell-intent.d.ts +68 -0
- package/dist-types/packages/peach-engine/src/sootsim-event.d.ts +35 -0
- package/dist-types/packages/peach-engine/src/top-overlay-state.d.ts +5 -0
- package/dist-types/packages/peach-engine/src/web-authentication-automation-host.d.ts +2 -0
- package/dist-types/packages/peach-engine/src/webAuthenticationContract.d.ts +34 -0
- package/dist-types/packages/peach-engine/src/webview-automation-host.d.ts +180 -0
- package/dist-types/packages/peach-engine/src/wireframe-mode.d.ts +16 -0
- package/dist-types/packages/peach-globals/src/frameBreakdownContract.d.ts +16 -0
- package/dist-types/packages/peach-globals/src/index.d.ts +3311 -0
- package/dist-types/packages/peach-globals/src/nativeSurfaceContract.d.ts +76 -0
- package/dist-types/packages/peach-globals/src/pointerSourceEventContract.d.ts +8 -0
- package/dist-types/packages/peach-globals/src/profileTrace.d.ts +11 -0
- package/dist-types/packages/peach-globals/src/profilerContract.d.ts +223 -0
- package/dist-types/packages/peach-kit/src/capabilities.d.ts +721 -0
- package/dist-types/packages/peach-kit/src/internal.d.ts +4 -0
- package/dist-types/packages/peach-kit/src/materials/types.d.ts +27 -0
- package/dist-types/packages/peach-kit/src/materials/uikit-blur-material.d.ts +14 -0
- package/dist-types/packages/peach-kit/src/navigation-types.d.ts +11 -0
- package/dist-types/packages/peach-kit/src/react-bridge.d.ts +53 -0
- package/dist-types/packages/peach-kit/src/runtime.d.ts +26 -0
- package/dist-types/packages/peach-kit/src/ui/hosting-safe-area.d.ts +24 -0
- package/dist-types/packages/peach-kit/src/ui/popover-placement.d.ts +53 -0
- package/dist-types/packages/peach-kit/src/ui/presentationContract.d.ts +17 -0
- package/kotlin/ComposeSources/PeachComposeHost.kt +1 -1
- package/kotlin/JniSources/com/facebook/jni/HybridData.kt +0 -2
- package/kotlin/JniSources/dev/peach/jni/NativeBindings.kt +0 -2
- package/kotlin/JniTransportSources/dev/peach/jni/integration/JniTransport.kt +0 -2
- package/kotlin/README.md +6 -0
- package/package.json +22 -2
- package/runtime-companion.json +1 -0
- package/skills/contrast/SKILL.md +1 -0
- package/src/assetCatalogContract.ts +21 -0
- package/src/bridge-contract-input.ts +84 -0
- package/src/bridge-contract.ts +35 -3
- package/src/browser-launch-policy.ts +1 -0
- package/src/bundle-channel.mjs +4 -2
- package/src/cli-runtime.ts +55 -0
- package/src/crash-fingerprint.ts +26 -0
- package/src/dev-bundle-resolution.ts +50 -23
- package/src/device-catalog.ts +1159 -0
- package/src/host/bridge-host.ts +3 -26
- package/src/host/browser-pointer.ts +71 -0
- package/src/host/dev-server-package-versions.ts +23 -0
- package/src/host/fetch-proxy-handler.ts +17 -4
- package/src/installed-package-versions.ts +142 -38
- package/src/kotlin-host.ts +1 -1
- package/src/metro-plugin.ts +4 -4
- package/src/metro-project-root.ts +68 -0
- package/src/nitro-adapter.lock.json +26 -0
- package/src/nitro-adapter.ts +103 -0
- package/src/nitro-bundle.ts +24 -10
- package/src/nitro-compile.ts +33 -51
- package/src/nitro-source.ts +177 -96
- package/src/nitroAdapterContract.ts +217 -0
- package/src/nitroContract.ts +24 -11
- package/src/process-group.ts +41 -34
- package/src/react-bridge-importers.ts +28 -0
- package/src/reactNativeConfigurationContract.ts +36 -0
- package/src/runtime-assets.ts +7 -2
- package/src/runtime-delivery.ts +2 -0
- package/src/runtimePlatformContract.ts +70 -0
- package/src/screenshots/frame-compose.ts +42 -43
- package/src/screenshots/org-deck.ts +9 -4
- package/src/screenshots/preset-names.ts +29 -0
- package/src/screenshots/registry.ts +5 -5
- package/src/screenshots/schema.ts +1 -1
- package/src/screenshots/screenshotContract.ts +971 -0
- package/src/settings-flags.ts +107 -0
- package/src/settingsContract.ts +609 -0
- package/src/storageSnapshotContract.ts +344 -0
- package/src/stub-pattern-matcher.ts +550 -0
- package/src/swift-compile.ts +908 -40
- package/src/swift-compiler-digest.ts +13 -1
- package/src/swift-distribution.lock.json +49 -22
- package/src/swift-host.ts +167 -52
- package/src/swift-objc-compile.ts +54 -24
- package/src/swift-objc-export.ts +532 -0
- package/src/swift-objc-import.ts +769 -0
- package/src/swift-objc-metadata.ts +285 -10
- package/src/swift-objc-sdk.ts +13970 -158
- package/src/swift-objc-standin.ts +137 -1
- package/src/swift-package.ts +94 -0
- package/src/swift-packages.ts +5 -5
- package/src/swift-submit.ts +6 -0
- package/src/swiftContract.ts +99 -0
- package/src/target-matcher.ts +6 -1
- package/src/vite-plugin.ts +14 -40
- package/src/worker-system-chunks.ts +1 -1
- package/src/workerChunkContract.ts +5 -0
- package/src/worklets-babel.ts +24 -5
- package/src/xcode-project.ts +36 -7
- package/src/xcode-target-members.ts +10 -3
- package/cli/drivers/playwright-sim-host.ts +0 -825
- package/kotlin/fixtures/counter/Counter.d.kt.ts +0 -17
- package/kotlin/fixtures/counter/Counter.kt +0 -51
- package/kotlin/fixtures/counter/CounterApp.native.tsx +0 -61
- package/kotlin/fixtures/counter/CounterApp.tsx +0 -3
- package/kotlin/fixtures/counter/CounterScreen.d.kt.ts +0 -8
- package/kotlin/fixtures/counter/CounterScreen.kt +0 -56
- package/kotlin/fixtures/counter/app/_layout.tsx +0 -4
- package/kotlin/fixtures/counter/app/index+spa.tsx +0 -1
- package/kotlin/fixtures/counter/app/routes.d.ts +0 -18
- package/kotlin/fixtures/counter/package.json +0 -20
- package/kotlin/fixtures/counter/tsconfig.json +0 -19
- package/kotlin/fixtures/counter/vite.config.ts +0 -20
- package/kotlin/fixtures/headless-counter/Headless.kt +0 -234
- package/kotlin/fixtures/import-animation/Animation.d.kt.ts +0 -7
- package/kotlin/fixtures/import-animation/Animation.kt +0 -80
- package/kotlin/fixtures/import-animation/ImportAnimation.native.tsx +0 -13
- package/kotlin/fixtures/import-animation/README.md +0 -24
- package/kotlin/fixtures/import-animation/app/_layout.tsx +0 -4
- package/kotlin/fixtures/import-animation/app/index+spa.tsx +0 -1
- package/kotlin/fixtures/import-animation/app/routes.d.ts +0 -18
- package/kotlin/fixtures/import-animation/package.json +0 -23
- package/kotlin/fixtures/import-animation/tsconfig.json +0 -20
- package/kotlin/fixtures/import-animation/vite.config.ts +0 -20
- package/kotlin/fixtures/import-drawing/Drawing.d.kt.ts +0 -7
- package/kotlin/fixtures/import-drawing/Drawing.kt +0 -101
- package/kotlin/fixtures/import-drawing/ImportDrawing.native.tsx +0 -18
- package/kotlin/fixtures/import-drawing/README.md +0 -34
- package/kotlin/fixtures/import-drawing/app/_layout.tsx +0 -4
- package/kotlin/fixtures/import-drawing/app/index+spa.tsx +0 -1
- package/kotlin/fixtures/import-drawing/package.json +0 -23
- package/kotlin/fixtures/import-drawing/tsconfig.json +0 -20
- package/kotlin/fixtures/import-drawing/vite.config.ts +0 -20
- package/kotlin/fixtures/import-editor/Editor.d.kt.ts +0 -7
- package/kotlin/fixtures/import-editor/Editor.kt +0 -59
- package/kotlin/fixtures/import-editor/ImportEditor.native.tsx +0 -23
- package/kotlin/fixtures/import-editor/README.md +0 -27
- package/kotlin/fixtures/import-editor/app/_layout.tsx +0 -4
- package/kotlin/fixtures/import-editor/app/index+spa.tsx +0 -1
- package/kotlin/fixtures/import-editor/package.json +0 -23
- package/kotlin/fixtures/import-editor/tsconfig.json +0 -20
- package/kotlin/fixtures/import-editor/vite.config.ts +0 -20
- package/kotlin/fixtures/import-effects/Effects.d.kt.ts +0 -7
- package/kotlin/fixtures/import-effects/Effects.kt +0 -87
- package/kotlin/fixtures/import-effects/ImportEffects.native.tsx +0 -13
- package/kotlin/fixtures/import-effects/README.md +0 -19
- package/kotlin/fixtures/import-effects/app/_layout.tsx +0 -4
- package/kotlin/fixtures/import-effects/app/index+spa.tsx +0 -1
- package/kotlin/fixtures/import-effects/package.json +0 -23
- package/kotlin/fixtures/import-effects/tsconfig.json +0 -20
- package/kotlin/fixtures/import-effects/vite.config.ts +0 -20
- package/kotlin/fixtures/import-layout/ImportLayout.native.tsx +0 -13
- package/kotlin/fixtures/import-layout/Layout.d.kt.ts +0 -7
- package/kotlin/fixtures/import-layout/Layout.kt +0 -72
- package/kotlin/fixtures/import-layout/README.md +0 -24
- package/kotlin/fixtures/import-layout/app/_layout.tsx +0 -4
- package/kotlin/fixtures/import-layout/app/index+spa.tsx +0 -1
- package/kotlin/fixtures/import-layout/package.json +0 -23
- package/kotlin/fixtures/import-layout/tsconfig.json +0 -20
- package/kotlin/fixtures/import-layout/vite.config.ts +0 -20
- package/kotlin/fixtures/import-navigation/ImportNavigation.native.tsx +0 -18
- package/kotlin/fixtures/import-navigation/Navigation.d.kt.ts +0 -7
- package/kotlin/fixtures/import-navigation/Navigation.kt +0 -104
- package/kotlin/fixtures/import-navigation/README.md +0 -31
- package/kotlin/fixtures/import-navigation/app/_layout.tsx +0 -4
- package/kotlin/fixtures/import-navigation/app/index+spa.tsx +0 -1
- package/kotlin/fixtures/import-navigation/package.json +0 -23
- package/kotlin/fixtures/import-navigation/tsconfig.json +0 -20
- package/kotlin/fixtures/import-navigation/vite.config.ts +0 -20
- package/kotlin/fixtures/import-overlays/ImportOverlays.native.tsx +0 -29
- package/kotlin/fixtures/import-overlays/Overlays.d.kt.ts +0 -7
- package/kotlin/fixtures/import-overlays/Overlays.kt +0 -93
- package/kotlin/fixtures/import-overlays/README.md +0 -34
- package/kotlin/fixtures/import-overlays/app/_layout.tsx +0 -4
- package/kotlin/fixtures/import-overlays/app/index+spa.tsx +0 -1
- package/kotlin/fixtures/import-overlays/package.json +0 -23
- package/kotlin/fixtures/import-overlays/tsconfig.json +0 -20
- package/kotlin/fixtures/import-overlays/vite.config.ts +0 -20
- package/kotlin/fixtures/import-resources/ImportResources.native.tsx +0 -18
- package/kotlin/fixtures/import-resources/README.md +0 -26
- package/kotlin/fixtures/import-resources/Resources.d.kt.ts +0 -6
- package/kotlin/fixtures/import-resources/Resources.kt +0 -72
- package/kotlin/fixtures/import-resources/app/_layout.tsx +0 -4
- package/kotlin/fixtures/import-resources/app/index+spa.tsx +0 -1
- package/kotlin/fixtures/import-resources/package.json +0 -23
- package/kotlin/fixtures/import-resources/tsconfig.json +0 -20
- package/kotlin/fixtures/import-resources/vite.config.ts +0 -20
- package/kotlin/fixtures/import-scroll/ImportNested.native.tsx +0 -10
- package/kotlin/fixtures/import-scroll/ImportScroll.native.tsx +0 -13
- package/kotlin/fixtures/import-scroll/Nested.d.kt.ts +0 -4
- package/kotlin/fixtures/import-scroll/Nested.kt +0 -64
- package/kotlin/fixtures/import-scroll/README.md +0 -38
- package/kotlin/fixtures/import-scroll/Scroll.d.kt.ts +0 -7
- package/kotlin/fixtures/import-scroll/Scroll.kt +0 -91
- package/kotlin/fixtures/import-scroll/app/_layout.tsx +0 -4
- package/kotlin/fixtures/import-scroll/app/index+spa.tsx +0 -1
- package/kotlin/fixtures/import-scroll/app/nested+spa.tsx +0 -1
- package/kotlin/fixtures/import-scroll/package.json +0 -23
- package/kotlin/fixtures/import-scroll/tsconfig.json +0 -20
- package/kotlin/fixtures/import-scroll/vite.config.ts +0 -20
- package/kotlin/fixtures/import-selection/ImportSelection.native.tsx +0 -44
- package/kotlin/fixtures/import-selection/README.md +0 -32
- package/kotlin/fixtures/import-selection/Selection.d.kt.ts +0 -8
- package/kotlin/fixtures/import-selection/Selection.kt +0 -78
- package/kotlin/fixtures/import-selection/app/_layout.tsx +0 -4
- package/kotlin/fixtures/import-selection/app/index+spa.tsx +0 -1
- package/kotlin/fixtures/import-selection/package.json +0 -23
- package/kotlin/fixtures/import-selection/tsconfig.json +0 -20
- package/kotlin/fixtures/import-selection/vite.config.ts +0 -20
- package/kotlin/fixtures/import-surfaces/ImportSurfaces.native.tsx +0 -13
- package/kotlin/fixtures/import-surfaces/README.md +0 -22
- package/kotlin/fixtures/import-surfaces/Surfaces.d.kt.ts +0 -7
- package/kotlin/fixtures/import-surfaces/Surfaces.kt +0 -64
- package/kotlin/fixtures/import-surfaces/app/_layout.tsx +0 -4
- package/kotlin/fixtures/import-surfaces/app/index+spa.tsx +0 -1
- package/kotlin/fixtures/import-surfaces/package.json +0 -23
- package/kotlin/fixtures/import-surfaces/tsconfig.json +0 -20
- package/kotlin/fixtures/import-surfaces/vite.config.ts +0 -20
- package/kotlin/fixtures/import-values/ImportValues.native.tsx +0 -61
- package/kotlin/fixtures/import-values/README.md +0 -28
- package/kotlin/fixtures/import-values/Values.d.kt.ts +0 -15
- package/kotlin/fixtures/import-values/Values.kt +0 -84
- package/kotlin/fixtures/import-values/app/_layout.tsx +0 -4
- package/kotlin/fixtures/import-values/app/index+spa.tsx +0 -1
- package/kotlin/fixtures/import-values/package.json +0 -23
- package/kotlin/fixtures/import-values/tsconfig.json +0 -20
- package/kotlin/fixtures/import-values/vite.config.ts +0 -20
- package/kotlin/fixtures/kotlin-app/app/build.gradle.kts +0 -30
- package/kotlin/fixtures/kotlin-app/app/src/main/AndroidManifest.xml +0 -13
- package/kotlin/fixtures/kotlin-app/app/src/main/java/dev/contrast/kotlinapp/MainActivity.kt +0 -60
- package/kotlin/fixtures/kotlin-app/app/src/main/java/dev/contrast/kotlinapp/ProbeApplication.kt +0 -18
- package/kotlin/fixtures/kotlin-app/build.gradle.kts +0 -5
- package/kotlin/fixtures/kotlin-app/gradle.properties +0 -4
- package/kotlin/fixtures/kotlin-app/settings.gradle.kts +0 -4
- package/kotlin/fixtures/kotlin-app-variants/Anim.kt +0 -62
- package/kotlin/fixtures/kotlin-app-variants/BarBehavior.kt +0 -38
- package/kotlin/fixtures/kotlin-app-variants/BarVisibility.kt +0 -36
- package/kotlin/fixtures/kotlin-app-variants/Bitmaps.kt +0 -50
- package/kotlin/fixtures/kotlin-app-variants/Browse.kt +0 -73
- package/kotlin/fixtures/kotlin-app-variants/Colors.kt +0 -41
- package/kotlin/fixtures/kotlin-app-variants/Controls.kt +0 -62
- package/kotlin/fixtures/kotlin-app-variants/Drag.kt +0 -56
- package/kotlin/fixtures/kotlin-app-variants/Draw.kt +0 -74
- package/kotlin/fixtures/kotlin-app-variants/Drawables.kt +0 -53
- package/kotlin/fixtures/kotlin-app-variants/Focus.kt +0 -62
- package/kotlin/fixtures/kotlin-app-variants/Form.kt +0 -47
- package/kotlin/fixtures/kotlin-app-variants/Icons.kt +0 -59
- package/kotlin/fixtures/kotlin-app-variants/Ime.kt +0 -53
- package/kotlin/fixtures/kotlin-app-variants/Lists.kt +0 -57
- package/kotlin/fixtures/kotlin-app-variants/Nav.kt +0 -47
- package/kotlin/fixtures/kotlin-app-variants/Note.kt +0 -40
- package/kotlin/fixtures/kotlin-app-variants/Overlays.kt +0 -56
- package/kotlin/fixtures/kotlin-app-variants/Pan.kt +0 -38
- package/kotlin/fixtures/kotlin-app-variants/Pickers.kt +0 -44
- package/kotlin/fixtures/kotlin-app-variants/Press.kt +0 -43
- package/kotlin/fixtures/kotlin-app-variants/Scroll.kt +0 -63
- package/kotlin/fixtures/kotlin-app-variants/Sheet.kt +0 -43
- package/kotlin/fixtures/kotlin-app-variants/Strings.kt +0 -49
- package/kotlin/fixtures/kotlin-app-variants/Tabs.kt +0 -47
- package/kotlin/fixtures/kotlin-app-variants/TextWidth.kt +0 -45
- package/kotlin/fixtures/kotlin-app-variants/TransientInsets.kt +0 -50
- package/kotlin/fixtures/kotlin-app-variants/Transition.kt +0 -69
- package/kotlin/fixtures/kotlin-app-variants/ViewConfig.kt +0 -22
- package/kotlin/fixtures/kotlin-app-variants/Widgets.kt +0 -67
- package/kotlin/fixtures/runtime-state/RuntimeState.kt +0 -200
- package/kotlin/fork/README.md +0 -97
- package/kotlin/fork/build.sh +0 -176
- package/kotlin/fork/compose-worker-globals.patch +0 -1247
- package/kotlin/fork/fork.json +0 -46
- package/kotlin/fork/publish.ts +0 -99
- package/kotlin/fork/skia-android-shaping.patch +0 -189
- package/kotlin/fork/skiko-local.init.gradle +0 -10
- package/kotlin/fork/skiko-worker-clock.patch +0 -122
|
@@ -0,0 +1,971 @@
|
|
|
1
|
+
import { isRecord } from '../is-record.ts'
|
|
2
|
+
import {
|
|
3
|
+
BACKGROUND_PRESET_NAMES,
|
|
4
|
+
POSE_PRESET_NAMES,
|
|
5
|
+
SCREENSHOT_CANVAS_NAMES,
|
|
6
|
+
TEXT_PRESET_NAMES,
|
|
7
|
+
type BackgroundPresetName,
|
|
8
|
+
type PosePresetName,
|
|
9
|
+
type ScreenshotCanvasName,
|
|
10
|
+
type TextPresetName,
|
|
11
|
+
} from './preset-names.ts'
|
|
12
|
+
import type { DeviceModel } from '../device-catalog.ts'
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
BACKGROUND_PRESET_NAMES,
|
|
16
|
+
POSE_PRESET_NAMES,
|
|
17
|
+
SCREENSHOT_CANVAS_NAMES,
|
|
18
|
+
TEXT_PRESET_NAMES,
|
|
19
|
+
type BackgroundPresetName,
|
|
20
|
+
type PosePresetName,
|
|
21
|
+
type ScreenshotCanvasName,
|
|
22
|
+
type TextPresetName,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// shared serialized scene contract, also used by the optional 3d renderer.
|
|
26
|
+
export const THREE_MODE_SETTING_IDS = [
|
|
27
|
+
'none',
|
|
28
|
+
'room',
|
|
29
|
+
'window-wall',
|
|
30
|
+
'white-backdrop',
|
|
31
|
+
'cyclorama',
|
|
32
|
+
'terrain',
|
|
33
|
+
] as const
|
|
34
|
+
|
|
35
|
+
export type ThreeModeSetting = (typeof THREE_MODE_SETTING_IDS)[number]
|
|
36
|
+
|
|
37
|
+
export const THREE_WINDOW_LIGHT_OFFSET_RANGE: readonly [number, number] = [-3, 3]
|
|
38
|
+
|
|
39
|
+
export function isThreeModeSetting(value: unknown): value is ThreeModeSetting {
|
|
40
|
+
return typeof value === 'string' && THREE_MODE_SETTING_IDS.some((id) => id === value)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface CanvasPreset {
|
|
44
|
+
name: ScreenshotCanvasName
|
|
45
|
+
label: string
|
|
46
|
+
width: number
|
|
47
|
+
height: number
|
|
48
|
+
store: 'apple' | 'google'
|
|
49
|
+
deviceModel?: DeviceModel
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface GradientStop {
|
|
53
|
+
offset: number
|
|
54
|
+
color: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface BackgroundSpec {
|
|
58
|
+
type: 'solid' | 'gradient'
|
|
59
|
+
color?: string
|
|
60
|
+
direction?: number
|
|
61
|
+
stops?: GradientStop[]
|
|
62
|
+
glow?: string
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface FrameShadowSpec {
|
|
66
|
+
color: string
|
|
67
|
+
blur: number
|
|
68
|
+
spread: number
|
|
69
|
+
opacity: number
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const SCREENSHOT_CANVASES: Record<ScreenshotCanvasName, CanvasPreset> = {
|
|
73
|
+
'iphone-6-9': {
|
|
74
|
+
name: 'iphone-6-9',
|
|
75
|
+
label: 'iPhone 6.7"',
|
|
76
|
+
width: 1284,
|
|
77
|
+
height: 2778,
|
|
78
|
+
store: 'apple',
|
|
79
|
+
},
|
|
80
|
+
'iphone-6-1': {
|
|
81
|
+
name: 'iphone-6-1',
|
|
82
|
+
label: 'iPhone 6.5"',
|
|
83
|
+
width: 1242,
|
|
84
|
+
height: 2688,
|
|
85
|
+
store: 'apple',
|
|
86
|
+
},
|
|
87
|
+
'ipad-pro-13': {
|
|
88
|
+
name: 'ipad-pro-13',
|
|
89
|
+
label: 'iPad Pro 13-inch',
|
|
90
|
+
width: 2064,
|
|
91
|
+
height: 2752,
|
|
92
|
+
store: 'apple',
|
|
93
|
+
deviceModel: 'ipad-pro-13',
|
|
94
|
+
},
|
|
95
|
+
'android-phone': {
|
|
96
|
+
name: 'android-phone',
|
|
97
|
+
label: 'Google Play phone',
|
|
98
|
+
width: 1080,
|
|
99
|
+
height: 1920,
|
|
100
|
+
store: 'google',
|
|
101
|
+
},
|
|
102
|
+
'android-tablet-7': {
|
|
103
|
+
name: 'android-tablet-7',
|
|
104
|
+
label: 'Google Play 7" tablet',
|
|
105
|
+
width: 1200,
|
|
106
|
+
height: 1920,
|
|
107
|
+
store: 'google',
|
|
108
|
+
},
|
|
109
|
+
'android-tablet-10': {
|
|
110
|
+
name: 'android-tablet-10',
|
|
111
|
+
label: 'Google Play 10" tablet',
|
|
112
|
+
width: 1600,
|
|
113
|
+
height: 2560,
|
|
114
|
+
store: 'google',
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export const BACKGROUND_PRESETS: Record<BackgroundPresetName, BackgroundSpec> = {
|
|
119
|
+
dark: {
|
|
120
|
+
type: 'gradient',
|
|
121
|
+
direction: 180,
|
|
122
|
+
glow: '#4caeff',
|
|
123
|
+
stops: [
|
|
124
|
+
{ offset: 0, color: '#111827' },
|
|
125
|
+
{ offset: 40, color: '#101725' },
|
|
126
|
+
{ offset: 100, color: '#06080d' },
|
|
127
|
+
],
|
|
128
|
+
},
|
|
129
|
+
cyan: {
|
|
130
|
+
type: 'gradient',
|
|
131
|
+
direction: 180,
|
|
132
|
+
glow: '#25c3ec',
|
|
133
|
+
stops: [
|
|
134
|
+
{ offset: 0, color: '#1b465c' },
|
|
135
|
+
{ offset: 32, color: '#122336' },
|
|
136
|
+
{ offset: 100, color: '#05070b' },
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
gold: {
|
|
140
|
+
type: 'gradient',
|
|
141
|
+
direction: 180,
|
|
142
|
+
glow: '#ffc25a',
|
|
143
|
+
stops: [
|
|
144
|
+
{ offset: 0, color: '#3b2f1a' },
|
|
145
|
+
{ offset: 34, color: '#18140d' },
|
|
146
|
+
{ offset: 100, color: '#050505' },
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
red: {
|
|
150
|
+
type: 'gradient',
|
|
151
|
+
direction: 180,
|
|
152
|
+
glow: '#ff6178',
|
|
153
|
+
stops: [
|
|
154
|
+
{ offset: 0, color: '#3e1018' },
|
|
155
|
+
{ offset: 35, color: '#17080c' },
|
|
156
|
+
{ offset: 100, color: '#050405' },
|
|
157
|
+
],
|
|
158
|
+
},
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export const DEFAULT_FRAME_SHADOW: FrameShadowSpec = {
|
|
162
|
+
color: '#25c3ec',
|
|
163
|
+
blur: 120,
|
|
164
|
+
spread: 52,
|
|
165
|
+
opacity: 0.34,
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export const DEFAULT_FRAME_STYLE: DeviceModel = 'iphone-17-pro'
|
|
169
|
+
|
|
170
|
+
// stage / canvas-rect FLIP animation. used by DeviceFrame.tsx for the live
|
|
171
|
+
// stage tween and by the composer's compose.ts for parity.
|
|
172
|
+
export const SCREENSHOT_MODE_ANIM = {
|
|
173
|
+
durationMs: 250,
|
|
174
|
+
easing: 'cubic-bezier(0.22, 1, 0.36, 1)',
|
|
175
|
+
} as const
|
|
176
|
+
|
|
177
|
+
// css clamp() rules for text layers. live mode uses container queries keyed
|
|
178
|
+
// off the floating canvas rect; the composer writes the same clamp() rules
|
|
179
|
+
// in its exported html so the two painters render matching headlines at
|
|
180
|
+
// matching canvas sizes.
|
|
181
|
+
export const SCREENSHOT_TEXT_CLAMP = {
|
|
182
|
+
headline: 'clamp(2rem, 5.6cqi, 5.5rem)',
|
|
183
|
+
subhead: 'clamp(1rem, 2.4cqi, 2.25rem)',
|
|
184
|
+
} as const
|
|
185
|
+
|
|
186
|
+
// safe-area percentages inside the canvas rect — reserves headroom and side
|
|
187
|
+
// padding for the text layer so the device frame never crowds the edges.
|
|
188
|
+
export const SCREENSHOT_TEXT_SAFE_AREA = {
|
|
189
|
+
topPct: 8,
|
|
190
|
+
sidePct: 7,
|
|
191
|
+
bottomGapPct: 4,
|
|
192
|
+
} as const
|
|
193
|
+
|
|
194
|
+
// ─── screenshot project config (live multi-frame mode) ───────────────────
|
|
195
|
+
//
|
|
196
|
+
// a project carries one screenshot composition: a target store/canvas
|
|
197
|
+
// preset, the device to pose, and an ordered list of frame slides. each
|
|
198
|
+
// slide owns its own copy/theme/pose so the App-Store strip can show
|
|
199
|
+
// different posed screens side by side. the closed plugin-screenshot owns
|
|
200
|
+
// the visual mapping for ScreenshotThemeName; the name union lives here so
|
|
201
|
+
// the engine projects store can persist it without importing the plugin.
|
|
202
|
+
|
|
203
|
+
// the background is a two-stop vertical gradient: the user picks a top
|
|
204
|
+
// color and a bottom color independently (two flyouts in the rail). the
|
|
205
|
+
// palette includes white + a grey ramp so a screenshot can stay basically
|
|
206
|
+
// grey, plus the brand hues.
|
|
207
|
+
export type ScreenshotBgColorName =
|
|
208
|
+
| 'white'
|
|
209
|
+
| 'gray-light'
|
|
210
|
+
| 'gray'
|
|
211
|
+
| 'gray-dark'
|
|
212
|
+
| 'slate'
|
|
213
|
+
| 'black'
|
|
214
|
+
| 'cyan'
|
|
215
|
+
| 'blue'
|
|
216
|
+
| 'teal'
|
|
217
|
+
| 'green'
|
|
218
|
+
| 'lime'
|
|
219
|
+
| 'gold'
|
|
220
|
+
| 'orange'
|
|
221
|
+
| 'coral'
|
|
222
|
+
| 'red'
|
|
223
|
+
| 'berry'
|
|
224
|
+
| 'magenta'
|
|
225
|
+
|
|
226
|
+
export interface ScreenshotBgColor {
|
|
227
|
+
name: ScreenshotBgColorName
|
|
228
|
+
value: string
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export const SCREENSHOT_BG_COLORS: ScreenshotBgColor[] = [
|
|
232
|
+
{ name: 'white', value: '#ffffff' },
|
|
233
|
+
{ name: 'gray-light', value: '#d1d5db' },
|
|
234
|
+
{ name: 'gray', value: '#6b7280' },
|
|
235
|
+
{ name: 'gray-dark', value: '#3b4350' },
|
|
236
|
+
{ name: 'slate', value: '#2a3644' },
|
|
237
|
+
{ name: 'black', value: '#000000' },
|
|
238
|
+
{ name: 'cyan', value: '#25c3ec' },
|
|
239
|
+
{ name: 'blue', value: '#3f7cff' },
|
|
240
|
+
{ name: 'teal', value: '#1fc7b4' },
|
|
241
|
+
{ name: 'green', value: '#42c95d' },
|
|
242
|
+
{ name: 'lime', value: '#92d21b' },
|
|
243
|
+
{ name: 'gold', value: '#f5c518' },
|
|
244
|
+
{ name: 'orange', value: '#ff912e' },
|
|
245
|
+
{ name: 'coral', value: '#ff6f5b' },
|
|
246
|
+
{ name: 'red', value: '#ff4f6f' },
|
|
247
|
+
{ name: 'berry', value: '#d054ff' },
|
|
248
|
+
{ name: 'magenta', value: '#ff4eb8' },
|
|
249
|
+
]
|
|
250
|
+
|
|
251
|
+
const BG_COLOR_MAP: Record<string, string> = Object.fromEntries(
|
|
252
|
+
SCREENSHOT_BG_COLORS.map((c) => [c.name, c.value]),
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
export function resolveBgColorValue(name: string): string {
|
|
256
|
+
return BG_COLOR_MAP[name] ?? BG_COLOR_MAP.gray
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export interface ScreenshotBackgroundStyles {
|
|
260
|
+
background: string
|
|
261
|
+
foreground: string
|
|
262
|
+
eyebrow: string
|
|
263
|
+
subtitle: string
|
|
264
|
+
placeholder: string
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export const DEFAULT_BG_TOP: ScreenshotBgColorName = 'gray'
|
|
268
|
+
|
|
269
|
+
export const DEFAULT_BG_BOTTOM: ScreenshotBgColorName = 'gray-dark'
|
|
270
|
+
|
|
271
|
+
// per-slide persistence of the 3d composition state (camera pose, scene
|
|
272
|
+
// look, env state) so a slide captured in 3d can re-open into the same
|
|
273
|
+
// scene. `null` titleColor means "auto contrast against bgTop" (the
|
|
274
|
+
// historical behavior); any palette name overrides.
|
|
275
|
+
// the operator's grade over the finished frame, as serializable ids. this is
|
|
276
|
+
// the one definition of the grade's shape: the 3d mode's own ThreeGradeState
|
|
277
|
+
// is this type, and the renderer maps each id to its number. It lives here
|
|
278
|
+
// because the plugins depend on the engine and not the other way round.
|
|
279
|
+
export interface ScreenshotThreeGrade {
|
|
280
|
+
contrast: 'low' | 'neutral' | 'high' | 'max'
|
|
281
|
+
saturation: 'low' | 'neutral' | 'high' | 'max'
|
|
282
|
+
brightness: 'low' | 'neutral' | 'high'
|
|
283
|
+
blackPoint: 'lifted' | 'neutral' | 'deep' | 'crushed'
|
|
284
|
+
grain: 'off' | 'subtle' | 'strong'
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export const SCREENSHOT_THREE_GRADE_IDS: {
|
|
288
|
+
[K in keyof ScreenshotThreeGrade]: readonly ScreenshotThreeGrade[K][]
|
|
289
|
+
} = {
|
|
290
|
+
contrast: ['low', 'neutral', 'high', 'max'],
|
|
291
|
+
saturation: ['low', 'neutral', 'high', 'max'],
|
|
292
|
+
brightness: ['low', 'neutral', 'high'],
|
|
293
|
+
blackPoint: ['lifted', 'neutral', 'deep', 'crushed'],
|
|
294
|
+
grain: ['off', 'subtle', 'strong'],
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// identity. a restored slide that saved no grade is put back onto this rather
|
|
298
|
+
// than left on whatever the previous slide was graded to.
|
|
299
|
+
export const SCREENSHOT_THREE_GRADE_DEFAULT: ScreenshotThreeGrade = {
|
|
300
|
+
contrast: 'neutral',
|
|
301
|
+
saturation: 'neutral',
|
|
302
|
+
brightness: 'neutral',
|
|
303
|
+
blackPoint: 'neutral',
|
|
304
|
+
grain: 'off',
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// the Cyclorama setting's light rig and sweep. angles are degrees, sweepMs is
|
|
308
|
+
// authored timeline time, curveRadius and shadowSoftness are fractions of the
|
|
309
|
+
// device's longest side. Same ownership reason as the grade above.
|
|
310
|
+
export interface ScreenshotThreeCyclorama {
|
|
311
|
+
keyAzimuthDeg: number
|
|
312
|
+
keyElevationDeg: number
|
|
313
|
+
keyRiseDeg: number
|
|
314
|
+
sweepMs: number
|
|
315
|
+
keyIntensity: number
|
|
316
|
+
warmIntensity: number
|
|
317
|
+
coolIntensity: number
|
|
318
|
+
curveRadius: number
|
|
319
|
+
shadowSoftness: number
|
|
320
|
+
// the two tints the operator picks. warmColor drives the warm contribution
|
|
321
|
+
// and coolColor the cool one, each carried by its existing intensity field.
|
|
322
|
+
warmColor: string
|
|
323
|
+
coolColor: string
|
|
324
|
+
warmColorEnd: string | null
|
|
325
|
+
coolColorEnd: string | null
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// the two colors are authored as strings, so the numeric ranges cover the
|
|
329
|
+
// numeric fields only rather than widening to a union nothing can clamp.
|
|
330
|
+
type ScreenshotThreeCycloramaNumericKey = {
|
|
331
|
+
[K in keyof ScreenshotThreeCyclorama]: ScreenshotThreeCyclorama[K] extends number
|
|
332
|
+
? K
|
|
333
|
+
: never
|
|
334
|
+
}[keyof ScreenshotThreeCyclorama]
|
|
335
|
+
|
|
336
|
+
export const SCREENSHOT_THREE_CYCLORAMA_RANGES: {
|
|
337
|
+
[K in ScreenshotThreeCycloramaNumericKey]: readonly [number, number]
|
|
338
|
+
} = {
|
|
339
|
+
keyAzimuthDeg: [-360, 360],
|
|
340
|
+
keyElevationDeg: [1, 89],
|
|
341
|
+
keyRiseDeg: [1, 89],
|
|
342
|
+
sweepMs: [0, 600_000],
|
|
343
|
+
keyIntensity: [0, 40],
|
|
344
|
+
warmIntensity: [0, 40],
|
|
345
|
+
coolIntensity: [0, 40],
|
|
346
|
+
curveRadius: [0.05, 6],
|
|
347
|
+
shadowSoftness: [0, 0.5],
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// the rig a Cyclorama slide opens on, calibrated against the rendered frame.
|
|
351
|
+
export const SCREENSHOT_THREE_CYCLORAMA_DEFAULT: ScreenshotThreeCyclorama = {
|
|
352
|
+
keyAzimuthDeg: 23.55,
|
|
353
|
+
keyElevationDeg: 59.7,
|
|
354
|
+
keyRiseDeg: 62.2,
|
|
355
|
+
sweepMs: 0,
|
|
356
|
+
keyIntensity: 3,
|
|
357
|
+
warmIntensity: 0.9,
|
|
358
|
+
coolIntensity: 1.1,
|
|
359
|
+
curveRadius: 0.08,
|
|
360
|
+
shadowSoftness: 0.06,
|
|
361
|
+
warmColor: '#ffcb12',
|
|
362
|
+
coolColor: '#2879ff',
|
|
363
|
+
warmColorEnd: null,
|
|
364
|
+
coolColorEnd: null,
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// six-digit #RRGGBB only. a three-digit or named color parses differently in
|
|
368
|
+
// the picker, the film validator and the renderer's color conversion, so the
|
|
369
|
+
// one spelling every owner agrees on is the only one accepted.
|
|
370
|
+
const SCREENSHOT_THREE_CYCLORAMA_COLOR_KEY_SET: ReadonlySet<string> = new Set([
|
|
371
|
+
'warmColor',
|
|
372
|
+
'coolColor',
|
|
373
|
+
'warmColorEnd',
|
|
374
|
+
'coolColorEnd',
|
|
375
|
+
])
|
|
376
|
+
|
|
377
|
+
const SCREENSHOT_THREE_CYCLORAMA_COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/
|
|
378
|
+
|
|
379
|
+
export function isScreenshotThreeCycloramaColorKey(
|
|
380
|
+
key: string,
|
|
381
|
+
): key is 'warmColor' | 'coolColor' | 'warmColorEnd' | 'coolColorEnd' {
|
|
382
|
+
return SCREENSHOT_THREE_CYCLORAMA_COLOR_KEY_SET.has(key)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export function isScreenshotThreeCycloramaColor(value: unknown): value is string {
|
|
386
|
+
return typeof value === 'string' && SCREENSHOT_THREE_CYCLORAMA_COLOR_PATTERN.test(value)
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// null holds the starting tint throughout an authored sweep.
|
|
390
|
+
export function normalizeScreenshotThreeCycloramaEndColor(
|
|
391
|
+
value: unknown,
|
|
392
|
+
base: string | null = null,
|
|
393
|
+
): string | null {
|
|
394
|
+
return value === null
|
|
395
|
+
? null
|
|
396
|
+
: isScreenshotThreeCycloramaColor(value)
|
|
397
|
+
? value.toLowerCase()
|
|
398
|
+
: base
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* The one place a cyclorama tint is turned into state. Anything that is not a
|
|
403
|
+
* six-digit hex takes the fallback rather than reaching the renderer, and a
|
|
404
|
+
* valid one is lower-cased so the picker, a saved slide and an authored film
|
|
405
|
+
* all hold the same spelling.
|
|
406
|
+
*/
|
|
407
|
+
export function normalizeScreenshotThreeCycloramaColor(
|
|
408
|
+
value: unknown,
|
|
409
|
+
fallback: string,
|
|
410
|
+
): string {
|
|
411
|
+
return isScreenshotThreeCycloramaColor(value) ? value.toLowerCase() : fallback
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export interface ScreenshotThreeAppearance extends Record<string, unknown> {
|
|
415
|
+
caseStyle?: 'standard' | 'edge-to-edge'
|
|
416
|
+
grade?: ScreenshotThreeGrade
|
|
417
|
+
cyclorama?: ScreenshotThreeCyclorama
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
export interface ScreenshotThreeScene {
|
|
421
|
+
device: 'iphone-17-air' | 'iphone-17-pro' | 'pixel-10'
|
|
422
|
+
// [x, y, z]
|
|
423
|
+
cameraPosition: [number, number, number]
|
|
424
|
+
cameraUp?: [number, number, number]
|
|
425
|
+
// orbit-controls target the camera looks at
|
|
426
|
+
target: [number, number, number]
|
|
427
|
+
// phone model transform
|
|
428
|
+
phonePosition: [number, number, number]
|
|
429
|
+
phoneRotation: [number, number, number]
|
|
430
|
+
colorway: string
|
|
431
|
+
background: string
|
|
432
|
+
// custom gradient override (caller color stops). when present it takes
|
|
433
|
+
// precedence over `background` so the deck's shared brand palette is
|
|
434
|
+
// restored on re-open instead of the named preset.
|
|
435
|
+
customGradient?: {
|
|
436
|
+
stops: { offset: number; color: string }[]
|
|
437
|
+
angleDeg?: number
|
|
438
|
+
} | null
|
|
439
|
+
// ids follow the shared serialized contract; appearance is renderer-owned.
|
|
440
|
+
setting: ThreeModeSetting
|
|
441
|
+
appearance?: ScreenshotThreeAppearance
|
|
442
|
+
focus?: Record<string, string | boolean | null | undefined> | null
|
|
443
|
+
// env state. shape mirrors the bridge — kept as serializable plain
|
|
444
|
+
// objects, normalized at apply time.
|
|
445
|
+
environmentActive: boolean
|
|
446
|
+
environmentPins?: Record<string, string | null | undefined>
|
|
447
|
+
environmentEffects?: Record<string, boolean>
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
export type TitleSize = 'sm' | 'md' | 'lg'
|
|
451
|
+
|
|
452
|
+
export type TitleUnderlay = 'black' | 'white'
|
|
453
|
+
|
|
454
|
+
export type TitleShadow = 'light' | 'medium' | 'strong'
|
|
455
|
+
|
|
456
|
+
export type ScreenshotTextAlign = 'left' | 'center' | 'right'
|
|
457
|
+
|
|
458
|
+
export interface ScreenshotFontChoice {
|
|
459
|
+
family: string
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
export interface ScreenshotTextPosition {
|
|
463
|
+
// normalized canvas coordinates for the text block's aligned top anchor.
|
|
464
|
+
x: number
|
|
465
|
+
y: number
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export interface ScreenshotImageLayer {
|
|
469
|
+
// ref into the same capture store used by screen/capture/clean layers.
|
|
470
|
+
ref: string
|
|
471
|
+
// normalized canvas coordinates for the image center.
|
|
472
|
+
x: number
|
|
473
|
+
y: number
|
|
474
|
+
// rendered image width as a fraction of the canvas width.
|
|
475
|
+
scale: number
|
|
476
|
+
// clockwise rotation in degrees.
|
|
477
|
+
rotation: number
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
export interface ScreenshotPhone2DTransform {
|
|
481
|
+
// percentage of the phone silhouette width.
|
|
482
|
+
x: number
|
|
483
|
+
// percentage of the phone silhouette height.
|
|
484
|
+
y: number
|
|
485
|
+
deg: number
|
|
486
|
+
scale: number
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
export const DEFAULT_PHONE_2D_TRANSFORM: ScreenshotPhone2DTransform = {
|
|
490
|
+
x: 0,
|
|
491
|
+
y: 0,
|
|
492
|
+
deg: 0,
|
|
493
|
+
scale: 1,
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
export const PHONE_2D_TRANSFORM_LIMITS = {
|
|
497
|
+
x: { min: -32, max: 32, step: 1 },
|
|
498
|
+
y: { min: -32, max: 32, step: 1 },
|
|
499
|
+
deg: { min: -18, max: 18, step: 1 },
|
|
500
|
+
scale: { min: 0.72, max: 1.28, step: 0.01 },
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
export interface ScreenshotSlide {
|
|
504
|
+
id: string
|
|
505
|
+
title: string
|
|
506
|
+
subtitle: string
|
|
507
|
+
bgTop: ScreenshotBgColorName
|
|
508
|
+
bgBottom: ScreenshotBgColorName
|
|
509
|
+
pose: PosePresetName
|
|
510
|
+
// override for the title/subtitle copy color. when undefined, copy
|
|
511
|
+
// contrast is derived automatically from bgTop. used by the rail's
|
|
512
|
+
// text-color picker so a designer can pin "white text on a light bg"
|
|
513
|
+
// intentionally, including in 3d mode where bgTop isn't the painted bg.
|
|
514
|
+
titleColor?: ScreenshotBgColorName
|
|
515
|
+
// type-scale preset for the title block (subtitle scales with it).
|
|
516
|
+
// undefined → 'md' default, same point size the rail shipped at.
|
|
517
|
+
titleSize?: TitleSize
|
|
518
|
+
// optional gradient underlay painted behind the title text — solid at
|
|
519
|
+
// the top of the slide, fading to transparent ~100px below the title.
|
|
520
|
+
// designed for 3d-mode shots where the live backdrop can be busy and
|
|
521
|
+
// copy needs a guaranteed legibility floor; in 2d mode it's purely
|
|
522
|
+
// stylistic. undefined → no underlay.
|
|
523
|
+
titleUnderlay?: TitleUnderlay
|
|
524
|
+
// text-shadow preset for the title/subtitle. boosts legibility on
|
|
525
|
+
// photographic / 3d backgrounds. undefined → no shadow.
|
|
526
|
+
titleShadow?: TitleShadow
|
|
527
|
+
// one Google Fonts family shared by title and subtitle. title/subtitle
|
|
528
|
+
// weights are selected from the curated family metadata at render time.
|
|
529
|
+
// undefined keeps the native SF Pro display/text stacks.
|
|
530
|
+
font?: ScreenshotFontChoice
|
|
531
|
+
// normalized top anchor for the complete title/subtitle block. the x
|
|
532
|
+
// coordinate follows textAlign (left edge, center, or right edge).
|
|
533
|
+
// undefined keeps the current top-center placement.
|
|
534
|
+
textPosition?: ScreenshotTextPosition
|
|
535
|
+
textAlign?: ScreenshotTextAlign
|
|
536
|
+
// decorative capture-store images. the editable overlay stack is the
|
|
537
|
+
// composed background/device base, these images, the text underlay, then
|
|
538
|
+
// text. keeping images above the reusable clean base means image and copy
|
|
539
|
+
// edits re-bake without booting the app or re-rendering a 3d scene.
|
|
540
|
+
images?: ScreenshotImageLayer[]
|
|
541
|
+
// ref into the binary capture store (cloud R2) for the COMPOSED App-Store
|
|
542
|
+
// deliverable — bg + title + posed phone + screen baked into one image (or
|
|
543
|
+
// the 3D-baked scene). this is what review shows edge-to-edge and what the
|
|
544
|
+
// zip exports. present once a slide has been captured.
|
|
545
|
+
captureRef?: string
|
|
546
|
+
// ref into the capture store for the COMPOSED deliverable WITHOUT the title
|
|
547
|
+
// block — same bg + posed phone + screen (or 3d scene), text omitted. baked
|
|
548
|
+
// alongside `captureRef` on every capture. lets a copy edit drop a live text
|
|
549
|
+
// overlay onto this and re-bake `captureRef` with NO device/screen repaint
|
|
550
|
+
// and, for 3d slides, NO scene re-render. absent on slides captured before
|
|
551
|
+
// this layer existed (and on composed-only org pushes) — callers fall back to
|
|
552
|
+
// recompose-from-screen / record-new there.
|
|
553
|
+
cleanRef?: string
|
|
554
|
+
// ref into the capture store for the BARE phone-screen pixels (screen only,
|
|
555
|
+
// no chrome). drives the fake-screen overlay so a slide can be re-posed /
|
|
556
|
+
// re-styled and re-baked into a new `captureRef` without booting a build.
|
|
557
|
+
// absent on composed-only org pushes, so Position is disabled until a slide
|
|
558
|
+
// has been captured with the 3-layer pipeline.
|
|
559
|
+
screenRef?: string
|
|
560
|
+
// 2d phone transform used by Position mode when 3d is off. x/y are stored as
|
|
561
|
+
// percentages of the phone silhouette width/height so preview and export
|
|
562
|
+
// apply the same transform regardless of card/canvas size.
|
|
563
|
+
phone2d?: ScreenshotPhone2DTransform
|
|
564
|
+
// 3d composition state, persisted on capture so re-opening the slide
|
|
565
|
+
// restores the exact scene the user shot.
|
|
566
|
+
threeScene?: ScreenshotThreeScene
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function isTitleSize(value: unknown): value is TitleSize {
|
|
570
|
+
return value === 'sm' || value === 'md' || value === 'lg'
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function isTitleUnderlay(value: unknown): value is TitleUnderlay {
|
|
574
|
+
return value === 'black' || value === 'white'
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
function isTitleShadow(value: unknown): value is TitleShadow {
|
|
578
|
+
return value === 'light' || value === 'medium' || value === 'strong'
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function isScreenshotTextAlign(value: unknown): value is ScreenshotTextAlign {
|
|
582
|
+
return value === 'left' || value === 'center' || value === 'right'
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function clampNumber(value: unknown, min: number, max: number, fallback: number): number {
|
|
586
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) return fallback
|
|
587
|
+
return Math.min(max, Math.max(min, value))
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
export function normalizeScreenshotPhone2DTransform(
|
|
591
|
+
input: unknown,
|
|
592
|
+
): ScreenshotPhone2DTransform | undefined {
|
|
593
|
+
if (!isRecord(input)) return undefined
|
|
594
|
+
const value = input
|
|
595
|
+
const x = clampNumber(
|
|
596
|
+
value.x,
|
|
597
|
+
PHONE_2D_TRANSFORM_LIMITS.x.min,
|
|
598
|
+
PHONE_2D_TRANSFORM_LIMITS.x.max,
|
|
599
|
+
DEFAULT_PHONE_2D_TRANSFORM.x,
|
|
600
|
+
)
|
|
601
|
+
const y = clampNumber(
|
|
602
|
+
value.y,
|
|
603
|
+
PHONE_2D_TRANSFORM_LIMITS.y.min,
|
|
604
|
+
PHONE_2D_TRANSFORM_LIMITS.y.max,
|
|
605
|
+
DEFAULT_PHONE_2D_TRANSFORM.y,
|
|
606
|
+
)
|
|
607
|
+
const deg = clampNumber(
|
|
608
|
+
value.deg,
|
|
609
|
+
PHONE_2D_TRANSFORM_LIMITS.deg.min,
|
|
610
|
+
PHONE_2D_TRANSFORM_LIMITS.deg.max,
|
|
611
|
+
DEFAULT_PHONE_2D_TRANSFORM.deg,
|
|
612
|
+
)
|
|
613
|
+
const scale = clampNumber(
|
|
614
|
+
value.scale,
|
|
615
|
+
PHONE_2D_TRANSFORM_LIMITS.scale.min,
|
|
616
|
+
PHONE_2D_TRANSFORM_LIMITS.scale.max,
|
|
617
|
+
DEFAULT_PHONE_2D_TRANSFORM.scale,
|
|
618
|
+
)
|
|
619
|
+
return { x, y, deg, scale }
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
function normalizeScreenshotFont(input: unknown): ScreenshotFontChoice | undefined {
|
|
623
|
+
if (!isRecord(input)) return undefined
|
|
624
|
+
const family = input.family
|
|
625
|
+
if (typeof family !== 'string') return undefined
|
|
626
|
+
const trimmed = family.trim()
|
|
627
|
+
return trimmed ? { family: trimmed.slice(0, 100) } : undefined
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function normalizeScreenshotTextPosition(
|
|
631
|
+
input: unknown,
|
|
632
|
+
): ScreenshotTextPosition | undefined {
|
|
633
|
+
if (!isRecord(input)) return undefined
|
|
634
|
+
const position = input
|
|
635
|
+
if (typeof position.x !== 'number' || typeof position.y !== 'number') return undefined
|
|
636
|
+
if (!Number.isFinite(position.x) || !Number.isFinite(position.y)) return undefined
|
|
637
|
+
return {
|
|
638
|
+
x: clampNumber(position.x, 0, 1, 0.5),
|
|
639
|
+
y: clampNumber(position.y, 0, 1, 0.06),
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
function normalizeScreenshotImages(input: unknown): ScreenshotImageLayer[] | undefined {
|
|
644
|
+
if (!Array.isArray(input)) return undefined
|
|
645
|
+
const images: ScreenshotImageLayer[] = []
|
|
646
|
+
for (const candidate of input.slice(0, 32)) {
|
|
647
|
+
if (!isRecord(candidate)) continue
|
|
648
|
+
const image = candidate
|
|
649
|
+
if (typeof image.ref !== 'string' || !image.ref.trim()) continue
|
|
650
|
+
images.push({
|
|
651
|
+
ref: image.ref.trim(),
|
|
652
|
+
x: clampNumber(image.x, 0, 1, 0.5),
|
|
653
|
+
y: clampNumber(image.y, 0, 1, 0.5),
|
|
654
|
+
scale: clampNumber(image.scale, 0.02, 2, 0.25),
|
|
655
|
+
rotation: clampNumber(image.rotation, -360, 360, 0),
|
|
656
|
+
})
|
|
657
|
+
}
|
|
658
|
+
return images.length > 0 ? images : undefined
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function normalizeCustomGradient(
|
|
662
|
+
input: unknown,
|
|
663
|
+
): ScreenshotThreeScene['customGradient'] | undefined {
|
|
664
|
+
if (!isRecord(input)) return undefined
|
|
665
|
+
const g = input
|
|
666
|
+
if (!Array.isArray(g.stops)) return undefined
|
|
667
|
+
const stops = g.stops
|
|
668
|
+
.filter(
|
|
669
|
+
(s): s is { offset: number; color: string } =>
|
|
670
|
+
isRecord(s) && typeof s.color === 'string' && typeof s.offset === 'number',
|
|
671
|
+
)
|
|
672
|
+
.map((s) => ({ offset: s.offset, color: s.color }))
|
|
673
|
+
if (stops.length === 0) return undefined
|
|
674
|
+
return {
|
|
675
|
+
stops,
|
|
676
|
+
...(typeof g.angleDeg === 'number' ? { angleDeg: g.angleDeg } : {}),
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// every dimension is checked against its own id list, and anything unknown
|
|
681
|
+
// falls back to identity for that dimension. A string that merely looks like
|
|
682
|
+
// an id is exactly what must not reach the renderer: it would be dropped
|
|
683
|
+
// there, silently restoring a slide to a look it was never graded with.
|
|
684
|
+
function normalizeThreeSceneGrade(input: Record<string, unknown>): ScreenshotThreeGrade {
|
|
685
|
+
const read = <K extends keyof ScreenshotThreeGrade>(
|
|
686
|
+
key: K,
|
|
687
|
+
): ScreenshotThreeGrade[K] => {
|
|
688
|
+
const value = input[key]
|
|
689
|
+
const ids: readonly ScreenshotThreeGrade[K][] = SCREENSHOT_THREE_GRADE_IDS[key]
|
|
690
|
+
return ids.find((id) => id === value) ?? SCREENSHOT_THREE_GRADE_DEFAULT[key]
|
|
691
|
+
}
|
|
692
|
+
return {
|
|
693
|
+
contrast: read('contrast'),
|
|
694
|
+
saturation: read('saturation'),
|
|
695
|
+
brightness: read('brightness'),
|
|
696
|
+
blackPoint: read('blackPoint'),
|
|
697
|
+
grain: read('grain'),
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// authored numbers, clamped to the same ranges the 3d bridge validates
|
|
702
|
+
// against. A missing or non-finite field takes the default rather than
|
|
703
|
+
// dropping out of the saved rig.
|
|
704
|
+
function normalizeThreeSceneCyclorama(value: unknown): ScreenshotThreeCyclorama {
|
|
705
|
+
const input = isRecord(value) ? value : {}
|
|
706
|
+
const read = (key: ScreenshotThreeCycloramaNumericKey): number => {
|
|
707
|
+
const [min, max] = SCREENSHOT_THREE_CYCLORAMA_RANGES[key]
|
|
708
|
+
return clampNumber(input[key], min, max, SCREENSHOT_THREE_CYCLORAMA_DEFAULT[key])
|
|
709
|
+
}
|
|
710
|
+
const readColor = (key: 'warmColor' | 'coolColor'): string =>
|
|
711
|
+
normalizeScreenshotThreeCycloramaColor(
|
|
712
|
+
input[key],
|
|
713
|
+
SCREENSHOT_THREE_CYCLORAMA_DEFAULT[key],
|
|
714
|
+
)
|
|
715
|
+
return {
|
|
716
|
+
keyAzimuthDeg: read('keyAzimuthDeg'),
|
|
717
|
+
keyElevationDeg: read('keyElevationDeg'),
|
|
718
|
+
keyRiseDeg: read('keyRiseDeg'),
|
|
719
|
+
sweepMs: read('sweepMs'),
|
|
720
|
+
keyIntensity: read('keyIntensity'),
|
|
721
|
+
warmIntensity: read('warmIntensity'),
|
|
722
|
+
coolIntensity: read('coolIntensity'),
|
|
723
|
+
curveRadius: read('curveRadius'),
|
|
724
|
+
shadowSoftness: read('shadowSoftness'),
|
|
725
|
+
warmColor: readColor('warmColor'),
|
|
726
|
+
coolColor: readColor('coolColor'),
|
|
727
|
+
warmColorEnd: normalizeScreenshotThreeCycloramaEndColor(
|
|
728
|
+
'warmColorEnd' in input ? input.warmColorEnd : null,
|
|
729
|
+
),
|
|
730
|
+
coolColorEnd: normalizeScreenshotThreeCycloramaEndColor(
|
|
731
|
+
'coolColorEnd' in input ? input.coolColorEnd : null,
|
|
732
|
+
),
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* The 3d bridge options that put a saved slide's scene back. Every dimension
|
|
738
|
+
* the slide can carry is named here, including the ones it saved at their
|
|
739
|
+
* default: configure() merges partial input onto the LIVE state, which is
|
|
740
|
+
* what live editing wants and exactly what restoring must not do. Leaving
|
|
741
|
+
* caseStyle, grade or the cyclorama rig out is how a standard slide opened
|
|
742
|
+
* after an edge-to-edge one came back wearing the other slide's case, its
|
|
743
|
+
* grain and its lighting.
|
|
744
|
+
*/
|
|
745
|
+
export function screenshotThreeSceneRestoreOptions(scene: ScreenshotThreeScene) {
|
|
746
|
+
return {
|
|
747
|
+
...scene.appearance,
|
|
748
|
+
device: scene.device,
|
|
749
|
+
caseStyle: scene.appearance?.caseStyle ?? 'standard',
|
|
750
|
+
colorway: scene.colorway,
|
|
751
|
+
background: scene.background,
|
|
752
|
+
...(scene.customGradient ? { customGradient: scene.customGradient } : {}),
|
|
753
|
+
setting: scene.setting,
|
|
754
|
+
grade: scene.appearance?.grade ?? SCREENSHOT_THREE_GRADE_DEFAULT,
|
|
755
|
+
// a slide saved before the tints existed carries a rig without them, and
|
|
756
|
+
// configure() merges partials onto the live state: hand the renderer a
|
|
757
|
+
// complete rig here or the previous slide's tints stay lit.
|
|
758
|
+
cyclorama: scene.appearance?.cyclorama
|
|
759
|
+
? normalizeThreeSceneCyclorama(scene.appearance.cyclorama)
|
|
760
|
+
: SCREENSHOT_THREE_CYCLORAMA_DEFAULT,
|
|
761
|
+
focus: scene.focus,
|
|
762
|
+
environment: scene.environmentActive
|
|
763
|
+
? {
|
|
764
|
+
pins: scene.environmentPins ?? {},
|
|
765
|
+
effects: scene.environmentEffects ?? {},
|
|
766
|
+
}
|
|
767
|
+
: false,
|
|
768
|
+
pose: {
|
|
769
|
+
phonePosition: scene.phonePosition,
|
|
770
|
+
phoneRotation: scene.phoneRotation,
|
|
771
|
+
cameraPosition: scene.cameraPosition,
|
|
772
|
+
cameraUp: scene.cameraUp,
|
|
773
|
+
target: scene.target,
|
|
774
|
+
},
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
function normalizeSceneRecord<T>(
|
|
779
|
+
input: unknown,
|
|
780
|
+
isValue: (value: unknown) => value is T,
|
|
781
|
+
): Record<string, T> | undefined {
|
|
782
|
+
if (!isRecord(input)) return undefined
|
|
783
|
+
return Object.fromEntries(
|
|
784
|
+
Object.entries(input).filter((entry): entry is [string, T] => isValue(entry[1])),
|
|
785
|
+
)
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
function isScreenshotBgColorName(value: unknown): value is ScreenshotBgColorName {
|
|
789
|
+
return SCREENSHOT_BG_COLORS.some((color) => color.name === value)
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
function normalizeThreeScene(input: unknown): ScreenshotThreeScene | undefined {
|
|
793
|
+
if (!isRecord(input)) return undefined
|
|
794
|
+
const s = input
|
|
795
|
+
const vec3 = (v: unknown): [number, number, number] | null => {
|
|
796
|
+
if (!Array.isArray(v) || v.length !== 3) return null
|
|
797
|
+
if (!v.every((n) => typeof n === 'number' && Number.isFinite(n))) return null
|
|
798
|
+
return [v[0], v[1], v[2]]
|
|
799
|
+
}
|
|
800
|
+
const cam = vec3(s.cameraPosition)
|
|
801
|
+
const cameraUp = vec3(s.cameraUp)
|
|
802
|
+
const tgt = vec3(s.target)
|
|
803
|
+
const pp = vec3(s.phonePosition)
|
|
804
|
+
const pr = vec3(s.phoneRotation)
|
|
805
|
+
if (!cam || !tgt || !pp || !pr) return undefined
|
|
806
|
+
const customGradient = normalizeCustomGradient(s.customGradient)
|
|
807
|
+
let appearance: ScreenshotThreeAppearance | undefined
|
|
808
|
+
if (isRecord(s.appearance)) {
|
|
809
|
+
const { caseStyle, grade, cyclorama, ...rest } = s.appearance
|
|
810
|
+
appearance = rest
|
|
811
|
+
if (
|
|
812
|
+
typeof appearance.windowLightOffset !== 'number' ||
|
|
813
|
+
!Number.isFinite(appearance.windowLightOffset) ||
|
|
814
|
+
appearance.windowLightOffset < THREE_WINDOW_LIGHT_OFFSET_RANGE[0] ||
|
|
815
|
+
appearance.windowLightOffset > THREE_WINDOW_LIGHT_OFFSET_RANGE[1]
|
|
816
|
+
)
|
|
817
|
+
delete appearance.windowLightOffset
|
|
818
|
+
if (caseStyle === 'standard' || caseStyle === 'edge-to-edge')
|
|
819
|
+
appearance.caseStyle = caseStyle
|
|
820
|
+
if (isRecord(grade)) appearance.grade = normalizeThreeSceneGrade(grade)
|
|
821
|
+
if (isRecord(cyclorama))
|
|
822
|
+
appearance.cyclorama = normalizeThreeSceneCyclorama(cyclorama)
|
|
823
|
+
}
|
|
824
|
+
const focus = normalizeSceneRecord(
|
|
825
|
+
s.focus,
|
|
826
|
+
(value) => value == null || typeof value === 'string' || typeof value === 'boolean',
|
|
827
|
+
)
|
|
828
|
+
const environmentPins = normalizeSceneRecord(
|
|
829
|
+
s.environmentPins,
|
|
830
|
+
(value) => value == null || typeof value === 'string',
|
|
831
|
+
)
|
|
832
|
+
const environmentEffects = normalizeSceneRecord(
|
|
833
|
+
s.environmentEffects,
|
|
834
|
+
(value) => typeof value === 'boolean',
|
|
835
|
+
)
|
|
836
|
+
return {
|
|
837
|
+
device:
|
|
838
|
+
s.device === 'iphone-17-pro' || s.device === 'pixel-10'
|
|
839
|
+
? s.device
|
|
840
|
+
: 'iphone-17-air',
|
|
841
|
+
cameraPosition: cam,
|
|
842
|
+
...(cameraUp ? { cameraUp } : {}),
|
|
843
|
+
target: tgt,
|
|
844
|
+
phonePosition: pp,
|
|
845
|
+
phoneRotation: pr,
|
|
846
|
+
colorway: typeof s.colorway === 'string' ? s.colorway : 'black',
|
|
847
|
+
background: typeof s.background === 'string' ? s.background : 'black',
|
|
848
|
+
...(customGradient ? { customGradient } : {}),
|
|
849
|
+
setting: isThreeModeSetting(s.setting) ? s.setting : 'none',
|
|
850
|
+
...(appearance ? { appearance } : {}),
|
|
851
|
+
...(focus ? { focus } : {}),
|
|
852
|
+
environmentActive: !!s.environmentActive,
|
|
853
|
+
environmentPins,
|
|
854
|
+
environmentEffects,
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// normalize a (possibly legacy / partial) slide so the rest of the code
|
|
859
|
+
// has exactly one shape. pre-production: a legacy `theme` slide just
|
|
860
|
+
// resets to the grey default rather than carrying a compat shim.
|
|
861
|
+
export function normalizeScreenshotSlide(input: unknown, index = 0): ScreenshotSlide {
|
|
862
|
+
const s = isRecord(input) ? input : {}
|
|
863
|
+
const threeScene = normalizeThreeScene(s.threeScene)
|
|
864
|
+
const phone2d = normalizeScreenshotPhone2DTransform(s.phone2d)
|
|
865
|
+
const font = normalizeScreenshotFont(s.font)
|
|
866
|
+
const textPosition = normalizeScreenshotTextPosition(s.textPosition)
|
|
867
|
+
const images = normalizeScreenshotImages(s.images)
|
|
868
|
+
return {
|
|
869
|
+
id: typeof s.id === 'string' && s.id ? s.id : makeScreenshotSlide(index).id,
|
|
870
|
+
title: typeof s.title === 'string' ? s.title : '',
|
|
871
|
+
subtitle: typeof s.subtitle === 'string' ? s.subtitle : '',
|
|
872
|
+
bgTop: isScreenshotBgColorName(s.bgTop) ? s.bgTop : DEFAULT_BG_TOP,
|
|
873
|
+
bgBottom: isScreenshotBgColorName(s.bgBottom) ? s.bgBottom : DEFAULT_BG_BOTTOM,
|
|
874
|
+
pose: POSE_PRESET_NAMES.find((pose) => pose === s.pose) ?? 'straight',
|
|
875
|
+
...(isScreenshotBgColorName(s.titleColor) ? { titleColor: s.titleColor } : {}),
|
|
876
|
+
...(isTitleSize(s.titleSize) ? { titleSize: s.titleSize } : {}),
|
|
877
|
+
...(isTitleUnderlay(s.titleUnderlay) ? { titleUnderlay: s.titleUnderlay } : {}),
|
|
878
|
+
...(isTitleShadow(s.titleShadow) ? { titleShadow: s.titleShadow } : {}),
|
|
879
|
+
...(font ? { font } : {}),
|
|
880
|
+
...(textPosition ? { textPosition } : {}),
|
|
881
|
+
...(isScreenshotTextAlign(s.textAlign) ? { textAlign: s.textAlign } : {}),
|
|
882
|
+
...(images ? { images } : {}),
|
|
883
|
+
...(typeof s.captureRef === 'string' ? { captureRef: s.captureRef } : {}),
|
|
884
|
+
...(typeof s.cleanRef === 'string' ? { cleanRef: s.cleanRef } : {}),
|
|
885
|
+
...(typeof s.screenRef === 'string' ? { screenRef: s.screenRef } : {}),
|
|
886
|
+
...(phone2d ? { phone2d } : {}),
|
|
887
|
+
...(threeScene ? { threeScene } : {}),
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
export interface ThreeProjectConfig {
|
|
892
|
+
colorway: string
|
|
893
|
+
background: string
|
|
894
|
+
// remaining 3d decor/script state is folded in during Phase 6.
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
export interface ScreenshotProjectConfig {
|
|
898
|
+
store: 'apple' | 'google'
|
|
899
|
+
canvas: ScreenshotCanvasName
|
|
900
|
+
deviceModel: DeviceModel
|
|
901
|
+
// false until the user picks a device from the screenshot rail. while
|
|
902
|
+
// false, entering screenshot mode adopts whatever device you were
|
|
903
|
+
// already on (the "default to current device" behavior); once true the
|
|
904
|
+
// project's device is authoritative and pushed to the engine on enter.
|
|
905
|
+
// single rule, no fallback ambiguity.
|
|
906
|
+
deviceModelExplicit?: boolean
|
|
907
|
+
frames: ScreenshotSlide[]
|
|
908
|
+
activeSlideId: string
|
|
909
|
+
three?: ThreeProjectConfig
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
// fresh projects open with a single slide; the user adds more from the
|
|
913
|
+
// overview gallery's + tile. matches the App-Store editor's blank-state
|
|
914
|
+
// expectation — empty canvas, not a grid of pre-seeded placeholders.
|
|
915
|
+
export const DEFAULT_SCREENSHOT_FRAME_COUNT = 1
|
|
916
|
+
|
|
917
|
+
// Apple allows up to 10 screenshots per device, Google Play 8.
|
|
918
|
+
export const SCREENSHOT_FRAME_LIMITS: Record<'apple' | 'google', number> = {
|
|
919
|
+
apple: 10,
|
|
920
|
+
google: 8,
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
export function makeScreenshotSlide(index: number): ScreenshotSlide {
|
|
924
|
+
return {
|
|
925
|
+
id: `slide_${Date.now().toString(36)}_${index}_${Math.random().toString(36).slice(2, 7)}`,
|
|
926
|
+
title: '',
|
|
927
|
+
subtitle: '',
|
|
928
|
+
bgTop: DEFAULT_BG_TOP,
|
|
929
|
+
bgBottom: DEFAULT_BG_BOTTOM,
|
|
930
|
+
pose: 'straight',
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
export function defaultScreenshotProjectConfig(
|
|
935
|
+
deviceModel: DeviceModel,
|
|
936
|
+
canvas: ScreenshotCanvasName = deviceModel === 'ipad-pro-13'
|
|
937
|
+
? 'ipad-pro-13'
|
|
938
|
+
: 'iphone-6-9',
|
|
939
|
+
): ScreenshotProjectConfig {
|
|
940
|
+
const frames = Array.from({ length: DEFAULT_SCREENSHOT_FRAME_COUNT }, (_, i) =>
|
|
941
|
+
makeScreenshotSlide(i),
|
|
942
|
+
)
|
|
943
|
+
const store = SCREENSHOT_CANVASES[canvas]?.store ?? 'apple'
|
|
944
|
+
return {
|
|
945
|
+
store,
|
|
946
|
+
canvas,
|
|
947
|
+
deviceModel,
|
|
948
|
+
frames,
|
|
949
|
+
activeSlideId: frames[0].id,
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
export function resolveCanvasPreset(name: string): CanvasPreset | null {
|
|
954
|
+
const preset = SCREENSHOT_CANVAS_NAMES.find((preset) => preset === name)
|
|
955
|
+
return preset ? SCREENSHOT_CANVASES[preset] : null
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
export function cloneBackgroundSpec(background: BackgroundSpec): BackgroundSpec {
|
|
959
|
+
return {
|
|
960
|
+
type: background.type,
|
|
961
|
+
color: background.color,
|
|
962
|
+
direction: background.direction,
|
|
963
|
+
glow: background.glow,
|
|
964
|
+
stops: background.stops?.map((stop) => ({ ...stop })),
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
export function resolveBackgroundPreset(name: string): BackgroundSpec | null {
|
|
969
|
+
const preset = BACKGROUND_PRESET_NAMES.find((preset) => preset === name)
|
|
970
|
+
return preset ? cloneBackgroundSpec(BACKGROUND_PRESETS[preset]) : null
|
|
971
|
+
}
|