- JavaScript 63.4%
- PHP 13.6%
- CSS 12.5%
- Python 8.1%
- HTML 2.4%
| js | ||
| server | ||
| app.js | ||
| app.js.bak | ||
| index.html | ||
| index.html.bak | ||
| README.md | ||
| README.md.bak | ||
| styles.css | ||
| styles.css.bak | ||
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 library.
- 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.leftis represented asmirror. - 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 Fontfirst. 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 / Clearwrap 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 worldexport 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 reportfor review/debug data. - Added
Clear reportsto 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
publishedAtand consumes one quota slot.
Server-side periodic rotation code is in server/rotation_worker.py.
Example:
python server/rotation_worker.py world.json --write
It performs:
- Permanent-hide marking for extremely downvoted objects.
- Randomly samples 50 hidden historical objects.
- Republishes the top 20 by upvote count.
- Reapplies the active display cap.
- Adds permanent-hidden objects to
adminReviewQueuefor 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 Library.
- 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 Library.
- 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
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
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.