serve-sim 0.1.47-beta.127.1 → 0.1.47

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 CHANGED
@@ -59,7 +59,7 @@ runs inside the simulator and exits with the device session.
59
59
  Duo uses one interactive RealityKit preview of the installed Xcode model, with
60
60
  live screen textures and touches mapped to each bent screen half. Apple's model
61
61
  stays in Xcode; it is not redistributed. Rotate animates the device and pose
62
- icons together. Motion uses a faster render target and sharpens when settled.
62
+ icons together. Motion uses a faster 1000×900 render target and sharpens once to 1500×1350 when settled.
63
63
  Screenshots capture the active app framebuffer, including the unfolded inner display.
64
64
 
65
65
  Use the pose buttons or hold **Alt** to reveal the continuous hinge slider.
@@ -8,6 +8,13 @@ import UniformTypeIdentifiers
8
8
 
9
9
  /// Renders Apple's installed V68 asset; no Apple asset is copied into the package.
10
10
  @MainActor final class DuoRenderer {
11
+ /// Motion target. 10:9 matches the sharpen target, so normalized anchors stay put.
12
+ static let previewWidth = 1000
13
+ static let previewHeight = 900
14
+ /// One-shot settle target for Retina screen text. Never 3000, and MSAA stays off:
15
+ /// 4× MSAA plus a 3000px idle target was the Apple Silicon CPU regression.
16
+ static let sharpenWidth = 1500
17
+ static let sharpenHeight = 1350
11
18
  private let renderer: RealityRenderer
12
19
  private let wrapper = Entity()
13
20
  private let rest = Entity()
@@ -30,7 +37,7 @@ import UniformTypeIdentifiers
30
37
  private var screenTextures: [String: TextureResource] = [:]
31
38
  private var screenFrames: [String: Data] = [:]
32
39
  private var lastAngle: Double = .nan
33
- // Preserve fine screen detail on Retina displays and antialias the shell.
40
+ // Active target: 1000×900 while moving, 1500×1350 after the one-shot sharpen.
34
41
  var width: Int { texture.width }
35
42
  var height: Int { texture.height }
36
43
  // Use Device Hub's 36 mm sensor model with a longer lens to flatten depth.
@@ -72,11 +79,13 @@ import UniformTypeIdentifiers
72
79
  renderer.entities.append(camera)
73
80
  renderer.activeCamera = camera
74
81
  renderer.lighting.resource = EnvironmentResource.duoObjectLighting()
75
- renderer.cameraSettings.antialiasing = .multisample4X
82
+ // Preserve screen detail after settle with a second target, not MSAA.
83
+ // Antialiasing the shell at 4× was too expensive for the live stream.
84
+ renderer.cameraSettings.antialiasing = .none
76
85
  renderer.cameraSettings.colorBackground = .color(CGColor(red: 0, green: 0, blue: 0, alpha: 0))
77
86
  // Keep both targets allocated: resizing during gestures would stall Metal.
78
- targets = try [1500, 3000].map { width in
79
- let descriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .bgra8Unorm_srgb, width: width, height: width * 9 / 10, mipmapped: false)
87
+ targets = try [(Self.previewWidth, Self.previewHeight), (Self.sharpenWidth, Self.sharpenHeight)].map { width, height in
88
+ let descriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .bgra8Unorm_srgb, width: width, height: height, mipmapped: false)
80
89
  descriptor.storageMode = .shared
81
90
  descriptor.usage = [.renderTarget, .shaderRead]
82
91
  guard let texture = device.makeTexture(descriptor: descriptor) else { throw CocoaError(.fileReadUnknown) }
@@ -86,10 +95,11 @@ import UniformTypeIdentifiers
86
95
  controller = subject.playAnimation(clip, transitionDuration: 0, startsPaused: true)
87
96
  }
88
97
 
89
- func render(jpeg: Data, panel: String, angle: Double, roll: Double, fullResolution: Bool = true) async throws -> Data {
98
+ func render(jpeg: Data, panel: String, angle: Double, roll: Double, fullResolution: Bool = false) async throws -> Data {
99
+ // False is the fast motion target. True is the one-shot 1500px settle frame.
90
100
  targetIndex = fullResolution ? 1 : 0
91
101
  guard angle.isFinite, (0...180).contains(angle), roll.isFinite else { throw CocoaError(.fileReadCorruptFile) }
92
- // Hinge, rotation, and idle sharpening often reuse the same framebuffer.
102
+ // Hinge and rotation updates often reuse the same screen image.
93
103
  // Keep both panel textures alive and skip image decoding/upload entirely.
94
104
  if screenFrames[panel] != jpeg {
95
105
  guard let source = CGImageSourceCreateWithData(jpeg as CFData, nil),
@@ -36,7 +36,8 @@ private func readRequest() throws -> (Request, Data)? {
36
36
  guard CommandLine.arguments.count == 2 else { throw CocoaError(.fileReadInvalidFileName) }
37
37
  let renderer = try await DuoRenderer(modelURL: URL(fileURLWithPath: CommandLine.arguments[1]))
38
38
  while let (request, jpeg) = try await Task.detached(operation: { try readRequest() }).value {
39
- let rendered = try await renderer.render(jpeg: jpeg, panel: request.panel, angle: request.hingeDegrees, roll: request.rollDegrees, fullResolution: request.fullResolution ?? true)
39
+ // Omitted fullResolution stays on the fast target. True is the 1500px settle sharpen.
40
+ let rendered = try await renderer.render(jpeg: jpeg, panel: request.panel, angle: request.hingeDegrees, roll: request.rollDegrees, fullResolution: request.fullResolution ?? false)
40
41
  let header = try JSONSerialization.data(withJSONObject: [
41
42
  "jpegLength": rendered.count, "width": renderer.width, "height": renderer.height,
42
43
  "pieces": renderer.pieces, "hardware": renderer.hardware, "panel": request.panel, "hingeDegrees": request.hingeDegrees,