### Instantiate and Configure TcpServer Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.LensStudio_Network.BaseServer.html This example shows how to create a TcpServer, connect to its onConnect and onError signals, and start it listening on a local address. Use this to set up basic network server functionality. ```javascript // BaseServer is the base class for network servers. Use TcpServer as a // concrete subclass to demonstrate listen(), close(), onConnect, onError. const server = TcpServer.create(); this.server = server; this.connections.push( server.onConnect.connect((socket) => { console.log('Client connected from:', socket.remoteAddress.address); }) ); this.connections.push( server.onError.connect((code: number) => { console.log('Server error code:', code); }) ); const addr = new Address(); addr.address = '127.0.0.1'; addr.port = 0; const ok = server.listen(addr); console.log('Server listening:', ok, 'on port:', server.port); ``` -------------------------------- ### Create and Use a File System Watcher Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.LensStudio_FileSystem.Watcher.html This example demonstrates how to create a Watcher instance for a project's assets directory, connect to its signals for file events (added, modified, removed, moved), and start the watching process. It logs events to the console and shows how to check if the watcher is active and its monitored path. ```javascript // Watcher monitors a filesystem path for additions, modifications, moves, // and removals. Create one via the static Watcher.create(path) method, // connect to its signals, then call start() to begin watching. const { Watcher } = await import('LensStudio:FileSystem'); const model = this.pluginSystem.findInterface(Editor.Model.IModel) as Editor.Model.IModel; const assetsDir = model.project.assetsDirectory; // Create a watcher on the project's assets directory const watcher = Watcher.create(assetsDir); console.log('Watcher created for path:', assetsDir.toString()); // Connect to file-change signals this.connections.push( watcher.onAdded.connect((path: Editor.Path) => { console.log('File added:', path.toString()); }) ); this.connections.push( watcher.onModified.connect((path: Editor.Path) => { console.log('File modified:', path.toString()); }) ); this.connections.push( watcher.onRemoved.connect((path: Editor.Path) => { console.log('File removed:', path.toString()); }) ); this.connections.push( watcher.onMoved.connect((oldPath: Editor.Path, newPath: Editor.Path) => { console.log('File moved from', oldPath.toString(), 'to', newPath.toString()); }) ); // Start watching watcher.start(); console.log('Watcher is active:', watcher.isWatching); console.log('Watcher path:', watcher.path.toString()); ``` -------------------------------- ### CoreService Lifecycle and Plugin Integration Example Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.LensStudio_CoreService.CoreService.html Demonstrates how to implement start() and stop() methods in a CoreService subclass to manage event connections and interact with the plugin system. Use this to set up and tear down service-specific logic and resources. ```javascript // CoreService manages its lifecycle through start() and stop(). // In start(), connect to signals and store the connections. // In stop(), disconnect them to avoid leaks. const model = this.pluginSystem.findInterface(Editor.Model.IModel) as Editor.Model.IModel; const conn = model.onProjectChanged.connect(() => { console.log('Project changed — new project loaded'); }); this.connections.push(conn); console.log(`Connected to model.onProjectChanged signal`); const scene = model.project.scene; const so = scene.createSceneObject('CoreServiceDemo'); console.log(`Created scene object: ${so.name}`); ``` -------------------------------- ### Cloud Storage Operations Example Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Built-In.CloudStorageModule.html Demonstrates how to get a cloud store, set a value, and list stored values. Use this for implementing persistent user data storage. ```javascript const cloudStorageOptions = CloudStorageOptions.create(); script.cloudStorageModule.getCloudStore( cloudStorageOptions, onCloudStoreReady, onError ); function onCloudStoreReady(store) { const writeOptions = CloudStorageWriteOptions.create(); writeOptions.scope = StorageScope.User; store.setValue( "myKey", "myValue", writeOptions, function onSuccess() { print("Stored Succesfully!"); const listOptions = CloudStorageListOptions.create(); listOptions.scope = StorageScope.User; store.listValues( listOptions, function(results, cursor) { for (var i = 0; i < results.length; ++i) { var key = results[i][0]; var value = results[i][1]; print(' - key: ' + key + ' value: ' + value); } }, onError ); }, onError ); } function onError(code, message) { print('Error: ' + code + ' ' + message); } ``` -------------------------------- ### Example Preset Implementation Source: https://developers.snap.com/lens-studio/api/editor-scripting/modules/Editor_Scripting.LensStudio_Preset.html An example demonstrating how to extend the Preset class to create a custom 'Empty Object Preset'. ```APIDOC ## Example Preset Implementation ### Description This example shows how to implement a custom preset that creates an empty scene object. ### Class: PresetModuleExamplePreset ```javascript export class PresetModuleExamplePreset extends Preset { connections: any[]; static descriptor() { const d = new Descriptor(); d.id = 'com.docs.PresetModuleExample'; d.name = 'Empty Object Preset'; d.description = 'Creates an empty scene object'; d.entityType = 'SceneObject'; d.section = 'Examples'; d.dependencies = [Editor.Model.IModel]; return d; } constructor(pluginSystem: Editor.PluginSystem, descriptor?: Descriptor) { super(pluginSystem, descriptor); this.connections = []; } async createAsync(destination: Editor.Model.SceneObject | Editor.Path): Promise { const model = this.pluginSystem.findInterface(Editor.Model.IModel) as unknown as Editor.Model.IModel; const scene = model.project.scene; const obj = scene.addSceneObject(destination as Editor.Model.SceneObject); obj.name = 'Example Preset Object'; return obj; } } ``` ``` -------------------------------- ### VideoRecorder Initialization and Usage Example Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Built-In.VideoRecorder.html This script demonstrates how to initialize and use the VideoRecorder to record a texture. It includes component validation, starting and stopping recording via touch events, and handling the resulting texture. Ensure the 'displayImage' component is assigned in the Inspector and a 'Render Target' asset is available. ```javascript // @input Component.Image displayImage let target = requireAsset("./Render Target.renderTarget"); let recorder = null; let isRecording = false; let isProcessingStop = false; // Function to validate components function validateComponents() { print("=== Component Validation ==="); if (!target) { print("ERROR: Render Target asset is null or undefined"); return false; } print("✓ Render Target asset loaded"); if (!script.displayImage) { print("ERROR: displayImage component is not assigned in Inspector"); return false; } print("✓ displayImage component found"); if (!script.displayImage.mainMaterial) { print("ERROR: displayImage.mainMaterial is null"); return false; } print("✓ displayImage.mainMaterial found"); if (!script.displayImage.mainMaterial.mainPass) { print("ERROR: displayImage.mainMaterial.mainPass is null"); return false; } print("✓ displayImage.mainMaterial.mainPass found"); print("=== All components validated successfully ==="); return true; } // Function to cleanup and reset recorder function cleanupRecorder() { try { if (recorder) { // Cancel any ongoing recording if (isRecording) { recorder.cancelRecording(); print("Recording cancelled during cleanup"); } recorder = null; } isRecording = false; isProcessingStop = false; print("Recorder cleaned up successfully"); } catch (error) { print("Error during cleanup: " + error); } } // Function to initialize VideoRecorder function initializeRecorder() { try { // Clean up any existing recorder first cleanupRecorder(); if (!validateComponents()) { print("ERROR: Component validation failed - cannot initialize VideoRecorder"); return false; } // Set up a new VideoRecorder instance const options = new VideoRecorder.Options(target); options.saveThumbnail = true; recorder = VideoRecorder.create(options); print("VideoRecorder initialized successfully"); return true; } catch (error) { print("Error initializing VideoRecorder: " + error); cleanupRecorder(); return false; } } // Initialize the recorder if (!initializeRecorder()) { print("FATAL: Cannot initialize VideoRecorder - script will not function"); } // Start recording script.createEvent("TouchStartEvent").bind(function(eventData) { if (!recorder) { print("VideoRecorder not initialized - attempting to reinitialize"); if (!initializeRecorder()) { print("Failed to reinitialize VideoRecorder"); return; } } if (isRecording) { print("Already recording, ignoring start request"); return; } if (isProcessingStop) { print("Still processing previous stop, ignoring start request"); return; } try { recorder.startRecording(); isRecording = true; print("Recording started"); } catch (error) { print("Error starting recording: " + error); isRecording = false; } }); // Stop recording and display the result script.createEvent("TouchEndEvent").bind(function(eventData) { if (!recorder) { print("VideoRecorder not initialized"); return; } if (!isRecording) { print("Not recording, ignoring stop request"); return; } if (isProcessingStop) { print("Already processing stop, ignoring request"); return; } try { print("Attempting to stop recording..."); isProcessingStop = true; // Fixed: properly handle the Promise returned by stopRecording() recorder.stopRecording().then(function(texture) { print("stopRecording() promise resolved"); // Debug the texture if (!texture) { print("ERROR: stopRecording() returned null/undefined texture"); print("This might indicate the recording was too short or failed"); isRecording = false; isProcessingStop = false; return; } print("✓ Texture received from stopRecording()") print("Texture type: " + typeof texture); // Re-validate components before assignment ``` -------------------------------- ### start Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Built-In.AnimationMixer.html Starts playing specified animation layers with customizable offset, and number of cycles. ```APIDOC ## start ### Description Starts playing animation layers named `name`, or all layers if `name` is empty. The animation will start with an offset of `offset` seconds. The animation will play `cycles` times, or loop forever if `cycles` is -1. ### Parameters #### Path Parameters * **name** (string) - Optional - The name of the animation layer(s) to start. If empty, all layers are started. * **offset** (number) - Required - The time in seconds at which to start the animation. * **cycles** (number) - Required - The number of times the animation should play. Use -1 for infinite looping. ### Returns void ``` -------------------------------- ### Visual Component Example Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.Editor.Components.Visual.html Example demonstrating how to create a scene object, add a RenderMeshVisual component, and set its renderOrder. ```APIDOC ## Example Usage ```javascript const model = this.pluginSystem.findInterface(Editor.Model.IModel) as Editor.Model.IModel; const scene = model.project.scene; const obj = scene.createSceneObject('VisualObj'); const rmv = obj.addComponent('RenderMeshVisual') as Editor.Components.RenderMeshVisual; rmv.renderOrder = 5; console.log(`Visual (RenderMeshVisual): renderOrder=${rmv.renderOrder}`); ``` ``` -------------------------------- ### AsrModule Transcription Example Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Built-In.AsrModule.html Demonstrates how to use the AsrModule to start and stop voice transcription sessions. Includes setup for transcription options, error handling, and update callbacks. ```javascript const asrModule = require("LensStudio:AsrModule"); function onTranscriptionError(errorCode) { print(`onTranscriptionErrorCallback errorCode: ${errorCode}`); switch (errorCode) { case AsrModule.AsrStatusCode.InternalError: print("stopTranscribing: Internal Error"); break; case AsrModule.AsrStatusCode.Unauthenticated: print("stopTranscribing: Unauthenticated"); break; case AsrModule.AsrStatusCode.NoInternet: print("stopTranscribing: No Internet"); break; } } function onTranscriptionUpdate(eventArgs) { var text = eventArgs.text; var isFinal = eventArgs.isFinal; print(`onTranscriptionUpdateCallback text=${text}, isFinal=${isFinal}`) } function startSession() { var options = AsrModule.AsrTranscriptionOptions.create(); options.silenceUntilTerminationMs = 1000; options.mode = AsrModule.AsrMode.HighAccuracy; options.onTranscriptionUpdateEvent.add(onTranscriptionUpdateCallback); options.onTranscriptionErrorEvent.add(onTranscriptionErrorCallback); // Start session asrModule.startTranscribing(options); } function stopSession() { asrModule .stopTranscribing() .then(function () { print( `stopTranscribing successfully` ); }); } ``` -------------------------------- ### CommerceKitModule Initialization and Example Usage Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Built-In.CommerceKitModule.html Demonstrates how to initialize the CommerceKitModule client, connect to the commerce service, query products, check purchase status, and launch a purchase flow. Includes error handling and connection closing. ```javascript const purchaseResult = await client.launchPurchaseFlow(productId); print(`Purchase flow completed with response code: ${purchaseResult.responseCode}`); if (purchaseResult.responseCode === Commerce.ResponseCode.Success) { print('Purchase flow was launched successfully.'); } } catch (error) { print('Error in purchase process: ' + error); } } // Example invocation of the various scenarios async function example() { try { // Initialize the commerce client print('Initializing commerce client...'); const clientOptions = new Commerce.ClientOptions(onPurchasesUpdated); client = module.createClient(clientOptions); await client.startConnection(); print('Connected to commerce service.'); const productIds = ['com.snap.product1', 'com.snap.product2', 'com.snap.product3', 'com.snap.newProduct1']; await updatePurchaseStatusCache(productIds); await demoQueryProducts(); demoCheckPurchaseStatus('com.snap.product1'); // Check from cache (no query needed) await demoLaunchPurchaseFlow('com.snap.newProduct1'); // Launch purchase flow demoCheckPurchaseStatus('com.snap.newProduct1'); // Check from cache (automatically updated via callback) } catch (error) { print('Error in commerce operations: ' + error); } finally { if (client) { client.endConnection(); print('Commerce client connection closed.'); } } } example(); ``` -------------------------------- ### Configure Entity Rotation Inversion Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.Editor.Components.RotationOptions.html This example demonstrates how to access and modify the `invertRotation` property of a `RotationOptions` component. It shows the setup required to get the component and then sets the property to true, logging the change. ```typescript const model = this.pluginSystem.findInterface(Editor.Model.IModel) as Editor.Model.IModel; const scene = model.project.scene; const obj = scene.createSceneObject('TrackerObj'); const dt = obj.addComponent('DeviceTracking') as Editor.Components.DeviceTracking; const rotOpts = dt.rotationOptions; rotOpts.invertRotation = true; console.log(`RotationOptions: invertRotation=${rotOpts.invertRotation}`); ``` -------------------------------- ### Get and Display Friend Info Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Built-In.SnapchatFriendUserInfo.html This example demonstrates how to fetch all friends of the active user and then iterate through them to display their display name, friendship start date, and last interaction time. It uses async/await for handling promises returned by the getAllFriends function. ```javascript async function getFriends() { return new Promise(function (resolve, reject) { global.userContextSystem.getAllFriends(function (friends) { resolve(friends); }); }); } async function init(){ let friends = await getFriends(); friends.forEach(f => { let friendshipStartDate = f.friendInfo.friendshipStart; let lastInteractionTime = f.friendInfo.lastInteractionTime; print(`Friendship with ${f.displayName} started on ${friendshipStartDate}, last interacted on ${lastInteractionTime}`) }); } init(); ``` -------------------------------- ### Creating and Configuring an Address Instance Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.LensStudio_Network.Address.html Demonstrates how to create an Address instance, set its host and port properties, and update them. Use this to specify where a TCP server should bind. ```javascript const { Address } = await import('LensStudio:Network'); const addr = new Address(); addr.address = '127.0.0.1'; addr.port = 8080; console.log('Created Address instance'); console.log(' address:', addr.address); console.log(' port:', addr.port); // Change to a different binding addr.address = '0.0.0.0'; addr.port = 3000; console.log('Updated Address to', addr.address + ':' + addr.port); ``` -------------------------------- ### Start Width Property Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Packages_SpectaclesInteractionKit_Components_Interaction_InteractorLineVisual_InteractorLineRenderer.InteractorLineRenderer.html Allows you to get or set the width of the line at its starting point. ```APIDOC ## startWidth ### Description Gets or sets the width of the line at the start. ### Getter - **startWidth**: number - Returns the current width of the line's start. ### Setter - **startWidth**(newWidth: number): void - Sets the width of the line's start. - **Parameters**: - newWidth (number): The new width for the line's start. ``` -------------------------------- ### Create and Listen with WebSocketServer Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.LensStudio_WebSocket.WebSocketServer.html Demonstrates how to create a WebSocket server, handle client connections and data, and start listening on a specific address and port. ```javascript const WS = await import('LensStudio:WebSocket'); const Network = await import('LensStudio:Network'); const server = WS.WebSocketServer.create(); this.connections.push( server.onConnect.connect((clientSocket) => { console.log(`Client connected from ${clientSocket.remoteAddress.address}`); clientSocket.onData.connect((data) => { console.log(`Server received: ${data.toString()}`); }); }) ); const addr = new Network.Address(); addr.address = '127.0.0.1'; addr.port = 9090; const listening = server.listen(addr); console.log(`WebSocketServer listening on ${server.address}: ${listening}`); ``` -------------------------------- ### Get Hand Velocity in a Script Component Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Built-In.ObjectTracking3D.html This example demonstrates how to get hand velocity within a Script Component, utilizing objectSpecificData and handling editor-specific conditions. ```typescript @component export class NewScript extends BaseScriptComponent { @input objectTracking3D: ObjectTracking3D; onAwake() { this.createEvent("UpdateEvent").bind(() => { this.getHandVelocity(); }); } getHandVelocity() { // In Lens Studio we do not have the objectSpecificData we need. if (global.deviceInfoSystem.isEditor()) { return new vec3(0, 1, -35); } // Each ObjectTracking3D Component might provide their own specific data let objectSpecificData = this.objectTracking3D.objectSpecificData; if (objectSpecificData) { let handVelocity = objectSpecificData["global"]; let fingerVelocity = objectSpecificData["index-3"]; print("Hand Velocity: " + handVelocity); print("Finger Velocity: " + fingerVelocity); return handVelocity; } else { return vec3.zero(); } } } ``` -------------------------------- ### Example Preset Class Implementation Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.LensStudio_Preset.Preset.html Demonstrates how to extend the base Preset class to create a custom light rig preset. This includes defining the descriptor and implementing the asynchronous creation logic. ```typescript export class PresetClassExamplePreset extends Preset { connections: any[]; static descriptor() { const d = new Descriptor(); d.id = 'com.docs.PresetClassExample'; d.name = 'Light Rig Preset'; d.description = 'Creates a scene object configured as a light rig'; d.entityType = 'SceneObject'; d.section = 'Lighting'; d.dependencies = [Editor.Model.IModel]; return d; } constructor(pluginSystem: Editor.PluginSystem, descriptor?: Descriptor) { super(pluginSystem, descriptor); this.connections = []; } async createAsync(destination: Editor.Model.SceneObject | Editor.Path): Promise { const model = this.pluginSystem.findInterface(Editor.Model.IModel) as unknown as Editor.Model.IModel; const scene = model.project.scene; const rig = scene.addSceneObject(destination as Editor.Model.SceneObject); rig.name = 'Light Rig'; return rig; } } ``` -------------------------------- ### getBoundingBox Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Built-In.Text.html Gets the bounding box encompassing characters in a specified range. The range is inclusive of the start and exclusive of the end. Supports optional start and end parameters. ```APIDOC ## getBoundingBox ### Description Gets the bounding box encompassing the characters in the range from `start` to `end`. The range is inclusive of `start` and exclusive of `end`. ### Method `getBoundingBox(start?: number, end?: number): Rect` ### Parameters #### Optional Parameters - **start** (number) - The starting index of the range (inclusive). - **end** (number) - The ending index of the range (exclusive). ### Returns `Rect` - The bounding box of the specified text range. ### Since Lens Scripting Version 316 ``` -------------------------------- ### Create and Configure EnvironmentSetting Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.LensStudio_AssetLibrary.EnvironmentSetting.html Demonstrates how to create an EnvironmentSetting instance, set its environment to Production and space to Public, and use it with AssetListRequest. ```javascript // EnvironmentSetting configures which Asset Library backend to query. // It has a public constructor and two writable properties. const setting = new EnvironmentSetting(); setting.environment = Environment.Production; setting.space = Space.Public; console.log('Environment:', setting.environment, '(Production)'); console.log('Space:', setting.space, '(Public)'); // Use EnvironmentSetting with AssetListRequest to query the library const { AssetFilter, AssetListRequest, Pagination } = await import('LensStudio:AssetLibrary'); const filter = new AssetFilter(); filter.pagination = Pagination.singleBatch(0, 10); const request = new AssetListRequest(setting, filter); console.log('Request created with environment setting'); console.log('Filter pagination limit:', request.assetFilter.pagination.limit); ``` -------------------------------- ### TextCursor Panel Example Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.LensStudio_Ui.TextCursor.html Demonstrates how to use TextCursor to select all text or move the cursor to the start within a TextEdit widget. This example shows practical application of TextCursor.MoveOperation and TextCursor.MoveMode. ```typescript export class TextCursorPanel extends PanelPlugin { connections: any[]; static descriptor() { const d = new Descriptor(); d.id = 'com.docs.UiTextCursorExample'; d.name = 'TextCursor Example'; d.defaultDockState = DockState.Detached; d.defaultSize = new Size(400, 300); return d; } constructor(pluginSystem: Editor.PluginSystem, descriptor?: Descriptor) { super(pluginSystem, descriptor); this.connections = []; } createWidget(parent: Widget): Widget { const root = new Widget(parent); const layout = new BoxLayout(); layout.setDirection(Direction.TopToBottom); layout.spacing = 8; root.layout = layout; const title = new Label(root); title.text = 'TextCursor Demo'; title.fontRole = FontRole.TitleBold; layout.addWidget(title); const edit = new TextEdit(root); edit.plainText = 'Hello World\nSecond line\nThird line'; layout.addWidget(edit); const selectAllBtn = new PushButton(root); selectAllBtn.text = 'Select All (Start -> End with KeepAnchor)'; layout.addWidget(selectAllBtn); const moveStartBtn = new PushButton(root); moveStartBtn.text = 'Move to Start'; layout.addWidget(moveStartBtn); this.connections.push( selectAllBtn.onClick.connect(() => { // TextCursor.movePosition navigates within the text const cursor = edit.textCursor; cursor.movePosition(TextCursor.MoveOperation.Start, TextCursor.MoveMode.MoveAnchor); cursor.movePosition(TextCursor.MoveOperation.End, TextCursor.MoveMode.KeepAnchor); edit.textCursor = cursor; }), moveStartBtn.onClick.connect(() => { const cursor = edit.textCursor; cursor.movePosition(TextCursor.MoveOperation.Start, TextCursor.MoveMode.MoveAnchor); edit.textCursor = cursor; }) ); return root; } deinit(): void { this.connections.forEach((c: any) => c?.disconnect()); this.connections = []; } } ``` -------------------------------- ### Count Native Packages with Setup Scripts Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.Editor.Assets.SetupScript.html This example demonstrates how to iterate through native package descriptors, check for the presence and content of their setup scripts, and count those that have a non-empty setup script. It requires access to the Editor's plugin system and asset manager. ```typescript const model = this.pluginSystem.findInterface(Editor.Model.IModel) as Editor.Model.IModel; const assetManager = model.project.assetManager; const packages = assetManager.assets.filter( (a) => a.isOfType('NativePackageDescriptor') ) as Editor.Assets.NativePackageDescriptor[]; // Count how many packages have a non-empty setupScript let withScript = 0; for (const pkg of packages) { const setupScript = pkg.setupScript; if (!Editor.isNull(setupScript) && setupScript.code.length > 0) { withScript++; } } console.log(`NativePackageDescriptors: ${packages.length} total, ${withScript} with setupScript`); ``` -------------------------------- ### gradientStartPosition Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Packages_SpectaclesUIKit_Scripts_Visuals_RoundedRectangle_RoundedRectangle.RoundedRectangle.html Gets or sets the start position of the background gradient. This defines the range for gradient stops. ```APIDOC ## gradientStartPosition ### Description Gets or sets the start position of the background gradient. ### Getter * **gradientStartPosition()**: vec2 - Returns the current background gradient start position. ### Setter * **gradientStartPosition(position: vec2)**: void - Sets the background gradient start position. * **position** (vec2) - The new gradient start position. ``` -------------------------------- ### borderGradientStartPosition Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Packages_SpectaclesUIKit_Scripts_Visuals_RoundedRectangle_RoundedRectangle.RoundedRectangle.html Gets or sets the start position of the border gradient. This defines the range for gradient stops. ```APIDOC ## borderGradientStartPosition ### Description Gets or sets the start position of the border gradient. ### Getter * **borderGradientStartPosition()**: vec2 - Returns the current border gradient start position. ### Setter * **borderGradientStartPosition(position: vec2)**: void - Sets the border gradient start position. * **position** (vec2) - The new gradient start position. ``` -------------------------------- ### Create and Use a Color Instance Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.LensStudio_Ui.Color.html Demonstrates how to import the Ui module, create a new Color instance, set its RGBA components, and log the values. Ensure the Ui module is imported before use. ```javascript const Ui = await import('LensStudio:Ui'); // Color holds RGBA components (0-1 range) const color = new Ui.Color(); color.red = 0.9; color.green = 0.3; color.blue = 0.1; color.alpha = 1.0; console.log('Color red:', color.red); console.log('Color green:', color.green); console.log('Color blue:', color.blue); console.log('Color alpha:', color.alpha); ``` -------------------------------- ### triggerStartAudioComponent Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Packages_SpectaclesInteractionKit_Components_Helpers_InteractableAudioFeedback.InteractableAudioFeedback.html Gets the AudioComponent used for trigger start feedback. This allows for further configuration, such as adjusting the volume. ```APIDOC ## triggerStartAudioComponent ### Description Gets the AudioComponent used for trigger start feedback for further configuration (such as volume). ### Returns AudioComponent ``` -------------------------------- ### Create and Configure an ImageView Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.LensStudio_Ui.ImageView.html Demonstrates how to create a root widget, set up a layout, add a label, and then create and configure an ImageView with properties like scaledContents, radius, and hover response. It also shows how to connect to the onClick signal and log property values. ```javascript const root = new Widget(parent); const layout = new BoxLayout(); layout.setDirection(Direction.TopToBottom); layout.spacing = 8; root.layout = layout; const title = new Label(root); title.text = 'ImageView Demo'; title.fontRole = FontRole.Title; layout.addWidget(title); // ImageView displays a pixmap image const imageView = new ImageView(root); imageView.scaledContents = true; imageView.radius = 8; imageView.responseHover = true; layout.addWidget(imageView); const conn = imageView.onClick.connect(() => { console.log('ImageView clicked'); }); this.connections.push(conn); console.log('ImageView scaledContents:', imageView.scaledContents); console.log('ImageView radius:', imageView.radius); ``` -------------------------------- ### Create ScopedStorage Instances (Constructor Example) Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.LensStudio_ScopedStorage.js.ScopedStorage.html Illustrates creating ScopedStorage instances, either using the default temporary directory or a user-specified path. ```javascript const tempStorage = new ScopedStorage(); const customStorage = new ScopedStorage('/path/to/directory'); ``` -------------------------------- ### GuiService Class Example Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.LensStudio_GuiService.GuiService.html Demonstrates how to extend the GuiService class to create a GUI-aware editor plugin with start and stop lifecycle methods. This example shows initialization of GUI components and access to the project scene. ```typescript export class GuiServiceClassExampleService extends GuiService { connections: any[]; static descriptor() { const d = new Descriptor(); d.id = 'com.docs.GuiServiceClassExample'; d.name = 'GuiService Class Example'; d.description = 'Demonstrates GuiService class with start/stop lifecycle'; d.dependencies = [Editor.Model.IModel]; return d; } constructor(pluginSystem: Editor.PluginSystem, descriptor?: Descriptor) { super(pluginSystem, descriptor); this.connections = []; } start(): void { const model = this.pluginSystem.findInterface(Editor.Model.IModel) as unknown as Editor.Model.IModel; const scene = model.project.scene; console.log('GuiService started'); console.log(`Scene has ${scene.rootSceneObjects.length} root object(s)`) } stop(): void { this.connections.forEach((c: any) => c?.disconnect()); this.connections = []; } } ``` -------------------------------- ### scalingSizeStart Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Packages_SpectaclesUIKit_Scripts_Components_Frame_Frame.Frame.html Controls the initial scaling size of the frame. Allows getting and setting the starting scale dimensions. ```APIDOC ## scalingSizeStart ### Description Controls the initial scaling size of the frame. Allows getting and setting the starting scale dimensions. ### Getter * **scalingSizeStart**(): vec2 - Gets the initial scaling size. ### Setter * **scalingSizeStart**(thisSize: vec2): void - Sets the initial scaling size. * **Parameters**: * **thisSize** (vec2) - The desired initial scaling size. ``` -------------------------------- ### Example Usage Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.Editor.Assets.ImageMarker.html Demonstrates how to create an ImageMarker asset, prompt the user to select an image file, and assign it as the marker's texture. ```APIDOC #### Example ``` // Create the asset const imageMarker = assetManager.createNativeAsset('ImageMarker', 'Image Marker [EDIT_ME]', destination); // Ask user for the file they want to use as image marker import * as Ui from 'LensStudio:Ui'; const gui = pluginSystem.findInterface(Ui.IGui); const filename = gui.dialogs.selectFileToOpen({ 'caption': 'Select image for the marker', 'filter': '*.png *.jpeg *.jpg' }, '') // Import the image, and use it as the marker's texture const importedTextureMeta = await assetManager.importExternalFileAsync(filename, destination, Editor.Model.ResultType.Auto); imageMarker.texture = importedTextureMeta.primary; ``` ``` -------------------------------- ### Handling Pan Gesture Start Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Built-In.PanGestureStartEvent.html This example demonstrates how to bind a callback function to the PanGestureStartEvent to capture translation and touch data when a pan gesture starts. Use this to react to the beginning of a user's swipe motion. ```javascript function onPanStart(eventData) { var translation = eventData.getTranslation(); var touches = eventData.getTouches(); } var ev = script.createEvent("PanGestureStartEvent"); ev.bind(onPanStart); ``` -------------------------------- ### Instantiate and Use SourcePath Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.Editor.Model.SourcePath.html Demonstrates how to create a SourcePath instance and access its various properties and methods. Use this to understand the different path representations and utilities available. ```javascript const sp = new Editor.Model.SourcePath( new Editor.Path('Textures/logo.png'), Editor.Model.SourceRootDirectory.Assets ); console.log(`toString: ${sp.toString()}`); console.log(`extension: ${sp.extension}`); console.log(`fileName: ${sp.fileName}`); console.log(`fileNameBase: ${sp.fileNameBase}`); console.log(`isEmpty: ${sp.isEmpty}`); console.log(`parent: ${sp.parent}`); console.log(`relativeToProject: ${sp.relativeToProject}`); console.log(`relativeToRoot: ${sp.relativeToRoot}`); console.log(`rootDirectory: ${sp.rootDirectory}`); console.log(`hasExtension('.png'): ${sp.hasExtension('.png')}`); console.log(`hasExtension('.jpg'): ${sp.hasExtension('.jpg')}`); const replaced = sp.replaceFileNameBase('icon'); console.log(`After replaceFileNameBase('icon'): ${replaced.toString()}`); ``` -------------------------------- ### Create and Configure a ProgressBar Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.LensStudio_Ui.ProgressBar.html This example demonstrates how to create a root widget, set up a vertical layout, add a label to display progress text, and then create a ProgressBar widget. It shows how to set the minimum and maximum range of the progress bar and update its current value. ```javascript const root = new Widget(parent); const layout = new BoxLayout(); layout.setDirection(Direction.TopToBottom); layout.spacing = 8; root.layout = layout; const label = new Label(root); label.text = 'Export Progress: 75%'; label.fontRole = FontRole.Title; layout.addWidget(label); // ProgressBar with range and value const progress = new ProgressBar(root); progress.setRange(0, 100); progress.value = 75; layout.addWidget(progress); ``` -------------------------------- ### Checking if Screen Point is Contained Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Built-In.ScreenTransform.html Example demonstrating how to check if a touch event starts within the bounds of a ScreenTransform. ```APIDOC ## Check Screen Point Containment ### Description This example checks if a touch event's screen point falls within the ScreenTransform's boundaries. ### Method ```javascript // @input Component.ScreenTransform screenTransform script.createEvent("TouchStartEvent").bind(function(eventData) { var touchPos = eventData.getTouchPosition(); if (script.screenTransform.containsScreenPoint(touchPos)) { print("contains screen point!"); } }); ``` ``` -------------------------------- ### CommerceKitModule Usage Example Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Built-In.CommerceKitModule.html This example demonstrates how to initialize the CommerceKitModule, query product details, check purchase status, and handle purchase flows. ```APIDOC ## CommerceKitModule The main entry point for integrating commerce functionalities into a Lens. It is typically added as an Asset in a Lens Studio project. This module provides access to the primary method for configuring and creating a Client object, which is used for all in-Lens purchase and product management needs. This module allows a Lens to interact with the commerce system, enabling features like displaying products, initiating purchases, and managing user entitlements. ### Example Usage ```javascript let module = require("LensStudio:CommerceKitModule"); // Declare client variable and purchase status cache let client = module.getClient(); // Assuming getClient() is the method to get the client let purchaseStatusCache = new Map(); // Helper function to print important product fields manually function printProductDetails(product) { console.log(` ID: ${product.id}, Name: ${product.displayName}, Price: ${product.price?.displayPrice || product.price?.price}`); } // Function to update the purchase status cache from purchase history async function updatePurchaseStatusCache(productIds) { try { const purchaseHistory = await client.queryPurchaseHistory(); productIds.forEach(productId => { const purchase = purchaseHistory.find(p => p.productId === productId); if (purchase) { purchaseStatusCache.set(productId, purchase.purchaseState); console.log("Purchase state of " + productId + ", purchased:" + (purchase.purchaseState === Commerce.PurchaseState.Purchased)); } else { purchaseStatusCache.set(productId, Commerce.PurchaseState.Unset); console.log("No purchase record found for product ID: " + productId); } }); } catch (error) { console.error('Error updating purchase status cache: ' + error); } } // Function to handle processing of a successful purchase. function processPurchase(purchase) { console.log(`Processing purchase for product: ${purchase.productId}, state: ${purchase.purchaseState}`); // Only acknowledge purchases that are in Purchased state if (purchase.purchaseState === Commerce.PurchaseState.Purchased || purchase.purchaseState === Commerce.PurchaseState.Pending) { client.acknowledgePurchase(purchase.token).then(() => { console.log(`Purchase for ${purchase.productId} acknowledged.`); }).catch(error => { console.error('Failed to acknowledge purchase: ' + error); }); } else { console.log(`Purchase for ${purchase.productId} is not in Purchased state, skipping acknowledgment.`); } } // Function to handle purchase status updates. const onPurchasesUpdated = (result, purchases) => { if (result.responseCode === Commerce.ResponseCode.Success && purchases.length > 0) { purchases.forEach(purchase => { console.log(`Successfully purchased: ${purchase.productId}`); processPurchase(purchase); }); } else if (result.responseCode === Commerce.ResponseCode.UserCanceled) { console.log('Purchase was cancelled.'); } else { console.log('Purchase failed or was not acknowledged.'); } // Update the status cache after processing purchases const productIds = ['com.snap.product1', 'com.snap.product2', 'com.snap.product3', 'com.snap.newProduct1']; updatePurchaseStatusCache(productIds); }; // Register the listener for purchase updates client.on('purchasesUpdated', onPurchasesUpdated); // Scenario: Query available product details. async function demoQueryProducts() { try { const productIds = ['com.snap.product1', 'com.snap.product2', 'com.snap.product3']; const products = await client.queryProductDetails(productIds); if (products && products.length > 0) { console.log('Available products:'); products.forEach((product) => { printProductDetails(product); }); } else { console.log('No products found'); } } catch (error) { console.error('Error during product query: ' + error); } } // Scenario: Check purchase status for a specific product (using cache). function demoCheckPurchaseStatus(productId) { const purchaseState = purchaseStatusCache.get(productId); if (purchaseState === undefined) { console.log(`Product '${productId}' not found in cache. Initialize cache first.`); return; } switch (purchaseState) { case Commerce.PurchaseState.Purchased: console.log(`Product '${productId}' has been purchased.`); break; case Commerce.PurchaseState.Unset: console.log(`Product '${productId}' has not been purchased.`); break; default: console.log(`Product '${productId}' purchase state: ${purchaseState}`); } } // Scenario: Launch purchase flow for a product. async function demoLaunchPurchaseFlow(productId) { try { // Assuming launchPurchaseFlow is a method of the client const purchase = await client.launchPurchaseFlow(productId); console.log(`Purchase flow launched for ${productId}.`); // The onPurchasesUpdated callback will handle the result } catch (error) { console.error('Error launching purchase flow: ' + error); } } // Initialize the cache with some product IDs const initialProductIds = ['com.snap.product1', 'com.snap.product2', 'com.snap.product3']; updatePurchaseStatusCache(initialProductIds); // Example calls: // demoQueryProducts(); // demoCheckPurchaseStatus('com.snap.product1'); // demoLaunchPurchaseFlow('com.snap.product1'); ``` ``` -------------------------------- ### VisualBoundariesProvider Methods Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Packages_SpectaclesInteractionKit_Components_UI_ScrollView_boundariesProvider_VisualBoundariesProvider.VisualBoundariesProvider.html Provides methods for creating screen transform boundaries, getting boundaries, and recomputing starting boundaries. ```APIDOC ## Methods ### `Protected` createScreenTransformRectBoundaries * **Description**: Computes Rect boundaries from a ScreenTransform. * **Parameters**: * **screenTransform** (ScreenTransform) - Required * **Returns**: Rect ### `Protected` getBoundaries * **Description**: Retrieves the computed boundaries. * **Returns**: Rect ### recomputeStartingBoundaries * **Description**: Recomputes the starting boundaries for the scene object. * **Returns**: void ``` -------------------------------- ### Creating and Configuring PushButtons Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.LensStudio_Ui.PushButton.html Demonstrates how to create a root widget, set up a layout, add a label to display status, and then create two PushButton instances: a standard one and a primary (accent-colored) one. It also shows how to connect onClick events to update the label's text based on button clicks. ```javascript const root = new Widget(parent); const layout = new BoxLayout(); layout.setDirection(Direction.TopToBottom); layout.spacing = 8; root.layout = layout; const status = new Label(root); status.text = 'Click count: 0'; status.fontRole = FontRole.Title; layout.addWidget(status); // Standard button const btn = new PushButton(root); btn.text = 'Increment'; layout.addWidget(btn); static count = 0; this.connections.push( btn.onClick.connect(() => { count++; status.text = `Click count: ${count}`; }) ); // Primary (accent-colored) button const primary = new PushButton(root); primary.text = 'Primary Action'; primary.primary = true; layout.addWidget(primary); this.connections.push( primary.onClick.connect(() => { status.text = 'Primary clicked!'; }) ); ``` -------------------------------- ### Get Package Metadata Source: https://developers.snap.com/lens-studio/api/editor-scripting/classes/Editor_Scripting.Editor.PackageMetadata.html Retrieves and logs metadata for the first library package found. This example demonstrates how to access the IPackageRegistry to get package details like name, asset ID, version, file count, and tags. ```typescript // PackageMetadata is returned by IPackageRegistry.packageMetadata(). const registry = this.pluginSystem.findInterface( Editor.IPackageRegistry.interfaceId ) as Editor.IPackageRegistry; const libPaths = registry.getLibraryPaths(); if (libPaths.length > 0) { const meta = registry.packageMetadata(libPaths[0]); console.log('Package name:', meta.name); console.log('Package assetId:', meta.assetId); console.log('Version:', `${meta.versionMajor}.${meta.versionMinor}.${meta.versionPatch}`); console.log('File count:', meta.filePaths.length); console.log('Tags:', meta.tags.join(', ')); } ``` -------------------------------- ### Create a Realtime Store with Options Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Built-In.RealtimeStoreCreateOptions.html Demonstrates how to create a realtime store with specified options, including ownership, persistence, and an initial data store. This is useful for setting up persistent or session-based data storage within a Lens experience. ```javascript // @input Asset.ConnectedLensModule connectedLensModule var options = ConnectedLensSessionOptions.create(); script.connectedLensModule.createSession(options) var initialStore = GeneralDataStore.create(); initialStore.putInt('state', 1); var options = RealtimeStoreCreateOptions.create(); options.ownership = RealtimeStoreCreateOptions.Ownership.Unowned; options.persistence = RealtimeStoreCreateOptions.Persistence.Session; options.initialStore = initialStore; session.createRealtimeStore(options, function onSuccess(store) { print('Store created! In On connected'); }, function onError(message) { print('Unable to create a store: ' + message) } ) ``` -------------------------------- ### SceneObjectBoundariesProvider Methods Source: https://developers.snap.com/lens-studio/api/lens-scripting/classes/Packages_SpectaclesInteractionKit_Components_UI_ScrollView_boundariesProvider_SceneObjectBoundariesProvider.SceneObjectBoundariesProvider.html Provides methods for creating screen transform rect boundaries, getting boundaries, and recomputing starting boundaries. ```APIDOC ## Methods ### `Protected`createScreenTransformRectBoundaries * createScreenTransformRectBoundaries(screenTransform: ScreenTransform): Rect #### Parameters * screenTransform: ScreenTransform #### Returns Rect ### `Protected` `Abstract`getBoundaries * getBoundaries(): Rect #### Returns Rect ### recomputeStartingBoundaries * recomputeStartingBoundaries(): void Recomputes starting boundaries #### Returns void ```