Skip to content

RPG Reactor 0.97.0

Latest

Choose a tag to compare

@github-actions github-actions released this 03 Aug 02:38
· 3 commits to main since this release

Added

  • A building can be declared on the map, not just in the tileset. A tileset can say what a tile is and nothing more: an autotile id is a corner arrangement shared by forty-eight shapes, so three shops built from one wall kind are indistinguishable to it, and an autotile has no place in a drawing for a declared rectangle to point at. Which cells make up one building is a fact about a placement. So there is a new palette tab beside Regions where you paint object numbers onto the map, and cells sharing a number are one object — a building assembled out of bits of three others is one thing and says so. A Footing brush marks which of its rows are the ground it stands on rather than courses of its height.

    This is what makes decoration hold still against the thing it is painted on. A flag hung on a shopfront is a picture tile, and picture tiles could never join a wall's facade, so the flag became its own object with its own footing two rows nearer the camera and slid sideways against the wall as you walked. Inside one painted object there is one anchor and one plane, so everything on the building moves with the building.

  • Walls classed Upright are solid too. Massing raised by the tileset's classes had already gained real sides; a wall stood up as a cut-out had not. It was one plane at the southern end of its run — correct from the front and nothing at all from the side, so walking round a shop thinned its front to a line and it vanished. 2D never draws a building's sides so there is no art for them, but the wall's own art is a better answer than a hole. Each is now a box a tile deep, with ends only where the run actually stops, and those ends take their picture from the same shape quadrants the front does rather than from the block's corner piece.

  • Flying the editor's 3D camera with WASD, Q and E for height and Shift to hurry, alongside a hover outline showing which cell the cursor is over, boxes drawn round events so they read as events, and dragging events in 3D as you can in 2D. Escape now lets go of whatever is held.

  • A page set to Custom movement can finally be given a route. The type could be set and there was no way to author what it did, so Custom meant "stand still". A Route… button beside the dropdown opens the same dialog the Set Movement Route command uses, minus the two questions a page has already answered.

  • Buildings in 3D are solid boxes rather than a single wall. A wall run drew one plane at the southern end of itself, so a building was inside-out from the north and a line from the east. Every wall tile on every map already records which of its sides face open air — that is what an autotile's shape is, sixteen of them for four neighbours — and the renderer was reading one bit of it and discarding the rest. It now builds each exposed side, one course of wall art per tile of height, with end caps where the run stops and none where it carries on. Nothing is authored and no project data changes: the information has been sitting in the map files the whole time.

  • A raised wall is capped with its roof. A wall autotile draws a wall face and has no top, so a building wore its own front as a hat. A4 pairs a roof with every wall by its own layout — rows alternate, eight kinds to a row — so that pairing is derived. A3 is walls throughout and has none to derive from, so the tileset editor gains a Roof tool: click a wall, then click the tile that covers it. The roof picks its corners from the mass it covers exactly as the same roof painted flat would, so a run of wall reads as one continuous surface rather than a row of separate huts.

  • Panel: a 3D shape for things with a front. A gate, a door, a signpost or a shopfront was drawn as a camera-facing cut-out, so it swung to follow the viewer — right for a bush, absurd for a gate you were walking through. A panel stands still, faces a direction, and has a little depth, so seen from the side it reads as a gate seen from the side instead of vanishing. Which way it faces is worked out rather than authored: a gap in an east-west wall faces south, a gap in a north-south wall faces east, a panel with something solid on one side turns its back to it, and anything else faces the way RPG Maker art is drawn. Set it per tile in the 3D Shape editor beside Flat, Upright, Scenery and Foliage.

  • A 3D map drew in 2D whenever it was the first one entered. three.js is fetched the moment a 3D map loads, and the spriteset decides which renderer it is building the instant it is created — but the scene started the fetch and built the spriteset in the same tick, so the decision was always made before the two megabytes had arrived, and nothing asked again once they had. The symptom looked impossible from the outside: the library sitting plainly in js/libs and the map rendering flat anyway. The scene now waits for the fetch before building anything, and an ordinary 2D map is not delayed by a frame.

  • The 3D view in the editor no longer snaps back while you work. Every rebuild — and one runs on every edit — re-framed the map, resetting both where the camera was looking and how far it had zoomed. Orbiting or painting threw the view away and put it back at the whole-map framing, which reads as the camera being broken rather than as a reset. The map is framed when it is a different map now; double-clicking empty space is still the way to put the whole map back in view, and is now the only thing that moves the camera on your behalf.

  • Editing a map in 3D no longer discards elevation painted since the last save. The rebuild re-read Map###.r3d.json from disk each time, so heights that had not been saved yet were replaced by whatever the file still held.

  • Lights are lights on a 3D map, not pictures of light. A lighting plugin draws circles and cones onto the screen, which over a 3D world lands flat across it instead of pooling on the ground and climbing walls. Reactor now reads the lights a plugin owns and puts them in the scene: a lantern becomes a sphere, a flashlight a cone down a corridor, and the ground and the buildings respond to both. MVNovaLighting and PSYCHRONIC_RaveLighting are covered, and both can be installed at once. Neither plugin is modified — its own flat lightmap is hidden while the real lights are drawn, and comes straight back when they are not.

    It is opted into per map with <3d lights> in the note, beside the <3d> that makes a map 3D at all, because a project already lit to its author's satisfaction should not have that quietly replaced. A map that has not asked keeps exactly what it had. The dimness of an unlit corner is authorable in the map's sidecar; the default is dim rather than black.

    Reading a plugin's internals is the only way to reach its lights, so that reading is quarantined in one small function per plugin, each free to fail: a plugin updated underneath Reactor costs its lights and prints one warning, rather than taking the map down.

    Lights are drawn rather than simulated. One THREE.PointLight per light is the obvious implementation and does not survive a real map: three.js sizes its light uniform arrays to the number of lights in the scene and compiles that count into every material's shader, so a city with a lantern on every corner overruns the fragment shader's uniform budget, the program fails to link, and the map draws nothing at all. Capping the count to fit is no answer either — twelve lights on a street of a hundred is not lighting.

    But a 2D lighting plugin never simulated anything. Its light is a shape: a radius, a colour, an alpha — a soft disc it stamps on the screen. So each light becomes a quad lying on the ground, sized to its own radius and tinted by its own colour, added to what is already there; a cone gets a cone. All the lights of one shape share a single geometry and material, so a hundred of them is one draw call and no shader uniforms whatsoever, and the buffers are allocated once and rewritten in place. The only real light in the scene is a single ambient one, which is the darkness the rest are read against.

    The lights are a pass of their own, drawn after the ground and after the tiles that cover characters, and composited by addition. Sharing a pass with those tiles will not do — a tree has to cover what is behind it, and light covers nothing — and drawing lights beneath the characters put every sprite, and the whole of the rest of the scene, on top of them. How strongly a light reads is a single number, because the alphas a plugin chose were meant for a flat overlay multiplied into a dark screen rather than a pool added to a lit one.

  • Characters can walk behind things in 3D. The star flag is what lets the 2D tilemap draw a tree or a doorway over a character; in 3D the ground was one picture behind every sprite, so nothing could ever be in front of anyone and a character walked over the front of everything. Star-flagged geometry is now drawn in a second pass laid over the sprites, mirroring the tilemap's own lower and upper layers, so the same tiles occlude the same characters in both views. A map with nothing flagged pays nothing: the second pass only exists when there is something to put in it.

  • Sprites are sized by depth, so the people are in the same perspective as the map. They were scaled by the projected height of a world-vertical segment, which is the natural measure and the wrong one: a pitched camera foreshortens such a segment, and that foreshortening eases with distance at close to the rate perspective shrinks it. The two cancelled — every sprite came out the same size wherever it stood, and the whole 3D treatment of characters amounted to nothing visible. A billboard turns to face the camera and is never foreshortened, so its size is the plain perspective divide, which is what it now uses.

  • The star-flagged pass is drawn inside the tilemap, where the tilemap's own upper layer sat, rather than as a sibling of it — so fog, weather and plugin overlays cover it as they always did. The light pass sits above all of them and is kept there, because plugins add their layers long after the spriteset is built and each one lands on top of whatever is already there.

  • A coloured light keeps its colour. The quads are added, so a channel pushed past full clamps while the others carry on climbing, and an amber lamp turned white from the middle outwards; the three are scaled together now, which costs brightness and keeps the hue. A cone fills the wedge it was given, too — both its falloffs were squared, which drew a thin bright plume up the middle of a correctly-sized beam and read as a narrow strip.

  • Characters are scaled by distance on a 3D map. They were positioned by the projection but never sized by it, so a figure at the far end of a street was drawn exactly as large as one at your feet — the map was in perspective and the people on it were not. One tile of world height is the reference, so a character keeps its size relative to the ground it stands on.

  • Everything standing in 3D now shares one idea of where the ground is. RPG Maker puts the foot of anything standing on the bottom edge of its cell — screenY is scrolledY * tileHeight + tileHeight, not the middle — and the 3D anchors used the cell's centre. Half a tile, on every prop and every character, which is why a street light sat short of the plate it stands on however its own height was measured. Props, character sprites, and the position plugins are told all use the same edge now.

  • Event previews in the editor could show the previous map's art. An event whose graphic is a tile is drawn from the tile palette's sheets, and those load asynchronously when a map opens — so a preview drawn before they arrived used whatever tileset the last map left behind, until something forced a redraw. Those events are re-rendered once the palette has its sheets, and only on maps that have any.

  • The editor allocated a fresh GPU texture for every event's character sheet on every rebuild of the event layer, and freed none of them — and each image that finished loading triggered another rebuild. Sheets are cached by path now, and dropped when the project changes.

  • Tall props stood halfway up their own height. A standing cut-out uses its map rows as height — that is the whole idea of standing a drawing up — but anchored itself on the middle of those rows as though they were a footprint. So a four-tile street light planted its feet two tiles north of the tile it belongs to, which at a pitched camera reads as floating above the ground; the taller the prop, the further off it sat. Cut-outs now stand on their southern row, which is the row the player walks on and the row their base height was already taken from. Columns are genuinely width, so an object still turns about its own middle rather than swinging around a corner.

  • An object could not be declared if it reached the top-left corner of a sheet. That cell is tile 0, which is also the engine's "no tile", so the declaration was refused — silently, since the two meanings had been conflated into one rule. They are separate questions now: tile 0 is a real place on a sheet and can be an object's corner, while a lookup for it is still refused, because an empty map cell reads as 0 and must not match anything. Overlap between objects is judged as rectangles on the sheet rather than by the tile ids they cover, which could not tell a real tile 0 from the 0 meaning "off the edge".

  • The tileset editor's 3D Shape key gains entries for the Roof tool, and the pairing it records is drawn: a wall that has been given a roof is marked, and so is the tile serving as that roof. The tool could set a pairing that nothing showed, so there was no way to see it or find it again.

  • The tileset editor's Remove appeared to do nothing. It removed the object, but the selection had been taken from that object a moment earlier and was still drawn — a box the exact size of the thing just deleted, which looks identical to it still being there. The selection now shrinks to what was dragged, the removal is saved, and it says what it did.

  • A prop too wide for one drag can be declared in pieces. A B–G sheet is sixteen columns shown as two eight-column halves stacked, so a tower or smoke stack crossing the middle appears as two pieces on different rows of the palette and cannot be dragged out in one go — though it is a single rectangle on the sheet itself. Shift-drag now adds a piece to the object just declared, merging them in sheet coordinates.

  • The 3D ground is drawn into the game's own scene rather than on a canvas behind it. Stacked canvases put the map outside the display list, and everything a game draws over the map assumes it is in there: a fog or lighting overlay set to MULTIPLY had nothing to multiply against and composited as a flat wash, so fog read heavier in 3D than in 2D; and the screen tone, which is a filter on the spriteset, never reached the ground at all. The 3D render is now a sprite where the tilemap's ground used to be, so tone, fog, blend modes and overlays reach it exactly as they reach a 2D map. It also removes the three separate opaque layers that had to be got out of the way to see it.

  • Characters report where they actually appear on a 3D map. screenX/screenY returned the scroll-based 2D position, which on a 3D map is nowhere in particular — the ground is projected through a camera with pitch and yaw. Reactor's own character sprites already projected themselves, but everything else that asks a character where it is — lighting plugins, pop-ups, mini labels — was told the 2D answer, which is why a light sat somewhere other than the thing it belonged to.

  • Going fullscreen left a 3D map drawn as a small rectangle in the middle of a black screen. The 3D canvas is a sibling of the game canvas rather than one of Graphics' own elements, so every rescale missed it and it kept the size it was built at. It now follows the game canvas through every resize, including entering and leaving fullscreen.

  • A full-screen black sprite was painted over the 3D map before anything else. Spriteset_Base puts a ScreenSprite at opacity 255 — an opaque black rectangle covering the whole screen — at the very bottom of every scene, so the page cannot show through where the map does not reach. On a 3D map the map reaches everywhere and the 3D canvas is what should show, so PIXI was covering it before drawing a single tile. It is hidden while a 3D map draws, alongside the parallax, and restored for everything else. Together with the canvas alpha channel below, these were three separate opaque layers between the 3D ground and the eye, each one enough on its own to hide it completely.

  • The game canvas had no alpha channel, so nothing could ever be seen behind it. PIXI decides whether the drawing buffer carries alpha once, when the renderer is created, from whether the background is already translucent — and never again. At the default it asks the browser for alpha: false, which makes the canvas opaque at the compositor level no matter what the clear colour says afterwards. A 3D map draws on a canvas underneath, so the ground was built, textured, aimed and rendered correctly every frame, and then composited away. The channel is requested at startup and the opaque default restored immediately, so a 2D map looks exactly as it did.

  • The 3D ground was drawn and then painted over, every frame. The two canvases are stacked — 3D underneath, the game canvas above — so PIXI can keep drawing windows, pictures and every plugin sprite on top. That only works if the game canvas is transparent where nothing is drawn, and PIXI clears to opaque black. So the 3D scene built correctly, hid the 2D tiles as intended, and was then covered by the very canvas it was meant to show through: characters visible, no tiles, no 3D. The canvas is made transparent while a 3D map is drawn and opaque again for everything else — a 2D map, a failed build, or leaving the map for a menu or a battle.

  • A parallax is no longer drawn on a 3D map. It is drawn on the game canvas, so it sat over the 3D ground and hid the world behind a sky. 3D maps do not draw a parallax yet; this is now why, rather than an oversight.

  • Asking whether WebGL works cost a WebGL context, every time it was asked. Both capability probes — Reactor3D.isSupported and Utils.canUseWebGL — created a canvas and took a real context to find out, then dropped it on the floor. A browser's budget is about sixteen. shouldRender3D calls the first one, and every character sprite calls that on every frame, so a 3D map with a hundred events took a hundred contexts a frame; MV compat exposes the second as Graphics.hasWebGL(), which MV plugins call freely. The browser began evicting live contexts, which took out the game's own renderer and left PIXI compiling shaders against a dead context — a white screen, from a question with a fixed answer. Both are answered once now, and hand the probe context straight back.

  • A 3D map could take the whole game down with it. The 3D scene is built inside createTilemap, inside onMapLoaded, which the scene calls from isReady — and isReady only marks the map loaded after that returns. So anything that threw while building left the scene reloading the map every frame forever: a white screen, and a fresh WebGL context each time until the browser began evicting live ones ("Too many active WebGL contexts", thousands of times). 3D is a view of the map; it can fail, and the map still has to draw. A failure now falls back to the 2D ground with the error printed once, and is not retried.

  • The 3D scene was built before the tileset sheets had loaded. createTilemap starts the sheet loads and built the scene in the same breath, so its textures were read from bitmaps that were still empty. It waits for them now, retrying from the frame update — a sheet that never arrives leaves a 2D map rather than a hung game.

  • A 3D map that renders flat now says why. Every gate between "the note says <3d>" and "the scene is built" — the note, WebGL support, three.js being present — could fail without a word, leaving an ordinary 2D map on screen that looks exactly like the feature not existing. The reason is printed once, and only for maps that asked for 3D.

  • node editor/build-scripts/sync-runtime.cjs copies the canonical runtime into every bundled project, with --check to report drift without changing anything. Each project keeps its own copy of the runtime in js/, as a real project does, and they had drifted silently — a runtime fix verified against a stale copy has not been verified. A test now holds every project present to the canonical version.

  • The 3D view is framed and proportioned like the 2D one. The camera sat at a fixed distance that showed about a quarter of the map, so everything arrived at twice its flat size: sprites upscaled past the resolution their art was drawn at, and every light twice the size its author chose. The distance is now derived rather than tuned — the point at which a tile under the focus covers the same pixels it would on a flat map — so it stays right on a project with a different tile size, resolution or field of view.

  • Cut-outs face the camera, so art keeps the proportions it was painted at. Standing them bolt upright is the honest reading and the wrong one for flat art: a pitched camera foreshortens a vertical plane to about six tenths, so every character came out squat and every sign shorter than it was drawn. It also meant the two ends of a wide sign leaned by angles some fourteen degrees apart, which no sprite can reproduce, being a rectangle. Facing the camera removes all three at once — a quad parallel to the image plane projects to a plain scaled rectangle. The trade is that a cut-out leans back with the camera rather than standing in the world; it is authorable per map with billboardTilt in the sidecar, and props and sprites both read the one number so they cannot disagree.

  • Anything hung on a wall follows its art onto that wall. A cell whose picture is stood up is no longer where the map says it is: it has moved onto a vertical plane at the wall's footing, some courses up. Signs, doors and the animations played on them stayed on the floor at their own row, so they sat at the wrong height and the wrong depth — and depth is what made them slide against their own building as the camera panned, because two surfaces at different distances do not move together. The lights a plugin owns follow the same rule, so a shopfront's glow lights the shopfront rather than the pavement.

  • Events that place a tile become part of the world. A door, a sign, a chest or a barrel is usually an event with a tile graphic rather than painted art, and the scene was built from the tile layers alone — so those stayed flat while the identical tile painted one cell over stood up properly. A classified event tile is now built into the scene as a prop, and its flat sprite stands down so the thing is not drawn twice. Events that move keep their sprites, since a prop is baked in at build time and cannot follow anything about.

Changed

  • The tileset editor's 3D Shape mode says more clearly what it has recorded. Selecting a declared object drew three boxes at once — the object's own outline, the selection tracing the same rectangle a pixel inside it, and the single-cell highlight the other edit modes use, sitting on whichever square was clicked. That last one made a click look as though it had picked one square out of the object, which is the opposite of what declaring an object is for. A selected object now carries one box and a wash across the whole rectangle, and the cell highlight is left to the modes that work a cell at a time.
  • A declared object's class is drawn in the middle of the object rather than in its top-left corner, where it read as one cell standing up while the rest of the picture lay flat. Where the middle of an object is a cell that has been laid flat, the class rises clear of that cell's own bar instead of printing on top of it.
  • The 3D selection is forgotten when you change tileset or leave the mode. It was a rectangle on one sheet of one tileset and was kept regardless, so it came back as a box around whatever art now occupied those cells — including on sheets it was never made on.
  • The current development version is 0.97.0.

Fixed

  • Grouping a building, saving, and reopening the project lost the grouping. It was written to disk correctly and never read back: the map's 3D sidecar was attached only when the 3D view opened, which held while everything in it was something only that view could show. Painting again over an unread sidecar and saving would have written one built from nothing.

  • A whole structure vanished while it was still on screen. A cut-out is not where its vertices say it is — its quad is built in the vertex shader, so every vertex of one object sits at the same anchor and the corners are carried out from it by a separate attribute. Three.js measures the bounding sphere from the positions, so it measured the anchors and nothing else: a six-by-six building had every anchor at a single point while its art reached almost seven tiles away, and it was culled the moment that point left the frustum.

  • Things drew over things they were standing behind. A cut-out is drawn without writing depth, because its soft edges have to blend with what is behind them, so within one merged buffer the last thing written is the thing you see — and the order was whatever the grouping passes happened to produce. 2D never has this problem because it draws row by row. Cut-outs and wall runs are now emitted north to south, so whatever stands further north goes down first.

  • An animation played over the entire map however far away it was. An animation carries no depth of its own, so it was left in front of everything — the convention in 2D, and fine there, but 3D draws the world in two passes and an animation floating over both is in front of the whole world. One played on a target now takes that target's place, so whatever covers the character covers its animation; one set to Screen is untouched, because it was never on the map to begin with.

  • A scenery event with a move route stood on the ground rather than on its building. Pinning a walking event to a wall would carry it up the facade as it crossed, so having a route ruled the facade out flatly — but most routes on scenery do not walk. They turn, wait, or animate in place, and the event stands where the author put it for the whole game. The question is now whether the event has left home, not whether it has a route.

  • Chunks were missing out of mountain ranges in 3D on maps that look solid in 2D. Where a tileset says one picture is drawn across several tiles, the 3D view was building it at the size of a single tile — so the art came out squashed and, being narrower than the ground it stood on, left bare strips beside it that read as bites taken out of the range. Cut-outs are now built at the size of the art they are drawn from, and never narrower than the cell they stand on.

  • A tile marked ☆ is drawn in front of ordinary tiles sharing its square in 3D, as it is in 2D. The top of a column could appear behind a plate of food resting against it.

  • Objects turn about their own centre when the 3D camera is orbited, and stand where the 2D map draws them. A column in the middle of a pool drifted to its edge as the view came round. Standing art now pivots on the middle of its square, while its visible base sits on whichever edge of that square is nearest the camera — which is where a real object's base reads from, and what keeps it seated at every angle.

  • An object no longer disappears in 3D when something is placed on top of it. A plate set down on a column made the column vanish: a cell can hold several standing tiles, as it does in 2D where they are drawn one over the other, but the 3D view was taking only the topmost and discarding the rest. All of them are drawn now, in the same order 2D draws them.

  • A column with something resting on it no longer comes apart in 3D. Its two halves were being treated as belonging to whatever was set down on them rather than to each other, so they drifted and turned as separate pieces. An object's parts are kept together, and anything sharing its square is its own object.

  • Painting a 3D shape onto a tile now takes effect straight away. The Roof, Clear and Object tools saved the change; painting Flat, Upright, Scenery, Foliage or Panel did not, so it showed on the map only after switching the 3D view off and on.

  • The 3D view no longer sometimes comes up blank until the mouse is moved over it.

  • Editing a tileset in the Database now shows up on the map straight away. Changing passability, the star flag or a tile's 3D shape left the map editor using the old settings until the project was closed and reopened — the map keeps the tileset it read when it was opened, and nothing told it otherwise.

  • Opening a project with the 3D box ticked now gives you a 3D map. The box stayed ticked from the previous project while the map came up in 2D, and had to be unticked and reticked before it agreed.

  • Tiles no longer take their layer from the tab they came from. A tile from the B tab was placed lower than one from C, which was lower than one from D, purely because of the letter — so the same object sat at a different depth depending on which tab you happened to take it from. Tiles from every picture tab now go to the top of the stack, with whatever was already in the cell moving down beneath them — so something painted over another thing is the thing you see. Checked against nearly 300,000 authored tiles in the bundled projects. To put a tile under what is already there, choose the layer by hand. Tiles marked with a star — the ones drawn over characters, like a tree canopy or the top of a doorway — keep their place instead: a plain tile painted into the same cell goes underneath them, as it does in RPG Maker.

  • A tileset sheet added in the Database can be used immediately. Adding one to the E, F or G slots left it missing from those tabs until you pressed Save beside the tileset's name, and a tile placed from one in the meantime disappeared, because the sheet had never been loaded. Assigning a sheet now tells the map and the palette straight away.

  • Walls cast shadows now, and lose them when erased. Placing a wall left no shadow beside it, and erasing one left any shadow that was there behind — so a wall removed from a map still had its shadow sitting on the floor. Walls now shade the cell to their east as RPG Maker does, from the brush, the rectangle and circle tools, bucket fill, the eraser and a pasted stamp alike, and a shadow you painted yourself with the shadow pen is left alone.

  • A piece of map copied with a right-drag now comes down as a finished piece. Pasting kept the exact tiles it was lifted from, so a stretch taken out of the middle of a wall arrived with no ends on it and read as a wall with a slice cut out. Autotiles are rebuilt where they land, the way RPG Maker does it, and a copy pasted against an existing wall joins it. Hold Shift to put the tiles down exactly as they were lifted instead.

  • Painting a tile over another one wiped it out, and left the new tile unable to join its neighbours. A table set down on a floor erased the floor; a stretch of road erased and painted back came out with hard ends instead of rejoining the road either side. The editor chose which of the two ground layers a tile belonged on by looking at whether its artwork had transparent pixels, and that is not what decides it — a tile goes above what is already there when it is a different terrain, whatever it is drawn with. A tile also joins whichever layer the same terrain is already using right beside it, so a stroke continues the run it is touching rather than starting a second one underneath it. Checked against every autotile in the bundled projects' maps, nearly two million of them, the old reading agreed with how RPG Maker itself laid them out 84% of the time; the new one agrees on all but two. Bucket fill is unchanged: filling grass with dirt still gives dirt, rather than dirt on top of grass.

  • The front row of a mountain range floated above the ground in 3D. Standing art that touches shares one base, so a wall with an uneven bottom does not tear apart — but that base was also being used to decide how high each part of it sat, and a range's southern edge steps back a tile at a time. Every column that stopped short was drawn hanging, with a gap underneath where the ground should meet it, which read as chunks bitten out of the front of the range. Over ten thousand columns across the bundled project's maps, some of them twenty-one tiles up. Standing art now comes down to the ground unless something is genuinely holding it up — an archway keeps its opening, because it has posts either side — and nothing about the depth it is drawn at changes.

  • The map jittered and snapped back when you panned past its edge. Holding the scroll wheel and dragging moved the view immediately but only corrected it once a frame, so pulling past the edge drew the map outside itself and hauled it back a moment later, over and over. A pan now stops at the edge and stays there, and moving back the other way picks up straight away instead of having to undo the overshoot first.

  • A 3D map was darker than the same map in 2D. The ground was shaded with a Lambert material under an ambient light on the assumption that full-white ambient equals unlit. It does not: three divides diffuse by pi, so "ambient 1" is nowhere near "unlit", and the exact factor moves between releases. Nothing here needs a light model — the lights are additive quads in a pass of their own — so the scene is now shaded the one way guaranteed to match the 2D tilemap pixel for pixel: not at all, with the ambient applied as a plain multiplier.

  • Signs crept against their own buildings while walking. Three separate causes, each measured against the running game rather than inferred. The camera was aimed after the sprites had projected through it, leaving them a frame behind the world — invisible standing still, and worst for whatever sat furthest from the focus. A sprite's size was measured across one tile and multiplied by its height, which is wrong because perspective is not linear: a three-tile sign landed its top edge twenty pixels out at the near end of a street and fifty-six at the far end. And a cell's height was recorded as a single world number, when a cut-out's courses are stacked along an axis that leans with the camera; the wall's footing and the lift up it are now kept apart, with one helper turning them back into a world point so nothing works it out for itself.

  • Flashlights were the wrong size and hard-edged. A cone's size is neither its scale nor its bitmap: Sprite_Light.refresh draws it at scale / bitmap.resolution times the bitmap, and scale for a cone holds a fallback the plugin never fills in. Reading either alone gave a ten-tile wedge or a two-tile needle. Lights are also built on the same camera-facing axes as everything else rather than lying flat on the floor, where the camera's pitch shortened them to about six tenths, and their pictures are drawn at four times the resolution with a softer shoulder so the edge fades rather than steps.

  • You walked in front of things you should have walked behind. The tilemap re-sorts its children by z every frame, so the pass carrying star-flagged geometry — added last, with no z — sorted as 0, under every character at 3. Only two of the seven geometry primitives were asking whether a tile draws above characters, as well; all of them do now.

  • Doors and braziers trailed the party across the map. An event whose tile is built into the scene has its flat sprite hidden, but the hide was applied while positioning and update settles visibility afterwards, so it was undone a moment later. The sprite was drawn a second time and never repositioned, and a stale sprite under a moving camera reads exactly like something following you.

  • Animations played at flat size over a 3D map. An animation is not a child of the sprite it plays on — it lives in the spriteset's effects container — so it never inherited the scaling that puts a character in proportion with the world.

  • The 3D preview in the tileset editor showed an empty box instead of the tile. Every path that renders a tileset layer caches its work under the file named the way it was loaded, with its extension; the preview looked the same layer up under the bare name held in the tileset record, missed every time, and fell back to drawing a blank placeholder. All of them now build that key one way. The test covering this had been written against the failing lookup, so it agreed with the preview and with nothing that fills the cache.

  • The 3D preview drew every unclassified tile standing up. A tile's class was read for the tint on the sheet but not for the preview beside it, which always gave a single tile a standing role — so Flat, Upright, Scenery and Foliage all previewed identically, and the one decision the panel exists to show could not be checked in it. The preview now lies a Flat tile down, and names the class under the picture.

  • A 3D tool that cannot apply now says why. Declaring an object on an A1–A4 autotile is refused by design — an autotile id is a corner arrangement rather than a place in a drawing, so a rectangle of the sheet means nothing there — but the refusal only reached the console, so the button appeared to be broken. It is written in the tool panel now, with what to use instead.

  • Opening a second project kept the first one's tile size in the tile palette. The map canvas is rebuilt for each project and reads the size on the way up, but the palette is built once and kept for the life of the editor, so it never re-read it. Opening a 32-pixel project from a 48-pixel one therefore drew a correct map beside a palette whose grid lines and selection box were half again too big for the art under them. Every map load re-reads it now, which is also what an open project's Database change already went through.

  • Event graphics on the map were drawn at 48 pixels regardless of the project's tile size, so on a 32-pixel project every event sprite overflowed its own tile by half and spilled across its neighbours. The same fixed 48 was in the event page editor's graphic preview and in the Transfer Player map picker, where it also put the grid and the click target out of step with the map being previewed.

  • An event whose graphic is a tile took that tile from the wrong place on the sheet. B–E sheets are 256 tiles arranged as two halves of 128 drawn side by side; both surfaces that draw an event's tile graphic read them as one 8-wide grid instead, so any tile past the 128th sampled off the bottom of the sheet, and the F and G sheets added in 0.96.0 were mistaken for E. They now share the definition the map canvas uses.

  • Projects that use a tile size other than 48 rendered as a mosaic of the wrong art. RPG Maker MZ lets a project choose 48, 32, 24 or 16 pixels and records the choice in System.json, and Reactor's own Database has always offered the setting — but the editor's map view, tile palette and tileset editor were written when 48 was the only answer, and sampled every sheet in 48-pixel steps regardless. On a 32-pixel project each read landed one and a half tiles further along than it should and the error accumulated, so the map drew as repeating fragments of unrelated tiles. The game itself was fine: the runtime already read the setting. Every surface that measures in pixels reads it now — the map view, the tile palette, the tileset editor, the hover preview and the 3D view — and changing the setting in the Database redraws the open map instead of waiting for the next launch.

  • The tileset editor's marks did not fit a tile smaller than 32. The passage arrows sit a fixed distance in from each edge, so on a 16-pixel tile the left and right ones landed on the same point and every direction read alike; a ladder icon ran into the tile beneath it; and the 3D class marks came out a negative width, which a canvas draws backwards, into the neighbouring tile, rather than not at all. The marks now come in with the cell below 32 and are untouched at 48 and 32, where they are deliberately kept full size rather than shrunk to something nobody can read.

  • The web editor did not start at all. It stopped on Node module "os" is unavailable in RPG Reactor Web before drawing anything. The component that launches extra editor windows on desktop asked for os and child_process while being constructed, and the web build has neither — it already knew to decline once it saw they were missing, but it never got that far, because asking was itself the error. It now asks in a way that can come back empty. Not yet run against the web builddocs/HANDOFF.md records what to check.

Next up is the unfinished 3D work listed under 0.96.0: wall tops, the forest
arrangement, parallax and sky, and incremental rebuild while painting.