# Project export: ZoomersToBoomers

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 12.0
- Tagline: Ever hear someone say “67” and have no clue what it means? ZoomersToBoomers uses Snap Spectacles to catch and decode slang in real time so you can understand without awkwardly searching online :3
- Devpost: https://devpost.com/software/zoomerstoboomers
- GitHub: https://github.com/nopunindented-temp/ZoomerToBoomer
- Video: https://www.youtube.com/embed/N3HS8OZMRsQ?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 5 GitHub contributor(s) — nopunindented-temp (38 commits), crystal11111 (11 commits), Madeline LA (7 commits), nopunindented (6 commits), Seohyeon (3 commits)

## Devpost submission (written by the team)

### Inspiration

Ever hear someone say “67” and have no idea what it means? That was us. We realized slang often creates a communication gap between generations, especially for people like social workers who regularly interact across age groups.

### What it does

ZoomersToBoomers bridges generations by decoding slang in real time. Using Snap Spectacles, it listens, identifies slang, and provides clear explanations. It help users understand modern language trends and connect more naturally.

### How we built it

We built the prototype using Lens Studio, integrating it with Snap Spectacles to capture real-world conversations and visuals. The recorded speech is then processed through the Groq API, which identifies slang and generates a simple, real-time description displayed right beside the person speaking.

### What's next

We plan to: Expand slang recognition to more global languages and cultural contexts. Add interactive flashcards to help users learn slang playfully. Introduce achievement badges for mastering new expressions. Build a community-driven slang library that evolves with real world use.

## README (from the GitHub repository)

No README available.

## Detected evidence (automated analysis)

Indexed codebase: 124 recognized source files, 1477 KB.
- Go (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (120 of 509)

```
.gitignore
Agentic/.gitattributes
Agentic/.gitignore
Agentic/Agentic Playground.esproj
Agentic/Assets/AgeGroupButtons.ts
Agentic/Assets/AgeGroupButtons.ts.meta
Agentic/Assets/AgenticPlayground/Materials/Image 2.mat
Agentic/Assets/AgenticPlayground/Materials/Image 2.mat.meta
Agentic/Assets/AgenticPlayground/Materials/Image 3.mat
Agentic/Assets/AgenticPlayground/Materials/Image 3.mat.meta
Agentic/Assets/AgenticPlayground/Materials/Image 4.mat
Agentic/Assets/AgenticPlayground/Materials/Image 4.mat.meta
Agentic/Assets/AgenticPlayground/Materials/Image.mat
Agentic/Assets/AgenticPlayground/Materials/Image.mat.meta
Agentic/Assets/AgenticPlayground/Materials/ImageMat.mat
Agentic/Assets/AgenticPlayground/Materials/ImageMat.mat.meta
Agentic/Assets/AgenticPlayground/Materials/ImageMaterial.mat
Agentic/Assets/AgenticPlayground/Materials/ImageMaterial.mat.meta
Agentic/Assets/AgenticPlayground/Materials/Material.mat
Agentic/Assets/AgenticPlayground/Materials/Material.mat.meta
Agentic/Assets/AgenticPlayground/Materials/Material3DGEN.mat
Agentic/Assets/AgenticPlayground/Materials/Material3DGEN.mat.meta
Agentic/Assets/AgenticPlayground/Materials/PBR 2.mat
Agentic/Assets/AgenticPlayground/Materials/PBR 2.mat.meta
Agentic/Assets/AgenticPlayground/Materials/PBR.mat
Agentic/Assets/AgenticPlayground/Materials/PBR.mat.meta
Agentic/Assets/AgenticPlayground/Materials/Unlit.mat
Agentic/Assets/AgenticPlayground/Materials/Unlit.mat.meta
Agentic/Assets/AgenticPlayground/Prefabs/AgentNodeImageText.prefab
Agentic/Assets/AgenticPlayground/Prefabs/AgentNodeImageText.prefab.meta
Agentic/Assets/AgenticPlayground/Prefabs/AgentNodeModel.prefab
Agentic/Assets/AgenticPlayground/Prefabs/AgentNodeModel.prefab.meta
Agentic/Assets/AgenticPlayground/Prefabs/AgentNodeText.prefab
Agentic/Assets/AgenticPlayground/Prefabs/AgentNodeText.prefab.meta
Agentic/Assets/AgenticPlayground/Prefabs/Button.prefab
Agentic/Assets/AgenticPlayground/Prefabs/Button.prefab.meta
Agentic/Assets/AgenticPlayground/Prefabs/CardBot.prefab
Agentic/Assets/AgenticPlayground/Prefabs/CardBot.prefab.meta
Agentic/Assets/AgenticPlayground/Prefabs/CardStatic.prefab
Agentic/Assets/AgenticPlayground/Prefabs/CardStatic.prefab.meta
Agentic/Assets/AgenticPlayground/Prefabs/CardSummary.prefab
Agentic/Assets/AgenticPlayground/Prefabs/CardSummary.prefab.meta
Agentic/Assets/AgenticPlayground/Prefabs/CardSummaryHighlight.prefab
Agentic/Assets/AgenticPlayground/Prefabs/CardSummaryHighlight.prefab.meta
Agentic/Assets/AgenticPlayground/Prefabs/CardUser.prefab
Agentic/Assets/AgenticPlayground/Prefabs/CardUser.prefab.meta
Agentic/Assets/AgenticPlayground/Prefabs/Line.prefab
Agentic/Assets/AgenticPlayground/Prefabs/Line.prefab.meta
Agentic/Assets/AgenticPlayground/Prefabs/NodeImageText.prefab
Agentic/Assets/AgenticPlayground/Prefabs/NodeImageText.prefab.meta
Agentic/Assets/AgenticPlayground/Prefabs/NodeModel.prefab
Agentic/Assets/AgenticPlayground/Prefabs/NodeModel.prefab.meta
Agentic/Assets/AgenticPlayground/Prefabs/NodeText.prefab
Agentic/Assets/AgenticPlayground/Prefabs/NodeText.prefab.meta
Agentic/Assets/AgenticPlayground/Prefabs/TestMesh.prefab
Agentic/Assets/AgenticPlayground/Prefabs/TestMesh.prefab.meta
Agentic/Assets/AgenticPlayground/Prefabs/ToolUsed.prefab
Agentic/Assets/AgenticPlayground/Prefabs/ToolUsed.prefab.meta
Agentic/Assets/AgenticPlayground/Scripts/Agents/AgentLanguageInterface.ts
Agentic/Assets/AgenticPlayground/Scripts/Agents/AgentLanguageInterface.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Agents/AgentMemorySystem.ts
Agentic/Assets/AgenticPlayground/Scripts/Agents/AgentMemorySystem.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Agents/AgentOrchestrator.ts
Agentic/Assets/AgenticPlayground/Scripts/Agents/AgentOrchestrator.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Agents/AgentToolExecutor.ts
Agentic/Assets/AgenticPlayground/Scripts/Agents/AgentToolExecutor.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Agents/AgentTypes.ts
Agentic/Assets/AgenticPlayground/Scripts/Agents/AgentTypes.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/ASR/ChatASRController.ts
Agentic/Assets/AgenticPlayground/Scripts/ASR/ChatASRController.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/ASR/SummaryASRController.ts
Agentic/Assets/AgenticPlayground/Scripts/ASR/SummaryASRController.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Components/ChatBridge.ts
Agentic/Assets/AgenticPlayground/Scripts/Components/ChatBridge.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Components/ChatComponent.ts
Agentic/Assets/AgenticPlayground/Scripts/Components/ChatComponent.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Components/DiagramBridge.ts
Agentic/Assets/AgenticPlayground/Scripts/Components/DiagramBridge.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Components/DiagramComponent.ts
Agentic/Assets/AgenticPlayground/Scripts/Components/DiagramComponent.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Components/SummaryBridge.ts
Agentic/Assets/AgenticPlayground/Scripts/Components/SummaryBridge.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Components/SummaryComponent.ts
Agentic/Assets/AgenticPlayground/Scripts/Components/SummaryComponent.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Core/AISummarizer.ts
Agentic/Assets/AgenticPlayground/Scripts/Core/AISummarizer.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Core/GeminiAssistant.ts
Agentic/Assets/AgenticPlayground/Scripts/Core/GeminiAssistant.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Core/GenerationQueueInitializer.ts
Agentic/Assets/AgenticPlayground/Scripts/Core/GenerationQueueInitializer.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Core/ImageGen.ts
Agentic/Assets/AgenticPlayground/Scripts/Core/ImageGen.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Core/ImageGenBridge.ts
Agentic/Assets/AgenticPlayground/Scripts/Core/ImageGenBridge.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Core/ModelGen.ts
Agentic/Assets/AgenticPlayground/Scripts/Core/ModelGen.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Core/ModelGenBridge.ts
Agentic/Assets/AgenticPlayground/Scripts/Core/ModelGenBridge.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Core/OpenAIAssistant.ts
Agentic/Assets/AgenticPlayground/Scripts/Core/OpenAIAssistant.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Nodes/ImageNode.ts
Agentic/Assets/AgenticPlayground/Scripts/Nodes/ImageNode.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Nodes/ModelNode.ts
Agentic/Assets/AgenticPlayground/Scripts/Nodes/ModelNode.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Nodes/TextNode.ts
Agentic/Assets/AgenticPlayground/Scripts/Nodes/TextNode.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Storage/ChatStorage.ts
Agentic/Assets/AgenticPlayground/Scripts/Storage/ChatStorage.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Storage/DiagramStorage.ts
Agentic/Assets/AgenticPlayground/Scripts/Storage/DiagramStorage.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Storage/StorageManager.ts
Agentic/Assets/AgenticPlayground/Scripts/Storage/StorageManager.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Storage/SummaryStorage.ts
Agentic/Assets/AgenticPlayground/Scripts/Storage/SummaryStorage.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Tests/TestConcurrentGeneration.ts
Agentic/Assets/AgenticPlayground/Scripts/Tests/TestConcurrentGeneration.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Tools/DiagramCreatorTool.ts
Agentic/Assets/AgenticPlayground/Scripts/Tools/DiagramCreatorTool.ts.meta
Agentic/Assets/AgenticPlayground/Scripts/Tools/DiagramUpdaterTool.ts
Agentic/Assets/AgenticPlayground/Scripts/Tools/DiagramUpdaterTool.ts.meta
[389 more files omitted for size]
```

### Dependencies

- go.mod: github.com/bytedance/sonic@v1.14.0, github.com/bytedance/sonic/loader@v0.3.0, github.com/cloudwego/base64x@v0.1.6, github.com/gabriel-vasile/mimetype@v1.4.8, github.com/gin-contrib/sse@v1.1.0, github.com/gin-gonic/gin@v1.11.0, github.com/go-playground/locales@v0.14.1, github.com/go-playground/universal-translator@v0.18.1, github.com/go-playground/validator/v10@v10.27.0, github.com/go-resty/resty/v2@v2.16.5, github.com/goccy/go-json@v0.10.2, github.com/goccy/go-yaml@v1.18.0, github.com/joho/godotenv@v1.5.1, github.com/json-iterator/go@v1.1.12, github.com/klauspost/cpuid/v2@v2.3.0, github.com/leodido/go-urn@v1.4.0, github.com/mattn/go-isatty@v0.0.20, github.com/modern-go/concurrent@v0.0.0-20180228061459-e0a39a4cb421, github.com/modern-go/reflect2@v1.0.2, github.com/pelletier/go-toml/v2@v2.2.4, github.com/quic-go/qpack@v0.5.1, github.com/quic-go/quic-go@v0.54.0, github.com/sashabaranov/go-openai@v1.41.2, github.com/twitchyliquid64/golang-asm@v0.15.1, github.com/ugorji/go/codec@v1.3.0, go.uber.org/mock@v0.5.0, golang.org/x/arch@v0.20.0, golang.org/x/crypto@v0.40.0, golang.org/x/mod@v0.25.0, golang.org/x/net@v0.42.0, golang.org/x/sync@v0.16.0, golang.org/x/sys@v0.35.0, golang.org/x/text@v0.27.0, golang.org/x/tools@v0.34.0, google.golang.org/protobuf@v1.36.9

### Recent commits (newest first)

- Merge pull request #14 from nopunindented-temp/fixed-cards
- Merge branch 'main' into fixed-cards
- change of scene
- fixed better spacing
- fix cards
- Merge pull request #13 from nopunindented-temp/feature/age-group-buttons
- feat: Add AgeGroupButtons component and resolve merge conflicts
- Merge pull request #12 from nopunindented-temp/feature/age-group-buttons
- feat: Add AgeGroupButtons component with PinchButton support
- mic
- Merge pull request #11 from nopunindented-temp/age-welcome
- finished
- Merge pull request #10 from nopunindented-temp/card-streaming
- Merge branch 'main' into card-streaming
- card building
- Merge pull request #9 from nopunindented-temp/navigations
- Full Navigation + Fixed Cards
- Merge pull request #8 from nopunindented-temp/restore
- Merge branch 'main' into restore
- Fade Landing Page Fully Working

## Key source files (fetched from GitHub, selected and truncated for size)

### Agentic/Context/asr-module.md

```markdown
# ASR Module

## Overview

The ASR Module enables the integration of Speech-to-Text functionality within Lenses, offering support for 40+ languages, including mixed language input. It delivers high accuracy, accommodating various accents and non-native speakers effectively.

## Getting Started

### Prerequisites

- Lens Studio v5.9.0 or later
- Spectacles OS v5.61 or later
- This API is only available on Spectacles.

## Scripting Example

Create a new TypeScript or JavaScript file in the Asset Browser and drag it into the Scene. Open the script for editing and add the following lines to include the AsrModule:

```javascript
const asrModule = require('LensStudio:AsrModule');
```

## Defining Callbacks

Transcription updates and errors are handled using callbacks.

```javascript
const onTranscriptionUpdate = (
  eventArgs: AsrModule.TranscriptionUpdateEvent
) => {
  print(
    `onTranscriptionUpdateCallback text=${eventArgs.text}, isFinal=${eventArgs.isFinal}`
  );
};

const onTranscriptionError = (errorCode: AsrModule.AsrStatusCode) => {
  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;
  }
};
```

## Transcription Options

The ASR Transcription Options object allows to configure the AsrModule. To create options:

```javascript
const options = AsrModule.AsrTranscriptionOptions.create();
options.silenceUntilTerminationMs = 1000;
options.mode = AsrModule.AsrMode.HighAccuracy;
options.onTranscriptionUpdateEvent.add((eventArgs) =>
  onTranscriptionUpdate(eventArgs);
);
options.onTranscriptionErrorEvent.add((eventArgs) =>
  onTranscriptionError(eventArgs);
);
```

`silenceUntilTerminationMs` specifies the duration in milliseconds of detected silence after which the current transcribed sentence or fragment is marked as final. Once a transcription is finalized, a new transcription begins within the same session. This process continues until the client explicitly stops the session.

`mode` is the operation mode of the ASR session. Possible values are:

- `HighAccuracy`
- `Balanced`
- `HighSpeed`

## Start and Stop Transcribing

To start transcribing, pass your options object into the `startTranscribing` function:

```javascript
asrModule.startTranscribing(options);
```

Call `stopTranscribing` to stop:

```javascript
asrModule.stopTranscribing().then(function () {
  print(`Transcribing stopped`);
});
```

## Full Script

### TypeScript

```typescript
@component
export class AsrExample extends BaseScriptComponent {
  private asrModule = require('LensStudio:AsrModule');

  private onTranscriptionUpdate(eventArgs: AsrModule.TranscriptionUpdateEvent) {
    print(
      `onTranscriptionUpdateCallback t
[truncated — 2366 more characters]
```

### Agentic/Context/websocket.md

```markdown
# WebSocket

## Overview

Spectacles offers the standardized WebSocket API to connect to real-time streams on the internet. This API is based on the [MDN reference](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket).

> **Important:** Accessing the internet in a Lens will disable access to privacy-sensitive user information in that Lens, such as the camera frame, location, and audio. For testing and experimental purposes however, extended permissions are available to access both the camera frame and the open internet at the same time. Note that lenses built this way may not be released publicly. Please see Extended Permissions doc for more information.

> **Exception:** There is an exception to this rule: if a WebSocket connection is created using the `createAPIWebSocket` and the associated specification ID is allowlisted, then both privacy-sensitive user data and internet access can be used simultaneously, even when Extended Permissions are disabled.

> **Note:** Prior to Lens Studio 5.9, `createWebSocket` was available via the `RemoteServiceModule`. From Lens Studio 5.9, this APIs has been moved to the `InternetModule`. Lenses that are already public can continue to use this method in `RemoteServiceModule` until they are re-published with Lens Studio 5.9.

## Getting Started

### Prerequisites

- Lens Studio v5.4.0 or later
- Spectacles OS v5.059 or later
- This API is only available on Spectacles.

### Setup Instructions

To use the WebSocket API add the `InternetModule` to your project and include it in your scripts as per the examples below.

> **Note:** The WebSocket API will only work in the Preview window if the Device Type Override is set to Spectacles.

## Core Component

The `InternetModule` exposes the WebSocket API. To connect to a WebSocket server, use the `createWebSocket` command with a `ws` or `wss` url.

> **Important:** Using insecure connections (`ws`) requires enabling Experimental APIs. While these Lenses are suitable for testing purposes, they cannot be published. Lenses employing secure connections (`wss`) are eligible for publication.

You can utilize the returned WebSocket object to manage the connection. For instance, you can monitor for a successful connection through the `onopen` property, handle incoming messages using the `onmessage` property, and send messages with the `send` method. The example below demonstrates how to perform all these actions:

### TypeScript

```typescript
@component
export class WebSocketExample extends BaseScriptComponent {
  @input
  remoteServiceModule: RemoteServiceModule;

  private socket!: WebSocket;

  // Method called when the script is awake
  async onAwake() {
    this.socket = this.remoteServiceModule.createWebSocket('wss://<some-url>');
    this.socket.binaryType = 'blob';

    // Listen for the open event
    this.socket.onopen = (event: WebSocketEvent) => {
      // Socket has opened, send a message back to the server
      this.socket.send('Message 1');

      // Try 
[truncated — 2661 more characters]
```

### go.mod

```
module github.com/nopunindented-temp/ZoomerToBoomer/system_api

go 1.23.0

toolchain go1.24.9

require (
	github.com/bytedance/sonic v1.14.0 // indirect
	github.com/bytedance/sonic/loader v0.3.0 // indirect
	github.com/cloudwego/base64x v0.1.6 // indirect
	github.com/gabriel-vasile/mimetype v1.4.8 // indirect
	github.com/gin-contrib/sse v1.1.0 // indirect
	github.com/gin-gonic/gin v1.11.0 // indirect
	github.com/go-playground/locales v0.14.1 // indirect
	github.com/go-playground/universal-translator v0.18.1 // indirect
	github.com/go-playground/validator/v10 v10.27.0 // indirect
	github.com/go-resty/resty/v2 v2.16.5 // indirect
	github.com/goccy/go-json v0.10.2 // indirect
	github.com/goccy/go-yaml v1.18.0 // indirect
	github.com/joho/godotenv v1.5.1 // indirect
	github.com/json-iterator/go v1.1.12 // indirect
	github.com/klauspost/cpuid/v2 v2.3.0 // indirect
	github.com/leodido/go-urn v1.4.0 // indirect
	github.com/mattn/go-isatty v0.0.20 // indirect
	github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
	github.com/modern-go/reflect2 v1.0.2 // indirect
	github.com/pelletier/go-toml/v2 v2.2.4 // indirect
	github.com/quic-go/qpack v0.5.1 // indirect
	github.com/quic-go/quic-go v0.54.0 // indirect
	github.com/sashabaranov/go-openai v1.41.2 // indirect
	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
	github.com/ugorji/go/codec v1.3.0 // indirect
	go.uber.org/mock v0.5.0 // indirect
	golang.org/x/arch v0.20.0 // indirect
	golang.org/x/crypto v0.40.0 // indirect
	golang.org/x/mod v0.25.0 // indirect
	golang.org/x/net v0.42.0 // indirect
	golang.org/x/sync v0.16.0 // indirect
	golang.org/x/sys v0.35.0 // indirect
	golang.org/x/text v0.27.0 // indirect
	golang.org/x/tools v0.34.0 // indirect
	google.golang.org/protobuf v1.36.9 // indirect
)

```

### main.go

```go
package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/joho/godotenv"
	"os"

	"github.com/nopunindented-temp/ZoomerToBoomer/system_api/api" // update path if needed
)

func main() {
	// Load environment variables from .env
	err := godotenv.Load(".env")
	if err != nil {
		log.Println("⚠️  No .env file found — proceeding with system environment vars.")
	}

	// Verify Groq key exists
	apiKey := os.Getenv("GROQ_API_KEY")
	if apiKey == "" {
		log.Fatal("❌ Missing GROQ_API_KEY — please set it in your .env file.")
	}

	// Register endpoint
	http.HandleFunc("/process-summary", handler.Handler)

	port := "8080"
	fmt.Printf("🚀 Local Spectacles API running at http://localhost:%s/process-summary\n", port)
	fmt.Println("Press Ctrl+C to stop.")
	log.Fatal(http.ListenAndServe(":"+port, nil))
}

```

### api/process-summary.go

```go
package handler

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"github.com/joho/godotenv"
	"github.com/go-resty/resty/v2"
)

// === Structs ===
type Conversation struct {
	Text       string `json:"text"`
	Generation string `json:"generation"`
}


func init() {
    _ = godotenv.Load()
}

type GroqResponse struct {
	ID      string `json:"id"`
	Object  string `json:"object"`
	Choices []struct {
		Index        int    `json:"index"`
		FinishReason string `json:"finish_reason"`
		Message      struct {
			Role    string `json:"role"`
			Content string `json:"content"`
		} `json:"message"`
	} `json:"choices"`
}

type GroqError struct {
	Error struct {
		Message string `json:"message"`
		Type    string `json:"type"`
		Code    string `json:"code"`
	} `json:"error"`
}

// === Handler (Vercel entrypoint) ===
func Handler(w http.ResponseWriter, r *http.Request) {
	// ✅ Always set CORS headers for every request
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
	w.Header().Set("Access-Control-Max-Age", "86400")

	// ✅ Handle preflight OPTIONS requests
	if r.Method == http.MethodOptions {
		w.WriteHeader(http.StatusNoContent)
		return
	}

	if r.Method != http.MethodPost {
		http.Error(w, "Only POST supported", http.StatusMethodNotAllowed)
		return
	}

	apiKey := os.Getenv("GROQ_API_KEY")
	if apiKey == "" {
		http.Error(w, "Missing GROQ_API_KEY", http.StatusInternalServerError)
		return
	}

	bodyBytes, _ := io.ReadAll(r.Body)
	var convo Conversation
	if err := json.Unmarshal(bodyBytes, &convo); err != nil {
		http.Error(w, "Invalid JSON body", http.StatusBadRequest)
		return
	}

	systemPrompt := fmt.Sprintf(`
	You are the Spectacles Agentic assistant.
	The listener belongs to the %s generation.

	Generational hierarchy (youngest → oldest):
	Gen Alpha (2013–2025)
	→ Gen Z (1997–2012)
	→ Millennial / Gen Y (1981–1996)
	→ Gen X (1965–1980)
	→ Baby Boomer (1946–1964)

	Your role is to explain slang or idioms only when there is a genuine cross-generational gap of two or more steps.

	Behavior rules:
	- Always infer which generation the *speaker* likely belongs to based on the slang or tone.
	- Some slang originates in one generation (e.g. Gen Z) but becomes actively used by the next (e.g. Gen Alpha). 
	In those cases, treat the slang as **belonging to both generations**. 
	Example: “rizz”, “fit goes hard”, and “no cap” are used by both Gen Z and Gen Alpha → do not flag them as cross-generational.
	- Compute the generational gap (absolute difference in list order):
	• Gap ≤ 1 → DO NOT explain; assume mutual understanding.
	• Gap ≥ 2 → explain slang, idioms, or cultural expressions that are likely unfamiliar.
	- Over-explaining or clarifying within a 1-generation gap is considered an error.
	- Ignore literal, common, or dictionary words (e.g. “slang”, “honestly”, “stupid”, “literally”).
	- For Gen Alpha listeners, use very simple, single-sentence explanations.
	- Output clean JSON:

	{
	"speaker_generation": "<guessed generation>",
	"generational_gap": "<integer difference>",
	"slang_explanations": {
		"<term>": "<concise meaning>"
	},
	"action": "<suggested_action>",
	"reason": "<brief_reason>"
	}
	`, convo.Generation)

	client := resty.New()
	client.SetHeader("Content-Type", "application/json")
	client.SetAuthToken(apiKey)

	attempts := []struct {
	Model     string
	WithTools bool
	}{
		{"llama-3.3-70b-versatile", false},
		{"llama-3.3-8b-instant", false},
	}

	var lastErrBody string
	for _, a := range attempts {
		reqBody := buildRequestBody(systemPrompt, convo.Text, a.Model, a.WithTools)
		resp, err := client.R().
			SetBody(reqBody).
			Post("https://api.groq.com/openai/v1/chat/completions")

		if err != nil {
			lastErrBody = err.Error()
			continue
		}

		if resp.StatusCode() == 200 {
			var gr GroqResponse
			if err := json.Unmarshal(resp.Body(), &gr); err != nil {
				http.Error(w, "Failed to parse Groq response", 500)
				return
			}
			if len(gr.Choices) == 0 {
				http.Error(w, "No response from Groq", 500)
				return
			}

			// ✅ CORS-safe successful response
			w.Header().Set("Content-Type", "application/json")
			json.NewEncoder(w).Encode(map[string]interface{}{
				"model_used": a.Model,
				"tools_used": a.WithTools,
				"result":     gr.Choices[0].Message.Content,
			})
			return
		}

		lastErrBody = string(resp.Body())
		if shouldRetryWithNextModel(resp.StatusCode(), resp.Body()) {
			continue
		} else {
			w.WriteHeader(resp.StatusCode())
			w.Write(resp.Body())
			return
		}
	}

	http.Error(w, "No model worked: "+trim(lastErrBody, 500), http.StatusBadGateway)
}

// === Helper functions ===
func buildRequestBody(systemPrompt, userText, model string, withTools bool) map[string]interface{} {
	msgs := []map[string]string{
		{"role": "system", "content": systemPrompt},
		{"role": "user", "content": userText},
	}
	req := map[string]interface{}{
		"model":       model,
		"messages":    msgs,
		"temperature": 0.2,
		"max_tokens":  4000,
	}
	if withTools {
		req["tool_choice"] = "auto"
		req["tools"] = []map[string]interface{}{
			{"type": "browser_search"},
		}
	}
	return req
}

func shouldRetryWithNextModel(status int, body []byte) bool {
	if status == 404 || status == 400 || status == 422 || status == 409 {
		var ge GroqError
		_ = json.Unmarshal(body, &ge)
		msg := strings.ToLower(ge.Error.Message)
		code := strings.ToLower(ge.Error.Code)
		if strings.Contains(code, "model_not_found") || strings.Contains(code, "model_decommissioned") {
			return true
		}
		if strings.Contains(msg, "tools") || strings.Contains(msg, "unsupported") {
			return true
		}
	}
	return false
}

func trim(s string, n int) string {
	b := []byte(s)
	if len(b) <= n {
		return s
	}
	return string(bytes.TrimSpace(b[:n]))
}

// Add this at the bottom of your file — temporarily for local testing only.
func main() {
    port := "8080"
    fmt.Println("🚀
[truncated — 139 more characters]
```

### Agentic/Assets/ToggleStartPause.js

```javascript
// @input Component.Text buttonText
// @input Component.MaterialMeshVisual sphereVisual
// @input Asset.Material startMaterial     // green
// @input Asset.Material pauseMaterial     // gray / normal

var isStarted = false;
var baseScale;
var pulseEvent;

// smooth pulse settings
var pulseSpeed = 0.9;     // slower = smoother breathing rhythm
var pulseAmount = 0.15;   // how large the sphere expands
var easeStrength = 0.15;  // smaller = softer easing (0.1–0.2 is natural)

// ---- Helpers ----

// Apply current material/text
function applyState() {
    if (!script.buttonText || !script.sphereVisual) return;

    if (isStarted) {
        script.buttonText.text = "Pause";
        script.buttonText.textFill.color = new vec4(1, 1, 1, 1);
        script.sphereVisual.clearMaterials();
        script.sphereVisual.addMaterial(script.pauseMaterial);
    } else {
        script.buttonText.text = "Start";
        script.buttonText.textFill.color = new vec4(1, 1, 1, 1);
        script.sphereVisual.clearMaterials();
        script.sphereVisual.addMaterial(script.startMaterial);
    }
}

// Breathing pulse loop (smooth sinusoidal)
function pulseLoop(eventData) {
    if (!baseScale) return;

    var time = getTime() * pulseSpeed;
    var sine = (Math.sin(time) + 1.0) / 2.0; // 0–1 range
    var eased = sine * sine * (3 - 2 * sine); // smoothstep easing

    var offset = pulseAmount * (eased - 0.5); // symmetric pulse around base
    var newScale = new vec3(
        baseScale.x * (1 + offset),
        baseScale.y * (1 + offset),
        baseScale.z * (1 + offset)
    );
    script.getSceneObject().getTransform().setLocalScale(newScale);
}

// Quick “pop” when toggled
function popAnimation() {
    var tform = script.getSceneObject().getTransform();
    var cur = tform.getLocalScale();
    var target = new vec3(cur.x * 1.3, cur.y * 1.3, cur.z * 1.3); // stronger pop

    var duration = 0.25;
    var time = 0;
    var popEvent = script.createEvent("UpdateEvent");

    popEvent.bind(function(e) {
        time += e.getDeltaTime();
        var t = Math.min(time / duration, 1.0);
        var easeOut = 1 - Math.pow(1 - t, 3);
        var newScale = vec3.lerp(cur, target, easeOut);
        tform.setLocalScale(newScale);

        if (t >= 1.0) {
            script.removeEvent(popEvent);
            // return to base scale smoothly
            var resetEvent = script.createEvent("UpdateEvent");
            var resetTime = 0;
            resetEvent.bind(function(e2) {
                resetTime += e2.getDeltaTime();
                var r = Math.min(resetTime / duration, 1.0);
                var back = 1 - Math.pow(1 - r, 3);
                tform.setLocalScale(vec3.lerp(target, baseScale, back));
                if (r >= 1.0) script.removeEvent(resetEvent);
            });
        }
    });
}

// Tap handler
function onTap() {
    if (!script.buttonText || !script.sphereVisual) return;

    script.removeEvent(pulseEvent); // temporarily stop pulsing
    popAnimation();

    var delayed = script.createEvent("DelayedCallbackEvent");
    delayed.bind(function() {
        isStarted = !isStarted;
        applyState();
        pulseEvent = script.createEvent("UpdateEvent");
        pulseEvent.bind(pulseLoop); // resume pulse
    });
    delayed.reset(1.0);
}

// Initialize
function init() {
    baseScale = script.getSceneObject().getTransform().getLocalScale();
    applyState();

    var interaction = script.getSceneObject().getComponent("Component.InteractionComponent");
    if (interaction) interaction.onTap.add(onTap);

    pulseEvent = script.createEvent("UpdateEvent");
    pulseEvent.bind(pulseLoop);
}

script.createEvent("OnStartEvent").bind(init);

```

### Agentic/Assets/Navigation.js

```javascript
// var startTime = 0;
// var transitionDone = false;

// script.createEvent("OnStartEvent").bind(function() {
//     startTime = getTime();

//     // Start state
//     if (script.landingPage) script.landingPage.enabled = true;
//     if (script.ageRangePage) script.ageRangePage.enabled = false;

//     print("Landing page fade sequence started...");
// });

// script.createEvent("UpdateEvent").bind(function() {
//     var elapsed = getTime() - startTime;

//     // --- Fade group 1: Welcome + Names ---
//     if (elapsed >= script.group1Delay) {
//         var t1 = Math.min((elapsed - script.group1Delay) / script.fadeDuration, 1.0);
//         fadeText(script.welcomeText, 1.0 - t1);
//         fadeText(script.namesText, 1.0 - t1);

//         if (t1 >= 1.0) {
//             disableText(script.welcomeText);
//             disableText(script.namesText);
//         }
//     }

//     // --- Fade group 2: One-liner ---
//     if (elapsed >= script.oneLinerDelay) {
//         var t2 = Math.min((elapsed - script.oneLinerDelay) / script.fadeDuration, 1.0);
//         fadeText(script.oneLinerText, 1.0 - t2);

//         // ✅ When fade complete → switch to Age Range Page
//         if (t2 >= 1.0 && !transitionDone) {
//             disableText(script.oneLinerText);
//             transitionDone = true;

//             if (script.landingPage) script.landingPage.enabled = false;
//             if (script.ageRangePage) script.ageRangePage.enabled = true;

//             print("✅ Transition complete — now showing Age Range Page");
//         }
//     }
// });

// // --------------------
// // Helper: fade 2D Text (2D Screen Text only)
// // --------------------
// function fadeText(txt, alpha) {
//     if (!txt) return;
//     try {
//         var color = txt.textFill.color;
//         txt.textFill.color = new vec4(color.x, color.y, color.z, alpha);
//     } catch (e) {
//         // Safe fallback
//     }
// }

// function disableText(txt) {
//     if (txt) txt.enabled = false;
// }

// ------------------------------ div

// --------------------
// Page Flow Controller (Full App Sequence)
// --------------------
//
// @input SceneObject landingPage
// @input SceneObject ageRangePage
// @input SceneObject microphonePage
// @input SceneObject lingoVocabPage
// @input SceneObject resultsPage
//
// @input Component.Text landing_welcomeText
// @input Component.Text landing_namesText
// @input Component.Text landing_oneLinerText
//
// @input float fadeDuration = 1.5
// @input float delayLanding = 4.5      // total time before landing fades
// @input float delayAgeRange = 3.0     // show age page this long before fade
// @input float delayMicrophone = 3.0
// @input float delayLingoVocab = 3.0

// var startTime = 0;
// var phase = 0; // 0 = landing, 1 = age range, 2 = mic, 3 = vocab, 4 = results
// var fadeStartTime = 0;
// var fading = false;

// script.createEvent("OnStartEvent").bind(function() {
//     startTime = getTime();

//     enableOnly(script.landingPage);
//     print("✅ Page flow started (Landing Page active).");
// });

// script.createEvent("UpdateEvent").bind(function() {
//     var now = getTime();

//     // --- PHASE 0: Landing Page ---
//     if (phase === 0 && now - startTime >= script.delayLanding) {
//         fadeText(script.landing_welcomeText, 0);
//         fadeText(script.landing_namesText, 0);
//         fadeText(script.landing_oneLinerText, 0);
//         nextPage(script.ageRangePage);
//     }

//     // --- PHASE 1: Age Range ---
//     if (phase === 1 && now - fadeStartTime >= script.delayAgeRange) {
//         nextPage(script.microphonePage);
//     }

//     // --- PHASE 2: Microphone ---
//     if (phase === 2 && now - fadeStartTime >= script.delayMicrophone) {
//         nextPage(script.lingoVocabPage);
//     }

//     // --- PHASE 3: LingoVocab ---
//     if (phase === 3 && now - fadeStartTime >= script.delayLingoVocab) {
//         nextPage(script.resultsPage);
//     }

//     // --- PHASE 4: Results ---
//     if (phase === 4) {
//         // End of sequence — do nothing or keep results visible
//     }
// });

// // --- Helper: Enable one page, disable others ---
// function enableOnly(obj) {
//     if (!obj) return;

//     if (script.landingPage) script.landingPage.enabled = (obj === script.landingPage);
//     if (script.ageRangePage) script.ageRangePage.enabled = (obj === script.ageRangePage);
//     if (script.microphonePage) script.microphonePage.enabled = (obj === script.microphonePage);
//     if (script.lingoVocabPage) script.lingoVocabPage.enabled = (obj === script.lingoVocabPage);
//     if (script.resultsPage) script.resultsPage.enabled = (obj === script.resultsPage);

//     fadeStartTime = getTime();
//     print("→ Switched to page: " + obj.name);
// }

// // --- Helper: Go to next phase/page ---
// function nextPage(nextObj) {
//     phase++;
//     enableOnly(nextObj);
// }

// // --- Helper: Fade 2D Text instantly or later ---
// function fadeText(txt, alpha) {
//     if (!txt) return;
//     try {
//         var c = txt.textFill.color;
//         txt.textFill.color = new vec4(c.x, c.y, c.z, alpha);
//     } catch (e) {
//         // ignore safely
//     }
// }
// ------------------------------ div

// --------------------
// Full App Flow Controller
// --------------------
// Linear sequence through all pages with timed transitions.
// Works cleanly with 2D Screen Text fade on landing.
//
// FLOW:
// Landing → AgeRange → Microphone → LingoVocab → Results → Rewards
//
// @input SceneObject landingPage
// @input SceneObject ageRangePage
// @input SceneObject microphonePage
// @input SceneObject lingoVocabPage
// @input SceneObject resultsPage
// @input SceneObject rewardsPage
//
// @input Component.Text landing_welcomeText
// @input Component.Text landing_namesText
// @input Component.Text landing_oneLinerText
//
// @input float fadeDuration = 1.5
// @input float delayLanding = 4.5      // seconds before leaving landing
// @input float delayAgeR
[truncated — 2535 more characters]
```

### Agentic/Assets/AgeGroupButtons.ts

```typescript
import { PinchButton } from "SpectaclesInteractionKit.lspkg/Components/UI/PinchButton/PinchButton";
import Event from "SpectaclesInteractionKit.lspkg/Utils/Event";
import { LSTween } from "LSTween.lspkg/LSTween";

@component
export class AgeGroupButtons extends BaseScriptComponent {
    @input
    private zoomerButton: PinchButton;
    @input
    private millennialButton: PinchButton;
    @input
    private genXButton: PinchButton;
    @input
    private boomerButton: PinchButton;
    @input
    private backButton: PinchButton;
    @input
    private enableDebugLogging: boolean = true;

    private ageGroups: Record<AgeGroupKey, AgeGroup> = {
        zoomer: { name: "Gen Z", button: null, selected: false, textObject: null },
        millennial: { name: "Millennial", button: null, selected: false, textObject: null },
        genX: { name: "Gen X", button: null, selected: false, textObject: null },
        boomer: { name: "Boomer", button: null, selected: false, textObject: null }
    };

    private buttonsHidden: boolean = false;

    // Events
    public onAgeGroupSelected: Event<string> = new Event<string>();
    public onButtonsHidden: Event<void> = new Event<void>();
    public onButtonsShown: Event<void> = new Event<void>();

    onAwake(): void {
        this.createEvent("OnStartEvent").bind(this.initialize.bind(this));
        
        if (this.enableDebugLogging) {
            print("AgeGroupButtons: 🎯 Age Group Button Controller awakened");
        }
    }

    private initialize(): void {
        this.setupButtons();
        this.setupUI();
        this.setupGlobalController();
        
        if (this.enableDebugLogging) {
            print("AgeGroupButtons: ✅ Initialized successfully");
        }
    }

    private setupButtons(): void {
        this.ageGroups.zoomer.button = this.zoomerButton?.getSceneObject() || null;
        this.ageGroups.millennial.button = this.millennialButton?.getSceneObject() || null;
        this.ageGroups.genX.button = this.genXButton?.getSceneObject() || null;
        this.ageGroups.boomer.button = this.boomerButton?.getSceneObject() || null;
        
        if (this.enableDebugLogging) {
            print(`AgeGroupButtons: 🔗 Buttons linked: Z=${!!this.zoomerButton}, M=${!!this.millennialButton}, X=${!!this.genXButton}, B=${!!this.boomerButton}`);
        }
    }

    private setupGlobalController(): void {
        (global as any).ageGroupController = {
            getSelected: () => this.getSelectedAgeGroup(),
            ageGroups: this.ageGroups,
            selectZoomer: () => this.selectAgeGroup('zoomer'),
            selectMillennial: () => this.selectAgeGroup('millennial'),
            selectGenX: () => this.selectAgeGroup('genX'),
            selectBoomer: () => this.selectAgeGroup('boomer'),
            hideButtons: () => this.hideAllButtons(),
            showButtons: () => this.showAllButtons(),
            goBack: () => this.goBack()
        };
    }

    private setupUI(): void {
        this.createTextLabels();
        
        if (this.zoomerButton) {
            this.zoomerButton.onButtonPinched.add(() => this.selectAgeGroup('zoomer'));
            if (this.enableDebugLogging) print(":dart: Zoomer button configured");
        }
        
        if (this.millennialButton) {
            this.millennialButton.onButtonPinched.add(() => this.selectAgeGroup('millennial'));
            if (this.enableDebugLogging) print(":dart: Millennial button configured");
        }
        
        if (this.genXButton) {
            this.genXButton.onButtonPinched.add(() => this.selectAgeGroup('genX'));
            if (this.enableDebugLogging) print(":dart: GenX button configured");
        }
        
        if (this.boomerButton) {
            this.boomerButton.onButtonPinched.add(() => this.selectAgeGroup('boomer'));
            if (this.enableDebugLogging) print(":dart: Boomer button configured");
        }
        
        if (this.backButton) {
            this.backButton.getSceneObject().enabled = false;
            this.backButton.onButtonPinched.add(() => this.goBack());
            if (this.enableDebugLogging) print(":dart: Back button configured");
        }
    }

    public selectAgeGroup(group: AgeGroupKey): void {
        // Clear all selections
        Object.keys(this.ageGroups).forEach((key: string) => {
            this.ageGroups[key as AgeGroupKey].selected = false;
        });
        
        // Set the selected group
        this.ageGroups[group].selected = true;
        
        if (this.enableDebugLogging) {
            print(`AgeGroupButtons: ✅ Selected: ${this.ageGroups[group].name}`);
        }
        
        // Trigger events
        this.onAgeGroupSelected.invoke(this.ageGroups[group].name);
        
        // Hide all buttons with animation
        this.hideAllButtons();
    }

    public goBack(): void {
        // Clear selection
        Object.keys(this.ageGroups).forEach((key: string) => {
            this.ageGroups[key as AgeGroupKey].selected = false;
        });
        
        // Show all buttons again
        this.showAllButtons();
        
        if (this.enableDebugLogging) {
            print("AgeGroupButtons: ⬅️ Returned to selection screen");
        }
    }



    public getSelectedAgeGroup(): string | null {
        for (const key in this.ageGroups) {
            if (this.ageGroups[key as AgeGroupKey].selected) {
                return this.ageGroups[key as AgeGroupKey].name;
            }
        }
        return null;
    }
    
    public isUIReady(): boolean {
        return !!(this.zoomerButton && this.millennialButton && this.genXButton && this.boomerButton);
    }
    
    public areButtonsHidden(): boolean {
        return this.buttonsHidden;
    }

    private createTextLabels(): void {
        Object.keys(this.ageGroups).forEach((key: string) => {
            const ageKey = key as AgeGroupKey;
            const button = this.ageGroups[ageKey].button;
            
            if (button)
[truncated — 4346 more characters]
```

### Agentic/Assets/Easy Lens/LensController.js

```javascript
// Main Controller
//
// Made with Easy Lens

//@input Component.ScriptComponent mainText
//@input Component.ScriptComponent touchEvents


try {

// Array of texts to cycle through when the interactable is clicked
const texts = [
    "Welcome to my Lens!",
    "Tap again to see more.",
    "Have a great day!",
    "Enjoy exploring AR!",
    "You clicked the interactable!"
];

let textIndex = 0;

// Set the initial text
script.mainText.text = texts[textIndex];

// Change text on tap
script.touchEvents.onTap.add(function() {
    textIndex = (textIndex + 1) % texts.length;
    script.mainText.text = texts[textIndex];
});

} catch(e) {
  print("error in controller");
  print(e);
}

```

### Agentic/Assets/SpectaclesUIKitBeta.lspkg/Scripts/DropShadow.ts

```typescript
import {GradientParameters, RoundedRectangle} from "./Visuals/RoundedRectangle/RoundedRectangle"

@component
export class DropShadow extends BaseScriptComponent {
  @input
  private _size: vec2 = new vec2(3, 3)

  @input
  private _cornerRadius: number = 1.5

  @input("vec4", "{.43,.43,.43,.15}")
  @widget(new ColorWidget())
  private color: vec4 = new vec4(11 / 255, 11 / 255, 11 / 255, 15 / 100)

  @input
  @widget(new SliderWidget(0.0, 1.0))
  private spread: number = 0.5

  private shadow: RoundedRectangle

  /**
   * The size of the drop shadow.
   * @type {vec2}
   */
  public get size(): vec2 {
    return this._size
  }

  /**
   * The size of the drop shadow.
   * @param {vec2} value - The new size of the drop shadow.
   */
  public set size(value: vec2) {
    this._size = value
    if (this.shadow) {
      this.shadow.size = new vec2(value.x, value.y)
    }
  }

  /**
   * The corner radius of the drop shadow.
   * @type {number}
   */
  public get cornerRadius(): number {
    return this._cornerRadius
  }

  /**
   * The corner radius of the drop shadow.
   * @param {number} value - The new corner radius of the drop shadow.
   */
  public set cornerRadius(value: number) {
    this._cornerRadius = value
    if (this.shadow) {
      this.shadow.cornerRadius = value
    }
  }

  private get defaultGradient(): GradientParameters {
    return {
      type: "Rectangle",
      start: new vec2(-1, 0),
      end: new vec2(1, 0),
      stop0: {enabled: true, color: this.color, percent: 1 - this.spread},
      stop1: {enabled: true, color: new vec4(this.color.x, this.color.y, this.color.z, 0), percent: 1},
      stop2: {enabled: false},
      stop3: {enabled: false},
      stop4: {enabled: false}
    } as GradientParameters
  }

  onAwake() {
    const transform = this.getTransform()
    const localPosition = transform.getLocalPosition()
    transform.setLocalPosition(new vec3(localPosition.x, localPosition.y, -0.01))
    this.shadow = this.sceneObject.createComponent(RoundedRectangle.getTypeName())
    this.shadow.initialize()

    this.shadow.size = new vec2(this._size.x, this._size.y)
    this.shadow.cornerRadius = this._cornerRadius
    this.shadow.border = false
    this.shadow.borderSize = 0
    this.shadow.gradient = true
    this.shadow.gradientType = "Rectangle"
    this.shadow.setBackgroundGradient(this.defaultGradient)

    this.shadow.renderMeshVisual.mainPass.colorMask = new vec4b(true, true, true, true)
    this.shadow.renderMeshVisual.mainPass.blendMode = BlendMode.Normal
    this.shadow.renderMeshVisual.mainMaterial.mainPass.depthTest = true
    this.shadow.renderMeshVisual.mainMaterial.mainPass.depthWrite = true
  }
}

```

[109 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]