feat: add production campaigns, gameplay labs, and review documentation
This commit is contained in:
+29
-11
@@ -1,3 +1,6 @@
|
||||
import { ART_DIRECTIONS, artDirection, directionTheme, appearanceTile } from './art-directions.js';
|
||||
import { mountDirectionReview } from './direction-review.js';
|
||||
import { itemStudy } from './item-study.js';
|
||||
import { attachBoardViewport } from './board-viewport.js';
|
||||
import { createStudyLevel } from './study-levels.js';
|
||||
import { TapQueue } from './tap-queue.js';
|
||||
@@ -16,6 +19,7 @@ let boardViewport;
|
||||
const regularLevel=createStudyLevel(3);
|
||||
let studyLevel=createStudyLevel(5);
|
||||
let colorCount=7;
|
||||
let direction=artDirection(new URLSearchParams(location.search).get("design"));
|
||||
let theme=themeWithColors(LEVEL_THEMES[0],colorCount),game=new Game(studyLevel),animation=null,rotation=null,frame=0,view=null,hint=null,afterRotation=null;
|
||||
const atlas=new Image();atlas.src=TILE_ATLAS;atlas.onload=()=>{painter.atlas=atlas;draw();paintSamples();};
|
||||
function decorateIcons(){
|
||||
@@ -24,27 +28,32 @@ function decorateIcons(){
|
||||
el.innerHTML=`<span class="art-icon" aria-hidden="true"><img src="${ICON_ATLAS}" alt="" style="width:${ICON_SIZE.w/f.w*100}%;height:${ICON_SIZE.h/f.h*100}%;left:${-f.x/f.w*100}%;top:${-f.y/f.h*100}%"></span>`;
|
||||
});
|
||||
}
|
||||
$('theme-tabs').innerHTML=LEVEL_THEMES.map(t=>`<button data-theme="${t.id}" aria-pressed="false"><i style="background:${t.background}"></i>${t.label}</button>`).join('');
|
||||
$('theme-grid').innerHTML=LEVEL_THEMES.map(t=>`<button class="theme-card" data-theme="${t.id}" aria-pressed="false"><div class="mini-scene" style="--bg:${t.background};--ink:${t.ink}"><span>${t.label} / ${t.range}</span><canvas data-sample="${t.id}" aria-label="${t.name}配色"></canvas></div><strong>${t.name}</strong><small>${t.palette.length} 色棋子 · ${t.background}</small></button>`).join('');
|
||||
$('item-study-content').innerHTML=itemStudy();
|
||||
$('theme-tabs').innerHTML=direction.themes.map(t=>`<button data-theme="${t.id}" aria-pressed="false"><i style="background:${t.background}"></i>${t.label}</button>`).join('');
|
||||
$('theme-grid').innerHTML=direction.themes.map(t=>`<button class="theme-card" data-theme="${t.id}" aria-pressed="false"><div class="mini-scene" style="--bg:${t.background};--ink:${t.ink}"><span>${t.label} / ${t.range}</span><canvas data-sample="${t.id}" aria-label="${t.name}配色"></canvas></div><strong>${t.name}</strong><small>${t.palette.length} 色棋子 · ${t.background}</small></button>`).join('');
|
||||
$('pigment-grid').innerHTML=PIGMENTS.map((p,i)=>`<div class="pigment-item"><canvas data-pigment="${i}" aria-label="${p.name}棋子"></canvas><strong>${p.name}</strong><small>${p.color}</small></div>`).join('');
|
||||
$('quick-theme').innerHTML=LEVEL_THEMES.map(t=>`<option value="${t.id}">${t.label}</option>`).join('');
|
||||
$('quick-theme').onchange=()=>setTheme(direction.themes.find(t=>t.id===$('quick-theme').value));
|
||||
function setTheme(next){
|
||||
theme=themeWithColors(next,colorCount);$('phone').style.setProperty('--scene-bg',theme.background);$('density-grid').style.setProperty('--bg',theme.background);$('density-grid').style.setProperty('--ink',theme.ink);$('phone').style.setProperty('--scene-ink',theme.ink);
|
||||
$('quick-theme').value=next.id;
|
||||
theme=directionTheme(direction,next.id,colorCount);$('phone').style.setProperty('--scene-bg',theme.background);$('density-grid').style.setProperty('--bg',theme.background);$('density-grid').style.setProperty('--ink',theme.ink);$('phone').style.setProperty('--scene-ink',theme.ink);
|
||||
$('item-study-content').style.setProperty('--scene-bg',theme.background);$('item-study-content').style.setProperty('--scene-ink',theme.ink);
|
||||
$('scene-label').textContent=`${theme.label} / ${theme.range}`;$('scene-name').textContent=theme.name;
|
||||
$('scene-description').textContent=`${theme.description} 当前展示 ${colorCount} 色扩展搭配。`;$('phone-label').textContent=`${theme.label} · ${theme.name}`;
|
||||
$('background-value').textContent=theme.background;$('background-chip').style.background=theme.background;
|
||||
$('palette-count').textContent=`${theme.palette.length} / 12`;
|
||||
$('local-palette').innerHTML=theme.palette.map(i=>`<span title="${PIGMENTS[i].name}" style="background:${PIGMENTS[i].color}"></span>`).join('');
|
||||
$('local-palette').innerHTML=theme.palette.map(i=>`<span title="${direction.pigments[i].name}" style="background:${direction.pigments[i].color}"></span>`).join('');
|
||||
document.querySelectorAll('[data-theme]').forEach(b=>b.setAttribute('aria-pressed',String(b.dataset.theme===theme.id)));
|
||||
for(const id of ['play-theme','game-link'])$(id).href=`index.html?theme=${theme.id}&colors=${colorCount}`;
|
||||
for(const id of ['play-theme','game-link'])$(id).href=`index.html?design=${direction.id}&theme=${theme.id}&colors=${colorCount}`;
|
||||
paintSamples();draw();
|
||||
}
|
||||
document.querySelectorAll('[data-theme]').forEach(b=>b.onclick=()=>setTheme(LEVEL_THEMES.find(t=>t.id===b.dataset.theme)));
|
||||
document.querySelectorAll('[data-theme]').forEach(b=>b.onclick=()=>setTheme(direction.themes.find(t=>t.id===b.dataset.theme)));
|
||||
function fit(c){const rect=c.getBoundingClientRect(),w=rect.width,h=c===canvas?rect.height:w,dpr=Math.min(devicePixelRatio||1,2);c.width=Math.round(w*dpr);c.height=Math.round(h*dpr);const context=c.getContext('2d');context.setTransform(dpr,0,0,dpr,0,0);return {context,width:w,height:h};}
|
||||
function paintSamples(){
|
||||
document.querySelectorAll('[data-theme].theme-card>small').forEach(el=>{const t=LEVEL_THEMES.find(t=>t.id===el.parentElement.dataset.theme);el.textContent=`${colorCount} 色棋子 · ${t.background}`;});
|
||||
document.querySelectorAll('[data-theme].theme-card>small').forEach(el=>{const t=direction.themes.find(t=>t.id===el.parentElement.dataset.theme);el.textContent=`${colorCount} 色棋子 · ${t.background}`;});
|
||||
document.querySelectorAll('[data-density]').forEach(c=>{const {context,width}=fit(c),p=new CanvasPainter(context);p.atlas=atlas;drawScene(p,studyLevel,studyLevel.tiles,layout(studyLevel.cells,width,width),{theme:themeWithColors(theme,Number(c.dataset.density))});});
|
||||
document.querySelectorAll('[data-sample]').forEach(c=>{const {context,width}=fit(c),p=new CanvasPainter(context);p.atlas=atlas;const v=layout(studyLevel.cells,width,width);drawScene(p,studyLevel,studyLevel.tiles,v,{theme:themeWithColors(LEVEL_THEMES.find(t=>t.id===c.dataset.sample),colorCount)});});
|
||||
document.querySelectorAll('[data-pigment]').forEach(c=>{const {context,width}=fit(c),p=new CanvasPainter(context);p.atlas=atlas;drawTile(p,width/2,width/2,width*.46,{color:Number(c.dataset.pigment),dir:1});});
|
||||
document.querySelectorAll('[data-sample]').forEach(c=>{const {context,width}=fit(c),p=new CanvasPainter(context);p.atlas=atlas;const v=layout(studyLevel.cells,width,width);drawScene(p,studyLevel,studyLevel.tiles,v,{theme:directionTheme(direction,c.dataset.sample,colorCount)});});
|
||||
document.querySelectorAll('[data-pigment]').forEach(c=>{const {context,width}=fit(c),p=new CanvasPainter(context);p.atlas=atlas;drawTile(p,width/2,width/2,width*.46,appearanceTile({color:Number(c.dataset.pigment),dir:1},theme));});
|
||||
}
|
||||
function resize(){const {width,height}=fit(canvas);const base=layout(game.level.cells,width,height);view=boardViewport?boardViewport.camera.fit(base,width,height):base;boardViewport?.update();draw();paintSamples();}
|
||||
function controls(){const busy=!!animation||!!rotation;for(const id of ['demo','left','right','undo','hint'])$(id).disabled=busy; $('undo').disabled=busy||!game.history.length;$('moves').textContent=game.moves;}
|
||||
@@ -88,6 +97,15 @@ $('study-dialog-content').onchange=e=>{if(e.target.id==='study-slow')$('slow').c
|
||||
boardViewport=attachBoardViewport(canvas,{changed:resize,tap:({x,y})=>{if(!view)return;const cell=hitCell(game.level.cells,view,x,y);const tile=cell&&game.tiles.find(t=>t.q===cell.q&&t.r===cell.r);if(tile)move(tile);}});
|
||||
$('board-size').onchange=()=>{studyLevel=$('board-size').value==='regular'?regularLevel:createStudyLevel(Number($('board-size').value));boardViewport.camera.reset();reset();resize();document.querySelectorAll('.density-card .mini-scene>span').forEach(el=>el.textContent=`${el.closest('[data-count]').dataset.count} 色 / ${studyLevel.tiles.length} 枚棋子`);};
|
||||
$('density-grid').innerHTML=[4,7,9,12].map(n=>`<button class="theme-card density-card" data-count="${n}" aria-pressed="${n===colorCount}"><div class="mini-scene"><span>${n} 色 / ${studyLevel.tiles.length} 枚棋子</span><canvas data-density="${n}" aria-label="${n}色棋盘对照"></canvas></div><strong>${n===4?'简洁':n===7?'丰富':n===9?'缤纷':'满色'} · ${n} 色</strong><small>${n===7?'建议优先体验':n===12?'观察相近色带来的复杂感':'同一布局,比较视觉密度'}</small></button>`).join('');
|
||||
document.querySelectorAll('[data-count]').forEach(b=>b.onclick=()=>{colorCount=Number(b.dataset.count);document.querySelectorAll('[data-count]').forEach(x=>x.setAttribute('aria-pressed',String(Number(x.dataset.count)===colorCount)));setTheme(LEVEL_THEMES.find(t=>t.id===theme.id));reset();});
|
||||
document.querySelectorAll('[data-count]').forEach(b=>b.onclick=()=>{colorCount=Number(b.dataset.count);document.querySelectorAll('[data-count]').forEach(x=>x.setAttribute('aria-pressed',String(Number(x.dataset.count)===colorCount)));setTheme(direction.themes.find(t=>t.id===theme.id));reset();});
|
||||
document.querySelector('.phone-top strong').textContent='测试关 01';
|
||||
decorateIcons();setTheme(theme);controls();new ResizeObserver(resize).observe(canvas);
|
||||
decorateIcons();controls();
|
||||
mountDirectionReview(direction,next=>{
|
||||
direction=next;
|
||||
document.querySelectorAll('[data-theme]').forEach(b=>{const t=direction.themes.find(t=>t.id===b.dataset.theme);const scene=b.querySelector('.mini-scene');if(scene){scene.style.setProperty('--bg',t.background);scene.style.setProperty('--ink',t.ink);b.querySelector('strong').textContent=t.name;b.querySelector('canvas').setAttribute('aria-label',t.name+'配色');}const dot=b.querySelector('i');if(dot)dot.style.background=t.background;});
|
||||
document.querySelectorAll('.pigment-item').forEach((el,i)=>{el.querySelector('small').textContent=direction.pigments[i].color;el.querySelector('strong').textContent=direction.pigments[i].name;el.querySelector('canvas').setAttribute('aria-label',direction.pigments[i].name+'棋子');});
|
||||
$('phone').style.setProperty('--design-accent',direction.accent);
|
||||
document.querySelector('.theme-collection h2').textContent=`${direction.name} · 五种关卡主题`;
|
||||
setTheme(direction.themes.find(t=>t.id===theme.id)||direction.themes[0]);
|
||||
});
|
||||
new ResizeObserver(resize).observe(canvas);
|
||||
|
||||
Reference in New Issue
Block a user