@mml-io/3d-web-experience-client 0.23.0 → 0.23.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.css +104 -104
- package/build/index.css.map +1 -1
- package/build/index.js +57 -57
- package/build/index.js.map +1 -1
- package/package.json +4 -4
package/build/index.js.map
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": 3,
|
3
3
|
"sources": ["../src/Networked3dWebExperienceClient.ts", "../src/avatar-selection-ui/AvatarSelectionUI.tsx", "../src/avatar-selection-ui/components/AvatarPanel/AvatarSectionUIComponent.tsx", "../src/avatar-selection-ui/icons/Avatar.svg", "esbuild-css-modules-plugin-ns-js::src/avatar-selection-ui/components/AvatarPanel/AvatarSelectionUIComponent.module.css:injector.js", "../src/avatar-selection-ui/components/AvatarPanel/AvatarSelectionUIComponent.module.css", "../src/chat-ui/TextChatUI.tsx", "../src/chat-ui/components/ChatPanel/TextChatUIComponent.tsx", "../src/chat-ui/helpers.tsx", "../src/chat-ui/icons/Chat.svg", "../src/chat-ui/icons/Pin.svg", "../src/chat-ui/components/Input/InputBox.tsx", "../src/chat-ui/icons/PaperPlane.svg", "esbuild-css-modules-plugin-ns-js::src/chat-ui/components/Input/InputBox.module.css:injector.js", "../src/chat-ui/components/Input/InputBox.module.css", "../src/chat-ui/components/Messages/Messages.tsx", "../src/chat-ui/components/Message/Message.tsx", "esbuild-css-modules-plugin-ns-js::src/chat-ui/components/Message/Message.module.css:injector.js", "../src/chat-ui/components/Message/Message.module.css", "esbuild-css-modules-plugin-ns-js::src/chat-ui/components/Messages/Messages.module.css:injector.js", "../src/chat-ui/components/Messages/Messages.module.css", "esbuild-css-modules-plugin-ns-js::src/chat-ui/components/ChatPanel/TextChatUIComponent.module.css:injector.js", "../src/chat-ui/components/ChatPanel/TextChatUIComponent.module.css", "esbuild-css-modules-plugin-ns-js::src/Networked3dWebExperience.module.css:injector.js", "../src/Networked3dWebExperience.module.css"],
|
4
|
-
"sourcesContent": ["import {\n AnimationConfig,\n CameraManager,\n CharacterDescription,\n CharacterManager,\n CharacterModelLoader,\n CharacterState,\n CollisionsManager,\n Composer,\n EnvironmentConfiguration,\n ErrorScreen,\n EulXYZ,\n GroundPlane,\n Key,\n KeyInputManager,\n LoadingScreen,\n LoadingScreenConfig,\n MMLCompositionScene,\n TimeManager,\n TweakPane,\n SpawnConfiguration,\n SpawnConfigurationState,\n Vect3,\n VirtualJoystick,\n Character,\n Quat,\n getSpawnData,\n} from \"@mml-io/3d-web-client-core\";\nimport {\n FROM_SERVER_CHAT_MESSAGE_TYPE,\n FROM_CLIENT_CHAT_MESSAGE_TYPE,\n ClientChatMessage,\n UserData,\n UserNetworkingClient,\n UserNetworkingClientUpdate,\n WebsocketStatus,\n parseServerChatMessage,\n DeltaNetV01ServerErrors,\n NetworkUpdate,\n SERVER_BROADCAST_MESSAGE_TYPE,\n ServerBroadcastMessage,\n parseServerBroadcastMessage,\n} from \"@mml-io/3d-web-user-networking\";\nimport {\n IMMLScene,\n LoadingProgressManager,\n registerCustomElementsToWindow,\n setGlobalDocumentTimeManager,\n setGlobalMMLScene,\n} from \"@mml-io/mml-web\";\nimport { Scene, AudioListener, Vector3 } from \"three\";\n\nimport { AvatarSelectionUI, AvatarConfiguration } from \"./avatar-selection-ui\";\nimport { StringToHslOptions, TextChatUI, TextChatUIProps } from \"./chat-ui\";\nimport styles from \"./Networked3dWebExperience.module.css\";\n\ntype MMLDocumentConfiguration = {\n url: string;\n position?: {\n x: number;\n y: number;\n z: number;\n };\n rotation?: {\n x: number;\n y: number;\n z: number;\n };\n scale?: {\n x: number;\n y: number;\n z: number;\n };\n};\n\nexport type Networked3dWebExperienceClientConfig = {\n userNetworkAddress: string;\n sessionToken: string;\n chatVisibleByDefault?: boolean;\n userNameToColorOptions?: StringToHslOptions;\n animationConfig: AnimationConfig;\n voiceChatAddress?: string;\n updateURLLocation?: boolean;\n onServerBroadcast?: (broadcast: ServerBroadcastMessage) => void;\n loadingScreen?: LoadingScreenConfig;\n} & UpdatableConfig;\n\nexport type UpdatableConfig = {\n enableChat?: boolean;\n mmlDocuments?: { [key: string]: MMLDocumentConfiguration };\n environmentConfiguration?: EnvironmentConfiguration;\n spawnConfiguration?: SpawnConfiguration;\n avatarConfiguration?: AvatarConfiguration;\n allowCustomDisplayName?: boolean;\n enableTweakPane?: boolean;\n allowOrbitalCamera?: boolean;\n postProcessingEnabled?: boolean;\n};\n\nfunction normalizeSpawnConfiguration(spawnConfig?: SpawnConfiguration): SpawnConfigurationState {\n return {\n spawnPosition: {\n x: spawnConfig?.spawnPosition?.x ?? 0,\n y: spawnConfig?.spawnPosition?.y ?? 0,\n z: spawnConfig?.spawnPosition?.z ?? 0,\n },\n spawnPositionVariance: {\n x: spawnConfig?.spawnPositionVariance?.x ?? 0,\n y: spawnConfig?.spawnPositionVariance?.y ?? 0,\n z: spawnConfig?.spawnPositionVariance?.z ?? 0,\n },\n spawnYRotation: spawnConfig?.spawnYRotation ?? 0,\n respawnTrigger: {\n minX: spawnConfig?.respawnTrigger?.minX ?? Number.NEGATIVE_INFINITY,\n maxX: spawnConfig?.respawnTrigger?.maxX ?? Number.POSITIVE_INFINITY,\n minY: spawnConfig?.respawnTrigger?.minY ?? -100,\n maxY: spawnConfig?.respawnTrigger?.maxY ?? Number.POSITIVE_INFINITY,\n minZ: spawnConfig?.respawnTrigger?.minZ ?? Number.NEGATIVE_INFINITY,\n maxZ: spawnConfig?.respawnTrigger?.maxZ ?? Number.POSITIVE_INFINITY,\n },\n enableRespawnButton: spawnConfig?.enableRespawnButton ?? false,\n };\n}\n\nexport class Networked3dWebExperienceClient {\n private element: HTMLDivElement;\n private canvasHolder: HTMLDivElement;\n\n private scene: Scene = new Scene();\n private composer: Composer;\n private tweakPane: TweakPane | null = null;\n private audioListener = new AudioListener();\n\n private cameraManager: CameraManager;\n\n private collisionsManager: CollisionsManager;\n\n private characterModelLoader: CharacterModelLoader;\n private characterManager: CharacterManager;\n\n private timeManager = new TimeManager();\n\n private keyInputManager = new KeyInputManager();\n private virtualJoystick: VirtualJoystick;\n\n private mmlCompositionScene: MMLCompositionScene;\n private mmlFrames: { [key: string]: HTMLElement } = {};\n\n private clientId: number | null = null;\n private networkClient: UserNetworkingClient;\n private remoteUserStates = new Map<number, UserNetworkingClientUpdate>();\n private userProfiles = new Map<number, UserData>();\n\n private textChatUI: TextChatUI | null = null;\n\n private avatarSelectionUI: AvatarSelectionUI | null = null;\n\n private readonly latestCharacterObject = {\n characterState: null as null | CharacterState,\n };\n private characterControllerPaneSet: boolean = false;\n\n private spawnConfiguration: SpawnConfigurationState;\n\n private initialLoadCompleted = false;\n private loadingProgressManager = new LoadingProgressManager();\n private loadingScreen: LoadingScreen;\n private errorScreen?: ErrorScreen;\n private groundPlane: GroundPlane | null = null;\n private respawnButton: HTMLDivElement | null = null;\n\n private currentRequestAnimationFrame: number | null = null;\n\n constructor(\n private holderElement: HTMLElement,\n private config: Networked3dWebExperienceClientConfig,\n ) {\n this.element = document.createElement(\"div\");\n this.element.style.position = \"absolute\";\n this.element.style.width = \"100%\";\n this.element.style.height = \"100%\";\n this.holderElement.appendChild(this.element);\n\n document.addEventListener(\"mousedown\", () => {\n if (this.audioListener.context.state === \"suspended\") {\n this.audioListener.context.resume();\n }\n });\n\n this.canvasHolder = document.createElement(\"div\");\n this.canvasHolder.style.position = \"absolute\";\n this.canvasHolder.style.width = \"100%\";\n this.canvasHolder.style.height = \"100%\";\n this.element.appendChild(this.canvasHolder);\n\n this.collisionsManager = new CollisionsManager(this.scene);\n this.cameraManager = new CameraManager(this.canvasHolder, this.collisionsManager);\n this.cameraManager.camera.add(this.audioListener);\n this.characterModelLoader = new CharacterModelLoader();\n\n this.virtualJoystick = new VirtualJoystick(this.element, {\n radius: 70,\n innerRadius: 20,\n mouseSupport: false,\n });\n\n this.composer = new Composer({\n scene: this.scene,\n cameraManager: this.cameraManager,\n spawnSun: true,\n environmentConfiguration: this.config.environmentConfiguration,\n postProcessingEnabled: this.config.postProcessingEnabled,\n });\n this.canvasHolder.appendChild(this.composer.renderer.domElement);\n\n if (this.config.enableTweakPane !== false) {\n this.setupTweakPane();\n }\n\n const resizeObserver = new ResizeObserver(() => {\n this.composer.fitContainer();\n });\n resizeObserver.observe(this.element);\n\n this.spawnConfiguration = normalizeSpawnConfiguration(this.config.spawnConfiguration);\n\n const spawnData = getSpawnData(this.spawnConfiguration, true);\n const spawnRotation = new Quat().setFromEulerXYZ(spawnData.spawnRotation);\n\n const initialNetworkLoadRef = {};\n this.loadingProgressManager.addLoadingAsset(initialNetworkLoadRef, \"network\", \"network\");\n this.networkClient = new UserNetworkingClient(\n {\n url: this.config.userNetworkAddress,\n sessionToken: this.config.sessionToken,\n websocketFactory: (url: string) => new WebSocket(url, \"delta-net-v0.1\"),\n statusUpdateCallback: (status: WebsocketStatus) => {\n console.log(`Websocket status: ${status}`);\n if (status === WebsocketStatus.Disconnected || status === WebsocketStatus.Reconnecting) {\n // The connection was lost after being established - the connection may be re-established with a different client ID\n this.characterManager.clear();\n this.remoteUserStates.clear();\n this.clientId = null;\n }\n },\n assignedIdentity: (clientId: number) => {\n console.log(`Assigned ID: ${clientId}`);\n this.clientId = clientId;\n if (this.initialLoadCompleted) {\n // Already loaded - respawn the character\n const spawnData = getSpawnData(this.spawnConfiguration, true);\n this.spawnCharacter(spawnData);\n } else {\n this.loadingProgressManager.completedLoadingAsset(initialNetworkLoadRef);\n }\n },\n onUpdate: (update: NetworkUpdate): void => {\n this.onNetworkUpdate(update);\n },\n onServerError: (error: { message: string; errorType: string }) => {\n switch (error.errorType) {\n case DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE:\n this.disposeWithError(error.message);\n break;\n case DeltaNetV01ServerErrors.USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE:\n this.disposeWithError(error.message);\n break;\n case DeltaNetV01ServerErrors.USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE:\n this.disposeWithError(error.message || \"Server shutdown\");\n break;\n default:\n console.error(`Unhandled server error: ${error.message}`);\n this.disposeWithError(error.message);\n }\n },\n onCustomMessage: (customType: number, contents: string) => {\n if (customType === SERVER_BROADCAST_MESSAGE_TYPE) {\n const serverBroadcastMessage = parseServerBroadcastMessage(contents);\n if (serverBroadcastMessage instanceof Error) {\n console.error(`Invalid server broadcast message: ${contents}`);\n } else {\n this.config.onServerBroadcast?.(serverBroadcastMessage);\n }\n } else if (customType === FROM_SERVER_CHAT_MESSAGE_TYPE) {\n const serverChatMessage = parseServerChatMessage(contents);\n if (serverChatMessage instanceof Error) {\n console.error(`Invalid server chat message: ${contents}`);\n } else {\n this.handleChatMessage(serverChatMessage.fromUserId, serverChatMessage.message);\n }\n } else {\n console.warn(`Did not recognize custom message type ${customType}`);\n }\n },\n },\n {\n username: null,\n characterDescription: null,\n colors: null,\n },\n {\n position: spawnData.spawnPosition,\n rotation: {\n quaternionY: spawnRotation.y,\n quaternionW: spawnRotation.w,\n },\n state: 0,\n },\n );\n\n if (this.config.allowOrbitalCamera) {\n this.keyInputManager.createKeyBinding(Key.C, () => {\n if (document.activeElement === document.body) {\n // No input is selected - accept the key press\n this.cameraManager.toggleFlyCamera();\n this.composer.fitContainer();\n }\n });\n }\n\n const animationsPromise = Character.loadAnimations(\n this.characterModelLoader,\n this.config.animationConfig,\n );\n\n this.characterManager = new CharacterManager({\n composer: this.composer,\n characterModelLoader: this.characterModelLoader,\n collisionsManager: this.collisionsManager,\n cameraManager: this.cameraManager,\n timeManager: this.timeManager,\n keyInputManager: this.keyInputManager,\n virtualJoystick: this.virtualJoystick,\n remoteUserStates: this.remoteUserStates,\n sendUpdate: (characterState: CharacterState) => {\n this.latestCharacterObject.characterState = characterState;\n this.networkClient.sendUpdate(characterState);\n },\n sendLocalCharacterColors: (colors: Array<[number, number, number]>) => {\n this.networkClient.updateColors(colors);\n },\n animationsPromise: animationsPromise,\n spawnConfiguration: this.spawnConfiguration,\n characterResolve: (characterId: number) => {\n return this.resolveCharacterData(characterId);\n },\n updateURLLocation: this.config.updateURLLocation !== false,\n });\n this.scene.add(this.characterManager.group);\n\n if (this.spawnConfiguration.enableRespawnButton) {\n this.respawnButton = this.createRespawnButton();\n this.element.appendChild(this.respawnButton);\n }\n\n this.setGroundPlaneEnabled(this.config.environmentConfiguration?.groundPlane ?? true);\n\n this.setupMMLScene();\n\n this.loadingScreen = new LoadingScreen(this.loadingProgressManager, this.config.loadingScreen);\n this.element.append(this.loadingScreen.element);\n\n this.loadingProgressManager.addProgressCallback(() => {\n const [, completed] = this.loadingProgressManager.toRatio();\n if (completed && !this.initialLoadCompleted) {\n this.initialLoadCompleted = true;\n /*\n When all content (in particular MML) has loaded, spawn the character (this is to avoid the character falling\n through as-yet-unloaded geometry)\n */\n\n this.connectToTextChat();\n this.mountAvatarSelectionUI();\n this.spawnCharacter(spawnData);\n }\n });\n this.loadingProgressManager.setInitialLoad(true);\n }\n\n private setGroundPlaneEnabled(enabled: boolean) {\n if (enabled && this.groundPlane === null) {\n this.groundPlane = new GroundPlane();\n this.collisionsManager.addMeshesGroup(this.groundPlane);\n this.scene.add(this.groundPlane);\n } else if (!enabled && this.groundPlane !== null) {\n this.collisionsManager.removeMeshesGroup(this.groundPlane);\n this.scene.remove(this.groundPlane);\n this.groundPlane = null;\n }\n }\n\n public updateConfig(config: Partial<UpdatableConfig>) {\n this.config = {\n ...this.config,\n ...config,\n };\n if (config.environmentConfiguration) {\n this.composer.updateEnvironmentConfiguration(config.environmentConfiguration);\n this.setGroundPlaneEnabled(config.environmentConfiguration.groundPlane ?? true);\n }\n\n if (this.avatarSelectionUI) {\n if (config.avatarConfiguration) {\n this.avatarSelectionUI.updateAvatarConfig(config.avatarConfiguration);\n }\n this.avatarSelectionUI.updateAllowCustomDisplayName(config.allowCustomDisplayName || false);\n }\n\n if (config.enableTweakPane !== undefined) {\n if (config.enableTweakPane === false && this.tweakPane !== null) {\n this.tweakPane.dispose();\n this.tweakPane = null;\n } else if (config.enableTweakPane === true && this.tweakPane === null) {\n this.setupTweakPane();\n }\n }\n\n if (this.config.postProcessingEnabled !== undefined) {\n this.composer.togglePostProcessing(this.config.postProcessingEnabled);\n if (this.tweakPane) {\n this.tweakPane.dispose();\n this.tweakPane = null;\n this.setupTweakPane();\n }\n }\n\n if (config.allowOrbitalCamera !== undefined) {\n if (config.allowOrbitalCamera === false) {\n this.keyInputManager.removeKeyBinding(Key.C);\n if (this.cameraManager.isFlyCameraOn() === true) {\n // Disable the fly camera if it was enabled\n this.cameraManager.toggleFlyCamera();\n }\n } else if (config.allowOrbitalCamera === true) {\n this.keyInputManager.createKeyBinding(Key.C, () => {\n if (document.activeElement === document.body) {\n // No input is selected - accept the key press\n this.cameraManager.toggleFlyCamera();\n this.composer.fitContainer();\n }\n });\n }\n }\n\n if (config.enableChat) {\n if (!config.enableChat && this.textChatUI !== null) {\n this.textChatUI.dispose();\n this.textChatUI = null;\n } else {\n this.connectToTextChat();\n }\n }\n\n this.spawnConfiguration = normalizeSpawnConfiguration(config.spawnConfiguration);\n if (this.characterManager.localController) {\n this.characterManager.localController.updateSpawnConfig(this.spawnConfiguration);\n }\n if (this.spawnConfiguration.enableRespawnButton && !this.respawnButton) {\n this.respawnButton = this.createRespawnButton();\n this.element.appendChild(this.respawnButton);\n } else if (!this.spawnConfiguration.enableRespawnButton && this.respawnButton) {\n this.respawnButton.remove();\n this.respawnButton = null;\n }\n\n if (config.mmlDocuments) {\n this.setMMLDocuments(config.mmlDocuments);\n }\n }\n\n static createFullscreenHolder(): HTMLDivElement {\n document.body.style.margin = \"0\";\n document.body.style.overflow = \"hidden\";\n\n const holder = document.createElement(\"div\");\n holder.style.position = \"absolute\";\n holder.style.width = \"100%\";\n holder.style.height = \"100%\";\n holder.style.overflow = \"hidden\";\n document.body.appendChild(holder);\n return holder;\n }\n\n private createRespawnButton(): HTMLDivElement {\n const respawnButton = document.createElement(\"div\");\n respawnButton.className = styles.respawnButton;\n respawnButton.textContent = \"RESPAWN\";\n respawnButton.addEventListener(\"click\", () => {\n this.characterManager.localController?.resetPosition();\n });\n return respawnButton;\n }\n\n private resolveCharacterData(clientId: number): UserData {\n const user = this.userProfiles.get(clientId)!;\n\n if (!user) {\n throw new Error(`Failed to resolve user for clientId ${clientId}`);\n }\n\n return {\n username: user.username,\n characterDescription: user.characterDescription,\n colors: user.colors,\n };\n }\n\n private onNetworkUpdate(update: NetworkUpdate): void {\n const { removedUserIds, addedUserIds, updatedUsers } = update;\n for (const clientId of removedUserIds) {\n this.userProfiles.delete(clientId);\n this.remoteUserStates.delete(clientId);\n }\n for (const [clientId, userData] of addedUserIds) {\n this.userProfiles.set(clientId, userData.userState);\n this.remoteUserStates.set(clientId, userData.components);\n }\n for (const [clientId, userDataUpdate] of updatedUsers) {\n const userState = userDataUpdate.userState;\n if (userState) {\n if (userState.username !== undefined) {\n this.userProfiles.get(clientId)!.username = userState.username;\n }\n if (userState.characterDescription !== undefined) {\n this.userProfiles.get(clientId)!.characterDescription = userState.characterDescription;\n }\n if (userState.colors !== undefined) {\n this.userProfiles.get(clientId)!.colors = userState.colors;\n }\n this.characterManager.networkCharacterInfoUpdated(clientId);\n }\n this.remoteUserStates.set(clientId, userDataUpdate.components);\n }\n }\n\n private sendIdentityUpdateToServer(\n displayName: string,\n characterDescription: CharacterDescription,\n ) {\n if (!this.clientId) {\n throw new Error(\"Client ID not set\");\n }\n\n this.networkClient.updateUsername(displayName);\n this.networkClient.updateCharacterDescription(characterDescription);\n }\n\n private setupTweakPane() {\n if (this.tweakPane) {\n return;\n }\n\n this.tweakPane = new TweakPane(\n this.element,\n this.composer.renderer,\n this.scene,\n this.composer,\n this.config.postProcessingEnabled,\n );\n this.cameraManager.setupTweakPane(this.tweakPane);\n this.composer.setupTweakPane(this.tweakPane);\n }\n\n private handleChatMessage(fromUserId: number, message: string) {\n if (this.textChatUI === null) {\n return;\n }\n\n if (fromUserId === 0) {\n // Server message - handle as system message\n this.textChatUI.addTextMessage(\"System\", message);\n } else {\n // User message\n const user = this.userProfiles.get(fromUserId);\n if (!user) {\n console.error(`User not found for clientId ${fromUserId}`);\n return;\n }\n const username = user.username ?? `Unknown User ${fromUserId}`;\n this.textChatUI.addTextMessage(username, message);\n this.characterManager.addChatBubble(fromUserId, message);\n }\n }\n\n private connectToTextChat() {\n if (this.clientId === null) {\n return;\n }\n\n if (this.config.enableChat && this.textChatUI === null) {\n const user = this.userProfiles.get(this.clientId);\n if (!user) {\n throw new Error(\"User not found\");\n }\n\n const textChatUISettings: TextChatUIProps = {\n holderElement: this.canvasHolder,\n sendMessageToServerMethod: (message: string) => {\n this.characterManager.addSelfChatBubble(message);\n this.mmlCompositionScene.onChatMessage(message);\n\n // Send chat message through deltanet custom message\n this.networkClient.sendCustomMessage(\n FROM_CLIENT_CHAT_MESSAGE_TYPE,\n JSON.stringify({ message } satisfies ClientChatMessage),\n );\n },\n visibleByDefault: this.config.chatVisibleByDefault,\n stringToHslOptions: this.config.userNameToColorOptions,\n };\n this.textChatUI = new TextChatUI(textChatUISettings);\n this.textChatUI.init();\n }\n }\n\n private mountAvatarSelectionUI() {\n if (this.clientId === null) {\n throw new Error(\"Client ID not set\");\n }\n const ownIdentity = this.userProfiles.get(this.clientId);\n if (!ownIdentity) {\n throw new Error(\"Own identity not found\");\n }\n this.avatarSelectionUI = new AvatarSelectionUI({\n holderElement: this.element,\n visibleByDefault: false,\n displayName: ownIdentity.username ?? `Unknown User ${this.clientId}`,\n characterDescription: ownIdentity.characterDescription ?? {\n meshFileUrl: \"\",\n },\n sendIdentityUpdateToServer: this.sendIdentityUpdateToServer.bind(this),\n availableAvatars: this.config.avatarConfiguration?.availableAvatars ?? [],\n allowCustomAvatars: this.config.avatarConfiguration?.allowCustomAvatars,\n allowCustomDisplayName: this.config.allowCustomDisplayName || false,\n });\n this.avatarSelectionUI.init();\n }\n\n public update(): void {\n this.timeManager.update();\n this.characterManager.update();\n this.cameraManager.update();\n const characterPosition = this.characterManager.localCharacter?.getPosition();\n this.composer.sun?.updateCharacterPosition(\n new Vector3(characterPosition?.x || 0, characterPosition?.y || 0, characterPosition?.z || 0),\n );\n this.composer.render(this.timeManager);\n if (this.tweakPane?.guiVisible) {\n this.tweakPane.updateStats(this.timeManager);\n this.tweakPane.updateCameraData(this.cameraManager);\n if (this.characterManager.localCharacter && this.characterManager.localController) {\n if (!this.characterControllerPaneSet) {\n this.characterControllerPaneSet = true;\n this.characterManager.setupTweakPane(this.tweakPane);\n } else {\n this.tweakPane.updateCharacterData(this.characterManager.localController);\n }\n }\n }\n this.currentRequestAnimationFrame = requestAnimationFrame(() => {\n this.update();\n });\n }\n\n private spawnCharacter({\n spawnPosition,\n spawnRotation,\n cameraPosition,\n }: {\n spawnPosition: Vect3;\n spawnRotation: EulXYZ;\n cameraPosition: Vect3;\n }) {\n if (this.clientId === null) {\n throw new Error(\"Client ID not set\");\n }\n\n const ownIdentity = this.userProfiles.get(this.clientId);\n if (!ownIdentity) {\n throw new Error(\"Own identity not found\");\n }\n\n this.characterManager.spawnLocalCharacter(\n this.clientId!,\n ownIdentity.username ?? `Unknown User ${this.clientId}`,\n ownIdentity.characterDescription,\n spawnPosition,\n spawnRotation,\n );\n\n if (cameraPosition !== null) {\n this.cameraManager.camera.position.set(cameraPosition.x, cameraPosition.y, cameraPosition.z);\n this.cameraManager.setTarget(\n new Vect3().add(spawnPosition).add(CharacterManager.headTargetOffset),\n );\n this.cameraManager.reverseUpdateFromPositions();\n }\n }\n\n private disposeWithError(message: string) {\n this.dispose();\n this.errorScreen = new ErrorScreen(\"An error occurred\", message);\n this.element.append(this.errorScreen.element);\n }\n\n public dispose() {\n this.characterManager.dispose();\n this.networkClient.stop();\n for (const [key, element] of Object.entries(this.mmlFrames)) {\n element.remove();\n }\n this.mmlFrames = {};\n this.textChatUI?.dispose();\n this.mmlCompositionScene.dispose();\n this.composer.dispose();\n this.tweakPane?.dispose();\n if (this.currentRequestAnimationFrame !== null) {\n cancelAnimationFrame(this.currentRequestAnimationFrame);\n this.currentRequestAnimationFrame = null;\n }\n this.cameraManager.dispose();\n this.loadingScreen.dispose();\n this.errorScreen?.dispose();\n }\n\n private setupMMLScene() {\n registerCustomElementsToWindow(window);\n this.mmlCompositionScene = new MMLCompositionScene({\n targetElement: this.element,\n renderer: this.composer.renderer,\n scene: this.scene,\n camera: this.cameraManager.camera,\n audioListener: this.audioListener,\n collisionsManager: this.collisionsManager,\n getUserPositionAndRotation: () => {\n return this.characterManager.getLocalCharacterPositionAndRotation();\n },\n });\n this.scene.add(this.mmlCompositionScene.group);\n setGlobalMMLScene(this.mmlCompositionScene.mmlScene as IMMLScene);\n setGlobalDocumentTimeManager(this.mmlCompositionScene.documentTimeManager);\n\n this.setMMLDocuments(this.config.mmlDocuments ?? {});\n\n const mmlProgressManager = this.mmlCompositionScene.mmlScene.getLoadingProgressManager!()!;\n this.loadingProgressManager.addLoadingDocument(mmlProgressManager, \"mml\", mmlProgressManager);\n mmlProgressManager.addProgressCallback(() => {\n this.loadingProgressManager.updateDocumentProgress(mmlProgressManager);\n });\n mmlProgressManager.setInitialLoad(true);\n }\n\n private createFrame(mmlDocument: MMLDocumentConfiguration) {\n const frameElement = document.createElement(\"m-frame\");\n frameElement.setAttribute(\"src\", mmlDocument.url);\n this.updateFrameAttributes(frameElement, mmlDocument);\n return frameElement;\n }\n\n private updateFrameAttributes(frameElement: HTMLElement, mmlDocument: MMLDocumentConfiguration) {\n const existingSrc = frameElement.getAttribute(\"src\");\n if (existingSrc !== mmlDocument.url) {\n frameElement.setAttribute(\"src\", mmlDocument.url);\n }\n if (mmlDocument.position) {\n frameElement.setAttribute(\"x\", mmlDocument.position.x.toString());\n frameElement.setAttribute(\"y\", mmlDocument.position.y.toString());\n frameElement.setAttribute(\"z\", mmlDocument.position.z.toString());\n } else {\n frameElement.setAttribute(\"x\", \"0\");\n frameElement.setAttribute(\"y\", \"0\");\n frameElement.setAttribute(\"z\", \"0\");\n }\n if (mmlDocument.rotation) {\n frameElement.setAttribute(\"rx\", mmlDocument.rotation.x.toString());\n frameElement.setAttribute(\"ry\", mmlDocument.rotation.y.toString());\n frameElement.setAttribute(\"rz\", mmlDocument.rotation.z.toString());\n } else {\n frameElement.setAttribute(\"rx\", \"0\");\n frameElement.setAttribute(\"ry\", \"0\");\n frameElement.setAttribute(\"rz\", \"0\");\n }\n if (mmlDocument.scale?.x !== undefined) {\n frameElement.setAttribute(\"sx\", mmlDocument.scale.x.toString());\n } else {\n frameElement.setAttribute(\"sx\", \"1\");\n }\n if (mmlDocument.scale?.y !== undefined) {\n frameElement.setAttribute(\"sy\", mmlDocument.scale.y.toString());\n } else {\n frameElement.setAttribute(\"sy\", \"1\");\n }\n if (mmlDocument.scale?.z !== undefined) {\n frameElement.setAttribute(\"sz\", mmlDocument.scale.z.toString());\n } else {\n frameElement.setAttribute(\"sz\", \"1\");\n }\n }\n\n private setMMLDocuments(mmlDocuments: { [key: string]: MMLDocumentConfiguration }) {\n const newFramesMap: { [key: string]: HTMLElement } = {};\n for (const [key, mmlDocSpec] of Object.entries(mmlDocuments)) {\n const existing = this.mmlFrames[key];\n if (!existing) {\n const frameElement = this.createFrame(mmlDocSpec);\n document.body.appendChild(frameElement);\n newFramesMap[key] = frameElement;\n } else {\n delete this.mmlFrames[key];\n newFramesMap[key] = existing;\n this.updateFrameAttributes(existing, mmlDocSpec);\n }\n }\n for (const [key, element] of Object.entries(this.mmlFrames)) {\n element.remove();\n }\n this.mmlFrames = newFramesMap;\n }\n}\n", "import * as React from \"react\";\nimport { forwardRef } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { createRoot, Root } from \"react-dom/client\";\n\nimport { AvatarConfiguration, AvatarType } from \"./AvatarType\";\nimport { AvatarSelectionUIComponent } from \"./components/AvatarPanel/AvatarSectionUIComponent\";\n\nconst ForwardedAvatarSelectionUIComponent = forwardRef(AvatarSelectionUIComponent);\n\nexport type AvatarSelectionUIProps = {\n holderElement: HTMLElement;\n visibleByDefault?: boolean;\n displayName: string;\n characterDescription: AvatarType;\n allowCustomDisplayName: boolean;\n sendIdentityUpdateToServer: (displayName: string, characterDescription: AvatarType) => void;\n} & AvatarConfiguration;\n\nexport class AvatarSelectionUI {\n private root: Root;\n\n private wrapper = document.createElement(\"div\");\n\n constructor(private config: AvatarSelectionUIProps) {\n this.config.holderElement.appendChild(this.wrapper);\n this.root = createRoot(this.wrapper);\n }\n\n private onUpdateUserAvatar = (avatar: AvatarType) => {\n this.config.characterDescription = avatar;\n this.config.sendIdentityUpdateToServer(this.config.displayName, avatar);\n };\n\n private onUpdateDisplayName = (displayName: string) => {\n this.config.displayName = displayName;\n this.config.sendIdentityUpdateToServer(displayName, this.config.characterDescription);\n };\n\n public updateAvatarConfig(avatarConfig: AvatarConfiguration) {\n this.config = {\n ...this.config,\n ...avatarConfig,\n };\n this.init();\n }\n\n public updateAllowCustomDisplayName(allowCustomDisplayName: boolean) {\n this.config = {\n ...this.config,\n allowCustomDisplayName,\n };\n this.init();\n }\n\n init() {\n flushSync(() =>\n this.root.render(\n <ForwardedAvatarSelectionUIComponent\n onUpdateUserAvatar={this.onUpdateUserAvatar}\n onUpdateDisplayName={this.onUpdateDisplayName}\n visibleByDefault={this.config.visibleByDefault}\n displayName={this.config.displayName}\n characterDescription={this.config.characterDescription}\n availableAvatars={this.config.availableAvatars}\n allowCustomAvatars={this.config.allowCustomAvatars || false}\n allowCustomDisplayName={this.config.allowCustomDisplayName || false}\n />,\n ),\n );\n }\n}\n", "import React, {\n ForwardRefRenderFunction,\n KeyboardEvent,\n MouseEvent,\n useRef,\n useState,\n} from \"react\";\n\nimport { AvatarType } from \"../../AvatarType\";\nimport AvatarIcon from \"../../icons/Avatar.svg\";\n\nimport styles from \"./AvatarSelectionUIComponent.module.css\";\n\ntype AvatarSelectionUIProps = {\n onUpdateUserAvatar: (avatar: AvatarType) => void;\n visibleByDefault?: boolean;\n availableAvatars: AvatarType[];\n\n characterDescription: AvatarType;\n allowCustomAvatars: boolean;\n\n displayName: string;\n allowCustomDisplayName: boolean;\n onUpdateDisplayName: (displayNameValue: string) => void;\n};\n\nenum CustomAvatarType {\n meshFileUrl,\n mmlUrl,\n mml,\n}\n\nfunction SelectedPill() {\n return <span className={styles.selectedPill}>Selected</span>;\n}\n\nexport const AvatarSelectionUIComponent: ForwardRefRenderFunction<any, AvatarSelectionUIProps> = (\n props: AvatarSelectionUIProps,\n) => {\n const visibleByDefault: boolean = props.visibleByDefault ?? false;\n const [isVisible, setIsVisible] = useState<boolean>(visibleByDefault);\n const [selectedAvatar, setSelectedAvatar] = useState<AvatarType | undefined>(\n props.characterDescription,\n );\n const [customAvatarType, setCustomAvatarType] = useState<CustomAvatarType>(\n CustomAvatarType.mmlUrl,\n );\n const [customAvatarValue, setCustomAvatarValue] = useState<string>(\"\");\n const inputRef = useRef<HTMLInputElement>(null);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n const [displayNameValue, setDisplayNameValue] = useState<string>(props.displayName);\n const displayNameRef = useRef<HTMLInputElement>(null);\n\n const handleRootClick = (e: MouseEvent) => {\n e.stopPropagation();\n };\n\n const selectAvatar = (avatar: AvatarType) => {\n setSelectedAvatar(avatar);\n props.onUpdateUserAvatar(avatar);\n };\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n setCustomAvatarValue(e.target.value);\n };\n\n const handleDisplayNameChange = (\n e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,\n ) => {\n setDisplayNameValue(e.target.value);\n };\n\n const setDisplayName = () => {\n if (!displayNameValue) {\n return;\n }\n props.onUpdateDisplayName(displayNameValue);\n };\n\n const addCustomAvatar = () => {\n if (!customAvatarValue) {\n return;\n }\n\n let newSelectedAvatar: AvatarType;\n switch (customAvatarType) {\n case CustomAvatarType.mml:\n newSelectedAvatar = {\n mmlCharacterString: customAvatarValue,\n };\n break;\n case CustomAvatarType.mmlUrl:\n newSelectedAvatar = {\n mmlCharacterUrl: customAvatarValue,\n };\n break;\n case CustomAvatarType.meshFileUrl:\n newSelectedAvatar = {\n meshFileUrl: customAvatarValue,\n };\n break;\n }\n\n setSelectedAvatar(newSelectedAvatar);\n props.onUpdateUserAvatar(newSelectedAvatar);\n };\n\n const handleKeyPress = (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n e.stopPropagation();\n };\n\n const handleAvatarInputKeyPress = (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n e.stopPropagation();\n if (e.key === \"Enter\") {\n addCustomAvatar();\n }\n };\n\n const handleDisplayNameKeyPress = (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n e.stopPropagation();\n if (e.key === \"Enter\") {\n setDisplayName();\n }\n };\n\n const handleTypeSwitch = (type: CustomAvatarType) => {\n setCustomAvatarType(type);\n setCustomAvatarValue(\"\");\n };\n\n const getPlaceholderByType = (type: CustomAvatarType) => {\n switch (type) {\n case CustomAvatarType.meshFileUrl:\n return \"https://.../avatar.glb\";\n case CustomAvatarType.mmlUrl:\n return \"https://.../avatar.html\";\n case CustomAvatarType.mml:\n return '<m-character src=\"https://link-to-avatar\">\\n</m-character';\n }\n };\n\n if (\n !props.availableAvatars.length &&\n !props.allowCustomAvatars &&\n !props.allowCustomDisplayName\n ) {\n return null;\n }\n\n let recognizedAvatar = false;\n\n return (\n <>\n <div className={styles.menuButton} onClick={handleRootClick}>\n {!isVisible && (\n <div className={styles.openTab} onClick={() => setIsVisible(true)}>\n <img src={`data:image/svg+xml;utf8,${encodeURIComponent(AvatarIcon)}`} />\n </div>\n )}\n {isVisible && (\n <button className={styles.closeButton} onClick={(e) => setIsVisible(false)}>\n X\n </button>\n )}\n </div>\n {isVisible && (\n <div className={`${styles.avatarSelectionContainer}`}>\n {props.allowCustomDisplayName && (\n <div className={styles.displayNameSection}>\n <div className={styles.sectionHeading}>Display Name</div>\n <div className={styles.displayNameInputSection}>\n <input\n ref={displayNameRef}\n className={styles.input}\n value={displayNameValue}\n onKeyDown={handleDisplayNameKeyPress}\n onChange={handleDisplayNameChange}\n placeholder={\"Enter your display name\"}\n />\n <button\n className={styles.setButton}\n disabled={!displayNameValue}\n type=\"button\"\n onClick={setDisplayName}\n >\n Set\n </button>\n </div>\n </div>\n )}\n {!!props.availableAvatars.length && (\n <div className={styles.avatarSelectionSection}>\n <div className={styles.sectionHeading}>Choose your Avatar</div>\n <div className={styles.avatarSelectionUi}>\n {props.availableAvatars.map((avatar, index) => {\n const isSelected =\n (selectedAvatar?.meshFileUrl &&\n selectedAvatar?.meshFileUrl === avatar.meshFileUrl) ||\n (selectedAvatar?.mmlCharacterUrl &&\n selectedAvatar?.mmlCharacterUrl === avatar.mmlCharacterUrl) ||\n (selectedAvatar?.mmlCharacterString &&\n selectedAvatar?.mmlCharacterString === avatar.mmlCharacterString);\n\n if (isSelected) {\n recognizedAvatar = true;\n }\n\n return (\n <div\n key={index}\n className={styles.avatarSelectionUiAvatar}\n onClick={() => selectAvatar(avatar)}\n >\n <div className={styles.avatarSelectionUiAvatarImgContainer}>\n {isSelected && <SelectedPill />}\n {avatar.thumbnailUrl ? (\n <img\n className={styles.avatarSelectionUiAvatarImage}\n src={avatar.thumbnailUrl}\n alt={avatar.name}\n />\n ) : (\n <div className={styles.avatarSelectionNoImage}>\n <img\n alt={avatar.name}\n src={`data:image/svg+xml;utf8,${encodeURIComponent(AvatarIcon)}`}\n />\n </div>\n )}\n <p>{avatar.name}</p>\n <span className={styles.tooltipText}>{avatar.name}</span>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n )}\n {props.allowCustomAvatars && (\n <div className={styles.customAvatarSection}>\n <div className={styles.sectionHeading}>Custom Avatar</div>\n <div className={styles.radioGroup}>\n <div className={styles.radioItem}>\n <input\n type=\"radio\"\n id=\"html\"\n name=\"customAvatarType\"\n onChange={() => handleTypeSwitch(CustomAvatarType.mmlUrl)}\n checked={customAvatarType === CustomAvatarType.mmlUrl}\n />\n <label htmlFor=\"html\">MML URL</label>\n </div>\n <div className={styles.radioItem}>\n <input\n type=\"radio\"\n id=\"mml\"\n name=\"customAvatarType\"\n onChange={() => handleTypeSwitch(CustomAvatarType.mml)}\n checked={customAvatarType === CustomAvatarType.mml}\n />\n <label htmlFor=\"mml\">MML</label>\n </div>\n <div className={styles.radioItem}>\n <input\n type=\"radio\"\n id=\"glb\"\n name=\"customAvatarType\"\n onChange={() => handleTypeSwitch(CustomAvatarType.meshFileUrl)}\n checked={customAvatarType === CustomAvatarType.meshFileUrl}\n />\n <label htmlFor=\"glb\">Mesh URL</label>\n </div>\n {!recognizedAvatar && <SelectedPill />}\n </div>\n <div className={styles.customAvatarInputSection}>\n {customAvatarType === CustomAvatarType.mml ? (\n <textarea\n ref={textareaRef}\n className={styles.input}\n value={customAvatarValue}\n onChange={handleInputChange}\n onKeyDown={handleKeyPress}\n placeholder={getPlaceholderByType(customAvatarType)}\n rows={4}\n />\n ) : (\n <input\n ref={inputRef}\n className={styles.input}\n value={customAvatarValue}\n onKeyDown={handleAvatarInputKeyPress}\n onChange={handleInputChange}\n placeholder={getPlaceholderByType(customAvatarType)}\n />\n )}\n <button\n className={styles.setButton}\n disabled={!customAvatarValue}\n type=\"button\"\n onClick={addCustomAvatar}\n >\n Set\n </button>\n </div>\n </div>\n )}\n </div>\n )}\n </>\n );\n};\n", "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448 512\"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d=\"M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512l388.6 0c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304l-91.4 0z\"/></svg>\n", "\nconst content = __content_placeholder__;\nconst digest = __digest_placeholder__; \nconst inject = () => {\n setTimeout(() => {\n if (!globalThis.document) {\n return;\n }\n let root = globalThis.document.querySelector(\"head\");\n if (root && root.shadowRoot) {\n root = root.shadowRoot;\n }\n if (!root) {\n root = globalThis.document.head;\n }\n let container = root.querySelector(\"#_\" + digest);\n if (!container) {\n container = globalThis.document.createElement(\"style\");\n container.id = \"_\" + digest;\n const text = globalThis.document.createTextNode(content);\n container.appendChild(text);\n root.appendChild(container);\n }\n }, 0);\n};\n\nexport { inject };\n ", "import \"esbuild-css-modules-plugin-ns-css:src/avatar-selection-ui/components/AvatarPanel/AvatarSelectionUIComponent.module.css\";\n\nimport { inject } from \"esbuild-css-modules-plugin-ns-js:src/avatar-selection-ui/components/AvatarPanel/AvatarSelectionUIComponent.module.css:injector.js\";\nexport default new Proxy({\n \"avatarSelectionContainer\": \"AvatarSelectionUIComponent-module__avatarSelectionContainer_VjZ7cq__0230\",\n \"avatarSelectionNoImage\": \"AvatarSelectionUIComponent-module__avatarSelectionNoImage_VjZ7cq__0230\",\n \"avatarSelectionSection\": \"AvatarSelectionUIComponent-module__avatarSelectionSection_VjZ7cq__0230\",\n \"avatarSelectionUi\": \"AvatarSelectionUIComponent-module__avatarSelectionUi_VjZ7cq__0230\",\n \"avatarSelectionUiAvatar\": \"AvatarSelectionUIComponent-module__avatarSelectionUiAvatar_VjZ7cq__0230\",\n \"avatarSelectionUiAvatarImage\": \"AvatarSelectionUIComponent-module__avatarSelectionUiAvatarImage_VjZ7cq__0230\",\n \"avatarSelectionUiAvatarImgContainer\": \"AvatarSelectionUIComponent-module__avatarSelectionUiAvatarImgContainer_VjZ7cq__0230\",\n \"avatarSelectionUiCloseButton\": \"AvatarSelectionUIComponent-module__avatarSelectionUiCloseButton_VjZ7cq__0230\",\n \"avatarSelectionUiHeader\": \"AvatarSelectionUIComponent-module__avatarSelectionUiHeader_VjZ7cq__0230\",\n \"closeButton\": \"AvatarSelectionUIComponent-module__closeButton_VjZ7cq__0230\",\n \"customAvatarInputSection\": \"AvatarSelectionUIComponent-module__customAvatarInputSection_VjZ7cq__0230\",\n \"customAvatarSection\": \"AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0230\",\n \"displayNameInputSection\": \"AvatarSelectionUIComponent-module__displayNameInputSection_VjZ7cq__0230\",\n \"displayNameSection\": \"AvatarSelectionUIComponent-module__displayNameSection_VjZ7cq__0230\",\n \"input\": \"AvatarSelectionUIComponent-module__input_VjZ7cq__0230\",\n \"menuButton\": \"AvatarSelectionUIComponent-module__menuButton_VjZ7cq__0230\",\n \"openTab\": \"AvatarSelectionUIComponent-module__openTab_VjZ7cq__0230\",\n \"radioGroup\": \"AvatarSelectionUIComponent-module__radioGroup_VjZ7cq__0230\",\n \"radioItem\": \"AvatarSelectionUIComponent-module__radioItem_VjZ7cq__0230\",\n \"sectionHeading\": \"AvatarSelectionUIComponent-module__sectionHeading_VjZ7cq__0230\",\n \"selectedPill\": \"AvatarSelectionUIComponent-module__selectedPill_VjZ7cq__0230\",\n \"setButton\": \"AvatarSelectionUIComponent-module__setButton_VjZ7cq__0230\",\n \"tooltipText\": \"AvatarSelectionUIComponent-module__tooltipText_VjZ7cq__0230\"\n}, {\n get: function(source, key) {\n inject();\n return source[key];\n }\n});\n ", "import { createRef, forwardRef } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { createRoot, Root } from \"react-dom/client\";\n\nimport { ChatUIComponent } from \"./components/ChatPanel/TextChatUIComponent\";\n\nexport type StringToHslOptions = {\n hueThresholds?: [number, number][];\n saturationThresholds?: [number, number][];\n lightnessThresholds?: [number, number][];\n};\n\nconst DEFAULT_HUE_RANGES: [number, number][] = [[10, 350]];\nconst DEFAULT_SATURATION_RANGES: [number, number][] = [[60, 100]];\nconst DEFAULT_LIGHTNESS_RANGES: [number, number][] = [[65, 75]];\n\nexport const DEFAULT_HSL_OPTIONS: StringToHslOptions = {\n hueThresholds: DEFAULT_HUE_RANGES,\n saturationThresholds: DEFAULT_SATURATION_RANGES,\n lightnessThresholds: DEFAULT_LIGHTNESS_RANGES,\n};\n\nconst ForwardedChatUIComponent = forwardRef(ChatUIComponent);\n\nexport type ChatUIInstance = {\n addMessage: (username: string, message: string) => void;\n};\n\nexport type TextChatUIProps = {\n holderElement: HTMLElement;\n sendMessageToServerMethod: (message: string) => void;\n visibleByDefault?: boolean;\n stringToHslOptions?: StringToHslOptions;\n};\n\nexport class TextChatUI {\n private root: Root;\n private appRef = createRef<ChatUIInstance>();\n\n public addTextMessage(username: string, message: string) {\n if (this.appRef.current) {\n this.appRef.current.addMessage(username, message);\n }\n }\n\n private wrapper = document.createElement(\"div\");\n\n constructor(private config: TextChatUIProps) {\n this.config.holderElement.appendChild(this.wrapper);\n this.root = createRoot(this.wrapper);\n }\n\n dispose() {\n this.root.unmount();\n this.wrapper.remove();\n }\n\n init() {\n flushSync(() =>\n this.root.render(\n <ForwardedChatUIComponent\n ref={this.appRef}\n sendMessageToServer={this.config.sendMessageToServerMethod}\n visibleByDefault={this.config.visibleByDefault}\n stringToHslOptions={this.config.stringToHslOptions}\n />,\n ),\n );\n }\n}\n", "import {\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n ForwardRefRenderFunction,\n MouseEvent,\n} from \"react\";\n\nimport { useClickOutside } from \"../../helpers\";\nimport ChatIcon from \"../../icons/Chat.svg\";\nimport PinButton from \"../../icons/Pin.svg\";\nimport { StringToHslOptions, type ChatUIInstance } from \"../../TextChatUI\";\nimport { InputBox } from \"../Input/InputBox\";\nimport { Messages } from \"../Messages/Messages\";\n\nimport styles from \"./TextChatUIComponent.module.css\";\ntype ChatUIProps = {\n sendMessageToServer: (message: string) => void;\n visibleByDefault?: boolean;\n stringToHslOptions?: StringToHslOptions;\n};\n\nconst MAX_MESSAGES = 50;\nconst SECONDS_TO_FADE_OUT = 6;\nconst AUTO_SCROLL_RESET_DELAY_MS = 100;\n\nexport const ChatUIComponent: ForwardRefRenderFunction<ChatUIInstance, ChatUIProps> = (\n props: ChatUIProps,\n ref,\n) => {\n const visibleByDefault: boolean = props.visibleByDefault ?? true;\n const [messages, setMessages] = useState<Array<{ username: string; message: string }>>([]);\n const [isVisible, setIsVisible] = useState<boolean>(visibleByDefault);\n const [isSticky, setSticky] = useState<boolean>(visibleByDefault);\n const [isFocused, setIsFocused] = useState(false);\n const [isOpenHovered, setOpenHovered] = useState(false);\n const [shouldAutoScroll, setShouldAutoScroll] = useState(false);\n\n const [panelStyle, setPanelStyle] = useState(styles.fadeOut);\n const [stickyStyle, setStickyStyle] = useState(styles.stickyButton);\n\n const stickyButtonRef = useRef<HTMLDivElement>(null);\n const closeButtonRef = useRef<HTMLDivElement>(null);\n const hideTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const inputBoxRef = useRef<{ focusInput: () => void } | null>(null);\n\n const startHideTimeout = useCallback(() => {\n if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = setTimeout(() => {\n if (isVisible) {\n setIsVisible(false);\n }\n }, SECONDS_TO_FADE_OUT * 1000);\n }, [isVisible]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (e.key === \"Enter\") {\n if (!isVisible) setIsVisible(true);\n setIsFocused(true);\n if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);\n if (inputBoxRef.current) inputBoxRef.current.focusInput();\n }\n },\n [isVisible],\n );\n\n const handleBlur = useCallback(() => {\n if (isFocused) setIsFocused(false);\n startHideTimeout();\n if (closeButtonRef.current) closeButtonRef.current.focus();\n }, [isFocused, startHideTimeout]);\n\n const hide = () => {\n setIsVisible(false);\n setIsFocused(false);\n if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);\n };\n\n const handleRootClick = (e: MouseEvent) => {\n e.stopPropagation();\n setOpenHovered(true);\n if (!isVisible) setIsVisible(true);\n };\n\n const handleStickyButton = (e: MouseEvent) => {\n e.stopPropagation();\n setSticky(!isSticky);\n };\n\n const handleWheel = (e: React.WheelEvent) => {\n e.stopPropagation();\n };\n\n const handleMouseLeave = () => {\n setOpenHovered(false);\n if (!isFocused && !isSticky && isVisible) {\n startHideTimeout();\n }\n };\n\n const handleMouseEnter = () => {\n setOpenHovered(true);\n if (!isVisible) setIsVisible(true);\n };\n\n const chatPanelRef = useClickOutside(() => {\n if (isFocused) {\n setIsFocused(false);\n startHideTimeout();\n }\n });\n\n useEffect(() => {\n if (isVisible && isSticky) {\n if (chatPanelRef.current) chatPanelRef.current.style.zIndex = \"100\";\n }\n setPanelStyle(isVisible || isFocused || isSticky ? styles.fadeIn : styles.fadeOut);\n setStickyStyle(\n isSticky\n ? styles.stickyButtonEnabled\n : isOpenHovered\n ? styles.stickyButton\n : styles.stickyButtonFadeOut,\n );\n if (chatPanelRef.current && chatPanelRef.current.style.zIndex !== \"100\") {\n // we just want to change the z-index after the browser has the chance\n // to apply the CSS to the SVG icons\n setTimeout(() => {\n if (chatPanelRef.current) chatPanelRef.current.style.zIndex = \"100\";\n }, 2000);\n }\n }, [isVisible, isSticky, isFocused, chatPanelRef, isOpenHovered]);\n\n const appendMessages = (username: string, message: string) => {\n setMessages((prev) => {\n const newMessages = [...prev, { username, message }];\n return newMessages.length > MAX_MESSAGES ? newMessages.slice(-MAX_MESSAGES) : newMessages;\n });\n };\n\n useImperativeHandle(ref, () => ({\n addMessage: (username: string, message: string) => {\n appendMessages(username, message);\n if (!isVisible) setIsVisible(true);\n startHideTimeout();\n },\n }));\n\n const handleSendMessage = (message: string) => {\n setShouldAutoScroll(true);\n props.sendMessageToServer(message);\n // Reset after a short delay\n setTimeout(() => setShouldAutoScroll(false), AUTO_SCROLL_RESET_DELAY_MS);\n };\n\n const setFocus = () => setIsFocused(true);\n\n useEffect(() => {\n window.addEventListener(\"keydown\", handleKeyDown, false);\n window.addEventListener(\"blur\", handleBlur, false);\n return () => {\n window.removeEventListener(\"keydown\", handleKeyDown, false);\n window.removeEventListener(\"blur\", handleBlur, false);\n };\n }, [handleBlur, handleKeyDown]);\n\n return (\n <div className={styles.textChatUi}>\n <div\n className={styles.uiHover}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onClick={handleRootClick}\n >\n <div className={styles.openTab} onClick={hide}>\n <img src={`data:image/svg+xml;utf8,${encodeURIComponent(ChatIcon)}`} />\n </div>\n <div ref={stickyButtonRef} className={stickyStyle} onClick={handleStickyButton}>\n <img src={`data:image/svg+xml;utf8,${encodeURIComponent(PinButton)}`} />\n </div>\n </div>\n <div\n ref={chatPanelRef}\n style={{ zIndex: -1 }}\n id=\"text-chat-wrapper\"\n className={`${styles.textChat} ${panelStyle}`}\n onWheel={handleWheel}\n >\n <div className={styles.messagesWrapper}>\n <Messages\n messages={messages}\n stringToHslOptions={props.stringToHslOptions}\n shouldAutoScroll={shouldAutoScroll}\n />\n </div>\n <InputBox\n ref={inputBoxRef}\n onSendMessage={handleSendMessage}\n hide={hide}\n setFocus={setFocus}\n />\n </div>\n </div>\n );\n};\n", "import { useEffect, useLayoutEffect, useRef } from \"react\";\n\ntype ClickAwayCallback = (event: MouseEvent | TouchEvent) => void;\n\nexport function useClickOutside(cb: ClickAwayCallback) {\n const ref = useRef<HTMLDivElement>(null);\n const refCb = useRef<ClickAwayCallback>(cb);\n\n useLayoutEffect(() => {\n refCb.current = cb;\n });\n\n useEffect(() => {\n const handler = (e: MouseEvent | TouchEvent) => {\n const element = ref.current;\n if (element && !element.contains(e.target as Node)) {\n refCb.current(e);\n }\n };\n\n document.addEventListener(\"mousedown\", handler);\n document.addEventListener(\"touchstart\", handler);\n\n return () => {\n document.removeEventListener(\"mousedown\", handler);\n document.removeEventListener(\"touchstart\", handler);\n };\n }, []);\n\n return ref;\n}\n", "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 512\"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d=\"M88.2 309.1c9.8-18.3 6.8-40.8-7.5-55.8C59.4 230.9 48 204 48 176c0-63.5 63.8-128 160-128s160 64.5 160 128s-63.8 128-160 128c-13.1 0-25.8-1.3-37.8-3.6c-10.4-2-21.2-.6-30.7 4.2c-4.1 2.1-8.3 4.1-12.6 6c-16 7.2-32.9 13.5-49.9 18c2.8-4.6 5.4-9.1 7.9-13.6c1.1-1.9 2.2-3.9 3.2-5.9zM0 176c0 41.8 17.2 80.1 45.9 110.3c-.9 1.7-1.9 3.5-2.8 5.1c-10.3 18.4-22.3 36.5-36.6 52.1c-6.6 7-8.3 17.2-4.6 25.9C5.8 378.3 14.4 384 24 384c43 0 86.5-13.3 122.7-29.7c4.8-2.2 9.6-4.5 14.2-6.8c15.1 3 30.9 4.5 47.1 4.5c114.9 0 208-78.8 208-176S322.9 0 208 0S0 78.8 0 176zM432 480c16.2 0 31.9-1.6 47.1-4.5c4.6 2.3 9.4 4.6 14.2 6.8C529.5 498.7 573 512 616 512c9.6 0 18.2-5.7 22-14.5c3.8-8.8 2-19-4.6-25.9c-14.2-15.6-26.2-33.7-36.6-52.1c-.9-1.7-1.9-3.4-2.8-5.1C622.8 384.1 640 345.8 640 304c0-94.4-87.9-171.5-198.2-175.8c4.1 15.2 6.2 31.2 6.2 47.8l0 .6c87.2 6.7 144 67.5 144 127.4c0 28-11.4 54.9-32.7 77.2c-14.3 15-17.3 37.6-7.5 55.8c1.1 2 2.2 4 3.2 5.9c2.5 4.5 5.2 9 7.9 13.6c-17-4.5-33.9-10.7-49.9-18c-4.3-1.9-8.5-3.9-12.6-6c-9.5-4.8-20.3-6.2-30.7-4.2c-12.1 2.4-24.7 3.6-37.8 3.6c-61.7 0-110-26.5-136.8-62.3c-16 5.4-32.8 9.4-50 11.8C279 439.8 350 480 432 480z\"/></svg>", "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d=\"M32 32C32 14.3 46.3 0 64 0H320c17.7 0 32 14.3 32 32s-14.3 32-32 32H290.5l11.4 148.2c36.7 19.9 65.7 53.2 79.5 94.7l1 3c3.3 9.8 1.6 20.5-4.4 28.8s-15.7 13.3-26 13.3H32c-10.3 0-19.9-4.9-26-13.3s-7.7-19.1-4.4-28.8l1-3c13.8-41.5 42.8-74.8 79.5-94.7L93.5 64H64C46.3 64 32 49.7 32 32zM160 384h64v96c0 17.7-14.3 32-32 32s-32-14.3-32-32V384z\"/></svg>", "import { forwardRef, KeyboardEvent, useImperativeHandle, useRef, useState } from \"react\";\n\nimport SendButton from \"../../icons/PaperPlane.svg\";\n\nimport styles from \"./InputBox.module.css\";\n\ntype InputBoxProps = {\n onSendMessage: (message: string) => void;\n hide: () => void;\n setFocus: () => void;\n};\n\nexport const InputBox = forwardRef<{ focusInput: () => void } | null, InputBoxProps>(\n ({ onSendMessage, hide, setFocus }, ref) => {\n const inputRef = useRef<HTMLInputElement>(null);\n const buttonRef = useRef<HTMLButtonElement>(null);\n const [inputValue, setInputValue] = useState(\"\");\n\n useImperativeHandle(ref, () => ({\n focusInput: () => {\n if (inputRef.current) inputRef.current.focus();\n },\n }));\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setInputValue(e.target.value);\n };\n\n const handleSendClick = () => {\n if (inputValue.trim() !== \"\") {\n onSendMessage(inputValue.trim());\n setInputValue(\"\");\n }\n };\n\n const handleKeyPress = (e: KeyboardEvent<HTMLInputElement>) => {\n e.stopPropagation();\n if (e.key === \"Enter\") {\n if (inputRef.current?.value.trim().length === 0) {\n if (buttonRef.current) buttonRef.current.focus();\n hide();\n return;\n }\n handleSendClick();\n }\n };\n\n return (\n <div className={styles.inputWrapper}>\n <input\n ref={inputRef}\n type=\"text\"\n placeholder=\"Type your message here...\"\n value={inputValue}\n onChange={handleInputChange}\n className={styles.chatInput}\n onKeyDown={handleKeyPress}\n onFocus={setFocus}\n />\n <button ref={buttonRef} onClick={handleSendClick} className={styles.sendButton}>\n <div className={styles.svgIcon}>\n <img src={`data:image/svg+xml;utf8,${encodeURIComponent(SendButton)}`} />\n </div>\n </button>\n </div>\n );\n },\n);\nInputBox.displayName = \"InputBox\";\n", "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d=\"M498.1 5.6c10.1 7 15.4 19.1 13.5 31.2l-64 416c-1.5 9.7-7.4 18.2-16 23s-18.9 5.4-28 1.6L284 427.7l-68.5 74.1c-8.9 9.7-22.9 12.9-35.2 8.1S160 493.2 160 480V396.4c0-4 1.5-7.8 4.2-10.7L331.8 202.8c5.8-6.3 5.6-16-.4-22s-15.7-6.4-22-.7L106 360.8 17.7 316.6C7.1 311.3 .3 300.7 0 288.9s5.9-22.8 16.1-28.7l448-256c10.7-6.1 23.9-5.5 34 1.4z\"/></svg>", "\nconst content = __content_placeholder__;\nconst digest = __digest_placeholder__; \nconst inject = () => {\n setTimeout(() => {\n if (!globalThis.document) {\n return;\n }\n let root = globalThis.document.querySelector(\"head\");\n if (root && root.shadowRoot) {\n root = root.shadowRoot;\n }\n if (!root) {\n root = globalThis.document.head;\n }\n let container = root.querySelector(\"#_\" + digest);\n if (!container) {\n container = globalThis.document.createElement(\"style\");\n container.id = \"_\" + digest;\n const text = globalThis.document.createTextNode(content);\n container.appendChild(text);\n root.appendChild(container);\n }\n }, 0);\n};\n\nexport { inject };\n ", "import \"esbuild-css-modules-plugin-ns-css:src/chat-ui/components/Input/InputBox.module.css\";\n\nimport { inject } from \"esbuild-css-modules-plugin-ns-js:src/chat-ui/components/Input/InputBox.module.css:injector.js\";\nexport default new Proxy({\n \"chatInput\": \"InputBox-module__chatInput_adOgOW__0230\",\n \"inputWrapper\": \"InputBox-module__inputWrapper_adOgOW__0230\",\n \"sendButton\": \"InputBox-module__sendButton_adOgOW__0230\",\n \"svgIcon\": \"InputBox-module__svgIcon_adOgOW__0230\"\n}, {\n get: function(source, key) {\n inject();\n return source[key];\n }\n});\n ", "import { FC, useEffect, useRef, useState } from \"react\";\n\nimport { StringToHslOptions } from \"../../TextChatUI\";\nimport Message from \"../Message/Message\";\n\nimport styles from \"./Messages.module.css\";\n\ntype MessagesProps = {\n messages: Array<{ username: string; message: string }>;\n stringToHslOptions?: StringToHslOptions;\n shouldAutoScroll?: boolean;\n};\n\nconst SCROLL_THRESHOLD_PX = 10; // Threshold to consider \"at bottom\" for scroll position\n\nexport const Messages: FC<MessagesProps> = ({ messages, stringToHslOptions, shouldAutoScroll }) => {\n const messagesEndRef = useRef<null | HTMLDivElement>(null);\n const containerRef = useRef<null | HTMLDivElement>(null);\n const [unreadCount, setUnreadCount] = useState(0);\n const [lastReadMessageIndex, setLastReadMessageIndex] = useState(0);\n const [wasAtBottom, setWasAtBottom] = useState(true);\n\n const isAtBottom = () => {\n if (!containerRef.current) return true;\n const { scrollTop, scrollHeight, clientHeight } = containerRef.current;\n return Math.abs(scrollHeight - clientHeight - scrollTop) < SCROLL_THRESHOLD_PX;\n };\n\n const handleScroll = () => {\n const atBottom = isAtBottom();\n setWasAtBottom(atBottom);\n\n // Mark messages as read when scrolled to bottom\n if (atBottom && unreadCount > 0) {\n setUnreadCount(0);\n setLastReadMessageIndex(messages.length - 1);\n }\n };\n\n const scrollToBottom = () => {\n if (messagesEndRef.current) {\n messagesEndRef.current.scrollIntoView({ behavior: \"smooth\" });\n }\n setUnreadCount(0);\n setLastReadMessageIndex(messages.length - 1);\n setWasAtBottom(true);\n };\n\n useEffect(() => {\n if (messages.length === 0) return;\n\n // Should auto-scroll if user sent message or was at bottom\n const shouldScroll = shouldAutoScroll || wasAtBottom;\n\n if (shouldScroll) {\n // Use setTimeout to ensure DOM is updated, then check if we need to scroll\n setTimeout(() => {\n if (!isAtBottom()) {\n if (messagesEndRef.current) {\n messagesEndRef.current.scrollIntoView({ behavior: \"smooth\" });\n }\n }\n setWasAtBottom(true);\n }, 0);\n setUnreadCount(0);\n setLastReadMessageIndex(messages.length - 1);\n } else {\n // User is scrolled up and this is someone else's message\n const newUnreadCount = messages.length - 1 - lastReadMessageIndex;\n setUnreadCount(newUnreadCount);\n }\n }, [messages, shouldAutoScroll, wasAtBottom, lastReadMessageIndex]);\n\n return (\n <>\n <div ref={containerRef} className={styles.messagesContainer} onScroll={handleScroll}>\n {messages.map((msg, index) => (\n <Message\n key={index}\n username={msg.username}\n message={msg.message}\n stringToHslOptions={stringToHslOptions}\n />\n ))}\n <div ref={messagesEndRef}></div>\n </div>\n {unreadCount > 0 && (\n <button className={styles.newMessagesButton} onClick={scrollToBottom}>\n {unreadCount} new message{unreadCount !== 1 ? \"s\" : \"\"}\n </button>\n )}\n </>\n );\n};\n", "import { FC, useState, useEffect, useCallback } from \"react\";\n\nimport { DEFAULT_HSL_OPTIONS, StringToHslOptions } from \"../../TextChatUI\";\n\nimport styles from \"./Message.module.css\";\n\nfunction ReverseHash(input: string): number {\n // Hash has an initial value of 5381. As bit shifting is used, output can be any signed 32 bit Integer.\n const stringLength = input.length;\n let hash = 5381;\n\n for (let i = stringLength - 1; i >= 0; i--) {\n hash = (hash << 5) + hash + input.charCodeAt(i);\n }\n\n return hash;\n}\n\nfunction generateValueFromThresholds(hash: number, thresholds: [number, number][]): number {\n const selectedThreshold = thresholds[hash % thresholds.length];\n const min = Math.min(...selectedThreshold);\n const max = Math.max(...selectedThreshold);\n\n const thresholdRange = Math.abs(max - min);\n return (hash % thresholdRange) + min;\n}\n\nfunction hslForString(\n input: string,\n options: StringToHslOptions = DEFAULT_HSL_OPTIONS,\n): [number, number, number] {\n // Because JS bit shifting only operates on 32-Bit signed Integers,\n // in the case of overflow where a negative hash is inappropriate,\n // the absolute value has to be taken. This 'halves' our theoretical\n // hash distribution. This may require an alternate approach if\n // collisions are too frequent.\n let hash = Math.abs(ReverseHash(\"lightness: \" + input));\n\n const lightness = options.lightnessThresholds\n ? generateValueFromThresholds(hash, options.lightnessThresholds)\n : generateValueFromThresholds(hash, DEFAULT_HSL_OPTIONS.lightnessThresholds!);\n\n hash = Math.abs(ReverseHash(\"saturation:\" + input));\n const saturation = options.saturationThresholds\n ? generateValueFromThresholds(hash, options.saturationThresholds)\n : generateValueFromThresholds(hash, DEFAULT_HSL_OPTIONS.saturationThresholds!);\n\n hash = Math.abs(ReverseHash(\"hue:\" + input));\n const hue = options.hueThresholds\n ? generateValueFromThresholds(hash, options.hueThresholds)\n : generateValueFromThresholds(hash, DEFAULT_HSL_OPTIONS.hueThresholds!);\n\n return [hue, saturation, lightness];\n}\n\ntype MessageProps = {\n username: string;\n message: string;\n stringToHslOptions?: StringToHslOptions;\n};\n\nconst Message: FC<MessageProps> = ({ username, message, stringToHslOptions }) => {\n const [userColors, setUserColors] = useState<Map<string, string>>(new Map());\n\n const generateColorForUsername = useCallback((): string => {\n const [hue, saturation, lightness] = hslForString(username, stringToHslOptions);\n return `hsl(${hue}, ${saturation}%, ${lightness}%)`;\n }, [stringToHslOptions, username]);\n\n useEffect(() => {\n if (!userColors.has(username)) {\n const color = generateColorForUsername();\n setUserColors(new Map(userColors).set(username, color));\n }\n }, [username, userColors, generateColorForUsername]);\n\n const userColor = userColors.get(username) || \"hsl(0, 0%, 0%)\";\n\n return (\n <div className={styles.messageContainer}>\n <span className={styles.userName} style={{ color: userColor }}>\n {username}\n </span>\n : {message}\n </div>\n );\n};\n\nexport default Message;\n", "\nconst content = __content_placeholder__;\nconst digest = __digest_placeholder__; \nconst inject = () => {\n setTimeout(() => {\n if (!globalThis.document) {\n return;\n }\n let root = globalThis.document.querySelector(\"head\");\n if (root && root.shadowRoot) {\n root = root.shadowRoot;\n }\n if (!root) {\n root = globalThis.document.head;\n }\n let container = root.querySelector(\"#_\" + digest);\n if (!container) {\n container = globalThis.document.createElement(\"style\");\n container.id = \"_\" + digest;\n const text = globalThis.document.createTextNode(content);\n container.appendChild(text);\n root.appendChild(container);\n }\n }, 0);\n};\n\nexport { inject };\n ", "import \"esbuild-css-modules-plugin-ns-css:src/chat-ui/components/Message/Message.module.css\";\n\nimport { inject } from \"esbuild-css-modules-plugin-ns-js:src/chat-ui/components/Message/Message.module.css:injector.js\";\nexport default new Proxy({\n \"messageContainer\": \"Message-module__messageContainer_ikOQiq__0230\",\n \"userName\": \"Message-module__userName_ikOQiq__0230\"\n}, {\n get: function(source, key) {\n inject();\n return source[key];\n }\n});\n ", "\nconst content = __content_placeholder__;\nconst digest = __digest_placeholder__; \nconst inject = () => {\n setTimeout(() => {\n if (!globalThis.document) {\n return;\n }\n let root = globalThis.document.querySelector(\"head\");\n if (root && root.shadowRoot) {\n root = root.shadowRoot;\n }\n if (!root) {\n root = globalThis.document.head;\n }\n let container = root.querySelector(\"#_\" + digest);\n if (!container) {\n container = globalThis.document.createElement(\"style\");\n container.id = \"_\" + digest;\n const text = globalThis.document.createTextNode(content);\n container.appendChild(text);\n root.appendChild(container);\n }\n }, 0);\n};\n\nexport { inject };\n ", "import \"esbuild-css-modules-plugin-ns-css:src/chat-ui/components/Messages/Messages.module.css\";\n\nimport { inject } from \"esbuild-css-modules-plugin-ns-js:src/chat-ui/components/Messages/Messages.module.css:injector.js\";\nexport default new Proxy({\n \"messagesContainer\": \"Messages-module__messagesContainer_LXaUUW__0230\",\n \"newMessagesButton\": \"Messages-module__newMessagesButton_LXaUUW__0230\"\n}, {\n get: function(source, key) {\n inject();\n return source[key];\n }\n});\n ", "\nconst content = __content_placeholder__;\nconst digest = __digest_placeholder__; \nconst inject = () => {\n setTimeout(() => {\n if (!globalThis.document) {\n return;\n }\n let root = globalThis.document.querySelector(\"head\");\n if (root && root.shadowRoot) {\n root = root.shadowRoot;\n }\n if (!root) {\n root = globalThis.document.head;\n }\n let container = root.querySelector(\"#_\" + digest);\n if (!container) {\n container = globalThis.document.createElement(\"style\");\n container.id = \"_\" + digest;\n const text = globalThis.document.createTextNode(content);\n container.appendChild(text);\n root.appendChild(container);\n }\n }, 0);\n};\n\nexport { inject };\n ", "import \"esbuild-css-modules-plugin-ns-css:src/chat-ui/components/ChatPanel/TextChatUIComponent.module.css\";\n\nimport { inject } from \"esbuild-css-modules-plugin-ns-js:src/chat-ui/components/ChatPanel/TextChatUIComponent.module.css:injector.js\";\nexport default new Proxy({\n \"closeButton\": \"TextChatUIComponent-module__closeButton_gFDdcW__0230\",\n \"controls\": \"TextChatUIComponent-module__controls_gFDdcW__0230\",\n \"fadeIn\": \"TextChatUIComponent-module__fadeIn_gFDdcW__0230\",\n \"fadeOut\": \"TextChatUIComponent-module__fadeOut_gFDdcW__0230\",\n \"messagesWrapper\": \"TextChatUIComponent-module__messagesWrapper_gFDdcW__0230\",\n \"openTab\": \"TextChatUIComponent-module__openTab_gFDdcW__0230\",\n \"stickyButton\": \"TextChatUIComponent-module__stickyButton_gFDdcW__0230\",\n \"stickyButtonEnabled\": \"TextChatUIComponent-module__stickyButtonEnabled_gFDdcW__0230\",\n \"stickyButtonFadeOut\": \"TextChatUIComponent-module__stickyButtonFadeOut_gFDdcW__0230\",\n \"textChat\": \"TextChatUIComponent-module__textChat_gFDdcW__0230\",\n \"textChatUi\": \"TextChatUIComponent-module__textChatUi_gFDdcW__0230\",\n \"uiHover\": \"TextChatUIComponent-module__uiHover_gFDdcW__0230\"\n}, {\n get: function(source, key) {\n inject();\n return source[key];\n }\n});\n ", "\nconst content = __content_placeholder__;\nconst digest = __digest_placeholder__; \nconst inject = () => {\n setTimeout(() => {\n if (!globalThis.document) {\n return;\n }\n let root = globalThis.document.querySelector(\"head\");\n if (root && root.shadowRoot) {\n root = root.shadowRoot;\n }\n if (!root) {\n root = globalThis.document.head;\n }\n let container = root.querySelector(\"#_\" + digest);\n if (!container) {\n container = globalThis.document.createElement(\"style\");\n container.id = \"_\" + digest;\n const text = globalThis.document.createTextNode(content);\n container.appendChild(text);\n root.appendChild(container);\n }\n }, 0);\n};\n\nexport { inject };\n ", "import \"esbuild-css-modules-plugin-ns-css:src/Networked3dWebExperience.module.css\";\n\nimport { inject } from \"esbuild-css-modules-plugin-ns-js:src/Networked3dWebExperience.module.css:injector.js\";\nexport default new Proxy({\n \"respawnButton\": \"Networked3dWebExperience-module__respawnButton_7g9l0W__0230\"\n}, {\n get: function(source, key) {\n inject();\n return source[key];\n }\n});\n "],
|
4
|
+
"sourcesContent": ["import {\n AnimationConfig,\n CameraManager,\n CharacterDescription,\n CharacterManager,\n CharacterModelLoader,\n CharacterState,\n CollisionsManager,\n Composer,\n EnvironmentConfiguration,\n ErrorScreen,\n EulXYZ,\n GroundPlane,\n Key,\n KeyInputManager,\n LoadingScreen,\n LoadingScreenConfig,\n MMLCompositionScene,\n TimeManager,\n TweakPane,\n SpawnConfiguration,\n SpawnConfigurationState,\n Vect3,\n VirtualJoystick,\n Character,\n Quat,\n getSpawnData,\n} from \"@mml-io/3d-web-client-core\";\nimport {\n FROM_SERVER_CHAT_MESSAGE_TYPE,\n FROM_CLIENT_CHAT_MESSAGE_TYPE,\n ClientChatMessage,\n UserData,\n UserNetworkingClient,\n UserNetworkingClientUpdate,\n WebsocketStatus,\n parseServerChatMessage,\n DeltaNetV01ServerErrors,\n NetworkUpdate,\n SERVER_BROADCAST_MESSAGE_TYPE,\n ServerBroadcastMessage,\n parseServerBroadcastMessage,\n} from \"@mml-io/3d-web-user-networking\";\nimport {\n IMMLScene,\n LoadingProgressManager,\n registerCustomElementsToWindow,\n setGlobalDocumentTimeManager,\n setGlobalMMLScene,\n} from \"@mml-io/mml-web\";\nimport { Scene, AudioListener, Vector3 } from \"three\";\n\nimport { AvatarSelectionUI, AvatarConfiguration } from \"./avatar-selection-ui\";\nimport { StringToHslOptions, TextChatUI, TextChatUIProps } from \"./chat-ui\";\nimport styles from \"./Networked3dWebExperience.module.css\";\n\ntype MMLDocumentConfiguration = {\n url: string;\n position?: {\n x: number;\n y: number;\n z: number;\n };\n rotation?: {\n x: number;\n y: number;\n z: number;\n };\n scale?: {\n x: number;\n y: number;\n z: number;\n };\n};\n\nexport type Networked3dWebExperienceClientConfig = {\n userNetworkAddress: string;\n sessionToken: string;\n chatVisibleByDefault?: boolean;\n userNameToColorOptions?: StringToHslOptions;\n animationConfig: AnimationConfig;\n voiceChatAddress?: string;\n updateURLLocation?: boolean;\n onServerBroadcast?: (broadcast: ServerBroadcastMessage) => void;\n loadingScreen?: LoadingScreenConfig;\n} & UpdatableConfig;\n\nexport type UpdatableConfig = {\n enableChat?: boolean;\n mmlDocuments?: { [key: string]: MMLDocumentConfiguration };\n environmentConfiguration?: EnvironmentConfiguration;\n spawnConfiguration?: SpawnConfiguration;\n avatarConfiguration?: AvatarConfiguration;\n allowCustomDisplayName?: boolean;\n enableTweakPane?: boolean;\n allowOrbitalCamera?: boolean;\n postProcessingEnabled?: boolean;\n};\n\nfunction normalizeSpawnConfiguration(spawnConfig?: SpawnConfiguration): SpawnConfigurationState {\n return {\n spawnPosition: {\n x: spawnConfig?.spawnPosition?.x ?? 0,\n y: spawnConfig?.spawnPosition?.y ?? 0,\n z: spawnConfig?.spawnPosition?.z ?? 0,\n },\n spawnPositionVariance: {\n x: spawnConfig?.spawnPositionVariance?.x ?? 0,\n y: spawnConfig?.spawnPositionVariance?.y ?? 0,\n z: spawnConfig?.spawnPositionVariance?.z ?? 0,\n },\n spawnYRotation: spawnConfig?.spawnYRotation ?? 0,\n respawnTrigger: {\n minX: spawnConfig?.respawnTrigger?.minX ?? Number.NEGATIVE_INFINITY,\n maxX: spawnConfig?.respawnTrigger?.maxX ?? Number.POSITIVE_INFINITY,\n minY: spawnConfig?.respawnTrigger?.minY ?? -100,\n maxY: spawnConfig?.respawnTrigger?.maxY ?? Number.POSITIVE_INFINITY,\n minZ: spawnConfig?.respawnTrigger?.minZ ?? Number.NEGATIVE_INFINITY,\n maxZ: spawnConfig?.respawnTrigger?.maxZ ?? Number.POSITIVE_INFINITY,\n },\n enableRespawnButton: spawnConfig?.enableRespawnButton ?? false,\n };\n}\n\nexport class Networked3dWebExperienceClient {\n private element: HTMLDivElement;\n private canvasHolder: HTMLDivElement;\n\n private scene: Scene = new Scene();\n private composer: Composer;\n private tweakPane: TweakPane | null = null;\n private audioListener = new AudioListener();\n\n private cameraManager: CameraManager;\n\n private collisionsManager: CollisionsManager;\n\n private characterModelLoader: CharacterModelLoader;\n private characterManager: CharacterManager;\n\n private timeManager = new TimeManager();\n\n private keyInputManager = new KeyInputManager();\n private virtualJoystick: VirtualJoystick;\n\n private mmlCompositionScene: MMLCompositionScene;\n private mmlFrames: { [key: string]: HTMLElement } = {};\n\n private clientId: number | null = null;\n private networkClient: UserNetworkingClient;\n private remoteUserStates = new Map<number, UserNetworkingClientUpdate>();\n private userProfiles = new Map<number, UserData>();\n\n private textChatUI: TextChatUI | null = null;\n\n private avatarSelectionUI: AvatarSelectionUI | null = null;\n\n private readonly latestCharacterObject = {\n characterState: null as null | CharacterState,\n };\n private characterControllerPaneSet: boolean = false;\n\n private spawnConfiguration: SpawnConfigurationState;\n\n private initialLoadCompleted = false;\n private loadingProgressManager = new LoadingProgressManager();\n private loadingScreen: LoadingScreen;\n private errorScreen?: ErrorScreen;\n private groundPlane: GroundPlane | null = null;\n private respawnButton: HTMLDivElement | null = null;\n\n private currentRequestAnimationFrame: number | null = null;\n\n constructor(\n private holderElement: HTMLElement,\n private config: Networked3dWebExperienceClientConfig,\n ) {\n this.element = document.createElement(\"div\");\n this.element.style.position = \"absolute\";\n this.element.style.width = \"100%\";\n this.element.style.height = \"100%\";\n this.holderElement.appendChild(this.element);\n\n document.addEventListener(\"mousedown\", () => {\n if (this.audioListener.context.state === \"suspended\") {\n this.audioListener.context.resume();\n }\n });\n\n this.canvasHolder = document.createElement(\"div\");\n this.canvasHolder.style.position = \"absolute\";\n this.canvasHolder.style.width = \"100%\";\n this.canvasHolder.style.height = \"100%\";\n this.element.appendChild(this.canvasHolder);\n\n this.collisionsManager = new CollisionsManager(this.scene);\n this.cameraManager = new CameraManager(this.canvasHolder, this.collisionsManager);\n this.cameraManager.camera.add(this.audioListener);\n this.characterModelLoader = new CharacterModelLoader();\n\n this.virtualJoystick = new VirtualJoystick(this.element, {\n radius: 70,\n innerRadius: 20,\n mouseSupport: false,\n });\n\n this.composer = new Composer({\n scene: this.scene,\n cameraManager: this.cameraManager,\n spawnSun: true,\n environmentConfiguration: this.config.environmentConfiguration,\n postProcessingEnabled: this.config.postProcessingEnabled,\n });\n this.canvasHolder.appendChild(this.composer.renderer.domElement);\n\n if (this.config.enableTweakPane !== false) {\n this.setupTweakPane();\n }\n\n const resizeObserver = new ResizeObserver(() => {\n this.composer.fitContainer();\n });\n resizeObserver.observe(this.element);\n\n this.spawnConfiguration = normalizeSpawnConfiguration(this.config.spawnConfiguration);\n\n const spawnData = getSpawnData(this.spawnConfiguration, true);\n const spawnRotation = new Quat().setFromEulerXYZ(spawnData.spawnRotation);\n\n const initialNetworkLoadRef = {};\n this.loadingProgressManager.addLoadingAsset(initialNetworkLoadRef, \"network\", \"network\");\n this.networkClient = new UserNetworkingClient(\n {\n url: this.config.userNetworkAddress,\n sessionToken: this.config.sessionToken,\n websocketFactory: (url: string) => new WebSocket(url, \"delta-net-v0.1\"),\n statusUpdateCallback: (status: WebsocketStatus) => {\n console.log(`Websocket status: ${status}`);\n if (status === WebsocketStatus.Disconnected || status === WebsocketStatus.Reconnecting) {\n // The connection was lost after being established - the connection may be re-established with a different client ID\n this.characterManager.clear();\n this.remoteUserStates.clear();\n this.clientId = null;\n }\n },\n assignedIdentity: (clientId: number) => {\n console.log(`Assigned ID: ${clientId}`);\n this.clientId = clientId;\n if (this.initialLoadCompleted) {\n // Already loaded - respawn the character\n const spawnData = getSpawnData(this.spawnConfiguration, true);\n this.spawnCharacter(spawnData);\n } else {\n this.loadingProgressManager.completedLoadingAsset(initialNetworkLoadRef);\n }\n },\n onUpdate: (update: NetworkUpdate): void => {\n this.onNetworkUpdate(update);\n },\n onServerError: (error: { message: string; errorType: string }) => {\n switch (error.errorType) {\n case DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE:\n this.disposeWithError(error.message);\n break;\n case DeltaNetV01ServerErrors.USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE:\n this.disposeWithError(error.message);\n break;\n case DeltaNetV01ServerErrors.USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE:\n this.disposeWithError(error.message || \"Server shutdown\");\n break;\n default:\n console.error(`Unhandled server error: ${error.message}`);\n this.disposeWithError(error.message);\n }\n },\n onCustomMessage: (customType: number, contents: string) => {\n if (customType === SERVER_BROADCAST_MESSAGE_TYPE) {\n const serverBroadcastMessage = parseServerBroadcastMessage(contents);\n if (serverBroadcastMessage instanceof Error) {\n console.error(`Invalid server broadcast message: ${contents}`);\n } else {\n this.config.onServerBroadcast?.(serverBroadcastMessage);\n }\n } else if (customType === FROM_SERVER_CHAT_MESSAGE_TYPE) {\n const serverChatMessage = parseServerChatMessage(contents);\n if (serverChatMessage instanceof Error) {\n console.error(`Invalid server chat message: ${contents}`);\n } else {\n this.handleChatMessage(serverChatMessage.fromUserId, serverChatMessage.message);\n }\n } else {\n console.warn(`Did not recognize custom message type ${customType}`);\n }\n },\n },\n {\n username: null,\n characterDescription: null,\n colors: null,\n },\n {\n position: spawnData.spawnPosition,\n rotation: {\n quaternionY: spawnRotation.y,\n quaternionW: spawnRotation.w,\n },\n state: 0,\n },\n );\n\n if (this.config.allowOrbitalCamera) {\n this.keyInputManager.createKeyBinding(Key.C, () => {\n if (document.activeElement === document.body) {\n // No input is selected - accept the key press\n this.cameraManager.toggleFlyCamera();\n this.composer.fitContainer();\n }\n });\n }\n\n const animationsPromise = Character.loadAnimations(\n this.characterModelLoader,\n this.config.animationConfig,\n );\n\n this.characterManager = new CharacterManager({\n composer: this.composer,\n characterModelLoader: this.characterModelLoader,\n collisionsManager: this.collisionsManager,\n cameraManager: this.cameraManager,\n timeManager: this.timeManager,\n keyInputManager: this.keyInputManager,\n virtualJoystick: this.virtualJoystick,\n remoteUserStates: this.remoteUserStates,\n sendUpdate: (characterState: CharacterState) => {\n this.latestCharacterObject.characterState = characterState;\n this.networkClient.sendUpdate(characterState);\n },\n sendLocalCharacterColors: (colors: Array<[number, number, number]>) => {\n this.networkClient.updateColors(colors);\n },\n animationsPromise: animationsPromise,\n spawnConfiguration: this.spawnConfiguration,\n characterResolve: (characterId: number) => {\n return this.resolveCharacterData(characterId);\n },\n updateURLLocation: this.config.updateURLLocation !== false,\n });\n this.scene.add(this.characterManager.group);\n\n if (this.spawnConfiguration.enableRespawnButton) {\n this.respawnButton = this.createRespawnButton();\n this.element.appendChild(this.respawnButton);\n }\n\n this.setGroundPlaneEnabled(this.config.environmentConfiguration?.groundPlane ?? true);\n\n this.setupMMLScene();\n\n this.loadingScreen = new LoadingScreen(this.loadingProgressManager, this.config.loadingScreen);\n this.element.append(this.loadingScreen.element);\n\n this.loadingProgressManager.addProgressCallback(() => {\n const [, completed] = this.loadingProgressManager.toRatio();\n if (completed && !this.initialLoadCompleted) {\n this.initialLoadCompleted = true;\n /*\n When all content (in particular MML) has loaded, spawn the character (this is to avoid the character falling\n through as-yet-unloaded geometry)\n */\n\n this.connectToTextChat();\n this.mountAvatarSelectionUI();\n this.spawnCharacter(spawnData);\n }\n });\n this.loadingProgressManager.setInitialLoad(true);\n }\n\n private setGroundPlaneEnabled(enabled: boolean) {\n if (enabled && this.groundPlane === null) {\n this.groundPlane = new GroundPlane();\n this.collisionsManager.addMeshesGroup(this.groundPlane);\n this.scene.add(this.groundPlane);\n } else if (!enabled && this.groundPlane !== null) {\n this.collisionsManager.removeMeshesGroup(this.groundPlane);\n this.scene.remove(this.groundPlane);\n this.groundPlane = null;\n }\n }\n\n public updateConfig(config: Partial<UpdatableConfig>) {\n this.config = {\n ...this.config,\n ...config,\n };\n if (config.environmentConfiguration) {\n this.composer.updateEnvironmentConfiguration(config.environmentConfiguration);\n this.setGroundPlaneEnabled(config.environmentConfiguration.groundPlane ?? true);\n }\n\n if (this.avatarSelectionUI) {\n if (config.avatarConfiguration) {\n this.avatarSelectionUI.updateAvatarConfig(config.avatarConfiguration);\n }\n this.avatarSelectionUI.updateAllowCustomDisplayName(config.allowCustomDisplayName || false);\n }\n\n if (config.enableTweakPane !== undefined) {\n if (config.enableTweakPane === false && this.tweakPane !== null) {\n this.tweakPane.dispose();\n this.tweakPane = null;\n } else if (config.enableTweakPane === true && this.tweakPane === null) {\n this.setupTweakPane();\n }\n }\n\n if (this.config.postProcessingEnabled !== undefined) {\n this.composer.togglePostProcessing(this.config.postProcessingEnabled);\n if (this.tweakPane) {\n this.tweakPane.dispose();\n this.tweakPane = null;\n this.setupTweakPane();\n }\n }\n\n if (config.allowOrbitalCamera !== undefined) {\n if (config.allowOrbitalCamera === false) {\n this.keyInputManager.removeKeyBinding(Key.C);\n if (this.cameraManager.isFlyCameraOn() === true) {\n // Disable the fly camera if it was enabled\n this.cameraManager.toggleFlyCamera();\n }\n } else if (config.allowOrbitalCamera === true) {\n this.keyInputManager.createKeyBinding(Key.C, () => {\n if (document.activeElement === document.body) {\n // No input is selected - accept the key press\n this.cameraManager.toggleFlyCamera();\n this.composer.fitContainer();\n }\n });\n }\n }\n\n if (config.enableChat) {\n if (!config.enableChat && this.textChatUI !== null) {\n this.textChatUI.dispose();\n this.textChatUI = null;\n } else {\n this.connectToTextChat();\n }\n }\n\n this.spawnConfiguration = normalizeSpawnConfiguration(config.spawnConfiguration);\n if (this.characterManager.localController) {\n this.characterManager.localController.updateSpawnConfig(this.spawnConfiguration);\n }\n if (this.spawnConfiguration.enableRespawnButton && !this.respawnButton) {\n this.respawnButton = this.createRespawnButton();\n this.element.appendChild(this.respawnButton);\n } else if (!this.spawnConfiguration.enableRespawnButton && this.respawnButton) {\n this.respawnButton.remove();\n this.respawnButton = null;\n }\n\n if (config.mmlDocuments) {\n this.setMMLDocuments(config.mmlDocuments);\n }\n }\n\n static createFullscreenHolder(): HTMLDivElement {\n document.body.style.margin = \"0\";\n document.body.style.overflow = \"hidden\";\n\n const holder = document.createElement(\"div\");\n holder.style.position = \"absolute\";\n holder.style.width = \"100%\";\n holder.style.height = \"100%\";\n holder.style.overflow = \"hidden\";\n document.body.appendChild(holder);\n return holder;\n }\n\n private createRespawnButton(): HTMLDivElement {\n const respawnButton = document.createElement(\"div\");\n respawnButton.className = styles.respawnButton;\n respawnButton.textContent = \"RESPAWN\";\n respawnButton.addEventListener(\"click\", () => {\n this.characterManager.localController?.resetPosition();\n });\n return respawnButton;\n }\n\n private resolveCharacterData(clientId: number): UserData {\n const user = this.userProfiles.get(clientId)!;\n\n if (!user) {\n throw new Error(`Failed to resolve user for clientId ${clientId}`);\n }\n\n return {\n username: user.username,\n characterDescription: user.characterDescription,\n colors: user.colors,\n };\n }\n\n private onNetworkUpdate(update: NetworkUpdate): void {\n const { removedUserIds, addedUserIds, updatedUsers } = update;\n for (const clientId of removedUserIds) {\n this.userProfiles.delete(clientId);\n this.remoteUserStates.delete(clientId);\n }\n for (const [clientId, userData] of addedUserIds) {\n this.userProfiles.set(clientId, userData.userState);\n this.remoteUserStates.set(clientId, userData.components);\n }\n for (const [clientId, userDataUpdate] of updatedUsers) {\n const userState = userDataUpdate.userState;\n if (userState) {\n if (userState.username !== undefined) {\n this.userProfiles.get(clientId)!.username = userState.username;\n }\n if (userState.characterDescription !== undefined) {\n this.userProfiles.get(clientId)!.characterDescription = userState.characterDescription;\n }\n if (userState.colors !== undefined) {\n this.userProfiles.get(clientId)!.colors = userState.colors;\n }\n this.characterManager.networkCharacterInfoUpdated(clientId);\n }\n this.remoteUserStates.set(clientId, userDataUpdate.components);\n }\n }\n\n private sendIdentityUpdateToServer(\n displayName: string,\n characterDescription: CharacterDescription,\n ) {\n if (!this.clientId) {\n throw new Error(\"Client ID not set\");\n }\n\n this.networkClient.updateUsername(displayName);\n this.networkClient.updateCharacterDescription(characterDescription);\n }\n\n private setupTweakPane() {\n if (this.tweakPane) {\n return;\n }\n\n this.tweakPane = new TweakPane(\n this.element,\n this.composer.renderer,\n this.scene,\n this.composer,\n this.config.postProcessingEnabled,\n );\n this.cameraManager.setupTweakPane(this.tweakPane);\n this.composer.setupTweakPane(this.tweakPane);\n }\n\n private handleChatMessage(fromUserId: number, message: string) {\n if (this.textChatUI === null) {\n return;\n }\n\n if (fromUserId === 0) {\n // Server message - handle as system message\n this.textChatUI.addTextMessage(\"System\", message);\n } else {\n // User message\n const user = this.userProfiles.get(fromUserId);\n if (!user) {\n console.error(`User not found for clientId ${fromUserId}`);\n return;\n }\n const username = user.username ?? `Unknown User ${fromUserId}`;\n this.textChatUI.addTextMessage(username, message);\n this.characterManager.addChatBubble(fromUserId, message);\n }\n }\n\n private connectToTextChat() {\n if (this.clientId === null) {\n return;\n }\n\n if (this.config.enableChat && this.textChatUI === null) {\n const user = this.userProfiles.get(this.clientId);\n if (!user) {\n throw new Error(\"User not found\");\n }\n\n const textChatUISettings: TextChatUIProps = {\n holderElement: this.canvasHolder,\n sendMessageToServerMethod: (message: string) => {\n this.characterManager.addSelfChatBubble(message);\n this.mmlCompositionScene.onChatMessage(message);\n\n // Send chat message through deltanet custom message\n this.networkClient.sendCustomMessage(\n FROM_CLIENT_CHAT_MESSAGE_TYPE,\n JSON.stringify({ message } satisfies ClientChatMessage),\n );\n },\n visibleByDefault: this.config.chatVisibleByDefault,\n stringToHslOptions: this.config.userNameToColorOptions,\n };\n this.textChatUI = new TextChatUI(textChatUISettings);\n this.textChatUI.init();\n }\n }\n\n private mountAvatarSelectionUI() {\n if (this.clientId === null) {\n throw new Error(\"Client ID not set\");\n }\n const ownIdentity = this.userProfiles.get(this.clientId);\n if (!ownIdentity) {\n throw new Error(\"Own identity not found\");\n }\n this.avatarSelectionUI = new AvatarSelectionUI({\n holderElement: this.element,\n visibleByDefault: false,\n displayName: ownIdentity.username ?? `Unknown User ${this.clientId}`,\n characterDescription: ownIdentity.characterDescription ?? {\n meshFileUrl: \"\",\n },\n sendIdentityUpdateToServer: this.sendIdentityUpdateToServer.bind(this),\n availableAvatars: this.config.avatarConfiguration?.availableAvatars ?? [],\n allowCustomAvatars: this.config.avatarConfiguration?.allowCustomAvatars,\n allowCustomDisplayName: this.config.allowCustomDisplayName || false,\n });\n this.avatarSelectionUI.init();\n }\n\n public update(): void {\n this.timeManager.update();\n this.characterManager.update();\n this.cameraManager.update();\n const characterPosition = this.characterManager.localCharacter?.getPosition();\n this.composer.sun?.updateCharacterPosition(\n new Vector3(characterPosition?.x || 0, characterPosition?.y || 0, characterPosition?.z || 0),\n );\n this.composer.render(this.timeManager);\n if (this.tweakPane?.guiVisible) {\n this.tweakPane.updateStats(this.timeManager);\n this.tweakPane.updateCameraData(this.cameraManager);\n if (this.characterManager.localCharacter && this.characterManager.localController) {\n if (!this.characterControllerPaneSet) {\n this.characterControllerPaneSet = true;\n this.characterManager.setupTweakPane(this.tweakPane);\n } else {\n this.tweakPane.updateCharacterData(this.characterManager.localController);\n }\n }\n }\n this.currentRequestAnimationFrame = requestAnimationFrame(() => {\n this.update();\n });\n }\n\n private spawnCharacter({\n spawnPosition,\n spawnRotation,\n cameraPosition,\n }: {\n spawnPosition: Vect3;\n spawnRotation: EulXYZ;\n cameraPosition: Vect3;\n }) {\n if (this.clientId === null) {\n throw new Error(\"Client ID not set\");\n }\n\n const ownIdentity = this.userProfiles.get(this.clientId);\n if (!ownIdentity) {\n throw new Error(\"Own identity not found\");\n }\n\n this.characterManager.spawnLocalCharacter(\n this.clientId!,\n ownIdentity.username ?? `Unknown User ${this.clientId}`,\n ownIdentity.characterDescription,\n spawnPosition,\n spawnRotation,\n );\n\n if (cameraPosition !== null) {\n this.cameraManager.camera.position.set(cameraPosition.x, cameraPosition.y, cameraPosition.z);\n this.cameraManager.setTarget(\n new Vect3().add(spawnPosition).add(CharacterManager.headTargetOffset),\n );\n this.cameraManager.reverseUpdateFromPositions();\n }\n }\n\n private disposeWithError(message: string) {\n this.dispose();\n this.errorScreen = new ErrorScreen(\"An error occurred\", message);\n this.element.append(this.errorScreen.element);\n }\n\n public dispose() {\n this.characterManager.dispose();\n this.networkClient.stop();\n for (const [key, element] of Object.entries(this.mmlFrames)) {\n element.remove();\n }\n this.mmlFrames = {};\n this.textChatUI?.dispose();\n this.mmlCompositionScene.dispose();\n this.composer.dispose();\n this.tweakPane?.dispose();\n if (this.currentRequestAnimationFrame !== null) {\n cancelAnimationFrame(this.currentRequestAnimationFrame);\n this.currentRequestAnimationFrame = null;\n }\n this.cameraManager.dispose();\n this.loadingScreen.dispose();\n this.errorScreen?.dispose();\n }\n\n private setupMMLScene() {\n registerCustomElementsToWindow(window);\n this.mmlCompositionScene = new MMLCompositionScene({\n targetElement: this.element,\n renderer: this.composer.renderer,\n scene: this.scene,\n camera: this.cameraManager.camera,\n audioListener: this.audioListener,\n collisionsManager: this.collisionsManager,\n getUserPositionAndRotation: () => {\n return this.characterManager.getLocalCharacterPositionAndRotation();\n },\n });\n this.scene.add(this.mmlCompositionScene.group);\n setGlobalMMLScene(this.mmlCompositionScene.mmlScene as IMMLScene);\n setGlobalDocumentTimeManager(this.mmlCompositionScene.documentTimeManager);\n\n this.setMMLDocuments(this.config.mmlDocuments ?? {});\n\n const mmlProgressManager = this.mmlCompositionScene.mmlScene.getLoadingProgressManager!()!;\n this.loadingProgressManager.addLoadingDocument(mmlProgressManager, \"mml\", mmlProgressManager);\n mmlProgressManager.addProgressCallback(() => {\n this.loadingProgressManager.updateDocumentProgress(mmlProgressManager);\n });\n mmlProgressManager.setInitialLoad(true);\n }\n\n private createFrame(mmlDocument: MMLDocumentConfiguration) {\n const frameElement = document.createElement(\"m-frame\");\n frameElement.setAttribute(\"src\", mmlDocument.url);\n this.updateFrameAttributes(frameElement, mmlDocument);\n return frameElement;\n }\n\n private updateFrameAttributes(frameElement: HTMLElement, mmlDocument: MMLDocumentConfiguration) {\n const existingSrc = frameElement.getAttribute(\"src\");\n if (existingSrc !== mmlDocument.url) {\n frameElement.setAttribute(\"src\", mmlDocument.url);\n }\n if (mmlDocument.position) {\n frameElement.setAttribute(\"x\", mmlDocument.position.x.toString());\n frameElement.setAttribute(\"y\", mmlDocument.position.y.toString());\n frameElement.setAttribute(\"z\", mmlDocument.position.z.toString());\n } else {\n frameElement.setAttribute(\"x\", \"0\");\n frameElement.setAttribute(\"y\", \"0\");\n frameElement.setAttribute(\"z\", \"0\");\n }\n if (mmlDocument.rotation) {\n frameElement.setAttribute(\"rx\", mmlDocument.rotation.x.toString());\n frameElement.setAttribute(\"ry\", mmlDocument.rotation.y.toString());\n frameElement.setAttribute(\"rz\", mmlDocument.rotation.z.toString());\n } else {\n frameElement.setAttribute(\"rx\", \"0\");\n frameElement.setAttribute(\"ry\", \"0\");\n frameElement.setAttribute(\"rz\", \"0\");\n }\n if (mmlDocument.scale?.x !== undefined) {\n frameElement.setAttribute(\"sx\", mmlDocument.scale.x.toString());\n } else {\n frameElement.setAttribute(\"sx\", \"1\");\n }\n if (mmlDocument.scale?.y !== undefined) {\n frameElement.setAttribute(\"sy\", mmlDocument.scale.y.toString());\n } else {\n frameElement.setAttribute(\"sy\", \"1\");\n }\n if (mmlDocument.scale?.z !== undefined) {\n frameElement.setAttribute(\"sz\", mmlDocument.scale.z.toString());\n } else {\n frameElement.setAttribute(\"sz\", \"1\");\n }\n }\n\n private setMMLDocuments(mmlDocuments: { [key: string]: MMLDocumentConfiguration }) {\n const newFramesMap: { [key: string]: HTMLElement } = {};\n for (const [key, mmlDocSpec] of Object.entries(mmlDocuments)) {\n const existing = this.mmlFrames[key];\n if (!existing) {\n const frameElement = this.createFrame(mmlDocSpec);\n document.body.appendChild(frameElement);\n newFramesMap[key] = frameElement;\n } else {\n delete this.mmlFrames[key];\n newFramesMap[key] = existing;\n this.updateFrameAttributes(existing, mmlDocSpec);\n }\n }\n for (const [key, element] of Object.entries(this.mmlFrames)) {\n element.remove();\n }\n this.mmlFrames = newFramesMap;\n }\n}\n", "import * as React from \"react\";\nimport { forwardRef } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { createRoot, Root } from \"react-dom/client\";\n\nimport { AvatarConfiguration, AvatarType } from \"./AvatarType\";\nimport { AvatarSelectionUIComponent } from \"./components/AvatarPanel/AvatarSectionUIComponent\";\n\nconst ForwardedAvatarSelectionUIComponent = forwardRef(AvatarSelectionUIComponent);\n\nexport type AvatarSelectionUIProps = {\n holderElement: HTMLElement;\n visibleByDefault?: boolean;\n displayName: string;\n characterDescription: AvatarType;\n allowCustomDisplayName: boolean;\n sendIdentityUpdateToServer: (displayName: string, characterDescription: AvatarType) => void;\n} & AvatarConfiguration;\n\nexport class AvatarSelectionUI {\n private root: Root;\n\n private wrapper = document.createElement(\"div\");\n\n constructor(private config: AvatarSelectionUIProps) {\n this.config.holderElement.appendChild(this.wrapper);\n this.root = createRoot(this.wrapper);\n }\n\n private onUpdateUserAvatar = (avatar: AvatarType) => {\n this.config.characterDescription = avatar;\n this.config.sendIdentityUpdateToServer(this.config.displayName, avatar);\n };\n\n private onUpdateDisplayName = (displayName: string) => {\n this.config.displayName = displayName;\n this.config.sendIdentityUpdateToServer(displayName, this.config.characterDescription);\n };\n\n public updateAvatarConfig(avatarConfig: AvatarConfiguration) {\n this.config = {\n ...this.config,\n ...avatarConfig,\n };\n this.init();\n }\n\n public updateAllowCustomDisplayName(allowCustomDisplayName: boolean) {\n this.config = {\n ...this.config,\n allowCustomDisplayName,\n };\n this.init();\n }\n\n init() {\n flushSync(() =>\n this.root.render(\n <ForwardedAvatarSelectionUIComponent\n onUpdateUserAvatar={this.onUpdateUserAvatar}\n onUpdateDisplayName={this.onUpdateDisplayName}\n visibleByDefault={this.config.visibleByDefault}\n displayName={this.config.displayName}\n characterDescription={this.config.characterDescription}\n availableAvatars={this.config.availableAvatars}\n allowCustomAvatars={this.config.allowCustomAvatars || false}\n allowCustomDisplayName={this.config.allowCustomDisplayName || false}\n />,\n ),\n );\n }\n}\n", "import React, {\n ForwardRefRenderFunction,\n KeyboardEvent,\n MouseEvent,\n useRef,\n useState,\n} from \"react\";\n\nimport { AvatarType } from \"../../AvatarType\";\nimport AvatarIcon from \"../../icons/Avatar.svg\";\n\nimport styles from \"./AvatarSelectionUIComponent.module.css\";\n\ntype AvatarSelectionUIProps = {\n onUpdateUserAvatar: (avatar: AvatarType) => void;\n visibleByDefault?: boolean;\n availableAvatars: AvatarType[];\n\n characterDescription: AvatarType;\n allowCustomAvatars: boolean;\n\n displayName: string;\n allowCustomDisplayName: boolean;\n onUpdateDisplayName: (displayNameValue: string) => void;\n};\n\nenum CustomAvatarType {\n meshFileUrl,\n mmlUrl,\n mml,\n}\n\nfunction SelectedPill() {\n return <span className={styles.selectedPill}>Selected</span>;\n}\n\nexport const AvatarSelectionUIComponent: ForwardRefRenderFunction<any, AvatarSelectionUIProps> = (\n props: AvatarSelectionUIProps,\n) => {\n const visibleByDefault: boolean = props.visibleByDefault ?? false;\n const [isVisible, setIsVisible] = useState<boolean>(visibleByDefault);\n const [selectedAvatar, setSelectedAvatar] = useState<AvatarType | undefined>(\n props.characterDescription,\n );\n const [customAvatarType, setCustomAvatarType] = useState<CustomAvatarType>(\n CustomAvatarType.mmlUrl,\n );\n const [customAvatarValue, setCustomAvatarValue] = useState<string>(\"\");\n const inputRef = useRef<HTMLInputElement>(null);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n const [displayNameValue, setDisplayNameValue] = useState<string>(props.displayName);\n const displayNameRef = useRef<HTMLInputElement>(null);\n\n const handleRootClick = (e: MouseEvent) => {\n e.stopPropagation();\n };\n\n const selectAvatar = (avatar: AvatarType) => {\n setSelectedAvatar(avatar);\n props.onUpdateUserAvatar(avatar);\n };\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n setCustomAvatarValue(e.target.value);\n };\n\n const handleDisplayNameChange = (\n e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,\n ) => {\n setDisplayNameValue(e.target.value);\n };\n\n const setDisplayName = () => {\n if (!displayNameValue) {\n return;\n }\n props.onUpdateDisplayName(displayNameValue);\n };\n\n const addCustomAvatar = () => {\n if (!customAvatarValue) {\n return;\n }\n\n let newSelectedAvatar: AvatarType;\n switch (customAvatarType) {\n case CustomAvatarType.mml:\n newSelectedAvatar = {\n mmlCharacterString: customAvatarValue,\n };\n break;\n case CustomAvatarType.mmlUrl:\n newSelectedAvatar = {\n mmlCharacterUrl: customAvatarValue,\n };\n break;\n case CustomAvatarType.meshFileUrl:\n newSelectedAvatar = {\n meshFileUrl: customAvatarValue,\n };\n break;\n }\n\n setSelectedAvatar(newSelectedAvatar);\n props.onUpdateUserAvatar(newSelectedAvatar);\n };\n\n const handleKeyPress = (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n e.stopPropagation();\n };\n\n const handleAvatarInputKeyPress = (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n e.stopPropagation();\n if (e.key === \"Enter\") {\n addCustomAvatar();\n }\n };\n\n const handleDisplayNameKeyPress = (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n e.stopPropagation();\n if (e.key === \"Enter\") {\n setDisplayName();\n }\n };\n\n const handleTypeSwitch = (type: CustomAvatarType) => {\n setCustomAvatarType(type);\n setCustomAvatarValue(\"\");\n };\n\n const getPlaceholderByType = (type: CustomAvatarType) => {\n switch (type) {\n case CustomAvatarType.meshFileUrl:\n return \"https://.../avatar.glb\";\n case CustomAvatarType.mmlUrl:\n return \"https://.../avatar.html\";\n case CustomAvatarType.mml:\n return '<m-character src=\"https://link-to-avatar\">\\n</m-character';\n }\n };\n\n if (\n !props.availableAvatars.length &&\n !props.allowCustomAvatars &&\n !props.allowCustomDisplayName\n ) {\n return null;\n }\n\n let recognizedAvatar = false;\n\n return (\n <>\n <div className={styles.menuButton} onClick={handleRootClick}>\n {!isVisible && (\n <div className={styles.openTab} onClick={() => setIsVisible(true)}>\n <img src={`data:image/svg+xml;utf8,${encodeURIComponent(AvatarIcon)}`} />\n </div>\n )}\n {isVisible && (\n <button className={styles.closeButton} onClick={(e) => setIsVisible(false)}>\n X\n </button>\n )}\n </div>\n {isVisible && (\n <div className={`${styles.avatarSelectionContainer}`}>\n {props.allowCustomDisplayName && (\n <div className={styles.displayNameSection}>\n <div className={styles.sectionHeading}>Display Name</div>\n <div className={styles.displayNameInputSection}>\n <input\n ref={displayNameRef}\n className={styles.input}\n value={displayNameValue}\n onKeyDown={handleDisplayNameKeyPress}\n onChange={handleDisplayNameChange}\n placeholder={\"Enter your display name\"}\n />\n <button\n className={styles.setButton}\n disabled={!displayNameValue}\n type=\"button\"\n onClick={setDisplayName}\n >\n Set\n </button>\n </div>\n </div>\n )}\n {!!props.availableAvatars.length && (\n <div className={styles.avatarSelectionSection}>\n <div className={styles.sectionHeading}>Choose your Avatar</div>\n <div className={styles.avatarSelectionUi}>\n {props.availableAvatars.map((avatar, index) => {\n const isSelected =\n (selectedAvatar?.meshFileUrl &&\n selectedAvatar?.meshFileUrl === avatar.meshFileUrl) ||\n (selectedAvatar?.mmlCharacterUrl &&\n selectedAvatar?.mmlCharacterUrl === avatar.mmlCharacterUrl) ||\n (selectedAvatar?.mmlCharacterString &&\n selectedAvatar?.mmlCharacterString === avatar.mmlCharacterString);\n\n if (isSelected) {\n recognizedAvatar = true;\n }\n\n return (\n <div\n key={index}\n className={styles.avatarSelectionUiAvatar}\n onClick={() => selectAvatar(avatar)}\n >\n <div className={styles.avatarSelectionUiAvatarImgContainer}>\n {isSelected && <SelectedPill />}\n {avatar.thumbnailUrl ? (\n <img\n className={styles.avatarSelectionUiAvatarImage}\n src={avatar.thumbnailUrl}\n alt={avatar.name}\n />\n ) : (\n <div className={styles.avatarSelectionNoImage}>\n <img\n alt={avatar.name}\n src={`data:image/svg+xml;utf8,${encodeURIComponent(AvatarIcon)}`}\n />\n </div>\n )}\n <p>{avatar.name}</p>\n <span className={styles.tooltipText}>{avatar.name}</span>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n )}\n {props.allowCustomAvatars && (\n <div className={styles.customAvatarSection}>\n <div className={styles.sectionHeading}>Custom Avatar</div>\n <div className={styles.radioGroup}>\n <div className={styles.radioItem}>\n <input\n type=\"radio\"\n id=\"html\"\n name=\"customAvatarType\"\n onChange={() => handleTypeSwitch(CustomAvatarType.mmlUrl)}\n checked={customAvatarType === CustomAvatarType.mmlUrl}\n />\n <label htmlFor=\"html\">MML URL</label>\n </div>\n <div className={styles.radioItem}>\n <input\n type=\"radio\"\n id=\"mml\"\n name=\"customAvatarType\"\n onChange={() => handleTypeSwitch(CustomAvatarType.mml)}\n checked={customAvatarType === CustomAvatarType.mml}\n />\n <label htmlFor=\"mml\">MML</label>\n </div>\n <div className={styles.radioItem}>\n <input\n type=\"radio\"\n id=\"glb\"\n name=\"customAvatarType\"\n onChange={() => handleTypeSwitch(CustomAvatarType.meshFileUrl)}\n checked={customAvatarType === CustomAvatarType.meshFileUrl}\n />\n <label htmlFor=\"glb\">Mesh URL</label>\n </div>\n {!recognizedAvatar && <SelectedPill />}\n </div>\n <div className={styles.customAvatarInputSection}>\n {customAvatarType === CustomAvatarType.mml ? (\n <textarea\n ref={textareaRef}\n className={styles.input}\n value={customAvatarValue}\n onChange={handleInputChange}\n onKeyDown={handleKeyPress}\n placeholder={getPlaceholderByType(customAvatarType)}\n rows={4}\n />\n ) : (\n <input\n ref={inputRef}\n className={styles.input}\n value={customAvatarValue}\n onKeyDown={handleAvatarInputKeyPress}\n onChange={handleInputChange}\n placeholder={getPlaceholderByType(customAvatarType)}\n />\n )}\n <button\n className={styles.setButton}\n disabled={!customAvatarValue}\n type=\"button\"\n onClick={addCustomAvatar}\n >\n Set\n </button>\n </div>\n </div>\n )}\n </div>\n )}\n </>\n );\n};\n", "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448 512\"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d=\"M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512l388.6 0c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304l-91.4 0z\"/></svg>\n", "\nconst content = __content_placeholder__;\nconst digest = __digest_placeholder__; \nconst inject = () => {\n setTimeout(() => {\n if (!globalThis.document) {\n return;\n }\n let root = globalThis.document.querySelector(\"head\");\n if (root && root.shadowRoot) {\n root = root.shadowRoot;\n }\n if (!root) {\n root = globalThis.document.head;\n }\n let container = root.querySelector(\"#_\" + digest);\n if (!container) {\n container = globalThis.document.createElement(\"style\");\n container.id = \"_\" + digest;\n const text = globalThis.document.createTextNode(content);\n container.appendChild(text);\n root.appendChild(container);\n }\n }, 0);\n};\n\nexport { inject };\n ", "import \"esbuild-css-modules-plugin-ns-css:src/avatar-selection-ui/components/AvatarPanel/AvatarSelectionUIComponent.module.css\";\n\nimport { inject } from \"esbuild-css-modules-plugin-ns-js:src/avatar-selection-ui/components/AvatarPanel/AvatarSelectionUIComponent.module.css:injector.js\";\nexport default new Proxy({\n \"avatarSelectionContainer\": \"AvatarSelectionUIComponent-module__avatarSelectionContainer_VjZ7cq__0232\",\n \"avatarSelectionNoImage\": \"AvatarSelectionUIComponent-module__avatarSelectionNoImage_VjZ7cq__0232\",\n \"avatarSelectionSection\": \"AvatarSelectionUIComponent-module__avatarSelectionSection_VjZ7cq__0232\",\n \"avatarSelectionUi\": \"AvatarSelectionUIComponent-module__avatarSelectionUi_VjZ7cq__0232\",\n \"avatarSelectionUiAvatar\": \"AvatarSelectionUIComponent-module__avatarSelectionUiAvatar_VjZ7cq__0232\",\n \"avatarSelectionUiAvatarImage\": \"AvatarSelectionUIComponent-module__avatarSelectionUiAvatarImage_VjZ7cq__0232\",\n \"avatarSelectionUiAvatarImgContainer\": \"AvatarSelectionUIComponent-module__avatarSelectionUiAvatarImgContainer_VjZ7cq__0232\",\n \"avatarSelectionUiCloseButton\": \"AvatarSelectionUIComponent-module__avatarSelectionUiCloseButton_VjZ7cq__0232\",\n \"avatarSelectionUiHeader\": \"AvatarSelectionUIComponent-module__avatarSelectionUiHeader_VjZ7cq__0232\",\n \"closeButton\": \"AvatarSelectionUIComponent-module__closeButton_VjZ7cq__0232\",\n \"customAvatarInputSection\": \"AvatarSelectionUIComponent-module__customAvatarInputSection_VjZ7cq__0232\",\n \"customAvatarSection\": \"AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0232\",\n \"displayNameInputSection\": \"AvatarSelectionUIComponent-module__displayNameInputSection_VjZ7cq__0232\",\n \"displayNameSection\": \"AvatarSelectionUIComponent-module__displayNameSection_VjZ7cq__0232\",\n \"input\": \"AvatarSelectionUIComponent-module__input_VjZ7cq__0232\",\n \"menuButton\": \"AvatarSelectionUIComponent-module__menuButton_VjZ7cq__0232\",\n \"openTab\": \"AvatarSelectionUIComponent-module__openTab_VjZ7cq__0232\",\n \"radioGroup\": \"AvatarSelectionUIComponent-module__radioGroup_VjZ7cq__0232\",\n \"radioItem\": \"AvatarSelectionUIComponent-module__radioItem_VjZ7cq__0232\",\n \"sectionHeading\": \"AvatarSelectionUIComponent-module__sectionHeading_VjZ7cq__0232\",\n \"selectedPill\": \"AvatarSelectionUIComponent-module__selectedPill_VjZ7cq__0232\",\n \"setButton\": \"AvatarSelectionUIComponent-module__setButton_VjZ7cq__0232\",\n \"tooltipText\": \"AvatarSelectionUIComponent-module__tooltipText_VjZ7cq__0232\"\n}, {\n get: function(source, key) {\n inject();\n return source[key];\n }\n});\n ", "import { createRef, forwardRef } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { createRoot, Root } from \"react-dom/client\";\n\nimport { ChatUIComponent } from \"./components/ChatPanel/TextChatUIComponent\";\n\nexport type StringToHslOptions = {\n hueThresholds?: [number, number][];\n saturationThresholds?: [number, number][];\n lightnessThresholds?: [number, number][];\n};\n\nconst DEFAULT_HUE_RANGES: [number, number][] = [[10, 350]];\nconst DEFAULT_SATURATION_RANGES: [number, number][] = [[60, 100]];\nconst DEFAULT_LIGHTNESS_RANGES: [number, number][] = [[65, 75]];\n\nexport const DEFAULT_HSL_OPTIONS: StringToHslOptions = {\n hueThresholds: DEFAULT_HUE_RANGES,\n saturationThresholds: DEFAULT_SATURATION_RANGES,\n lightnessThresholds: DEFAULT_LIGHTNESS_RANGES,\n};\n\nconst ForwardedChatUIComponent = forwardRef(ChatUIComponent);\n\nexport type ChatUIInstance = {\n addMessage: (username: string, message: string) => void;\n};\n\nexport type TextChatUIProps = {\n holderElement: HTMLElement;\n sendMessageToServerMethod: (message: string) => void;\n visibleByDefault?: boolean;\n stringToHslOptions?: StringToHslOptions;\n};\n\nexport class TextChatUI {\n private root: Root;\n private appRef = createRef<ChatUIInstance>();\n\n public addTextMessage(username: string, message: string) {\n if (this.appRef.current) {\n this.appRef.current.addMessage(username, message);\n }\n }\n\n private wrapper = document.createElement(\"div\");\n\n constructor(private config: TextChatUIProps) {\n this.config.holderElement.appendChild(this.wrapper);\n this.root = createRoot(this.wrapper);\n }\n\n dispose() {\n this.root.unmount();\n this.wrapper.remove();\n }\n\n init() {\n flushSync(() =>\n this.root.render(\n <ForwardedChatUIComponent\n ref={this.appRef}\n sendMessageToServer={this.config.sendMessageToServerMethod}\n visibleByDefault={this.config.visibleByDefault}\n stringToHslOptions={this.config.stringToHslOptions}\n />,\n ),\n );\n }\n}\n", "import {\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n ForwardRefRenderFunction,\n MouseEvent,\n} from \"react\";\n\nimport { useClickOutside } from \"../../helpers\";\nimport ChatIcon from \"../../icons/Chat.svg\";\nimport PinButton from \"../../icons/Pin.svg\";\nimport { StringToHslOptions, type ChatUIInstance } from \"../../TextChatUI\";\nimport { InputBox } from \"../Input/InputBox\";\nimport { Messages } from \"../Messages/Messages\";\n\nimport styles from \"./TextChatUIComponent.module.css\";\ntype ChatUIProps = {\n sendMessageToServer: (message: string) => void;\n visibleByDefault?: boolean;\n stringToHslOptions?: StringToHslOptions;\n};\n\nconst MAX_MESSAGES = 50;\nconst SECONDS_TO_FADE_OUT = 6;\nconst AUTO_SCROLL_RESET_DELAY_MS = 100;\n\nexport const ChatUIComponent: ForwardRefRenderFunction<ChatUIInstance, ChatUIProps> = (\n props: ChatUIProps,\n ref,\n) => {\n const visibleByDefault: boolean = props.visibleByDefault ?? true;\n const [messages, setMessages] = useState<Array<{ username: string; message: string }>>([]);\n const [isVisible, setIsVisible] = useState<boolean>(visibleByDefault);\n const [isSticky, setSticky] = useState<boolean>(visibleByDefault);\n const [isFocused, setIsFocused] = useState(false);\n const [isOpenHovered, setOpenHovered] = useState(false);\n const [shouldAutoScroll, setShouldAutoScroll] = useState(false);\n\n const [panelStyle, setPanelStyle] = useState(styles.fadeOut);\n const [stickyStyle, setStickyStyle] = useState(styles.stickyButton);\n\n const stickyButtonRef = useRef<HTMLDivElement>(null);\n const closeButtonRef = useRef<HTMLDivElement>(null);\n const hideTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const inputBoxRef = useRef<{ focusInput: () => void } | null>(null);\n\n const startHideTimeout = useCallback(() => {\n if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = setTimeout(() => {\n if (isVisible) {\n setIsVisible(false);\n }\n }, SECONDS_TO_FADE_OUT * 1000);\n }, [isVisible]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (e.key === \"Enter\") {\n if (!isVisible) setIsVisible(true);\n setIsFocused(true);\n if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);\n if (inputBoxRef.current) inputBoxRef.current.focusInput();\n }\n },\n [isVisible],\n );\n\n const handleBlur = useCallback(() => {\n if (isFocused) setIsFocused(false);\n startHideTimeout();\n if (closeButtonRef.current) closeButtonRef.current.focus();\n }, [isFocused, startHideTimeout]);\n\n const hide = () => {\n setIsVisible(false);\n setIsFocused(false);\n if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);\n };\n\n const handleRootClick = (e: MouseEvent) => {\n e.stopPropagation();\n setOpenHovered(true);\n if (!isVisible) setIsVisible(true);\n };\n\n const handleStickyButton = (e: MouseEvent) => {\n e.stopPropagation();\n setSticky(!isSticky);\n };\n\n const handleWheel = (e: React.WheelEvent) => {\n e.stopPropagation();\n };\n\n const handleMouseLeave = () => {\n setOpenHovered(false);\n if (!isFocused && !isSticky && isVisible) {\n startHideTimeout();\n }\n };\n\n const handleMouseEnter = () => {\n setOpenHovered(true);\n if (!isVisible) setIsVisible(true);\n };\n\n const chatPanelRef = useClickOutside(() => {\n if (isFocused) {\n setIsFocused(false);\n startHideTimeout();\n }\n });\n\n useEffect(() => {\n if (isVisible && isSticky) {\n if (chatPanelRef.current) chatPanelRef.current.style.zIndex = \"100\";\n }\n setPanelStyle(isVisible || isFocused || isSticky ? styles.fadeIn : styles.fadeOut);\n setStickyStyle(\n isSticky\n ? styles.stickyButtonEnabled\n : isOpenHovered\n ? styles.stickyButton\n : styles.stickyButtonFadeOut,\n );\n if (chatPanelRef.current && chatPanelRef.current.style.zIndex !== \"100\") {\n // we just want to change the z-index after the browser has the chance\n // to apply the CSS to the SVG icons\n setTimeout(() => {\n if (chatPanelRef.current) chatPanelRef.current.style.zIndex = \"100\";\n }, 2000);\n }\n }, [isVisible, isSticky, isFocused, chatPanelRef, isOpenHovered]);\n\n const appendMessages = (username: string, message: string) => {\n setMessages((prev) => {\n const newMessages = [...prev, { username, message }];\n return newMessages.length > MAX_MESSAGES ? newMessages.slice(-MAX_MESSAGES) : newMessages;\n });\n };\n\n useImperativeHandle(ref, () => ({\n addMessage: (username: string, message: string) => {\n appendMessages(username, message);\n if (!isVisible) setIsVisible(true);\n startHideTimeout();\n },\n }));\n\n const handleSendMessage = (message: string) => {\n setShouldAutoScroll(true);\n props.sendMessageToServer(message);\n // Reset after a short delay\n setTimeout(() => setShouldAutoScroll(false), AUTO_SCROLL_RESET_DELAY_MS);\n };\n\n const setFocus = () => setIsFocused(true);\n\n useEffect(() => {\n window.addEventListener(\"keydown\", handleKeyDown, false);\n window.addEventListener(\"blur\", handleBlur, false);\n return () => {\n window.removeEventListener(\"keydown\", handleKeyDown, false);\n window.removeEventListener(\"blur\", handleBlur, false);\n };\n }, [handleBlur, handleKeyDown]);\n\n return (\n <div className={styles.textChatUi}>\n <div\n className={styles.uiHover}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onClick={handleRootClick}\n >\n <div className={styles.openTab} onClick={hide}>\n <img src={`data:image/svg+xml;utf8,${encodeURIComponent(ChatIcon)}`} />\n </div>\n <div ref={stickyButtonRef} className={stickyStyle} onClick={handleStickyButton}>\n <img src={`data:image/svg+xml;utf8,${encodeURIComponent(PinButton)}`} />\n </div>\n </div>\n <div\n ref={chatPanelRef}\n style={{ zIndex: -1 }}\n id=\"text-chat-wrapper\"\n className={`${styles.textChat} ${panelStyle}`}\n onWheel={handleWheel}\n >\n <div className={styles.messagesWrapper}>\n <Messages\n messages={messages}\n stringToHslOptions={props.stringToHslOptions}\n shouldAutoScroll={shouldAutoScroll}\n />\n </div>\n <InputBox\n ref={inputBoxRef}\n onSendMessage={handleSendMessage}\n hide={hide}\n setFocus={setFocus}\n />\n </div>\n </div>\n );\n};\n", "import { useEffect, useLayoutEffect, useRef } from \"react\";\n\ntype ClickAwayCallback = (event: MouseEvent | TouchEvent) => void;\n\nexport function useClickOutside(cb: ClickAwayCallback) {\n const ref = useRef<HTMLDivElement>(null);\n const refCb = useRef<ClickAwayCallback>(cb);\n\n useLayoutEffect(() => {\n refCb.current = cb;\n });\n\n useEffect(() => {\n const handler = (e: MouseEvent | TouchEvent) => {\n const element = ref.current;\n if (element && !element.contains(e.target as Node)) {\n refCb.current(e);\n }\n };\n\n document.addEventListener(\"mousedown\", handler);\n document.addEventListener(\"touchstart\", handler);\n\n return () => {\n document.removeEventListener(\"mousedown\", handler);\n document.removeEventListener(\"touchstart\", handler);\n };\n }, []);\n\n return ref;\n}\n", "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 512\"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d=\"M88.2 309.1c9.8-18.3 6.8-40.8-7.5-55.8C59.4 230.9 48 204 48 176c0-63.5 63.8-128 160-128s160 64.5 160 128s-63.8 128-160 128c-13.1 0-25.8-1.3-37.8-3.6c-10.4-2-21.2-.6-30.7 4.2c-4.1 2.1-8.3 4.1-12.6 6c-16 7.2-32.9 13.5-49.9 18c2.8-4.6 5.4-9.1 7.9-13.6c1.1-1.9 2.2-3.9 3.2-5.9zM0 176c0 41.8 17.2 80.1 45.9 110.3c-.9 1.7-1.9 3.5-2.8 5.1c-10.3 18.4-22.3 36.5-36.6 52.1c-6.6 7-8.3 17.2-4.6 25.9C5.8 378.3 14.4 384 24 384c43 0 86.5-13.3 122.7-29.7c4.8-2.2 9.6-4.5 14.2-6.8c15.1 3 30.9 4.5 47.1 4.5c114.9 0 208-78.8 208-176S322.9 0 208 0S0 78.8 0 176zM432 480c16.2 0 31.9-1.6 47.1-4.5c4.6 2.3 9.4 4.6 14.2 6.8C529.5 498.7 573 512 616 512c9.6 0 18.2-5.7 22-14.5c3.8-8.8 2-19-4.6-25.9c-14.2-15.6-26.2-33.7-36.6-52.1c-.9-1.7-1.9-3.4-2.8-5.1C622.8 384.1 640 345.8 640 304c0-94.4-87.9-171.5-198.2-175.8c4.1 15.2 6.2 31.2 6.2 47.8l0 .6c87.2 6.7 144 67.5 144 127.4c0 28-11.4 54.9-32.7 77.2c-14.3 15-17.3 37.6-7.5 55.8c1.1 2 2.2 4 3.2 5.9c2.5 4.5 5.2 9 7.9 13.6c-17-4.5-33.9-10.7-49.9-18c-4.3-1.9-8.5-3.9-12.6-6c-9.5-4.8-20.3-6.2-30.7-4.2c-12.1 2.4-24.7 3.6-37.8 3.6c-61.7 0-110-26.5-136.8-62.3c-16 5.4-32.8 9.4-50 11.8C279 439.8 350 480 432 480z\"/></svg>", "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d=\"M32 32C32 14.3 46.3 0 64 0H320c17.7 0 32 14.3 32 32s-14.3 32-32 32H290.5l11.4 148.2c36.7 19.9 65.7 53.2 79.5 94.7l1 3c3.3 9.8 1.6 20.5-4.4 28.8s-15.7 13.3-26 13.3H32c-10.3 0-19.9-4.9-26-13.3s-7.7-19.1-4.4-28.8l1-3c13.8-41.5 42.8-74.8 79.5-94.7L93.5 64H64C46.3 64 32 49.7 32 32zM160 384h64v96c0 17.7-14.3 32-32 32s-32-14.3-32-32V384z\"/></svg>", "import { forwardRef, KeyboardEvent, useImperativeHandle, useRef, useState } from \"react\";\n\nimport SendButton from \"../../icons/PaperPlane.svg\";\n\nimport styles from \"./InputBox.module.css\";\n\ntype InputBoxProps = {\n onSendMessage: (message: string) => void;\n hide: () => void;\n setFocus: () => void;\n};\n\nexport const InputBox = forwardRef<{ focusInput: () => void } | null, InputBoxProps>(\n ({ onSendMessage, hide, setFocus }, ref) => {\n const inputRef = useRef<HTMLInputElement>(null);\n const buttonRef = useRef<HTMLButtonElement>(null);\n const [inputValue, setInputValue] = useState(\"\");\n\n useImperativeHandle(ref, () => ({\n focusInput: () => {\n if (inputRef.current) inputRef.current.focus();\n },\n }));\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setInputValue(e.target.value);\n };\n\n const handleSendClick = () => {\n if (inputValue.trim() !== \"\") {\n onSendMessage(inputValue.trim());\n setInputValue(\"\");\n }\n };\n\n const handleKeyPress = (e: KeyboardEvent<HTMLInputElement>) => {\n e.stopPropagation();\n if (e.key === \"Enter\") {\n if (inputRef.current?.value.trim().length === 0) {\n if (buttonRef.current) buttonRef.current.focus();\n hide();\n return;\n }\n handleSendClick();\n }\n };\n\n return (\n <div className={styles.inputWrapper}>\n <input\n ref={inputRef}\n type=\"text\"\n placeholder=\"Type your message here...\"\n value={inputValue}\n onChange={handleInputChange}\n className={styles.chatInput}\n onKeyDown={handleKeyPress}\n onFocus={setFocus}\n />\n <button ref={buttonRef} onClick={handleSendClick} className={styles.sendButton}>\n <div className={styles.svgIcon}>\n <img src={`data:image/svg+xml;utf8,${encodeURIComponent(SendButton)}`} />\n </div>\n </button>\n </div>\n );\n },\n);\nInputBox.displayName = \"InputBox\";\n", "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d=\"M498.1 5.6c10.1 7 15.4 19.1 13.5 31.2l-64 416c-1.5 9.7-7.4 18.2-16 23s-18.9 5.4-28 1.6L284 427.7l-68.5 74.1c-8.9 9.7-22.9 12.9-35.2 8.1S160 493.2 160 480V396.4c0-4 1.5-7.8 4.2-10.7L331.8 202.8c5.8-6.3 5.6-16-.4-22s-15.7-6.4-22-.7L106 360.8 17.7 316.6C7.1 311.3 .3 300.7 0 288.9s5.9-22.8 16.1-28.7l448-256c10.7-6.1 23.9-5.5 34 1.4z\"/></svg>", "\nconst content = __content_placeholder__;\nconst digest = __digest_placeholder__; \nconst inject = () => {\n setTimeout(() => {\n if (!globalThis.document) {\n return;\n }\n let root = globalThis.document.querySelector(\"head\");\n if (root && root.shadowRoot) {\n root = root.shadowRoot;\n }\n if (!root) {\n root = globalThis.document.head;\n }\n let container = root.querySelector(\"#_\" + digest);\n if (!container) {\n container = globalThis.document.createElement(\"style\");\n container.id = \"_\" + digest;\n const text = globalThis.document.createTextNode(content);\n container.appendChild(text);\n root.appendChild(container);\n }\n }, 0);\n};\n\nexport { inject };\n ", "import \"esbuild-css-modules-plugin-ns-css:src/chat-ui/components/Input/InputBox.module.css\";\n\nimport { inject } from \"esbuild-css-modules-plugin-ns-js:src/chat-ui/components/Input/InputBox.module.css:injector.js\";\nexport default new Proxy({\n \"chatInput\": \"InputBox-module__chatInput_adOgOW__0232\",\n \"inputWrapper\": \"InputBox-module__inputWrapper_adOgOW__0232\",\n \"sendButton\": \"InputBox-module__sendButton_adOgOW__0232\",\n \"svgIcon\": \"InputBox-module__svgIcon_adOgOW__0232\"\n}, {\n get: function(source, key) {\n inject();\n return source[key];\n }\n});\n ", "import { FC, useEffect, useRef, useState } from \"react\";\n\nimport { StringToHslOptions } from \"../../TextChatUI\";\nimport Message from \"../Message/Message\";\n\nimport styles from \"./Messages.module.css\";\n\ntype MessagesProps = {\n messages: Array<{ username: string; message: string }>;\n stringToHslOptions?: StringToHslOptions;\n shouldAutoScroll?: boolean;\n};\n\nconst SCROLL_THRESHOLD_PX = 10; // Threshold to consider \"at bottom\" for scroll position\n\nexport const Messages: FC<MessagesProps> = ({ messages, stringToHslOptions, shouldAutoScroll }) => {\n const messagesEndRef = useRef<null | HTMLDivElement>(null);\n const containerRef = useRef<null | HTMLDivElement>(null);\n const [unreadCount, setUnreadCount] = useState(0);\n const [lastReadMessageIndex, setLastReadMessageIndex] = useState(0);\n const [wasAtBottom, setWasAtBottom] = useState(true);\n\n const isAtBottom = () => {\n if (!containerRef.current) return true;\n const { scrollTop, scrollHeight, clientHeight } = containerRef.current;\n return Math.abs(scrollHeight - clientHeight - scrollTop) < SCROLL_THRESHOLD_PX;\n };\n\n const handleScroll = () => {\n const atBottom = isAtBottom();\n setWasAtBottom(atBottom);\n\n // Mark messages as read when scrolled to bottom\n if (atBottom && unreadCount > 0) {\n setUnreadCount(0);\n setLastReadMessageIndex(messages.length - 1);\n }\n };\n\n const scrollToBottom = () => {\n if (messagesEndRef.current) {\n messagesEndRef.current.scrollIntoView({ behavior: \"smooth\" });\n }\n setUnreadCount(0);\n setLastReadMessageIndex(messages.length - 1);\n setWasAtBottom(true);\n };\n\n useEffect(() => {\n if (messages.length === 0) return;\n\n // Should auto-scroll if user sent message or was at bottom\n const shouldScroll = shouldAutoScroll || wasAtBottom;\n\n if (shouldScroll) {\n // Use setTimeout to ensure DOM is updated, then check if we need to scroll\n setTimeout(() => {\n if (!isAtBottom()) {\n if (messagesEndRef.current) {\n messagesEndRef.current.scrollIntoView({ behavior: \"smooth\" });\n }\n }\n setWasAtBottom(true);\n }, 0);\n setUnreadCount(0);\n setLastReadMessageIndex(messages.length - 1);\n } else {\n // User is scrolled up and this is someone else's message\n const newUnreadCount = messages.length - 1 - lastReadMessageIndex;\n setUnreadCount(newUnreadCount);\n }\n }, [messages, shouldAutoScroll, wasAtBottom, lastReadMessageIndex]);\n\n return (\n <>\n <div ref={containerRef} className={styles.messagesContainer} onScroll={handleScroll}>\n {messages.map((msg, index) => (\n <Message\n key={index}\n username={msg.username}\n message={msg.message}\n stringToHslOptions={stringToHslOptions}\n />\n ))}\n <div ref={messagesEndRef}></div>\n </div>\n {unreadCount > 0 && (\n <button className={styles.newMessagesButton} onClick={scrollToBottom}>\n {unreadCount} new message{unreadCount !== 1 ? \"s\" : \"\"}\n </button>\n )}\n </>\n );\n};\n", "import { FC, useState, useEffect, useCallback } from \"react\";\n\nimport { DEFAULT_HSL_OPTIONS, StringToHslOptions } from \"../../TextChatUI\";\n\nimport styles from \"./Message.module.css\";\n\nfunction ReverseHash(input: string): number {\n // Hash has an initial value of 5381. As bit shifting is used, output can be any signed 32 bit Integer.\n const stringLength = input.length;\n let hash = 5381;\n\n for (let i = stringLength - 1; i >= 0; i--) {\n hash = (hash << 5) + hash + input.charCodeAt(i);\n }\n\n return hash;\n}\n\nfunction generateValueFromThresholds(hash: number, thresholds: [number, number][]): number {\n const selectedThreshold = thresholds[hash % thresholds.length];\n const min = Math.min(...selectedThreshold);\n const max = Math.max(...selectedThreshold);\n\n const thresholdRange = Math.abs(max - min);\n return (hash % thresholdRange) + min;\n}\n\nfunction hslForString(\n input: string,\n options: StringToHslOptions = DEFAULT_HSL_OPTIONS,\n): [number, number, number] {\n // Because JS bit shifting only operates on 32-Bit signed Integers,\n // in the case of overflow where a negative hash is inappropriate,\n // the absolute value has to be taken. This 'halves' our theoretical\n // hash distribution. This may require an alternate approach if\n // collisions are too frequent.\n let hash = Math.abs(ReverseHash(\"lightness: \" + input));\n\n const lightness = options.lightnessThresholds\n ? generateValueFromThresholds(hash, options.lightnessThresholds)\n : generateValueFromThresholds(hash, DEFAULT_HSL_OPTIONS.lightnessThresholds!);\n\n hash = Math.abs(ReverseHash(\"saturation:\" + input));\n const saturation = options.saturationThresholds\n ? generateValueFromThresholds(hash, options.saturationThresholds)\n : generateValueFromThresholds(hash, DEFAULT_HSL_OPTIONS.saturationThresholds!);\n\n hash = Math.abs(ReverseHash(\"hue:\" + input));\n const hue = options.hueThresholds\n ? generateValueFromThresholds(hash, options.hueThresholds)\n : generateValueFromThresholds(hash, DEFAULT_HSL_OPTIONS.hueThresholds!);\n\n return [hue, saturation, lightness];\n}\n\ntype MessageProps = {\n username: string;\n message: string;\n stringToHslOptions?: StringToHslOptions;\n};\n\nconst Message: FC<MessageProps> = ({ username, message, stringToHslOptions }) => {\n const [userColors, setUserColors] = useState<Map<string, string>>(new Map());\n\n const generateColorForUsername = useCallback((): string => {\n const [hue, saturation, lightness] = hslForString(username, stringToHslOptions);\n return `hsl(${hue}, ${saturation}%, ${lightness}%)`;\n }, [stringToHslOptions, username]);\n\n useEffect(() => {\n if (!userColors.has(username)) {\n const color = generateColorForUsername();\n setUserColors(new Map(userColors).set(username, color));\n }\n }, [username, userColors, generateColorForUsername]);\n\n const userColor = userColors.get(username) || \"hsl(0, 0%, 0%)\";\n\n return (\n <div className={styles.messageContainer}>\n <span className={styles.userName} style={{ color: userColor }}>\n {username}\n </span>\n : {message}\n </div>\n );\n};\n\nexport default Message;\n", "\nconst content = __content_placeholder__;\nconst digest = __digest_placeholder__; \nconst inject = () => {\n setTimeout(() => {\n if (!globalThis.document) {\n return;\n }\n let root = globalThis.document.querySelector(\"head\");\n if (root && root.shadowRoot) {\n root = root.shadowRoot;\n }\n if (!root) {\n root = globalThis.document.head;\n }\n let container = root.querySelector(\"#_\" + digest);\n if (!container) {\n container = globalThis.document.createElement(\"style\");\n container.id = \"_\" + digest;\n const text = globalThis.document.createTextNode(content);\n container.appendChild(text);\n root.appendChild(container);\n }\n }, 0);\n};\n\nexport { inject };\n ", "import \"esbuild-css-modules-plugin-ns-css:src/chat-ui/components/Message/Message.module.css\";\n\nimport { inject } from \"esbuild-css-modules-plugin-ns-js:src/chat-ui/components/Message/Message.module.css:injector.js\";\nexport default new Proxy({\n \"messageContainer\": \"Message-module__messageContainer_ikOQiq__0232\",\n \"userName\": \"Message-module__userName_ikOQiq__0232\"\n}, {\n get: function(source, key) {\n inject();\n return source[key];\n }\n});\n ", "\nconst content = __content_placeholder__;\nconst digest = __digest_placeholder__; \nconst inject = () => {\n setTimeout(() => {\n if (!globalThis.document) {\n return;\n }\n let root = globalThis.document.querySelector(\"head\");\n if (root && root.shadowRoot) {\n root = root.shadowRoot;\n }\n if (!root) {\n root = globalThis.document.head;\n }\n let container = root.querySelector(\"#_\" + digest);\n if (!container) {\n container = globalThis.document.createElement(\"style\");\n container.id = \"_\" + digest;\n const text = globalThis.document.createTextNode(content);\n container.appendChild(text);\n root.appendChild(container);\n }\n }, 0);\n};\n\nexport { inject };\n ", "import \"esbuild-css-modules-plugin-ns-css:src/chat-ui/components/Messages/Messages.module.css\";\n\nimport { inject } from \"esbuild-css-modules-plugin-ns-js:src/chat-ui/components/Messages/Messages.module.css:injector.js\";\nexport default new Proxy({\n \"messagesContainer\": \"Messages-module__messagesContainer_LXaUUW__0232\",\n \"newMessagesButton\": \"Messages-module__newMessagesButton_LXaUUW__0232\"\n}, {\n get: function(source, key) {\n inject();\n return source[key];\n }\n});\n ", "\nconst content = __content_placeholder__;\nconst digest = __digest_placeholder__; \nconst inject = () => {\n setTimeout(() => {\n if (!globalThis.document) {\n return;\n }\n let root = globalThis.document.querySelector(\"head\");\n if (root && root.shadowRoot) {\n root = root.shadowRoot;\n }\n if (!root) {\n root = globalThis.document.head;\n }\n let container = root.querySelector(\"#_\" + digest);\n if (!container) {\n container = globalThis.document.createElement(\"style\");\n container.id = \"_\" + digest;\n const text = globalThis.document.createTextNode(content);\n container.appendChild(text);\n root.appendChild(container);\n }\n }, 0);\n};\n\nexport { inject };\n ", "import \"esbuild-css-modules-plugin-ns-css:src/chat-ui/components/ChatPanel/TextChatUIComponent.module.css\";\n\nimport { inject } from \"esbuild-css-modules-plugin-ns-js:src/chat-ui/components/ChatPanel/TextChatUIComponent.module.css:injector.js\";\nexport default new Proxy({\n \"closeButton\": \"TextChatUIComponent-module__closeButton_gFDdcW__0232\",\n \"controls\": \"TextChatUIComponent-module__controls_gFDdcW__0232\",\n \"fadeIn\": \"TextChatUIComponent-module__fadeIn_gFDdcW__0232\",\n \"fadeOut\": \"TextChatUIComponent-module__fadeOut_gFDdcW__0232\",\n \"messagesWrapper\": \"TextChatUIComponent-module__messagesWrapper_gFDdcW__0232\",\n \"openTab\": \"TextChatUIComponent-module__openTab_gFDdcW__0232\",\n \"stickyButton\": \"TextChatUIComponent-module__stickyButton_gFDdcW__0232\",\n \"stickyButtonEnabled\": \"TextChatUIComponent-module__stickyButtonEnabled_gFDdcW__0232\",\n \"stickyButtonFadeOut\": \"TextChatUIComponent-module__stickyButtonFadeOut_gFDdcW__0232\",\n \"textChat\": \"TextChatUIComponent-module__textChat_gFDdcW__0232\",\n \"textChatUi\": \"TextChatUIComponent-module__textChatUi_gFDdcW__0232\",\n \"uiHover\": \"TextChatUIComponent-module__uiHover_gFDdcW__0232\"\n}, {\n get: function(source, key) {\n inject();\n return source[key];\n }\n});\n ", "\nconst content = __content_placeholder__;\nconst digest = __digest_placeholder__; \nconst inject = () => {\n setTimeout(() => {\n if (!globalThis.document) {\n return;\n }\n let root = globalThis.document.querySelector(\"head\");\n if (root && root.shadowRoot) {\n root = root.shadowRoot;\n }\n if (!root) {\n root = globalThis.document.head;\n }\n let container = root.querySelector(\"#_\" + digest);\n if (!container) {\n container = globalThis.document.createElement(\"style\");\n container.id = \"_\" + digest;\n const text = globalThis.document.createTextNode(content);\n container.appendChild(text);\n root.appendChild(container);\n }\n }, 0);\n};\n\nexport { inject };\n ", "import \"esbuild-css-modules-plugin-ns-css:src/Networked3dWebExperience.module.css\";\n\nimport { inject } from \"esbuild-css-modules-plugin-ns-js:src/Networked3dWebExperience.module.css:injector.js\";\nexport default new Proxy({\n \"respawnButton\": \"Networked3dWebExperience-module__respawnButton_7g9l0W__0232\"\n}, {\n get: function(source, key) {\n inject();\n return source[key];\n }\n});\n "],
|
5
5
|
"mappings": "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",
|
6
6
|
"names": ["jsx", "forwardRef", "flushSync", "createRoot", "useCallback", "useEffect", "useImperativeHandle", "useRef", "useState", "useRef", "forwardRef", "useRef", "useState", "content", "digest", "inject", "inject", "jsx", "jsxs", "forwardRef", "useRef", "useState", "useEffect", "useRef", "useState", "useState", "useEffect", "content", "digest", "inject", "inject", "jsx", "jsxs", "useState", "useEffect", "Message_default", "content", "digest", "inject", "inject", "Fragment", "jsx", "jsxs", "useRef", "useState", "useEffect", "Message_default", "content", "digest", "inject", "inject", "jsx", "jsxs", "useState", "useRef", "useCallback", "useEffect", "useImperativeHandle", "jsx", "forwardRef", "createRoot", "flushSync", "content", "digest", "inject", "inject", "spawnData", "_a"]
|
7
7
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@mml-io/3d-web-experience-client",
|
3
|
-
"version": "0.23.
|
3
|
+
"version": "0.23.2",
|
4
4
|
"publishConfig": {
|
5
5
|
"access": "public"
|
6
6
|
},
|
@@ -19,8 +19,8 @@
|
|
19
19
|
"lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix"
|
20
20
|
},
|
21
21
|
"dependencies": {
|
22
|
-
"@mml-io/3d-web-client-core": "^0.23.
|
23
|
-
"@mml-io/3d-web-user-networking": "^0.23.
|
22
|
+
"@mml-io/3d-web-client-core": "^0.23.2",
|
23
|
+
"@mml-io/3d-web-user-networking": "^0.23.2",
|
24
24
|
"@mml-io/mml-web": "0.20.0",
|
25
25
|
"react": "^19.0.0",
|
26
26
|
"react-dom": "^19.0.0",
|
@@ -33,5 +33,5 @@
|
|
33
33
|
"@types/react-dom": "^19.0.3",
|
34
34
|
"esbuild-css-modules-plugin": "3.1.4"
|
35
35
|
},
|
36
|
-
"gitHead": "
|
36
|
+
"gitHead": "4a73bae2a51eb35b593f2f5f0d7f5a6683155eb5"
|
37
37
|
}
|