clone

a browser grid puzzle game where you push words around to rewrite the rules of each level

main
miau-is-true / src / app / intent-router.js
intent-router.js 1.9K
1/**2 * Routes normalized input intents to the active application scene.3 *4 * Device adapters only describe intent and the stage only owns scene UI. This5 * boundary connects those two concerns without knowing DOM event details.6 */7export function createIntentRouter({8 getStage,9 getTitleController,10 move = () => {},11 wait = () => {},12 undo = () => {},13 restart = () => {},14 mute = () => {},15 onSummary = () => {},16} = {}) {17 const moves = Object.freeze({18 up: () => move(0, -1),19 down: () => move(0, 1),20 left: () => move(-1, 0),21 right: () => move(1, 0),22 });2324 function route(intent = {}) {25 const stage = getStage();26 const type = intent.type;27 if (!stage) return false;2829 if (type === 'summary') {30 onSummary();31 return true;32 }3334 if (stage.scene === 'title') {35 if (type === 'menu') {36 stage.show('pause');37 return true;38 }39 const titleInput = type === 'confirm'40 ? 'enter'41 : type === 'undo'42 ? 'z'43 : type === 'restart'44 ? 'r'45 : intent.dir;46 getTitleController()?.input(titleInput);47 stage.render();48 return true;49 }5051 if (stage.scene === 'proof' || stage.scene === 'win') {52 if (stage.scene === 'win' && stage.isWinExiting) return true;53 if (type === 'move' && stage.scene === 'proof') moves[intent.dir]?.();54 if (type === 'wait' && stage.scene === 'proof') wait();55 if (type === 'undo') undo();56 if (type === 'restart') restart();57 if (type === 'menu' && stage.scene === 'proof') stage.show('pause');58 if (type === 'mute') mute();59 if (type === 'confirm' && stage.scene === 'win') stage.handleIntent?.(intent);60 return true;61 }6263 if (intent.source !== 'keyboard' && !(intent.source === 'touch' && intent.point))64 return Boolean(stage.handleIntent?.(intent));65 return false;66 }6768 return Object.freeze({ route });69}7071export default createIntentRouter;