-
Notifications
You must be signed in to change notification settings - Fork 0
PR_26179_CHARLIE_025-sprites-basic-drawing #261
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,12 @@ | ||
| const DEFAULT_GRID_SIZE = 16; | ||
| const SUPPORTED_GRID_SIZES = Object.freeze([16, 32]); | ||
| const DRAWING_TOOLS = Object.freeze(["pencil", "eraser", "fill"]); | ||
|
|
||
| const editorState = { | ||
| activeTool: "pencil", | ||
| gridSize: DEFAULT_GRID_SIZE, | ||
| paintedPixels: new Set(), | ||
| }; | ||
|
|
||
| function gridLabel(size) { | ||
| return `Sprite Creator ${size} by ${size} pixel canvas`; | ||
|
|
@@ -9,6 +16,67 @@ function buttonForSize(size) { | |
| return document.querySelector(`[data-sprites-grid-size="${size}"]`); | ||
| } | ||
|
|
||
| function pixelKey(row, column) { | ||
| return `${row}:${column}`; | ||
| } | ||
|
|
||
| function draftStatusText() { | ||
| const count = editorState.paintedPixels.size; | ||
| if (count === 0) { | ||
| return "Unsaved editor state: empty draft."; | ||
| } | ||
| return `Unsaved editor state: ${count} draft pixel${count === 1 ? "" : "s"} painted.`; | ||
| } | ||
|
|
||
| function updateDraftStatus() { | ||
| const status = document.querySelector("[data-sprites-draft-status]"); | ||
| if (status) { | ||
| status.textContent = draftStatusText(); | ||
| } | ||
| } | ||
|
|
||
| function setActiveTool(toolName) { | ||
| if (!DRAWING_TOOLS.includes(toolName)) { | ||
| return; | ||
| } | ||
| editorState.activeTool = toolName; | ||
| document.querySelectorAll("[data-sprite-tool-button]").forEach((button) => { | ||
| const isActive = button.dataset.spriteToolButton === toolName; | ||
| button.classList.toggle("primary", isActive); | ||
| button.setAttribute("aria-pressed", String(isActive)); | ||
| }); | ||
| const status = document.querySelector("[data-sprites-tool-status]"); | ||
| if (status) { | ||
| status.textContent = `${toolName[0].toUpperCase()}${toolName.slice(1)} is active. Drawing stays in unsaved editor state for this page session only.`; | ||
| } | ||
| } | ||
|
|
||
| function paintCell(cell) { | ||
| const key = pixelKey(cell.dataset.spritePixelRow, cell.dataset.spritePixelColumn); | ||
| if (editorState.activeTool === "eraser") { | ||
| editorState.paintedPixels.delete(key); | ||
| cell.classList.remove("is-painted"); | ||
| } else { | ||
| editorState.paintedPixels.add(key); | ||
| cell.classList.add("is-painted"); | ||
|
Comment on lines
+57
to
+61
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For screen-reader users, painting or erasing a grid cell only changes the CSS class and draft count; the cell's accessible name/state remains just Useful? React with 👍 / 👎.
Comment on lines
+59
to
+61
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
After the Fill button is clicked, the toolbar and status leave Useful? React with 👍 / 👎. |
||
| } | ||
| updateDraftStatus(); | ||
| } | ||
|
|
||
| function fillGrid() { | ||
| const grid = document.querySelector("[data-sprites-pixel-grid]"); | ||
| if (!grid) { | ||
| return; | ||
| } | ||
| editorState.paintedPixels.clear(); | ||
| grid.querySelectorAll("[data-sprite-pixel-row]").forEach((cell) => { | ||
| const key = pixelKey(cell.dataset.spritePixelRow, cell.dataset.spritePixelColumn); | ||
| editorState.paintedPixels.add(key); | ||
| cell.classList.add("is-painted"); | ||
| }); | ||
| updateDraftStatus(); | ||
| } | ||
|
|
||
| function setGridSize(size) { | ||
| const grid = document.querySelector("[data-sprites-pixel-grid]"); | ||
| const status = document.querySelector("[data-sprites-grid-status]"); | ||
|
|
@@ -17,6 +85,8 @@ function setGridSize(size) { | |
| } | ||
|
|
||
| grid.replaceChildren(); | ||
| editorState.gridSize = size; | ||
| editorState.paintedPixels.clear(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a user has painted pixels and clicks the already-active 16x16/32x32 size button, the click still calls Useful? React with 👍 / 👎. |
||
| grid.dataset.spritesGridSize = String(size); | ||
| grid.setAttribute("aria-label", gridLabel(size)); | ||
|
|
||
|
|
@@ -26,11 +96,11 @@ function setGridSize(size) { | |
| const cell = document.createElement("button"); | ||
| cell.className = "sprite-canvas-cell"; | ||
| cell.type = "button"; | ||
| cell.disabled = true; | ||
| cell.setAttribute("role", "gridcell"); | ||
| cell.setAttribute("aria-label", `Pixel row ${row}, column ${column}`); | ||
| cell.dataset.spritePixelRow = String(row); | ||
| cell.dataset.spritePixelColumn = String(column); | ||
| cell.addEventListener("click", () => paintCell(cell)); | ||
| grid.append(cell); | ||
| } | ||
|
|
||
|
|
@@ -43,6 +113,7 @@ function setGridSize(size) { | |
| if (status) { | ||
| status.textContent = `Canvas display mode: ${size}x${size}. No pixel data is saved.`; | ||
| } | ||
| updateDraftStatus(); | ||
| } | ||
|
|
||
| function wireGridControls() { | ||
|
|
@@ -55,5 +126,22 @@ function wireGridControls() { | |
| }); | ||
| } | ||
|
|
||
| function wireDrawingTools() { | ||
| document.querySelectorAll("[data-sprite-tool-button]").forEach((button) => { | ||
| const toolName = button.dataset.spriteToolButton; | ||
| if (!DRAWING_TOOLS.includes(toolName) || button.disabled) { | ||
| return; | ||
| } | ||
| button.addEventListener("click", () => { | ||
| setActiveTool(toolName); | ||
| if (toolName === "fill") { | ||
| fillGrid(); | ||
| } | ||
| }); | ||
| }); | ||
| } | ||
|
|
||
| wireGridControls(); | ||
| wireDrawingTools(); | ||
| setGridSize(DEFAULT_GRID_SIZE); | ||
| setActiveTool(editorState.activeTool); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| # PR_26179_CHARLIE_025-sprites-basic-drawing | ||
|
|
||
| Team: CHARLIE | ||
| Workflow: stacked feature workflow | ||
| Base branch: PR_26179_CHARLIE_024-sprites-canvas-grid | ||
| Canonical ZIP path: dev/workspace/zip/PR_26179_CHARLIE_025-sprites-basic-drawing_delta.zip | ||
|
|
||
| ## Summary | ||
|
|
||
| Implemented basic Sprite Creator drawing for Pencil, Eraser, and Fill on the visible pixel canvas. Drawing state is page-session editor state only and is clearly labeled as unsaved. No product save, browser storage, API, DB, schema, or publishing behavior was added. | ||
|
|
||
| ## Branch Validation | ||
|
|
||
| PASS | ||
|
|
||
| - Current branch: PR_26179_CHARLIE_025-sprites-basic-drawing | ||
| - Based on: PR_26179_CHARLIE_024-sprites-canvas-grid | ||
| - No start_of_day files changed | ||
| - No DB/API/schema files changed | ||
| - No stale PR #219-#228 code copied | ||
|
|
||
| ## Requirement Checklist | ||
|
|
||
| | Requirement | Status | Notes | | ||
| | --- | --- | --- | | ||
| | Implement Pencil | PASS | Clicking a pixel paints it in unsaved editor state. | | ||
| | Implement Eraser | PASS | Clicking a painted pixel clears it. | | ||
| | Implement Fill | PASS | Fill paints the current grid. | | ||
| | Page-session editor state only | PASS | State lives in the module runtime only. | | ||
| | Clearly marked unsaved | PASS | Status copy labels unsaved editor state. | | ||
| | No product save | PASS | No save/load/publishing contract added. | | ||
| | No browser-owned authoritative product data | PASS | No browser storage or persistence added. | | ||
| | No DB/API/schema changes | PASS | Only UI/JS/CSS/test/report files changed. | | ||
|
|
||
| ## Validation Lane Report | ||
|
|
||
| Commands: | ||
|
|
||
| ```text | ||
| node --check assets/toolbox/sprites/js/index.js | ||
| node --check dev/tests/playwright/tools/SpritesToolShell.spec.mjs | ||
| git diff --check -- toolbox/sprites/index.html assets/toolbox/sprites/js/index.js assets/theme-v2/css/gamefoundrystudio.css dev/tests/playwright/tools/SpritesToolShell.spec.mjs | ||
| rg --pcre2 -n -i "localStorage|sessionStorage|indexedDB|<style|style=|<script(?![^>]+src=)|on(click|change|submit|input|load|error)=|imageDataUrl|local-mem|fake-login|MEM DB" toolbox/sprites/index.html assets/toolbox/sprites/js/index.js dev/tests/playwright/tools/SpritesToolShell.spec.mjs | ||
| npx playwright test dev/tests/playwright/tools/SpritesToolShell.spec.mjs --workers=1 --reporter=list --output=<temp> | ||
| ``` | ||
|
|
||
| Results: | ||
|
|
||
| - Node syntax checks: PASS | ||
| - `git diff --check`: PASS | ||
| - Guard scan: PASS, no matches | ||
| - Targeted Playwright: PASS, 1 test passed | ||
|
|
||
| ## Manual Validation Notes | ||
|
|
||
| 1. Open `/toolbox/sprites/index.html` from the stacked branch. | ||
| 2. Click a pixel with Pencil active and confirm it paints. | ||
| 3. Choose Eraser, click the painted pixel, and confirm it clears. | ||
| 4. Choose Fill and confirm the visible grid fills. | ||
| 5. Confirm copy says the state is unsaved editor state. | ||
|
|
||
| ## ZIP Path | ||
|
|
||
| `dev/workspace/zip/PR_26179_CHARLIE_025-sprites-basic-drawing_delta.zip` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new drawing code only makes painted pixels visible through this
.is-paintedrule, but/toolbox/sprites/index.htmllinks onlyassets/theme-v2/css/theme.css, andtheme.cssdoes not importgamefoundrystudio.css(repo-wide search also found no runtime import of this file). In the actual Sprite Creator page, clicking Pencil/Fill will add the class and update the count, but the pixel background will not change, so the core drawing behavior is effectively invisible to users.Useful? React with 👍 / 👎.