/* HBMIC main v6 for Cafe24 builder: load after #hbMain, Anime.js loaded in */ document.getElementById('hbMain').classList.add('js', matchMedia('(prefers-reduced-motion: reduce)').matches ? 'rm' : 'm'); (function () { 'use strict'; var root = document.getElementById('hbMain'); if (!root) return; var RM = root.classList.contains('rm'); var A = window.anime; if (!A) { root.classList.remove('js'); root.classList.add('rm'); RM = true; } /* ================= language (same rules as hbmic-translation-client.js) ================= */ var LANGS = ['ko', 'en', 'zh-CN', 'ja', 'vi', 'id']; var SHORT = { 'ko': 'KO', 'en': 'EN', 'zh-CN': 'ZH', 'ja': 'JA', 'vi': 'VI', 'id': 'ID' }; function normLang(v) { v = String(v || '').toLowerCase().replace('_', '-'); if (v === 'zh' || v === 'zh-cn') return 'zh-CN'; for (var i = 0; i < LANGS.length; i++) if (LANGS[i].toLowerCase() === v || LANGS[i].toLowerCase() === v.split('-')[0]) return LANGS[i]; return ''; } function pageLang() { try { var u = normLang(new URL(location.href).searchParams.get('lang')); if (u) return u; } catch (e) {} var gm = document.cookie.match(/(?:^|;\s*)googtrans=[^;]*/g), m = gm ? [0, gm[gm.length - 1].replace(/^;?\s*googtrans=/, '')] : null; // last cookie wins, same as hbmic-translation-client.js if (m) { var c = normLang(decodeURIComponent(m[1]).split('/')[2]); if (c) return c; } // first visit: same guess as the client (browser's first preferred locale) var f = String((navigator.languages && navigator.languages[0]) || navigator.language || '').replace('_', '-').toLowerCase().split('-'); var reg = f.length > 1 ? f[f.length - 1].toUpperCase() : ''; if (reg === 'KR' || f[0] === 'ko') return 'ko'; if (reg === 'CN') return 'zh-CN'; if (reg === 'JP' || f[0] === 'ja') return 'ja'; if (reg === 'VN' || f[0] === 'vi') return 'vi'; if (reg === 'ID' || f[0] === 'id') return 'id'; return 'en'; } var LANG = pageLang(); function initLang() { var box = root.querySelector('.hb-lang'); if (!box) return; var btn = box.querySelector('.hb-lang__btn'), list = box.querySelector('.hb-lang__list'), cur = box.querySelector('.hb-lang__cur'); function mark(l) { cur.textContent = SHORT[l] || 'KO'; root.querySelectorAll('.gtranslate_wrapper a[data-gt-lang]').forEach(function (a) { var on = normLang(a.getAttribute('data-gt-lang')) === l; a.classList.toggle('gt-current-lang', on); if (on) a.setAttribute('aria-current', 'true'); else a.removeAttribute('aria-current'); }); } function show(v) { list.hidden = !v; btn.setAttribute('aria-expanded', v ? 'true' : 'false'); } btn.addEventListener('click', function () { show(list.hidden); if (!list.hidden) { var a = list.querySelector('.gt-current-lang') || list.querySelector('a'); a.focus({ preventScroll: true }); } }); // registered before the translation client (it loads with defer), so this runs first window.addEventListener('click', function (e) { var a = e.target && e.target.closest ? e.target.closest('.gtranslate_wrapper a[data-gt-lang]') : null; if (a) { e.preventDefault(); LANG = normLang(a.getAttribute('data-gt-lang')) || 'ko'; mark(LANG); show(false); return; } if (!box.contains(e.target)) show(false); }, true); box.addEventListener('keydown', function (e) { if (e.key === 'Escape' && !list.hidden) { show(false); btn.focus(); } }); mark(LANG); show(false); } initLang(); /* ================= background: temporary pastel / video + WebGL ripple ================= */ var Bg = (function () { var host = root.querySelector('.hb-bg'); var glc = host.querySelector('.hb-bg__gl'); var video = host.querySelector('.hb-bg__video'); var src = document.createElement('canvas'); src.className = 'hb-bg__src'; src.setAttribute('aria-hidden', 'true'); host.insertBefore(src, glc); var ctx = src.getContext('2d'); var mobile = matchMedia('(max-width: 767px)').matches; var useVideo = false; var url = (mobile ? host.dataset.videoMobile : host.dataset.videoPc) || ''; if (url) { video.src = url; video.addEventListener('playing', function () { useVideo = true; host.classList.add('has-video'); }); if (!RM) video.play().catch(function () {}); } // pastel: lavender, sky, light pink, mint (temporary) var BLOBS = [ { c: '205,192,247', x: .62, y: .30, r: .62, sx: .11, sy: .08, p: 41 }, { c: '178,220,248', x: .86, y: .70, r: .70, sx: .09, sy: .10, p: 53 }, { c: '250,205,224', x: .74, y: .92, r: .55, sx: .12, sy: .07, p: 37 }, { c: '190,238,216', x: .95, y: .18, r: .58, sx: .08, sy: .11, p: 47 }, { c: '214,200,250', x: .48, y: .80, r: .50, sx: .10, sy: .09, p: 59 } ]; function draw2D(t) { var w = src.width, h = src.height, m = Math.max(w, h); ctx.fillStyle = '#F4F2FB'; ctx.fillRect(0, 0, w, h); for (var i = 0; i < BLOBS.length; i++) { var b = BLOBS[i], k = t / b.p * Math.PI * 2; var x = (b.x + Math.sin(k) * b.sx) * w, y = (b.y + Math.cos(k * .8) * b.sy) * h, r = b.r * m; var g = ctx.createRadialGradient(x, y, 0, x, y, r); g.addColorStop(0, 'rgba(' + b.c + ',1)'); g.addColorStop(.55, 'rgba(' + b.c + ',.45)'); g.addColorStop(1, 'rgba(' + b.c + ',0)'); ctx.fillStyle = g; ctx.fillRect(0, 0, w, h); } // keep the left 40-45% bright (wider on mobile because text spreads wider) var wash = ctx.createLinearGradient(0, 0, w, 0); if (mobile) { wash.addColorStop(0, 'rgba(255,255,255,.9)'); wash.addColorStop(.6, 'rgba(255,255,255,.62)'); wash.addColorStop(1, 'rgba(255,255,255,.15)'); } else { wash.addColorStop(0, 'rgba(255,255,255,.96)'); wash.addColorStop(.36, 'rgba(255,255,255,.9)'); wash.addColorStop(.6, 'rgba(255,255,255,0)'); } ctx.fillStyle = wash; ctx.fillRect(0, 0, w, h); } // ---- WebGL ---- var gl = null, prog, tex, U = {}, N = 32; var pts = new Float32Array(N * 4), ptI = 0; var mouse = { x: -9999, y: -9999, amt: 0, target: 0, last: 0 }; var VS = 'attribute vec2 p;varying vec2 v;void main(){v=p*.5+.5;gl_Position=vec4(p,0.,1.);}'; var FS = [ 'precision highp float;', 'uniform sampler2D u_tex;uniform vec2 u_res;uniform float u_time;uniform vec4 u_pts[32];uniform vec3 u_mouse;uniform vec2 u_scale;uniform vec2 u_off;', 'varying vec2 v;', 'void main(){', ' vec2 px=v*u_res; vec2 disp=vec2(0.); float shade=0.;', ' for(int i=0;i<32;i++){', ' vec4 q=u_pts[i]; float age=u_time-q.z;', ' if(q.w<=0.||age<0.||age>2.8) continue;', ' vec2 d=px-q.xy; float dist=length(d)+.001;', ' float r=age*240.; float band=exp(-pow((dist-r)/80.,2.));', ' float amp=q.w*exp(-age*1.5)*smoothstep(0.,.18,age);', ' float w=sin((dist-r)*.05)*band*amp;', ' disp+=d/dist*w; shade+=w;', ' }', ' vec2 dm=px-u_mouse.xy; float g=exp(-dot(dm,dm)/(2.*160.*160.))*u_mouse.z;', ' disp+=-dm/160.*g*.55+vec2(sin(px.y*.03+u_time*1.6),cos(px.x*.03+u_time*1.3))*g*.45;', ' vec2 off=disp*15./u_res;', ' vec2 t=u_off+(v+off)*u_scale; vec2 ca=off*.5*u_scale;', ' vec3 col=vec3(texture2D(u_tex,t+ca).r,texture2D(u_tex,t).g,texture2D(u_tex,t-ca).b);', ' col+=shade*.055+g*.025;', ' gl_FragColor=vec4(clamp(col,0.,1.),1.);', '}' ].join('\n'); function sh(type, s) { var o = gl.createShader(type); gl.shaderSource(o, s); gl.compileShader(o); if (!gl.getShaderParameter(o, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(o)); return o; } try { gl = glc.getContext('webgl', { alpha: false, antialias: false, premultipliedAlpha: false, preserveDrawingBuffer: false }); if (!gl) throw new Error('no webgl'); prog = gl.createProgram(); gl.attachShader(prog, sh(gl.VERTEX_SHADER, VS)); gl.attachShader(prog, sh(gl.FRAGMENT_SHADER, FS)); gl.linkProgram(prog); if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) throw new Error('link'); gl.useProgram(prog); var buf = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buf); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW); var loc = gl.getAttribLocation(prog, 'p'); gl.enableVertexAttribArray(loc); gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0); ['u_tex', 'u_res', 'u_time', 'u_pts', 'u_mouse', 'u_scale', 'u_off'].forEach(function (n) { U[n] = gl.getUniformLocation(prog, n); }); tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, tex); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.uniform1i(U.u_tex, 0); } catch (e) { gl = null; host.classList.add('no-gl'); } var dpr = 1, cw = 1, ch = 1, lastVT = -2, isIdle = false; function resize() { var r = host.getBoundingClientRect(); cw = Math.max(1, r.width); ch = Math.max(1, r.height); dpr = Math.min(window.devicePixelRatio || 1, 1.5); glc.width = Math.round(cw * dpr); glc.height = Math.round(ch * dpr); src.width = 420; src.height = Math.max(1, Math.round(420 * ch / cw)); // blurred background, low resolution is enough if (gl) gl.viewport(0, 0, glc.width, glc.height); } function source() { return useVideo && video.readyState >= 2 ? video : src; } function fit(s) { var sw = s.videoWidth || s.width, shh = s.videoHeight || s.height, sa = sw / shh, ca = cw / ch; return sa > ca ? [ca / sa, 1, (1 - ca / sa) / 2, 0] : [1, sa / ca, 0, (1 - sa / ca) / 2]; } function render(now) { var t = now / 1000; if (!useVideo) draw2D(RM ? 0 : t); if (!gl) return; var s = source(); // 11/11 13:20 speed: upload a video frame only when it changed (video 24-30fps, screen 60-144Hz); skip drawing when nothing moves var vid = s === video; // 11/11 13:30 speed: mouse still for 3.2s (no ripple left) -> show the real