pixel drawer
  • JavaScript 63.4%
  • PHP 13.6%
  • CSS 12.5%
  • Python 8.1%
  • HTML 2.4%
Find a file
2026-06-02 21:43:57 +09:00
js updated 2026-06-02 21:43:57 +09:00
server updated 2026-06-02 21:43:57 +09:00
.gitignore split 2026-06-02 17:19:36 +09:00
app.js updated 2026-06-02 21:43:57 +09:00
index.html updated 2026-06-02 21:43:57 +09:00
README.md split 2026-06-02 17:19:36 +09:00
styles.css updated 2026-06-02 21:43:57 +09:00

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.

Refactor layout

  • app.js remains the browser bootstrap and main UI coordinator.
  • js/core-utils.js, js/state-index.js, js/rotation-policy.js, and js/lighting.js hold reusable logic shared by the app.
  • js/editor-actions.js is lazy-loaded when Pixel Studio opens; the app keeps inline fallbacks for first-use safety.
  • Server rotation defaults can be supplied with server/rotation_policy.json and --config.
  • Server policy tests live in server/test_rotation_worker.py.

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:

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

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.

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.

v16b hotfix

  • Fixed the dark/blank world regression caused by using source-in compositing directly on the main world canvas for ship water reflection.
  • Ship reflections are now precomposited on an offscreen canvas before drawing, so terrain and sprites are not erased or darkened.