pixel/README.md

303 lines
19 KiB
Markdown
Raw Normal View History

2026-06-04 14:37:03 +09:00
# Pixel Island
2026-06-01 18:26:09 +09:00
2026-06-01 22:48:15 +09:00
Browser-only prototype for a shared pixel-art island.
2026-06-01 21:17:09 +09:00
## Run
2026-06-01 18:26:09 +09:00
2026-06-01 22:48:15 +09:00
Open `index.html` in a modern browser. No build step or third-party dependency is required.
2026-06-01 18:26:09 +09:00
2026-06-02 17:19:36 +09:00
## 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`.
2026-06-01 22:48:15 +09:00
## Current prototype scope
2026-06-01 18:26:09 +09:00
2026-06-01 22:48:15 +09:00
- Draw pixel assets in the in-browser editor.
2026-06-02 16:26:44 +09:00
- Save assets to the local collection.
2026-06-01 22:48:15 +09:00
- 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.
2026-06-03 18:47:09 +09:00
- Local voting, hiding, remix/copy edit, and collection management are included.
2026-06-01 18:26:09 +09:00
2026-06-01 22:48:15 +09:00
## 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.
- 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.
## 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 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.
## Phase 4 follow-up adjustments
- 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.
2026-06-02 00:05:03 +09:00
## 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 local object reporting from the selection bubble. Reported objects are hidden locally and stored in a local moderation report log.
- 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.
2026-06-02 02:35:22 +09:00
## 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.
- 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.
2026-06-03 18:47:09 +09:00
- The local display cap is adjustable from Settings.
2026-06-02 02:35:22 +09:00
- 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.
2026-06-02 16:26:44 +09:00
- PlacementObject: a temporary island exhibition object. It can rotate out while the Asset remains in Collection.
2026-06-02 02:35:22 +09:00
- 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.
2026-06-02 16:26:44 +09:00
- Capacity rotation and extreme downvote rotation use the same user-facing explanation: the island exhibition is full, but the work remains in Collection.
2026-06-02 02:35:22 +09:00
- 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.
2026-06-02 16:26:44 +09:00
## 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.
2026-06-02 17:19:36 +09:00
## 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.
2026-06-02 23:45:38 +09:00
## Phase 6 create-layout / authority prep
- The Create tab editor now follows the tighter canvas-first layout: top metadata row, canvas with a vertical palette, large tool buttons, and a full-width Advanced settings panel.
- The palette ramps were rebuilt into cleaner 4-color rows so hue/lightness progression is easier to read.
- Local browser data uses a new storage key so older palette-corrupted art is discarded automatically.
- Shared-world prep now treats publish, object move, day/night time, and spontaneous dynamic motion as server-authoritative concerns.
- The client can keep pending shared publish/move visuals locally while waiting for server validation, and dynamic runtime motion can interpolate toward server-supplied target positions.
## Phase 6b server-authority / Create tab correction
- CREATE layout now groups the canvas and primary tools in the left column with the palette as the right column, matching the attached design more closely.
- Save schema was bumped to 15. Existing local art data from older palette mappings is intentionally reset and replaced with new seed artwork.
- Added server-side `world.phase` and `dynamic.move` event helpers/tests. Shared clients should treat these events as the source of truth for day/night and autonomous dynamic positions.
- Pending shared object moves now render as temporary local interpolation only; the persistent world state is updated only by server-issued events.
- Depth shading can now use a cursor-local light source on rendered sprites at night.
2026-06-03 03:13:14 +09:00
## Custom update 3: colored local light fix + heritage/masterpiece gallery
- Save schema is now `25`.
- Fixed the local depth-light wash so the affected area no longer collapses into a mostly gray band; local lights now preserve more of the source color.
- Reworked depth local-light behavior so the source itself and nearby outer/depth corners catch the strongest highlights, while distance has a weaker effect on brightness than before.
- Reduced the selection bubble offset so the bubble sits noticeably closer to the top of the selected artwork.
- Added several new large default works themed around masterpieces, heritage, and artifacts: **Smile Portrait**, **Great Wave Panel**, **Sunflower Still Life**, **Rosetta Stela**, **Pharaoh Mask**, **Stone Circle**, **Terracotta Sentinel**.
## Custom update 4: cursor-light smoothing + gray-bloom hotfix
- Save schema is now `26`.
- Fixed the urgent regression where a single local light could wash large parts of a sprite into a gray, low-chroma bloom.
- Reduced local-light body fill on depth sprites so highlights stay concentrated on lit edges / corners instead of flattening the whole silhouette.
- Smoothed cursor-light falloff so in-range / out-of-range transitions are less abrupt.
- Removed the always-on center fallback for the cursor inspection light and softened the visible cursor halo, which eliminates the unwanted blue circular artifact when no pointer light should be shown.
## Custom update 5: asset-light gray fix + temporary global delete + more default works
- Save schema is now `27`.
- Adjusted **asset-mounted local lights** again so they no longer wash large depth sprites into a gray body fill; their effect is concentrated much more strongly on lit edges and corners.
- Fixed the analog clock hand offset (it had been visually about 5 degrees early).
- Added a **temporary** delete override so **all collection works can be deleted** regardless of owner. This is clearly marked in `app.js` with comments and can be reverted by setting `TEMP_ALLOW_DELETE_ALL_WORKS = false`.
- Added many more default works: **Rain Bell Tower**, **Crimson Pagoda**, **Meteor Forge**, **Ink Garden Screen**, **Meadow Totem**, **Twilight Caravan**, **Pepper Fox**, **Glass Manta**, **Festival Drummer**, **Bloom Sprite**.