GLM 5.1 テスト

Reddit r/LocalLLaMA / 2026/4/8

💬 オピニオンDeveloper Stack & InfrastructureSignals & Early TrendsTools & Practical UsageModels & Research

要点

  • 著者は、HGX H200上でsglangコンテナを使用してZAIからGLM 5.1をデプロイした個人的なテストについて共有している。テンソル並列化と推測(スペキュレイティブ)デコーディングの設定(EAGLE、num draft stepsなど)も構成されている。
  • モデルの出力に感銘を受けたと述べる一方で、通常よりかなり長い時間「考えて」(約7分)おり、自己チェックを繰り返していた点に言及している。
  • この投稿には、スクランブルしてから滑らかで現実的な層回転とアニメーションによって自分自身で解く、単一ファイルでライブラリ不要のHTML/CSS/バニラJSによるルービックキューブを作成することを求める詳細なコーディングプロンプトが含まれている。
  • さらに、追加メディア(動画や画像)の処理例にも触れており、最初に興味を引かれたきっかけとなったInstagram投稿へのリンクも掲載されている。

動画を処理しています 4w0egf932ytg1...

こんにちは皆さん。ZAIのGLM 5.1を試したテストを共有したかったんだ

このコマンドで社内のHGX H200にデプロイしました

docker run -d \ --name name \ --restart unless-stopped \ --gpus all \ --shm-size 32g \ --ipc=host \ -v ... \ -p 1984:30000 \ lmsysorg/sglang:dev \ sglang serve \ --model-path /model \ --host 0.0.0.0 \ --port 30000 \ --tp 8 \ --reasoning-parser glm45 \ --tool-call-parser glm47 \ --speculative-algorithm EAGLE \ --speculative-num-steps 3 \ --speculative-eagle-topk 1 \ --speculative-num-draft-tokens 4 \ --mem-fraction-static 0.85 \ --served-model-name name \ --enable-metrics 

https://www.instagram.com/p/DWEcde4ESI_/

このプロンプト付きのクソしょうもないインスタ投稿をたまたま見て、気になったんだ。言えるのは、感心したってこと。だけどモードは7分間考え続けてた笑。何度も自分に確認してた

画像を処理しています yual7fn02ytg1...

画像を処理しています i3gr9by02ytg1...

プロンプト

ライブラリを一切使わずに、HTML・CSS・バニラJavaScriptのみで1つのHTMLファイルを作成してください(ライブラリなし)。27個の小さなキュービーからなる、完全に機能するルービックキューブを含む、中央配置の3Dシーンを構築してください。各キュービーは、正しく色付けされた面を持つ必要があります(クラシックなキューブの色)。キューブは以下を満たすべきです: - 少しだけ3Dのパース(遠近)を感じるアイドル状態で開始する - シーンの下に「Start」ボタンを含める - クリックされたら、ランダムな現実的な面回転で自動的にキューブをスクランブルする - その後、逆手順のムーブまたは論理的な手順で、ステップごとに自分自身を解く - 各ムーブは、なめらかなイージングでアニメーションする(瞬間的なジャンプなし) - 回転は実際のキューブの物理のように、正しいレイヤーにのみ影響する アニメーション要件: - ループの合計持続時間:約30秒 - フェーズを含める:スクランブル → 解く → 短いポーズ → 繰り返しを無限に - なめらかな cubic-bezier または ease-in-out のトランジションを使う 見た目のスタイル: - 暗い背景(黒またはグラデーション) - 発光するキューブの面、微かな反射 - 軟らかい影と奥行きでリアリティを出す - ホバーアニメーション付きの、クリーンでモダンなUIのボタン 追加機能: - マウスドラッグでキューブ全体をリアルタイムに回転できるようにする - トランスフォームの整合性を維持する(キューブ構造が崩れない) - アニメーションがなめらかで最適化されていることを保証する 出力: - 完全に動作するコードを、1つのHTMLファイルだけで返す - 説明は不要、コードのみ 

生成されたコード

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Rubik's Cube</title> <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600;700&display=swap" rel="stylesheet"> <style> *{margin:0;padding:0;box-sizing:border-box} body{ background: radial-gradient(ellipse at 30% 20%,rgba(18,22,55,0.5) 0%,transparent 55%), radial-gradient(ellipse at 70% 80%,rgba(55,12,28,0.3) 0%,transparent 55%), #030308; min-height:100vh; display:flex;flex-direction:column;align-items:center;justify-content:center; font-family:'Space Grotesk',sans-serif; overflow:hidden;user-select:none;-webkit-user-select:none; } #scene{ width:440px;height:440px; perspective:880px;perspective-origin:50% 48%; display:flex;align-items:center;justify-content:center; position:relative; } #scene::after{ content:'';position:absolute;bottom:12%;left:50%;transform:translateX(-50%); width:200px;height:30px; background:radial-gradient(ellipse,rgba(140,160,255,0.07) 0%,transparent 70%); border-radius:50%;pointer-events:none;filter:blur(8px); } #cube-container{ transform-style:preserve-3d;position:relative;cursor:grab; } #cube-container:active{cursor:grabbing} .cubie{ position:absolute;left:0;top:0;width:0;height:0; transform-style:preserve-3d; } .face{ position:absolute; width:60px;height:60px;left:-30px;top:-30px; border-radius:5px; backface-visibility:hidden; overflow:hidden; } .face::after{ content:'';position:absolute;inset:0;border-radius:inherit; background:linear-gradient(135deg,rgba(255,255,255,0.28) 0%,rgba(255,255,255,0.06) 30%,transparent 52%,rgba(0,0,0,0.13) 100%); pointer-events:none; } .face.front{transform:translateZ(33px)} .face.back{transform:rotateY(180deg) translateZ(33px)} .face.right{transform:rotateY(90deg) translateZ(33px)} .face.left{transform:rotateY(-90deg) translateZ(33px)} .face.top{transform:rotateX(90deg) translateZ(33px)} .face.bottom{transform:rotateX(-90deg) translateZ(33px)} .face-outer{ box-shadow:inset 0 0 10px rgba(255,255,255,0.06); border:1px solid rgba(255,255,255,0.08); } #status{ margin-top:28px;color:rgba(255,255,255,0.35); font-size:12px;letter-spacing:4px;text-transform:uppercase; min-height:20px;transition:color 0.5s ease;font-weight:600; } #start-btn{ margin-top:14px;padding:14px 52px; font-size:14px;font-weight:700;letter-spacing:4px; color:#fff;background:linear-gradient(135deg,#e94560,#c62a4a); border:none;border-radius:50px;cursor:pointer; transition:all 0.35s cubic-bezier(0.4,0,0.2,1); box-shadow:0 4px 24px rgba(233,69,96,0.3); font-family:'Space Grotesk',sans-serif; position:relative;overflow:hidden; } #start-btn::before{ content:'';position:absolute;top:0;left:-100%; width:100%;height:100%; background:linear-gradient(90deg,transparent,rgba(255,255,255,0.15),transparent); transition:left 0.55s ease; } #start-btn:hover::before{left:100%} #start-btn:hover{ transform:translateY(-3px); box-shadow:0 8px 32px rgba(233,69,96,0.45); background:linear-gradient(135deg,#f05a73,#d63350); } #start-btn:active{transform:translateY(1px);box-shadow:0 2px 12px rgba(233,69,96,0.25)} #start-btn:disabled{ background:linear-gradient(135deg,#2a2a35,#1e1e28); box-shadow:0 2px 10px rgba(0,0,0,0.3);cursor:default; color:rgba(255,255,255,0.25); } #start-btn:disabled:hover{transform:none;box-shadow:0 2px 10px rgba(0,0,0,0.3)} #start-btn:disabled::before{display:none} pulse{0%,100%{opacity:0.35}50%{opacity:0.7}} #status.active{animation:pulse 1.8s ease-in-out infinite} </style> </head> <body> <div id="scene"><div id="cube-container"></div></div> <div id="status">ドラッグして回転</div> <button id="start-btn">START</button> <script> /* ========== 行列ユーティリティ ========== */ function mat3Mul(a,b){ const r=[[0,0,0],[0,0,0],[0,0,0]]; for(let i=0;i<3;i++)for(let j=0;j<3;j++)for(let k=0;k<3;k++)r[i][j]+=a[i][k]*b[k][j]; return r; } function mat3Css(m){ return `matrix3d(${m[0][0]},${m[1][0]},${m[2][0]},0,${m[0][1]},${m[1][1]},${m[2][1]},0,${m[0][2]},${m[1][2]},${m[2][2]},0,0,0,0,0,1)`; } function rotMat(axis,deg){ const a=deg*Math.PI/180,c=Math.cos(a),s=Math.sin(a); if(axis==='x')return[[1,0,0],[0,c,-s],[0,s,c]]; if(axis==='y')return[[c,0,s],[0,1,0],[-s,0,c]]; return[[c,-s,0],[s,c,0],[0,0,1]]; } function mat3Vec(m,v){ return{x:m[0][0]*v.x+m[0][1]*v.y+m[0][2]*v.z,y:m[1][0]*v.x+m[1][1]*v.y+m[1][2]*v.z,z:m[2][0]*v.x+m[2][1]*v.y+m[2][2]*v.z}; } function roundMat(m){return m.map(r=>r.map(v=>Math.round(v)))} /* ========== イージング ========== */ function easeIO(t){return t<0.5?4*t*t*t:1-Math.pow(-2*t+2,3)/2} /* ========== 定数 ========== */ const SP=70; // 各キュービー中心間の間隔 const CH=33; // キュービー半サイズ(面のtranslateZ) const COLORS={ right:'#b71234',left:'#ff5800',top:'#ffffff', bottom:'#ffd500',front:'#009b48',back:'#0046ad',inner:'#0e0e0e' }; /* ムーブ定義 — CSSのYダウン座標系 */ const MOVES={ R :{axis:'x',layer:1, angle:90}, Ri:{axis:'x',layer:1, angle:-90}, L :{axis:'x',layer:-1,angle:-90}, Li:{axis:'x',layer:-1,angle:90}, U :{axis:'y',layer:-1,angle:90}, Ui:{axis:'y',layer:-1,angle:-90}, D :{axis:'y 

返却形式: {"translated": "翻訳されたHTML"}',layer:1, angle:-90}, Di:{axis:'y',layer:1, angle:90}, F :{axis:'z',layer:1, angle:90}, Fi:{axis:'z',layer:1, angle:-90}, B :{axis:'z',layer:-1,angle:-90}, Bi:{axis:'z',layer:-1,angle:90}, }; const MKEYS=Object.keys(MOVES); function inv(n){return n.endsWith('i')?n.slice(0,-1):n+'i'} /* ========== キューブ状態 ========== */ const container=document.getElementById('cube-container'); const cubies=[]; const I3=[[1,0,0],[0,1,0],[0,0,1]]; function buildCube(){ for(let x=-1;x<=1;x++)for(let y=-1;y<=1;y++)for(let z=-1;z<=1;z++){ const cb={op:{x,y,z},m:JSON.parse(JSON.stringify(I3)),el:null}; const el=document.createElement('div');el.className='cubie'; const fc=[ {n:'front', c:z===1?COLORS.front:null}, {n:'back', c:z===-1?COLORS.back:null}, {n:'right', c:x===1?COLORS.right:null}, {n:'left', c:x===-1?COLORS.left:null}, {n:'top', c:y===-1?COLORS.top:null}, {n:'bottom',c:y===1?COLORS.bottom:null}, ]; fc.forEach(f=>{ const d=document.createElement('div'); d.className='face '+f.n; if(f.c){d.style.backgroundColor=f.c;d.classList.add('face-outer')} else{d.style.backgroundColor=COLORS.inner} el.appendChild(d); }); cb.el=el;container.appendChild(el); setTrans(cb); cubies.push(cb); } } function curPos(cb){ const p=mat3Vec(cb.m,cb.op); return{x:Math.round(p.x),y:Math.round(p.y),z:Math.round(p.z)}; } function transStr(cb){ return mat3Css(cb.m)+` translate3d(${cb.op.x*SP}px,${cb.op.y*SP}px,${cb.op.z*SP}px)`; } function setTrans(cb){cb.el.style.transform=transStr(cb)} /* ========== 移動アニメーション ========== */ async function doMove(name,dur=480){ const d=MOVES[name],{axis,layer,angle}=d; const axU=axis.toUpperCase(); const aff=cubies.filter(c=>curPos(c)[axis]===layer); aff.forEach(c=>{c._b=transStr(c)}); const t0=performance.now(); await new Promise(res=>{ function tick(now){ const p=Math.min((now-t0)/dur,1),e=easeIO(p),a=angle*e; aff.forEach(c=>{c.el.style.transform=`rotate${axU}(${a}deg) ${c._b}`}); if(p<1)requestAnimationFrame(tick); else{ const rm=rotMat(axis,angle); aff.forEach(c=>{c.m=roundMat(mat3Mul(rm,c.m));setTrans(c)}); res(); } } requestAnimationFrame(tick); }); } /* ========== スクランブル&解法 ========== */ let hist=[]; async function scramble(n=22){ hist=[];let last=''; for(let i=0;i<n;i++){ let mv,att=0; do{mv=MKEYS[Math.floor(Math.random()*MKEYS.length)];att++} while((mv===last||mv===inv(last))&&att<30); hist.push(mv);last=mv; await doMove(mv,420); } } async function solve(){ const rev=[...hist].reverse().map(inv); for(const mv of rev)await doMove(mv,420); hist=[]; } function delay(ms){return new Promise(r=>setTimeout(r,ms))} /* ========== マウス / タッチのドラッグ ========== */ let rx=-28,ry=38,drag=false,lx,ly; const scene=document.getElementById('scene'); function updCont(){container.style.transform=`rotateX(${rx}deg) rotateY(${ry}deg)`} scene.addEventListener('mousedown',e=>{drag=true;lx=e.clientX;ly=e.clientY}); window.addEventListener('mousemove',e=>{ if(!drag)return; ry+=(e.clientX-lx)*0.45;rx-=(e.clientY-ly)*0.45; rx=Math.max(-89,Math.min(89,rx));lx=e.clientX;ly=e.clientY;updCont(); }); window.addEventListener('mouseup',()=>{drag=false}); scene.addEventListener('touchstart',e=>{drag=true;lx=e.touches[0].clientX;ly=e.touches[0].clientY},{passive:true}); window.addEventListener('touchmove',e=>{ if(!drag)return;e.preventDefault(); const t=e.touches[0]; ry+=(t.clientX-lx)*0.45;rx-=(t.clientY-ly)*0.45; rx=Math.max(-89,Math.min(89,rx));lx=t.clientX;ly=t.clientY;updCont(); },{passive:false}); window.addEventListener('touchend',()=>{drag=false}); /* ========== 停止時の自動回転 ========== */ let idle=true; function idleTick(){ if(!idle)return; ry+=0.1;updCont();requestAnimationFrame(idleTick); } /* ========== 状態表示&ボタン ========== */ const statusEl=document.getElementById('status'); const btn=document.getElementById('start-btn'); let started=false; btn.addEventListener('click',()=>{ if(started)return;started=true;idle=false; btn.disabled=true; runLoop(); }); async function runLoop(){ while(true){ statusEl.textContent='SCRAMBLING';statusEl.style.color='rgba(233,69,96,0.7)'; statusEl.classList.add('active'); await scramble(22); statusEl.textContent='ANALYZING';statusEl.style.color='rgba(0,155,72,0.6)'; await delay(1400); statusEl.textContent='SOLVING';statusEl.style.color='rgba(0,200,83,0.7)'; await solve(); statusEl.textContent='SOLVED';statusEl.style.color='rgba(255,213,0,0.75)'; statusEl.classList.remove('active'); await delay(2800); statusEl.classList.add('active'); } } /* ========== 初期化 ========== */ buildCube(); updCont(); idleTick(); </script> </body> </html>みなさん。ZAIDさんのGLM 5.1をテストしたので共有したかったんだ。会社のHGX H200に、このコマンドでデプロイしました:docker run -d 
 --name name 
 --restart unless-stopped 
 --gpus all 
 --shm-size 32g 
 --ipc=host 
 -v ... 
 -p 1984:30000 
 lmsysorg/sglang:dev 
 sglang serve 
 --model-path /model 
 --host 0.0.0.0 
 --port 30000 
 --tp 8 
 --reasoning-parser glm45 
 --tool-call-parser glm47 
 --speculative-algorithm EAGLE 
 --speculative-num-steps 3 
 --speculative-eagle-topk 1 
 --speculative-num-draft-tokens 4 
 --mem-fraction-static 0.85 
 --served-model-name name 
 --enable-metricshttps://www.instagram.com/p/DWEcde4ESI_/さっき、このプロンプト付きのくだらないインスタ投稿を見かけて、気になった。って言える。感動したよ。ただ、モードは7分間考えてた(笑)、何度も自分に言い聞かせて落ち着かせてた。プロンプト1つのHTMLファイルを、HTML・CSS・バニラJavaScriptのみ(ライブラリなし)で作成してください。27個の小さなキュービーで構成された、完全に機能するルービックキューブを中心に配置された3Dシーンとして構築してください。各キュービーは正しく着色された面(定番のキューブカラー)を持たなければなりません。キューブは次の要件を満たす必要があります:- 少しだけ3Dの遠近感がある状態で、最初はアイドル表示にする - シーンの下に「Start」ボタンを含める - クリックされたら、ランダムな現実的な面回転で自動的にスクランブルする - 次に、逆手順のムーブや論理的なシーケンスを使って、自分自身で段階的に解く - 各ムーブは滑らかにアニメーションし(瞬間移動しない) - 回転は正しいレイヤーにのみ影響する(実際のキューブ物理のように)アニメーション要件:- 総ループ時間:約30秒 - フェーズを含める:scramble → solve → 短いポーズ → それを無限に繰り返す - なめらかな cubic-bezier または ease-in-out のトランジションを使用するデザインスタイル:- 暗い背景(黒またはグラデーション) - 光るキューブの面(微妙な反射付き) - 柔らかな影と奥行きでリアリティを出す - すっきりしたモダンなUIのボタン(ホバーアニメーション付き)追加機能:- マウスドラッグでキューブ全体をリアルタイムに回転できるようにする - トランスフォームの整合性を維持する(キューブ構造が壊れない) - アニメーションを滑らかにし、最適化すること出力:- 完全に動作するコードを、1つのHTMLファイルのみで返す - 説明は不要で、コードのみ提供Generated code<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ルービックキューブ</title> <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600;700&display=swap" rel="stylesheet"> <style> *{margin:0;padding:0;box-sizing:border-box} body{ background: radial-gradient(ellipse at 30% 20%,rgba(18,22,55,0.5) 0%,transparent 55%), radial-gradient(ellipse at 70% 80%,rgba(55,12,28,0.3) 0%,transparent 55%), #030308; min-height:100vh; display:flex;flex-direction:column;align-items:center;justify-content:center; font-family:'Space Grotesk',sans-serif; overflow:hidden;user-select:none;-webkit-user-select:none; } #scene{ width:440px;height:440px; perspective:880px;perspective-origin:50% 48%; display:flex;align-items:center;justify-content:center; position:relative; } #scene::after{ content:'';position:absolute;bottom:12%;left:50%;transform:translateX(-50%); width:200px;height:30px; background:radial-gradient(ellipse,rgba(140,160,255,0.07) 0%,transparent 70%); border-radius:50%;pointer-events:none;filter:blur(8px); } #cube-container{ transform-style:preserve-3d;position:relative;cursor:grab; } #cube-container:active{cursor:grabbing} .cubie{ position:absolute;left:0;top:0;width:0;height:0; transform-style:preserve-3d; } .face{ position:absolute; width:60px;height:60px;left:-30px;top:-30px; border-radius:5px; backface-visibility:hidden; overflow:hidden; } .face::after{ content:'';position:absolute;inset:0;border-radius:inherit; background:linear-gradient(135deg,rgba(255,255,255,0.28) 0%,rgba(255,255,255,0.06) 30%,transparent 52%,rgba(0,0,0,0.13) 100%); pointer-events:none; } .face.front{transform:translateZ(33px)} .face.back{transform:rotateY(180deg) translateZ(33px)} .face.right{transform:rotateY(90deg) translateZ(33px)} .face.left{transform:rotateY(-90deg) translateZ(33px)} .face.top{transform:rotateX(90deg) translateZ(33px)} .face.bottom{transform:rotateX(-90deg) translateZ(33px)} .face-outer{ box-shadow:inset 0 0 10px rgba(255,255,255,0.06); border:1px solid rgba(255,255,255,0.08); } #status{ margin-top:28px;color:rgba(255,255,255,0.35); font-size:12px;letter-spacing:4px;text-transform:uppercase; min-height:20px;transition:color 0.5s ease;font-weight:600; } #start-btn{ margin-top:14px;padding:14px 52px; font-size:14px;font-weight:700;letter-spacing:4px; color:#fff;background:linear-gradient(135deg,#e94560,#c62a4a); border:none;border-radius:50px;cursor:pointer; transition:all 0.35s cubic-bezier(0.4,0,0.2,1); box-shadow:0 4px 24px rgba(233,69,96,0.3); font-family:'Space Grotesk',sans-serif; position:relative;overflow:hidden; } #start-btn::before{ content:'';position:absolute;top:0;left:-100%; width:100%;height:100%; background:linear-gradient(90deg,transparent,rgba(255,255,255,0.15),transparent); transition:left 0.55s ease; } #start-btn:hover::before{left:100%} #start-btn:hover{ transform:translateY(-3px); box-shadow:0 8px 32px rgba(233,69,96,0.45); background:linear-gradient(135deg,#f05a73,#d63350); } #start-btn:active{transform:translateY(1px);box-shadow:0 2px 12px rgba(233,69,96,0.25)} #start-btn:disabled{ background:linear-gradient(135deg,#2a2a35,#1e1e28); box-shadow:0 2px 10px rgba(0,0,0,0.3);cursor:default; color:rgba(255,255,255,0.25); } #start-btn:disabled:hover{transform:none;box-shadow:0 2px 10px rgba(0,0,0,0.3)} #start-btn:disabled::before{display:none} pulse{0%,100%{opacity:0.35}50%{opacity:0.7}} #status.active{animation:pulse 1.8s ease-in-out infinite} </style> </head> <body> <div id="scene"><div id="cube-container"></div></div> <div id="status">ドラッグして回転</div> <button id="start-btn">スタート</button> <script> /* ========== 行列ユーティリティ ========== */ function mat3Mul(a,b){ const r=[[0,0,0],[0,0,0],[0,0,0]]; for(let i=0;i<3;i++)for(let j=0;j<3;j++)for(let k=0;k<3;k++)r[i][j]+=a[i][k]*b[k][j]; return r; } function mat3Css(m){ return `matrix3d(${m[0][0]},${m[1][0]},${m[2][0]},0,${m[0][1]},${m[1][1]},${m[2][1]},0,${m[0][2]},${m[1][2]},${m[2][2]},0,0,0,0,1)`; } function rotMat(axis,deg){ const a=deg*Math.PI/180,c=Math.cos(a),s=Math.sin(a); if(axis==='x')return[[1,0,0],[0,c,-s],[0,s,c]]; if(axis==='y')return[[c,0,s],[0,1,0],[-s,0,c]]; return[[c,-s,0],[s,c,0],[0,0,1]]; } function mat3Vec(m,v){ return{x:m[0][0]*v.x+m[0][1]*v.y+m[0][2]*v.z,y:m[1][0]*v.x+m[1][1]*v.y+m[1][2]*v.z,z:m[2][0]*v.x+m[2][1]*v.y+m[2][2]*v.z}; } function roundMat(m){return m.map(r=>r.map(v=>Math.round(v)))} /* ========== イージング ========== */ function easeIO(t){return t<0.5?4*t*t*t:1-Math.pow(-2*t+2,3)/2} /* ========== 定数 ========== */ const SP=70; // キュービー中心間の間隔 const CH=33; // キュービーの半サイズ(face translateZ) const COLORS={ right:'#b71234',left:'#ff5800',top:'#ffffff', bottom:'#ffd500',front:'#009b48',back:'#0046ad',inner:'#0e0e0e' }; /* 移動の定義 — CSSのY下向き座標系 */ const MOVES={ R :{axis:'x',layer:1, angle:90}, Ri:{axis:'x',layer:1, angle:-90}, L :{axis:'x',layer:-1,angle:-90}, Li:{axis:'x',layer:-1,angle:90}, U :{axis:'y',layer:-1,angle:90}, Ui:{axis:'y',layer:-1,angle:-90}, D :{axis:'y',layer:1, angle:-90}, Di:{axis:'y',layer:1, angle:90}, F :{axis:'z',layer:1, angle:90}, Fi:{axis:'z',layer:1, angle:-90}, B :{axis:'z',layer:-1,angle:-90}, Bi:{axis:'z',layer:-1,angle:90}, }; const MKEYS=Object.keys(MOVES); function inv(n){return n.endsWith('i')?n.slice(0,-1):n+'i'} /* ========== キューブ状態 ========== */ const container=document.getElementById('cube-container'); const cubies=[]; const I3=[[1,0,0],[0,1,0],[0,0,1]]; function buildCube(){ for(let x=-1;x<=1;x++)for(let y=-1;y<=1;y++)for(let z=-1;z<=1;z++){ const cb={op:{x,y,z},m:JSON.parse(JSON.stringify(I3)),el:null}; const el=document.createElement('div');el.className='cubie'; const fc=[ {n:'front', c:z===1?COLORS.front:null}, {n:'back', c:z===-1?COLORS.back:null}, {n:'right', c:x===1?COLORS.right:null}, {n:'left', c:x===-1?COLORS.left:null}, {n:'top', c:y===-1?COLORS.top:null}, {n:'bottom',c:y===1?COLORS.bottom:null}, ]; fc.forEach(f=>{ const d=document.createElement('div'); d.className='face '+f.n; if(f.c){d.style.backgroundColor=f.c;d.classList.add('face-outer')} else{d.style.backgroundColor=COLORS.inner} el.appendChild(d); }); cb.el=el;container.appendChild(el); setTrans(cb); cubies.push(cb); } } function curPos(cb){ const p=mat3Vec(cb.m,cb.op); return{x:Math.round(p.x),y:Math.round(p.y),z:Math.round(p.z)}; } function transStr(cb){ return mat3Css(cb.m)+` translate3d(${cb.op.x*SP}px,${cb.op.y*SP}px,${cb.op.z*SP}px)`; } function setTrans(cb){cb.el.style.transform=transStr(cb)} /* ========== 移動アニメーション ========== */ async function doMove(name,dur=480){ const d=MOVES[name],{axis,layer,angle}=d; const axU=axis.toUpperCase(); const aff=cubies.filter(c=>curPos(c)[axis]===layer); aff.forEach(c=>{c._b=transStr(c)}); const t0=performance.now(); await new Promise(res=>{ function tick(now){ const p=Math.min((now-t0)/dur,1),e=easeIO(p),a=angle*e; aff.forEach(c=>{c.el.style.transform=`rotate${axU}(${a}deg) ${c._b}`}); if(p<1)requestAnimationFrame(tick); else{ const rm=rotMat(axis,angle); aff.forEach(c=>{c.m=roundMat(mat3Mul(rm,c.m));setTrans(c)}); res(); } } requestAnimationFrame(tick); }); } /* ========== シャッフル&解法 ========== */ let hist=[]; async function scramble(n=22){ hist=[];let last=''; for(let i=0;i<n;i++){ let mv,att=0; do{mv=MKEYS[Math.floor(Math.random()*MKEYS.length)];att++} while((mv===last||mv===inv(last))&&att<30); hist.push(mv);last=mv; await doMove(mv,420); } } async function solve(){ const rev=[...hist].reverse().map(inv); for(const mv of rev)await doMove(mv,420); hist=[]; } function delay(ms){return new Promise(r=>setTimeout(r,ms))} /* ========== マウス/タッチのドラッグ ========== */ let rx=-28,ry=38,drag=false,lx,ly; const scene=document.getElementById('scene'); function updCont(){container.style.transform=`rotateX(${rx}deg) rotateY(${ry}deg)`} scene.addEventListener('mousedown',e=>{drag=true;lx=e.clientX;ly=e.clientY}); window.addEventListener('mousemove',e=>{ if(!drag)return; ry+=(e.clientX-lx)*0.45;rx-=(e.clientY-ly)*0.45; rx=Math.max(-89,Math.min(89,rx));lx=e.clientX;ly=e.clientY;updCont(); }); window.addEventListener('mouseup',()=>{drag=false}); scene.addEventListener('touchstart',e=>{drag=true;lx=e.touches[0].clientX;ly=e.touches[0].clientY},{passive:true}); window.addEventListener('touchmove',e=>{ if(!drag)return;e.preventDefault(); const t=e.touches[0]; ry+=(t.clientX-lx)*0.45;rx-=(t.clientY-ly)*0.45; rx=Math.max(-89,Math.min(89,rx));lx=t.clientX;ly=t.clientY;updCont(); },{passive:false}); window.addEventListener('touchend',()=>{drag=false}); /* ========== アイドル時の自動回転 ========== */ let idle=true; function idleTick(){ if(!idle)return; ry+=0.1;updCont();requestAnimationFrame(idleTick); } /* ========== ステータス & ボタン ========== */ const statusEl=document.getElementById('status'); const btn=document.getElementById('start-btn'); let started=false; btn.addEventListener('click',()=>{ if(started)return;started=true;idle=false; btn.disabled=true; runLoop(); }); async function runLoop(){ while(true){ statusEl.textContent='スクランブル中';statusEl.style.color='rgba(233,69,96,0.7)'; statusEl.classList.add('active'); await scramble(22); statusEl.textContent='解析中';statusEl.style.color='rgba(0,155,72,0.6)'; await delay(1400); statusEl.textContent='解決中';statusEl.style.color='rgba(0,200,83,0.7)'; await solve(); statusEl.textContent='解決しました';statusEl.style.color='rgba(255,213,0,0.75)'; statusEl.classList.remove('active'); await delay(2800); statusEl.classList.add('active'); } } /* ========== 初期化 ========== */ buildCube(); updCont(); idleTick(); </script> </body> </html> 
提出者: