Create a new simulator from CLI

snippets

Create a new visionOS simulator. Command takes a name, device type, and runtime.

% xcrun simctl create "TestAVP" com.apple.CoreSimulator.SimDeviceType.Apple-Vision-Pro-4K com.apple.CoreSimulator.SimRuntime.xrOS-26-2 
4F8B10C1-90F3-4E91-8A73-AED33CACE123

Curious Case of the Missing Simulators

devlogs

In Xcode I recently encountered an issue where all of my simulators disappeared. In Xcode the canvas would only show a preview for the macOS build and I had no option to preview for any other Apple platform.

The “Devices and Simulator” window was completely empty. The target platforms and simulators are listed as installed in Settings->Components screen in Xcode’s settings.

On the command line, we can confirm this by running xcrun simctl list. Here we see that there are no devices available.

Site Update

devlogs

Site update

  • Removed the terminal Hugo theme.
  • Updated to custom theme
  • Removed projects section. Project updates are now in devlogs
  • Removed downtime section. This was previously hidden and now removed completely. Downtime updates may appear on a dedicated site in the future.
  • Added social section with links to YouTube, Mastodon, and GitHub
  • About page is now hidden. Content from About has been merged with the social page.
  • Support page is now hidden.

Pinned Entities

snippets

import RealityKit

struct PinnedEntityComponent: Component {
    weak var pinnedto: Entity? = nil
    let pinName: String
    var transform: Transform = .identity
}

struct PinnedEntitySystem: System {
    static let query: EntityQuery = .init(where: .has(PinnedEntityComponent.self))
    init(scene: Scene) {
    }
    
    func update(context: SceneUpdateContext) {
        let entities = context.entities(matching: Self.query, updatingSystemWhen: .rendering)
        for entity in entities {
            guard let comp = entity.components[PinnedEntityComponent.self] else {
                continue
            }
            
            //if the entity we are pinned to is no longer available then remove
            //the pinned object from the scene
            guard let pinnedto = comp.pinnedto else {
                entity.removeFromParent()
                continue
            }
            
            guard let pin = pinnedto.pins[comp.pinName] else { continue }
            
            //pin position and orientation can actually be nil so ! is dangerous here
            entity.setPosition(
                pin.position(relativeTo: nil)!
                , relativeTo: nil)
            entity.setOrientation(
                pin.orientation(relativeTo: nil)! * comp.transform.rotation
                , relativeTo: nil)
        }
    }
}

SwiftUI Text Color From Background

snippets

Choose a readable Text color automatically based on the background color.

import SwiftUI
extension Color {
    func bestTextColor() -> Color {
        guard let components = self.resolve(in: .init()).cgColor.components else { return .black}
        guard components.count >= 3 else { return .black }
        let red: CGFloat = components[safe: 0]
        let green: CGFloat = components[safe: 1]
        let blue: CGFloat = components[safe: 2]
        
        // Relative luminance approximation for contrast decisions.
        let luminance = (0.299 * red) + (0.587 * green) + (0.114 * blue)
        return luminance > 0.6 ? .black : .white
    }
}

extension Array<CGFloat> {
    subscript(safe index: Int, default: CGFloat = 0) -> CGFloat {
        guard self.count > index else { return `default` }
        return self[index]
    }
}