Changelog
What changed, week by week
Every change to the game ships with a note in plain words. Open one for the developer detail. The story behind the big ones is on the devlog; new notes are also posted in our Discord’s #changes channel.
Week 43, 202619 Oct – 25 Oct · 32 changes
- Fix
After joining the waitlist, the two optional questions now open in their own window, so the whole form and its button are always visible, on phones too.
Website#99
Developer detail
The questions panel sat inside the first screen, which has a fixed height (its art is sized by container queries) and hides overflow, so the panel's bottom and its button were cut off. It is now a modal
<dialog>(top layer, never clipped, fits the viewport), with Skip, and a thank-you with the Discord invite after sending. Kit itself was fine: sign-ups land as unconfirmed subscribers until the confirmation link is clicked. - Fix
Joining the waitlist now tells you clearly that one step is left, checking your inbox and clicking the confirmation link, and that link brings you to a page that says you are on the list and what happens next.
Website#99
Developer detail
- After joining, the form is replaced by a "Check your inbox to confirm" card with the address used; the questions dialog opens with the same message as its heading and repeats it as "One last step" after the answers are sent. Testers missed the small status line, and the Kit email can land in Spam.
- New
/confirmedpage, the Kit form's redirect after confirmation: "You are on the list", the next steps, Discord and devlog buttons, a copy-link button (?ref=friend). Not indexed; it removes any query Kit appends.
- Internal
The website is now hosted on Vercel at felucca.online, rebuilt automatically whenever something on the site changes, with its images served from our own media domain.
InfrastructureWebsite#81
Developer detail
- GitHub repository
alerdenisov/felucca(private); Vercel projectfeluccawith rootweb/builds production frommain. - The ignored build step now always builds a redeploy of the already deployed commit: it used
to cancel those, so a redeploy after changing env vars (baked into
NEXT_PUBLIC_*) never ran. - Media variants uploaded to R2 (
media.felucca.online, 612 files, 45 MB, immutable caching).
- GitHub repository
- Art
Towns get their dressing: market stalls for nine trades with their goods, street lamps in each realm's style, fountains, statues of the rulers, trade signs, the banners of the four powers, laundry, puddles and building works.
Art and assetsWorld#104
Developer detail
123 sprites of group
townof the world-props order, scripts intools/blender/models/world_town/, manifestassets/manifest.d/world_town.toml:- Market: stalls (2x1, front south and east) for fish, meat, cloth, pottery, weapons, bread, flowers, herbs and jewellery, each with its own awning colours; the awning ends above the counter's back edge so the goods stay in view. A vendor's cart, 21 goods and yard props (crates, barrels, sacks, cheese, scales, butcher's block, chicken crate, firewood).
- Street furniture: benches, the double lamp, the Dominion's crowned iron lamp and the Concord's crystal lamp (both light the street), brazier, notice board, crier's podium, small and grand fountains (3x3, bronze figure), covered well, pump, trough, hitching post, mounting block, street sign, pillory, market bell; statues of the Dominion's king, the Concord's queen and the free city's founder (2x2).
- Signs and heraldry: sixteen trade signs on wall brackets (four facings, like
shop_sign), banners on poles and wall flags of the Dominion, Concord, free city and isles, bunting and a heraldic shield; wall pieces stand on the north (_x) or west (_y) edge. - Clutter and works: flower boxes, planters, potted tree, topiaries, rubbish heaps (2 variants), puddles (4 variants), sewer grate, broken barrel, laundry line and drying rack, broom, wheel and ladder leaning on a wall, outdoor bread oven (glowing), quench barrel, grindstone, two-storey scaffolding, building materials, bricks, mortar, roof tiles.
Every model sits on the texel lattice (
check_lattice()passes everywhere); leaves and petals vanish on breaking. Helpers copied from the catalog kits into the group'stown_kit.py. - Art
Rocks, cliffs and ores for the open world: seven kinds of rock in five sizes, cliff faces that line the mountains, outcrops, arches and spires, mining veins of all nine ores, quarries, gems, glowing crystals, lava rock and steam vents, ice and snow.
Art and assetsWorld#104
Developer detail
The 107 sprites of group
stoneof the world-props order, modelled procedurally intools/blender/models/world_stone/(kitstone_kit.py), every vertex on the texel lattice (check_latticeOK on all 182 frames), manifestassets/manifest.d/world_stone.toml.- Rocks (
rocks.py, 35 sprites, 91 frames): granite (angular, light flecks), mossy (moss on the tops), sandstone (stacked strata in two bands), basalt (hexagon columns), limestone (pale, dark fissures), beach (sea-rounded, barnacles low down) and river (dark, glossy, algae at the waterline), each as pebbles (flat), small (knee high), medium (waist high), large (2 m, 2x2) and cluster (2x2), 2–3 variants each. - Cliffs (
cliffs.py, 20 sprites): granite, sandstone, basalt and snow faces, 3 m, on the tile's north (_x) or west (_y) edge like walls. Displacements are periodic per tile and every piece end shares one cross-section, so runs, the inner corner (x + y on one tile), the outer corner and the end (both placed at the north-west corner of the tile where an x run from the west and a y run from the north stop) join without seams. Placement rules are in the script's docstring. - Formations (
formations.py, 14): outcrops, a big outcrop with ledges, a 6 m spire, arches to walk under (2.1 m clear,_s/_e), a ledge, a balanced rock, a split boulder with a sapling, rocks with an ammonite, carved runes or ochre paintings, a split geode and a meteorite in its crater. - Flat ground (
ground_stone.py, 7): scree, gravel, stepping stones, slabs, salt crust, obsidian shards on ash, lava crust with glowing seams. - Resources (
ores.py, 19): ore veins of iron, dull copper, shadow iron, copper, bronze, gold, agapite, verite and valorite (faint glow), granite and marble quarry faces, four gem kinds and four glowing crystal clusters. - Volcanic and ice (
elements.py, 13): obsidian outcrop, lava rocks (the large one with glowing cracks), steam vent, fumarole, volcanic bomb, ash mounds, ice blocks and spikes, frozen boulders, snow mounds, a rock with icicles.
- Rocks (
- Art
Roads, rivers and coasts get their props: milestones and wayside shrines of both realms, toll and border posts, stone and plank bridges, docks and harbour gear, rowboats, fishing boats and shipwrecks, a lighthouse, beach finds, pirate camps and snowed-in carts.
Art and assetsWorld#104
Developer detail
The
shoregroup of the world-props order: 119 sprites modelled on the texel lattice intools/blender/models/world_shore/(shore_kit.pyplus seven family scripts) and listed inassets/manifest.d/world_shore.toml.- Roads (27): milestones (plain in two variants, Karrak with the iron crown, Aelwyn with a carved leaf), three- and four-armed signposts, wayside shrines of both realms and an old stone one, lantern posts, toll barriers and a toll booth, border stones and banner posts, hitching rails, benches, a well, dropped crates, cairns, a traveller's pack, a memorial cross, road works.
- Bridges and docks (23): stone and plank bridge decks at road height that tile in both
directions, parapets and railings on the tile edges like fences, piers, rope bridge planks,
dock ends and broken docks matching the catalog's
dock_planks, quay stairs, pilings, bollards, a dock crane, harbour and jetty lamps, a bell buoy. - Harbour goods (17), boats (13: rowboats afloat and beached, canoe, fishing boat, a boat laid up keel-up on trestles, ferry raft and post), wrecks (10: a heeled 5 x 3 hull, bow, stern, fallen mast, figurehead, flotsam), beach (12, incl. the lighthouse), rivers, pirates and winter roads (17).
Boat hulls are convex hulls of lattice points; boats afloat put their waterline at z = 0.
- Art
The ruins of the Old Empire are drawn: broken walls in five stone styles that match their houses, rubble, columns, arches, an aqueduct, toppled statues, a giant stone head in the grass, stone circles with glowing runes, dolmens and burnt-out farms.
Art and assetsWorld#104
Developer detail
The
ruinsgroup of the world-props order (assets/requests/world-props/ruins.md): all 117 sprites, inassets/manifest.d/world_ruins.toml, scripts intools/blender/models/world_ruins/.- Ruined walls (
ruin_<set>_<low|mid|tall>_<x|y>,ruin_<set>_cornerfor stone, marble, sandstone, brick and fieldstone;ivy_wall_*,charred_wall_wood_*): each is its wall set's own code (wallset_<set>.py, run withwalls_kit.runcaught) clipped to a jagged column profile, so face plane, thickness, trims and materials are exactly those of the houses. Column heights prefer the set's course tops (the break follows the masonry), a quarter break mid-block; both ends of a profile share one height (low 12, mid 24, tall 40 levels, snapped per set), so pieces of a height join in runs. Sandstone and fieldstone lay their courses out byFrame.mask, so the clip uses aClipFramethat keepsmaskempty while the set code runs. - Everything else is texel voxels (
nature_kit.Vox) or lattice lathes: rubble heaps stacked from each set's blocks on a height map, coursed arches and piers drawn as south-face patterns, tapered and eroded megaliths, voxel sculptures (ruins_kit.Sculpt: ellipsoids and tapered capsules) for the statues, round towers in staggered courses. Weathering is broad blotches, moss in cushions and lichen patches on stone only (features, metal and glow are left alone). The overgrowth usesnature_kitcrowns and trunks with vanishing leaves (#66). - Glowing:
menhir_runes(blue runes) andstatue_maiden_aelwyn(her lantern). - Every script ends with
check_lattice()(OK for all; the tree and bush crowns are snapped bynature_kit.finish).
- Ruined walls (
- Art
115 new grim props for the wilds: skulls of people and beasts up to a dragon's, skeletons, carcasses, the wreckage of the war between the two realms, graves, barrows, tombs and monster lairs.
Art and assetsWorld#104
Developer detail
Group
remainsof the world-props order (assets/requests/world-props/remains.md), all 115 sprites modelled and baked: skulls (human, piles, pike, demon, cow, horse, deer, wolf, bear, ram, orc, troll, a giant's skull sunk to the nose, a dragon skull), bones and great skeletons (scattered and gnawed bones, fish, ribcages up to whale and dragon, a giant's spine, femur and skeleton), posed skeletons (sitting, in armour, crawling, hanged, in a web, with a lit lantern, in a hanging cage, a horse), carcasses, battlefield gear and lost things, war wreckage (torn banners of the Dominion, the Concord and the orcs, ballista, catapult, siege tower, chevaux de frise, stake field, burnt wagon), graves and memorials, stains and lairs, barrows, tombs and crypts.Scripts in
tools/blender/models/world_remains/on the group kitremains_kit.py:Vox, a voxel model on the texel lattice that emits only faces touching air (one mesh, a slot per material), andmound, a closed heightfield with corner heights on levels for earth and hides. Every script passescheck_lattice(). Manifestassets/manifest.d/world_remains.tomlstates each prop's footprint from the order (the baker otherwise derives 2x1 from overhanging bones).grave_mound_oldis ordered with 4 facings and 2 variants, which the baker cannot combine: its two variants are the two orientations (north-south, east-west). - Docs
We ordered 1060 new props for the world, from rye sprouts and haystacks to skulls, shipwrecks and dungeon gates, and planned where every one of them goes.
Art and assetsWorldGame design#104
Developer detail
tools/world_props_order.pywrites the order (assets/requests/world-props.toml, lists per group inassets/requests/world-props/), the brief isassets/requests/world-props.md, the placement plandocs/world-dressing.md. Nine sessions model the nine groups in parallel. The demo village's test that every catalog asset stands in the village skipsworld_*manifests. - Art
113 wild plants for every corner of Felucca, from poppies, bluebells and heather to cattails, glowing Elderwood mushrooms, fallen trees and moss-hung swamp trees.
Art and assetsWorld#104
Developer detail
Group
floraof the world-props order (decision #104), modelled and baked: flowers (26), grasses, sedges, reeds and ferns (15), ground cover and forest litter (16), bushes and shrubs (18), mushrooms (8), young, dead and odd trees (11), stumps, logs and a big fallen tree (12), jungle, swamp and desert plants (7). Scripts intools/blender/models/world_flora/, manifestassets/manifest.d/world_flora.toml.- Leafy bushes, saplings, the young oak, snowy pine, small palm, juniper, ferns, the mangrove crown and the dead swamp tree come from the Quaternius CC0 nature packs (models by Quaternius, #74) at real size, squashed in plan to their tile, leaf cards recoloured per species, berries as small boxes on the outer cards.
- Everything else is texel voxels on the lattice (one material per texel,
check_latticeOK): the pack grass and flower cards read as pale slabs at 32 px per tile, voxel blades and heads read cleanly. Flat pieces stay on levels 0..1; carpets (poppies, daisies, bluebells, buttercups, dandelions, clover, leaf litter, pine needles, ivy, duckweed) wrap at the tile edge and tile seamlessly. Leaves, petals, grass and moss vanish on breaking (#66); glowing mushrooms and fire lilies have emissive texels. branch_fallenhas its 4 facings but one variant (ordered with 2):uo-bakerbakes variants only fordirections = 1.
- Art
Farmland gets its art: thirteen crops in four stages of growth that fill fields edge to edge, haystacks, sheaves and scarecrows, farmyard furniture from hen houses to cider presses, carts and a hay wagon, wattle and split-rail fences, a windmill and a water wheel.
Art and assetsWorld#104
Developer detail
The
farmgroup of the world-props order: all 124 sprites inassets/manifest.d/world_farm.toml, scripts intools/blender/models/world_farm/on the texel lattice.- Field pieces (
crops.py): rye, wheat, barley, oats, flax, hemp, cabbages, turnips, onions, beans, hops and grapevines in sprout / young / grown / ripe, plus stubble and a melon patch, three variants each (two for melons). Plants are texel voxels in rows on the crests of the furrows ground tile (period 4 texels); each tile is cut out of an endless field (FieldVoxwraps cells into the tile), and every plant that can reach over the tile edge is seeded by its position alone, so all variants agree on the edge and any mix of them tiles seamlessly. Sprouts, stubble and melons stay within 2 levels (flat). - Harvest (
harvest.py): round haystacks (one held down by roped stones), a long rick under a stepped thatch (_s/_e), small stacks, loose hay with a pitchfork, bales, stooks, lying sheaves, sacks, baskets, a crate of apples, heaps of pumpkins and cabbages, three scarecrows. - Fences (
fences.py): woven wattle hurdles and zig-zag split-rail fences as x / y / corner / post pieces on the doors_fences convention, a step stile, a sluice gate, a 2x2 hurdle pen, vineyard trellis edge pieces, hop poles. - Farmyard (
yard_gear.py,yard_pens.py,yard_wood.py,yard_presses.py): churns, troughs, a goose pen, grain bin, hitching post and racks, hen house, rabbit hutch, skeps, box hive, bee bench, dovecote, a granary on staddle stones, manure and compost heaps, woodpiles, chopping block, kindling, cider and wine presses. - Works (
works_carts.py,works_tools.py,works_mills.py,works_orchard.py): wheelbarrows, hand and turnip carts, a hay wagon (_s/_e), plough, harrow, ox yoke, buckets, a well sweep, a post windmill (sails to about 11 m, past its 3x3 footprint like a tree crown), an undershot water wheel cut at the waterline (_s/_e), an orchard ladder and staked fruit saplings.
Every 1x1 entry declares
footprint = [1, 1]: wheelbarrows, ploughs, scarecrow arms and the like reach a little past the tile, and the bake would otherwise infer a 2-tile footprint. - Field pieces (
- Art
Camps in the wild now have their own props, from tents, yurts and bonfires to orc totems, bandit loot, woodcutters' saw pits, charcoal kilns, quarry cranes and mine entrances.
Art and assetsWorld#104
Developer detail
All 128 sprites of the
campsgroup of the world-props order are modelled and baked (assets/manifest.d/world_camps.toml, scripts intools/blender/models/world_camps/):- tents and shelters: pup tent, wall tent (s/e), the Dominion's command pavilion, the Concord's silk pavilion, hide tent, ragged bandit tent, yurt, lean-to (s/e), field hospital;
- fires and cooking: spit roast, cauldron, cold campfire, bonfire, fire pit, cooking tripod, smoking rack, iron field brazier, orc skull fire pit, the ogre's pot;
- bedding and furniture, racks and stands, war banners of both realms, supplies and loot;
- orc camps (totems, banner pole, war drum, hide hut, bone fence and spike wall x/y, cages, throne, trophy rack, idol, giant's club), carts and wagons, palisades and barriers, a lookout;
- woodcutters, charcoal burners, quarries and mines, hunters' traps and the hermit's things.
Every model sits on the texel lattice (
check_latticeOK for all) and bakes with the dominant resolve; flames, embers, the mine lantern and the bloomery are emissive, leaves and herbs vanish when broken. Footprints, facings, variants, glows and flat pieces follow the order contract (assets/requests/world-props.toml). Group helpers live incamps_kit.py, which reuses the fire, log and stone helpers oflights_crafting, the skulls and pictures ofcivic_dungeon/decor_homeand the edge mirror ofdoors_fencesread-only. - Art
The world gets its magic and its dungeons: the eight virtue shrines with their coloured flames, fey rings, an ancient elder tree, wizards' yards, waystones, a doorway for every kind of dungeon, dark rituals and portals, and reagent plants.
Art and assetsWorld#104
Developer detail
The
arcanegroup of the world-props order: 114 sprites inassets/manifest.d/world_arcane.toml, scripts intools/blender/models/world_arcane/on the texel lattice (helpers inarcane_kit.py: coloured magic flames, the virtue table and glyphs, rune bitmaps, snapped mounds, edge pieces).- Shrines: the eight virtue shrines (2x2) carry their glyph on a stele that faces the camera, glowing in the virtue's colour above a bowl of that flame (humility burns black); the Dominion's spiked war altar, the Concord's moon basin, a ruined ankh shrine, a candle niche, offerings, prayer flags, a censer and a holy font.
- Dungeon entrances face the camera with a dark way in: mine, dwarven delve, barrow, crypt and
cave in
_s/_e(the_epiece is the_smodel mirrored across the view diagonal, as UO's pairs are, so the opening stays on the camera side), plus sunken temple, fey hollow, fire lair, ice cave, sea grotto, ruined keep (4x2) and the Old Empire's triumphal gate (5x3). - Waystones and wizards' grounds: runes sit on a corner cut along the plan diagonal, so they read square on screen; arcane circle, crystal pylon, armillary astrolabe, telescope, cauldron, mana well and more.
- Fey, trees, rituals, lairs, reagents: fairy-ring quarters (variant v holds the quarter of a ring centred on its tile's south-east, south-west, north-west, north-east corner for v = 0..3), the ancient tree (a Quaternius CC0 pack tree, models by Quaternius, grown to 20 m on a modelled buttressed base), portals, summoning circle, spider webs, dragon hoard, and the reagent nodes.
- New
The land between the towns comes alive: fields in plots with crops, haystacks and scarecrows, farmsteads and windmills, shrines, ruins, graveyards, battlefields, camps, harbours, bridges, dungeon gates, and flowers, rocks and bones in every biome.
WorldGame design#104
Developer detail
uo-atlas/src/dress/: the world's dressing, placed by the bake.scatter.rs(per region, from its tiles and the global geometry): biome cover in noise drifts with rocks and rare finds; river banks, lake shallows, coasts; cliff faces where mountains rise north or west, with corners and tapering ends; fields cut into plots (crop and growth stage by plot and climate, stubble with stooks and ricks, fallow) behind hedges, wattle and split-rail fences with stiles; milestones, wayside shrines, lanterns before towns, border posts, toll booths, road works, roadside debris by danger; bridges on every ford (decks, parapets, piers, posts); nodes at the atlas's deposits; danger, frontier and isles props.sites.rs(planned once, like towns): a vignette for every kind of place of interest, dungeon entrances by kind, farmsteads (some burnt), orchards and vineyards, windmills, watermills with ferries, work camps at deposits (mines, quarries, woodcutters, hunters, fishers), harbours for ports (pirate guns on the isles), gallows at dangerous crossroads, army camps beside battlefields, corrupted circles. Sites may hold generated buildings on level ground; earlier sites win where two overlap.- Towns (#103): stalls by trade with goods, rulers' statues, banners, realm lamps, trade signs by building kind, flags, shields and flower boxes on facades, life by the doors, clutter in back streets, building works on free plots.
- Statics chunks list the extra tiles multi-tile blockers cover; ruined walls, cliffs, palisades, barricades, bridge parapets and portcullises block their edge.
tools/world_props_usage.py: every one of the 1060 ordered props has a rule.- Sites move off rock to open ground and put their landmark where it fits; glades; battlefields trample their fields.
- Client: sprites under 0.4 units cast no shadow shell (a dressed meadow 15 → 8 ms); the sprite atlas starts with 12 layers.
- Seed 1: 13.97 M statics (6.8 M before), 4232 sites. Numbers:
docs/world-dressing.md. - Client
--prop-gallery a,b,…: chosen sprites in rows on the demo ground, to look at props in the real renderer (the blog's showcases). Orchards keep grass under their trees.
- New
The whole world now has a map. A rugged main island split between two rival realms, a contested river valley between them and lawless island chains around it, with every town, road and dungeon placed, drawn as pixel art at one pixel per tile.
WorldGame design#97


Developer detail
New crate
uo-atlas(cargo run --release -p uo-atlas -- --seed 1 --out atlas-out, about a minute and a half, about 40 MB). Deterministic from the seed; nothing of it is in the playable map yet.- Scale: 16384 × 16384 tiles by default (1 tile = 1 m), about 68 minutes running edge to edge at 250 ms per tile. Geography and placement run on a 16-tile macro grid, the picture per tile.
- Shape: a warped main island (lobes, gulfs, fjords), a frontier valley with the great river, the Sunder; a cold northern plateau behind a mountain wall, a warm southern forest country with the Elderwood; five or six archipelagos cut by straits, one of them volcanic.
- Politics: the Karrak Dominion (north) and the Aelwyn Concord (south) split the main island by culture-specific travel cost from their capitals; the March along the border, a free port at the river mouth, the wilds, and the isles, where there is no law. Provinces around every capital, city and March town.
- Scarcity: Karrak has the main island's gold, gems and rare ores, Aelwyn the bow woods,
grain and herbs and no rare ore; the isles hold the largest share of the best of both and all
the sulfurous ash. Checked by
cargo test -p uo-atlason three seeds. - Places: about 270 settlements, highways, roads and tracks, forts at the Sunder bridges, about 170 dungeons with the ruined old imperial capital as the great one, about 2700 sites, danger per cell and 15 encounter zones with weighted encounter tables.
- Output: tile pyramid (1:1, 1:4, 1:16), realm and danger overlays,
atlas.json, and a viewer (index.html) with search, layers, deposits per resource, hover details and the local encounter table.
Details:
docs/world-atlas.md. - Art
Buildings get their missing wall pieces. Cut corners and bay windows now have real diagonal walls, balconies and roof terraces have low parapets, fortified buildings have arrow slits and tower tops have crenellations, in all nine wall styles.
Art and assets#102
Developer detail
The building generator (#101) already placed these pieces; the client drew placeholders until now. 126 new sprites, 14 per full wall set (stone, brick, wood, log, plaster, sandstone, marble, fieldstone, dungeon), ordered in
assets/requests/wall-pieces.md:diag_a/diag_b(+_window): full-height diagonal walls between the corner posts of the wall grid, built in a sheared frame so every vertex stays on the texel lattice and neighbouring diagonal tiles join exactly. Their outlines sit on half-pixel rows, so they read a little softer than straight walls.low_*: parapets, the set's own wall cut at level 16 under a two-level coping.slit_*: arrow slits 2 texels wide at levels 22..36, splayed on the camera side.crenel_*: solid to 12 with a string course, merlons 4 texels wide every 8 up to 24; the corner piece gets an L-shaped corner merlon.
walls_kitbuilds them from each set's existing wall and post code: diagonal frames, profile clipping (Frame.mask) for parapets, kit copings with per-set hooks, and the slit reveal. Every piece passescheck_lattice()and bakes withresolve = dominant. The village shows all of them in a mason's yard. - New
The playtest waitlist on the website now really signs you up. Confirm your address by email and you get playtest invites, development news and the occasional offer, then two optional questions and a link to our Discord.
Website#99
Developer detail
- Subscribers live in Kit (kit.com), not on our side:
POST /api/waitlistcreates the subscriber inactive and adds them to the waitlist form, whose double opt-in sends the confirmation (web/src/lib/waitlist/). Joining is the consent to invites, dev news and offers, as the line under the button says (no checkbox). Fields:opt_in_at,opt_in_text,source(from?ref=orutm_source). - After joining, an optional questions step (
POST /api/waitlist/profile, HMAC token valid one hour) storesuo_playedandinterests, and the Discord invite is shown. - Abuse guards: honeypot field, a best-effort per-IP limit (5 per 10 minutes per instance).
/privacypage; footer links.npm run kit:setup -w weblists Kit forms and creates the custom fields (--apply). Env:KIT_API_KEY,KIT_FORM_ID,WAITLIST_SECRET.- Not verified against the live Kit account yet: the double opt-in email on API sign-ups needs one test with a throwaway address.
- Subscribers live in Kit (kit.com), not on our side:
- Fix
The same controls and the same HUD everywhere. WASD and the right mouse button now run your character in the offline demo too (they used to move the camera there), the arrow keys move the camera, and the village, the combat demo and the online game share one set of panels.
Client#96
Developer detail
- One control scheme (
controls.rs): mouse and keys become intents, which the active mode applies: offline outside a battle (roam.rs: paths around walls and props, running one tile at a time, a click on a destructible object hits it), in an offline battle (battle orders; a held direction orders one step whenever nothing else is queued, as the server does) and online (server commands with prediction). - One HUD (
hud.rs): status, vitals, spell bar, target card, log, outcome banner, overhead bars and floating text, filled by the active mode. An offline battle adds its tempo timeline. - Keys that moved: arrows pan the camera in every mode, H cycles roofs (R is always hold), numpad steps work offline too, Esc disarms a spell or quits only outside a fight, and a plain right click no longer hits objects (left click does; Shift + right click still blasts).
--recordin the offline village (no battle) no longer waits forever for a battle to start.
- One control scheme (
- New
Felucca's 268 towns, villages and forts are built: streets laid out so you always see the fronts, a square with a landmark, markets, walls and gates where the roads arrive, about 2600 buildings with yards, and free plots left for players.
WorldGame designServerClient#103




Developer detail
Town plans in
uo-atlas(towns.rs), computed once from the natural ground before the bake and read by the ground painter, the bake and the atlas picture.- Bastide layout for the fixed camera: bands of plots fronting south onto their street, cross streets at irregular spacing with east-fronting corner plots, the square in the middle band, a market square below it in capitals and cities.
- Districts (civic, rich, gate, craft, common, outer) choose the kinds; required buildings per
tier with caps; 10–20 % free plots listed in
world.json. - Octagonal walls with diagonal pieces and crenellations (palisades for Aelwyn and the isles), a ring road, gates where atlas roads arrive (a south gate if none), roads end at the edge.
- Ground levelled per town, streets, squares, yards, vegetable patches; brooks built over, rivers forded. Yards and props by trade, fences, lamp posts, shop signs.
- Statics format 2: facing, storey, roof, exact height and building per record; arenas and
blocking use ground pieces only; the client keeps baked heights and hides upper storeys and
roofs as
Overheadwhen you step inside. uo-atlas --town <name>writes plan sheets;--plans-onlyskips the picture. Forts are bigger (radius 26). Seed 1: 2665 buildings, 326 free plots.- Tests: plans of a whole atlas (doors on streets, no overlaps, required buildings, gates, determinism), statics chunks round trip, building pieces read back from a bake.
- Fix
Houses with cut corners are symmetric now: both front corners are cut, or all four, never one alone.
World#104
Developer detail
uo-buildingsused to roll every convex corner on its own, so a house could have one cut corner on one side. Now a building picks one pattern (none, the front pair of each wing, or all four), a corner is cut only together with its twin across the wing, on every storey where both exist, and glazed diagonals are all or none. New test: every diagonal outside a bay has its twin. The diversity bar of the plan test drops to 60 % distinct layouts (warehouses: 59 of 96), since lopsided cuts no longer count as variety. - Docs
Design direction: your gear will set your speed, as in Ultima Online's Age of Shadows: faster swings, faster casting and quicker recovery from properties on items, worth hunting for.
Game designCombat#93
Developer detail
Decision #93 replaces the rigid Renaissance timing with AOS/Mondain's Legacy-style properties (Swing Speed Increase, Faster Casting, Faster Cast Recovery and more), each a modifier on items and effects with a cap. Times are computed in milliseconds and rounded down to the 250 ms quantum, so a bonus saves a whole quantum or nothing and builds aim at breakpoints. Not implemented yet; formulas and caps are open (
docs/combat.md› Speed properties). - New
Run like in Ultima Online. Hold the right mouse button to run toward the cursor, or use WASD. Outside a fight you run twice as fast as you walk, and running stays smooth even when you turn often.
ClientServer#91
Developer detail
- Right mouse button held: run toward the cursor (eight directions, half-tile dead zone). WASD: screen directions. Online the camera pans with the arrow keys (#91).
- Out of a fight a step is 1 AP (250 ms); in a fight (attacked or attacking in the last 10 s) it stays 2 AP so the tempo against weapon swings holds (#92). The server publishes the player's step time and the client predicts at it.
- Held running is client-driven as in UO (#94): each step the client shows is sent as a
Step; the server queues up to four, takes them in order and checks each, refusing a bad one withStepRejected. Running in circles for 40 s: 128 predicted steps, no corrections (21 before). In a fight the server walks a heldMove { dir }instead.
- Fix
River banks and shores no longer look torn: water lies flat at its own level and the shoreline follows the same soft, dithered border as every other ground.
RenderingWorld#104
Developer detail
The client drew water as one flat sheet at −0.2 over the whole map and sank every water tile to a bed at −0.6, so a river up on a plateau carved a trench with steep, spiky slopes that the sheet cut through. Now water is a terrain type like the others: water tiles are flat at their own surface (sea, lake level, rivers one step below their banks), every corner touching water sits on the waterline, and the terrain shader draws water with its ripples and gloss wherever its per-texel border pick lands on a water tile. No sheet.
WATER_LEVELis the sea's −0.25. - New
The game client plays online. Log in, walk a map far bigger than the demo village, fight bandit camps with other players, and keep playing if your connection drops.
ClientProtocol and SDK#88

Developer detail
uo-client --server ws://… --name …(#88): the terrain is built from a 192 × 192 window that follows the player, region statics stream in and out, server object damage drives cracks, debris and open doors, mobiles are dressed from their equipment, and combat events reuse the offline showcase's effects. A dropped connection resumes on the next gateway in the list.--bot combat-auto,--bot wanderand--bot runplay by themselves, also headless.Movement went through several rounds of fixes found in play: commands are numbered per session (a character walks again after logging back in), walks keep their planned route, the client predicts walks leg by leg with the server's own planner (
uo_world::walk), a walk order beats auto-attacking back, lagging mobiles catch up instead of jumping two tiles, and own steps are predicted with rollback onStepRejected. - Art
New night lighting. Nights are no longer pitch black. Moonlight washes the world in a dark blue you can see in, shadows keep a faint hint of colour, characters take on the moonlight too, and torches, braziers and lanterns glow a calm warm light instead of a strong orange.
RenderingCharactersClient#95

Developer detail
Before (left) and after (right), the village at 23:00:

- Moonlight. The night phase has a weak cool moon (strength 0.05) and a dim blue sky
ambient (20), exposure +0.5 EV instead of +0.75. The black toon band stays only as a guard
(
toon_t00.012 → 0.003). - Blue in the dark, colour by the fire. A new per-phase dim tint (
Phase::dim_tint,Shading::dim_tint) pulls texels in the two darkest toon bands towards blue at their own luminance (night 0.65; blue light alone leaves green grass green). Pools of firelight sit in the brighter bands and keep their colour. - Characters. Their readability light floor (
MIN_LIGHT0.6) and rim take the same tint, and the floor now tops the light level up by luminance instead of a per-channelmax, so a character in the dark is moonlit blue and one by a brazier stays warm. - Warm, not orange. Sprite lights, torches and the campfire go through
Look::light_color(saturation 0.6 in linear light, luminance kept). Combat effects keep their colours. - The moon now casts light, so the directional light fades out briefly around the sun-to-moon switch (≈ 5:00 and 19:00) and shadows never jump.
- Everything stays tunable at runtime:
UO_LOOK="night.dim_tint_amount=0.5,light_saturation=0.5".
- Moonlight. The night phase has a weak cool moon (strength 0.05) and a dim blue sky
ambient (20), exposure +0.5 EV instead of +0.75. The black toon band stays only as a guard
(
- Internal
We stress-tested the server with 2,000 bots and real game clients while crashing machines on purpose: nobody was duplicated or lost, a crashed machine's part of the world came back in under five seconds, and restarts didn't kick anyone.
ServerInfrastructure#89

Developer detail
uo-loadtest(#89) runs thousands of protocol bots (combat, wander, duel, siege, churn) and whole scenarios: sims and gateways as processes on the store, real headless Bevy clients, chaos steps (kill,stop,start,rolling) and a check every second that no player is simulated twice and every region is owned.The plan's full run (M7) on ScyllaDB: 3 sims and 2 gateways as processes, 2000 bots and 2 Bevy clients through a sim crash, a gateway crash and a rolling restart of every sim: tick p99 4 ms (target 25), failover 4.7 s (target 7), no duplicates, every bot back, 1.7–2 s per sim to restart. Getting there fixed a local-handoff routing loop, a dead tick that kept renewing its leases, LWT renewal storms (now membership fencing, #90), DDL stalling LWT on restarts, tick preemption (time-constraint policy on macOS) and path searches to unreachable targets. Numbers:
docs/server-performance.md,docs/server-m7-report.json. - New
Felucca has a game server: one shared world, split into regions across many machines, built for tens of thousands of players at once. When a machine falls over, its part of the world moves to another in a few seconds and you stay in the game.
ServerProtocol and SDKWorld#87

Developer detail
uo-serveris one binary with two roles over a shared store (#87):- gateways hold the WebSockets, sessions and each player's area of interest (18 tiles) and route commands; they keep no game state;
- sims own 64 × 64-tile regions of the 1024 × 1024 map on leases and simulate each one as an
open-world
uo-combatbattle at 20 Hz, players, bandit camps and destructible objects together.
The store is ScyllaDB or Apache Cassandra (same driver and schema;
deploy/docker-compose.yml) or an in-memory store for one process. Ownership is compare-and-set (region leases, character owners), state writes are fenced by generation so a late write from a former owner always loses. Players are handed between regions and machines without noticing; a battle stays on one machine while it lasts; a crashed sim's regions are taken over after its membership expires (#90); planned drains and rolling restarts move players with no dropped connection.World content comes from the new
uo-worldcrate: regions, per-tile map windows, deterministic camps and nature per region, and the combat arena builder shared with the client. The server also owns object damage now: hits and breaks travel as object updates and are stored.Protocol v2 (
uo_proto::msg): snapshot plus per-tick deltas of the area of interest,Resumeon any gateway, combat orders and the combat event stream, object updates, vitals. Documentation:docs/server-architecture.md. - New
You can now walk Felucca. The game map is the world from the atlas, with its rivers, lakes, forests, meadows, snowfields and the open ground of every town, and the server starts the parts of the world where players are.
WorldServerClient#100



Developer detail
uo-atlas --bake <dir>bakes the playable world once into static files:map.bin(terrain and height of every tile, per 64×64 region, deflated, 12.8 MB),statics.bin(6.2 M nature and camp objects, 18.6 MB),world.json(places, camp sites, a hash of the data files). Nothing is generated at run time; what players change stays server patches.- The atlas picture and the bake share the per-tile rules (
uo_atlas::ground,uo_atlas::game): biome terrain with patches, heights from the atlas elevation, rivers, lakes at their level, roads (causeways and fords over water for now), towns as levelled terraces with plaza, lanes and plots. - Nature by biome and climate: stands and clearings, saplings at the edges, undergrowth, at most one blocking object per 2×2 tiles; real-size trees, so forests keep their ground visible. Bandit camps at the atlas's camp sites (451).
uo_world::bakedreads the files lazily per region;uo-server --world assets/world/felucca; the client loads the bake named inWelcomeand checks its hash.- Big worlds are demand-driven on the server: a
region_demandtable (sims: their players' regions and neighbours; gateways: the region of a login), placement only of demanded regions, idle regions retired after 30 s. Small worlds and every cluster test run as before. UO_SPAWN=x,y(development) starts new characters at a given place; the online bot wanders only to walkable goals.
- New
Real-time tactical combat is in the client. Fight bandits on the open map with cover that breaks, spells, powder kegs and a forest cabin to hold, and watch the timeline show who acts next.
CombatClient#69

Developer detail
The combat showcase branch (
feat/combat-demo) lands onmain. Rules live in the pureuo-combatcrate (#68): every action costs action points, 1 AP is 250 ms of recovery, the clock never stops, orders queue during recovery and a ready fighter auto-attacks its target. Projectiles and targeted spells need a line of fire; destructible statics on it are full or low cover and take the stopped shot (#66 hits).What ships in the client (
--combat-demo [cabin|camp],--combat-auto):- the bandit camp and the forest cabin assault (#69, #71): sappers with powder kegs, halberd sweeps that wreck rooms, Wall of Stone, doors that open;
- the FFX-style timeline HUD, spell bar, target card, log and overhead bars;
- hotkeys on numbers and QWERTY (#70), autoplay with the hero holding the house and falling (#72, #79), the cabin mirrored so its entrance faces the camera (#80);
- the Mega Explosion last stand (#86),
--no-hud(#84) and--recordvideo capture.
Tests cover the tempo (six dagger swings to two halberd swings in six seconds), cover, spells against cover, Wall of Stone, walking, breaking through walls and determinism.
- Art
The bear-skin rug is now life size, and log cabin walls have dark wooden joints instead of grey chinking.
Art and assets#83
- New
Buildings are now planned like an architect would: fourteen kinds from cottages to inns, temples and towers, in many shapes, with real rooms, stairs, front doors facing the camera, bay windows, terraces and furniture that never blocks the way.
WorldGame designArt and assets#101



Developer detail
New crate
uo-buildings: aSpec(kind, style, plot, front, seed) becomes a full plan.- Shapes I, L, T, U, H, Z, cross and courtyard from rectangular wings, storeys per wing.
- A room program per kind and storey (25 room kinds); corridors with rooms off them upstairs in inns, manors and barracks; straight 4-tile stairs under a room of the storey above.
- The front door faces south or east (the camera never turns); east fronts are south plans flipped across the diagonal. Doors inside along a tree from the entrance.
- Windows, arrow slits on fortified buildings, cut corners (octagonal towers), bay windows, terraces with low-wall parapets, crenellated tower tops.
- Furniture from room templates, only where every room, door and stair stays reachable; floors and wall sets by style (Karrak, Aelwyn, Free, Isles).
- Checks: everything reachable from the front door; 14 kinds × 4 styles × 2 fronts × 12 seeds pass, 81–96 distinct layouts of 96 per kind, about 1 ms per building.
uo-buildingswrites plan sheets and a list of sprites the catalog lacks; the client shows generated buildings with--building-gallery <kinds>.- Ordered: diagonal walls, low walls, arrow slits and crenellations (
assets/requests/wall-pieces.md); placeholders until they are baked. Upper storeys can't be walked on yet (2D movement), and buildings are not in the world yet (towns come next).
Week 42, 202612 Oct – 18 Oct · 9 changes
- New
The website now has a devlog. Follow every change, read the blog, discuss posts on our Discord, browse the docs and see the roadmap.
WebsiteInfrastructure#81
Developer detail
The site moved to Next.js (
web/): the landing page is a pixel-identical port, plus/changelog(these fragments, weekly),/blogwith RSS andfeed.json,/docsfromdocs/*.md,/decisionsfrom the CLAUDE.md log and/roadmapfromroadmap.yamlandtasks/. Blog comments are the messages of each post's Discord forum thread, cached forever and revalidated by the bot through a signed endpoint. Media: pre-built variants on R2 behind a customnext/imageloader. CI requires a fragment for engine, asset and chain PRs. Nothing is deployed yet; seedocs/devlog.md. - Internal
Images and videos on the website can no longer disappear because a local copy of the originals was incomplete.
Website
Developer detail
npm run media:variantsused to drop every manifest entry whose original it could not find, so running it against a folder withoutvideo/removed the combat video from the site. Missing originals are now kept with a warning;-- --pruneremoves them on purpose. - Internal
Running the website locally no longer crashes in a full checkout of the game.
Website
Developer detail
next devdied withEMFILE: too many open filesin the main checkout: Velite's watch mode puts chokidar on the whole repo root (its root is..) and filters later, so it walkedtarget/(6.6 GB of Rust builds),node_modules/and.claude/worktrees/.web/scripts/velite-watch.mjsnow watches only the content paths withfs.watchand rerunsvelite buildin a fresh process, one build at a time. - Internal
Every change to the project now gets a note in this changelog, including the ones behind the scenes.
InfrastructureDocs#82
Developer detail
The rule used to apply only to engine, asset and chain changes. Now every PR and every direct commit to
maincarries a fragment, whatever it touches; only edits of the devlog content itself (changes/,blog/,tasks/,roadmap.yaml) are exempt. A new typedev(Internal) covers tooling, CI and infrastructure. The PR check in.github/scripts/check-pr-content.mjsenforces it. - New
Felucca Online has a home page, with real captures from the client and a playtest waitlist.
Website#76

Developer detail
Static HTML and Tailwind v4, flat interface over the game's own pixel art. The logo is shipped as a 1:1 master and only scaled by whole numbers. Gameplay images are client captures, never drawn.
- New
Characters are never lost behind trees or walls any more: a dithered see-through circle opens around every one of them.
Rendering#75
Developer detail
Up to 32 mobiles in view each cut a circle through nearer sprites that rise above their feet: a solid core and a Bayer-dithered rim in whole texels. Floors, rugs and low plants stay. Key 9 or
--disable see_through. - Art
Trees, bushes, flowers and rocks were redrawn from textured models at real size; grown trees now stand 10 to 17 metres tall.
Art and assetsWorld#74
Developer detail
Models from the Quaternius CC0 nature packs, one pack model per variant, scaled to real size (1 unit = 1 m). The baker now clips alpha cut-outs and keeps authored normals on leaf cards.
- New
Walls, doors, fences and trees now take hits, crack, and break apart into debris that sinks into the ground.
WorldRendering#66

Developer detail
Hits shake the sprite and flash it white; cracks follow a seeded Voronoi tiling and grow with damage. The last hit swaps the impostor for chunks built from the sprite itself, so it splits along its own cracks. Leaves and flames burst into particles instead. Durability: stone walls 8 hits, other walls 5, trees and rocks 6. Client-side for now; the server will own it.
- Fix
Fixed black specks that stuck to objects and followed the camera, worst in busy scenes far from the centre.
Rendering#73
Developer detail
The depth prepass and the main pass rebuild the same depth in two shaders that Metal compiles with fast math, so they rounded differently. The main pass now moves its depth 4e-6 towards the camera. Village: 37 k speck pixels down to 0.
