初始提交:三玩法 Web 原型与设计文档

- 玩法一 数字一笔:规则库、求解器、26 关、竖屏触摸 Web 原型、测试
- 玩法二 连连气球:连消畅玩版核心、Web 原型、Cocos 球槽组件与导出脚本
- 玩法三 六边一笔:规则库、求解器、10 关 + 转墙实验包、Web 原型、测试
- 产品文档、UI 设计规范、各玩法 GDD / HANDOFF
- 文档移除全部外部参考作引用;删除玩法二 v0 旧稿
This commit is contained in:
cabinw
2026-09-16 14:30:59 +08:00
commit 8026e4628d
169 changed files with 22162 additions and 0 deletions
@@ -0,0 +1,34 @@
import assert from 'node:assert/strict';
import {writeFile} from 'node:fs/promises';
const task=await taskSpace(4),page=task.page('p1');
const dir='/Users/wukaibing/Grok/number-swipe/modes/02-connect-1234/docs/qa-v2';
await page.goto('http://localhost:8002');
const opening=await page.evaluate(()=>({state:window.__balloons.snapshot(),hint:window.__balloons.hint()}));
await page.goto('http://localhost:8003');
await page.waitForFunction(()=>document.querySelector('#app').dataset.mode==='flow',undefined,{timeout:5000});
const key='mode:02-connect-1234:balloons-v2';
const backup=await page.evaluate(k=>({v2:localStorage.getItem(k),v1:localStorage.getItem('mode:02-connect-1234:v1')}),key);
assert.equal(await page.evaluate(()=>typeof window.__balloons),'undefined');
await page.evaluate(()=>{window.qaErrors=[];addEventListener('error',e=>window.qaErrors.push(e.message));addEventListener('unhandledrejection',e=>window.qaErrors.push(String(e.reason)));});
const coords=await page.evaluate(data=>{const r=document.querySelector('#board').getBoundingClientRect(),s=Math.min(r.width/360,r.height/416);return data.hint.map(id=>{const b=data.state.balls.find(b=>b.id===id);return{x:r.left+(r.width-360*s)/2+b.x*s,y:r.top+(r.height-416*s)/2+b.y*s,id:0};});},opening);
for(let i=0;i<coords.length;i++)await page.cdp('Input.dispatchTouchEvent',{type:i?'touchMove':'touchStart',touchPoints:[coords[i]]});
await page.cdp('Input.dispatchTouchEvent',{type:'touchEnd',touchPoints:[]});
await page.waitForFunction(()=>document.querySelector('#app').dataset.animating==='false',undefined,{timeout:7000});
const result=await page.evaluate(()=>({turns:Number(document.querySelector('#app').dataset.turns),score:document.querySelector('#score').textContent,errors:window.qaErrors,debugExposed:typeof window.__balloons!=='undefined'}));
assert.equal(result.turns,1);assert(Number(result.score.replaceAll(',',''))>0);assert.deepEqual(result.errors,[]);
await page.screenshot({path:dir+'/production-merge.png'});
await page.reload();assert.equal(await page.evaluate(()=>document.querySelector('#best-score').textContent),result.score);
await page.click('#help');
await page.waitForFunction(()=>document.querySelector('#sheet').getAnimations().every(a=>a.playState==='finished'),undefined,{timeout:3000});
await page.screenshot({path:dir+'/help.png'});await page.click('button[aria-label="关闭面板"]');
// 仅恢复本次正式包验收前的 v2 纪录;保留其它存档。
await page.evaluate(({key,v2})=>{if(v2===null)localStorage.removeItem(key);else localStorage.setItem(key,v2);},{key,v2:backup.v2});
assert.equal(await page.evaluate(()=>localStorage.getItem('mode:02-connect-1234:v1')),backup.v1);
await page.reload();
await page.screenshot({path:dir+'/mobile.png'});
await page.cdp('Emulation.setDeviceMetricsOverride',{width:1280,height:900,deviceScaleFactor:2,mobile:false});
await page.waitForFunction(()=>innerWidth===1280,undefined,{timeout:3000});await page.screenshot({path:dir+'/desktop.png'});
await page.cdp('Emulation.setDeviceMetricsOverride',{width:390,height:844,deviceScaleFactor:2,mobile:true});
await page.waitForFunction(()=>innerWidth===390,undefined,{timeout:3000});
await writeFile(dir+'/production.json',JSON.stringify({...result,persistence:true,originalRecordRestored:true,legacyRecordPreserved:true,url:await page.url()},null,2)+'\n');
console.log({...result,persistence:true,originalRecordRestored:true,url:await page.url()});