yag @admin dogsi
lebian she/it i am a valid atom

i love the source engine. even more, i love its level editor, hammer. i think it's the last level editor that exists. i want an experience similar to it, because making game levels in something like blender frankly sucks. so a while back, i started writing down a kind of spec for a game-agnostic level editor. i don't think i'm going to work on it any time soon, but it's a neat idea i think and worth exploring at some point.


  • hammer but modern
  • generic, not tied to any engine
  • main save format is bespoke, but can export to gltf and obj (only geo)
  • two types of primitives, brush and point entity
  • entities can be brush or point
  • brush editing tools (that part sucks :( )
  • entities can have simple keyvalues and attributes, which are also keyvalues with an expression language

an example of attributes is I/O. attributes follow a schema with an expression language that allows them to be constrained. in i/o this is useful for defining an entity's inputs and outputs and then being able to make sure the attribute's value (eg input to fire) is an input of the target entity. therefore, attribute values can be any type, including full objects. eg:

code block{
//... rest of entity def
	"attributes": [
		{
			"name": "outputs",
			"kind": "fields", // how to edit this attribute ("fields" will show an editable window similar to the entity kv inspector and store them as an array)
			"value": [
				{
					"output": "OnStartOpen",
					"targetname": "$TARGETNAME$",
					"input": "$ONE(ent(targetname).attributes.inputs)$",
					"data": "",
					"delay": 0.0,
				}
			]
		},
		{
			"name": "inputs",
			"kind": "data", // "data" kind is not saved in the map file, it's just for reference
			"value": [
				"Open", "Close"
			]
		}
	]
}

entity def:

code block{
	"classname": "info_player_start",
	"kind": "point", //"point"|"solid"|"any" - "any" is most useful for base classes
	"base": [], // Array<EntityDef> - will inherit kv's and attributes from base classes
	"position": "", // vec3
	"rotation": "", // vec3
	"scale": "", // vec3
	"kv": {
		"team": {
			"type": "enum_string",
			"value": "Red,Blue,None",
			"default": "None",
		},
		"start_enabled": {
			"type": "bool", // simple types don't need the value key
			"default": true,
		}
	},
	"attributes": [ // see above
		{
			"name": "outputs",
			"kind": "fields",
			"value": [
				{
					"output": "OnSpawn",
					"targetname": "$TARGETNAME$",
					"input": "$ONE(ent(targetname).attributes.inputs)$",
					"data": "",
					"delay": 0.0,
				}
			]
		}
	]
}

example of a saved entity:

code block{
	"classname": "info_player_start",
	"kv": {
		"team": "Red",
		"start_enabled": true // kv's with default fields are still saved to be able to open maps without a gamedef
	},
	"attributes": {
		"outputs": [
			{
				"output": "OnSpawn",
				"targetname": "some_door",
				"input": "Open",
				"data": "",
				"delay": 0.5,
			}
		]
	}
}

gizmos are attributes:

code block{
	"name": "radius",
	"kind": "sphere_gizmo",
	"value": [
		{
			"default": 1.0,
			"controlling_kv": "radius", // editing the radius kv will edit the gizmo, and editing the gizmo will edit the radius kv
		}
	]
}

i'm not settled at all on most of this. one thing i really like about Trenchbroom is the expression language, so i want to have something like it in the entity definition files. i think instead of interpolating it in something like "$FUNC$" i'd rather go with {{expr}}.

i know also that i strongly want to have an engine-agnostic input/output system, as provided in the first few examples. it should be possible to express level logic without leaving the level editor.

it could be argued that this should be part of the engine for whatever game you're working on, but a game engine allows less assumptions to be made than a separate app i think.

im Normal and you'r NOT.

bear that in mind.

xananax @xananax potentially in the bathroom

What is the issue with Hammer itself? Too old? Doesn't run well? Save format not easy to parse?

I know what you're thinking

yag @admin dogsi
lebian she/it i am a valid atom

doesnt run on linux and too tied to source. it's also too old as you said. the workflow is super clunky. what i want is the good parts of hammer (brush based workflow and i/o) with modern niceties (arbitrary unit grids, easy asset import)

im Normal and you'r NOT.

bear that in mind.

yag @admin dogsi
lebian she/it i am a valid atom

and on trenchbroom: its nice, but suffers also from being too tied to quake. and the asset workflow is really unpleasant, though better and less coupled than hammer. TB also has superior brush editing

im Normal and you'r NOT.

bear that in mind.

artyom @artyom

Have you given netradiant a try to study and examine?

https://github.com/Garux/netradiant-custom

yag @admin dogsi
lebian she/it i am a valid atom

artyom said:

Have you given netradiant a try to study and examine?

https://github.com/Garux/netradiant-custom

i haven't used it directly myself, but it's definitely interesting. but it still exhibits its quake roots, and being a fork of a fork of a fork of a fork (...), it's quite old and has 20 years of baggage. i'd like to try it one day but i really don't have the time to set up a game for it.

which is kind of another problem with both tb and netradiant, the time it takes from setup to getting to actually map is crazy. which is why some games just ship pre-made configs for their editor of choice i suppose

im Normal and you'r NOT.

bear that in mind.

Are you sure you want to delete the highlighted post?