1(() => { 2 'use strict'; 3 // Runtime copy comes from the page's JSON block; the Korean literals stay as the fallback. 4 const BC_I18N = (() => { try { return JSON.parse((document.getElementById('w2-i18n') || document.getElementById('hp-i18n')).textContent); } catch { return {}; } })(); 5 const bcT = (key, fallback) => (typeof BC_I18N[key] === 'string' ? BC_I18N[key] : fallback); 6 const root = document.querySelector('.web2-page'); 7 if (!root) return; 8 const reduced = matchMedia('(prefers-reduced-motion: reduce)'); 9 const clamp = (value, min = 0, max = 1) => Math.max(min, Math.min(max, value)); 10 11 const sculpture = window.BlueCanvasSculpture; 12 document.querySelectorAll('.w2-sculpture,.w2-mini-sculpture').forEach(host=>{ 13 try { sculpture(host); } catch { /* Static artwork remains if GPU access is unavailable. */ } 14 }); 15 16 // One canvas travels from its original hero slot to the discovery system. 17 // Its layout size stays constant during scroll: only the composited wrapper moves. 18 function discoveryJourney() { 19 const host=root.querySelector('.w2-sculpture'); 20 const canvas=host.querySelector('canvas'); 21 const origin=host.querySelector('.w2-sculpture-stage'); 22 const art=root.querySelector('.w2-search-art'); 23 const field=art.querySelector('.w2-discovery-field'); 24 const rows=[...root.querySelectorAll('.w2-search-rows>div')]; 25 const contact=root.querySelector('.w2-cta'); 26 const words=['Be found.','Be the answer.','Be understood.']; 27 const captions=['SEARCH ENGINE<br>OPTIMIZATION','ANSWER ENGINE<br>OPTIMIZATION','GENERATIVE ENGINE<br>OPTIMIZATION']; 28 const sections=[...root.querySelectorAll('main>section')]; 29 const float=document.createElement('div'); 30 float.className='w2-journey'; 31 const badge=document.createElement('div'); 32 badge.className='w2-journey-badge'; 33 badge.innerHTML='<span aria-hidden="true">01 / 03</span><button type="button" aria-label="'+bcT('rotatePause','ìë íì ë©ì¶ê¸°').replace(/"/g,'"')+'" aria-pressed="false">â ¡</button>'; 34 const stop=badge.querySelector('button'); 35 const originalPause=host.querySelector('.w2-sculpture-pause'); 36 const searchPause=stop.cloneNode(true); 37 searchPause.className='w2-discovery-pause'; 38 art.removeAttribute('aria-hidden'); 39 [...art.children].forEach(child=>child.setAttribute('aria-hidden','true')); 40 art.append(searchPause); 41 root.append(float,badge); 42 let attached=false,queued=0,active=-1,manual=null,lastPhase=-1; 43 let width=1,height=1,originX=0,originY=0,fieldX=0,fieldY=0,fieldSize=1,end=0,searchY=0,searchEnd=0; 44 let anchors=[]; 45 const smooth=value=>{const t=clamp(value);return t*t*(3-2*t);}; 46 const mix=(a,b,t)=>a+(b-a)*t; 47 rows.forEach((row,i)=>{ 48 const label=row.querySelector('b'); 49 const button=document.createElement('button'); 50 button.type='button';button.className='w2-discovery-select'; 51 button.textContent=label.textContent; 52 button.setAttribute('aria-label',label.textContent+' '+bcT('visualSuffix','ë¹ì£¼ì¼ 보기')); 53 button.setAttribute('aria-pressed','false'); 54 label.replaceWith(button); 55 button.addEventListener('click',()=>{manual=i;select(i);schedule();}); 56 row.addEventListener('pointerenter',event=>{if(event.pointerType==='mouse'){manual=i;select(i);schedule();}}); 57 }); 58 function select(index) { 59 if(active===index)return; 60 active=index;art.dataset.discovery=String(index); 61 rows.forEach((row,i)=>{ 62 row.classList.toggle('is-active',i===index); 63 row.querySelector('button').setAttribute('aria-pressed',String(i===index)); 64 }); 65 art.querySelector('.w2-discovery-count').textContent='0'+(index+1)+' / 03'; 66 art.querySelector('.w2-discovery-word').textContent=words[index]; 67 art.querySelector('.w2-discovery-caption').innerHTML=captions[index]; 68 } 69 function measure() { 70 const a=origin.getBoundingClientRect(),b=field.getBoundingClientRect(); 71 width=a.width;height=a.height;originX=a.left;originY=a.top+scrollY; 72 fieldX=b.left+b.width/2;fieldY=b.top+scrollY+b.height/2;fieldSize=b.width; 73 const search=art.parentElement.getBoundingClientRect(); 74 searchY=search.top+scrollY;searchEnd=search.bottom+scrollY; 75 end=contact.getBoundingClientRect().top+scrollY; 76 anchors=sections.map(section=>section.getBoundingClientRect().top+scrollY); 77 float.style.width=width+'px';float.style.height=height+'px'; 78 schedule(); 79 } 80 function syncPause() { 81 const paused=originalPause.getAttribute('aria-pressed')==='true'; 82 [stop,searchPause].forEach(button=>{ 83 button.setAttribute('aria-pressed',String(paused));button.textContent=paused?'â·':'â ¡'; 84 button.setAttribute('aria-label',paused?bcT('rotatePlay','ìë íì ììí기'):bcT('rotatePause','ìë íì ë©ì¶ê¸°')); 85 }); 86 art.classList.toggle('is-paused',paused);schedule(); 87 } 88 stop.addEventListener('click',()=>originalPause.click()); 89 searchPause.addEventListener('click',()=>originalPause.click()); 90 new MutationObserver(syncPause).observe(originalPause,{attributes:true,attributeFilter:['aria-pressed']}); 91 function render() { 92 queued=0; 93 const enabled=!reduced.matches&&host.classList.contains('is-ready'); 94 if(enabled&&!attached){float.append(canvas);attached=true;} 95 if(!enabled&&attached){origin.prepend(canvas);attached=false;} 96 float.hidden=!enabled; 97 const y=scrollY,vh=innerHeight,mobile=innerWidth<=600; 98 const fieldTop=fieldY-y-fieldSize/2; 99 const inView=fieldTop<vh&&fieldTop+fieldSize>84; 100 art.classList.toggle('is-inview',inView&&!document.hidden&&enabled); 101 searchPause.hidden=!enabled;
102 const searchProgress=clamp((vh*.78-fieldTop)/Math.max(1,fieldSize+vh*.25)); 103 art.style.setProperty('--discovery-turn',(searchProgress*110).toFixed(2)+'deg'); 104 if(searchY-y>vh||searchEnd-y<84)manual=null; 105 select(manual===null?Math.min(2,Math.floor(searchProgress*3)):manual); 106 if(!enabled){ 107 badge.hidden=true;art.classList.remove('has-journey'); 108 host.dispatchEvent(new CustomEvent('w2-journey',{detail:{active:true,turn:0,material:0}})); 109 return; 110 } 111 const departure=smooth((y-Math.max(0,originY-180))/Math.max(220,height*.85)); 112 const smallHeight=mobile?66:106; 113 const smallScale=smallHeight/height; 114 const edgeX=innerWidth-width*smallScale/2-(mobile?0:3); 115 const edgeY=mobile?135:Math.min(vh*.24,215); 116 let cx=mix(originX+width/2,edgeX,departure); 117 let cy=mix(originY-y+height/2,edgeY,departure); 118 let scale=mix(1,smallScale,departure); 119 // Dock while the field is safely below the header; leave before it scrolls away. 120 const dock=smooth((vh*.94-fieldTop)/Math.max(120,vh*.23)) * smooth((fieldTop+fieldSize*.62-105)/Math.max(100,fieldSize*.28)); 121 cx=mix(cx,fieldX,dock);cy=mix(cy,fieldY-y,dock); 122 scale=mix(scale,fieldSize*.53/height,dock); 123 const fade=1-smooth((y+vh*.65-end)/(vh*.35)); 124 float.style.transform='translate3d('+(cx-width*scale/2).toFixed(2)+'px,'+(cy-height*scale/2).toFixed(2)+'px,0) scale('+scale.toFixed(5)+')'; 125 float.style.opacity=String(fade); 126 float.classList.toggle('is-travelling',departure>.01); 127 canvas.tabIndex=departure>.01?-1:0; 128 if(departure>.01)canvas.setAttribute('aria-hidden','true');else canvas.removeAttribute('aria-hidden'); 129 badge.hidden=departure<.98||dock>.1||fade<.1; 130 badge.style.left=(edgeX-(mobile?30:41))+'px'; 131 badge.style.top=(edgeY+smallHeight/2+3)+'px'; 132 art.classList.toggle('has-journey',dock>.8); 133 let section=0;anchors.forEach((top,i)=>{if(y+vh*.45>=top)section=i;}); 134 const phase=dock>.45?100+active:departure<.05?-1:section; 135 const state={active:fade>.01,turn:y*.00055,material:dock*(active/2)}; 136 if(phase!==lastPhase){ 137 if(phase!==-1)state.shape=dock>.45?active:section%3; 138 lastPhase=phase; 139 } 140 badge.querySelector('span').textContent=String(section+1).padStart(2,'0')+' / '+String(sections.length).padStart(2,'0'); 141 host.dispatchEvent(new CustomEvent('w2-journey',{detail:state})); 142 } 143 function schedule(){if(!queued)queued=requestAnimationFrame(render);} 144 addEventListener('scroll',schedule,{passive:true}); 145 addEventListener('resize',measure,{passive:true}); 146 addEventListener('pageshow',measure); 147 document.addEventListener('visibilitychange',schedule); 148 reduced.addEventListener('change',()=>{lastPhase=-1;measure();}); 149 new MutationObserver(schedule).observe(host,{attributes:true,attributeFilter:['class']}); 150 if('ResizeObserver'in window){const observer=new ResizeObserver(measure);observer.observe(root.querySelector('main'));observer.observe(origin);} 151 if(document.fonts)document.fonts.ready.then(measure); 152 select(0);measure();syncPause(); 153 } 154 discoveryJourney(); 155 156 if ('IntersectionObserver' in window) { 157 const inView = new Set(); 158 const immersive = new IntersectionObserver(entries => { 159 entries.forEach(entry => { if(entry.isIntersecting)inView.add(entry.target);else inView.delete(entry.target); }); 160 root.classList.toggle('w2-in-experiment',inView.size>0); 161 }); 162 document.querySelectorAll('.w2-hero,.w2-showcase,.w2-depth,.w2-playground').forEach(el=>immersive.observe(el)); 163 } 164 165 const depth=document.querySelector('.w2-depth'); 166 const depthStage=depth.querySelector('.w2-depth-sticky'); 167 const captions=[...depth.querySelectorAll('[data-depth-copy]')]; 168 const count=depth.querySelector('.w2-depth-count'); 169 let scrollFrame=0; 170 function updateDepth() { 171 scrollFrame=0; 172 const bounds=depth.getBoundingClientRect(); 173 if(bounds.top>innerHeight||bounds.bottom<0)return; 174 const available=depth.offsetHeight-depthStage.offsetHeight; 175 const p=reduced.matches?.5:clamp((84-bounds.top)/Math.max(1,available)); 176 const open=reduced.matches?0:Math.pow(Math.sin(Math.PI*clamp(p/.88)),.85); 177 const detail=reduced.matches?0:clamp((p-.08)/.16)*(1-clamp((p-.64)/.2)); 178 depthStage.style.setProperty('--depth-detail',detail.toFixed(4)); 179 depthStage.style.setProperty('--depth-resolved',reduced.matches?'1':clamp((p-.84)/.1).toFixed(4)); 180 depthStage.style.setProperty('--depth-flow',(p*-420).toFixed(1)); 181 depthStage.style.setProperty('--depth-open',open.toFixed(4));depthStage.style.setProperty('--depth-progress',p.toFixed(4)); 182 const active=p<.22?0:p<.76?1:2; 183 captions.forEach((item,i)=>{item.classList.toggle('is-active',i===active);item.setAttribute('aria-hidden',String(i!==active));}); 184 count.textContent='0'+(active+1)+' â 03'; 185 } 186 function onScroll(){if(!scrollFrame)scrollFrame=requestAnimationFrame(updateDepth);} 187 addEventListener('scroll',onScroll,{passive:true});addEventListener('resize',onScroll,{passive:true});reduced.addEventListener('change',onScroll);updateDepth(); 188 189 const range=document.querySelector('#w2-width'); 190 const output=document.querySelector('.w2-width-control output'); 191 const liveStage=document.querySelector('.w2-live-stage'); 192 const frame=document.querySelector('.w2-live-frame'); 193 const mini=document.querySelector('.w2-mini-site'); 194 const devices=[...document.querySelectorAll('[data-w2-device]')]; 195 const theme=document.querySelector('.w2-theme-switch'); 196 root.classList.add('w2-play-ready'); 197 function setWidth() { 198 const width=Math.round(320+780*Number(range.value)/100); 199 const zoom=Math.min(1,liveStage.clientWidth/width); 200 frame.style.width=width+'px';frame.style.transform='translateX(-50%) scale('+zoom+')'; 201 liveStage.style.height=Math.ceil(frame.offsetHeight*zoom+64)+'px'; 202 output.value=width+'px';range.setAttribute('aria-valuetext',width+bcT('pixels','í½ì '));
203 devices.forEach(button=>button.setAttribute('aria-pressed',String(Number(button.dataset.w2Device)===Number(range.value)))); 204 mini.querySelector('.w2-mini-sculpture').dispatchEvent(new Event('w2-preview-resize')); 205 } 206 // Brief control cues on first arrival. The preview remains under user control. 207 const playground=document.querySelector('.w2-playground'); 208 const controls=playground.querySelector('.w2-play-controls'); 209 let cueDone=false,cueTimer=0; 210 function clearCue() { 211 clearTimeout(cueTimer);cueTimer=0; 212 controls.classList.remove('is-cueing'); 213 } 214 function dismissCue() { cueDone=true;clearCue(); } 215 controls.addEventListener('pointerdown',dismissCue,{capture:true}); 216 controls.addEventListener('focusin',dismissCue); 217 controls.addEventListener('input',dismissCue,{capture:true}); 218 mini.addEventListener('pointerdown',dismissCue,{capture:true}); 219 if('IntersectionObserver'in window)new IntersectionObserver(entries=>{ 220 if(entries[0].isIntersecting&&!cueDone&&!document.hidden) { 221 cueDone=true;controls.classList.add('is-cueing'); 222 cueTimer=setTimeout(clearCue,3200); 223 } else if(!entries[0].isIntersecting)clearCue(); 224 },{threshold:.9,rootMargin:'-100px 0px -12% 0px'}).observe(controls); 225 reduced.addEventListener('change',clearCue); 226 document.addEventListener('visibilitychange',()=>{if(document.hidden)clearCue();}); 227 range.disabled=false;theme.disabled=false; 228 devices.forEach(button=>{button.disabled=false;button.addEventListener('click',()=>{range.value=button.dataset.w2Device;setWidth();});}); 229 range.addEventListener('input',setWidth); 230 theme.addEventListener('click',()=>{ 231 const dark=mini.classList.toggle('is-dark');theme.setAttribute('aria-pressed',String(dark));theme.innerHTML='<span aria-hidden="true">â</span> '+(dark?bcT('lightTheme','ë¼ì´í¸ í ë§'):bcT('darkTheme','ë¤í¬ í ë§')); 232 mini.querySelector('.w2-mini-sculpture').dispatchEvent(new Event('w2-material-change'));
233 }); 234 if('ResizeObserver'in window){const resize=new ResizeObserver(setWidth);resize.observe(liveStage);resize.observe(frame);}else addEventListener('resize',setWidth,{passive:true}); 235 setWidth(); 236 237 const fine=matchMedia('(hover: hover) and (pointer: fine)'); 238 document.querySelectorAll('.w2-work-image').forEach(card=>{ 239 let pending=0,point=null; 240 card.addEventListener('pointermove',event=>{ 241 if(!fine.matches||reduced.matches)return; 242 point={x:event.clientX,y:event.clientY}; 243 if(pending)return; 244 pending=requestAnimationFrame(()=>{pending=0;const rect=card.getBoundingClientRect();card.style.setProperty('--shine-x',point.x-rect.left+'px');card.style.setProperty('--shine-y',point.y-rect.top+'px');}); 245 },{passive:true}); 246 }); 247})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.