Patch Notes

Summary of recent updates to Mazegen.

March 2026

Performance improvements

  • Replaced broad CSS transitions with explicit property lists to reduce style recalculation during hover and focus.
  • Reduced backdrop blur intensity on dropdown menus for faster compositing.
  • Main canvas now uses GPU-accelerated rendering by default; only canvases that need frequent pixel reads opt into software mode.
  • Cached layout measurements during drag operations to eliminate redundant reflows in mask editor, modal splitters, workspace splitter, and color dropper.
  • Removed duplicate image loading during config import.

Canny edges, blend weights & performance

  • Canny edge detection: Processed mask and maze walls now match the edge preview (adaptive thresholds, hysteresis binarization, fixed intermediate resolution). Edge thickness slider affects maze walls in line with the preview; range reclamped.
  • Blend weight sliders: Edges, Dots, and Lines weights use full 0–100 range with linear mapping. Removed 50–100 clamp and sqrt curve so weights are respected in all blend modes.
  • Cell-size regen: Changing maze cell size or rows/cols no longer triggers multiple regens. Endpoint defaults update silently; pattern bias is resized for size-only regens; applyPatternToGrid() runs once per regen; solvability retries only re-run makeMaze() with a restored grid snapshot.
  • Performance: Pattern settings preview debounced; morphology (dilate/erode) and cell rendering optimized; Canny resolution and percentile (histogram) tuned; redundant strength pass removed.
  • Bug fix: Fixed const timing redeclaration in generator.js (renamed second use to regenTiming) that caused parse failure and newMaze is not defined.

Google Fonts on canvas

  • Google Fonts now render correctly when generating the maze (text walls). The chosen typeface appears on the canvas instead of a fallback font.
  • Font loading is awaited and the stylesheet is injected when needed so the selected font is ready before the maze is drawn.
  • Fixed Google Fonts URL encoding and chunked requests so the CSS loads reliably (avoids MIME type / blocked resource errors).

P2P Multiplayer Rooms

  • Create or join rooms via Experimental menu. Real-time peer-to-peer connections using WebRTC. Share room links to invite others.
  • Persistent username across refreshes via localStorage so you keep your display name when reconnecting to the same room.

Room Chat

  • Built-in chat in the Room modal and a floating desktop chat widget. Messages are sent directly between peers (no server relay).
  • Rate limiting and input sanitization for safety.

Maze Sharing

  • Send or request maze configurations from peers. Full config transfer over WebRTC data channels with progress feedback.

Match Lobby

  • Invite peers to play mode matches. Vote on whose maze to play, ready-up system, countdown, and synchronized match start.

Draw Mode

  • Lock the maze and draw/erase walls (thin edges or thick blocked cells) with freehand or line tools. Undo/redo history.
  • Solvability protection prevents unsolvable edits.

Live Cursors

  • Figma-style real-time cursor sharing. See other users' pointer positions on the canvas with colored arrows and name labels.
  • Draw mode tool state is broadcast alongside position.

P2P Connection Hardening

  • Deterministic WebRTC initiator, ICE restart and full reconnect on failure, stale callback guards.
  • Signaling server rate limiting, room size cap (8 peers).

Maze Samples

  • Maze Samples gallery: File → Maze Samples opens a modal of pre-made maze configs. Click a sample to load its full configuration (images, settings, layout) and close the modal.
  • Sample assets live in assets/maze-samples/configs/ (JSON) and assets/maze-samples/thumbnails/ (images). Thumbnails keep aspect ratio and don't stretch in the grid.
  • On mobile: Maze Samples button now closes the nav drawer on click (same as other drawer items). The Maze Samples modal is full-screen (100vw × 100dvh) on viewports ≤901px.

Save/export and canvas dimensions

  • Save Config: Full and lightweight save both prompt for a filename before download, with a default name pre-filled (e.g. maze-config-…). Cancel skips the download.
  • Export Image: The Export Maze as Image modal has a File name field; it's filled with a default when the modal opens and the extension updates when you change image format.
  • Lock aspect ratio: Checkbox next to maze width/height in Maze Size (Canvas tab) and in Easy Mode. When checked, changing one dimension updates the other to keep the same ratio; preference is shared and saved in config.
  • Auto (fit viewport): When enabled, the dimensions panel and lock-aspect-ratio checkbox are hidden instead of disabled. The help (?) button sits next to the "Canvas dimensions (px)" section title.

February 2026

Solvability & orphan cells

  • Orphan bridging: Single O(n) pass after mask application eliminates unblocked cells with no flat-side neighbor — either unblocks one cardinal neighbor to bridge or re-blocks the orphan so mazes stay solvable.
  • Reachable endpoints: Manual start/finish snap to the nearest reachable cell (at least one unblocked cardinal neighbor); findNearestUnblocked in generation also requires a reachable neighbor so endpoints never land on isolated cells.
  • If 3 regeneration attempts still fail, an alert modal suggests fixes (move endpoints, change mask, increase grid size).

Feature gating & grid stats

  • Max playable rows/columns: Tracked after mask application; Image and Text menus (and their Reset buttons) disable when either max is under 50 cells, with tooltips explaining why.
  • Centralized updateFeatureGating() combines grid-size and image-upload checks; disabled buttons show guidance (e.g. "Requires at least 50 cells…" or "Upload an image first").

Performance — BFS & neighbors

  • isSolvable BFS: ring-buffer index instead of q.shift(), inlined 4-direction traversal — no per-cell array allocations.
  • getAllNeighborCoords: Reusable scratch buffer instead of .map(); findClosestEdgeCell uses squared distance (no Math.sqrt).
  • nearestReachableCell: Inlined cardinal checks with NEIGHBOR_OFFSETS instead of getAllNeighborCoords per cell.

Text Editor — Color Dropper

  • Color dropper to pick fill or stroke from the maze canvas.
  • Custom canvas-snapshot approach (no EyeDropper API) for broad browser support.
  • Full-screen overlay shows maze snapshot; tap or click to sample pixel color; applied color updates the active layer's fill or stroke.
  • Dropper buttons (eyedropper icon) next to Fill and Stroke in the Color tab.
  • Live loupe magnifier (11×11 region) with correct coordinate mapping for object-fit: contain.
  • Mobile-friendly: loupe offset for touch, large cancel button, touch-action: none on overlay.

Performance — Debounced maze regeneration

  • scheduleRegen now debounces with a 200ms window — rapid input changes batch into a single regen.
  • Added scheduleRegenImmediate for callers that need instant regen (presets, resets, modal applies).
  • Text editor inputs: stopPropagation on both input and change events in bindInspector prevents double-regen when Live mode is on.
  • Opt-in timing instrumentation (window._mazeDebugTiming) for text mask rendering and cluster-breaking.

Text Editor — Max cluster / hollow text

  • Per-layer Max Cluster setting: randomized walker carves paths through text clusters exceeding the threshold.
  • Enables hollow/playable text effects — maze paths run inside large letterforms.
  • Cluster-breaking isolated to text-blocked cells only; non-text blocked areas are preserved.

Text Editor — Tabbed settings & streamlined properties

  • Tabbed interface (Font, Layout, Color) using existing tab pattern; removed shadow, blend, opacity, align controls — alignment hardcoded to center.
  • Per-layer text color renders in the maze via per-pixel color map; white fill acts as path mask (bubble/outline effects).
  • Configurable white mask tolerance (Mask Tol) per layer.
  • Two-pass stroke rendering (stroke first, fill second) for clean perimeter outline.

Text Editor — Full redesign

  • Layer-based WYSIWYG text editor: two-pane layout (workspace + inspector), full layer CRUD, drag/scale/rotate on canvas.
  • Font, style, size, tracking, fill/stroke, max cluster, white mask tolerance; hybrid local + Google Fonts; font size 8–600px.
  • Text layers take priority over image pattern bias; aspect-correct text buffers; snap-to-grid and live preview.
  • Double-click to edit inline (textarea overlay); color dropper for fill/stroke from maze.

Placement modal, maze settings, flash & cell rendering

  • Placement: Live Preview runs full regen; auto-disables on modal close; Apply hides while Live Preview is on.
  • Maze Size: Canvas / Cell size / Shape tabs are UI-only (no regen on switch); Shape Fit default Fit inside; outside-mask single color picker.
  • Flash: Overlay redraw throttled; overlapping flash loops prevented; redundant trace() removed.

Maze generation & bug fixes

  • Wall removal: Random vertical openings and dead-end breaker scale with grid size (e.g. small grids get proportionally lower removal).
  • Fixed text rasterizer var redeclaration; text mask aspect-correct buffers; malformed scrollbar selectors; placement live preview state; generator.js var causing SyntaxError; mobile play button; cell size (px) and change-only inputs after number-stepper event restore.
  • Number stepper component and resizable sidebar/workspace splitter (matchMedia-aware on mobile).

Endpoint confirmation panel

  • Confirm / Try again: Moved out of the Endpoints modal into a small floating panel that appears near your selected cell (above, below, or beside the teal preview based on canvas quadrant).
  • Endpoints modal: Stays closed while you pick a cell and confirm; re-opens only after you click Confirm or the panel's X. Try again keeps you in selection mode without re-opening the modal.
  • Panel: Header with X (same as other modals); Confirm and Try again buttons in a compact panel positioned to avoid overlapping the preview or going off-screen.

Shape mask & endpoints

  • Manual start/finish: With shape mask and pattern image, manually selected start/finish cells are no longer moved to the mask edge; your selection is kept.
  • Negative space: Clicking outside the maze area (e.g. in the black area around a heart shape) to set start/finish is now rejected with a message instead of being accepted.

Custom maze dimensions & cell size control

  • Custom dimensions: Set canvas width and height directly for full control over maze size (e.g. 900×600).
  • Cell size or row/column counts: Maze Size & Shape lets you choose between specifying cell size (px) or row and column counts; switch depending on whether you want fixed cell pixels or a fixed grid resolution.
  • More precise control over cell size and grid density for different export and layout needs.

Endpoints, canvas selection & color/style

  • Endpoints: Place start/finish by clicking the canvas and confirming, or use automated placement.
  • Canvas selection fix: "Select start/finish on canvas" now aligns correctly when using manual canvas dimensions (e.g. 900×600).
  • Color & Style: Walls and Cells & background merged into one section; wall thickness moved to Maze Size & Shape → Cell size. Switching between Wall color, Cell/path color, and Outside mask tabs no longer triggers maze regeneration.

Start/End flash, zoom 10–500%, preset save/upload

  • Start/end flash: Green and gold pulsing rings highlight start and finish after generation or via Help → Flash Start / End.
  • Zoom: Range expanded to 10%–500%.
  • Start/end defaults: Top-left and bottom-right by default; reset to corners on page load, when mask is turned off, or when invert mask is turned on.
  • Preset save/upload: Each preset dropdown (Maze size, Endpoints, Background, Wall, Filters, Blend, Edges, Dots, Lines) has Save and Load icons to export/import that section's settings as JSON.

Pattern mask, shape masks, solvability

  • Pattern image mask: Uses background-removal mask directly for clean boundaries.
  • Shape masks: Circle, heart, hexagon, etc. fixed; work regardless of background removal.
  • Closed cells: Disconnected regions are bridged so mazes are fully traversable.
  • Start/end in mask: Start and end are forced inside mask bounds; waypoints constrained to mask.
  • Solvability: Guaranteed solvable mazes; emergency path carving when needed.
  • Shape size: Slider maximum increased (up to 1000%).