试试问我:学数学对学医有什么用?',
staticAIPlaceholder:'输入问题...',staticMbtiTooltip:'测测你的数学人格'},
en:{home:'Home',discover:'Discover',toolbox:'Toolbox',knowledge:'Cards',story:'HuLu Quest',simulator:'Simulator',favorites:'Favorites',profile:'Profile',search:'Search...',guest:'Guest',
heroTitle:'Hulu Math · Play your way into math',heroSub:'Math isn\'t formulas. It\'s how you make sense of things.',heroCTA:'Start Exploring →',
exploreTitle:'Explore Math',tryTitle:'Try These',
mbtiName:'MathBTI Personality Test',mbtiDesc:'12 questions. One math soul. Meet your sprite. →',
toolboxName:'Math Toolbox',toolboxDesc:'Mental Math · Calculator · Symbol Lookup · Graph →',
storyName:'HuLu Quest',storyDesc:'A Song Dynasty math wuxia · 8 chapters · 8+ endings →',
simName:'Math Life',simDesc:'Live four years as a math major. Choose your path. →',
videoName:'Discover Videos',videoDesc:'12 subject areas',cardName:'Knowledge Cards',cardDesc:'8 math topics',
aiName:'AI Tutor',aiDesc:'Ask anything. No judgment.',
petTip:'Come back daily to earn EXP and level up your sprite.',
dailyFactPrefix:'💡 Math Trivia: ',
discoverGreet:'A hand-picked collection of math videos, curated by volunteers from across the sciences.',
filterAll:'All',noVideo:'No videos yet',noCard:'No cards yet',noResult:'No results',
loadFailVideo:'Couldn\'t load videos',loadFailCard:'Couldn\'t load cards',loadFailProfile:'Couldn\'t load',
loadMore:'Scroll for more…',loadEnd:'— That\'s all of them · ',loadEndSuf:' videos —',
close:'Close',save:'Save',saveOK:'Saved',saveFail:'Couldn\'t save',
toolboxHeader:'Toolbox',toolboxSub:'Get your hands dirty — race the clock, crunch numbers, explore symbols, draw curves',
toolMathrace:'Mental Math',toolMathraceDesc:'60 seconds. How high can you score?',
toolCalc:'Calculator',toolCalcDesc:'Quick arithmetic, powers, trig — whatever you need.',
toolSym:'Symbol Lookup',toolSymDesc:'Tap a symbol to see what it means and how to write it in LaTeX.',
toolGraph:'Function Grapher',toolGraphDesc:'Type any f(x) and watch its curve appear in real time.',
knowledgeHeader:'Knowledge Cards',knowledgeSub:'One idea at a time. Bite-sized math, built for curiosity.',
storyHeader:'HuLu Quest',storySub:'A math-fueled wuxia set in the Song Dynasty. 8 chapters. 8+ endings.',
storyLoadFail:'Couldn\'t load the story',storyNodeNotFound:'Node not found',
simHeader:'Math Major Simulator',simSub:'Four years. Real choices. Multiple endings. What kind of mathematician will you become?',
simLoadFail:'Couldn\'t load the simulator',simReset:'Start fresh',
favHeader:'My Favorites',favSub:'Your saved videos and cards',
favEmpty:'Nothing saved yet',favEmptyHint:'Tap 🤍 on any video or card to save it here.',
profileHeader:'Profile',profileEdit:'Edit Profile',
profileAvatar:'Avatar:',profileNick:'Nickname:',
profileWatchCount:'Videos watched',profileFavCount:'Favorites',
aiHeader:'AI Math Tutor',aiWelcome:'Hey! I\'m your Hulu Math AI tutor 👋
Try asking: "Why do we even need calculus?"',
aiPlaceholder:'Ask anything...',aiOffline:'The AI is taking a quick break. Try again in a moment.',aiNetworkErr:'Looks like you\'re offline. Check your connection and try again.',
calcErr:'That doesn\'t look right',calcPlaceholder:'e.g. 2+3*4',
graphPlaceholder:'e.g. Math.sin(x) or x*x',graphBtn:'Plot',
mrTitle:'Ready?',mrPlaceholder:'Type your answer',mrTimeout:'⏰ Time\'s up! You scored ',mrCorrect:'right',mrRight:'✅ Correct! +10',
symDetail:'👆 Tap any symbol to learn more',
mbtiFloat:'Discover your Math Personality',
aiAskBtn:'Ask AI',aiAskSuffix:'?',
petLevelUp:'Level up! Now Lv.{n}',
staticHeroTitle:'Hulu Math · Play your way into math',staticHeroSub:'Math isn\'t formulas. It\'s how you make sense of things.',staticHeroCTA:'Start Exploring →',
staticExploreTitle:'Explore Math',staticTryTitle:'Try These',
staticDiscoverGreet:'A hand-picked collection of math videos, curated by volunteers from across the sciences.',
staticToolboxTitle:'🧰 Toolbox',staticToolboxSub:'Get your hands dirty — race the clock, crunch numbers, explore symbols, draw curves',
staticToolMathrace:'Mental Math',staticToolMathraceDesc:'60 seconds. How high can you score?',
staticToolCalc:'Calculator',staticToolCalcDesc:'Quick arithmetic, powers, trig — whatever you need.',
staticToolSym:'Symbol Lookup',staticToolSymDesc:'Tap a symbol to see what it means and how to write it in LaTeX.',
staticToolGraph:'Function Grapher',staticToolGraphDesc:'Type any f(x) and watch its curve appear in real time.',
staticKnowledgeTitle:'📚 Knowledge Cards',staticKnowledgeSub:'One idea at a time. Bite-sized math, built for curiosity.',
staticStoryTitle:'⚔️ HuLu Quest',staticStorySub:'A math-fueled wuxia set in the Song Dynasty. 8 chapters. 8+ endings.',
staticSimTitle:'🎮 Math Major Simulator',staticSimSub:'Four years. Real choices. Multiple endings. What kind of mathematician will you become?',
staticFavTitle:'❤️ My Favorites',staticFavSub:'Your saved videos and cards',
staticProfileTitle:'👤 Profile',
staticAIToggleTitle:'AI Math Tutor',staticAIHeader:'💬 AI Math Tutor',
staticAIWelcome:'Hey! I\'m your Hulu Math AI tutor 👋
Try asking: "Why do we even need calculus?"',
staticAIPlaceholder:'Ask anything...',
staticMbtiTooltip:'Discover your Math Personality'}};
function t(k){const d=I18N[_lang];return (d&&d[k])||(I18N.zh[k]||k);}
function rI18n(){
document.querySelectorAll('[data-i18n]').forEach(el=>{
const k=el.getAttribute('data-i18n');
const v=t(k);
if(el.tagName==='INPUT'){el.placeholder=v}
else if(el.hasAttribute('title')&&el.getAttribute('data-i18n-type')==='title'){el.title=v}
else{el.innerHTML=v}
});
}
function switchLang(l){
_lang=l;localStorage.setItem('mb_lang',l);
document.querySelectorAll('.lang-btn').forEach(b=>b.classList.toggle('active',b.dataset.lang===l));
document.getElementById('globalSearch').placeholder=t('search');
rI18n();
navigateTo(CP);
api('/api/user/profile?user_id='+USER_ID).then(r=>{if(r.code===0&&r.data){document.getElementById('sidebarName').textContent=r.data.nickname||t('guest')}}).catch(()=>{});
}
function toggleSidebar(){document.getElementById('sidebar').classList.toggle('open');document.getElementById('sidebarOverlay').classList.toggle('active')}
function closeSidebar(){document.getElementById('sidebar').classList.remove('open');document.getElementById('sidebarOverlay').classList.remove('active')}
let searchTimeout;
function handleGlobalSearch(){
clearTimeout(searchTimeout);
searchTimeout=setTimeout(()=>{
const q=document.getElementById('globalSearch').value.trim().toLowerCase();
const el=document.getElementById('searchResults');
if(!q||q.length<1){el.classList.remove('show');return}
const results=[];
allV.forEach(v=>{if((v.title||'').toLowerCase().includes(q)||(v.author||'').toLowerCase().includes(q)||(v.discipline||'').toLowerCase().includes(q))results.push({t:t('videoTitle')||'Video',title:v.title,id:v.id,type:'video'})});
allK.forEach(k=>{if((k.title||'').toLowerCase().includes(q)||(k.description||'').toLowerCase().includes(q))results.push({t:t('cardLabel')||'Card',title:k.title,id:k.id,type:'knowledge'})});
if(results.length===0){el.innerHTML='
'}
}
const VC_PAGE=12;
let vcList=[],vcCount=0,vcObserver=null;
const UP_COLORS=['#5B6AF0','#818CF8','#F59E0B','#10B981','#EF4444','#8B5CF6','#EC4899','#14B8A6'];
function hashStr(s){let h=0;for(let i=0;i=10000?(n/10000).toFixed(1)+'万':''+n}
function fmtDur(m){m=parseInt(m)||0;return(m<10?'0'+m:''+m)+':00'}
function rVCNP(cid,vids){
const c=document.getElementById(cid);
vcList=vids||[];vcCount=0;c.innerHTML='';
if(!vcList.length){c.innerHTML='
';
}
async function loadKnowledgePage(){
chatCtx={type:'knowledge'};
if(allK.length){rKCFilters();rKCCards();rKP();return}
try{const r=await api('/api/knowledge');if(r.code===0){allK=r.data||[];kT=r.topics||[];rKCFilters();rKCCards()}}catch(e){document.getElementById('knowledgeGrid').innerHTML='
卡片加载失败
'}}
function rKCFilters(){let h='';kT.forEach(t=>{h+=''});document.getElementById('knowledgeFilters').innerHTML=h}
function fKC(t){cT=t;rKCFilters();rKCCards()}
function rKP(){
const bar=document.getElementById('knowledgeDrawProgress');
if(!bar)return;
const readThisSession=(cardState.knowledgeRead||0)%3;
const needMore=3-readThisSession;
bar.style.display='flex';
if(needMore<=0){
document.getElementById('drawProgressText').textContent='🎉 可以抽卡了!点击去抽卡';
document.getElementById('drawProgressFill').style.width='100%';
bar.classList.add('draw-progress-ready');
}else{
document.getElementById('drawProgressText').textContent='再读 '+needMore+' 张知识卡片即可抽卡';
document.getElementById('drawProgressFill').style.width=(readThisSession/3*100)+'%';
bar.classList.remove('draw-progress-ready');
}
}
function rKCCards(){const cards=cT?allK.filter(c=>c.topic===cT):allK;const g=document.getElementById('knowledgeGrid');if(!cards||cards.length===0){g.innerHTML='
'+t('noCard')+'
';return}g.innerHTML=cards.map(c=>'
'+c.icon+'
'+esc(c.question)+'
'+esc(c.title)+'
'+esc(c.description)+'
'+esc(c.read_time)+'
').join('');setTimeout(rKP,100)}
function rDF(){let h='';vD.forEach(d=>{h+=''});document.getElementById('discoverFilters').innerHTML=h}
function fV(d){cD=d;rDF();rVCNP('discoverVideos',d?allV.filter(v=>v.discipline===d):allV)}
function openVideo(id,title,desc,url,author,disc){chatCtx={type:'video',title:title};rH('video',id,title);let h='
'}}catch(e){}document.getElementById('toolModal').classList.add('show')}
function closeToolModal(){var m=document.getElementById('toolModal');if(m)m.classList.remove('show')}
function loadToolbox(){chatCtx={}}
let toolState={};
function openTool(name){
let h='';
if(name==='mathrace'){toolState={score:0,total:0,time:60,timer:null,correct:0};h=rMR()}
else if(name==='calculator')h=rCalc();
else if(name==='symbols')h=rSym();
else if(name==='grapher')h=rGraph();
document.getElementById('toolModalContent').innerHTML=h;
document.getElementById('toolModal').classList.add('show');
if(name==='mathrace')startMRLoop();
if(name==='grapher')setTimeout(plotGraph,200);
}
function rMR(){return'
✅ 0⏱ 60s📝 0
准备好了吗?
'}
function startMRLoop(){toolState={score:0,total:0,time:60,timer:null,correct:0};document.getElementById('mrScore').textContent='0';document.getElementById('mrTime').textContent='60s';document.getElementById('mrTotal').textContent='0';document.getElementById('mrResult').textContent='';document.getElementById('mrAnswer').value='';document.getElementById('mrAnswer').disabled=false;document.getElementById('mrAnswer').focus();genMR();toolState.timer=setInterval(()=>{toolState.time--;document.getElementById('mrTime').textContent=toolState.time+'s';document.getElementById('mrTimer').style.width=(toolState.time/60*100)+'%';if(toolState.time<=0){clearInterval(toolState.timer);document.getElementById('mrAnswer').disabled=true;document.getElementById('mrResult').innerHTML='⏰ 时间到!得分:'+toolState.score+' 正确:'+toolState.correct+'/'+toolState.total;addPetExp(toolState.score)}},1000);genMR()}
function genMR(){const ops=['+','-','×'];const op=ops[Math.floor(Math.random()*3)];let a,b;if(op==='+'){a=Math.floor(Math.random()*90)+10;b=Math.floor(Math.random()*90)+10}else if(op==='-'){a=Math.floor(Math.random()*90)+10;b=Math.floor(Math.random()*a)}else{a=Math.floor(Math.random()*12)+2;b=Math.floor(Math.random()*12)+2}toolState.answer=op==='+'?a+b:op==='-'?a-b:a*b;toolState.total++;document.getElementById('mrTotal').textContent=toolState.total;document.getElementById('mrQuestion').textContent=a+' '+op+' '+b+' = ?';document.getElementById('mrAnswer').value='';document.getElementById('mrAnswer').focus()}
function checkMR(){const ans=parseInt(document.getElementById('mrAnswer').value);if(isNaN(ans))return;if(ans===toolState.answer){toolState.score+=10;toolState.correct++;document.getElementById('mrResult').innerHTML='✅ '+t('mrRight')+''}else{document.getElementById('mrResult').innerHTML='❌ '+toolState.answer+''}document.getElementById('mrScore').textContent=toolState.score;if(toolState.time>0)setTimeout(genMR,600)}
function rCalc(){return'
':'')+'';document.getElementById('storyChoices').innerHTML='';if(tt)clearTimeout(tt);const te=document.getElementById('storyText'),tx=n.scene||'';let i=0;te.textContent='';function ty(){if(i{let h='';if(c.effects){const p=[];if(c.effects.shuli)p.push('数理根基'+(c.effects.shuli>0?'+':'')+c.effects.shuli);if(c.effects.xiayi)p.push('侠义声望'+(c.effects.xiayi>0?'+':'')+c.effects.xiayi);if(c.effects.xinzhi)p.push('心志韧性'+(c.effects.xinzhi>0?'+':'')+c.effects.xinzhi);if(p.length)h='['+p.join(' | ')+']'}return''}).join('')}
function sC(next,ef){aSE(ef);rSN(next)}
function aSE(ef){if(!ef)return;if(ef.shuli)sVN.stats.shuli=(sVN.stats.shuli||10)+ef.shuli;if(ef.xiayi)sVN.stats.xiayi=(sVN.stats.xiayi||10)+ef.xiayi;if(ef.xinzhi)sVN.stats.xinzhi=(sVN.stats.xinzhi||10)+ef.xinzhi;if(ef.favorability){if(!sVN.fav)sVN.fav={};for(const k in ef.favorability)sVN.fav[k]=(sVN.fav[k]||0)+ef.favorability[k]}}
function resetStory(){if(tt)clearTimeout(tt);sVN={currentNode:null,stats:{shuli:10,xiayi:10,xinzhi:10},fav:{}};localStorage.removeItem('mb_story_save');loadStory()}
function dC(ni){if(!ni)return 1;const m=ni.match(/^ch(\d+)/);return m?parseInt(m[1]):1}
async function loadSimulator(){chatCtx={type:'simulator'};try{const r=await api('/api/simulator');if(r.code===0){simD=r.data;try{const sr=await api('/api/simulator/save?user_id='+USER_ID);if(sr.code===0&&sr.data)simS=sr.data}catch(e){}const sn=simD.start_node||'y1_welcome';if(!simS.currentNode||!simD.nodes||!simD.nodes[simS.currentNode])simS.currentNode=sn;rSiN(simS.currentNode)}}catch(e){document.getElementById('simScene').innerHTML='
模拟器加载失败
'}}
function rSiN(ni){if(!simD||!simD.nodes||!simD.nodes[ni]){document.getElementById('simScene').innerHTML='
';document.getElementById('simChoices').innerHTML=(n.choices||[]).map(c=>'').join('')}
function siC(next,ef){if(ef){if(ef.gpa)simS.stats.gpa=Math.max(0,Math.min(4,(simS.stats.gpa||3)+ef.gpa*.1));if(ef.interest)simS.stats.interest=(simS.stats.interest||0)+ef.interest;if(ef.skill)simS.stats.skill=(simS.stats.skill||0)+ef.skill}rSiN(next);addPetExp(5)}
function resetSim(){simS={currentNode:null,stats:{gpa:3,interest:0,skill:0}};loadSimulator()}
async function loadFavorites(){chatCtx={};try{await rFC()}catch(e){}try{const r=await api('/api/favorites?user_id='+USER_ID);const g=document.getElementById('favGrid');if(r.code===0){const f=r.data||[];if(f.length===0){g.innerHTML='