Skip to content

Refactor Pixel Forge into modular app architecture with persistence, PWA baseline, accessibility, and export enhancements - #1

Merged
TalaeiDev merged 3 commits into
mainfrom
copilot/refactor-dungeon-designer
Sep 5, 2026
Merged

TalaeiDev merged 3 commits into
mainfrom
copilot/refactor-dungeon-designer

Conversation

Copilot AI commented Sep 5, 2026 •

Copy link
Copy Markdown
Contributor

The dungeon designer was constrained by a single 2.6k+ line HTML file, making iteration and reliability difficult. This change restructures the app into modular assets and adds missing production features: persistence, offline/PWA support, accessibility upgrades, responsive breakpoints, and broader export capabilities.

  • Architecture split (monolith → modules)

    • Added index.html as the primary entrypoint and split styles/scripts into:
      • styles/theme.css, styles/layout.css, styles/components.css
      • js/app.js, js/canvas.js, js/tools.js, js/state.js, js/utils.js, js/storage.js
    • Converted pixel-forge-page.html into a redirect shim to index.html for compatibility.
  • Persistence and project lifecycle

    • Added localStorage-backed autosave (30s cadence), manual save, and restore-last-project.
    • Added save status + project filename indicators in header.
    • Extended serialized state with metadata (projectName, timestamps).
  • Export/import capabilities

    • Kept JSON export/import and hardened import validation/messages.
    • Added PNG export and SVG export paths via js/canvas.js.
  • PWA and offline baseline

    • Added manifest.json, service-worker.js, and app icon.
    • Registered service worker and wired install prompt flow.
    • Included PWA/mobile meta tags in index.html.
  • Accessibility and UX

    • Added ARIA labeling defaults for interactive controls and live region status updates.
    • Added keyboard-shortcuts modal and Escape-to-close behavior.
    • Added focus-visible styles for keyboard navigation and improved workspace semantics.
  • Performance and responsiveness

    • Added requestAnimationFrame throttling for mini-map redraw scheduling.
    • Added debounced connection refreshes during drag/resize.
    • Added responsive breakpoints at 768px, 480px, and 320px (in addition to existing compact behavior).
// autosave loop + stateful persistence
setInterval(() => {
  if (!dirtySince) return;
  persistProject(true); // localStorage snapshot + timestamped status update
}, 30000);

// frame-friendly rendering
const scheduleMiniMapUpdate = window.PixelForgeUtils.rafThrottle(() => {
  window.PixelForgeState.metrics.miniMapRenders += 1;
  updateMiniMap();
});

Copilot AI and others added 2 commits September 5, 2026 20:20
Co-authored-by: TalaeiDev <90834494+TalaeiDev@users.noreply.github.com>
Co-authored-by: TalaeiDev <90834494+TalaeiDev@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor Pixel Forge dungeon designer into modular structure Refactor Pixel Forge into modular app architecture with persistence, PWA baseline, accessibility, and export enhancements Sep 5, 2026
Copilot AI requested a review from TalaeiDev September 5, 2026 20:25

@TalaeiDev TalaeiDev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update page performance and structure

@TalaeiDev
TalaeiDev requested a lite review from Copilot September 5, 2026 20:32
@TalaeiDev
TalaeiDev marked this pull request as ready for review September 5, 2026 20:34
@TalaeiDev
TalaeiDev merged commit 5272898 into main Sep 5, 2026
1 check passed
@TalaeiDev
TalaeiDev deleted the copilot/refactor-dungeon-designer branch September 5, 2026 20:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There are a few correctness/robustness and accessibility gaps in the new offline caching, persistence error-handling, and exported SVG/PNG output that should be addressed before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR refactors Pixel Forge from a single large HTML file into a modular static app (separate CSS/JS), and adds baseline production features including persistence, export improvements, and PWA/offline support.

Changes:

  • Split UI styling into styles/* and core behavior into js/*, with index.html as the main entrypoint and pixel-forge-page.html as a redirect shim.
  • Added persistence via localStorage autosave/manual save + status indicators, plus PNG/SVG export helpers.
  • Added PWA baseline: manifest.json, service-worker.js, install prompt wiring, and an app icon.
File summaries
File Description
styles/theme.css Adds theme variables, focus-visible outlines, and sr-only helper.
styles/layout.css Defines the app grid layout, panels, and workspace base styling.
styles/components.css Adds/organizes component styles (rooms/doors/hallways, tooltips, modal, breakpoints).
service-worker.js Introduces offline cache + fetch caching behavior for PWA baseline.
README.md Updates docs to reflect modular structure, features, and development notes.
pixel-forge-page.html Converts prior monolith page into an index.html redirect shim.
manifest.json Adds basic PWA manifest metadata and icon.
js/utils.js Adds shared debounce/raf-throttle/download/time helpers.
js/tools.js Adds install prompt binding and service worker registration helpers.
js/storage.js Adds localStorage JSON helpers and shared keys.
js/state.js Adds a lightweight metrics store for runtime counters.
js/canvas.js Adds SVG/PNG export helpers.
js/app.js Main editor logic, persistence/autosave, accessibility defaults, and performance scheduling.
index.html New primary app shell with PWA meta, controls, modal, and script/style includes.
icons/icon.svg Adds an app icon for the manifest/favicon.
Review details

Suppressed comments (2)

index.html:85

  • The mini-map canvas has no accessible name; the JS fallback will end up using the element id ("miniMapCanvas"), which is not user-friendly for assistive tech.
            <div class="mini-map" id="miniMap">
                <div class="mini-label">🗺️ Overview</div>
                <canvas id="miniMapCanvas"></canvas>
                <div class="mini-viewport" id="miniViewport"></div>

index.html:204

  • The shortcuts modal is missing dialog semantics (role/aria-modal) and an aria-labelledby hook, which makes it harder for screen readers to announce the modal context and title correctly.
    <div id="shortcutsModal" class="modal" aria-hidden="true">
        <div class="modal-content">
            <h2>Keyboard shortcuts</h2>
            <p>1 Draw · 2 Select · 3 Door · 4 Hallway</p>
            <p>Ctrl+Z Undo · Ctrl+Y Redo · Ctrl+D Duplicate · Del Delete</p>
  • Files reviewed: 13/15 changed files
  • Comments generated: 4
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread index.html
Comment on lines +38 to +39
<button id="deleteButton" class="danger">✕</button>
<button id="clearButton" class="danger">🗑</button>
Comment thread js/canvas.js
Comment on lines +29 to +38
buildSvg(node) {
const width = Math.max(1, node.scrollWidth);
const height = Math.max(1, node.scrollHeight);
const clone = node.cloneNode(true);
clone.style.transform = 'none';
clone.querySelectorAll('.grid-layer,.room-tooltip,.context-menu,.mini-map').forEach((el) => el.remove());
const serializer = new XMLSerializer();
const body = serializer.serializeToString(clone);
return `<?xml version="1.0" encoding="UTF-8"?>\n<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><foreignObject x="0" y="0" width="100%" height="100%">${body}</foreignObject></svg>`;
}
Comment thread js/storage.js
Comment on lines +16 to +18
saveJSON(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
Comment thread service-worker.js
Comment on lines +34 to +43
self.addEventListener('fetch', (event) => {
if (event.request.method !== 'GET') return;
event.respondWith(
caches.match(event.request).then((cached) => cached || fetch(event.request).then((response) => {
const responseClone = response.clone();
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, responseClone));
return response;
}).catch(() => caches.match('./index.html').then((response) => response || Response.error())))
);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants