# Pixel Island Summoner Browser-only prototype for a shared pixel-art island. ## Run Open `index.html` in a modern browser. No build step or third-party dependency is required. ## Current prototype scope - Draw pixel assets in the in-browser editor. - Save assets to the local collection. - Place static assets and summon dynamic assets onto the island. - Dynamic assets default to right-facing on spawn; left-facing is rendered by mirroring during movement only. - Local voting, hiding, remix/copy edit, and import/export tools are included. ## Phase 1 changes - Asset data is normalized to schema 2+ compatible shape. - Dynamic left-facing pixels are not stored; `faces.left` is represented as `mirror`. - Empty depth/light metadata is omitted or normalized. - Editor tools include Draw, Erase, Fill, Pick, Undo, and Redo. ## Phase 2 changes - Local save uses a compact Phase 2 envelope in `localStorage`. - Pixel planes are bbox-cropped and RLE-compressed when this is smaller than raw cropped data. - Compact asset bundles can be exported separately from world snapshots. - World snapshots contain placements, dynamic summons, and an asset manifest rather than full asset blobs. - Local object/asset mutations append small sync events to `eventLog`. - IndexedDB asset/snapshot cache helpers are included for future server-backed missing-asset fetches. ## Phase 3 changes - Terrain rendering is chunk-cached instead of using one large terrain canvas. - Only terrain chunks intersecting the current viewport are drawn. - Static and dynamic objects outside the viewport margin are culled before sprite generation/sorting. - Dynamic runtime updates are stepped at 15 Hz and capped per frame to avoid spiral-of-death on slow devices. - Rendering pauses while the browser tab is hidden and resumes on visibility change. - Tile/object lookups use a small spatial index for inspect, erase, and nearby-target searches. - Data tab reports visible terrain chunks for quick performance inspection. ## Phase 4 changes - Editor schema is now 5. - Added Line and Rect tools. Rect supports filled rectangles with Shift; right-click erases line/rect cells. - Added Select tool. Drag to select a rectangular area, then drag the selection or use arrow keys/buttons to move it. - Nudge buttons move the active selection; without a selection they shift the whole drawing. - Added horizontal/vertical flip, palette-colored outline generation, and clear selection. - Added editor PNG export/import. PNG import quantizes the image to the current island palette and current canvas size. - Added keyboard shortcuts: B/E/F/I/L/R/S for tools, Ctrl/Cmd+Z/Y for history, arrows for moving selected pixels, Escape to clear selection. ## Export formats - **Export full JSON**: human-readable full local state. - **Export compact**: compact local state suitable for saving/transferring. - **Export snapshot**: placement state plus asset manifest; requires asset bundles or cache to render fully. - **Export asset bundle**: compact asset blob list for missing-asset transfer. ## Phase 4 follow-up adjustments - PNG import now chooses the editor canvas size from the image size. Square 8/16/32/64 PNGs import at their native size; other sizes are fit into the nearest supported square canvas. - Depth is now three-state: high, normal, and low. High brightens sprite pixels; low darkens them. - Right-clicking the world canvas clears the current map selection instead of moving or placing the selected asset. - Dynamic sprites now pause intermittently instead of walking continuously. - Night rendering is darker. - Object picking now uses sprite-sized, per-opaque-pixel hit testing, so transparent pixels are not clickable. - The CSS font stack now tries `3x5 MT Pixel Font` first. The font file itself is not bundled. ## Phase 5 changes - Editor schema is now 7. - Fixed the Advanced Draw depth controls so `Depth / High / Low / Clear` wrap inside the drawer instead of overflowing to the right. - Added Phase 5 guardrails in the Data tab: - local asset/object volume counters, - duplicate-content count, - orphan placement checks, - terrain compatibility checks, - hidden/report counters. - Added `Validate world` export for pre-server integrity checks. - Added local object reporting from the selection bubble. Reported objects are hidden locally and stored in a local moderation report log. - Added `Export moderation report` for review/debug data. - Added `Clear reports` to clear local report logs without un-hiding already hidden objects. - Added soft local guardrail limits: 160 assets and 220 world objects. Existing objects can still be moved; new saves/placements are blocked when the local cap is reached. ## Phase 5 follow-up changes - Static sprites now anchor closer to the center of their tile instead of the front corner. - Object selection is pixel-accurate: transparent sprite cells no longer select the object, and tile inspection does not select hidden/transparent areas. - Right-clicking the map clears selection silently. - Hidden panel now lists both hidden library assets and hidden map objects. Objects hidden by Report appear there and can be restored with Show again. - Report now opens a reason dialog with Cancel and Report + Hide actions. - Library cards include Place/Move, which makes dynamic human assets easier to reposition. - Default bundled pixel art was replaced with a new set: Hill Cottage, Pine Cluster, Shell Rock, Wave Skiff, Fisher Kid, Moss Cat, Koi Fish, and Cloud Gull. - Added a static Ship role/subtype. Ships can be placed on water, float subtly, and periodically emit ring ripples. - Local storage key was bumped to load the new default set in this prototype build. ## Phase 5 polish - Night lights now draw after the darkness overlay and use fixed bright cores/halos, so lamp pixels visually ignore the night darkening pass. - The sky color now transitions quickly around dawn and dusk. Day and night remain mostly stable instead of drifting continuously. ## Phase 5 Effects - Nearby objects receive a faint surface glow from adjacent light sources. - Light cores are less dazzling, while night ambient darkness is lifted slightly. - Land-moving dynamic sprites emit small terrain-colored step particles. ## Visual FX follow-up - Step particles now vary in hue / saturation / lightness around the terrain color. - Nature assets shed tiny drifting leaf/petal dots. - Coast foam uses two slow-rotating porous bluish-white layers. - Depth now affects phase-aware sprite shading for sun/moon exposure. - Added toggles for lights, particles, and the day-night cycle. ## Phase 5 UI / particle follow-up - Coastal foam no longer uses cut-out holes. - Walking particles are less frequent and use more visibly varied colors. - Remix always creates a new derivative asset; Edit updates the user's own original asset. - Advanced Draw now includes configurable particle emitter cells for any asset. - PNG export/import moved to the Data tab. - Nudge arrow buttons under the canvas were removed; keyboard arrow nudging remains. - UI text is larger overall, while palette color-code labels keep their small size. ## Rotation policy build This build adds count-based island rotation. - Default island display cap: 250 objects. - The local display cap is adjustable from Data > Visual settings. - Objects are not deleted when the cap is exceeded; the effective oldest objects are omitted from the island display. - Upvotes delay rotation-out by slot adjustment. Downvotes advance rotation-out. - Local publish / republish quota: 5 objects per author per rolling hour. - Replacing or republishing a rotation-hidden object updates its `publishedAt` and consumes one quota slot. Server-side periodic rotation code is in `server/rotation_worker.py`. Example: ```bash python server/rotation_worker.py world.json --write ``` It performs: 1. Permanent-hide marking for extremely downvoted objects. 2. Randomly samples 50 hidden historical objects. 3. Republishes the top 20 by upvote count. 4. Reapplies the active display cap. 5. Adds permanent-hidden objects to `adminReviewQueue` for deletion checks. ## Local-only rotation note This build does not call a server from the browser. The island display cap is applied client-side, and objects over the cap are kept in local save but not drawn. Server recirculation / permanent hiding only happens when `server/rotation_worker.py` is run against exported world JSON. ## Exhibition Policy Revision This build separates **Asset** and **PlacementObject** more explicitly. - Asset: a durable library work. Remix only copies pixels and lineage into the canvas. - PlacementObject: a temporary island exhibition object. It can rotate out while the Asset remains in Collection. - Edit has been removed. To revise a work, remix/copy it, save a new Asset, then delete the old one if desired. - Publishing requires a prototype local account. The first 24 hours allow 5 public placements/hour; day 2+ allows 10/hour. - The island exhibition has 250 visible slots: 150 newest slots and 100 random revival slots. - Upvote rank effect is capped at +50 votes. - Capacity rotation and extreme downvote rotation use the same user-facing explanation: the island exhibition is full, but the work remains in Collection. - Server moderation can mark `permanent_hidden` / `violation_hidden`; these are hidden from authors and viewers. Admins can restore them with the Python worker. - Particles are disabled offscreen/when zoomed out and capped at 200 active particles. ### Server worker ```bash python server/rotation_worker.py world.json --write python server/rotation_worker.py world.json --restore object123 --write python server/rotation_worker.py world.json --hide-violation object123 --write ``` The Python worker is the authoritative production policy. The browser mirrors it only for local prototype use. ### Compression lab ```bash python server/compression_lab.py exported_world.json ``` Use this to compare minified JSON, gzip, zlib, and Brotli when available. Production should use the compact asset codec plus HTTP gzip/Brotli rather than hand-rolled custom compression first. ## Phase 5 Exhibition UI polish follow-up - Compressed the account/name card so the top HUD uses less vertical space. - Removed the right-side Pan / Place / Erase HUD; placement is guided through Save + Place and Library actions. - Renamed the liked codex label to Favorite. - Removed the Advanced Draw depth Clear button; depth can still be cleared with Shift/right-click. - Normal Erase now removes Light / Particle / Depth metadata on the first click and removes the pixel color on the next click. - Light rendering and nearby glow are night-only, with subtle random flicker. - Remix previews hide the nearby source work while checking placement, and final placement nudges away from the remix source to avoid doubled sprites. - Depth edge shading now reacts to configured light positions or the current sun/moon direction; object silhouette edges are excluded. ## v8 polish notes - `Save + Place on Island` now auto-generates a local account when needed. The generated account stores an ID, editable display name, and generated password in local storage; users are prompted to change the password. - `Check on Island` and `New` were removed from the finish area. Saved works enter an island placement preview with `Place here` and `Back to canvas`. - Editor Select now clears with right-click. The island also shows the left-click/right-click selection hint. - Basic draw buttons keep a stable layout even when Advanced is open; advanced tools are placed below them. - Draw tools now have distinct colors and compact icons. - Particle editing no longer paints emitter positions. Particle effects emit from the whole sprite, with palette-based color and up/down/left/right direction. ## v9 interaction polish and bug fixes - Removed automatic remix-source avoidance: remix children can now be placed near their source without being forced to a different tile. - Animated coastal foam with drift, bob, scale, and opacity pulses. - Removed Collection/Create buttons from the Pixel Island title bar and added a compact cute menu button for the left drawer. - Added a confirmation dialog before clearing the entire canvas. - Palette swatches now handle pointerdown directly so the first palette click is applied reliably. - Particle right-click no longer disables the particle effect; right-click pans/does nothing, while Shift-click can disable. - Added particle range controls: select an area, then press “Use Sel”; “Whole” resets emission to the whole sprite. - Swapped Particle and Depth button order. - Left/Right canvas side buttons no longer mirror the editing canvas view. - Fixed dynamic animal placement preview so the sprite is visible before pressing Place here. ### v10 interaction / lighting polish - Replaced the title-side menu control with a larger bottom `DRAW` button. - Warmed the evening phase with orange/vermilion sky tint and warm darkness overlay. - Increased lamp reflection bleed radius and light radius so nearby sprites glow more softly. - Dynamic sprites now save a canvas marked `Left` by mirroring it into the canonical right-facing asset; runtime facing is driven by the actual movement vector. - Hidden particle range overlays no longer look like an undeletable blue canvas square; the range overlay is shown only while the Particle tool is active. - Remix actions are now displayed as a bottom sheet. Report is inside a small Menu section. - Added teleport-to-remix-source from the selected object sheet. - Object draw order now uses the rendered bottom/contact line, so lower objects consistently draw in front. - 8×8 sprites use their whole sprite bounding box for click selection, including transparent cells. - Coastal foam motion was made more visible. ## v12 lighting/compression notes - Night light reflections are now rendered per sprite immediately after the sprite, preserving front/back draw order. - Reflection tint affects both depth and non-depth pixels; depth pixels receive stronger directional response. - Depth no longer uses light-source response unless the night lighting system is actually active. - Strong compression direction for weak servers: store indexed palette pixels as bit-packed palette indices plus an alpha bitmask and RLE/LZ on top; avoid PNG/base64 as the canonical server payload. ## v13 compression and remix lineage changes - Palette index encoding is the canonical pixel format. Each pixel stores `.` for transparent or a one-character palette code. - Compact export now supports `bp6`, a 6-bit packed plane format. Transparent plus the 62 palette codes fit in one 6-bit value. - Compact export chooses the smallest representation per pixel plane: cropped raw, cropped RLE, or cropped 6-bit packing. - Remix delta storage was removed again; remixes are stored as independent packed pixel planes. - Deleting a source asset now cascades through remix descendants. Their island placements, dynamic summons, votes, hidden flags, and moderation rows are removed together. - Sync events now include `asset.delete`; applying that event also cascades to remix descendants on the receiver. ## v14 rollback / interaction polish - Removed remix delta saving and remix-source cascade deletion. - Particles are cell-based again, like Light and Depth: choose color + direction, then paint emitter cells. - Selected dynamic sprites bounce too, with a slight deterministic tilt. - The object speech bubble is kept above the object and away from the DRAW dock. - Added a compact clock in the upper-right corner. - Reworked daylight/moonlight shadow transitions so evening fades sun shadows out before night, moon shadows fade in during night, and pre-dawn moon shadows disappear before sunrise. ## v14b startup fix - Restored `updateSelectedLabel()` so bootstrap no longer throws `ReferenceError`. ## v15 interaction polish - Restored object speech bubbles above the actual rendered sprite, using sprite draw coordinates instead of tile-center estimates. - Replaced the numeric clock with a fixed analog day-night clock using a sky-color conic gradient and no numbers. - Kept selected-object shadows mirrored from the ground line while the sprite jumps. - Smoothed sky and overlay interpolation across dawn, day, evening, and night.