[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-meta-camera-streaming":3,"mdc-1scpg1-key":37,"related-repo-meta-camera-streaming":991,"related-org-meta-camera-streaming":1089},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":12,"stars":26,"repoUrl":27,"updatedAt":28,"license":29,"forks":30,"topics":31,"repo":32,"sourceUrl":35,"mdContent":36},"camera-streaming","configure camera streaming and photo capture","Stream, video frames, photo capture, resolution\u002Fframe rate configuration",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},"meta","Meta Open Source","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fmeta.png","facebook",[13,17,20,23],{"name":14,"slug":15,"type":16},"iOS","ios","tag",{"name":18,"slug":19,"type":16},"Hardware","hardware",{"name":21,"slug":22,"type":16},"Camera","camera",{"name":24,"slug":25,"type":16},"Video","video",488,"https:\u002F\u002Fgithub.com\u002Ffacebook\u002Fmeta-wearables-dat-ios","2026-05-15T06:14:43.555881",null,112,[],{"repoUrl":27,"stars":26,"forks":30,"topics":33,"description":34},[],"Meta Wearables Device Access Toolkit for iOS","https:\u002F\u002Fgithub.com\u002Ffacebook\u002Fmeta-wearables-dat-ios\u002Ftree\u002FHEAD\u002Fplugins\u002Fmwdat-ios\u002Fskills\u002Fcamera-streaming","---\nname: camera-streaming\ndescription: Stream, video frames, photo capture, resolution\u002Fframe rate configuration\n---\n\n# Camera Streaming (iOS)\n\nGuide for implementing camera streaming and photo capture with the DAT SDK.\n\n## Key concepts\n\n- **Stream**: Main interface for camera streaming\n- **VideoFrame**: Individual video frames — call `.makeUIImage()` to render\n- **StreamConfiguration**: Configure resolution, frame rate, and codec\n- **PhotoData**: Still image captured from glasses\n\n## Creating a DeviceSession\n\n```swift\nimport MWDATCamera\nimport MWDATCore\n\nlet wearables = Wearables.shared\nlet deviceSelector = AutoDeviceSelector(wearables: wearables)\n\u002F\u002F Or for a specific device: SpecificDeviceSelector(device: deviceId)\nlet deviceSession = try wearables.createSession(deviceSelector: deviceSelector)\ntry deviceSession.start()\n\n\u002F\u002F Wait for the device session to reach the started state\nfor await state in deviceSession.stateStream() {\n    if state == .started { break }\n}\n```\n\n## Adding a Stream\n\nOnce the `DeviceSession` is started, add a `Stream` capability:\n\n```swift\nlet config = StreamConfiguration(\n    videoCodec: .raw,\n    resolution: .medium,  \u002F\u002F 504x896\n    frameRate: 24\n)\n\nguard let stream = try deviceSession.addStream(config: config) else {\n    \u002F\u002F DeviceSession must be in the started state before adding a stream\n    return\n}\n```\n\n### Resolution options\n\n| Resolution | Size |\n|-----------|------|\n| `.high` | 720 x 1280 |\n| `.medium` | 504 x 896 |\n| `.low` | 360 x 640 |\n\n### Frame rate options\n\nValid values: `2`, `7`, `15`, `24`, `30` FPS.\n\nLower resolution and frame rate yield higher visual quality due to less Bluetooth compression.\n\n## Observing stream state\n\n`StreamState` transitions: `stopping` → `stopped` → `waitingForDevice` → `starting` → `streaming` → `paused`\n\n```swift\nlet stateToken = stream.statePublisher.listen { state in\n    Task { @MainActor in\n        switch state {\n        case .streaming:\n            \u002F\u002F Stream is active, frames are flowing\n        case .waitingForDevice:\n            \u002F\u002F Waiting for glasses to connect\n        case .stopped:\n            \u002F\u002F Stream ended — release resources\n        case .paused:\n            \u002F\u002F Temporarily suspended — keep connection, wait\n        default:\n            break\n        }\n    }\n}\n```\n\n## Receiving video frames\n\n```swift\nlet frameToken = stream.videoFramePublisher.listen { frame in\n    guard let image = frame.makeUIImage() else { return }\n    Task { @MainActor in\n        self.previewImage = image\n    }\n}\n```\n\n## Starting and stopping\n\n```swift\n\u002F\u002F Start the stream capability\nstream.start()\n\n\u002F\u002F Stop streaming\nstream.stop()\n\n\u002F\u002F Stop the parent device session when you're done with all capabilities\ndeviceSession.stop()\n```\n\n## Photo capture\n\nCapture a still photo while streaming:\n\n```swift\n\u002F\u002F Listen for photo data\nlet photoToken = stream.photoDataPublisher.listen { photoData in\n    let imageData = photoData.data\n    \u002F\u002F Convert to UIImage or save\n}\n\n\u002F\u002F Trigger capture\nstream.capturePhoto(format: .jpeg)\n```\n\n## Bandwidth and quality\n\nResolution and frame rate are constrained by Bluetooth Classic bandwidth. The SDK automatically reduces quality when bandwidth is limited:\n1. First lowers resolution (e.g., High → Medium)\n2. Then reduces frame rate (e.g., 30 → 24), never below 15 FPS\n\nRequest lower settings for higher visual quality per frame.\n\n## Links\n\n- [Stream API reference](https:\u002F\u002Fwearables.developer.meta.com\u002Fdocs\u002Freference\u002Fios_swift\u002Fdat\u002F0.8\u002Fmwdatcamera_stream)\n- [StreamConfiguration API reference](https:\u002F\u002Fwearables.developer.meta.com\u002Fdocs\u002Freference\u002Fios_swift\u002Fdat\u002F0.8\u002Fmwdatcamera_streamconfiguration)\n- [Integration guide](https:\u002F\u002Fwearables.developer.meta.com\u002Fdocs\u002Fbuild-integration-ios)\n",{"data":38,"body":39},{"name":4,"description":6},{"type":40,"children":41},"root",[42,51,57,64,119,125,255,261,281,366,373,452,458,500,505,511,564,701,707,759,765,834,840,845,914,920,925,939,944,950,985],{"type":43,"tag":44,"props":45,"children":47},"element","h1",{"id":46},"camera-streaming-ios",[48],{"type":49,"value":50},"text","Camera Streaming (iOS)",{"type":43,"tag":52,"props":53,"children":54},"p",{},[55],{"type":49,"value":56},"Guide for implementing camera streaming and photo capture with the DAT SDK.",{"type":43,"tag":58,"props":59,"children":61},"h2",{"id":60},"key-concepts",[62],{"type":49,"value":63},"Key concepts",{"type":43,"tag":65,"props":66,"children":67},"ul",{},[68,80,99,109],{"type":43,"tag":69,"props":70,"children":71},"li",{},[72,78],{"type":43,"tag":73,"props":74,"children":75},"strong",{},[76],{"type":49,"value":77},"Stream",{"type":49,"value":79},": Main interface for camera streaming",{"type":43,"tag":69,"props":81,"children":82},{},[83,88,90,97],{"type":43,"tag":73,"props":84,"children":85},{},[86],{"type":49,"value":87},"VideoFrame",{"type":49,"value":89},": Individual video frames — call ",{"type":43,"tag":91,"props":92,"children":94},"code",{"className":93},[],[95],{"type":49,"value":96},".makeUIImage()",{"type":49,"value":98}," to render",{"type":43,"tag":69,"props":100,"children":101},{},[102,107],{"type":43,"tag":73,"props":103,"children":104},{},[105],{"type":49,"value":106},"StreamConfiguration",{"type":49,"value":108},": Configure resolution, frame rate, and codec",{"type":43,"tag":69,"props":110,"children":111},{},[112,117],{"type":43,"tag":73,"props":113,"children":114},{},[115],{"type":49,"value":116},"PhotoData",{"type":49,"value":118},": Still image captured from glasses",{"type":43,"tag":58,"props":120,"children":122},{"id":121},"creating-a-devicesession",[123],{"type":49,"value":124},"Creating a DeviceSession",{"type":43,"tag":126,"props":127,"children":132},"pre",{"className":128,"code":129,"language":130,"meta":131,"style":131},"language-swift shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import MWDATCamera\nimport MWDATCore\n\nlet wearables = Wearables.shared\nlet deviceSelector = AutoDeviceSelector(wearables: wearables)\n\u002F\u002F Or for a specific device: SpecificDeviceSelector(device: deviceId)\nlet deviceSession = try wearables.createSession(deviceSelector: deviceSelector)\ntry deviceSession.start()\n\n\u002F\u002F Wait for the device session to reach the started state\nfor await state in deviceSession.stateStream() {\n    if state == .started { break }\n}\n","swift","",[133],{"type":43,"tag":91,"props":134,"children":135},{"__ignoreMap":131},[136,147,156,166,175,184,193,202,211,219,228,237,246],{"type":43,"tag":137,"props":138,"children":141},"span",{"class":139,"line":140},"line",1,[142],{"type":43,"tag":137,"props":143,"children":144},{},[145],{"type":49,"value":146},"import MWDATCamera\n",{"type":43,"tag":137,"props":148,"children":150},{"class":139,"line":149},2,[151],{"type":43,"tag":137,"props":152,"children":153},{},[154],{"type":49,"value":155},"import MWDATCore\n",{"type":43,"tag":137,"props":157,"children":159},{"class":139,"line":158},3,[160],{"type":43,"tag":137,"props":161,"children":163},{"emptyLinePlaceholder":162},true,[164],{"type":49,"value":165},"\n",{"type":43,"tag":137,"props":167,"children":169},{"class":139,"line":168},4,[170],{"type":43,"tag":137,"props":171,"children":172},{},[173],{"type":49,"value":174},"let wearables = Wearables.shared\n",{"type":43,"tag":137,"props":176,"children":178},{"class":139,"line":177},5,[179],{"type":43,"tag":137,"props":180,"children":181},{},[182],{"type":49,"value":183},"let deviceSelector = AutoDeviceSelector(wearables: wearables)\n",{"type":43,"tag":137,"props":185,"children":187},{"class":139,"line":186},6,[188],{"type":43,"tag":137,"props":189,"children":190},{},[191],{"type":49,"value":192},"\u002F\u002F Or for a specific device: SpecificDeviceSelector(device: deviceId)\n",{"type":43,"tag":137,"props":194,"children":196},{"class":139,"line":195},7,[197],{"type":43,"tag":137,"props":198,"children":199},{},[200],{"type":49,"value":201},"let deviceSession = try wearables.createSession(deviceSelector: deviceSelector)\n",{"type":43,"tag":137,"props":203,"children":205},{"class":139,"line":204},8,[206],{"type":43,"tag":137,"props":207,"children":208},{},[209],{"type":49,"value":210},"try deviceSession.start()\n",{"type":43,"tag":137,"props":212,"children":214},{"class":139,"line":213},9,[215],{"type":43,"tag":137,"props":216,"children":217},{"emptyLinePlaceholder":162},[218],{"type":49,"value":165},{"type":43,"tag":137,"props":220,"children":222},{"class":139,"line":221},10,[223],{"type":43,"tag":137,"props":224,"children":225},{},[226],{"type":49,"value":227},"\u002F\u002F Wait for the device session to reach the started state\n",{"type":43,"tag":137,"props":229,"children":231},{"class":139,"line":230},11,[232],{"type":43,"tag":137,"props":233,"children":234},{},[235],{"type":49,"value":236},"for await state in deviceSession.stateStream() {\n",{"type":43,"tag":137,"props":238,"children":240},{"class":139,"line":239},12,[241],{"type":43,"tag":137,"props":242,"children":243},{},[244],{"type":49,"value":245},"    if state == .started { break }\n",{"type":43,"tag":137,"props":247,"children":249},{"class":139,"line":248},13,[250],{"type":43,"tag":137,"props":251,"children":252},{},[253],{"type":49,"value":254},"}\n",{"type":43,"tag":58,"props":256,"children":258},{"id":257},"adding-a-stream",[259],{"type":49,"value":260},"Adding a Stream",{"type":43,"tag":52,"props":262,"children":263},{},[264,266,272,274,279],{"type":49,"value":265},"Once the ",{"type":43,"tag":91,"props":267,"children":269},{"className":268},[],[270],{"type":49,"value":271},"DeviceSession",{"type":49,"value":273}," is started, add a ",{"type":43,"tag":91,"props":275,"children":277},{"className":276},[],[278],{"type":49,"value":77},{"type":49,"value":280}," capability:",{"type":43,"tag":126,"props":282,"children":284},{"className":128,"code":283,"language":130,"meta":131,"style":131},"let config = StreamConfiguration(\n    videoCodec: .raw,\n    resolution: .medium,  \u002F\u002F 504x896\n    frameRate: 24\n)\n\nguard let stream = try deviceSession.addStream(config: config) else {\n    \u002F\u002F DeviceSession must be in the started state before adding a stream\n    return\n}\n",[285],{"type":43,"tag":91,"props":286,"children":287},{"__ignoreMap":131},[288,296,304,312,320,328,335,343,351,359],{"type":43,"tag":137,"props":289,"children":290},{"class":139,"line":140},[291],{"type":43,"tag":137,"props":292,"children":293},{},[294],{"type":49,"value":295},"let config = StreamConfiguration(\n",{"type":43,"tag":137,"props":297,"children":298},{"class":139,"line":149},[299],{"type":43,"tag":137,"props":300,"children":301},{},[302],{"type":49,"value":303},"    videoCodec: .raw,\n",{"type":43,"tag":137,"props":305,"children":306},{"class":139,"line":158},[307],{"type":43,"tag":137,"props":308,"children":309},{},[310],{"type":49,"value":311},"    resolution: .medium,  \u002F\u002F 504x896\n",{"type":43,"tag":137,"props":313,"children":314},{"class":139,"line":168},[315],{"type":43,"tag":137,"props":316,"children":317},{},[318],{"type":49,"value":319},"    frameRate: 24\n",{"type":43,"tag":137,"props":321,"children":322},{"class":139,"line":177},[323],{"type":43,"tag":137,"props":324,"children":325},{},[326],{"type":49,"value":327},")\n",{"type":43,"tag":137,"props":329,"children":330},{"class":139,"line":186},[331],{"type":43,"tag":137,"props":332,"children":333},{"emptyLinePlaceholder":162},[334],{"type":49,"value":165},{"type":43,"tag":137,"props":336,"children":337},{"class":139,"line":195},[338],{"type":43,"tag":137,"props":339,"children":340},{},[341],{"type":49,"value":342},"guard let stream = try deviceSession.addStream(config: config) else {\n",{"type":43,"tag":137,"props":344,"children":345},{"class":139,"line":204},[346],{"type":43,"tag":137,"props":347,"children":348},{},[349],{"type":49,"value":350},"    \u002F\u002F DeviceSession must be in the started state before adding a stream\n",{"type":43,"tag":137,"props":352,"children":353},{"class":139,"line":213},[354],{"type":43,"tag":137,"props":355,"children":356},{},[357],{"type":49,"value":358},"    return\n",{"type":43,"tag":137,"props":360,"children":361},{"class":139,"line":221},[362],{"type":43,"tag":137,"props":363,"children":364},{},[365],{"type":49,"value":254},{"type":43,"tag":367,"props":368,"children":370},"h3",{"id":369},"resolution-options",[371],{"type":49,"value":372},"Resolution options",{"type":43,"tag":374,"props":375,"children":376},"table",{},[377,396],{"type":43,"tag":378,"props":379,"children":380},"thead",{},[381],{"type":43,"tag":382,"props":383,"children":384},"tr",{},[385,391],{"type":43,"tag":386,"props":387,"children":388},"th",{},[389],{"type":49,"value":390},"Resolution",{"type":43,"tag":386,"props":392,"children":393},{},[394],{"type":49,"value":395},"Size",{"type":43,"tag":397,"props":398,"children":399},"tbody",{},[400,418,435],{"type":43,"tag":382,"props":401,"children":402},{},[403,413],{"type":43,"tag":404,"props":405,"children":406},"td",{},[407],{"type":43,"tag":91,"props":408,"children":410},{"className":409},[],[411],{"type":49,"value":412},".high",{"type":43,"tag":404,"props":414,"children":415},{},[416],{"type":49,"value":417},"720 x 1280",{"type":43,"tag":382,"props":419,"children":420},{},[421,430],{"type":43,"tag":404,"props":422,"children":423},{},[424],{"type":43,"tag":91,"props":425,"children":427},{"className":426},[],[428],{"type":49,"value":429},".medium",{"type":43,"tag":404,"props":431,"children":432},{},[433],{"type":49,"value":434},"504 x 896",{"type":43,"tag":382,"props":436,"children":437},{},[438,447],{"type":43,"tag":404,"props":439,"children":440},{},[441],{"type":43,"tag":91,"props":442,"children":444},{"className":443},[],[445],{"type":49,"value":446},".low",{"type":43,"tag":404,"props":448,"children":449},{},[450],{"type":49,"value":451},"360 x 640",{"type":43,"tag":367,"props":453,"children":455},{"id":454},"frame-rate-options",[456],{"type":49,"value":457},"Frame rate options",{"type":43,"tag":52,"props":459,"children":460},{},[461,463,469,471,477,478,484,485,491,492,498],{"type":49,"value":462},"Valid values: ",{"type":43,"tag":91,"props":464,"children":466},{"className":465},[],[467],{"type":49,"value":468},"2",{"type":49,"value":470},", ",{"type":43,"tag":91,"props":472,"children":474},{"className":473},[],[475],{"type":49,"value":476},"7",{"type":49,"value":470},{"type":43,"tag":91,"props":479,"children":481},{"className":480},[],[482],{"type":49,"value":483},"15",{"type":49,"value":470},{"type":43,"tag":91,"props":486,"children":488},{"className":487},[],[489],{"type":49,"value":490},"24",{"type":49,"value":470},{"type":43,"tag":91,"props":493,"children":495},{"className":494},[],[496],{"type":49,"value":497},"30",{"type":49,"value":499}," FPS.",{"type":43,"tag":52,"props":501,"children":502},{},[503],{"type":49,"value":504},"Lower resolution and frame rate yield higher visual quality due to less Bluetooth compression.",{"type":43,"tag":58,"props":506,"children":508},{"id":507},"observing-stream-state",[509],{"type":49,"value":510},"Observing stream state",{"type":43,"tag":52,"props":512,"children":513},{},[514,520,522,528,530,536,537,543,544,550,551,557,558],{"type":43,"tag":91,"props":515,"children":517},{"className":516},[],[518],{"type":49,"value":519},"StreamState",{"type":49,"value":521}," transitions: ",{"type":43,"tag":91,"props":523,"children":525},{"className":524},[],[526],{"type":49,"value":527},"stopping",{"type":49,"value":529}," → ",{"type":43,"tag":91,"props":531,"children":533},{"className":532},[],[534],{"type":49,"value":535},"stopped",{"type":49,"value":529},{"type":43,"tag":91,"props":538,"children":540},{"className":539},[],[541],{"type":49,"value":542},"waitingForDevice",{"type":49,"value":529},{"type":43,"tag":91,"props":545,"children":547},{"className":546},[],[548],{"type":49,"value":549},"starting",{"type":49,"value":529},{"type":43,"tag":91,"props":552,"children":554},{"className":553},[],[555],{"type":49,"value":556},"streaming",{"type":49,"value":529},{"type":43,"tag":91,"props":559,"children":561},{"className":560},[],[562],{"type":49,"value":563},"paused",{"type":43,"tag":126,"props":565,"children":567},{"className":128,"code":566,"language":130,"meta":131,"style":131},"let stateToken = stream.statePublisher.listen { state in\n    Task { @MainActor in\n        switch state {\n        case .streaming:\n            \u002F\u002F Stream is active, frames are flowing\n        case .waitingForDevice:\n            \u002F\u002F Waiting for glasses to connect\n        case .stopped:\n            \u002F\u002F Stream ended — release resources\n        case .paused:\n            \u002F\u002F Temporarily suspended — keep connection, wait\n        default:\n            break\n        }\n    }\n}\n",[568],{"type":43,"tag":91,"props":569,"children":570},{"__ignoreMap":131},[571,579,587,595,603,611,619,627,635,643,651,659,667,675,684,693],{"type":43,"tag":137,"props":572,"children":573},{"class":139,"line":140},[574],{"type":43,"tag":137,"props":575,"children":576},{},[577],{"type":49,"value":578},"let stateToken = stream.statePublisher.listen { state in\n",{"type":43,"tag":137,"props":580,"children":581},{"class":139,"line":149},[582],{"type":43,"tag":137,"props":583,"children":584},{},[585],{"type":49,"value":586},"    Task { @MainActor in\n",{"type":43,"tag":137,"props":588,"children":589},{"class":139,"line":158},[590],{"type":43,"tag":137,"props":591,"children":592},{},[593],{"type":49,"value":594},"        switch state {\n",{"type":43,"tag":137,"props":596,"children":597},{"class":139,"line":168},[598],{"type":43,"tag":137,"props":599,"children":600},{},[601],{"type":49,"value":602},"        case .streaming:\n",{"type":43,"tag":137,"props":604,"children":605},{"class":139,"line":177},[606],{"type":43,"tag":137,"props":607,"children":608},{},[609],{"type":49,"value":610},"            \u002F\u002F Stream is active, frames are flowing\n",{"type":43,"tag":137,"props":612,"children":613},{"class":139,"line":186},[614],{"type":43,"tag":137,"props":615,"children":616},{},[617],{"type":49,"value":618},"        case .waitingForDevice:\n",{"type":43,"tag":137,"props":620,"children":621},{"class":139,"line":195},[622],{"type":43,"tag":137,"props":623,"children":624},{},[625],{"type":49,"value":626},"            \u002F\u002F Waiting for glasses to connect\n",{"type":43,"tag":137,"props":628,"children":629},{"class":139,"line":204},[630],{"type":43,"tag":137,"props":631,"children":632},{},[633],{"type":49,"value":634},"        case .stopped:\n",{"type":43,"tag":137,"props":636,"children":637},{"class":139,"line":213},[638],{"type":43,"tag":137,"props":639,"children":640},{},[641],{"type":49,"value":642},"            \u002F\u002F Stream ended — release resources\n",{"type":43,"tag":137,"props":644,"children":645},{"class":139,"line":221},[646],{"type":43,"tag":137,"props":647,"children":648},{},[649],{"type":49,"value":650},"        case .paused:\n",{"type":43,"tag":137,"props":652,"children":653},{"class":139,"line":230},[654],{"type":43,"tag":137,"props":655,"children":656},{},[657],{"type":49,"value":658},"            \u002F\u002F Temporarily suspended — keep connection, wait\n",{"type":43,"tag":137,"props":660,"children":661},{"class":139,"line":239},[662],{"type":43,"tag":137,"props":663,"children":664},{},[665],{"type":49,"value":666},"        default:\n",{"type":43,"tag":137,"props":668,"children":669},{"class":139,"line":248},[670],{"type":43,"tag":137,"props":671,"children":672},{},[673],{"type":49,"value":674},"            break\n",{"type":43,"tag":137,"props":676,"children":678},{"class":139,"line":677},14,[679],{"type":43,"tag":137,"props":680,"children":681},{},[682],{"type":49,"value":683},"        }\n",{"type":43,"tag":137,"props":685,"children":687},{"class":139,"line":686},15,[688],{"type":43,"tag":137,"props":689,"children":690},{},[691],{"type":49,"value":692},"    }\n",{"type":43,"tag":137,"props":694,"children":696},{"class":139,"line":695},16,[697],{"type":43,"tag":137,"props":698,"children":699},{},[700],{"type":49,"value":254},{"type":43,"tag":58,"props":702,"children":704},{"id":703},"receiving-video-frames",[705],{"type":49,"value":706},"Receiving video frames",{"type":43,"tag":126,"props":708,"children":710},{"className":128,"code":709,"language":130,"meta":131,"style":131},"let frameToken = stream.videoFramePublisher.listen { frame in\n    guard let image = frame.makeUIImage() else { return }\n    Task { @MainActor in\n        self.previewImage = image\n    }\n}\n",[711],{"type":43,"tag":91,"props":712,"children":713},{"__ignoreMap":131},[714,722,730,737,745,752],{"type":43,"tag":137,"props":715,"children":716},{"class":139,"line":140},[717],{"type":43,"tag":137,"props":718,"children":719},{},[720],{"type":49,"value":721},"let frameToken = stream.videoFramePublisher.listen { frame in\n",{"type":43,"tag":137,"props":723,"children":724},{"class":139,"line":149},[725],{"type":43,"tag":137,"props":726,"children":727},{},[728],{"type":49,"value":729},"    guard let image = frame.makeUIImage() else { return }\n",{"type":43,"tag":137,"props":731,"children":732},{"class":139,"line":158},[733],{"type":43,"tag":137,"props":734,"children":735},{},[736],{"type":49,"value":586},{"type":43,"tag":137,"props":738,"children":739},{"class":139,"line":168},[740],{"type":43,"tag":137,"props":741,"children":742},{},[743],{"type":49,"value":744},"        self.previewImage = image\n",{"type":43,"tag":137,"props":746,"children":747},{"class":139,"line":177},[748],{"type":43,"tag":137,"props":749,"children":750},{},[751],{"type":49,"value":692},{"type":43,"tag":137,"props":753,"children":754},{"class":139,"line":186},[755],{"type":43,"tag":137,"props":756,"children":757},{},[758],{"type":49,"value":254},{"type":43,"tag":58,"props":760,"children":762},{"id":761},"starting-and-stopping",[763],{"type":49,"value":764},"Starting and stopping",{"type":43,"tag":126,"props":766,"children":768},{"className":128,"code":767,"language":130,"meta":131,"style":131},"\u002F\u002F Start the stream capability\nstream.start()\n\n\u002F\u002F Stop streaming\nstream.stop()\n\n\u002F\u002F Stop the parent device session when you're done with all capabilities\ndeviceSession.stop()\n",[769],{"type":43,"tag":91,"props":770,"children":771},{"__ignoreMap":131},[772,780,788,795,803,811,818,826],{"type":43,"tag":137,"props":773,"children":774},{"class":139,"line":140},[775],{"type":43,"tag":137,"props":776,"children":777},{},[778],{"type":49,"value":779},"\u002F\u002F Start the stream capability\n",{"type":43,"tag":137,"props":781,"children":782},{"class":139,"line":149},[783],{"type":43,"tag":137,"props":784,"children":785},{},[786],{"type":49,"value":787},"stream.start()\n",{"type":43,"tag":137,"props":789,"children":790},{"class":139,"line":158},[791],{"type":43,"tag":137,"props":792,"children":793},{"emptyLinePlaceholder":162},[794],{"type":49,"value":165},{"type":43,"tag":137,"props":796,"children":797},{"class":139,"line":168},[798],{"type":43,"tag":137,"props":799,"children":800},{},[801],{"type":49,"value":802},"\u002F\u002F Stop streaming\n",{"type":43,"tag":137,"props":804,"children":805},{"class":139,"line":177},[806],{"type":43,"tag":137,"props":807,"children":808},{},[809],{"type":49,"value":810},"stream.stop()\n",{"type":43,"tag":137,"props":812,"children":813},{"class":139,"line":186},[814],{"type":43,"tag":137,"props":815,"children":816},{"emptyLinePlaceholder":162},[817],{"type":49,"value":165},{"type":43,"tag":137,"props":819,"children":820},{"class":139,"line":195},[821],{"type":43,"tag":137,"props":822,"children":823},{},[824],{"type":49,"value":825},"\u002F\u002F Stop the parent device session when you're done with all capabilities\n",{"type":43,"tag":137,"props":827,"children":828},{"class":139,"line":204},[829],{"type":43,"tag":137,"props":830,"children":831},{},[832],{"type":49,"value":833},"deviceSession.stop()\n",{"type":43,"tag":58,"props":835,"children":837},{"id":836},"photo-capture",[838],{"type":49,"value":839},"Photo capture",{"type":43,"tag":52,"props":841,"children":842},{},[843],{"type":49,"value":844},"Capture a still photo while streaming:",{"type":43,"tag":126,"props":846,"children":848},{"className":128,"code":847,"language":130,"meta":131,"style":131},"\u002F\u002F Listen for photo data\nlet photoToken = stream.photoDataPublisher.listen { photoData in\n    let imageData = photoData.data\n    \u002F\u002F Convert to UIImage or save\n}\n\n\u002F\u002F Trigger capture\nstream.capturePhoto(format: .jpeg)\n",[849],{"type":43,"tag":91,"props":850,"children":851},{"__ignoreMap":131},[852,860,868,876,884,891,898,906],{"type":43,"tag":137,"props":853,"children":854},{"class":139,"line":140},[855],{"type":43,"tag":137,"props":856,"children":857},{},[858],{"type":49,"value":859},"\u002F\u002F Listen for photo data\n",{"type":43,"tag":137,"props":861,"children":862},{"class":139,"line":149},[863],{"type":43,"tag":137,"props":864,"children":865},{},[866],{"type":49,"value":867},"let photoToken = stream.photoDataPublisher.listen { photoData in\n",{"type":43,"tag":137,"props":869,"children":870},{"class":139,"line":158},[871],{"type":43,"tag":137,"props":872,"children":873},{},[874],{"type":49,"value":875},"    let imageData = photoData.data\n",{"type":43,"tag":137,"props":877,"children":878},{"class":139,"line":168},[879],{"type":43,"tag":137,"props":880,"children":881},{},[882],{"type":49,"value":883},"    \u002F\u002F Convert to UIImage or save\n",{"type":43,"tag":137,"props":885,"children":886},{"class":139,"line":177},[887],{"type":43,"tag":137,"props":888,"children":889},{},[890],{"type":49,"value":254},{"type":43,"tag":137,"props":892,"children":893},{"class":139,"line":186},[894],{"type":43,"tag":137,"props":895,"children":896},{"emptyLinePlaceholder":162},[897],{"type":49,"value":165},{"type":43,"tag":137,"props":899,"children":900},{"class":139,"line":195},[901],{"type":43,"tag":137,"props":902,"children":903},{},[904],{"type":49,"value":905},"\u002F\u002F Trigger capture\n",{"type":43,"tag":137,"props":907,"children":908},{"class":139,"line":204},[909],{"type":43,"tag":137,"props":910,"children":911},{},[912],{"type":49,"value":913},"stream.capturePhoto(format: .jpeg)\n",{"type":43,"tag":58,"props":915,"children":917},{"id":916},"bandwidth-and-quality",[918],{"type":49,"value":919},"Bandwidth and quality",{"type":43,"tag":52,"props":921,"children":922},{},[923],{"type":49,"value":924},"Resolution and frame rate are constrained by Bluetooth Classic bandwidth. The SDK automatically reduces quality when bandwidth is limited:",{"type":43,"tag":926,"props":927,"children":928},"ol",{},[929,934],{"type":43,"tag":69,"props":930,"children":931},{},[932],{"type":49,"value":933},"First lowers resolution (e.g., High → Medium)",{"type":43,"tag":69,"props":935,"children":936},{},[937],{"type":49,"value":938},"Then reduces frame rate (e.g., 30 → 24), never below 15 FPS",{"type":43,"tag":52,"props":940,"children":941},{},[942],{"type":49,"value":943},"Request lower settings for higher visual quality per frame.",{"type":43,"tag":58,"props":945,"children":947},{"id":946},"links",[948],{"type":49,"value":949},"Links",{"type":43,"tag":65,"props":951,"children":952},{},[953,965,975],{"type":43,"tag":69,"props":954,"children":955},{},[956],{"type":43,"tag":957,"props":958,"children":962},"a",{"href":959,"rel":960},"https:\u002F\u002Fwearables.developer.meta.com\u002Fdocs\u002Freference\u002Fios_swift\u002Fdat\u002F0.8\u002Fmwdatcamera_stream",[961],"nofollow",[963],{"type":49,"value":964},"Stream API reference",{"type":43,"tag":69,"props":966,"children":967},{},[968],{"type":43,"tag":957,"props":969,"children":972},{"href":970,"rel":971},"https:\u002F\u002Fwearables.developer.meta.com\u002Fdocs\u002Freference\u002Fios_swift\u002Fdat\u002F0.8\u002Fmwdatcamera_streamconfiguration",[961],[973],{"type":49,"value":974},"StreamConfiguration API reference",{"type":43,"tag":69,"props":976,"children":977},{},[978],{"type":43,"tag":957,"props":979,"children":982},{"href":980,"rel":981},"https:\u002F\u002Fwearables.developer.meta.com\u002Fdocs\u002Fbuild-integration-ios",[961],[983],{"type":49,"value":984},"Integration guide",{"type":43,"tag":986,"props":987,"children":988},"style",{},[989],{"type":49,"value":990},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":992,"total":213},[993,1000,1016,1029,1049,1062,1077],{"slug":4,"name":4,"fn":5,"description":6,"org":994,"tags":995,"stars":26,"repoUrl":27,"updatedAt":28},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[996,997,998,999],{"name":21,"slug":22,"type":16},{"name":18,"slug":19,"type":16},{"name":14,"slug":15,"type":16},{"name":24,"slug":25,"type":16},{"slug":1001,"name":1001,"fn":1002,"description":1003,"org":1004,"tags":1005,"stars":26,"repoUrl":27,"updatedAt":1015},"dat-conventions","develop iOS applications with DAT SDK","Swift patterns, async\u002Fawait, naming conventions, key types for DAT SDK iOS development",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1006,1007,1010,1013],{"name":14,"slug":15,"type":16},{"name":1008,"slug":1009,"type":16},"Mobile","mobile",{"name":1011,"slug":1012,"type":16},"SDK","sdk",{"name":1014,"slug":130,"type":16},"Swift","2026-05-15T06:14:42.334435",{"slug":1017,"name":1017,"fn":1018,"description":1019,"org":1020,"tags":1021,"stars":26,"repoUrl":27,"updatedAt":1028},"debugging","debug wearable device software","Common issues, Developer Mode, version compatibility, state machine diagnosis",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1022,1024,1027],{"name":1023,"slug":1017,"type":16},"Debugging",{"name":1025,"slug":1026,"type":16},"Engineering","engineering",{"name":14,"slug":15,"type":16},"2026-05-15T06:14:38.626606",{"slug":1030,"name":1030,"fn":1031,"description":1032,"org":1033,"tags":1034,"stars":26,"repoUrl":27,"updatedAt":1048},"display-access","manage display capabilities on wearable devices","Display capability setup, display-capable device selection, UI DSL, icons, buttons, images, and video playback",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1035,1038,1041,1044,1047],{"name":1036,"slug":1037,"type":16},"Design","design",{"name":1039,"slug":1040,"type":16},"Images","images",{"name":1042,"slug":1043,"type":16},"Interaction","interaction",{"name":1045,"slug":1046,"type":16},"UI Components","ui-components",{"name":24,"slug":25,"type":16},"2026-05-15T06:14:39.844502",{"slug":1050,"name":1050,"fn":1051,"description":1052,"org":1053,"tags":1054,"stars":26,"repoUrl":27,"updatedAt":1061},"getting-started","set up Meta wearable SDK integration","SDK setup, Swift Package Manager integration, Info.plist configuration, and first connection to Meta glasses",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1055,1058,1059,1060],{"name":1056,"slug":1057,"type":16},"Configuration","configuration",{"name":14,"slug":15,"type":16},{"name":1011,"slug":1012,"type":16},{"name":1014,"slug":130,"type":16},"2026-05-15T06:14:41.086639",{"slug":1063,"name":1063,"fn":1064,"description":1065,"org":1066,"tags":1067,"stars":26,"repoUrl":27,"updatedAt":1076},"mockdevice-testing","test wearable apps with mock devices","MockDeviceKit for testing without physical glasses hardware",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1068,1069,1070,1073],{"name":14,"slug":15,"type":16},{"name":1008,"slug":1009,"type":16},{"name":1071,"slug":1072,"type":16},"QA","qa",{"name":1074,"slug":1075,"type":16},"Testing","testing","2026-05-15T06:14:37.406692",{"slug":1078,"name":1078,"fn":1079,"description":1080,"org":1081,"tags":1082,"stars":26,"repoUrl":27,"updatedAt":1088},"permissions-registration","register apps with Meta AI","App registration with Meta AI, camera permission flows",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1083,1084,1085],{"name":21,"slug":22,"type":16},{"name":14,"slug":15,"type":16},{"name":1086,"slug":1087,"type":16},"Permissions","permissions","2026-05-15T06:14:46.030253",{"items":1090,"total":1219},[1091,1113,1127,1148,1155,1162,1168,1176,1183,1190,1196,1206],{"slug":1092,"name":1092,"fn":1093,"description":1094,"org":1095,"tags":1096,"stars":1110,"repoUrl":1111,"updatedAt":1112},"relay-best-practices","write idiomatic Relay code","Best practices for writing idiomatic Relay code. ALWAYS use this skill when writing or modifying React components that use Relay for data fetching. Covers fragments, queries, mutations, pagination, and common anti-patterns. Use when you see `useFragment`, `useLazyLoadQuery`, `usePreloadedQuery`, `useMutation`, `usePaginationFragment`, `graphql` template literals, `react-relay` imports, or `__generated__\u002F*.graphql` files. Also use when asked to explain Relay concepts, debug Relay issues, or review Relay code.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1097,1098,1101,1104,1107],{"name":1025,"slug":1026,"type":16},{"name":1099,"slug":1100,"type":16},"Frontend","frontend",{"name":1102,"slug":1103,"type":16},"GraphQL","graphql",{"name":1105,"slug":1106,"type":16},"React","react",{"name":1108,"slug":1109,"type":16},"Relay","relay",18950,"https:\u002F\u002Fgithub.com\u002Ffacebook\u002Frelay","2026-04-22T04:58:15.370563",{"slug":1114,"name":1114,"fn":1115,"description":1116,"org":1117,"tags":1118,"stars":1110,"repoUrl":1111,"updatedAt":1126},"relay-performance","optimize Relay application performance","Performance best practices for Relay applications. Use when optimizing data fetching, reducing re-renders, configuring caching, or improving time to first meaningful paint. Covers query placement, @defer, pagination, fetch policies, garbage collection, fragment granularity, and server-side filtering. Companion to the relay-best-practices skill which covers correctness and architecture.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1119,1120,1121,1124,1125],{"name":1099,"slug":1100,"type":16},{"name":1102,"slug":1103,"type":16},{"name":1122,"slug":1123,"type":16},"Performance","performance",{"name":1105,"slug":1106,"type":16},{"name":1108,"slug":1109,"type":16},"2026-06-10T07:30:28.726513",{"slug":1128,"name":1128,"fn":1129,"description":1130,"org":1131,"tags":1132,"stars":1145,"repoUrl":1146,"updatedAt":1147},"add-shape-types-to-torch-model","annotate PyTorch models with tensor shapes","Port a PyTorch model to use pyrefly's tensor shape type system (Tensor[[B, C, H, W]], Int[T]). Use this skill whenever the user wants to add shape annotations to a PyTorch model, type a model with tensor dimensions, port a model to use shape tracking, or annotate model forward methods with tensor shapes. Also use when the user mentions tensor shape ports, Int types for PyTorch, or pyrefly shape checking on a model file. Invoke BEFORE starting any model port — the skill's gated workflow prevents common failure modes.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1133,1136,1139,1142],{"name":1134,"slug":1135,"type":16},"Data Modeling","data-modeling",{"name":1137,"slug":1138,"type":16},"Deep Learning","deep-learning",{"name":1140,"slug":1141,"type":16},"Python","python",{"name":1143,"slug":1144,"type":16},"PyTorch","pytorch",6833,"https:\u002F\u002Fgithub.com\u002Ffacebook\u002Fpyrefly","2026-07-18T05:12:08.515952",{"slug":4,"name":4,"fn":5,"description":6,"org":1149,"tags":1150,"stars":26,"repoUrl":27,"updatedAt":28},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1151,1152,1153,1154],{"name":21,"slug":22,"type":16},{"name":18,"slug":19,"type":16},{"name":14,"slug":15,"type":16},{"name":24,"slug":25,"type":16},{"slug":1001,"name":1001,"fn":1002,"description":1003,"org":1156,"tags":1157,"stars":26,"repoUrl":27,"updatedAt":1015},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1158,1159,1160,1161],{"name":14,"slug":15,"type":16},{"name":1008,"slug":1009,"type":16},{"name":1011,"slug":1012,"type":16},{"name":1014,"slug":130,"type":16},{"slug":1017,"name":1017,"fn":1018,"description":1019,"org":1163,"tags":1164,"stars":26,"repoUrl":27,"updatedAt":1028},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1165,1166,1167],{"name":1023,"slug":1017,"type":16},{"name":1025,"slug":1026,"type":16},{"name":14,"slug":15,"type":16},{"slug":1030,"name":1030,"fn":1031,"description":1032,"org":1169,"tags":1170,"stars":26,"repoUrl":27,"updatedAt":1048},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1171,1172,1173,1174,1175],{"name":1036,"slug":1037,"type":16},{"name":1039,"slug":1040,"type":16},{"name":1042,"slug":1043,"type":16},{"name":1045,"slug":1046,"type":16},{"name":24,"slug":25,"type":16},{"slug":1050,"name":1050,"fn":1051,"description":1052,"org":1177,"tags":1178,"stars":26,"repoUrl":27,"updatedAt":1061},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1179,1180,1181,1182],{"name":1056,"slug":1057,"type":16},{"name":14,"slug":15,"type":16},{"name":1011,"slug":1012,"type":16},{"name":1014,"slug":130,"type":16},{"slug":1063,"name":1063,"fn":1064,"description":1065,"org":1184,"tags":1185,"stars":26,"repoUrl":27,"updatedAt":1076},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1186,1187,1188,1189],{"name":14,"slug":15,"type":16},{"name":1008,"slug":1009,"type":16},{"name":1071,"slug":1072,"type":16},{"name":1074,"slug":1075,"type":16},{"slug":1078,"name":1078,"fn":1079,"description":1080,"org":1191,"tags":1192,"stars":26,"repoUrl":27,"updatedAt":1088},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1193,1194,1195],{"name":21,"slug":22,"type":16},{"name":14,"slug":15,"type":16},{"name":1086,"slug":1087,"type":16},{"slug":1197,"name":1197,"fn":1198,"description":1199,"org":1200,"tags":1201,"stars":26,"repoUrl":27,"updatedAt":1205},"sample-app-guide","build wearable apps with camera streaming","Building a complete DAT app with camera streaming and photo capture",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1202,1203,1204],{"name":21,"slug":22,"type":16},{"name":14,"slug":15,"type":16},{"name":1008,"slug":1009,"type":16},"2026-05-15T06:14:36.185947",{"slug":1207,"name":1207,"fn":1208,"description":1209,"org":1210,"tags":1211,"stars":26,"repoUrl":27,"updatedAt":1218},"session-lifecycle","monitor device session lifecycle states","Device session states, pause\u002Fresume, availability monitoring",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1212,1213,1214,1217],{"name":14,"slug":15,"type":16},{"name":1008,"slug":1009,"type":16},{"name":1215,"slug":1216,"type":16},"Monitoring","monitoring",{"name":1122,"slug":1123,"type":16},"2026-05-15T06:14:44.790925",27]