@mml-io/3d-web-experience-client 0.0.0-experimental-c32c620-20250626 → 0.0.0-experimental-3a2278c-20250715

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.
Files changed (30) hide show
  1. package/build/Networked3dWebExperienceClient.d.ts +10 -13
  2. package/build/avatar-selection-ui/AvatarSelectionUI.d.ts +21 -0
  3. package/build/avatar-selection-ui/AvatarType.d.ts +21 -0
  4. package/build/avatar-selection-ui/components/AvatarPanel/AvatarSectionUIComponent.d.ts +14 -0
  5. package/build/avatar-selection-ui/index.d.ts +2 -0
  6. package/build/chat-ui/TextChatUI.d.ts +25 -0
  7. package/build/chat-ui/components/ChatPanel/TextChatUIComponent.d.ts +9 -0
  8. package/build/chat-ui/components/Input/InputBox.d.ts +9 -0
  9. package/build/chat-ui/components/Message/Message.d.ts +9 -0
  10. package/build/chat-ui/components/Messages/Messages.d.ts +12 -0
  11. package/build/chat-ui/helpers.d.ts +3 -0
  12. package/build/chat-ui/index.d.ts +1 -0
  13. package/build/index.css +875 -0
  14. package/build/index.css.map +7 -0
  15. package/build/index.js +1230 -201
  16. package/build/index.js.map +4 -4
  17. package/build/src/Networked3dWebExperience.module.css.d.ts +4 -0
  18. package/build/src/Networked3dWebExperience.module.d.css.ts +4 -0
  19. package/build/src/avatar-selection-ui/components/AvatarPanel/AvatarSelectionUIComponent.module.css.d.ts +26 -0
  20. package/build/src/avatar-selection-ui/components/AvatarPanel/AvatarSelectionUIComponent.module.d.css.ts +26 -0
  21. package/build/src/chat-ui/components/ChatPanel/TextChatUIComponent.module.css.d.ts +15 -0
  22. package/build/src/chat-ui/components/ChatPanel/TextChatUIComponent.module.d.css.ts +15 -0
  23. package/build/src/chat-ui/components/Input/InputBox.module.css.d.ts +7 -0
  24. package/build/src/chat-ui/components/Input/InputBox.module.d.css.ts +7 -0
  25. package/build/src/chat-ui/components/Message/Message.module.css.d.ts +5 -0
  26. package/build/src/chat-ui/components/Message/Message.module.d.css.ts +5 -0
  27. package/build/src/chat-ui/components/Messages/Messages.module.css.d.ts +5 -0
  28. package/build/src/chat-ui/components/Messages/Messages.module.d.css.ts +5 -0
  29. package/package.json +13 -11
  30. package/LICENSE +0 -19
package/build/index.js CHANGED
@@ -1,12 +1,11 @@
1
+ globalThis['__css-content-4f8287b7f1327101523ba48f76bd7efb__']=".AvatarSelectionUIComponent-module__menuButton_VjZ7cq__0220{z-index:102;user-select:none;width:70px;min-height:70px;position:absolute;top:0;right:0}.AvatarSelectionUIComponent-module__input_VjZ7cq__0220{color:#fff;backdrop-filter:blur(10px);background-color:#0006;border:1px solid #fff3;border-radius:8px;outline:none;flex:1;margin-right:6px;padding:6px 8px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;font-size:14px;font-weight:400;transition:all .2s ease-in-out}.AvatarSelectionUIComponent-module__input_VjZ7cq__0220:focus{background-color:#0009;border-color:#fff6;box-shadow:0 0 0 3px #ffffff26}.AvatarSelectionUIComponent-module__input_VjZ7cq__0220::placeholder{color:#ffffff80}.AvatarSelectionUIComponent-module__closeButton_VjZ7cq__0220{backdrop-filter:blur(10px);color:#fffc;cursor:pointer;user-select:none;background:#0009;border:1px solid #fff3;border-radius:50%;justify-content:center;align-items:center;width:44px;height:44px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;font-size:16px;font-weight:500;transition:all .2s ease-in-out;display:flex;position:absolute;top:8px;right:8px}.AvatarSelectionUIComponent-module__closeButton_VjZ7cq__0220:hover{color:#ffffffe6;background:#000c;transform:scale(1.05)}.AvatarSelectionUIComponent-module__closeButton_VjZ7cq__0220:active{transform:scale(.95)}.AvatarSelectionUIComponent-module__openTab_VjZ7cq__0220{backdrop-filter:blur(10px);cursor:pointer;user-select:none;background:#0009;border:1px solid #fff3;border-radius:50%;justify-content:center;align-items:center;width:44px;height:44px;transition:all .2s ease-in-out;display:flex;position:absolute;top:8px;right:8px}.AvatarSelectionUIComponent-module__openTab_VjZ7cq__0220:hover{background:#000c;transform:scale(1.05)}.AvatarSelectionUIComponent-module__openTab_VjZ7cq__0220:active{transform:scale(.95)}.AvatarSelectionUIComponent-module__openTab_VjZ7cq__0220 img{filter:invert(80%);width:24px;height:24px;transition:all .2s ease-in-out}.AvatarSelectionUIComponent-module__avatarSelectionContainer_VjZ7cq__0220{backdrop-filter:blur(20px);z-index:103;user-select:none;background:#000000bf;border:1px solid #fff3;border-radius:16px;width:400px;max-width:78vw;max-height:calc(100vh - 24px);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;position:absolute;top:8px;right:60px;overflow:hidden auto;box-shadow:0 8px 32px #0006,0 0 0 1px #ffffff1a}.AvatarSelectionUIComponent-module__avatarSelectionContainer_VjZ7cq__0220::-webkit-scrollbar{width:8px}.AvatarSelectionUIComponent-module__avatarSelectionContainer_VjZ7cq__0220::-webkit-scrollbar-track{background:none}.AvatarSelectionUIComponent-module__avatarSelectionContainer_VjZ7cq__0220::-webkit-scrollbar-thumb{background:#fff3;border:1px solid #ffffff1a;border-radius:4px}.AvatarSelectionUIComponent-module__avatarSelectionContainer_VjZ7cq__0220::-webkit-scrollbar-thumb:hover{background:#ffffff4d}.AvatarSelectionUIComponent-module__avatarSelectionSection_VjZ7cq__0220{border-bottom:1px solid #ffffff26;padding:10px}.AvatarSelectionUIComponent-module__avatarSelectionSection_VjZ7cq__0220:last-child{border-bottom:none}.AvatarSelectionUIComponent-module__avatarSelectionUi_VjZ7cq__0220{background:#0000004d;border:1px solid #ffffff26;border-radius:12px;grid-template-columns:repeat(auto-fill,minmax(85px,1fr));gap:8px;max-height:320px;padding:10px;display:grid;overflow:hidden auto}.AvatarSelectionUIComponent-module__avatarSelectionUi_VjZ7cq__0220::-webkit-scrollbar{width:6px}.AvatarSelectionUIComponent-module__avatarSelectionUi_VjZ7cq__0220::-webkit-scrollbar-track{background:none}.AvatarSelectionUIComponent-module__avatarSelectionUi_VjZ7cq__0220::-webkit-scrollbar-thumb{background:#ffffff26;border-radius:3px}.AvatarSelectionUIComponent-module__avatarSelectionUiHeader_VjZ7cq__0220{color:#ffffffe6;text-align:center;font-weight:600;position:relative}.AvatarSelectionUIComponent-module__avatarSelectionUiCloseButton_VjZ7cq__0220{position:absolute;top:20px;right:20px}.AvatarSelectionUIComponent-module__avatarSelectionUiAvatar_VjZ7cq__0220{color:#ffffffe6;text-align:center;cursor:pointer;border-radius:8px;padding:4px;transition:all .2s ease-in-out}.AvatarSelectionUIComponent-module__avatarSelectionUiAvatar_VjZ7cq__0220:hover{background:#0000004d;transform:translateY(-2px)}.AvatarSelectionUIComponent-module__avatarSelectionUiAvatarImgContainer_VjZ7cq__0220{border-radius:8px;position:relative;overflow:hidden}.AvatarSelectionUIComponent-module__avatarSelectionNoImage_VjZ7cq__0220{aspect-ratio:1;box-sizing:border-box;background:#0003;border:1px solid #ffffff26;border-radius:8px;justify-content:center;align-items:center;width:100%;display:flex}.AvatarSelectionUIComponent-module__avatarSelectionNoImage_VjZ7cq__0220 img{filter:invert(70%);opacity:.7;width:40%}.AvatarSelectionUIComponent-module__avatarSelectionUiAvatar_VjZ7cq__0220 p{text-overflow:ellipsis;white-space:nowrap;color:#fffc;margin:4px 0 0;font-size:12px;font-weight:500;position:relative;overflow:hidden}.AvatarSelectionUIComponent-module__tooltipText_VjZ7cq__0220{pointer-events:none;z-index:1000;color:#ffffffe6;backdrop-filter:blur(10px);opacity:0;visibility:hidden;white-space:nowrap;background:#000c;border-radius:8px;margin-bottom:4px;padding:4px 6px;font-size:12px;font-weight:500;transition:opacity .2s ease-in-out;position:absolute;bottom:100%;left:50%;transform:translate(-50%)}.AvatarSelectionUIComponent-module__avatarSelectionUiAvatar_VjZ7cq__0220 p:hover+.AvatarSelectionUIComponent-module__tooltipText_VjZ7cq__0220{opacity:1;visibility:visible;transition-delay:.5s}.AvatarSelectionUIComponent-module__avatarSelectionUiAvatarImgContainer_VjZ7cq__0220 .AvatarSelectionUIComponent-module__avatarSelectionUiAvatarImage_VjZ7cq__0220{aspect-ratio:1;border-radius:8px;width:100%;transition:all .2s ease-in-out}.AvatarSelectionUIComponent-module__selectedPill_VjZ7cq__0220{color:#fff;backdrop-filter:blur(10px);background:linear-gradient(135deg,#22c55e,#16a34a);border:1px solid #fff3;border-radius:6px;padding:2px 4px;font-size:11px;font-weight:600;box-shadow:0 2px 4px #0003}.AvatarSelectionUIComponent-module__avatarSelectionUiAvatarImgContainer_VjZ7cq__0220 .AvatarSelectionUIComponent-module__selectedPill_VjZ7cq__0220{z-index:2;position:absolute;top:4px;right:4px}.AvatarSelectionUIComponent-module__avatarSelectionUiAvatar_VjZ7cq__0220 img:hover{opacity:.8;transform:scale(1.05)}.AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0220{color:#ffffffe6;border-bottom:1px solid #ffffff26;padding:10px;position:relative}.AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0220:last-child{border-bottom:none}.AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0220 .AvatarSelectionUIComponent-module__radioGroup_VjZ7cq__0220{flex-wrap:wrap;align-items:center;gap:4px;margin-bottom:8px;display:flex}.AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0220 .AvatarSelectionUIComponent-module__radioItem_VjZ7cq__0220{white-space:nowrap;align-items:center;gap:3px;margin-right:6px;display:flex}.AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0220 label{color:#fffc;cursor:pointer;margin:0;font-size:14px;font-weight:500;transition:color .2s ease-in-out}.AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0220 label:hover{color:#fff}.AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0220 input[type=radio]{appearance:none;cursor:pointer;background:none;border:2px solid #ffffff4d;border-radius:50%;outline:none;width:18px;height:18px;transition:all .2s ease-in-out;position:relative}.AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0220 input[type=radio]:hover{border-color:#ffffff80}.AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0220 input[type=radio]:focus{box-shadow:0 0 0 3px #ffffff1a}.AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0220 input[type=radio]:checked{background:#ffffff1a;border-color:#fffc}.AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0220 input[type=radio]:checked:after{content:\"\";background:#ffffffe6;border-radius:50%;width:8px;height:8px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0220 input[type=radio][disabled]{opacity:.4;cursor:not-allowed}.AvatarSelectionUIComponent-module__customAvatarInputSection_VjZ7cq__0220{align-items:stretch;display:flex}.AvatarSelectionUIComponent-module__setButton_VjZ7cq__0220{color:#ffffffe6;backdrop-filter:blur(10px);cursor:pointer;background:linear-gradient(135deg,#0009,#0006);border:1px solid #fff3;border-radius:8px;justify-content:center;align-items:center;height:44px;padding-left:16px;padding-right:16px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;font-size:14px;font-weight:500;transition:all .2s ease-in-out;display:flex}.AvatarSelectionUIComponent-module__setButton_VjZ7cq__0220:hover:not(:disabled){background:linear-gradient(135deg,#000c,#0009);border-color:#ffffff4d;transform:translateY(-1px);box-shadow:0 4px 8px #0000004d}.AvatarSelectionUIComponent-module__setButton_VjZ7cq__0220:active:not(:disabled){transform:translateY(0);box-shadow:0 2px 4px #0003}.AvatarSelectionUIComponent-module__setButton_VjZ7cq__0220:disabled{opacity:.5;cursor:not-allowed;transform:none}.AvatarSelectionUIComponent-module__sectionHeading_VjZ7cq__0220{color:#ffffffe6;letter-spacing:-.01em;margin-bottom:8px;font-size:18px;font-weight:600}.AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0220 .AvatarSelectionUIComponent-module__selectedPill_VjZ7cq__0220{margin-left:8px;position:relative;top:-2px}.AvatarSelectionUIComponent-module__displayNameSection_VjZ7cq__0220{color:#ffffffe6;border-bottom:1px solid #ffffff26;padding:10px;position:relative}.AvatarSelectionUIComponent-module__displayNameInputSection_VjZ7cq__0220{align-items:stretch;display:flex}.InputBox-module__inputWrapper_adOgOW__0220{pointer-events:all;align-items:stretch;gap:6px;display:flex}.InputBox-module__chatInput_adOgOW__0220{color:#fff;backdrop-filter:blur(10px);box-sizing:border-box;background:#0006;border:1px solid #fff3;border-radius:8px;outline:none;flex:1;height:36px;padding:0 8px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;font-size:14px;font-weight:400;transition:all .2s ease-in-out}.InputBox-module__chatInput_adOgOW__0220:focus{background:#0009;border-color:#fff6;box-shadow:0 0 0 3px #ffffff26}.InputBox-module__chatInput_adOgOW__0220::placeholder{color:#ffffff80}.InputBox-module__sendButton_adOgOW__0220{color:#ffffffe6;backdrop-filter:blur(10px);cursor:pointer;background:linear-gradient(135deg,#0009,#0006);border:1px solid #fff3;border-radius:8px;outline:none;justify-content:center;align-items:center;width:36px;height:36px;transition:all .2s ease-in-out;display:flex}.InputBox-module__sendButton_adOgOW__0220:hover{background:linear-gradient(135deg,#000c,#0009);border-color:#ffffff4d;transform:translateY(-1px);box-shadow:0 4px 8px #0000004d}.InputBox-module__sendButton_adOgOW__0220:active{transform:translateY(0);box-shadow:0 2px 4px #0003}.InputBox-module__sendButton_adOgOW__0220 .InputBox-module__svgIcon_adOgOW__0220 img{filter:invert(80%);width:18px;height:18px;transition:all .2s ease-in-out}.InputBox-module__sendButton_adOgOW__0220:hover .InputBox-module__svgIcon_adOgOW__0220 img{filter:invert(90%)}.Message-module__messageContainer_ikOQiq__0220{backdrop-filter:blur(8px);word-break:break-word;color:#ffffffe6;direction:ltr;background:#0000004d;border:1px solid #fff3;border-radius:8px;width:fit-content;margin:6px auto 6px 2px;padding:4px 8px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;font-size:14px;transition:all .2s ease-in-out;overflow-x:hidden}.Message-module__messageContainer_ikOQiq__0220:hover{background:#0006;border-color:#ffffff4d}.Message-module__userName_ikOQiq__0220{color:#ffffffe6;margin-right:4px;font-weight:600}.Messages-module__messagesContainer_LXaUUW__0220{z-index:1000;max-height:inherit;scrollbar-width:thin;scrollbar-color:#fff3 transparent;pointer-events:fill;direction:rtl;position:relative;bottom:0;left:-1px;overflow-y:auto}.Messages-module__messagesContainer_LXaUUW__0220::-webkit-scrollbar{width:6px}.Messages-module__messagesContainer_LXaUUW__0220::-webkit-scrollbar-track{background:none}.Messages-module__messagesContainer_LXaUUW__0220::-webkit-scrollbar-thumb{background:#fff3;border:1px solid #ffffff1a;border-radius:3px}.Messages-module__messagesContainer_LXaUUW__0220::-webkit-scrollbar-thumb:hover{background:#ffffff4d}.Messages-module__newMessagesButton_LXaUUW__0220{-webkit-backdrop-filter:blur(10px);color:#fff;cursor:pointer;z-index:1001;direction:ltr;background:#000000bf;border:1px solid #fff3;border-radius:20px;padding:8px 16px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:14px;font-weight:500;transition:all .2s;position:absolute;bottom:50px;left:50%;transform:translate(-50%);box-shadow:0 4px 12px #0000004d}.Messages-module__newMessagesButton_LXaUUW__0220:hover{background:#000000d9;border-color:#ffffff4d;transform:translate(-50%)translateY(-2px);box-shadow:0 6px 16px #0006}.Messages-module__newMessagesButton_LXaUUW__0220:active{transform:translate(-50%)translateY(0);box-shadow:0 2px 8px #0000004d}.TextChatUIComponent-module__uiHover_gFDdcW__0220{z-index:102;pointer-events:all;width:58px;min-height:58px;position:absolute;bottom:0;left:0}.TextChatUIComponent-module__textChatUi_gFDdcW__0220{flex-direction:row;align-items:flex-end;width:100%;max-width:500px;height:0;display:flex;position:absolute;bottom:0;left:0}.TextChatUIComponent-module__textChat_gFDdcW__0220{z-index:-1;color:#fff;user-select:none;opacity:0;flex-direction:column;justify-content:space-between;width:100%;max-height:500px;margin-bottom:8px;margin-left:60px;padding:5px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;transition:opacity .25s ease-in-out,transform .2s ease-in-out;display:flex;transform:translate(-100%)}.TextChatUIComponent-module__fadeIn_gFDdcW__0220{opacity:1;transform:translate(0)}.TextChatUIComponent-module__fadeOut_gFDdcW__0220{opacity:.6;transform:translate(calc(-100% - 72px))}.TextChatUIComponent-module__controls_gFDdcW__0220{position:absolute;top:2px;right:0}.TextChatUIComponent-module__openTab_gFDdcW__0220{backdrop-filter:blur(10px);cursor:pointer;z-index:102;user-select:none;background:#0009;border:1px solid #fff3;border-radius:50%;justify-content:center;align-items:center;width:44px;height:44px;transition:all .2s ease-in-out;display:flex;position:absolute;bottom:8px;left:8px}.TextChatUIComponent-module__openTab_gFDdcW__0220:hover{background:#000c;border-color:#ffffff4d;transform:scale(1.05)}.TextChatUIComponent-module__openTab_gFDdcW__0220:active{transform:scale(.95)}.TextChatUIComponent-module__openTab_gFDdcW__0220 img{filter:invert(80%);width:24px;height:24px;transition:all .2s ease-in-out}.TextChatUIComponent-module__stickyButton_gFDdcW__0220{z-index:103;backdrop-filter:blur(10px);cursor:pointer;user-select:none;opacity:1;background:#0009;border:1px solid #fff3;border-radius:50%;justify-content:center;align-items:center;width:24px;height:24px;transition:all .2s ease-in-out;display:flex;position:absolute;bottom:38px;left:38px}.TextChatUIComponent-module__stickyButton_gFDdcW__0220:hover{background:#000c;border-color:#ffffff4d;transform:scale(1.05)}.TextChatUIComponent-module__stickyButtonFadeOut_gFDdcW__0220{z-index:103;backdrop-filter:blur(10px);cursor:pointer;user-select:none;opacity:0;pointer-events:none;background:#0009;border:1px solid #fff3;border-radius:50%;justify-content:center;align-items:center;width:24px;height:24px;transition:all .2s ease-in-out;display:flex;position:absolute;bottom:42px;left:42px}.TextChatUIComponent-module__stickyButtonEnabled_gFDdcW__0220{z-index:103;backdrop-filter:blur(10px);cursor:pointer;user-select:none;background:#000c;border:1px solid #22c55e99;border-radius:50%;justify-content:center;align-items:center;width:24px;height:24px;transition:all .2s ease-in-out;display:flex;position:absolute;bottom:42px;left:42px;box-shadow:0 0 8px #22c55e4d}.TextChatUIComponent-module__stickyButtonEnabled_gFDdcW__0220:hover{border-color:#22c55ecc;transform:scale(1.05);box-shadow:0 0 12px #22c55e66}.TextChatUIComponent-module__stickyButton_gFDdcW__0220 img,.TextChatUIComponent-module__stickyButtonFadeOut_gFDdcW__0220 img,.TextChatUIComponent-module__stickyButtonEnabled_gFDdcW__0220 img{filter:invert(70%);width:12px;height:12px;transition:all .2s ease-in-out}.TextChatUIComponent-module__stickyButton_gFDdcW__0220:hover img,.TextChatUIComponent-module__stickyButtonEnabled_gFDdcW__0220:hover img{filter:invert(90%)}.TextChatUIComponent-module__controls_gFDdcW__0220 .TextChatUIComponent-module__closeButton_gFDdcW__0220{color:#fffc;backdrop-filter:blur(10px);cursor:pointer;background:#0009;border:1px solid #fff3;border-radius:50%;justify-content:center;align-items:center;width:28px;height:28px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;font-size:14px;font-weight:500;transition:all .2s ease-in-out;display:flex;position:absolute;top:3px;right:3px}.TextChatUIComponent-module__closeButton_gFDdcW__0220:hover{color:#ffffffe6;background:#000c;border-color:#ffffff4d;transform:scale(1.05)}.TextChatUIComponent-module__closeButton_gFDdcW__0220:active{transform:scale(.95)}.TextChatUIComponent-module__messagesWrapper_gFDdcW__0220{direction:rtl;width:fit-content;max-height:450px;margin-bottom:8px;position:relative}.Networked3dWebExperience-module__respawnButton_7g9l0W__0220{z-index:102;color:#ffffffe6;backdrop-filter:blur(10px);cursor:pointer;user-select:none;background:linear-gradient(135deg,#0009,#0006);border:1px solid #fff3;border-radius:8px;justify-content:center;align-items:center;padding:12px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;font-size:14px;font-weight:500;transition:all .2s ease-in-out;display:flex;position:absolute;top:8px;left:8px}.Networked3dWebExperience-module__respawnButton_7g9l0W__0220:hover{background:linear-gradient(135deg,#000c,#0009);border-color:#ffffff4d;transform:translateY(-1px)}.Networked3dWebExperience-module__respawnButton_7g9l0W__0220:active{transform:translateY(0)}\n";globalThis['__css-digest-4f8287b7f1327101523ba48f76bd7efb__']="4f8287b7f1327101523ba48f76bd7efb";
1
2
  // src/Networked3dWebExperienceClient.ts
2
- import { AvatarSelectionUI } from "@mml-io/3d-web-avatar-selection-ui";
3
3
  import {
4
4
  CameraManager,
5
5
  CharacterManager,
6
6
  CharacterModelLoader,
7
7
  CollisionsManager,
8
8
  Composer,
9
- decodeCharacterAndCamera,
10
9
  ErrorScreen,
11
10
  GroundPlane,
12
11
  Key,
@@ -15,28 +14,1042 @@ import {
15
14
  MMLCompositionScene,
16
15
  TimeManager,
17
16
  TweakPane,
18
- VirtualJoystick
19
- } from "@mml-io/3d-web-client-core";
17
+ Vect3,
18
+ VirtualJoystick,
19
+ Character,
20
+ Quat,
21
+ getSpawnData
22
+ } from "/Users/marcuslongmuir/mml/3d-web-experience/packages/3d-web-client-core/build/index.js";
20
23
  import {
21
- ChatNetworkingClient,
22
- TextChatUI
23
- } from "@mml-io/3d-web-text-chat";
24
- import {
25
- USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE,
26
- USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE,
27
- USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE,
28
- USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE,
24
+ FROM_SERVER_CHAT_MESSAGE_TYPE,
25
+ FROM_CLIENT_CHAT_MESSAGE_TYPE,
29
26
  UserNetworkingClient,
30
- WebsocketStatus
31
- } from "@mml-io/3d-web-user-networking";
32
- import { VoiceChatManager } from "@mml-io/3d-web-voice-chat";
27
+ WebsocketStatus,
28
+ parseServerChatMessage,
29
+ DeltaNetV01ServerErrors,
30
+ SERVER_BROADCAST_MESSAGE_TYPE,
31
+ parseServerBroadcastMessage
32
+ } from "/Users/marcuslongmuir/mml/3d-web-experience/packages/3d-web-user-networking/build/index.js";
33
33
  import {
34
34
  LoadingProgressManager,
35
35
  registerCustomElementsToWindow,
36
36
  setGlobalDocumentTimeManager,
37
37
  setGlobalMMLScene
38
38
  } from "@mml-io/mml-web";
39
- import { AudioListener, Euler, Scene, Vector3 } from "three";
39
+ import { Scene, AudioListener, Vector3 } from "three";
40
+
41
+ // src/avatar-selection-ui/AvatarSelectionUI.tsx
42
+ import { createRef, forwardRef } from "react";
43
+ import { flushSync } from "react-dom";
44
+ import { createRoot } from "react-dom/client";
45
+
46
+ // src/avatar-selection-ui/components/AvatarPanel/AvatarSectionUIComponent.tsx
47
+ import {
48
+ useRef,
49
+ useState
50
+ } from "react";
51
+
52
+ // src/avatar-selection-ui/icons/Avatar.svg
53
+ var Avatar_default = '<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';
54
+
55
+ // esbuild-css-modules-plugin-ns-js::src/avatar-selection-ui/components/AvatarPanel/AvatarSelectionUIComponent.module.css:injector.js
56
+ var content = globalThis['__css-content-4f8287b7f1327101523ba48f76bd7efb__'];
57
+ var digest = globalThis['__css-digest-4f8287b7f1327101523ba48f76bd7efb__'];
58
+ var inject = () => {
59
+ setTimeout(() => {
60
+ if (!globalThis.document) {
61
+ return;
62
+ }
63
+ let root = globalThis.document.querySelector("head");
64
+ if (root && root.shadowRoot) {
65
+ root = root.shadowRoot;
66
+ }
67
+ if (!root) {
68
+ root = globalThis.document.head;
69
+ }
70
+ let container = root.querySelector("#_" + digest);
71
+ if (!container) {
72
+ container = globalThis.document.createElement("style");
73
+ container.id = "_" + digest;
74
+ const text = globalThis.document.createTextNode(content);
75
+ container.appendChild(text);
76
+ root.appendChild(container);
77
+ }
78
+ }, 0);
79
+ };
80
+
81
+ // src/avatar-selection-ui/components/AvatarPanel/AvatarSelectionUIComponent.module.css
82
+ var AvatarSelectionUIComponent_default = new Proxy({
83
+ "avatarSelectionContainer": "AvatarSelectionUIComponent-module__avatarSelectionContainer_VjZ7cq__0220",
84
+ "avatarSelectionNoImage": "AvatarSelectionUIComponent-module__avatarSelectionNoImage_VjZ7cq__0220",
85
+ "avatarSelectionSection": "AvatarSelectionUIComponent-module__avatarSelectionSection_VjZ7cq__0220",
86
+ "avatarSelectionUi": "AvatarSelectionUIComponent-module__avatarSelectionUi_VjZ7cq__0220",
87
+ "avatarSelectionUiAvatar": "AvatarSelectionUIComponent-module__avatarSelectionUiAvatar_VjZ7cq__0220",
88
+ "avatarSelectionUiAvatarImage": "AvatarSelectionUIComponent-module__avatarSelectionUiAvatarImage_VjZ7cq__0220",
89
+ "avatarSelectionUiAvatarImgContainer": "AvatarSelectionUIComponent-module__avatarSelectionUiAvatarImgContainer_VjZ7cq__0220",
90
+ "avatarSelectionUiCloseButton": "AvatarSelectionUIComponent-module__avatarSelectionUiCloseButton_VjZ7cq__0220",
91
+ "avatarSelectionUiHeader": "AvatarSelectionUIComponent-module__avatarSelectionUiHeader_VjZ7cq__0220",
92
+ "closeButton": "AvatarSelectionUIComponent-module__closeButton_VjZ7cq__0220",
93
+ "customAvatarInputSection": "AvatarSelectionUIComponent-module__customAvatarInputSection_VjZ7cq__0220",
94
+ "customAvatarSection": "AvatarSelectionUIComponent-module__customAvatarSection_VjZ7cq__0220",
95
+ "displayNameInputSection": "AvatarSelectionUIComponent-module__displayNameInputSection_VjZ7cq__0220",
96
+ "displayNameSection": "AvatarSelectionUIComponent-module__displayNameSection_VjZ7cq__0220",
97
+ "input": "AvatarSelectionUIComponent-module__input_VjZ7cq__0220",
98
+ "menuButton": "AvatarSelectionUIComponent-module__menuButton_VjZ7cq__0220",
99
+ "openTab": "AvatarSelectionUIComponent-module__openTab_VjZ7cq__0220",
100
+ "radioGroup": "AvatarSelectionUIComponent-module__radioGroup_VjZ7cq__0220",
101
+ "radioItem": "AvatarSelectionUIComponent-module__radioItem_VjZ7cq__0220",
102
+ "sectionHeading": "AvatarSelectionUIComponent-module__sectionHeading_VjZ7cq__0220",
103
+ "selectedPill": "AvatarSelectionUIComponent-module__selectedPill_VjZ7cq__0220",
104
+ "setButton": "AvatarSelectionUIComponent-module__setButton_VjZ7cq__0220",
105
+ "tooltipText": "AvatarSelectionUIComponent-module__tooltipText_VjZ7cq__0220"
106
+ }, {
107
+ get: function(source, key) {
108
+ inject();
109
+ return source[key];
110
+ }
111
+ });
112
+
113
+ // src/avatar-selection-ui/components/AvatarPanel/AvatarSectionUIComponent.tsx
114
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
115
+ function SelectedPill() {
116
+ return /* @__PURE__ */ jsx("span", { className: AvatarSelectionUIComponent_default.selectedPill, children: "Selected" });
117
+ }
118
+ var AvatarSelectionUIComponent = (props, ref) => {
119
+ const visibleByDefault = props.visibleByDefault ?? false;
120
+ const [isVisible, setIsVisible] = useState(visibleByDefault);
121
+ const [selectedAvatar, setSelectedAvatar] = useState(
122
+ props.characterDescription
123
+ );
124
+ const [customAvatarType, setCustomAvatarType] = useState(
125
+ 1 /* mmlUrl */
126
+ );
127
+ const [customAvatarValue, setCustomAvatarValue] = useState("");
128
+ const inputRef = useRef(null);
129
+ const textareaRef = useRef(null);
130
+ const [displayNameValue, setDisplayNameValue] = useState(props.displayName);
131
+ const displayNameRef = useRef(null);
132
+ const handleRootClick = (e) => {
133
+ e.stopPropagation();
134
+ };
135
+ const selectAvatar = (avatar) => {
136
+ setSelectedAvatar(avatar);
137
+ props.onUpdateUserAvatar(avatar);
138
+ };
139
+ const handleInputChange = (e) => {
140
+ setCustomAvatarValue(e.target.value);
141
+ };
142
+ const handleDisplayNameChange = (e) => {
143
+ setDisplayNameValue(e.target.value);
144
+ };
145
+ const setDisplayName = () => {
146
+ if (!displayNameValue) {
147
+ return;
148
+ }
149
+ props.onUpdateDisplayName(displayNameValue);
150
+ };
151
+ const addCustomAvatar = () => {
152
+ if (!customAvatarValue) {
153
+ return;
154
+ }
155
+ let newSelectedAvatar;
156
+ switch (customAvatarType) {
157
+ case 2 /* mml */:
158
+ newSelectedAvatar = {
159
+ mmlCharacterString: customAvatarValue
160
+ };
161
+ break;
162
+ case 1 /* mmlUrl */:
163
+ newSelectedAvatar = {
164
+ mmlCharacterUrl: customAvatarValue
165
+ };
166
+ break;
167
+ case 0 /* meshFileUrl */:
168
+ newSelectedAvatar = {
169
+ meshFileUrl: customAvatarValue
170
+ };
171
+ break;
172
+ }
173
+ setSelectedAvatar(newSelectedAvatar);
174
+ props.onUpdateUserAvatar(newSelectedAvatar);
175
+ };
176
+ const handleKeyPress = (e) => {
177
+ e.stopPropagation();
178
+ };
179
+ const handleAvatarInputKeyPress = (e) => {
180
+ e.stopPropagation();
181
+ if (e.key === "Enter") {
182
+ addCustomAvatar();
183
+ }
184
+ };
185
+ const handleDisplayNameKeyPress = (e) => {
186
+ e.stopPropagation();
187
+ if (e.key === "Enter") {
188
+ setDisplayName();
189
+ }
190
+ };
191
+ const handleTypeSwitch = (type) => {
192
+ setCustomAvatarType(type);
193
+ setCustomAvatarValue("");
194
+ };
195
+ const getPlaceholderByType = (type) => {
196
+ switch (type) {
197
+ case 0 /* meshFileUrl */:
198
+ return "https://.../avatar.glb";
199
+ case 1 /* mmlUrl */:
200
+ return "https://.../avatar.html";
201
+ case 2 /* mml */:
202
+ return '<m-character src="https://link-to-avatar">\n</m-character';
203
+ }
204
+ };
205
+ if (!props.availableAvatars.length && !props.allowCustomAvatars && !props.allowCustomDisplayName) {
206
+ return null;
207
+ }
208
+ let recognizedAvatar = false;
209
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
210
+ /* @__PURE__ */ jsxs("div", { className: AvatarSelectionUIComponent_default.menuButton, onClick: handleRootClick, children: [
211
+ !isVisible && /* @__PURE__ */ jsx("div", { className: AvatarSelectionUIComponent_default.openTab, onClick: () => setIsVisible(true), children: /* @__PURE__ */ jsx("img", { src: `data:image/svg+xml;utf8,${encodeURIComponent(Avatar_default)}` }) }),
212
+ isVisible && /* @__PURE__ */ jsx("button", { className: AvatarSelectionUIComponent_default.closeButton, onClick: (e) => setIsVisible(false), children: "X" })
213
+ ] }),
214
+ isVisible && /* @__PURE__ */ jsxs("div", { className: `${AvatarSelectionUIComponent_default.avatarSelectionContainer}`, children: [
215
+ props.allowCustomDisplayName && /* @__PURE__ */ jsxs("div", { className: AvatarSelectionUIComponent_default.displayNameSection, children: [
216
+ /* @__PURE__ */ jsx("div", { className: AvatarSelectionUIComponent_default.sectionHeading, children: "Display Name" }),
217
+ /* @__PURE__ */ jsxs("div", { className: AvatarSelectionUIComponent_default.displayNameInputSection, children: [
218
+ /* @__PURE__ */ jsx(
219
+ "input",
220
+ {
221
+ ref: displayNameRef,
222
+ className: AvatarSelectionUIComponent_default.input,
223
+ value: displayNameValue,
224
+ onKeyDown: handleDisplayNameKeyPress,
225
+ onChange: handleDisplayNameChange,
226
+ placeholder: "Enter your display name"
227
+ }
228
+ ),
229
+ /* @__PURE__ */ jsx(
230
+ "button",
231
+ {
232
+ className: AvatarSelectionUIComponent_default.setButton,
233
+ disabled: !displayNameValue,
234
+ type: "button",
235
+ onClick: setDisplayName,
236
+ children: "Set"
237
+ }
238
+ )
239
+ ] })
240
+ ] }),
241
+ !!props.availableAvatars.length && /* @__PURE__ */ jsxs("div", { className: AvatarSelectionUIComponent_default.avatarSelectionSection, children: [
242
+ /* @__PURE__ */ jsx("div", { className: AvatarSelectionUIComponent_default.sectionHeading, children: "Choose your Avatar" }),
243
+ /* @__PURE__ */ jsx("div", { className: AvatarSelectionUIComponent_default.avatarSelectionUi, children: props.availableAvatars.map((avatar, index) => {
244
+ const isSelected = (selectedAvatar == null ? void 0 : selectedAvatar.meshFileUrl) && (selectedAvatar == null ? void 0 : selectedAvatar.meshFileUrl) === avatar.meshFileUrl || (selectedAvatar == null ? void 0 : selectedAvatar.mmlCharacterUrl) && (selectedAvatar == null ? void 0 : selectedAvatar.mmlCharacterUrl) === avatar.mmlCharacterUrl || (selectedAvatar == null ? void 0 : selectedAvatar.mmlCharacterString) && (selectedAvatar == null ? void 0 : selectedAvatar.mmlCharacterString) === avatar.mmlCharacterString;
245
+ if (isSelected) {
246
+ recognizedAvatar = true;
247
+ }
248
+ return /* @__PURE__ */ jsx(
249
+ "div",
250
+ {
251
+ className: AvatarSelectionUIComponent_default.avatarSelectionUiAvatar,
252
+ onClick: () => selectAvatar(avatar),
253
+ children: /* @__PURE__ */ jsxs("div", { className: AvatarSelectionUIComponent_default.avatarSelectionUiAvatarImgContainer, children: [
254
+ isSelected && /* @__PURE__ */ jsx(SelectedPill, {}),
255
+ avatar.thumbnailUrl ? /* @__PURE__ */ jsx(
256
+ "img",
257
+ {
258
+ className: AvatarSelectionUIComponent_default.avatarSelectionUiAvatarImage,
259
+ src: avatar.thumbnailUrl,
260
+ alt: avatar.name
261
+ }
262
+ ) : /* @__PURE__ */ jsx("div", { className: AvatarSelectionUIComponent_default.avatarSelectionNoImage, children: /* @__PURE__ */ jsx(
263
+ "img",
264
+ {
265
+ alt: avatar.name,
266
+ src: `data:image/svg+xml;utf8,${encodeURIComponent(Avatar_default)}`
267
+ }
268
+ ) }),
269
+ /* @__PURE__ */ jsx("p", { children: avatar.name }),
270
+ /* @__PURE__ */ jsx("span", { className: AvatarSelectionUIComponent_default.tooltipText, children: avatar.name })
271
+ ] })
272
+ },
273
+ index
274
+ );
275
+ }) })
276
+ ] }),
277
+ props.allowCustomAvatars && /* @__PURE__ */ jsxs("div", { className: AvatarSelectionUIComponent_default.customAvatarSection, children: [
278
+ /* @__PURE__ */ jsx("div", { className: AvatarSelectionUIComponent_default.sectionHeading, children: "Custom Avatar" }),
279
+ /* @__PURE__ */ jsxs("div", { className: AvatarSelectionUIComponent_default.radioGroup, children: [
280
+ /* @__PURE__ */ jsxs("div", { className: AvatarSelectionUIComponent_default.radioItem, children: [
281
+ /* @__PURE__ */ jsx(
282
+ "input",
283
+ {
284
+ type: "radio",
285
+ id: "html",
286
+ name: "customAvatarType",
287
+ onChange: () => handleTypeSwitch(1 /* mmlUrl */),
288
+ checked: customAvatarType === 1 /* mmlUrl */
289
+ }
290
+ ),
291
+ /* @__PURE__ */ jsx("label", { htmlFor: "html", children: "MML URL" })
292
+ ] }),
293
+ /* @__PURE__ */ jsxs("div", { className: AvatarSelectionUIComponent_default.radioItem, children: [
294
+ /* @__PURE__ */ jsx(
295
+ "input",
296
+ {
297
+ type: "radio",
298
+ id: "mml",
299
+ name: "customAvatarType",
300
+ onChange: () => handleTypeSwitch(2 /* mml */),
301
+ checked: customAvatarType === 2 /* mml */
302
+ }
303
+ ),
304
+ /* @__PURE__ */ jsx("label", { htmlFor: "mml", children: "MML" })
305
+ ] }),
306
+ /* @__PURE__ */ jsxs("div", { className: AvatarSelectionUIComponent_default.radioItem, children: [
307
+ /* @__PURE__ */ jsx(
308
+ "input",
309
+ {
310
+ type: "radio",
311
+ id: "glb",
312
+ name: "customAvatarType",
313
+ onChange: () => handleTypeSwitch(0 /* meshFileUrl */),
314
+ checked: customAvatarType === 0 /* meshFileUrl */
315
+ }
316
+ ),
317
+ /* @__PURE__ */ jsx("label", { htmlFor: "glb", children: "Mesh URL" })
318
+ ] }),
319
+ !recognizedAvatar && /* @__PURE__ */ jsx(SelectedPill, {})
320
+ ] }),
321
+ /* @__PURE__ */ jsxs("div", { className: AvatarSelectionUIComponent_default.customAvatarInputSection, children: [
322
+ customAvatarType === 2 /* mml */ ? /* @__PURE__ */ jsx(
323
+ "textarea",
324
+ {
325
+ ref: textareaRef,
326
+ className: AvatarSelectionUIComponent_default.input,
327
+ value: customAvatarValue,
328
+ onChange: handleInputChange,
329
+ onKeyDown: handleKeyPress,
330
+ placeholder: getPlaceholderByType(customAvatarType),
331
+ rows: 4
332
+ }
333
+ ) : /* @__PURE__ */ jsx(
334
+ "input",
335
+ {
336
+ ref: inputRef,
337
+ className: AvatarSelectionUIComponent_default.input,
338
+ value: customAvatarValue,
339
+ onKeyDown: handleAvatarInputKeyPress,
340
+ onChange: handleInputChange,
341
+ placeholder: getPlaceholderByType(customAvatarType)
342
+ }
343
+ ),
344
+ /* @__PURE__ */ jsx(
345
+ "button",
346
+ {
347
+ className: AvatarSelectionUIComponent_default.setButton,
348
+ disabled: !customAvatarValue,
349
+ type: "button",
350
+ onClick: addCustomAvatar,
351
+ children: "Set"
352
+ }
353
+ )
354
+ ] })
355
+ ] })
356
+ ] })
357
+ ] });
358
+ };
359
+
360
+ // src/avatar-selection-ui/AvatarSelectionUI.tsx
361
+ import { jsx as jsx2 } from "react/jsx-runtime";
362
+ var ForwardedAvatarSelectionUIComponent = forwardRef(AvatarSelectionUIComponent);
363
+ var AvatarSelectionUI = class {
364
+ constructor(config) {
365
+ this.config = config;
366
+ this.appRef = createRef();
367
+ this.wrapper = document.createElement("div");
368
+ this.onUpdateUserAvatar = (avatar) => {
369
+ this.config.characterDescription = avatar;
370
+ this.config.sendIdentityUpdateToServer(this.config.displayName, avatar);
371
+ };
372
+ this.onUpdateDisplayName = (displayName) => {
373
+ this.config.displayName = displayName;
374
+ this.config.sendIdentityUpdateToServer(displayName, this.config.characterDescription);
375
+ };
376
+ this.config.holderElement.appendChild(this.wrapper);
377
+ this.root = createRoot(this.wrapper);
378
+ }
379
+ updateAvatarConfig(avatarConfig) {
380
+ this.config = {
381
+ ...this.config,
382
+ ...avatarConfig
383
+ };
384
+ this.init();
385
+ }
386
+ updateAllowCustomDisplayName(allowCustomDisplayName) {
387
+ this.config = {
388
+ ...this.config,
389
+ allowCustomDisplayName
390
+ };
391
+ this.init();
392
+ }
393
+ init() {
394
+ flushSync(
395
+ () => this.root.render(
396
+ /* @__PURE__ */ jsx2(
397
+ ForwardedAvatarSelectionUIComponent,
398
+ {
399
+ ref: this.appRef,
400
+ onUpdateUserAvatar: this.onUpdateUserAvatar,
401
+ onUpdateDisplayName: this.onUpdateDisplayName,
402
+ visibleByDefault: this.config.visibleByDefault,
403
+ displayName: this.config.displayName,
404
+ characterDescription: this.config.characterDescription,
405
+ availableAvatars: this.config.availableAvatars,
406
+ allowCustomAvatars: this.config.allowCustomAvatars || false,
407
+ allowCustomDisplayName: this.config.allowCustomDisplayName || false
408
+ }
409
+ )
410
+ )
411
+ );
412
+ }
413
+ };
414
+
415
+ // src/chat-ui/TextChatUI.tsx
416
+ import { createRef as createRef2, forwardRef as forwardRef3 } from "react";
417
+ import { flushSync as flushSync2 } from "react-dom";
418
+ import { createRoot as createRoot2 } from "react-dom/client";
419
+
420
+ // src/chat-ui/components/ChatPanel/TextChatUIComponent.tsx
421
+ import {
422
+ useCallback as useCallback2,
423
+ useEffect as useEffect4,
424
+ useImperativeHandle as useImperativeHandle2,
425
+ useRef as useRef5,
426
+ useState as useState5
427
+ } from "react";
428
+
429
+ // src/chat-ui/helpers.tsx
430
+ import { useEffect, useLayoutEffect, useRef as useRef2 } from "react";
431
+ function useClickOutside(cb) {
432
+ const ref = useRef2(null);
433
+ const refCb = useRef2(cb);
434
+ useLayoutEffect(() => {
435
+ refCb.current = cb;
436
+ });
437
+ useEffect(() => {
438
+ const handler = (e) => {
439
+ const element = ref.current;
440
+ if (element && !element.contains(e.target)) {
441
+ refCb.current(e);
442
+ }
443
+ };
444
+ document.addEventListener("mousedown", handler);
445
+ document.addEventListener("touchstart", handler);
446
+ return () => {
447
+ document.removeEventListener("mousedown", handler);
448
+ document.removeEventListener("touchstart", handler);
449
+ };
450
+ }, []);
451
+ return ref;
452
+ }
453
+
454
+ // src/chat-ui/icons/Chat.svg
455
+ var Chat_default = '<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>';
456
+
457
+ // src/chat-ui/icons/Pin.svg
458
+ var Pin_default = '<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>';
459
+
460
+ // src/chat-ui/components/Input/InputBox.tsx
461
+ import { forwardRef as forwardRef2, useImperativeHandle, useRef as useRef3, useState as useState2 } from "react";
462
+
463
+ // src/chat-ui/icons/PaperPlane.svg
464
+ var PaperPlane_default = '<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>';
465
+
466
+ // esbuild-css-modules-plugin-ns-js::src/chat-ui/components/Input/InputBox.module.css:injector.js
467
+ var content2 = globalThis['__css-content-4f8287b7f1327101523ba48f76bd7efb__'];
468
+ var digest2 = globalThis['__css-digest-4f8287b7f1327101523ba48f76bd7efb__'];
469
+ var inject2 = () => {
470
+ setTimeout(() => {
471
+ if (!globalThis.document) {
472
+ return;
473
+ }
474
+ let root = globalThis.document.querySelector("head");
475
+ if (root && root.shadowRoot) {
476
+ root = root.shadowRoot;
477
+ }
478
+ if (!root) {
479
+ root = globalThis.document.head;
480
+ }
481
+ let container = root.querySelector("#_" + digest2);
482
+ if (!container) {
483
+ container = globalThis.document.createElement("style");
484
+ container.id = "_" + digest2;
485
+ const text = globalThis.document.createTextNode(content2);
486
+ container.appendChild(text);
487
+ root.appendChild(container);
488
+ }
489
+ }, 0);
490
+ };
491
+
492
+ // src/chat-ui/components/Input/InputBox.module.css
493
+ var InputBox_default = new Proxy({
494
+ "chatInput": "InputBox-module__chatInput_adOgOW__0220",
495
+ "inputWrapper": "InputBox-module__inputWrapper_adOgOW__0220",
496
+ "sendButton": "InputBox-module__sendButton_adOgOW__0220",
497
+ "svgIcon": "InputBox-module__svgIcon_adOgOW__0220"
498
+ }, {
499
+ get: function(source, key) {
500
+ inject2();
501
+ return source[key];
502
+ }
503
+ });
504
+
505
+ // src/chat-ui/components/Input/InputBox.tsx
506
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
507
+ var InputBox = forwardRef2(
508
+ ({ onSendMessage, hide, setFocus }, ref) => {
509
+ const inputRef = useRef3(null);
510
+ const buttonRef = useRef3(null);
511
+ const [inputValue, setInputValue] = useState2("");
512
+ useImperativeHandle(ref, () => ({
513
+ focusInput: () => {
514
+ if (inputRef.current) inputRef.current.focus();
515
+ }
516
+ }));
517
+ const handleInputChange = (e) => {
518
+ setInputValue(e.target.value);
519
+ };
520
+ const handleSendClick = () => {
521
+ if (inputValue.trim() !== "") {
522
+ onSendMessage(inputValue.trim());
523
+ setInputValue("");
524
+ }
525
+ };
526
+ const handleKeyPress = (e) => {
527
+ var _a;
528
+ e.stopPropagation();
529
+ if (e.key === "Enter") {
530
+ if (((_a = inputRef.current) == null ? void 0 : _a.value.trim().length) === 0) {
531
+ if (buttonRef.current) buttonRef.current.focus();
532
+ hide();
533
+ return;
534
+ }
535
+ handleSendClick();
536
+ }
537
+ };
538
+ return /* @__PURE__ */ jsxs2("div", { className: InputBox_default.inputWrapper, children: [
539
+ /* @__PURE__ */ jsx3(
540
+ "input",
541
+ {
542
+ ref: inputRef,
543
+ type: "text",
544
+ placeholder: "Type your message here...",
545
+ value: inputValue,
546
+ onChange: handleInputChange,
547
+ className: InputBox_default.chatInput,
548
+ onKeyDown: handleKeyPress,
549
+ onFocus: setFocus
550
+ }
551
+ ),
552
+ /* @__PURE__ */ jsx3("button", { ref: buttonRef, onClick: handleSendClick, className: InputBox_default.sendButton, children: /* @__PURE__ */ jsx3("div", { className: InputBox_default.svgIcon, children: /* @__PURE__ */ jsx3("img", { src: `data:image/svg+xml;utf8,${encodeURIComponent(PaperPlane_default)}` }) }) })
553
+ ] });
554
+ }
555
+ );
556
+ InputBox.displayName = "InputBox";
557
+
558
+ // src/chat-ui/components/Messages/Messages.tsx
559
+ import { useEffect as useEffect3, useRef as useRef4, useState as useState4 } from "react";
560
+
561
+ // src/chat-ui/components/Message/Message.tsx
562
+ import { useState as useState3, useEffect as useEffect2, useCallback } from "react";
563
+
564
+ // esbuild-css-modules-plugin-ns-js::src/chat-ui/components/Message/Message.module.css:injector.js
565
+ var content3 = globalThis['__css-content-4f8287b7f1327101523ba48f76bd7efb__'];
566
+ var digest3 = globalThis['__css-digest-4f8287b7f1327101523ba48f76bd7efb__'];
567
+ var inject3 = () => {
568
+ setTimeout(() => {
569
+ if (!globalThis.document) {
570
+ return;
571
+ }
572
+ let root = globalThis.document.querySelector("head");
573
+ if (root && root.shadowRoot) {
574
+ root = root.shadowRoot;
575
+ }
576
+ if (!root) {
577
+ root = globalThis.document.head;
578
+ }
579
+ let container = root.querySelector("#_" + digest3);
580
+ if (!container) {
581
+ container = globalThis.document.createElement("style");
582
+ container.id = "_" + digest3;
583
+ const text = globalThis.document.createTextNode(content3);
584
+ container.appendChild(text);
585
+ root.appendChild(container);
586
+ }
587
+ }, 0);
588
+ };
589
+
590
+ // src/chat-ui/components/Message/Message.module.css
591
+ var Message_default = new Proxy({
592
+ "messageContainer": "Message-module__messageContainer_ikOQiq__0220",
593
+ "userName": "Message-module__userName_ikOQiq__0220"
594
+ }, {
595
+ get: function(source, key) {
596
+ inject3();
597
+ return source[key];
598
+ }
599
+ });
600
+
601
+ // src/chat-ui/components/Message/Message.tsx
602
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
603
+ function ReverseHash(input) {
604
+ const stringLength = input.length;
605
+ let hash = 5381;
606
+ for (let i = stringLength - 1; i >= 0; i--) {
607
+ hash = (hash << 5) + hash + input.charCodeAt(i);
608
+ }
609
+ return hash;
610
+ }
611
+ function generateValueFromThresholds(hash, thresholds) {
612
+ const selectedThreshold = thresholds[hash % thresholds.length];
613
+ const min = Math.min(...selectedThreshold);
614
+ const max = Math.max(...selectedThreshold);
615
+ const thresholdRange = Math.abs(max - min);
616
+ return hash % thresholdRange + min;
617
+ }
618
+ function hslForString(input, options = DEFAULT_HSL_OPTIONS) {
619
+ let hash = Math.abs(ReverseHash("lightness: " + input));
620
+ const lightness = options.lightnessThresholds ? generateValueFromThresholds(hash, options.lightnessThresholds) : generateValueFromThresholds(hash, DEFAULT_HSL_OPTIONS.lightnessThresholds);
621
+ hash = Math.abs(ReverseHash("saturation:" + input));
622
+ const saturation = options.saturationThresholds ? generateValueFromThresholds(hash, options.saturationThresholds) : generateValueFromThresholds(hash, DEFAULT_HSL_OPTIONS.saturationThresholds);
623
+ hash = Math.abs(ReverseHash("hue:" + input));
624
+ const hue = options.hueThresholds ? generateValueFromThresholds(hash, options.hueThresholds) : generateValueFromThresholds(hash, DEFAULT_HSL_OPTIONS.hueThresholds);
625
+ return [hue, saturation, lightness];
626
+ }
627
+ var Message = ({ username, message, stringToHslOptions }) => {
628
+ const [userColors, setUserColors] = useState3(/* @__PURE__ */ new Map());
629
+ const generateColorForUsername = useCallback(() => {
630
+ const [hue, saturation, lightness] = hslForString(username, stringToHslOptions);
631
+ return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
632
+ }, [stringToHslOptions, username]);
633
+ useEffect2(() => {
634
+ if (!userColors.has(username)) {
635
+ const color = generateColorForUsername();
636
+ setUserColors(new Map(userColors).set(username, color));
637
+ }
638
+ }, [username, userColors, generateColorForUsername]);
639
+ const userColor = userColors.get(username) || "hsl(0, 0%, 0%)";
640
+ return /* @__PURE__ */ jsxs3("div", { className: Message_default.messageContainer, children: [
641
+ /* @__PURE__ */ jsx4("span", { className: Message_default.userName, style: { color: userColor }, children: username }),
642
+ ": ",
643
+ message
644
+ ] });
645
+ };
646
+ var Message_default2 = Message;
647
+
648
+ // esbuild-css-modules-plugin-ns-js::src/chat-ui/components/Messages/Messages.module.css:injector.js
649
+ var content4 = globalThis['__css-content-4f8287b7f1327101523ba48f76bd7efb__'];
650
+ var digest4 = globalThis['__css-digest-4f8287b7f1327101523ba48f76bd7efb__'];
651
+ var inject4 = () => {
652
+ setTimeout(() => {
653
+ if (!globalThis.document) {
654
+ return;
655
+ }
656
+ let root = globalThis.document.querySelector("head");
657
+ if (root && root.shadowRoot) {
658
+ root = root.shadowRoot;
659
+ }
660
+ if (!root) {
661
+ root = globalThis.document.head;
662
+ }
663
+ let container = root.querySelector("#_" + digest4);
664
+ if (!container) {
665
+ container = globalThis.document.createElement("style");
666
+ container.id = "_" + digest4;
667
+ const text = globalThis.document.createTextNode(content4);
668
+ container.appendChild(text);
669
+ root.appendChild(container);
670
+ }
671
+ }, 0);
672
+ };
673
+
674
+ // src/chat-ui/components/Messages/Messages.module.css
675
+ var Messages_default = new Proxy({
676
+ "messagesContainer": "Messages-module__messagesContainer_LXaUUW__0220",
677
+ "newMessagesButton": "Messages-module__newMessagesButton_LXaUUW__0220"
678
+ }, {
679
+ get: function(source, key) {
680
+ inject4();
681
+ return source[key];
682
+ }
683
+ });
684
+
685
+ // src/chat-ui/components/Messages/Messages.tsx
686
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
687
+ var Messages = ({ messages, stringToHslOptions, shouldAutoScroll }) => {
688
+ const messagesEndRef = useRef4(null);
689
+ const containerRef = useRef4(null);
690
+ const [unreadCount, setUnreadCount] = useState4(0);
691
+ const [lastReadMessageIndex, setLastReadMessageIndex] = useState4(0);
692
+ const [wasAtBottom, setWasAtBottom] = useState4(true);
693
+ const isAtBottom = () => {
694
+ if (!containerRef.current) return true;
695
+ const { scrollTop, scrollHeight, clientHeight } = containerRef.current;
696
+ return Math.abs(scrollHeight - clientHeight - scrollTop) < 10;
697
+ };
698
+ const handleScroll = () => {
699
+ const atBottom = isAtBottom();
700
+ setWasAtBottom(atBottom);
701
+ if (atBottom && unreadCount > 0) {
702
+ setUnreadCount(0);
703
+ setLastReadMessageIndex(messages.length - 1);
704
+ }
705
+ };
706
+ const scrollToBottom = () => {
707
+ if (messagesEndRef.current) {
708
+ messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
709
+ }
710
+ setUnreadCount(0);
711
+ setLastReadMessageIndex(messages.length - 1);
712
+ setWasAtBottom(true);
713
+ };
714
+ useEffect3(() => {
715
+ if (messages.length === 0) return;
716
+ const shouldScroll = shouldAutoScroll || wasAtBottom;
717
+ if (shouldScroll) {
718
+ setTimeout(() => {
719
+ if (!isAtBottom()) {
720
+ if (messagesEndRef.current) {
721
+ messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
722
+ }
723
+ }
724
+ setWasAtBottom(true);
725
+ }, 0);
726
+ setUnreadCount(0);
727
+ setLastReadMessageIndex(messages.length - 1);
728
+ } else {
729
+ const newUnreadCount = messages.length - 1 - lastReadMessageIndex;
730
+ setUnreadCount(newUnreadCount);
731
+ }
732
+ }, [messages, shouldAutoScroll, wasAtBottom, lastReadMessageIndex]);
733
+ return /* @__PURE__ */ jsxs4(Fragment2, { children: [
734
+ /* @__PURE__ */ jsxs4(
735
+ "div",
736
+ {
737
+ ref: containerRef,
738
+ className: Messages_default.messagesContainer,
739
+ onScroll: handleScroll,
740
+ children: [
741
+ messages.map((msg, index) => /* @__PURE__ */ jsx5(
742
+ Message_default2,
743
+ {
744
+ username: msg.username,
745
+ message: msg.message,
746
+ stringToHslOptions
747
+ },
748
+ index
749
+ )),
750
+ /* @__PURE__ */ jsx5("div", { ref: messagesEndRef })
751
+ ]
752
+ }
753
+ ),
754
+ unreadCount > 0 && /* @__PURE__ */ jsxs4(
755
+ "button",
756
+ {
757
+ className: Messages_default.newMessagesButton,
758
+ onClick: scrollToBottom,
759
+ children: [
760
+ unreadCount,
761
+ " new message",
762
+ unreadCount !== 1 ? "s" : ""
763
+ ]
764
+ }
765
+ )
766
+ ] });
767
+ };
768
+
769
+ // esbuild-css-modules-plugin-ns-js::src/chat-ui/components/ChatPanel/TextChatUIComponent.module.css:injector.js
770
+ var content5 = globalThis['__css-content-4f8287b7f1327101523ba48f76bd7efb__'];
771
+ var digest5 = globalThis['__css-digest-4f8287b7f1327101523ba48f76bd7efb__'];
772
+ var inject5 = () => {
773
+ setTimeout(() => {
774
+ if (!globalThis.document) {
775
+ return;
776
+ }
777
+ let root = globalThis.document.querySelector("head");
778
+ if (root && root.shadowRoot) {
779
+ root = root.shadowRoot;
780
+ }
781
+ if (!root) {
782
+ root = globalThis.document.head;
783
+ }
784
+ let container = root.querySelector("#_" + digest5);
785
+ if (!container) {
786
+ container = globalThis.document.createElement("style");
787
+ container.id = "_" + digest5;
788
+ const text = globalThis.document.createTextNode(content5);
789
+ container.appendChild(text);
790
+ root.appendChild(container);
791
+ }
792
+ }, 0);
793
+ };
794
+
795
+ // src/chat-ui/components/ChatPanel/TextChatUIComponent.module.css
796
+ var TextChatUIComponent_default = new Proxy({
797
+ "closeButton": "TextChatUIComponent-module__closeButton_gFDdcW__0220",
798
+ "controls": "TextChatUIComponent-module__controls_gFDdcW__0220",
799
+ "fadeIn": "TextChatUIComponent-module__fadeIn_gFDdcW__0220",
800
+ "fadeOut": "TextChatUIComponent-module__fadeOut_gFDdcW__0220",
801
+ "messagesWrapper": "TextChatUIComponent-module__messagesWrapper_gFDdcW__0220",
802
+ "openTab": "TextChatUIComponent-module__openTab_gFDdcW__0220",
803
+ "stickyButton": "TextChatUIComponent-module__stickyButton_gFDdcW__0220",
804
+ "stickyButtonEnabled": "TextChatUIComponent-module__stickyButtonEnabled_gFDdcW__0220",
805
+ "stickyButtonFadeOut": "TextChatUIComponent-module__stickyButtonFadeOut_gFDdcW__0220",
806
+ "textChat": "TextChatUIComponent-module__textChat_gFDdcW__0220",
807
+ "textChatUi": "TextChatUIComponent-module__textChatUi_gFDdcW__0220",
808
+ "uiHover": "TextChatUIComponent-module__uiHover_gFDdcW__0220"
809
+ }, {
810
+ get: function(source, key) {
811
+ inject5();
812
+ return source[key];
813
+ }
814
+ });
815
+
816
+ // src/chat-ui/components/ChatPanel/TextChatUIComponent.tsx
817
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
818
+ var MAX_MESSAGES = 50;
819
+ var SECONDS_TO_FADE_OUT = 6;
820
+ var ChatUIComponent = (props, ref) => {
821
+ const visibleByDefault = props.visibleByDefault ?? true;
822
+ const [messages, setMessages] = useState5([]);
823
+ const [isVisible, setIsVisible] = useState5(visibleByDefault);
824
+ const [isSticky, setSticky] = useState5(visibleByDefault);
825
+ const [isFocused, setIsFocused] = useState5(false);
826
+ const [isOpenHovered, setOpenHovered] = useState5(false);
827
+ const [shouldAutoScroll, setShouldAutoScroll] = useState5(false);
828
+ const [panelStyle, setPanelStyle] = useState5(TextChatUIComponent_default.fadeOut);
829
+ const [stickyStyle, setStickyStyle] = useState5(TextChatUIComponent_default.stickyButton);
830
+ const stickyButtonRef = useRef5(null);
831
+ const closeButtonRef = useRef5(null);
832
+ const hideTimeoutRef = useRef5(null);
833
+ const inputBoxRef = useRef5(null);
834
+ const startHideTimeout = useCallback2(() => {
835
+ if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
836
+ hideTimeoutRef.current = setTimeout(() => {
837
+ if (isVisible) {
838
+ setIsVisible(false);
839
+ }
840
+ }, SECONDS_TO_FADE_OUT * 1e3);
841
+ }, [isVisible]);
842
+ const handleKeyDown = useCallback2(
843
+ (e) => {
844
+ if (e.key === "Enter") {
845
+ if (!isVisible) setIsVisible(true);
846
+ setIsFocused(true);
847
+ if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
848
+ if (inputBoxRef.current) inputBoxRef.current.focusInput();
849
+ }
850
+ },
851
+ [isVisible]
852
+ );
853
+ const handleBlur = useCallback2(() => {
854
+ if (isFocused) setIsFocused(false);
855
+ startHideTimeout();
856
+ if (closeButtonRef.current) closeButtonRef.current.focus();
857
+ }, [isFocused, startHideTimeout]);
858
+ const hide = () => {
859
+ setIsVisible(false);
860
+ setIsFocused(false);
861
+ if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
862
+ };
863
+ const handleRootClick = (e) => {
864
+ e.stopPropagation();
865
+ setOpenHovered(true);
866
+ if (!isVisible) setIsVisible(true);
867
+ };
868
+ const handleStickyButton = (e) => {
869
+ e.stopPropagation();
870
+ setSticky(!isSticky);
871
+ };
872
+ const handleWheel = (e) => {
873
+ e.stopPropagation();
874
+ };
875
+ const handleMouseLeave = () => {
876
+ setOpenHovered(false);
877
+ if (!isFocused && !isSticky && isVisible) {
878
+ startHideTimeout();
879
+ }
880
+ };
881
+ const handleMouseEnter = () => {
882
+ setOpenHovered(true);
883
+ if (!isVisible) setIsVisible(true);
884
+ };
885
+ const chatPanelRef = useClickOutside(() => {
886
+ if (isFocused) {
887
+ setIsFocused(false);
888
+ startHideTimeout();
889
+ }
890
+ });
891
+ useEffect4(() => {
892
+ if (isVisible && isSticky) {
893
+ if (chatPanelRef.current) chatPanelRef.current.style.zIndex = "100";
894
+ }
895
+ setPanelStyle(isVisible || isFocused || isSticky ? TextChatUIComponent_default.fadeIn : TextChatUIComponent_default.fadeOut);
896
+ setStickyStyle(
897
+ isSticky ? TextChatUIComponent_default.stickyButtonEnabled : isOpenHovered ? TextChatUIComponent_default.stickyButton : TextChatUIComponent_default.stickyButtonFadeOut
898
+ );
899
+ if (chatPanelRef.current && chatPanelRef.current.style.zIndex !== "100") {
900
+ setTimeout(() => {
901
+ if (chatPanelRef.current) chatPanelRef.current.style.zIndex = "100";
902
+ }, 2e3);
903
+ }
904
+ }, [isVisible, isSticky, isFocused, chatPanelRef, isOpenHovered]);
905
+ const appendMessages = (username, message) => {
906
+ setMessages((prev) => {
907
+ const newMessages = [...prev, { username, message }];
908
+ return newMessages.length > MAX_MESSAGES ? newMessages.slice(-MAX_MESSAGES) : newMessages;
909
+ });
910
+ };
911
+ useImperativeHandle2(ref, () => ({
912
+ addMessage: (username, message) => {
913
+ appendMessages(username, message);
914
+ if (!isVisible) setIsVisible(true);
915
+ startHideTimeout();
916
+ }
917
+ }));
918
+ const handleSendMessage = (message) => {
919
+ setShouldAutoScroll(true);
920
+ props.sendMessageToServer(message);
921
+ setTimeout(() => setShouldAutoScroll(false), 100);
922
+ };
923
+ const setFocus = () => setIsFocused(true);
924
+ useEffect4(() => {
925
+ window.addEventListener("keydown", handleKeyDown, false);
926
+ window.addEventListener("blur", handleBlur, false);
927
+ return () => {
928
+ window.removeEventListener("keydown", handleKeyDown, false);
929
+ window.removeEventListener("blur", handleBlur, false);
930
+ };
931
+ }, [handleBlur, handleKeyDown]);
932
+ return /* @__PURE__ */ jsxs5("div", { className: TextChatUIComponent_default.textChatUi, children: [
933
+ /* @__PURE__ */ jsxs5(
934
+ "div",
935
+ {
936
+ className: TextChatUIComponent_default.uiHover,
937
+ onMouseEnter: handleMouseEnter,
938
+ onMouseLeave: handleMouseLeave,
939
+ onClick: handleRootClick,
940
+ children: [
941
+ /* @__PURE__ */ jsx6("div", { className: TextChatUIComponent_default.openTab, onClick: hide, children: /* @__PURE__ */ jsx6("img", { src: `data:image/svg+xml;utf8,${encodeURIComponent(Chat_default)}` }) }),
942
+ /* @__PURE__ */ jsx6("div", { ref: stickyButtonRef, className: stickyStyle, onClick: handleStickyButton, children: /* @__PURE__ */ jsx6("img", { src: `data:image/svg+xml;utf8,${encodeURIComponent(Pin_default)}` }) })
943
+ ]
944
+ }
945
+ ),
946
+ /* @__PURE__ */ jsxs5(
947
+ "div",
948
+ {
949
+ ref: chatPanelRef,
950
+ style: { zIndex: -1 },
951
+ id: "text-chat-wrapper",
952
+ className: `${TextChatUIComponent_default.textChat} ${panelStyle}`,
953
+ onWheel: handleWheel,
954
+ children: [
955
+ /* @__PURE__ */ jsx6("div", { className: TextChatUIComponent_default.messagesWrapper, children: /* @__PURE__ */ jsx6(Messages, { messages, stringToHslOptions: props.stringToHslOptions, shouldAutoScroll }) }),
956
+ /* @__PURE__ */ jsx6(
957
+ InputBox,
958
+ {
959
+ ref: inputBoxRef,
960
+ onSendMessage: handleSendMessage,
961
+ hide,
962
+ setFocus
963
+ }
964
+ )
965
+ ]
966
+ }
967
+ )
968
+ ] });
969
+ };
970
+
971
+ // src/chat-ui/TextChatUI.tsx
972
+ import { jsx as jsx7 } from "react/jsx-runtime";
973
+ var DEFAULT_HUE_RANGES = [[10, 350]];
974
+ var DEFAULT_SATURATION_RANGES = [[60, 100]];
975
+ var DEFAULT_LIGHTNESS_RANGES = [[65, 75]];
976
+ var DEFAULT_HSL_OPTIONS = {
977
+ hueThresholds: DEFAULT_HUE_RANGES,
978
+ saturationThresholds: DEFAULT_SATURATION_RANGES,
979
+ lightnessThresholds: DEFAULT_LIGHTNESS_RANGES
980
+ };
981
+ var ForwardedChatUIComponent = forwardRef3(ChatUIComponent);
982
+ var TextChatUI = class {
983
+ constructor(config) {
984
+ this.config = config;
985
+ this.appRef = createRef2();
986
+ this.wrapper = document.createElement("div");
987
+ this.config.holderElement.appendChild(this.wrapper);
988
+ this.root = createRoot2(this.wrapper);
989
+ }
990
+ addTextMessage(username, message) {
991
+ if (this.appRef.current) {
992
+ this.appRef.current.addMessage(username, message);
993
+ }
994
+ }
995
+ dispose() {
996
+ this.root.unmount();
997
+ this.wrapper.remove();
998
+ }
999
+ init() {
1000
+ flushSync2(
1001
+ () => this.root.render(
1002
+ /* @__PURE__ */ jsx7(
1003
+ ForwardedChatUIComponent,
1004
+ {
1005
+ ref: this.appRef,
1006
+ sendMessageToServer: this.config.sendMessageToServerMethod,
1007
+ visibleByDefault: this.config.visibleByDefault,
1008
+ stringToHslOptions: this.config.stringToHslOptions
1009
+ }
1010
+ )
1011
+ )
1012
+ );
1013
+ }
1014
+ };
1015
+
1016
+ // esbuild-css-modules-plugin-ns-js::src/Networked3dWebExperience.module.css:injector.js
1017
+ var content6 = globalThis['__css-content-4f8287b7f1327101523ba48f76bd7efb__'];
1018
+ var digest6 = globalThis['__css-digest-4f8287b7f1327101523ba48f76bd7efb__'];
1019
+ var inject6 = () => {
1020
+ setTimeout(() => {
1021
+ if (!globalThis.document) {
1022
+ return;
1023
+ }
1024
+ let root = globalThis.document.querySelector("head");
1025
+ if (root && root.shadowRoot) {
1026
+ root = root.shadowRoot;
1027
+ }
1028
+ if (!root) {
1029
+ root = globalThis.document.head;
1030
+ }
1031
+ let container = root.querySelector("#_" + digest6);
1032
+ if (!container) {
1033
+ container = globalThis.document.createElement("style");
1034
+ container.id = "_" + digest6;
1035
+ const text = globalThis.document.createTextNode(content6);
1036
+ container.appendChild(text);
1037
+ root.appendChild(container);
1038
+ }
1039
+ }, 0);
1040
+ };
1041
+
1042
+ // src/Networked3dWebExperience.module.css
1043
+ var Networked3dWebExperience_default = new Proxy({
1044
+ "respawnButton": "Networked3dWebExperience-module__respawnButton_7g9l0W__0220"
1045
+ }, {
1046
+ get: function(source, key) {
1047
+ inject6();
1048
+ return source[key];
1049
+ }
1050
+ });
1051
+
1052
+ // src/Networked3dWebExperienceClient.ts
40
1053
  function normalizeSpawnConfiguration(spawnConfig) {
41
1054
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
42
1055
  return {
@@ -69,27 +1082,23 @@ var Networked3dWebExperienceClient = class {
69
1082
  this.scene = new Scene();
70
1083
  this.tweakPane = null;
71
1084
  this.audioListener = new AudioListener();
72
- this.collisionsManager = new CollisionsManager(this.scene);
73
- this.characterModelLoader = new CharacterModelLoader();
74
1085
  this.timeManager = new TimeManager();
75
1086
  this.keyInputManager = new KeyInputManager();
76
1087
  this.mmlFrames = {};
77
1088
  this.clientId = null;
78
1089
  this.remoteUserStates = /* @__PURE__ */ new Map();
79
1090
  this.userProfiles = /* @__PURE__ */ new Map();
80
- this.networkChat = null;
81
1091
  this.textChatUI = null;
82
1092
  this.avatarSelectionUI = null;
83
- this.voiceChatManager = null;
84
1093
  this.latestCharacterObject = {
85
1094
  characterState: null
86
1095
  };
87
1096
  this.characterControllerPaneSet = false;
88
1097
  this.initialLoadCompleted = false;
89
1098
  this.loadingProgressManager = new LoadingProgressManager();
90
- this.currentRequestAnimationFrame = null;
91
1099
  this.groundPlane = null;
92
1100
  this.respawnButton = null;
1101
+ this.currentRequestAnimationFrame = null;
93
1102
  var _a;
94
1103
  this.element = document.createElement("div");
95
1104
  this.element.style.position = "absolute";
@@ -106,8 +1115,10 @@ var Networked3dWebExperienceClient = class {
106
1115
  this.canvasHolder.style.width = "100%";
107
1116
  this.canvasHolder.style.height = "100%";
108
1117
  this.element.appendChild(this.canvasHolder);
1118
+ this.collisionsManager = new CollisionsManager(this.scene);
109
1119
  this.cameraManager = new CameraManager(this.canvasHolder, this.collisionsManager);
110
1120
  this.cameraManager.camera.add(this.audioListener);
1121
+ this.characterModelLoader = new CharacterModelLoader();
111
1122
  this.virtualJoystick = new VirtualJoystick(this.element, {
112
1123
  radius: 70,
113
1124
  innerRadius: 20,
@@ -117,7 +1128,8 @@ var Networked3dWebExperienceClient = class {
117
1128
  scene: this.scene,
118
1129
  cameraManager: this.cameraManager,
119
1130
  spawnSun: true,
120
- environmentConfiguration: this.config.environmentConfiguration
1131
+ environmentConfiguration: this.config.environmentConfiguration,
1132
+ postProcessingEnabled: this.config.postProcessingEnabled
121
1133
  });
122
1134
  this.canvasHolder.appendChild(this.composer.renderer.domElement);
123
1135
  if (this.config.enableTweakPane !== false) {
@@ -127,62 +1139,88 @@ var Networked3dWebExperienceClient = class {
127
1139
  this.composer.fitContainer();
128
1140
  });
129
1141
  resizeObserver.observe(this.element);
1142
+ this.spawnConfiguration = normalizeSpawnConfiguration(this.config.spawnConfiguration);
1143
+ const spawnData = getSpawnData(this.spawnConfiguration, true);
1144
+ const spawnRotation = new Quat().setFromEulerXYZ(spawnData.spawnRotation);
130
1145
  const initialNetworkLoadRef = {};
131
1146
  this.loadingProgressManager.addLoadingAsset(initialNetworkLoadRef, "network", "network");
132
- this.networkClient = new UserNetworkingClient({
133
- url: this.config.userNetworkAddress,
134
- sessionToken: this.config.sessionToken,
135
- websocketFactory: (url) => new WebSocket(url),
136
- statusUpdateCallback: (status) => {
137
- if (status === WebsocketStatus.Disconnected || status === WebsocketStatus.Reconnecting) {
138
- this.characterManager.clear();
139
- this.remoteUserStates.clear();
140
- this.clientId = null;
141
- }
142
- },
143
- assignedIdentity: (clientId) => {
144
- console.log(`Assigned ID: ${clientId}`);
145
- this.clientId = clientId;
146
- if (this.initialLoadCompleted) {
147
- this.spawnCharacter();
148
- } else {
149
- this.loadingProgressManager.completedLoadingAsset(initialNetworkLoadRef);
1147
+ this.networkClient = new UserNetworkingClient(
1148
+ {
1149
+ url: this.config.userNetworkAddress,
1150
+ sessionToken: this.config.sessionToken,
1151
+ websocketFactory: (url) => new WebSocket(url, "delta-net-v0.1"),
1152
+ statusUpdateCallback: (status) => {
1153
+ console.log(`Websocket status: ${status}`);
1154
+ if (status === WebsocketStatus.Disconnected || status === WebsocketStatus.Reconnecting) {
1155
+ this.characterManager.clear();
1156
+ this.remoteUserStates.clear();
1157
+ this.clientId = null;
1158
+ }
1159
+ },
1160
+ assignedIdentity: (clientId) => {
1161
+ console.log(`Assigned ID: ${clientId}`);
1162
+ this.clientId = clientId;
1163
+ if (this.initialLoadCompleted) {
1164
+ const spawnData2 = getSpawnData(this.spawnConfiguration, true);
1165
+ this.spawnCharacter(spawnData2);
1166
+ } else {
1167
+ this.loadingProgressManager.completedLoadingAsset(initialNetworkLoadRef);
1168
+ }
1169
+ },
1170
+ onUpdate: (update) => {
1171
+ this.onNetworkUpdate(update);
1172
+ },
1173
+ onServerError: (error) => {
1174
+ switch (error.errorType) {
1175
+ case DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE:
1176
+ this.disposeWithError(error.message);
1177
+ break;
1178
+ case DeltaNetV01ServerErrors.USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE:
1179
+ this.disposeWithError(error.message);
1180
+ break;
1181
+ case DeltaNetV01ServerErrors.USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE:
1182
+ this.disposeWithError(error.message || "Server shutdown");
1183
+ break;
1184
+ default:
1185
+ console.error(`Unhandled server error: ${error.message}`);
1186
+ this.disposeWithError(error.message);
1187
+ }
1188
+ },
1189
+ onCustomMessage: (customType, contents) => {
1190
+ var _a2, _b;
1191
+ if (customType === SERVER_BROADCAST_MESSAGE_TYPE) {
1192
+ const serverBroadcastMessage = parseServerBroadcastMessage(contents);
1193
+ if (serverBroadcastMessage instanceof Error) {
1194
+ console.error(`Invalid server broadcast message: ${contents}`);
1195
+ } else {
1196
+ (_b = (_a2 = this.config).onServerBroadcast) == null ? void 0 : _b.call(_a2, serverBroadcastMessage);
1197
+ }
1198
+ } else if (customType === FROM_SERVER_CHAT_MESSAGE_TYPE) {
1199
+ const serverChatMessage = parseServerChatMessage(contents);
1200
+ if (serverChatMessage instanceof Error) {
1201
+ console.error(`Invalid server chat message: ${contents}`);
1202
+ } else {
1203
+ this.handleChatMessage(serverChatMessage.fromUserId, serverChatMessage.message);
1204
+ }
1205
+ } else {
1206
+ console.warn(`Did not recognize custom message type ${customType}`);
1207
+ }
150
1208
  }
151
1209
  },
152
- clientUpdate: (remoteClientId, userNetworkingClientUpdate) => {
153
- if (userNetworkingClientUpdate === null) {
154
- this.remoteUserStates.delete(remoteClientId);
155
- } else {
156
- this.remoteUserStates.set(remoteClientId, userNetworkingClientUpdate);
157
- }
1210
+ {
1211
+ username: null,
1212
+ characterDescription: null,
1213
+ colors: null
158
1214
  },
159
- clientProfileUpdated: (clientId, username, characterDescription) => {
160
- this.updateUserProfile(clientId, {
161
- username,
162
- characterDescription
163
- });
164
- },
165
- onServerError: (error) => {
166
- switch (error.errorType) {
167
- case USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE:
168
- this.disposeWithError(error.message);
169
- break;
170
- case USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE:
171
- this.disposeWithError(error.message);
172
- break;
173
- case USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE:
174
- this.disposeWithError(error.message || "Server shutdown");
175
- break;
176
- default:
177
- console.error(`Unhandled server error: ${error.message}`);
178
- this.disposeWithError(error.message);
179
- }
180
- },
181
- onServerBroadcast: (broadcast) => {
182
- var _a2, _b;
183
- (_b = (_a2 = this.config).onServerBroadcast) == null ? void 0 : _b.call(_a2, broadcast);
1215
+ {
1216
+ position: spawnData.spawnPosition,
1217
+ rotation: {
1218
+ quaternionY: spawnRotation.y,
1219
+ quaternionW: spawnRotation.w
1220
+ },
1221
+ state: 0
184
1222
  }
185
- });
1223
+ );
186
1224
  if (this.config.allowOrbitalCamera) {
187
1225
  this.keyInputManager.createKeyBinding(Key.C, () => {
188
1226
  if (document.activeElement === document.body) {
@@ -191,7 +1229,10 @@ var Networked3dWebExperienceClient = class {
191
1229
  }
192
1230
  });
193
1231
  }
194
- this.spawnConfiguration = normalizeSpawnConfiguration(this.config.spawnConfiguration);
1232
+ const animationsPromise = Character.loadAnimations(
1233
+ this.characterModelLoader,
1234
+ this.config.animationConfig
1235
+ );
195
1236
  this.characterManager = new CharacterManager({
196
1237
  composer: this.composer,
197
1238
  characterModelLoader: this.characterModelLoader,
@@ -205,7 +1246,10 @@ var Networked3dWebExperienceClient = class {
205
1246
  this.latestCharacterObject.characterState = characterState;
206
1247
  this.networkClient.sendUpdate(characterState);
207
1248
  },
208
- animationConfig: this.config.animationConfig,
1249
+ sendLocalCharacterColors: (colors) => {
1250
+ this.networkClient.updateColors(colors);
1251
+ },
1252
+ animationsPromise,
209
1253
  spawnConfiguration: this.spawnConfiguration,
210
1254
  characterResolve: (characterId) => {
211
1255
  return this.resolveCharacterData(characterId);
@@ -214,7 +1258,8 @@ var Networked3dWebExperienceClient = class {
214
1258
  });
215
1259
  this.scene.add(this.characterManager.group);
216
1260
  if (this.spawnConfiguration.enableRespawnButton) {
217
- this.element.appendChild(this.characterManager.createRespawnButton());
1261
+ this.respawnButton = this.createRespawnButton();
1262
+ this.element.appendChild(this.respawnButton);
218
1263
  }
219
1264
  this.setGroundPlaneEnabled(((_a = this.config.environmentConfiguration) == null ? void 0 : _a.groundPlane) ?? true);
220
1265
  this.setupMMLScene();
@@ -224,10 +1269,10 @@ var Networked3dWebExperienceClient = class {
224
1269
  const [, completed] = this.loadingProgressManager.toRatio();
225
1270
  if (completed && !this.initialLoadCompleted) {
226
1271
  this.initialLoadCompleted = true;
227
- this.connectToVoiceChat();
1272
+ console.log("Initial load completed");
228
1273
  this.connectToTextChat();
229
1274
  this.mountAvatarSelectionUI();
230
- this.spawnCharacter();
1275
+ this.spawnCharacter(spawnData);
231
1276
  }
232
1277
  });
233
1278
  this.loadingProgressManager.setInitialLoad(true);
@@ -244,7 +1289,6 @@ var Networked3dWebExperienceClient = class {
244
1289
  }
245
1290
  }
246
1291
  updateConfig(config) {
247
- var _a;
248
1292
  this.config = {
249
1293
  ...this.config,
250
1294
  ...config
@@ -267,6 +1311,14 @@ var Networked3dWebExperienceClient = class {
267
1311
  this.setupTweakPane();
268
1312
  }
269
1313
  }
1314
+ if (this.config.postProcessingEnabled !== void 0) {
1315
+ this.composer.togglePostProcessing(this.config.postProcessingEnabled);
1316
+ if (this.tweakPane) {
1317
+ this.tweakPane.dispose();
1318
+ this.tweakPane = null;
1319
+ this.setupTweakPane();
1320
+ }
1321
+ }
270
1322
  if (config.allowOrbitalCamera !== void 0) {
271
1323
  if (config.allowOrbitalCamera === false) {
272
1324
  this.keyInputManager.removeKeyBinding(Key.C);
@@ -282,11 +1334,9 @@ var Networked3dWebExperienceClient = class {
282
1334
  });
283
1335
  }
284
1336
  }
285
- if (config.chatNetworkAddress !== void 0) {
286
- if (config.chatNetworkAddress === null && this.networkChat !== null) {
287
- this.networkChat.stop();
288
- this.networkChat = null;
289
- (_a = this.textChatUI) == null ? void 0 : _a.dispose();
1337
+ if (config.enableChat) {
1338
+ if (!config.enableChat && this.textChatUI !== null) {
1339
+ this.textChatUI.dispose();
290
1340
  this.textChatUI = null;
291
1341
  } else {
292
1342
  this.connectToTextChat();
@@ -297,7 +1347,7 @@ var Networked3dWebExperienceClient = class {
297
1347
  this.characterManager.localController.updateSpawnConfig(this.spawnConfiguration);
298
1348
  }
299
1349
  if (this.spawnConfiguration.enableRespawnButton && !this.respawnButton) {
300
- this.respawnButton = this.characterManager.createRespawnButton();
1350
+ this.respawnButton = this.createRespawnButton();
301
1351
  this.element.appendChild(this.respawnButton);
302
1352
  } else if (!this.spawnConfiguration.enableRespawnButton && this.respawnButton) {
303
1353
  this.respawnButton.remove();
@@ -318,6 +1368,16 @@ var Networked3dWebExperienceClient = class {
318
1368
  document.body.appendChild(holder);
319
1369
  return holder;
320
1370
  }
1371
+ createRespawnButton() {
1372
+ const respawnButton = document.createElement("div");
1373
+ respawnButton.className = Networked3dWebExperience_default.respawnButton;
1374
+ respawnButton.textContent = "RESPAWN";
1375
+ respawnButton.addEventListener("click", () => {
1376
+ var _a;
1377
+ (_a = this.characterManager.localController) == null ? void 0 : _a.resetPosition();
1378
+ });
1379
+ return respawnButton;
1380
+ }
321
1381
  resolveCharacterData(clientId) {
322
1382
  const user = this.userProfiles.get(clientId);
323
1383
  if (!user) {
@@ -325,41 +1385,43 @@ var Networked3dWebExperienceClient = class {
325
1385
  }
326
1386
  return {
327
1387
  username: user.username,
328
- characterDescription: user.characterDescription
1388
+ characterDescription: user.characterDescription,
1389
+ colors: user.colors
329
1390
  };
330
1391
  }
331
- updateUserProfile(id, userData) {
332
- console.log(`Update user_profile for id=${id} (username=${userData.username})`);
333
- this.userProfiles.set(id, userData);
334
- if (this.textChatUI && id === this.clientId) {
335
- this.textChatUI.setClientName(userData.username);
1392
+ onNetworkUpdate(update) {
1393
+ const { removedUserIds, addedUserIds, updatedUsers } = update;
1394
+ for (const clientId of removedUserIds) {
1395
+ this.userProfiles.delete(clientId);
1396
+ this.remoteUserStates.delete(clientId);
1397
+ }
1398
+ for (const [clientId, userData] of addedUserIds) {
1399
+ this.userProfiles.set(clientId, userData.userState);
1400
+ this.remoteUserStates.set(clientId, userData.components);
1401
+ }
1402
+ for (const [clientId, userDataUpdate] of updatedUsers) {
1403
+ const userState = userDataUpdate.userState;
1404
+ if (userState) {
1405
+ if (userState.username !== void 0) {
1406
+ this.userProfiles.get(clientId).username = userState.username;
1407
+ }
1408
+ if (userState.characterDescription !== void 0) {
1409
+ this.userProfiles.get(clientId).characterDescription = userState.characterDescription;
1410
+ }
1411
+ if (userState.colors !== void 0) {
1412
+ this.userProfiles.get(clientId).colors = userState.colors;
1413
+ }
1414
+ this.characterManager.networkCharacterInfoUpdated(clientId);
1415
+ }
1416
+ this.remoteUserStates.set(clientId, userDataUpdate.components);
336
1417
  }
337
- this.characterManager.respawnIfPresent(id);
338
1418
  }
339
1419
  sendIdentityUpdateToServer(displayName, characterDescription) {
340
1420
  if (!this.clientId) {
341
1421
  throw new Error("Client ID not set");
342
1422
  }
343
- this.networkClient.sendMessage({
344
- type: USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE,
345
- userIdentity: {
346
- username: displayName,
347
- characterDescription
348
- }
349
- });
350
- }
351
- connectToVoiceChat() {
352
- if (this.clientId === null) return;
353
- if (this.voiceChatManager === null && this.config.voiceChatAddress) {
354
- this.voiceChatManager = new VoiceChatManager({
355
- url: this.config.voiceChatAddress,
356
- holderElement: this.element,
357
- userId: this.clientId,
358
- remoteUserStates: this.remoteUserStates,
359
- latestCharacterObj: this.latestCharacterObject,
360
- autoJoin: false
361
- });
362
- }
1423
+ this.networkClient.updateUsername(displayName);
1424
+ this.networkClient.updateCharacterDescription(characterDescription);
363
1425
  }
364
1426
  setupTweakPane() {
365
1427
  if (this.tweakPane) {
@@ -369,57 +1431,53 @@ var Networked3dWebExperienceClient = class {
369
1431
  this.element,
370
1432
  this.composer.renderer,
371
1433
  this.scene,
372
- this.composer.effectComposer
1434
+ this.composer,
1435
+ this.config.postProcessingEnabled
373
1436
  );
374
1437
  this.cameraManager.setupTweakPane(this.tweakPane);
375
1438
  this.composer.setupTweakPane(this.tweakPane);
376
1439
  }
1440
+ handleChatMessage(fromUserId, message) {
1441
+ if (this.textChatUI === null) {
1442
+ return;
1443
+ }
1444
+ if (fromUserId === 0) {
1445
+ this.textChatUI.addTextMessage("System", message);
1446
+ } else {
1447
+ const user = this.userProfiles.get(fromUserId);
1448
+ if (!user) {
1449
+ console.error(`User not found for clientId ${fromUserId}`);
1450
+ return;
1451
+ }
1452
+ const username = user.username ?? `Unknown User ${fromUserId}`;
1453
+ this.textChatUI.addTextMessage(username, message);
1454
+ this.characterManager.addChatBubble(fromUserId, message);
1455
+ }
1456
+ }
377
1457
  connectToTextChat() {
378
1458
  if (this.clientId === null) {
379
1459
  return;
380
1460
  }
381
- if (this.networkChat === null && this.config.chatNetworkAddress) {
1461
+ if (this.config.enableChat && this.textChatUI === null) {
382
1462
  const user = this.userProfiles.get(this.clientId);
383
1463
  if (!user) {
384
1464
  throw new Error("User not found");
385
1465
  }
386
- if (this.textChatUI === null) {
387
- const textChatUISettings = {
388
- holderElement: this.element,
389
- clientname: user.username,
390
- sendMessageToServerMethod: (message) => {
391
- this.characterManager.addSelfChatBubble(message);
392
- this.mmlCompositionScene.onChatMessage(message);
393
- if (this.clientId === null || this.networkChat === null) return;
394
- this.networkChat.sendChatMessage(message);
395
- },
396
- visibleByDefault: this.config.chatVisibleByDefault,
397
- stringToHslOptions: this.config.userNameToColorOptions
398
- };
399
- this.textChatUI = new TextChatUI(textChatUISettings);
400
- this.textChatUI.init();
401
- }
402
- this.networkChat = new ChatNetworkingClient({
403
- url: this.config.chatNetworkAddress,
404
- sessionToken: this.config.sessionToken,
405
- websocketFactory: (url) => new WebSocket(url),
406
- statusUpdateCallback: (status) => {
407
- if (status === WebsocketStatus.Disconnected || status === WebsocketStatus.Reconnecting) {
408
- }
1466
+ const textChatUISettings = {
1467
+ holderElement: this.canvasHolder,
1468
+ sendMessageToServerMethod: (message) => {
1469
+ this.characterManager.addSelfChatBubble(message);
1470
+ this.mmlCompositionScene.onChatMessage(message);
1471
+ this.networkClient.sendCustomMessage(
1472
+ FROM_CLIENT_CHAT_MESSAGE_TYPE,
1473
+ JSON.stringify({ message })
1474
+ );
409
1475
  },
410
- clientChatUpdate: (clientId, chatNetworkingUpdate) => {
411
- var _a;
412
- if (chatNetworkingUpdate !== null && this.textChatUI !== null) {
413
- const username = ((_a = this.userProfiles.get(clientId)) == null ? void 0 : _a.username) || "Unknown";
414
- this.textChatUI.addTextMessage(username, chatNetworkingUpdate.text);
415
- this.characterManager.addChatBubble(clientId, chatNetworkingUpdate.text);
416
- }
417
- },
418
- onServerError: (error) => {
419
- console.error(`Chat server error: ${error.message}. errorType: ${error.errorType}`);
420
- this.disposeWithError(error.message);
421
- }
422
- });
1476
+ visibleByDefault: this.config.chatVisibleByDefault,
1477
+ stringToHslOptions: this.config.userNameToColorOptions
1478
+ };
1479
+ this.textChatUI = new TextChatUI(textChatUISettings);
1480
+ this.textChatUI.init();
423
1481
  }
424
1482
  }
425
1483
  mountAvatarSelectionUI() {
@@ -434,8 +1492,10 @@ var Networked3dWebExperienceClient = class {
434
1492
  this.avatarSelectionUI = new AvatarSelectionUI({
435
1493
  holderElement: this.element,
436
1494
  visibleByDefault: false,
437
- displayName: ownIdentity.username,
438
- characterDescription: ownIdentity.characterDescription,
1495
+ displayName: ownIdentity.username ?? `Unknown User ${this.clientId}`,
1496
+ characterDescription: ownIdentity.characterDescription ?? {
1497
+ meshFileUrl: ""
1498
+ },
439
1499
  sendIdentityUpdateToServer: this.sendIdentityUpdateToServer.bind(this),
440
1500
  availableAvatars: ((_a = this.config.avatarConfiguration) == null ? void 0 : _a.availableAvatars) ?? [],
441
1501
  allowCustomAvatars: (_b = this.config.avatarConfiguration) == null ? void 0 : _b.allowCustomAvatars,
@@ -444,16 +1504,16 @@ var Networked3dWebExperienceClient = class {
444
1504
  this.avatarSelectionUI.init();
445
1505
  }
446
1506
  update() {
447
- var _a, _b, _c, _d;
1507
+ var _a, _b, _c;
448
1508
  this.timeManager.update();
449
1509
  this.characterManager.update();
450
- (_a = this.voiceChatManager) == null ? void 0 : _a.speakingParticipants.forEach((value, id) => {
451
- this.characterManager.setSpeakingCharacter(id, value);
452
- });
453
1510
  this.cameraManager.update();
454
- (_c = this.composer.sun) == null ? void 0 : _c.updateCharacterPosition((_b = this.characterManager.localCharacter) == null ? void 0 : _b.position);
1511
+ const characterPosition = (_a = this.characterManager.localCharacter) == null ? void 0 : _a.getPosition();
1512
+ (_b = this.composer.sun) == null ? void 0 : _b.updateCharacterPosition(
1513
+ new Vector3((characterPosition == null ? void 0 : characterPosition.x) || 0, (characterPosition == null ? void 0 : characterPosition.y) || 0, (characterPosition == null ? void 0 : characterPosition.z) || 0)
1514
+ );
455
1515
  this.composer.render(this.timeManager);
456
- if ((_d = this.tweakPane) == null ? void 0 : _d.guiVisible) {
1516
+ if ((_c = this.tweakPane) == null ? void 0 : _c.guiVisible) {
457
1517
  this.tweakPane.updateStats(this.timeManager);
458
1518
  this.tweakPane.updateCameraData(this.cameraManager);
459
1519
  if (this.characterManager.localCharacter && this.characterManager.localController) {
@@ -469,60 +1529,29 @@ var Networked3dWebExperienceClient = class {
469
1529
  this.update();
470
1530
  });
471
1531
  }
472
- randomWithVariance(value, variance) {
473
- const min = value - variance;
474
- const max = value + variance;
475
- return Math.random() * (max - min) + min;
476
- }
477
- spawnCharacter() {
1532
+ spawnCharacter({
1533
+ spawnPosition,
1534
+ spawnRotation,
1535
+ cameraPosition
1536
+ }) {
478
1537
  if (this.clientId === null) {
479
1538
  throw new Error("Client ID not set");
480
1539
  }
481
- const spawnPosition = new Vector3();
482
- spawnPosition.set(
483
- this.randomWithVariance(
484
- this.spawnConfiguration.spawnPosition.x,
485
- this.spawnConfiguration.spawnPositionVariance.x
486
- ),
487
- this.randomWithVariance(
488
- this.spawnConfiguration.spawnPosition.y,
489
- this.spawnConfiguration.spawnPositionVariance.y
490
- ),
491
- this.randomWithVariance(
492
- this.spawnConfiguration.spawnPosition.z,
493
- this.spawnConfiguration.spawnPositionVariance.z
494
- )
495
- );
496
- const spawnRotation = new Euler(
497
- 0,
498
- -this.spawnConfiguration.spawnYRotation * (Math.PI / 180),
499
- 0
500
- );
501
- let cameraPosition = null;
502
- const offset = new Vector3(0, 0, 3.3);
503
- offset.applyEuler(new Euler(0, spawnRotation.y, 0));
504
- cameraPosition = spawnPosition.clone().sub(offset).add(this.characterManager.headTargetOffset);
505
- if (window.location.hash && window.location.hash.length > 1) {
506
- const urlParams = decodeCharacterAndCamera(window.location.hash.substring(1));
507
- spawnPosition.copy(urlParams.character.position);
508
- spawnRotation.setFromQuaternion(urlParams.character.quaternion);
509
- cameraPosition = urlParams.camera.position;
510
- }
511
1540
  const ownIdentity = this.userProfiles.get(this.clientId);
512
1541
  if (!ownIdentity) {
513
1542
  throw new Error("Own identity not found");
514
1543
  }
515
1544
  this.characterManager.spawnLocalCharacter(
516
1545
  this.clientId,
517
- ownIdentity.username,
1546
+ ownIdentity.username ?? `Unknown User ${this.clientId}`,
518
1547
  ownIdentity.characterDescription,
519
1548
  spawnPosition,
520
1549
  spawnRotation
521
1550
  );
522
1551
  if (cameraPosition !== null) {
523
- this.cameraManager.camera.position.copy(cameraPosition);
1552
+ this.cameraManager.camera.position.set(cameraPosition.x, cameraPosition.y, cameraPosition.z);
524
1553
  this.cameraManager.setTarget(
525
- new Vector3().add(spawnPosition).add(this.characterManager.headTargetOffset)
1554
+ new Vect3().add(spawnPosition).add(CharacterManager.headTargetOffset)
526
1555
  );
527
1556
  this.cameraManager.reverseUpdateFromPositions();
528
1557
  }
@@ -533,24 +1562,24 @@ var Networked3dWebExperienceClient = class {
533
1562
  this.element.append(this.errorScreen.element);
534
1563
  }
535
1564
  dispose() {
536
- var _a, _b, _c, _d;
1565
+ var _a, _b, _c;
1566
+ this.characterManager.dispose();
537
1567
  this.networkClient.stop();
538
- (_a = this.networkChat) == null ? void 0 : _a.stop();
539
1568
  for (const [key, element] of Object.entries(this.mmlFrames)) {
540
1569
  element.remove();
541
1570
  }
542
1571
  this.mmlFrames = {};
543
- (_b = this.textChatUI) == null ? void 0 : _b.dispose();
1572
+ (_a = this.textChatUI) == null ? void 0 : _a.dispose();
544
1573
  this.mmlCompositionScene.dispose();
545
1574
  this.composer.dispose();
546
- (_c = this.tweakPane) == null ? void 0 : _c.dispose();
1575
+ (_b = this.tweakPane) == null ? void 0 : _b.dispose();
547
1576
  if (this.currentRequestAnimationFrame !== null) {
548
1577
  cancelAnimationFrame(this.currentRequestAnimationFrame);
549
1578
  this.currentRequestAnimationFrame = null;
550
1579
  }
551
1580
  this.cameraManager.dispose();
552
1581
  this.loadingScreen.dispose();
553
- (_d = this.errorScreen) == null ? void 0 : _d.dispose();
1582
+ (_c = this.errorScreen) == null ? void 0 : _c.dispose();
554
1583
  }
555
1584
  setupMMLScene() {
556
1585
  registerCustomElementsToWindow(window);