Insign — a tiny DSL for Minecraft build regions & metadata
Goal: author compact annotations on signs/books (or any text source) that compile into a deterministic regions + metadata structure you can ship with schematics and tools.
- Regions = unions of axis-aligned boxes (AABBs) keyed by IDs like
cpu.core - Metadata = namespaced key/values attached to regions (plus
$globaland wildcards likecpu.*) - Authoring constraints: terse on signs, multi-line friendly, stable & deterministic
This repository currently contains the spec and examples. Implementation comes next.
Why?
- Portable context for builds: label sub-assemblies, bus lines, rooms—precisely and repeatably.
- Machine-readable: consumers (renderers, validators, pipelines) can query regions and inherited metadata.
- Sign-friendly: minimal punctuation, statement markers, multi-line allowed.
Library I/O (language-agnostic)
Input
An ordered array of tuples: ([sx, sy, sz], text).
posis the source block’s world coords (sign/lectern).textis raw DSL; newlines allowed.- Order is used only to derive stable IDs for anonymous regions; it must not affect semantics.
Output (conceptual JSON)
Notes
rcis relative topos;acis absolute.- Bounds are inclusive; each box is stored as a pair of vec3 corners, normalized per axis.
- Anonymous regions appear only if they received metadata (recommended).
Authoring Syntax (sign-friendly)
- Geometry starts with
@ - Metadata starts with
#
A statement starts at @ or # and ends right before the next @/# (or end of text). Newlines are allowed inside a statement.
Geometry (@…)
Named regions (unified form)
@<region>=rc([x1,y1,z1],[x2,y2,z2]) // relative to this tuple’s pos
@<region>=ac([x1,y1,z1],[x2,y2,z2]) // absolute world coords
@<region>=<expr> // boolean expression over regions
Anonymous regions (no =; sign-local only)
@rc([x1,y1,z1],[x2,y2,z2])
@ac([x1,y1,z1],[x2,y2,z2])
@def(<expr>)
Booleans (Phase 0 / MVP)
<expr> := term { + term }*
term := <region> | ( <expr> )
- Operators:
+union only in Phase 0. - Other ops (
-,&,^) are reserved for a later phase.
Current region .
- Within a single tuple, the most recent geometry statement (named or anonymous).
- No current region across tuples.
Metadata (#…)
Attach to current region (this tuple):
#key=<json>
Attach to an explicit target (dense):
#<target>:<key>=<json>
Where <target> is:
- a region ID (
fooorfoo.bar) - a wildcard prefix (
prefix.*) $global
Values: strict JSON (string/number/bool/null/array/object). (No computed value functions in v0.1; reserved for future.)
Inheritance & Determinism
-
Read-time precedence per key: Exact region > longest matching wildcard(s) > $global.
-
Conflicts: different values for the same
<named target, key>across tuples → compile error (identical duplicates allowed). -
A named region is either:
- Accumulator (one or more
rc/acappend boxes), or - Defined (
@<region>=<expr>). Mixing both modes is an error.
- Accumulator (one or more
-
Anonymous region IDs derive from
(tuple_index, statement_index)—never random UUIDs. -
Deterministic output ordering is recommended:
$global, then wildcards (lexicographic), then regions (lexicographic).
Examples
1) Anonymous region + inline metadata (relative)
@rc([0,64,0],
[31,72,15])
#doc.label="Data Loop"
#logic.clock_hz=4
2) Named accumulators split across signs
@dataloop=rc([0,64,0],[31,72,15])
@dataloop.alu=rc([8,64,8],[22,70,14])
@dataloop.registers=rc([2,64,2],[12,69,6])+rc([14,64,2],[24,69,6])
#dataloop:doc.label="Data Loop"
#dataloop.registers:logic.word_size=8
3) Boolean union (Phase 0)
@core=dataloop.alu+dataloop.registers
#core:doc.note="ALU ∪ registers"
4) Absolute span + targeted metadata
@cpu.bus=ac([100,70,-20],[132,78,-5])
#cpu.bus:io.direction="east-west"
5) Wildcards & global metadata
#cpu.*:logic.clock_hz=4
#$global:io.bus_width=8
6) Multi-line statements are fine
@dataloop.registers=rc([2,64,2],
[12,69,6])
+ rc([14,64,2],
[24,69,6])
#dataloop.registers:doc.note="two banks"
Formal Grammar (EBNF, v0.1)
Lexical
digit = "0"…"9" ;
int = ["-"], digit, { digit } ;
region-id = 1*( ALNUM | "_" | "." ) ; // [A-Za-z0-9_.]+
key = region-id ;
vec3 = "[", int, ",", int, ",", int, "]" ;
box = vec3, ",", vec3 ;
Program
input = { stmt } ;
stmt = geom | meta ;
Geometry
geom = "@", ( named-geom | anon-geom ) ;
named-geom = region-id, "=", ( "rc(", box, ")"
| "ac(", box, ")"
| expr ) ;
anon-geom = "rc(", box, ")"
| "ac(", box, ")"
| "def(", expr, ")" ;
expr = term, { "+", term } ; // Phase 0: union only
term = region-id | "(", expr, ")" ;
Metadata
meta = "#", ( targeted-meta | current-meta ) ;
targeted-meta = meta-target, ":", key, "=", json ;
current-meta = key, "=", json ;
meta-target = "$global" | region-id | region-id, ".*" ;
json = RFC 8259 JSON literal ;
Installation & Usage
Rust Library
Add to your Cargo.toml:
[]
= "0.1.1"
# For FFI bindings (Kotlin/JVM integration)
= "0.1.1"
# For WASM bindings (Web/Node.js)
= "0.1.1"
Basic usage:
use compile;
let input = vec!;
let result = compile?;
let json = to_string_pretty?;
println!;
CLI Tool
Install from crates.io:
Or download pre-built binaries from the GitHub Releases page.
|
FFI (Kotlin/JVM)
Download the appropriate native library from GitHub Releases:
- Linux:
libinsign_ffi.so - macOS:
libinsign_ffi.dylib - Windows:
insign_ffi.dll
// Example Kotlin integration (requires JNA)
val library = Native.load("insign_ffi", InsignLibrary::class.java)
val json = "[{\"pos\":[0,0,0],\"text\":\"@rc([0,0,0],[1,1,1])\"}]"
val result = library.compile_json(json)
println(result)
WASM (Web/Node.js)
Node.js:
const = require;
const input = JSON.;
const result = ;
console.log;
Browser:
Development
Building from Source
# Clone the repository
# Build all packages
# Run tests
# Build FFI library
# Build WASM package
Parity Testing
To verify that FFI and WASM produce identical outputs:
License
MIT (see LICENSE in this repository).