Letter trails · classroom path game — Trace a bent sequence of adjacent letter cells without reusing a cell and distinguish path validity from whether a word is accepted.

HTML for this example

Select the code and use your copy shortcut. Changes in this preview are temporary.

<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Letter trails · classroom path game</title><style>
*{box-sizing:border-box}body{margin:0;background:#fff8dc;color:#234b4e;font:16px/1.5 system-ui,sans-serif}main{max-width:1050px;margin:auto;padding:30px}h1{font-size:clamp(35px,6vw,54px);letter-spacing:-.04em;line-height:1.1;margin:7px 0 10px}h2{font-size:23px;margin:0 0 12px}p{margin:0 0 12px}.label{font-size:12px;letter-spacing:.13em;font-weight:750;text-transform:uppercase}.sub{color:#597170}.play{display:grid;grid-template-columns:1fr 1.1fr;gap:30px;margin-top:26px}.boardwrap{background:#208182;border-radius:22px;padding:20px;color:white;align-self:start}.board{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}.cell{position:relative;min-height:100px;background:#fffdf0;border:3px solid #fffdf0;border-radius:13px;color:#245759;font:800 40px system-ui;padding:9px;box-shadow:0 5px 0 #125b5f;cursor:pointer}.cell small{display:block;font:500 11px system-ui;margin-top:4px}.cell[aria-pressed=true]{background:#ffcf59;border-color:#ffcf59}.cell .order{position:absolute;top:4px;right:8px;font:800 13px system-ui}.board-hint{font-size:13px;margin:17px 0 0;color:#e5f8f3}.panel{background:#fffdf4;border:1px solid #e3d8aa;border-radius:15px;padding:22px}.bank{font-size:17px;word-spacing:12px;font-weight:750;letter-spacing:.05em;color:#1f6b6c;margin-bottom:18px}.chain{font-size:32px;font-weight:750;letter-spacing:.1em;min-height:48px;margin:5px 0}.coords{min-height:44px;font-size:13px;overflow-wrap:anywhere;color:#55716c}.row{display:flex;gap:8px;flex-wrap:wrap}.row button{flex:1}button.action{min-height:45px;background:#246f70;color:white;border:1px solid #246f70;border-radius:8px;padding:10px 15px;font:700 14px system-ui;cursor:pointer}button.secondary{background:#fffdf4;color:#246f70}button:disabled{opacity:.5;cursor:default}:focus-visible{outline:3px solid #ac5427;outline-offset:3px}label{font-weight:650;font-size:14px;display:block}input{font:22px system-ui;display:block;width:100%;border:1px solid #92b2a7;border-radius:7px;padding:10px;margin:6px 0 14px;text-transform:uppercase}.feedback{border-left:4px solid #dca73c;padding:12px 15px;margin-top:17px;background:#fff3c9;min-height:80px}.feedback strong{display:block}.feedback p{font-size:14px;margin:4px 0}.accepted{margin-top:25px}.accepted li{margin:8px 0}.accepted ul{padding-left:20px}.found{font-size:15px;font-weight:700;color:#1f6b6c}.bottom{display:grid;grid-template-columns:1fr 1fr;gap:25px;margin-top:27px}.small{font-size:14px;color:#597170}details{border-top:1px solid #dccf9c;padding-top:18px}summary{cursor:pointer;font-weight:700;min-height:40px}footer{font-size:13px;color:#597170;margin-top:25px}@media(max-width:720px){main{padding:22px 17px}.play{grid-template-columns:1fr;gap:20px}.boardwrap{width:100%;max-width:390px;margin:auto}.cell{min-height:84px}.bottom{grid-template-columns:1fr}.panel{padding:19px}}@media(max-width:380px){main{padding:20px 12px}.boardwrap{padding:15px}.board{gap:8px}.cell{min-height:78px;font-size:34px}.row{gap:6px}.row button{padding:10px}}
</style></head><body><main><p class="label">Original 3 × 3 classroom board</p><h1>Follow the letter trail.</h1><p class="sub">Tap neighboring cells, spell a bank word, and explain your route.</p><section class="play"><div class="boardwrap"><div id="board" class="board" aria-label="Letter cells, rows CAX, TRE, XXX"></div><p class="board-hint">Horizontal, vertical, or diagonal neighbors. Turns are allowed. Each cell can be used once per word.</p></div><div class="panel"><p class="label">Spelling bank for this exercise</p><p class="bank">CAT CART CARE TART</p><p class="label">Your ordered path</p><div class="chain" id="letters">—</div><p id="coordinates" class="coords">No cells selected.</p><div class="row"><button type="button" id="undo" class="action secondary">Undo last</button><button type="button" id="cancel" class="action secondary">Cancel attempt</button></div><label for="claim" style="margin-top:18px">Word you claim<input id="claim" autocomplete="off" maxlength="30" spellcheck="false"></label><button id="check" type="button" class="action" style="width:100%">Check this path</button><div class="feedback" role="status"><strong id="verdict">Build a path to begin.</strong><p id="feedback">Choose cells in order, then enter the word you claim.</p></div></div></section><section class="panel accepted"><div class="row" style="align-items:center;justify-content:space-between"><h2>Accepted trails</h2><span class="found" id="found-count">0 distinct spellings</span><button type="button" id="reset" class="action secondary" style="flex:0 auto">Reset board & list</button></div><p id="empty" class="small">No accepted attempts yet. Repeated spellings count once.</p><ul id="found-list"></ul></section><div class="bottom"><section><h2>Explain one decision</h2><p class="small">Which step turns a corner? If a trial is rejected, is the problem the letters, the route, or the bank? A partner or teacher reviews your explanation.</p><p class="small">Use Tab to reach a cell and Enter or Space to add it. Arrow keys move focus between cells without selecting a letter. Repeated selections remain visible so the checker can explain reuse.</p></section><details><summary>Teacher example key · keep separate</summary><p class="small">Illustrations, not student records or an exhaustive search:</p><p class="small">CAT: r1c1 → r1c2 → r2c1<br>CART: r1c1 → r1c2 → r2c2 → r2c1<br>CARE: r1c1 → r1c2 → r2c2 → r2c3</p><p class="small">TART via r2c1 → r1c2 → r2c2 → r2c1 repeats T. Claimed CAT via r1c1 → r1c2 → r3c1 spells CAX and skips a neighbor.</p></details></div><footer>This independent letter-path exercise uses a finite teacher-reviewed spelling bank. It is not a full dictionary, commercial board, timed competition, vocabulary assessment, or affiliated product. Attempts and found words remain only in this open page.</footer></main><script>
'use strict';const $=id=>document.getElementById(id);const board=['C','A','X','T','R','E','X','X','X'];const bank=new Set(['CAT','CART','CARE','TART']);let path=[],found=new Map();
function coord(i){return'r'+(Math.floor(i/3)+1)+'c'+(i%3+1);}
function inspect(indices,claim){const issues=[],valid=indices.every(i=>Number.isInteger(i)&&i>=0&&i<9),letters=indices.map(i=>Number.isInteger(i)&&i>=0&&i<9?board[i]:'?').join('');if(!indices.length)issues.push('The attempt is incomplete: select at least one cell.');if(!valid)issues.push('A coordinate is outside the board.');const reuse=indices.filter((i,n)=>indices.indexOf(i)!==n);if(reuse.length)issues.push('Cell reuse: '+[...new Set(reuse)].map(coord).join(', ')+'. Each cell may appear once.');for(let n=1;n<indices.length;n++){let a=indices[n-1],b=indices[n];if([a,b].every(i=>Number.isInteger(i)&&i>=0&&i<9)&&Math.max(Math.abs(Math.floor(a/3)-Math.floor(b/3)),Math.abs(a%3-b%3))!==1)issues.push('Not a neighboring step: '+coord(a)+' → '+coord(b)+'.');}const normalized=claim.trim().toUpperCase();if(!normalized)issues.push('Enter the word you claim.');else if(normalized!==letters)issues.push('The selected cells spell '+letters+', not '+normalized+'.');if(indices.length&&!bank.has(letters))issues.push('Actual spelling '+letters+' is not in this exercise’s bank.');return{letters,issues,accepted:issues.length===0,neighbor:!issues.some(x=>x.startsWith('Not a neighboring')),reuse:reuse.length>0,inBank:bank.has(letters)};}
function clearFeedback(){$('verdict').textContent='Not checked.';$('feedback').textContent='Check the current path and claimed word.';}
function renderPath(){$('letters').textContent=path.length?path.map(i=>board[i]).join(''):'—';$('coordinates').textContent=path.length?path.map(coord).join(' → '):'No cells selected.';for(let i=0;i<9;i++){const button=$('cell-'+coord(i));button.setAttribute('aria-pressed',String(path.includes(i)));$('order-'+i).textContent=path.includes(i)?path.map((v,n)=>v===i?n+1:null).filter(Boolean).join(','):'';}$('undo').disabled=!path.length;}
function renderFound(){$('found-count').textContent=found.size+' distinct spelling'+(found.size===1?'':'s');$('empty').hidden=found.size>0;$('found-list').replaceChildren();found.forEach((p,word)=>{let li=document.createElement('li');li.textContent=word+' · '+p.map(coord).join(' → ');$('found-list').appendChild(li);});}
for(let i=0;i<9;i++){const b=document.createElement('button');b.type='button';b.className='cell';b.id='cell-'+coord(i);b.setAttribute('aria-label',board[i]+', row '+(Math.floor(i/3)+1)+', column '+(i%3+1));b.setAttribute('aria-pressed','false');let letter=document.createElement('span');letter.textContent=board[i];b.appendChild(letter);let c=document.createElement('small');c.textContent=coord(i);b.appendChild(c);let badge=document.createElement('span');badge.className='order';badge.id='order-'+i;b.appendChild(badge);b.addEventListener('click',()=>{path.push(i);renderPath();clearFeedback();});b.addEventListener('keydown',e=>{const moves={ArrowDown:3,ArrowUp:-3,ArrowLeft:-1,ArrowRight:1};if(e.key in moves){e.preventDefault();let next=i+moves[e.key];if(next>=0&&next<9&&(Math.abs(moves[e.key])===3||Math.floor(next/3)===Math.floor(i/3)))$('cell-'+coord(next)).focus();}if(e.repeat&&(e.key==='Enter'||e.key===' '))e.preventDefault();});$('board').appendChild(b);}
$('check').addEventListener('click',()=>{const r=inspect(path,$('claim').value);if(r.accepted){const duplicate=found.has(r.letters);if(!duplicate)found.set(r.letters,[...path]);$('verdict').textContent=duplicate?r.letters+' already accepted.':r.letters+' accepted.';$('feedback').textContent='Actual letters: '+r.letters+'. Every step is a neighbor, no cell is reused, and the spelling is in the bank.'+(duplicate?' Distinct count unchanged.':'');renderFound();}else{$('verdict').textContent=path.length?'Path not accepted.':'Incomplete attempt.';$('feedback').textContent='Actual letters: '+(r.letters||'none')+'. '+r.issues.join(' ');}});
$('undo').addEventListener('click',()=>{path.pop();renderPath();clearFeedback();});$('cancel').addEventListener('click',()=>{path=[];$('claim').value='';renderPath();clearFeedback();});$('claim').addEventListener('input',clearFeedback);$('claim').addEventListener('keydown',e=>{if(e.key==='Enter'&&!e.isComposing&&!e.repeat){e.preventDefault();$('check').click();}});$('reset').addEventListener('click',()=>{path=[];found.clear();$('claim').value='';renderPath();renderFound();$('verdict').textContent='Build a path to begin.';$('feedback').textContent='Choose cells in order, then enter the word you claim.';});renderPath();renderFound();
</script></body></html>