βΆ Video walkthrough
A run through the whole setup β pointing the editor at your own game files, loading terrain and the map layout, building, and exporting SQF for the server. The fastest way in if you would rather watch than read.
Your files stay on your computer
The editor runs entirely in your browser. Projects are saved to your browser's own IndexedDB database on your machine, and any SQF or asset-pack files you open are read locally in the page. Nothing you load, build or export is uploaded to ArmaTools β there is no account and no server-side processing. (The site's host adds a cookieless page-view beacon to every page; details in Projects and local data below.)
1 What works now
Everything listed here is implemented and tested.
- 3D viewport β orbit, pan, zoom, focus selection, top-down view, configurable grid, ArmA-coloured world axes and a map boundary box for the common Epoch maps.
- 2D map view β press M or use the 3D / 2D Map toggle for a north-up orthographic view, the way the original ArmA editor worked. It is the same scene, not a second editor: selection, placement, snapping and the gizmo all behave identically, and anything you select in one view is selected in the other. Panning and zooming only β a map does not orbit β and the gizmo drops the axes that mean nothing from overhead.
- Object library β 1,700+ real ArmA 2 / Operation Arrowhead / Epoch classnames, categorised and searchable. Objects seen in real Epoch map additions are marked and ranked first. Favourites and recents are remembered. Load a mod under Assets and its own classnames join the list, marked β, categorised from the
CfgVehiclesinheritance tree β so an addon's objects are searchable without anyone having to teach the editor about that addon. - Placement β click an object, click in the viewport. A translucent preview follows the cursor, placement stays active for repeat placement (Alt+click to place just one), and a chip over the viewport says how to stop. New objects export as
setPosATLβ see below for why that matters. - Ground alignment β Drop to ground under Position, and Align to terrain under Rotation: the Epoch build-mode behaviour that tilts a piece onto the slope it stands on, with a Level button to put pitch and roll back to zero. Yaw is never touched by either β which way a wall faces is your decision, the ground under it is not.
- Selection β click, shift-click, box select by dragging, select-all, and selection from the scene tree with shift-range support.
- Transforms β move, rotate and scale gizmos with world/local space, translation snapping (0.1 m to 5 m) and rotation snapping (1Β° to 90Β°). Arrow keys nudge.
- Undo/redo β a full command history. A gizmo drag is one undo step, not sixty; a 3,000-object import is one step.
- Groups β nested folders with cascading hide and lock, so a base can be split into Walls / Towers / Barracks.
- Properties inspector β exact classname, editor-only label, X/Y/Z position, yaw/pitch/roll, placement mode, group and init line. Edits apply immediately, and to every selected object at once.
- Editing tools β align, distribute, match height, match rotation, snap to ground, reset/level rotation, move to view, plus row and ring arrays for building walls and perimeters quickly. A model sweep lays out one of every classname in a category, each labelled mesh or BOX, for finding which objects your archives will not decode.
- Path placement β press P, click along the ground, and the chosen object (or composition) fills the path at your spacing, each piece turned to follow the curve. Objects are spaced by arc length, so a fence keeps exactly 5 m between posts around a bend instead of bunching up. Optional Catmull-Rom smoothing, a lateral offset for kerbside lights, and a loop mode for perimeters. The preview shows the real placements before you commit, and the whole path is one undo step.
- Compositions (prefabs) β save a selection as a reusable cluster, then stamp it anywhere, rotated with [ and ] before you click. Build a checkpoint once and place it twenty times along a road. Each stamp lands in its own group and undoes in one step. Compositions are stored locally and can be exported as files to share.
- Measurement β point-to-point distance, ground distance, bearing, and bounding dimensions for a multi-selection.
- SQF export β Epoch server map addition, generic SQF, compact,
fn_spawnObjects, DZMS and WAI presets, with configurable precision and sorting. A Live SQF injector option paces the build so it can be run on a server that is already up. - SQF import β parses real Epoch map additions, including relative compositions that offset from a
_centervariable, and steps into[] spawn { }blocks. Unrecognised statements are listed with line numbers, never executed. - Database import and export β paste
object_datarows from your MySQL server (INSERT statements or a CSV/TSV export) and see player-built bases in 3D, then write them back out as INSERT rows. See below. - mission.sqm import and export β read objects straight out of a mission file, or export a paste-ready
class Vehiclesblock for servers without addon access. Pasting a mission.sqm into the import box is detected automatically; the preprocessor#definemacros real Epoch missions use are expanded, so nothing is silently missed. - Projects β create, rename, duplicate, delete, autosave, and import/export a portable
.armatools.jsonproject file. Refreshing the page recovers your work. - Real terrain, sampled from your own game β the Terrain button hands you a short SQF script. Run it once on your server, paste the resulting log back, and the editor renders your map's actual elevation: coastline, valleys, ridges. Click-to-place lands on the hillside, and snap-to-ground uses the real ground rather than sea level. Nothing is uploaded and no game assets are copied β only a list of heights your own server measured.
- Reads your own ArmA 2 / Epoch files β point Assets at your addons folder and the editor parses the PBO archives, the binarised configs and the model headers to give every recognised classname its real dimensions instead of an estimate. See below.
2 Reading your ArmA files
Open Assets β Choose addons folder and select something like
@DayZ_Epoch/addons. Everything is read locally in the page; nothing is uploaded,
and no game data is written anywhere except your own browser.
What the editor reads, and why:
- PBO archives β the file table only, up front. Archives are then read a slice at a time, so a 100 MB PBO never has to be loaded into memory.
- config.bin β the binarised config, walked to build a
classname β model pathmap. Inheritance is resolved, because mostLand_*classes inherit their model from a base class rather than declaring one. - P3D headers β about a kilobyte per model. The ODOL header carries the model's bounding box, so proxies get exact footprints without decompressing any geometry. Indexing a whole Epoch addons folder (84 archives, ~42,000 files) takes about a second. Full meshes and textures are read later, and only for the models a map layout actually places.
ASC_EU_BulbBLUB was estimated at
0.5 Γ 0.5 Γ 6 m from its name; it is actually a 15 cm bulb.
Once your files are loaded, walls line up because the boxes are the right size.
Encrypted or obfuscated PBOs (some mods ship them) are reported and skipped rather than producing nonsense. Base Bohemia archives and the Epoch addons are ordinary uncompressed PBOs and read fine.
3 What does not work yet
Stated plainly, so you know what you are getting.
- Every model reading cleanly. Objects you place now render with real triangles from your own
.p3dfiles, at full detail. Map scenery defaults to the coarsest LOD β an island is far too many instances for anything else, which is why a distant castle shows no door frames β but Assets β Map detail will draw it at full detail if you can spare the memory, and View β Placed object detail controls your own objects independently. Some archives will not give up their model data at all: Taviana and most of Origins read as ODOL v48 and then dissolve into padding where the LOD table belongs. Objects from those stay correctly-sized boxes, and the editor names the archive responsible rather than leaving you guessing. - Terrain from the .wrp file itself. ArmA's terrain encoding resisted a long analysis (six approaches ruled out; the details are recorded in
js/formats/wrp.js). The Terrain button works around it completely by asking the game for its heights instead β see below. Reading a.wrpdirectly would still be nicer, and remains open. - Map objects on every world. Chernarus, Sauerland, Namalsk and Bootcamp give up their layout β all 1,055,146 objects on Chernarus, with real shapes for about 90% of the models. Other worlds store the table differently and say so rather than coming up empty.
- Textured surfaces. PAA decoding works and map scenery is tinted with each model's real colour, averaged from its own
_cotexture β but a tint is not a texture. Putting the image on the surface needs UV coordinates out of the LOD vertex table, which is the next step. - Scale is preview only. ArmA 2 cannot scale placed objects, so the scale gizmo affects the editor view and is deliberately not written into exported SQF.
- mission.sqm markers, triggers and waypoints. Objects and units import and export; markers, sensors/triggers and waypoints are counted and reported but not brought into the scene, because the editor has no model for them yet. Group structure is flattened β units keep their side as metadata but the group hierarchy is not preserved on export.
- Mobile. This is a desktop application and says so rather than degrading badly.
4 Basic workflow
Steps 1β3 are the one-time setup that turns the editor from a box-pusher into something that shows you your actual map. Skip them and everything still works β you just build against a flat grey plane with proxy shapes.
βββ one-time setup (per browser) βββββββββββββββββββββββββ
Assets β Choose addons folderβ¦
β point at @DayZ_Epoch/addons and your ArmA 2 addons
β β every classname gets its real size, mesh and colour
β β the mod's own classnames join the Objects list
β
Terrain β run the sampler script on your server, paste the log
β β real elevation: coastline, valleys, ridges
β β click-to-place lands on the hillside, not sea level
β β "Align to terrain" and "Drop to ground" start working
β
Assets β Draw map layout (optional, needs the folder above)
β the island's own buildings and roads, as scenery
β build against the real Cherno, not empty ground
βββ every session βββββββββββββββββββββββββββββββββββββββ
Create a project
β
Choose your map (sets the world boundary)
β
Search for a classname in the Objects panel
β
Click it, then click in the viewport to place
β
Adjust position and rotation (gizmo or the inspector)
β
Export SQF β Epoch server map addition
β
Drop the .sqf into your dayz_server addon and call it
Getting the export onto your server
The Epoch server map addition preset produces the same shape you already
see in a server's map-addition scripts β wherever you keep them. Epoch has no standard
folder for these; most owners make one (buildings/,
AddedBuildings/, mapaddons/) inside
@DayZ_Epoch_Server/addons/dayz_server/ and call it from
server_functions.sqf:
if (isServer) then {
_vehicle_1 = objNull;
if (true) then
{
_this = createVehicle ["Land_HBarrier_large", [6321.4,7822.7,0.15], [], 0, "CAN_COLLIDE"];
_vehicle_1 = _this;
_this setDir 183.5;
_this setPos [6321.4,7822.7,0.15];
};
};
Save it into your server addon folder and execute it from server_functions.sqf
(or wherever your build already calls its map additions), for example:
// "buildings" here is just a folder you make - Epoch does not ship one. [] ExecVM "\z\addons\dayz_server\buildings\my_trader_city.sqf";
The Custom Map Addons guide covers the server-side setup in full, including the mission-file method if you do not have server addon access.
Injecting a build into a server that is already running
A file that is perfectly fine at server start can take a running server down. SQF is
cooperative: several hundred createVehicle calls in one uninterrupted pass hold
the scheduler for as long as they take, and past a couple of hundred objects players time out
or the session drops outright.
Tick Live SQF injector in the export dialog for that case. It wraps the whole
script in [] spawn { } and inserts a pause every N objects β between object
blocks, never inside one β so the server keeps ticking while the build lands:
[] spawn {
diag_log format ["[MapAddition] building 340 objects, 100 per batch"];
if (isServer) then {
... 100 objects ...
diag_log format ["[MapAddition] %1 objects placed, pausing 7s", 100];
uiSleep 7;
... and so on ...
};
diag_log "[MapAddition] done - 340 objects";
};
Use the plain file at server start β the pauses only slow the boot there. The live build still
re-imports into this editor unchanged, so you never have to keep two copies in sync. Downloads
get a -live suffix so the two files are not mistaken for each other.
Camera
Flight is a mode because W, E and R are also the gizmo shortcuts. Turn it on and those three stand down; turn it off and they select the gizmo again. Holding a camera mouse button flies without the mode, the way Unreal and Unity do it.
Keyboard shortcuts
Left-drag is selection: it picks objects and draws the box-select marquee, so the camera lives on the other two buttons. W, E and R stay bound to the move/rotate/scale gizmo β holding a camera button is what turns WASD into flight, the same way Unreal and Unity do it.
5 Importing existing SQF
Imported SQF is parsed, never executed. There is no eval and no
dynamic code execution anywhere in the importer β it tokenises the file and pattern-matches
the statements it understands.
Statements the importer understands
_v = createVehicle ["Class",[x,y,z],[],0,"CAN_COLLIDE"];
_v = createVehicleLocal [...];
_v = "Class" createVehicle [x,y,z];
_u = _grp createUnit ["Class",[x,y,z],[],0,"FORM"];
_v = objNull; _vehicle_1 = _this; (aliasing)
_v setDir 183.5;
_v setPos [x,y,z]; β setPos on export
_v setPosATL [x,y,z]; β setPosATL on export
_v setPosASL [x,y,z]; β setPosASL on export
_v setVectorDirAndUp [[..],[..]];
_v setVectorDir [..]; / _v setVectorUp [..];
_v setVehicleInit "...";
_v enableSimulation false; (and setVehicleLock, lock, setFuel,
setVariable, setDamage β¦ preserved verbatim)
[] spawn { β¦ }; stepped into, not skipped β objects
[args] call { β¦ }; inside a scheduler block import normally
Relative compositions work too. If the file defines its own origin, the importer resolves it rather than dropping everything at 0,0:
_center = [3960.23, 10914.5, 0.381744];
_this setPosATL [((_center select 0) + 0.27),
((_center select 1) + 1.82),
(0.36) + (_z_adjustment)];
/* β¦ */ are skipped, exactly as the game would skip
them. That is the normal way server owners disable part of a composition, so the importer
respects it.
Player-built bases, from the database
A live server does not keep player bases in a script β they live in MySQL, in
object_data, one row per object. Paste those rows into the import box and the
editor reads them: either INSERT statements (straight from mysqldump or
phpMyAdmin) or a CSV/TSV export with a header row, which is what a GUI
client's copy/export produces. The format is detected β there is nothing to choose.
Everything about an object's placement is packed into one text column:
[dir, [x,y,z], "ownerUID", [[dirVec],[upVec]], "buildUID"]
Only the first two are guaranteed and different forks append different things, so the reader
identifies members by shape rather than by position β a bare number is the
direction, a three-number array is the position, whichever order they arrive in. Columns are
found by name, so extra ones (base_id, StorageCoins,
Hitpoints) are ignored rather than throwing the parse off.
setPosASL. The stored Z is an
absolute world height, so a base built on a hillside only comes back where the player put
it if it is read against sea level.
The matching Database β object_data INSERT rows export preset writes them
back, with vectors for anything tilted. ObjectID and ObjectUID are
deliberately left out of the column list so MySQL assigns them: they are
AUTO_INCREMENT keys, and re-using imported ones collides with rows the server
already has. Set the Instance to match your server, and the
Owner UID to a SteamID or 0 for a server-owned build.
Back the table up first.
When something isn't understood
The import dialog lists every unrecognised statement with its line number before you commit. Everything the importer does understand is still imported β one odd line never costs you the whole file. Statements it skips are left alone, not run and not guessed at.
Round-trip fidelity
Classname, position, rotation and placement mode survive an
export β import β export cycle unchanged. This is verified automatically
against every real map-addition file on a production Epoch 1.0.7.1 server β
1,945 objects across 27 files, with zero differences. Formatting is
normalised (a setDir -31.390728 comes back as its equivalent
328.609272), but nothing moves.
Why new objects export as setPosATL
Objects you place in the editor default to setPosATL, not setPos.
This is deliberate, and it is the single most common way a hand-built composition goes wrong
in game.
setPos measures height from whatever surface is beneath the object β and that
includes other objects. Put a second crate where one already stands and the engine
seats it on the first crate's roof. Run a wall across a road and the pieces over the road sit
higher than the pieces beside it. The error only appears once a build gets dense, which is
exactly when it is most expensive to fix, and it is the classic failure of the in-game ArmA 2
editor. setPosATL measures from the terrain and nothing else, so a piece
lands where you put it regardless of what is next to it.
Both are heights above ground, so nothing moves in the viewport and nothing changes about files you import β each object keeps the command it was written with, which is what keeps the round trip lossless. Per-object control lives in the inspector, and Export β Placement can force the whole file onto one command.
6 Projects and local data
Exactly what is stored, and where.
- IndexedDB (database
dze-3d-editor) β your projects: object classnames, positions, rotations, groups, project names and editor settings. On your device only. - localStorage β small preferences: theme (
dze-theme), object favourites, recently used classnames, and the id of the last project you had open. - Compositions β saved prefabs live in the same IndexedDB database, separate from your projects, so they are available in every project.
- Nothing is sent anywhere. The editor makes no network requests while you work β no project data, no file contents, no classnames. Three.js is served from this site rather than a CDN, so loading the editor pulls no third-party code either.
One caveat, for accuracy: the site is hosted on Cloudflare Pages, which injects its own Cloudflare Web Analytics beacon into every page on the domain. It is cookieless and records page views rather than behaviour, but it is a request to a third-party host and it applies to this page like any other. It is not part of the editor, has no access to your projects or files, and the editor sends it nothing. See the privacy policy.
Autosave runs a couple of seconds after you stop editing, and at least every 30 seconds during continuous work. The status bar shows whether the current state is saved.
.armatools.json file somewhere safe for anything you care about.
7 Asset packs (for real models later)
The editor can already load locally converted assets β the plumbing is in place, waiting on a converter. No ArmA assets are hosted on this site, and none ever will be: Bohemia Interactive's models and textures are not ours to redistribute.
The intended flow keeps everything on the machine that already owns the game:
You own ArmA 2
β
A local converter reads your installation
β
It writes an ArmaTools asset pack on your disk
β
The editor loads that pack from your disk
β
Real models render; anything missing stays a proxy
Pack layout
ArmaToolsAssetPack/ βββ manifest.json βββ models/ β βββ land_hbarrier_large.glb βββ worlds/ β βββ chernarus/ β βββ world.json β βββ heightmap.* β βββ chunks/ βββ textures/
manifest.json
{
"format": "armatools-arma2-assets",
"version": 1,
"game": "arma2oa",
"name": "My Chernarus pack",
"objects": {
"Land_HBarrier_large": {
"model": "models/land_hbarrier_large.glb",
"size": [8, 2.4, 2.4]
}
},
"worlds": {
"chernarus": { "world": "worlds/chernarus/world.json" }
}
}
size is optional β the bounding box of the GLB is used when it is missing.
Classname lookup is case-insensitive, because ArmA is. Models are GLB (binary glTF) because
it is the one format a browser can load without a converter library.
Load a pack from Assets in the toolbar. Where the File System Access API is available you can pick a folder directly; otherwise a directory picker or a ZIP works. ZIPs are read with the browser's built-in decompression, so no third-party library is involved.
8 Roadmap
Real terrain and models are being developed separately from the editor foundation, on purpose. Making PBO/P3D/WRP parsing a prerequisite would have meant months before anything was usable. The editor is useful now and gains fidelity later without being rewritten.
- Next β terrain chunk loading from an asset pack, so a heightmap can be dropped in without touching the editor; a 2D top-down mode over the same scene.
- After that β spline placement (draw a path, get a fence), terrain-aware placement modes, and saved compositions/prefabs.
- Epoch integration β trader city workflows, buildable classname collections, and shared conversion with Sam's Mission SQF Manager so a composition can go straight to DZMS or WAI.
- mission.sqm β import and export, including units, groups, markers and triggers.
- Native formats β researched and documented before any parser is written, with licences checked first. Likely a local converter rather than in-browser PBO reading, because that keeps Bohemia's assets on your machine where they belong.
9 Technical notes
Coordinates
ArmA uses X = east, Y = north, Z = elevation. Three.js uses Y = up. The editor converts in
exactly one place (js/core/coords.js) so the swap can never drift:
three.x = arma.x, three.y = arma.z, three.z = -arma.y.
setDir is a clockwise compass bearing, so three.rotation.y = -radians(yaw).
Performance
Proxy geometry and materials are shared per category and size, so 3,000 barriers allocate a handful of buffers rather than 3,000. Object matrices are updated manually rather than every frame, and the viewport only renders when something actually changed β an idle editor costs no GPU. A 3,000-object scene imports, renders and exports comfortably within a frame budget.
Browser requirements
WebGL 2, ES modules and import maps: current Chrome, Edge, Firefox or Safari on a desktop. The editor detects missing support and explains the problem instead of showing a blank canvas.
About the DZE 3D Map Editor
The DZE 3D Map Editor is a free, browser-based level editor for DayZ Epoch and ArmA 2 server developers. It replaces the awkward loop of launching ArmA, using the in-game 2D editor, exporting to clipboard and hand-cleaning the result β you place real ArmA classnames in a 3D viewport and export server-ready SQF directly.
It is aimed at custom map additions: trader cities, military base expansions, roadblocks,
bandit camps and similar server-side compositions placed with createVehicle,
setDir and setPos. It reads the map addition files your server
already runs, and writes files in the same format.
Related tools
- Sam's Mission SQF Manager β convert compositions between DZMS, WAI and fn_spawnObjects formats.
- SQF / HPP Cleaner β strip comments and whitespace before shipping mission files.
- Custom Map Addons guide β the server-side setup, start to finish.