Yesterday at ten • timeline practice — Use a supplied past timeline to distinguish an ongoing background action from a shorter event, and build was/were plus-ing forms.
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>Yesterday at ten • timeline practice</title><style>*{box-sizing:border-box}body{margin:0;background:var(--bg,#f3f7fa);color:var(--ink,#203342);font:16px/1.55 system-ui,Segoe UI,sans-serif}main{max-width:1100px;margin:auto;padding:28px 30px 50px}h1{font-size:clamp(27px,3.5vw,40px);line-height:1.18;letter-spacing:-.035em;margin:8px 0 12px}h2{font-size:21px;line-height:1.35;margin:0 0 16px}h3{font-size:18px}.eyebrow{color:var(--accent,#176783);font-size:12px;letter-spacing:.12em;font-weight:800;text-transform:uppercase}.intro,.muted,small{color:#516272}.intro{margin:0 0 24px}.panel{padding:24px;border:1px solid var(--line,#d6e0e7);border-radius:12px;background:white;margin:18px 0}.grid{display:grid;grid-template-columns:1fr 1fr;gap:22px}.grid>*{min-width:0}.controls{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin:16px 0}button,input,textarea,select{font:inherit}button{border:1px solid var(--accent,#176783);background:var(--accent,#176783);color:white;padding:10px 16px;min-height:44px;border-radius:7px;font-weight:700;cursor:pointer}button.secondary{background:white;color:var(--accent,#176783)}button[aria-pressed=true]{background:var(--tint,#e3f2f8);color:var(--ink,#203342);box-shadow:inset 0 0 0 2px var(--accent,#176783)}button:hover{filter:brightness(.96)}:focus-visible{outline:3px solid #d56b00;outline-offset:3px}label{display:block;margin:12px 0 5px;font-size:14px;font-weight:650}input:not([type=checkbox]),select,textarea{width:100%;padding:10px 12px;min-height:44px;border:1px solid #94a5b2;background:white;color:inherit;border-radius:7px}textarea{resize:vertical;min-height:120px}input[type=checkbox]{width:20px;height:20px;margin-right:9px}label.inline{display:flex;align-items:center;font-weight:500;gap:7px}.result{padding:24px;background:var(--tint,#e3f2f8);border:1px solid var(--line,#c8dce7);border-radius:12px}.big{font-size:clamp(30px,5vw,48px);font-weight:780;line-height:1.25;letter-spacing:-.035em;margin:10px 0}.trace{font:15px/1.7 ui-monospace,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.error{color:#a12820;font-weight:650;min-height:24px}.table-wrap{overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:15px}th,td{text-align:left;border-bottom:1px solid var(--line,#d6e0e7);padding:12px 9px;vertical-align:top}th{font-size:12px;text-transform:uppercase;letter-spacing:.03em;color:#516272}code,pre,.code{font:14px/1.65 ui-monospace,Consolas,monospace}pre{white-space:pre-wrap;overflow-wrap:anywhere;background:var(--tint,#eef3f7);padding:16px;border-radius:6px}details{border-top:1px solid var(--line,#d6e0e7);margin:24px 0;padding-top:16px}summary{cursor:pointer;font-weight:700;min-height:44px}footer{border-top:1px solid var(--line,#d6e0e7);margin-top:26px;padding-top:16px;font-size:13px;color:#516272}.bar{height:16px;background:#dce4ea;border-radius:20px;overflow:hidden;margin:12px 0}.bar span{display:block;height:100%;background:var(--accent,#176783)}[hidden]{display:none!important}@media(max-width:720px){main{padding:20px}.grid{grid-template-columns:1fr;gap:12px}.panel,.result{padding:20px}}@media(max-width:400px){main{padding:16px}.panel,.result{padding:16px}button{padding:10px 13px}} .paper{background:white;padding:26px;border:1px solid var(--line,#d6e0e7)}.badge{display:inline-block;padding:4px 10px;border-radius:20px;background:var(--tint,#e3f2f8);font-size:13px;font-weight:700}.feedback{padding:18px;background:var(--tint,#e3f2f8);border-left:4px solid var(--accent,#176783);line-height:1.7}.schedule-row{display:grid;grid-template-columns:70px 1fr 90px;gap:14px;padding:16px 0;border-bottom:1px solid var(--line,#d6e0e7);align-items:start}.schedule-row label{margin:0}.schedule-row small{display:block;margin-top:6px}.schedule-row b{font-size:17px}.schedule-time{font-weight:700;font-variant-numeric:tabular-nums}.export{margin:24px 0}.export textarea{min-height:180px}.choice-list{display:flex;gap:10px;flex-wrap:wrap;margin:18px 0}.choice-list button{background:white;color:var(--ink,#203342);border-color:var(--line,#94a5b2)}@media(max-width:400px){.schedule-row{grid-template-columns:48px 1fr 65px;gap:9px}.schedule-row input{padding:8px}}
body{--accent:#985226;--bg:#faf5ef;--tint:#f6e7d7;--ink:#493427;--line:#e6d5c6}.timeline-board{background:#fff;padding:20px 24px;border:1px solid #e6d5c6;border-radius:8px}.axis{display:flex;justify-content:space-between;font-size:13px;gap:12px;margin-bottom:16px}.track{margin:16px 0}.track b{display:block;font-size:14px;margin-bottom:5px}.track small{font-size:13px}.rail{position:relative;height:19px;background:#ede9e3;border-radius:5px}.interval{position:absolute;height:100%;border-radius:4px}.sorting{left:25%;width:75%;background:#8cacc9}.carrying{left:0;width:75%;background:#91bda8}.bell{position:absolute;left:calc(50% - 7px);top:2px;width:15px;height:15px;background:#d8864f;border:2px solid #7d3e17;border-radius:50%}.marker{position:absolute;top:-5px;height:29px;border-left:2px dashed #493427;left:50%}.sentence{font:24px/1.5 Georgia,serif}.panel{border-radius:6px}#feedback{margin-bottom:0}@media(max-width:400px){.timeline-board{padding:16px}.axis{font-size:12px}}</style></head><body><main>
<header><span class="eyebrow">Yesterday / one supplied morning</span><h1>What was happening at <span id="clock-title">10:00</span>?</h1><p class="intro">Use the recorded interval and the requested construction to choose a sentence.</p></header>
<section class="timeline-board"><div class="axis"><span>9:50</span><b id="marker-label">Inspection: 10:00</b><span>10:10</span></div><div class="track"><b>Mara · sorting cards</b><div class="rail"><span class="interval sorting"></span><i class="marker" id="marker-0"></i></div><small>9:55–10:10</small></div><div class="track"><b>Theo and Lee · carrying boxes</b><div class="rail"><span class="interval carrying"></span><i class="marker" id="marker-1"></i></div><small>9:50–10:05</small></div><div class="track"><b>Jo · desk bell</b><div class="rail"><span class="bell"></span><i class="marker" id="marker-2"></i></div><small>Event at 10:00</small></div><div class="controls"><button type="button" id="time-952" class="secondary">9:52</button><button type="button" id="time-1000" class="secondary">10:00</button><button type="button" id="time-1007" class="secondary">10:07</button></div></section>
<section class="panel"><div class="controls"><button type="button" id="mara" class="secondary">Mara</button><button type="button" id="boxes" class="secondary">Theo and Lee</button><button type="button" id="bell" class="secondary">Bell event</button></div><h2 id="prompt"></h2><div id="choice-list" class="choice-list"></div><p id="preview" class="sentence" aria-live="polite">Choose a construction.</p><div class="controls"><button type="button" id="check">Check sentence</button><button type="button" id="retry" class="secondary">Try again</button><button type="button" id="reset" class="secondary">Reset timeline</button></div><p id="feedback" class="feedback" aria-live="polite">Not answered.</p></section>
<details><summary>Full text timeline and construction boundaries</summary><p>Yesterday morning: Mara sorted cards from 9:55 to 10:10. Theo and Lee carried boxes from 9:50 to 10:05. Jo rang the desk bell at 10:00. The selected inspection time appears above.</p><p>The ringing does not establish that Mara stopped; the supplied sorting interval continues to 10:10. Outside an activity interval, these records do not support calling that activity ongoing at the marker. The event item requests simple past. Other English perspectives need their own context.</p></details>
<footer>Original fictional records. Only supplied choices are checked; no arbitrary prose grading, recorded learner responses, or saved score.</footer>
</main><script>const $=id=>document.getElementById(id);const on=(id,e,fn)=>$(id).addEventListener(e,fn);const txt=(id,v)=>$(id).textContent=v;const esc=s=>String(s).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));const positive=x=>String(x).trim()!==''&&Number.isFinite(Number(x))&&Number(x)>0;const num=x=>Number(x.toPrecision(10)).toString();function enter(id,fn){on(id,'keydown',e=>{if(e.key==='Enter'&&!e.isComposing&&e.keyCode!==229){e.preventDefault();fn()}})}function selectText(id){$(id).focus();$(id).select()}
let who='mara',minute=600,selection='';
const records={mara:{subject:'Mara',start:595,end:610,verb:'sorting',object:'cards',aux:'was'},boxes:{subject:'Theo and Lee',start:590,end:605,verb:'carrying',object:'boxes',aux:'were'},bell:{subject:'Jo',time:600}};
const clock=m=>Math.floor(m/60)+':'+String(m%60).padStart(2,'0');
function taskState(w,m){const r=records[w];if(w==='bell')return {prompt:m===600?'Describe the bell as the supplied simple-past event.':'Does the record place the bell event at '+clock(m)+'?',options:m===600?['rang','was ringing','ring']:['At this marker','Not at this marker'],key:m===600?'rang':'Not at this marker'};if(!(r.start<m&&m<r.end))return {prompt:'Does this interval support an ongoing '+r.verb+' action at '+clock(m)+'?',options:['Ongoing at this marker','Not supported by this interval'],key:'Not supported by this interval'};return {prompt:'Use past continuous for '+r.subject+' at '+clock(m)+'.',options:[r.aux+' '+r.verb,(r.aux==='was'?'were':'was')+' '+r.verb,r.aux+' '+(w==='mara'?'sort':'carry')],key:r.aux+' '+r.verb}}
function feedbackFor(w,m,s){if(!s)return 'Not answered. Choose a supplied construction first.';const task=taskState(w,m),r=records[w],correct=s===task.key;let evidence=w==='bell'?'Jo’s bell event is recorded at 10:00. This item uses a simple-past event perspective.':r.subject+' '+r.verb+' interval: '+clock(r.start)+'–'+clock(r.end)+'. '+(r.start<m&&m<r.end?'The marker lies inside that interval. Use '+r.aux+' plus the supplied -ing form.':'The marker is outside that interval; these records do not establish an ongoing action there.');return (correct?'Correct. ':'Revisit the requested construction. ')+evidence+(w==='mara'?' The bell does not stop the sorting; its supplied endpoint is 10:10.':'')+' This is an item-specific choice, not a judgment on every possible English description.'}
function clearChoice(){selection='';for(const b of $('choice-list').children)b.setAttribute('aria-pressed','false');txt('preview','Choose a construction.');txt('feedback','Not answered.')}
function view(){const task=taskState(who,minute);txt('clock-title',clock(minute));txt('marker-label','Inspection: '+clock(minute));txt('prompt',task.prompt);for(let i=0;i<3;i++)$('marker-'+i).style.left=((minute-590)/20*100)+'%';for(const [id,m]of [['time-952',592],['time-1000',600],['time-1007',607]])$(id).setAttribute('aria-pressed',String(m===minute));for(const w of Object.keys(records))$(w).setAttribute('aria-pressed',String(w===who));$('choice-list').innerHTML='';task.options.forEach((v,i)=>{const b=document.createElement('button');b.type='button';b.id='answer-'+i;b.textContent=v;b.setAttribute('aria-pressed','false');b.addEventListener('click',()=>{selection=v;for(const sibling of $('choice-list').children)sibling.setAttribute('aria-pressed',String(sibling===b));txt('preview',who==='bell'&&minute===600?'Jo '+v+' the bell.':v);txt('feedback','Choice changed. Check the current item.')});$('choice-list').appendChild(b)});clearChoice()}
for(const w of Object.keys(records))on(w,'click',()=>{who=w;view()});for(const [id,m]of [['time-952',592],['time-1000',600],['time-1007',607]])on(id,'click',()=>{minute=m;view()});on('check','click',()=>txt('feedback',feedbackFor(who,minute,selection)));on('retry','click',clearChoice);on('reset','click',()=>{who='mara';minute=600;view()});view();
</script></body></html>