Builds interiors from carved and filled shapes, with Maplet+'s geometry: rooms, doorways, stairs and any convex shape, checked and saved as a model.
Import blitz.maplet As Maplet gives your program these, with Maplet. in front. Each name leads to its part of the reference.
CreateInterior:Interior(name:Str = "Interior")LoadInterior:Interior(file:Str, name:Str = "")LoadError:Str()InteriorSetTexture(texture:Str), SetSides(sides:Int), SetGroup(group:Str), CarveBox(name:Str, x0:Float, y0:Float, z0:Float, x1:Float, y1:Float, z1:Float), FillBox(name:Str, x0:Float, y0:Float, z0:Float, x1:Float, y1:Float, z1:Float), Carve(shape:Str, name:Str, x:Float, y:Float, z:Float, width:Float, height:Float, depth:Float, yaw:Float = 0, pitch:Float = 0, roll:Float = 0), Fill(shape:Str, name:Str, x:Float, y:Float, z:Float, width:Float, height:Float, depth:Float, yaw:Float = 0, pitch:Float = 0, roll:Float = 0), CarveSector(name:Str, x:Float, y:Float, z:Float, innerRadius:Float, outerRadius:Float, startAngle:Float, sweep:Float, height:Float), FillSector(name:Str, x:Float, y:Float, z:Float, innerRadius:Float, outerRadius:Float, startAngle:Float, sweep:Float, height:Float), AddHullPoint(x:Float, y:Float, z:Float), CarveHull(name:Str), FillHull(name:Str), Doorway(name:Str, x:Float, y:Float, z:Float, width:Float, height:Float, depth:Float, yaw:Float = 0), ArchedDoorway(name:Str, x:Float, y:Float, z:Float, width:Float, height:Float, depth:Float, yaw:Float = 0), Stair(name:Str, x:Float, y:Float, z:Float, width:Float, rise:Float, run:Float, steps:Int, yaw:Float = 0), SpiralStair(name:Str, x:Float, y:Float, z:Float, innerRadius:Float, outerRadius:Float, rise:Float, steps:Int, startAngle:Float = 0, turn:Float = 22.5, thickness:Float = 0.25), MarkRoom(name:Str, x0:Float, y0:Float, z0:Float, x1:Float, y1:Float, z1:Float), MarkStart(x:Float, y:Float, z:Float, yaw:Float = 0), MarkPoint(name:Str, x:Float, y:Float, z:Float), AddLight(name:Str, x:Float, y:Float, z:Float, red:Float = 255, green:Float = 255, blue:Float = 255, range:Float = 10), MustBeSpace(name:Str, x:Float, y:Float, z:Float), MustBeSolid(name:Str, x:Float, y:Float, z:Float), MustBeClear(name:Str, x0:Float, y0:Float, z0:Float, x1:Float, y1:Float, z1:Float), MustStand(name:Str, x:Float, y:Float, z:Float, height:Float = 1.8), Build:Int(folder:Str), Error:Str(), FailedChecks:Int(), FailedCheck:Str(index:Int), ShapeCount:Int(), FaceCount:Int(), SavePlan:Int(file:Str, y:Float, size:Int = 1024), SaveView:Int(file:Str, x:Float, y:Float, z:Float, targetX:Float, targetY:Float, targetZ:Float, width:Int = 960, height:Int = 600, fov:Float = 75)Maplet builds the insides of places: halls, cellars, castles, dungeons, caves. Start from solid rock and carve out the space you want, then fill back in what should be solid, such as a pillar, a gallery or a flight of stairs. Your program says what to carve and fill, and Maplet turns it into a model with the walls, floors and ceilings in place, ready to load and walk round.
The geometry comes from Maplet+, a remake of Mark Sibly's Maplet, the interior modeller that came with Blitz3D's early days. What you build here also opens in Maplet+ Extended, if you want to shape it further by hand.

Open hall.bb and run it. It builds the hall in the picture, with an arched doorway into a side room, then lets you walk round inside.
; Builds a stone hall with a wooden gallery up a stair and an arched doorway
; into a side room, then lets you walk round it. Mouse looks, WASD walks,
; Escape quits.
Dialect "modern"
Import blitz.maplet As Maplet
; Carve the rooms out of solid rock. Later shapes win.
Local hall:Maplet.Interior = Maplet.CreateInterior("Hall")
hall.CarveBox("Hall", -6, 0, -8, 6, 7, 8)
hall.CarveBox("Side room", 6.6, 0, -3, 12, 3.5, 3)
hall.ArchedDoorway("Arch", 6.3, 0, 0, 2, 3, 1, 90)
; Fill a wooden gallery back in at the far end, with a stair up to it.
hall.SetTexture("wood")
hall.FillBox("Gallery", -6, 3.4, 4, 6, 3.6, 8)
hall.Stair("Stair", -4.5, 0, -1, 2, 3.6, 5, 12)
hall.AddLight("Lamp", 0, 5, 0, 255, 210, 160, 16)
hall.MarkStart(0, 0, -6)
; Build refuses to write the model if these fail.
hall.MustBeClear("Through the arch", 0, 1, 0, 10, 1, 0)
hall.MustStand("Top of the stair", -4.5, 3.6, 4.5)
If hall.Build("hall") = False Then RuntimeError hall.Error()
Delete hall
; Walk round what was built.
Graphics3D 960, 600, 0, 2
SetBuffer BackBuffer()
AmbientLight 80, 76, 72
Local level:Int = LoadMesh("hall/interior.glb")
EntityType level, 2
Local lamp:Int = CreateLight(2)
PositionEntity lamp, 0, 5, 0
LightColor lamp, 255, 210, 160
LightRange lamp, 16
Local player:Int = CreatePivot()
PositionEntity player, 0, 1, -6
EntityRadius player, 0.4, 0.9
EntityType player, 1
Collisions 1, 2, 2, 3
Local camera:Int = CreateCamera(player)
PositionEntity camera, 0, 0.7, 0
CameraRange camera, 0.05, 100
Local pitch:Float = 0
HidePointer
MoveMouse GraphicsWidth() / 2, GraphicsHeight() / 2
While Not KeyDown(1)
TurnEntity player, 0, -MouseXSpeed() * 0.2, 0
pitch = pitch + MouseYSpeed() * 0.2
If pitch > 80 Then pitch = 80
If pitch < -80 Then pitch = -80
RotateEntity camera, pitch, 0, 0
MoveMouse GraphicsWidth() / 2, GraphicsHeight() / 2
MoveEntity player, (KeyDown(32) - KeyDown(30)) * 0.08, 0, (KeyDown(17) - KeyDown(31)) * 0.1
TranslateEntity player, 0, -0.1, 0 ; Gravity: the floor stops the fall.
UpdateWorld
RenderWorld
Text 10, 10, "Mouse looks, WASD walks, Escape quits."
Flip
Wend
End
The hall is carved first, so the gallery and the stair, filled afterwards, are
solid inside it. Each shape has a name. Build writes the model into the
hall folder beside the program, and the rest of the program loads it like
any other model.
Leave a wall between them by carving them apart, then carve a doorway through it. A doorway stands on the floor in the middle of the wall, and faces along a yaw, as entities do: 0 faces along z, 90 along x. Make it a little deeper than the wall is thick.
house.CarveBox("Kitchen", 0, 0, 0, 6, 3, 5)
house.CarveBox("Hall", 6.2, 0, 1, 12, 3, 4)
house.Doorway("Kitchen door", 6.1, 0, 2.5, 1, 2.2, 0.4, 90)
Carving two rooms that touch makes one bigger room, with no wall at all.
Carve the space the stair climbs through, then fill the steps in with Stair.
For a tower, carve a cylinder and fill a SpiralStair round a post:
castle.Carve("cylinder", "Tower", 19, 0, 19, 10, 24, 10)
castle.Fill("cylinder", "Post", 19, 0, 19, 1.2, 24, 1.2)
castle.SpiralStair("Tower stair", 19, 0, 19, 0.6, 4.9, 23.5, 47)
Each face takes the texture of the shape that made it, so a room's floor is the room's texture. Carve the room a little lower, then fill the floor back with the texture it should have:
hall.CarveBox("Hall", -6, -0.2, -8, 6, 7, 8)
hall.SetTexture("flagstone")
hall.FillBox("Floor", -6, -0.2, -8, 6, 0, 8)
Filling a slab below the room changes nothing, as the rock there is solid already.
Carve and Fill take a shape, a size and a turn: ramps, roof wedges,
pyramids, cylinders and cones, at any angle. CarveSector makes curved
corridors and round rooms. For anything else convex, add its corners with
AddHullPoint and carve or fill the hull round them. Make other shapes from
several pieces.
Add checks. MustBeClear checks that a straight line is open all the way, such
as a corridor. MustStand checks that someone can stand at a place, with a
floor below and head room above: check a stair a step at a time. If any check
fails, Build returns False and leaves the last good model alone, and
FailedCheck says what was in the way and where.
SavePlan saves a picture looking down on the rooms below a height, with the
rooms and any failed checks labelled. SaveView saves a picture from a camera
you place. Both work straight after Build, even without Graphics3D.
Build also writes interior.mapletplus, which opens in Maplet+ Extended.
To go on from a project, open it with LoadInterior and add to it.
Blip's tip
Name every shape. The names say what failed when a check fails, they label the history in Maplet+, and they keep a shape's ID the same each time you build, so a change to one shape changes only that shape.
blitz.maplet.core.geometry, blitz.maplet.core.model, blitz.maplet.core.export, blitz.maplet.core.extended, blitz.maplet.core.persistence0.1.0 unpublished preview. Builds the inside of a building, a dungeon or a
cave from shapes: carve out space, fill solid back in, and get a model, with
checks that rooms join up and stairs can be climbed. The geometry is
Maplet+'s, the remake of Mark
Sibly's Maplet. Extended only; requires object-lifecycle-v1.
Blitz3D+ comes with this module, so any Extended program can
Import blitz.maplet. Open castle.bb and run it: it
builds a castle keep with a round tower off each corner and a spiral stair in
each tower, then lets you walk round it.
Dialect "modern"
Import blitz.maplet As Maplet
Local house:Maplet.Interior = Maplet.CreateInterior("House")
house.CarveBox("Kitchen", 0, 0, 0, 6, 3, 5)
house.CarveBox("Hall", 6.2, 0, 1, 12, 3, 4)
house.Doorway("Kitchen door", 6.1, 0, 2.5, 1, 2.2, 0.4, 90)
house.MustBeClear("Kitchen to hall", 3, 1, 2.5, 9, 1, 2.5)
house.AddLight("Lamp", 3, 2.6, 2.5)
If house.Build("house") Then
Print "Built house/interior.glb"
Else
Print house.Error()
EndIf
Delete house
End
An interior starts solid everywhere. Carve cuts space out of it and Fill
puts solid back, in the order you give them, so a later shape wins: carve a
room, then fill a pillar inside it. The walls, floors and ceilings are the faces
between space and solid, and they face into the space, so the model is meant to
be seen from inside.
Positions are Blitz3D+ world units, which the World Editor treats as metres,
with y up. A shape stands on the point you give: that point is the centre of
its base. Turns are degrees, as RotateEntity takes them: roll first, then
pitch, then yaw; a yaw of 90 turns the shape's front from +z to -x.
Every shape has a name. Names identify the shapes in the saved project, so give each shape its own name; a repeated name is told apart by when it comes. Building the same shapes again gives the same files, IDs included.
| Declaration | What it does |
|---|---|
CreateInterior(name:Str = "Interior"):Interior | A new interior, solid everywhere. Yours: Delete it when done. |
LoadInterior(file:Str, name:Str = ""):Interior | Opens a Maplet+ Extended project (.mapletplus), such as an interior.mapletplus that Build wrote or one shaped by hand in Maplet+, to build on. Its textures are found beside it, or where a full path names them, as Maplet+ names a texture picked in it. Returns Null when it cannot be read. |
LoadError():Str | Why the last LoadInterior returned Null. |
| Method | What it does |
|---|---|
Interior.CarveBox(name:Str, x0:Float, y0:Float, z0:Float, x1:Float, y1:Float, z1:Float) | Carves the box between two opposite corners. The quickest way to make a room. |
Interior.FillBox(name:Str, x0:Float, y0:Float, z0:Float, x1:Float, y1:Float, z1:Float) | Fills the box between two corners with solid: a floor, a wall, a block. |
Interior.Carve(shape:Str, name:Str, x:Float, y:Float, z:Float, width:Float, height:Float, depth:Float, yaw:Float = 0, pitch:Float = 0, roll:Float = 0) | Carves a shape standing on x,y,z, width across x, height up y and depth along z before it is turned. shape is "box", "ramp" (rising from nothing at its front to its full height at its back, +z), "wedge" (a roof, its ridge along z), "pyramid", "cylinder" or "cone". A pitch of 90 lays a cylinder along +z. |
Interior.Fill(shape:Str, name:Str, x:Float, y:Float, z:Float, width:Float, height:Float, depth:Float, yaw:Float = 0, pitch:Float = 0, roll:Float = 0) | Fills a shape with solid, placed as Carve places it. |
Interior.CarveSector(name:Str, x:Float, y:Float, z:Float, innerRadius:Float, outerRadius:Float, startAngle:Float, sweep:Float, height:Float) | Carves part of a ring round x,z between two radii, standing on y: from startAngle through sweep degrees. Angles go as yaw does: 0 points along +z and 90 along -x. An inner radius of 0 gives a slice of a cylinder: a curved corridor or a round room's alcove. |
Interior.FillSector(name:Str, x:Float, y:Float, z:Float, innerRadius:Float, outerRadius:Float, startAngle:Float, sweep:Float, height:Float) | Fills part of a ring: a curved wall, a step of a spiral stair. |
Interior.AddHullPoint(x:Float, y:Float, z:Float) | Adds a corner for the next hull. |
Interior.CarveHull(name:Str) | Carves the smallest convex shape round the points added since the last hull: up to 64, and not all flat. Any convex shape at all. |
Interior.FillHull(name:Str) | Fills the smallest convex shape round the points. |
Settings for the shapes that follow:
| Method | What it does |
|---|---|
Interior.SetTexture(texture:Str) | A picture file, relative to the program's folder, or a built-in look: "stone" (the first), "brick", "wood", "plaster", "flagstone" or "rock". A texture repeats every world unit. The built-in looks are drawn into the output folder as PNGs, so no picture files are needed. A picture other than a PNG or JPEG goes into the model as a PNG. |
Interior.SetSides(sides:Int) | How many flat sides make a cylinder, cone or curve: 3 to 64, 16 at first. |
Interior.SetGroup(group:Str) | The group that following shapes belong to in Maplet+'s History; "" for none. |
These add ordinary shapes, grouped under the piece's name. Copy and change
them freely: they are a few lines each in the module's interior.bb.
| Method | What it does |
|---|---|
Interior.Doorway(name:Str, x:Float, y:Float, z:Float, width:Float, height:Float, depth:Float, yaw:Float = 0) | Carves an opening standing on x,y,z, depth through, facing along yaw. Make depth a little more than the wall is thick. |
Interior.ArchedDoorway(name:Str, x:Float, y:Float, z:Float, width:Float, height:Float, depth:Float, yaw:Float = 0) | A doorway with a round top, height high at the middle. |
Interior.Stair(name:Str, x:Float, y:Float, z:Float, width:Float, rise:Float, run:Float, steps:Int, yaw:Float = 0) | Fills solid steps going up from x,y,z, the middle of the bottom step's front edge, rising rise over run along yaw. Carve the stairwell first. |
Interior.SpiralStair(name:Str, x:Float, y:Float, z:Float, innerRadius:Float, outerRadius:Float, rise:Float, steps:Int, startAngle:Float = 0, turn:Float = 22.5, thickness:Float = 0.25) | Fills a spiral of treads round x,z, each thickness thick, turning turn degrees and rising rise/steps from the one before. Carve the tower first. |
Marks don't change the shape. They tell the World Editor and your game what is
where, in interior.json.
| Method | What it does |
|---|---|
Interior.MarkRoom(name:Str, x0:Float, y0:Float, z0:Float, x1:Float, y1:Float, z1:Float) | Names a room by its bounds. The World Editor makes each room a zone. |
Interior.MarkStart(x:Float, y:Float, z:Float, yaw:Float = 0) | Where the player starts: feet at x,y,z. |
Interior.MarkPoint(name:Str, x:Float, y:Float, z:Float) | A named place, such as where a chest or an enemy goes. |
Interior.AddLight(name:Str, x:Float, y:Float, z:Float, red:Float = 255, green:Float = 255, blue:Float = 255, range:Float = 10) | A point light, saved with the interior. |
Build runs the checks on the finished shape. A failed check stops Build
writing the model, so a broken interior never replaces a good one.
| Method | What it checks |
|---|---|
Interior.MustBeSpace(name:Str, x:Float, y:Float, z:Float) | The point is open space. |
Interior.MustBeSolid(name:Str, x:Float, y:Float, z:Float) | The point is solid. |
Interior.MustBeClear(name:Str, x0:Float, y0:Float, z0:Float, x1:Float, y1:Float, z1:Float) | The straight line between the points is open all the way: a corridor, a doorway, a route. |
Interior.MustStand(name:Str, x:Float, y:Float, z:Float, height:Float = 1.8) | Someone can stand at x,y,z: a floor just below and height of space above. Check stairs with it, a step at a time. |
| Method | What it does |
|---|---|
Interior.Build:Int(folder:Str) | Builds the shape, runs the checks and writes build.json in the folder (relative to the program's folder). When everything passes it also writes interior.glb, with its textures in it, interior.mapletplus, interior.json and textures, and returns True; an interior.b3d that an earlier version wrote there goes. When the World Editor builds the interior, it names the folder in B3D_MAPLET_OUTPUT, and Build writes there instead. |
Interior.Error:Str() | Why the last Build failed, or "". |
Interior.FailedChecks:Int() | How many checks failed. |
Interior.FailedCheck:Str(index:Int) | A failed check, 0 to FailedChecks()-1, with what was found: "Tower door: expected space at (15.5, 1.5, 15.5), found solid". |
Interior.ShapeCount:Int() | How many shapes have been carved or filled. |
Interior.FaceCount:Int() | How many faces the last Build made. |
interior.glb loads with LoadMesh, with its textures in it, as matt
materials: lit as any glTF model is, so give it lights, not only
AmbientLight. Collide with it as you would with any level: EntityType and
polygon Collisions. The World Editor can take its materials out of it to
change them. textures holds the same pictures, for the project. interior.mapletplus opens in
Maplet+ Extended. build.json holds the outcome, every check and any problems,
for tools; interior.json holds the rooms, start, points and lights.
Building takes from a moment for a few rooms to some seconds for a few hundred
shapes, such as the castle's spiral stairs. Build keeps the geometry after
every 16 shapes in .build.cache, so building again after a change starts
from the last of those before the first shape that changed: the castle builds
in 20 seconds the first time, and in 3 when nothing or only its last shapes
changed. build.json's reused says how many shapes it skipped. Delete
.build.cache whenever you like; the next build makes it again. Its name
starts with a dot, so games packaged for the web or the Mac leave it out.
Pictures of the last build, which work even when checks failed, so you can see
what went wrong. They are drawn in a hidden window and a world of their own,
with or without Graphics3D, and never touch your scene.
| Method | What it does |
|---|---|
Interior.SavePlan:Int(file:Str, y:Float, size:Int = 1024) | A floor plan, looking straight down from height y: everything below it, with the rooms, the start and any failed checks labelled. size is its width in pixels. A relative file goes in the last build's folder. |
Interior.SaveView:Int(file:Str, x:Float, y:Float, z:Float, targetX:Float, targetY:Float, targetZ:Float, width:Int = 960, height:Int = 600, fov:Float = 75) | A view from x,y,z looking at the target, lit by the interior's lights. A relative file goes in the last build's folder. |
Shapes are convex pieces; make other shapes from several. A hull takes up to 64 points. Maplet+ maps each texture flat onto each face, repeating every world unit. The model has no lightmap: light it in the World Editor with Bake lighting, or with lights in your game.