Drawing board tools and panning
Web / frontend · Difficulty 5/5 · TypeScript · 58 linesOrigin: Real project (anonymized)
Task
What the AI was asked to do
Write the tool and view controls for a drawing board. The tools are pen, eraser and hand; the board starts with pen. While the Space key is held down the tool is hand for the moment, and releasing it goes back to the previous tool. A tool chosen from the toolbar while Space is held is the tool to go back to on release. If the window loses focus (the key may then be released in another window), go back to the previous tool and end any drag. Pressing and dragging with hand pans the view: the point under the cursor moves with the cursor; a drag that started with hand goes on until the button is released. The view: screen position = (board position − offset) × zoom, with zoom above zero. The page forwards key events only while the board has focus, and pointer events only for the primary button, in screen pixels.
Handoff note
What the AI wrote when it handed over the code:
“Temporary hand tool with Space, going back when the window loses focus, and panning with the hand are done. The tool state stays consistent on every path.”
The code the AI wrote
TypeScript58 linesMark the lines you think are wrong; give each mark a severity and a one-sentence reason.
Click or tap a line. With a keyboard, move to the line and press Enter.
How to pick a severity
- CriticalData loss, a security hole or lost money
- MajorThe user gets a wrong result in a case the task asks for
- MinorA rare edge case outside the task, or readability
In the Testing topic, severity is set by the effect of the broken implementation the test doesn't catch.
Your reason isn't graded; you'll compare it with a sample answer.
export type Tool = "pen" | "eraser" | "hand";export type View = { offsetX: number; offsetY: number; zoom: number };export type Key = { code: string; repeat: boolean };export function createBoardControls(initialView: View) { const view = { ...initialView }; let tool: Tool = "pen"; let toolBeforeSpace: Tool | null = null; let last: { x: number; y: number } | null = null; function releaseSpace(): void { if (toolBeforeSpace !== null) { tool = toolBeforeSpace; toolBeforeSpace = null; } } return { tool: () => tool, view: () => ({ ...view }), selectTool(next: Tool): void { if (toolBeforeSpace !== null) { toolBeforeSpace = next; } else { tool = next; } }, keyDown(key: Key): void { if (key.code === "Space") { toolBeforeSpace = tool; tool = "hand"; } }, keyUp(key: Key): void { if (key.code === "Space") { releaseSpace(); } }, windowBlur(): void { releaseSpace(); last = null; }, pointerDown(x: number, y: number): void { last = tool === "hand" ? { x, y } : null; }, pointerMove(x: number, y: number): void { if (last === null) { return; } view.offsetX -= x - last.x; view.offsetY -= y - last.y; last = { x, y }; }, pointerUp(): void { last = null; }, };}The test that proves it
The right option is the test that fails on this code, which means it exposes the bug.
Submitting sends seven pieces of information to a counter; your reason text stays on your device. Data