openvibers/openvibe.games CHANGELOG.md

CHANGELOG.md

main 15.5 KB · 190 lines · markdown

1# Changelog
2
3All notable changes to OpenVibe.Games are recorded here. The format follows
4[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
5adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
7## [Unreleased]
8
9### Added
10
11- **Two official example creator worlds** (plan §4 Games: "creator worlds (none published yet)"; review next step 3): **Beacon Hill**, a sculpted hill with a beacon, a flagstone path, benches, a campfire and three zones, and **The Workshop**, a walled yard with a shed you can walk into, workbenches, crates, props, resource nodes and lamps. They are ordinary v2 map documents (`apps/server/src/worlds/exampleWorlds.ts`) that staff can open in `/editor`, published for the official OpenVibe account by `apps/server/src/worlds/seedExampleWorlds.ts` (`pnpm --filter @openvibe/server exec tsx scripts/seedExampleWorlds.ts`, idempotent, `--revise` updates a changed map) so `/worlds` and the home's creator-worlds section have real entries. A person's world is never touched. `exampleWorlds.test.ts`, `seedExampleWorlds.test.ts`.
12
13- Share: a creator world's page, a round's result page, the leaderboard and the in-game round result now open the network's one Share sheet (`data-ov-share-sheet`, openvibe-shared 4.114.0) with the page's public address. The result page now starts the shared navbar itself, which is what loads the sheet on the first press; `navigator.share` is gone.
14
15### Fixed
16
17- **A drag at the end of the casual game's view did nothing.** The game view (`.cg-view`) is a scroll area
18 inside a page that scrolls, and it held its overscroll, so once the view reached its end a finger drag moved
19 neither the view nor the page and the footer could not be reached from the game. The view now passes the drag
20 to the page at its end (`apps/client/src/casual/casual.css`; `apps/client/src/casual/casual-scroll.test.ts`
21 swipes at the view's end and checks the page moved).
22- **A shared /worlds link had no preview.** The creator worlds page carried no Open Graph or Twitter tags, so a
23 link posted in Discord or X showed a bare URL. It now has the same card as the home page, with its own title and
24 description.
25- **No step said to make a pickaxe.** Scraplandia's first steps went from the Stone Axe to "Mine at the quarry", whose
26 hint only said a Stone Pickaxe breaks the deposits, and the gather step finished after a single stone. A new
27 "Craft a Stone Pickaxe" step follows the axe (2 Wood Planks and 3 Stones), and the gather hint says a log and five
28 stones make the first two tools: one pile and one log are exactly both recipes.
29- **Townsfolk in the Salvage Rush arena.** The 90-second scrap round ran the content's seven NPC spawns, laid out for
30 the procedural world: townsfolk and a warden wandered inside the arena and Rustjaw thugs stood just past its edge.
31 A world definition can now name its own NPCs (`npcSpawns`; `[]` is none), and the arena has none. A map's own NPCs
32 still win.
33- **Touch play's HUD was buried under the controls.** On a phone, the stick (bottom left) and the button grid (bottom
34 right) covered the first-steps panel, and the HP, food, water and stamina bars sat on the hotbar. While the touch
35 controls show:
36 - the hotbar sits above the buttons, in smaller slots;
37 - the bars sit above the stick;
38 - the waypoint sits under the OpenVibe button;
39 - the first-steps panel sits at the top right and shows only the step in progress;
40 - the debug status line hides.
41- **An empty pile kept saying "E — gather".** When a node had nothing left (the gate piles empty fast when several new
42 scrappers arrive together), its prompt still offered to gather and E did nothing. It now says so, for example
43 "Loose Stones — picked clean, back within 2 mins" or "Oak Tree — felled, grows back within … mins". A production
44 play-test found it: a new guest walked to the north gate, and the branch pile had been emptied a minute earlier.
45- **"City Warden — LMB attack".** Looking at a friendly warden or townsperson now shows just their name, so the prompt
46 no longer invites you to hit them; a swing still lands. Wildlife says "LMB hunt", and Rustjaw thugs keep "⚠ — LMB
47 attack".
48- **Scrap City drew every static on its own.** It is several hundred static meshes (walls, wall plates, buildings,
49 roofs, doors, stalls), and each textured one had a material of its own because its texture's scale follows its size.
50 That came to 165 draw calls in view and 298 shadow casters, with 525 materials.
51 - Statics are now merged once built (`render/staticBatches.ts`). Each static's texture tiling is baked into its UVs
52 and its tint into its vertex colours, so everything with one texture shares one material, per 32 m square.
53 - Lamps, the fountain, statics the water reflects, painted surfaces, per-face styles and glb models stay as they
54 were.
55 - A live map save unbatches, rebuilds what changed and batches again.
56 - Lamp lights switch off by day, not just dim: at intensity 0 a lamp still cost every pixel it was included on. A
57 batch is under the lamps' size limit (60 m; the terrain is 210 m).
58 - In town: statics went from 165 draw calls to 44 and shadow casters from 439 to 178. The frame came to about 230
59 draw calls (720 this evening), and a test browser ran at 38–44 fps instead of 8–13.
60- **Far avatars floated, twisted.** The merged copy that stands in for an avatar past 18 m baked each part's world
61 position, but a Babylon clone keeps its source's parent, so the joint chain applied a second time: far NPCs hung
62 0.4 m up, out of shape. Each copy now drops its parent before baking, and a test checks that the copy stands on its
63 feet at a person's height.
64- **NPCs cost 150 draw calls in town.** Each avatar is about 14 meshes, so eleven townsfolk and wardens in view drew
65 150 times a frame. Past 18 m an avatar, NPC or remote player, now draws as one merged copy of itself in its rest
66 pose and skips the animation work. It switches back to the full rig inside 16 m. In town, NPC draws went from 150
67 to 4.
68- **Shadows halved the frame rate in town.** The shadow pass drew every caster in Scrap City again each frame (about
69 390 more draw calls, ~720 a frame), and a test browser dropped from ~50 to ~10 fps. The shadow map is now redrawn
70 every third frame, and at once whenever the shadow box moves, so no shadow jumps. That gives ~490 draw calls and
71 about twice the frame rate in the same browser.
72- **Lamps blacked out the world.** A material uses its first 8 lights, and the town's lamp lights (off by day) were
73 created before the sun and sky. A map with a dozen lamps rendered every surface black. The sun and sky now have the
74 higher render priority. Each lamp lights only the geometry in its range, and its light goes with its post, so a live
75 map save no longer leaks lights.
76- **Terrain paint never showed.** The layered surface sampled the paint mask at the base texture's tiled UV. On any
77 terrain (base tiling half its extent), the mask read its clamped edge, so one layer covered the whole terrain. The
78 mask now spans the surface once, and each layer tiles by its own count.
79- **Nights lit from under the ground.** After sunset the sun's light kept the set sun's direction, pointing up out of
80 the ground, so the ground got only sky light and nights were brown-black. The light is now the moon's, shining down
81 from the moon, a little stronger than the old night light.
82- **The first-person hand.** The right fist stood upright in front of a held tool, a flat skin-coloured block in the
83 corner of the screen, and the gun's grip sat below the screen's edge. Now the fist closes on each tool's grip, the
84 gun's grip or low on an axe or pickaxe handle (the head leaning away), and the forearm runs out of the lower-right
85 corner. The arm is lit a little from within, like the tool, so it reads at night.
86- **The status line under the OpenVibe button.** In the world, the tick, fps and entity line sat under the folded
87 Frame's button in the same corner. It now sits below it.
88
89### Added
90
91- **Salvage Rush's arena looks like a scrapyard pit.** A plated wall runs round the edge with a lamp on each corner
92 (they light after dark). Scrap heaps sit against the wall and crates and drums in the far corners, all clear of the
93 eight scrap spots and the new spawn pad. It was a bare floor with four coloured boxes.
94- **A waypoint for the first steps.** An arrow and a distance at the top of the screen point toward the current
95 step's target: "Oak Tree · 30 m". The target is the nearest node in sight that has something left (a starter pile,
96 preferring whichever gives what you still lack; an oak; a stone deposit; a scrap pile), else a landmark. The haul step
97 points at the recovery bird's announced landing. "The forest is west of town" was all a new scrapper had to find a
98 forest over 100 m away.
99 - Landmarks are map zones with the wilds' own rules, so they change no gameplay: The Forest, The Quarry and The
100 Scrapyard on Scrap Island. They can be moved in the editor.
101- **The town's props look like things.** Merchant stalls have a counter, posts, a striped awning in the stall's colour
102 and goods on top. Crates have edge boards, barrels have hoops and a bung, and the storage box has a lid and a latch.
103 The workbench has legs, a shelf, a vise and a saw, the still has a dome and a pipe, planters grow, and the campfire
104 is logs in a ring of stones under an unlit flame. Every prop was its collision shape in one flat colour (the plaza's
105 stalls were purple boxes). Each look is one vertex-coloured mesh, so a prop is still one draw call.
106- **NPCs look like people.** Wardens, townsfolk and Rustjaw thugs wear the players' own low-poly avatar, so they
107 walk, turn and flinch like players. Each is dressed by its archetype (wardens in denim or slate, Rustjaw in rust
108 with beards and buzz cuts, townsfolk in everyday colours) and varied by its id. Dust hares are small faceted hares.
109 Every NPC was a tinted box with a box head.
110- **NPCs in the map, and 26 on Scrap Island.** The v2 map document has `npcs` (an archetype and a ground position),
111 and the editor's Entity tool places them: City warden, Townsfolk, Dust hare and Rustjaw thug. A map with NPCs
112 replaces the content's seven spawns, which were laid out for the procedural world and stood Rustjaw thugs just
113 outside Scrap City's wall. The server matches the NPCs to the map's spawns at boot and on every live save: a spawn
114 placed, moved or deleted in the editor shows up at once, and an NPC no spawn claims goes, saved row and all. Scrap
115 Island now has:
116 - a warden at each gate and one by the spawn square;
117 - six townsfolk on the avenues and the ring road;
118 - nine hares at the farm and in the fields;
119 - six Rustjaw thugs at the far end of the scrapyard, in the deep forest and on Rust Ridge, all beyond a leash's
120 reach of a gate.
121
122 Creator worlds still run no NPCs, and a creator map with NPC spawns says so.
123- **Something flies off a hit.** Wood chips off a tree or branches, grit off a rock, sparks off scrap, leaves off a
124 bush. Before, a swing changed nothing on screen until the server moved a count. Nothing flies toward the camera, and a
125 point-blank hit throws smaller pieces. Two thin-instanced meshes draw every particle.
126- **Sound.** Scraplandia had none. Every sound is synthesised in the browser, so there are no files to load:
127 - footsteps on grass, stone and water;
128 - a jump and a landing as hard as the fall;
129 - a swing's whoosh;
130 - the hit: a thunk on wood, a clack on stone, a ring on scrap, a thud on people;
131 - a blip when something goes into the pack, and a chime on a level-up;
132 - wind that gusts and rises in a storm, rain, birds by day and crickets at night.
133
134 Under water everything is muffled. Settings has a volume slider (saved; 0 is off). Audio starts on the first click
135 or key, as browsers require.
136- **First steps.** A new scrapper gets a checklist in the corner:
137 - gather branches and stones (piles just inside every city gate);
138 - craft a Stone Axe;
139 - chop an oak in the west forest;
140 - mine at the quarry;
141 - salvage the scrapyard;
142 - extract a haul.
143
144 Each step says where to go. Progress only moves forward and is kept in the browser, and the list can be closed.
145- **Scrap Island, Scraplandia's world (2026-10-19).** Production ran on an empty map document, so a new player
146 spawned over open water and drowned within seconds. `apps/server/src/maps/scrapIsland.ts` generates the island as an
147 ordinary v2 map document, the file the editor saves, so staff keep editing it in `/editor`. It is deterministic.
148 - **Scrap City**, walled and safe: the plaza and fountain, four market stalls, a crafting corner, avenues and a ring
149 road, houses, tenements and shacks, lamps and four watchtowers.
150 - **The wilds**: the scrapyard (container stacks, a crane, wrecks, scrap piles), the forest (about 200 oaks, berries
151 and branches), the terraced quarry, Rust Ridge and its radio mast, the lake and jetty, the farm, the shipwreck
152 beach, and ruins along the dirt roads.
153 - The terrain is one 420 m heightfield painted grass, rock and sand.
154 - Scraplandia's world id is now `scrap_island`: resources re-seed and characters move to the new spawn.
155 - Write it with `scripts/writeScrapIsland.ts` (docs/games.md).
156
157- **KTX2 surface textures (M6).** The built-in surface textures ship as KTX2 (Basis ETC1S with mipmaps), beside their
158 JPEGs:
159 - the GPU keeps them compressed, about a seventh of the memory of a decoded JPEG, which matters most on the low tier;
160 - they decode in workers instead of on the main thread;
161 - they are a quarter smaller (1.64 MB against 2.17 MB).
162
163 Babylon's decoder is vendored same-origin in `/ktx2/` (`apps/client/scripts/vendorKtx2.sh`, following
164 `@babylonjs/core`), so nothing loads from Babylon's CDN. `apps/client/scripts/encodeKtx2.sh` makes the files with
165 basisu, flipped vertically, because Babylon does not flip compressed data the way it flips a JPEG. This was checked
166 pixel by pixel in Chrome.
167
168 The JPEG is used when WebAssembly or workers are missing, with `?ktx2=0`, with `openvibe.ktx2=off`, or when a KTX2
169 fails to load. The server answers `.ktx2` as `image/ktx2`.
170
171- **The casual line and Vibe Heroes (plan T22).** `packages/casual` is a kit for small phone-first games: data
172 packs, a server-fought auto-battle, shards and fusing, levels and star-ups, gear, energy, an idle chest with
173 offline earnings, daily and weekly quests, a login calendar, earned-only summons with published odds and a
174 visible guarantee, and a gem store whose products list exactly what they give. Vibe Heroes (20 original
175 heroes, 100 stages in 10 chapters) plays at `/play/vibe-heroes` as a guest, and a sign-in on the same browser
176 takes the save into the account. Every currency or item change is a ledger line written in the same
177 transaction as the state, under the client's idempotency key (migration 0007). The page loads under 30 KB of
178 gzip JS, has its own share card, and keeps an ad link's `src`/`c` with the first visit.
179
180- **Scraplandia "Haul" mode.** Recovery-bird extractions now score haul points:
181 each secured valuable scores `count × valuable.points`. Valuable item definitions
182 carry per-item points (`salvage_core` 20, `pepper_tonic` 30,
183 `blueprint_scrap_pistol` 40, `blueprint_still` 60), defaulting to 10.
184- **Scraplandia haul leaderboard.** `scraplandia` joins the leaderboard, ranked by
185 summed haul points across all time and this week. The leaderboard page gains a
186 Salvage Rush / Scraplandia haul switch.
187- **Haul achievements.** Scraplandia gains First haul, Big haul (≥ 500 in one
188 extraction) and Haul week (≥ 2,000 in one week), evaluated server-side after each
189 recorded haul and shown in the in-game Achievements panel.
190