44 < meta charset ="UTF-8 ">
55 < meta name ="viewport " content ="width=device-width, initial-scale=1.0, user-scalable=no ">
66 < title > AION.AI · Six Wives · Epistemic Atlas</ title >
7+ <!-- Import map for Three.js -->
8+ < script type ="importmap ">
9+ {
10+ "imports" : {
11+ "three" : "https://unpkg.com/three@0.128.0/build/three.module.js" ,
12+ "three/addons/" : "https://unpkg.com/three@0.128.0/examples/jsm/"
13+ }
14+ }
15+ </ script >
716 < link href ="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,300;14..32,400;14..32,500;14..32,600;14..32,700&display=swap " rel ="stylesheet ">
817 < link rel ="stylesheet " href ="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css ">
918 < script src ="https://cdn.jsdelivr.net/npm/marked/marked.min.js "> </ script >
1019 < script src ="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js "> </ script >
1120 < style >
21+ /* (same styles as before – unchanged) */
1222 * { margin : 0 ; padding : 0 ; box-sizing : border-box; }
1323 : root {
1424 --bg-dark : # 0a0a0f ;
194204 JUSTITIA : { color : '#b0a8b9' , emoji : '⚖️' , name : 'JUSTITIA' , description : 'balanced blue, structured' }
195205 } ;
196206
197- // Helper functions
207+ // Helper functions (unchanged, except where noted)
198208 function scrollBottom ( ) { messagesDiv . scrollTop = messagesDiv . scrollHeight ; }
199209 function escapeHtml ( s ) { return ( s || '' ) . replace ( / & / g, '&' ) . replace ( / < / g, '<' ) . replace ( / > / g, '>' ) ; }
200210 function renderMarkdown ( text ) {
220230 return [ ppi , ratio ] . filter ( Boolean ) . join ( ' · ' ) ;
221231 }
222232
223- // Enhanced multi-wife parser – supports:
224- // **ALBEDO:** content
225- // **[ALBEDO]:** content
226- // ---\n\nALBEDO: content
233+ // Multi-wife parser (unchanged)
227234 function parseMultiWifeResponse ( text ) {
228235 const blocks = [ ] ;
229236 const lines = text . split ( '\n' ) ;
232239 const markerRegex = / ^ ( \* \* ( [ A - Z _ ] + ) : | ^ \* \* \[ ( [ A - Z _ ] + ) \] ) : | ^ - - - \n \n ( [ A - Z _ ] + ) : / i;
233240 for ( let i = 0 ; i < lines . length ; i ++ ) {
234241 let line = lines [ i ] ;
235- // Special case: detect a marker that spans two lines (---\n\nNAME:)
236242 if ( line . trim ( ) === '---' && i + 1 < lines . length && lines [ i + 1 ] . trim ( ) . match ( / ^ ( [ A - Z _ ] + ) : / i) ) {
237243 const name = lines [ i + 1 ] . trim ( ) . match ( / ^ ( [ A - Z _ ] + ) : / i) [ 1 ] ;
238244 if ( currentWife && currentContent . length ) {
239245 blocks . push ( { wife : currentWife , content : currentContent . join ( '\n' ) . trim ( ) } ) ;
240246 }
241247 currentWife = name . toUpperCase ( ) ;
242248 currentContent = [ ] ;
243- i ++ ; // skip the next line
249+ i ++ ;
244250 continue ;
245251 }
246252 const match = line . match ( markerRegex ) ;
254260 if ( contentAfterMarker ) currentContent . push ( contentAfterMarker ) ;
255261 } else {
256262 if ( currentWife !== null ) currentContent . push ( line ) ;
257- // else ignore preamble before first marker
258263 }
259264 }
260265 if ( currentWife && currentContent . length ) {
263268 return blocks . length ? blocks : null ;
264269 }
265270
266- // Render a single assistant message (may contain multiple wives)
267271 function renderAssistantResponse ( rawText , extra ) {
268272 const blocks = parseMultiWifeResponse ( rawText ) ;
269273 if ( ! blocks ) {
270- // Fallback: single voice
271274 addMessage ( 'assistant' , extra . active_wife || 'ALBEDO' , rawText , extra ) ;
272275 return ;
273276 }
274- // Render each block in order
275277 for ( const block of blocks ) {
276278 const wife = WIFE_STYLES [ block . wife ] ? block . wife : 'ALBEDO' ;
277279 addMessage ( 'assistant' , wife , block . content , extra ) ;
351353 document . getElementById ( 'statusDot' ) . style . color = isError ? '#ff5e5e' : '#4c9f70' ;
352354 }
353355
354- // Crypto helpers (kept for structured mode )
356+ // Crypto helpers (unchanged )
355357 async function computeHash ( obj ) {
356358 const encoder = new TextEncoder ( ) ;
357359 const data = encoder . encode ( JSON . stringify ( obj ) ) ;
365367 return Array . from ( new Uint8Array ( sig ) ) . map ( b => b . toString ( 16 ) . padStart ( 2 , '0' ) ) . join ( '' ) ;
366368 }
367369
368- // Session persistence
370+ // Session persistence (unchanged)
369371 function loadSessionFromStorage ( ) {
370372 const stored = localStorage . getItem ( 'aion_session' ) ;
371373 if ( stored ) {
444446 }
445447 }
446448
447- // Send a message to a specific wife using /talk command (sets exclusive mode)
448449 async function sendToWife ( wife , text ) {
449450 const msgText = `/talk ${ wife } \n${ text } ` ;
450451 const resp = await fetchWithTimeout ( `${ API_BASE } /api/assistant` , {
461462 return resp . json ( ) ;
462463 }
463464
464- // Ask all wives (parallel)
465465 async function askAllWives ( ) {
466466 const text = input . value . trim ( ) ;
467467 if ( ! text ) return ;
510510 }
511511 }
512512
513- // Regular chat (single wife)
514513 async function sendRegularChat ( message ) {
515514 const resp = await fetchWithTimeout ( `${ API_BASE } /api/assistant` , {
516515 method : 'POST' ,
627626 fileInput . click ( ) ;
628627 } ;
629628
630- // Ask All Wives
631629 askAllBtn . onclick = askAllWives ;
632630
633- // Settings modal
631+ // Settings modal (unchanged)
634632 function showSettingsModal ( ) {
635633 const modal = document . createElement ( 'div' ) ;
636634 modal . className = 'modal-overlay' ;
@@ -691,7 +689,7 @@ <h3>⚙️ Settings</h3>
691689 }
692690 settingsBtn . onclick = showSettingsModal ;
693691
694- // Private room modal (reuse )
692+ // Private room modal (unchanged )
695693 function showPrivateRoomModal ( ) {
696694 const modal = document . createElement ( 'div' ) ;
697695 modal . className = 'modal-overlay' ;
@@ -722,15 +720,15 @@ <h3>⚙️ Settings</h3>
722720 }
723721 privateRoomBtn . onclick = showPrivateRoomModal ;
724722
725- // FCL mode toggle
723+ // FCL mode toggle (unchanged)
726724 fclToggleBtn . onclick = ( ) => {
727725 fclMode = fclMode === 'GREEN' ? 'BLACK' : 'GREEN' ;
728726 fclToggleBtn . textContent = fclMode === 'GREEN' ? '⚡ FCL: GREEN' : '⚡ FCL: BLACK' ;
729727 fclToggleBtn . className = `fcl-toggle ${ fclMode === 'GREEN' ? 'green' : 'black' } ` ;
730728 addSystemMessage ( `🔄 FCL mode switched to ${ fclMode } ALERT.` ) ;
731729 } ;
732730
733- // Brain Analytics modal (simplified )
731+ // Brain Analytics modal (unchanged )
734732 let analyticsModal = null ;
735733 async function showAnalytics ( ) {
736734 setStatus ( 'Loading analytics...' , false ) ;
@@ -771,7 +769,7 @@ <h3>📊 Brain Analytics</h3>
771769 }
772770 analyticsBtn . onclick = showAnalytics ;
773771
774- // Epistemic Atlas – lazy load with error handling (kept)
772+ // Epistemic Atlas – corrected with import map and dynamic imports
775773 let atlasModal = null ;
776774 async function loadEpistemicAtlas ( ) {
777775 if ( atlasLoaded ) return ;
@@ -782,10 +780,9 @@ <h3>📊 Brain Analytics</h3>
782780 atlasLoaded = true ;
783781 setStatus ( 'Loading constellation...' , false ) ;
784782 try {
785- await import ( 'https://unpkg.com/three@0.128.0/build/three.module.js' ) ;
786- await import ( 'https://unpkg.com/three@0.128.0/examples/jsm/controls/OrbitControls.js' ) ;
787- const { default : THREE } = await import ( 'https://unpkg.com/three@0.128.0/build/three.module.js' ) ;
788- const { OrbitControls } = await import ( 'https://unpkg.com/three@0.128.0/examples/jsm/controls/OrbitControls.js' ) ;
783+ // Using import map, we can now import the modules
784+ const THREE = await import ( 'three' ) ;
785+ const { OrbitControls } = await import ( 'three/addons/controls/OrbitControls.js' ) ;
789786
790787 const resp = await fetch ( `${ API_BASE } /api/epistemic-atlas?sessionId=${ sessionId } ` ) ;
791788 if ( ! resp . ok ) throw new Error ( `HTTP ${ resp . status } ` ) ;
@@ -891,7 +888,7 @@ <h3>📊 Brain Analytics</h3>
891888 }
892889 constellationBtn . onclick = loadEpistemicAtlas ;
893890
894- // Particles background
891+ // Particles background (unchanged)
895892 function initParticles ( ) {
896893 const canvas = document . getElementById ( 'particles' ) ;
897894 const ctx = canvas . getContext ( '2d' ) ;
0 commit comments