diff --git a/.envrc b/.envrc
new file mode 100644
index 0000000..88657c2
--- /dev/null
+++ b/.envrc
@@ -0,0 +1 @@
+GOPROXY="direct"
diff --git a/cmd/game/main.go b/cmd/game/main.go
index ab82123..ec6b64a 100644
--- a/cmd/game/main.go
+++ b/cmd/game/main.go
@@ -192,9 +192,9 @@ func main() {
 
 	potion2 := controller.CreateEntity([]ecs.Component{})
 	controller.AddComponent(potion2, types.Appearance{
-		Glyph: types.PlainGlyphHolder{"!"},
+		Glyph: types.PlainGlyphHolder{Glyph: "!"},
 		ColorSet: types.TileColorSet{
-			Fg: types.PlainColorHolder{255, 222, 255, 55},
+			Fg: types.PlainColorHolder{A: 255, R: 222, G: 255, B: 55},
 		},
 	})
 	controller.AddComponent(potion2, rooms[1].Center) //implicit Coords
diff --git a/config.json b/config.json
index 1b77443..9023718 100644
--- a/config.json
+++ b/config.json
@@ -1,5 +1,5 @@
 {
-    "version": "v0.0.1.7-16-gbf13c9c",
+    "version": "v0.0.1.7-29-g4f18b6d",
     "title": "Alchemyst",
     "sizeX": 100,
     "sizeY": 47,
diff --git a/engine/fov/precomputed_permissive/precomputed_permissive.go b/engine/fov/precomputed_permissive/precomputed_permissive.go
index 2b490d4..c807bfe 100644
--- a/engine/fov/precomputed_permissive/precomputed_permissive.go
+++ b/engine/fov/precomputed_permissive/precomputed_permissive.go
@@ -62,7 +62,7 @@ func (pp *precomputedPermissive) ComputeFov(coords types.Coords, radius int) {
 func (pp *precomputedPermissive) PrecomputeFovMap() {
 	max := pp.MaxTorchRadius
 	minusMax := (-1) * max
-	zeroCoords := types.Coords{0, 0}
+	zeroCoords := types.Coords{X: 0, Y: 0}
 	var x, y int
 	//fill list
 	for x = minusMax; x < max+1; x++ {
@@ -70,7 +70,7 @@ func (pp *precomputedPermissive) PrecomputeFovMap() {
 			if x == 0 && y == 0 {
 				continue;
 			}
-			iterCoords := types.Coords{x, y}
+			iterCoords := types.Coords{X: x, Y: y}
 			distance := zeroCoords.DistanceTo(iterCoords)
 			if distance <= float64(max) {
 				pp.CellList = append(pp.CellList, &Cell{iterCoords, distance, nil})
@@ -101,7 +101,7 @@ func (pp *precomputedPermissive) PrecomputeFovMap() {
 			roundedX := int(basic.Round(lineX))
 			roundedY := int(basic.Round(lineY))
 
-			idx, cell, err := pp.FindByCoords(types.Coords{roundedX, roundedY})
+			idx, cell, err := pp.FindByCoords(types.Coords{X: roundedX, Y: roundedY})
 			if err != nil {
 				//inexistent coord found
 				break;
diff --git a/engine/fov/precomputed_shade/precomputed_shade_test.go b/engine/fov/precomputed_shade/precomputed_shade_test.go
index 298d7e0..4019ddd 100644
--- a/engine/fov/precomputed_shade/precomputed_shade_test.go
+++ b/engine/fov/precomputed_shade/precomputed_shade_test.go
@@ -8,12 +8,12 @@ import (
 )
 
 func TestPsDistance(t *testing.T) {
-	iterCoords := types.Coords{0, 0}
+    iterCoords := types.Coords{X: 0, Y: 0}
 
-	fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{0, 1}))
-	fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{0, 5}))
-	fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{3, 3}))
-	fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{100, 0}))
+	fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{X: 0, Y: 1}))
+	fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{X: 0, Y: 5}))
+	fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{X: 3, Y: 3}))
+	fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{X: 100, Y: 0}))
 }
 
 func TestPrecompShade(t *testing.T) {
@@ -44,7 +44,7 @@ func TestPrecompShade(t *testing.T) {
 		}
 	}
 
-	playerCoords := types.Coords{10, 10}
+	playerCoords := types.Coords{X: 10, Y: 10}
 
 	level.SetTileByXY(8, 12, gamemap.NewWall())
 	level.SetTileByXY(10, 8, gamemap.NewWall())
diff --git a/engine/gamemap/level.go b/engine/gamemap/level.go
index 8c82464..63aec53 100644
--- a/engine/gamemap/level.go
+++ b/engine/gamemap/level.go
@@ -1,6 +1,8 @@
 package gamemap
 
 import (
+	"fmt"
+
 	"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
 	"lab.zaar.be/thefish/alchemyst-go/engine/types"
 	"lab.zaar.be/thefish/alchemyst-go/util/appctx"
@@ -28,7 +30,7 @@ func (l *Level) GetTileNbs (coords types.Coords) []*Tile {
 	result := make([]*Tile,0)
 	for i := coords.X-1; i < coords.X+1; i++ {
 		for j := coords.Y-1; j < coords.Y+1; j++ {
-			nbc := types.Coords{i,j}
+			nbc := types.Coords{X: i,Y: j}
 			if l.InBounds(nbc){
 				if nbc == coords {
 					continue
@@ -66,14 +68,14 @@ func (l *Level) Put (x, y int, tileFunc interface{}) {
 	if tile == nil {
 		appctx.Logger().Fatal().Msgf("Got non-tile type to put into level: %v", tile)
 	}
-	if l.InBounds(types.Coords{x, y}) {
+	if l.InBounds(types.Coords{X: x, Y: y}) {
 		l.Tiles[y*l.W+x] = tile
 	}
 }
 
 func NewLevel(branch string, depth int) *Level {
 	l := &Level{
-		Name:     branch + string(depth),
+		Name:     fmt.Sprintf(branch, depth),
 		Depth:    depth,
 		Rect: types.NewRect(0,0, mapWidth, mapHeight),
 	}
@@ -84,13 +86,13 @@ func NewLevel(branch string, depth int) *Level {
 }
 
 func (l *Level) SetAllInvisible() {
-	for idx, _ := range l.Tiles {
+	for idx := range l.Tiles {
 		l.Tiles[idx].Visible = false
 	}
 }
 
 func (l *Level) SetAllVisible() {
-	for idx, _ := range l.Tiles {
+	for idx := range l.Tiles {
 		l.Tiles[idx].Visible = true
 	}
 }
diff --git a/engine/gamemap/mapgens/common.go b/engine/gamemap/mapgens/common.go
index c32e30d..fc9ac9d 100644
--- a/engine/gamemap/mapgens/common.go
+++ b/engine/gamemap/mapgens/common.go
@@ -13,7 +13,7 @@ var maxRoomSize = 22
 var maxrooms = 100
 
 var fges = map[int]types.RectFill{
-	1: types.RectFill{
+	1: {
 		Top:         gamemap.NewWall,
 		Bottom:      gamemap.NewWall,
 		Left:        gamemap.NewWall,
@@ -25,7 +25,7 @@ var fges = map[int]types.RectFill{
 		Body:        gamemap.NewFloor,
 	},
 
-	2: types.RectFill{
+	2: {
 		Top:         gamemap.NewWaterTile,
 		Bottom:      gamemap.NewWaterTile,
 		Left:        gamemap.NewWaterTile,
@@ -53,7 +53,14 @@ func GetRandomRoomList(rng *util.RNG, l *gamemap.Level, maxRooms, minRoomSize, m
 
 
 		var newRoom = gamemap.Room{}
-		if !prefabUsed || rng.Range(0, 5) > 3 {
+		if prefabUsed && rng.Range(0, 5) <= 3 {
+			newRoom = gamemap.NewRandomRectRoom(
+				rng,
+				rng.Range(minRoomSize, maxRoomSize),
+				rng.Range(minRoomSize, maxRoomSize),
+				fillage,
+			)
+		} else {
 			//if prefabUsed {
 			//prefab
 			prefabUsed = true
@@ -67,20 +74,14 @@ func GetRandomRoomList(rng *util.RNG, l *gamemap.Level, maxRooms, minRoomSize, m
 				Mobs: r.Mobs,
 				Connectors: make([]types.Coords,0),
 			}
-			for _, coord := range r.Connectors {
-				newRoom.Connectors = append(newRoom.Connectors, coord)
-			}
-		} else {
-			newRoom = gamemap.NewRandomRectRoom(
-				rng,
-				rng.Range(minRoomSize, maxRoomSize),
-				rng.Range(minRoomSize, maxRoomSize),
-				fillage,
-			)
+            newRoom.Connectors = append(newRoom.Connectors, r.Connectors...)
+			// for _, coord := range r.Connectors {
+			// 	newRoom.Connectors = append(newRoom.Connectors, coord)
+			// }
 		}
 		where := types.Coords{
-			rng.Range(1, l.W-2-newRoom.W),
-			rng.Range(1, l.H-2-newRoom.H),
+			X: rng.Range(1, l.W-2-newRoom.W),
+			Y: rng.Range(1, l.H-2-newRoom.H),
 		}
 
 		newRoom.MoveToCoords(where)
@@ -172,7 +173,7 @@ func DigHTunnel(l *gamemap.Level, x1, x2, y int) {
 		finish = x1
 	}
 	for i := start; i <= finish; i++ {
-		if l.InBounds(types.Coords{i, y}) {
+		if l.InBounds(types.Coords{X: i, Y: y}) {
 			l.MakePassByXY(i, y, gamemap.NewFloor())
 			//l.Tiles[i][y] = gamemap.NewFloor()
 		}
@@ -189,7 +190,7 @@ func DigVTunnel(l *gamemap.Level, y1, y2, x int) {
 		finish = y1
 	}
 	for i := start; i <= finish; i++ {
-		if l.InBounds(types.Coords{x, i}) {
+		if l.InBounds(types.Coords{X: x, Y: i}) {
 			l.MakePassByXY(x, i, gamemap.NewFloor())
 		}
 	}
diff --git a/engine/gamemap/prefab.go b/engine/gamemap/prefab.go
index fcdba80..103660c 100644
--- a/engine/gamemap/prefab.go
+++ b/engine/gamemap/prefab.go
@@ -2,7 +2,8 @@ package gamemap
 
 import (
 	"encoding/json"
-	"io/ioutil"
+	"os"
+
 	"lab.zaar.be/thefish/alchemyst-go/engine/items"
 	"lab.zaar.be/thefish/alchemyst-go/engine/mob"
 	"lab.zaar.be/thefish/alchemyst-go/engine/types"
@@ -29,7 +30,7 @@ type PrefabRecord struct {
 }
 
 func LoadPrefabFile(filename string) (*PrefabFile, error) {
-	data, err := ioutil.ReadFile(filename)
+	data, err := os.ReadFile(filename)
 	if err!= nil {
 		return nil, err
 	}
@@ -62,6 +63,8 @@ func (pfbl PrefabLoader) PrefabRoomsList() []Room {
 
 	for _, rawPrefab := range file.Prefabs {
 
+        appctx.Logger().Debug().Msgf("adding %s", rawPrefab.name)
+
 		for k,v := range rawPrefab.TileLegend {
 			currentTileLegend[k] = v
 		}
@@ -73,8 +76,8 @@ func (pfbl PrefabLoader) PrefabRoomsList() []Room {
 		}
 
 		room := Room{
-			Rect:types.Rect{0, 0, rawPrefab.Size.X, rawPrefab.Size.Y},
-			Center: types.Coords{rawPrefab.Size.X / 2, rawPrefab.Size.Y / 2}, //fixme
+			Rect:types.Rect{X: 0, Y: 0, W: rawPrefab.Size.X, H: rawPrefab.Size.Y},
+			Center: types.Coords{X: rawPrefab.Size.X / 2, Y: rawPrefab.Size.Y / 2}, //fixme
 			Geometry: make([]func()*Tile, rawPrefab.Size.X*rawPrefab.Size.Y),
 			Mobs: make([]mob.Mob, rawPrefab.Size.X*rawPrefab.Size.Y),
 			Items: make([]items.Carried, rawPrefab.Size.X*rawPrefab.Size.Y),
@@ -99,7 +102,7 @@ func (pfbl PrefabLoader) PrefabRoomsList() []Room {
 				}
 				if shortName == "connector" {
 					f = NewWall
-					room.Connectors = append(room.Connectors, types.Coords{i,j})
+					room.Connectors = append(room.Connectors, types.Coords{X: i,Y: j})
 				} else {
 					f, ok = TileTypeMap[shortName]
 					if (!ok) {
diff --git a/engine/gamemap/room.go b/engine/gamemap/room.go
index 4c6edbe..f9c4dfc 100644
--- a/engine/gamemap/room.go
+++ b/engine/gamemap/room.go
@@ -3,12 +3,13 @@ package gamemap
 import (
 	"errors"
 	"fmt"
+	"strings"
+
 	"lab.zaar.be/thefish/alchemyst-go/engine/items"
 	"lab.zaar.be/thefish/alchemyst-go/engine/mob"
 	"lab.zaar.be/thefish/alchemyst-go/engine/types"
 	"lab.zaar.be/thefish/alchemyst-go/util"
 	"lab.zaar.be/thefish/alchemyst-go/util/appctx"
-	"strings"
 )
 
 var invalidBlit = errors.New("trying to blit on existing good tile")
@@ -27,7 +28,7 @@ func (r *Room) Put (x, y int, tileFunc interface{}) {
 	if tf == nil {
 		return //fixme error
 	}
-	if r.InBounds(types.Coords{x, y}) {
+	if r.InBounds(types.Coords{X: x, Y: y}) {
 		r.Geometry[x+y*r.W] = tf
 	}
 }
@@ -39,7 +40,7 @@ func (room *Room) BlitToLevel(l *Level) error {
 	for j := 0; j < room.H; j++ {
 
 		for i := 0; i < room.W; i++ {
-			mapCoords := types.Coords{room.X + i, room.Y + j}
+			mapCoords := types.Coords{X: room.X + i, Y: room.Y + j}
 			underlyingTile := l.GetTile(mapCoords)
 
 			tileFunc := room.Geometry[i+j*room.W]
@@ -85,17 +86,17 @@ func NewRandomRectRoom(rng *util.RNG, w, h int, fillage types.RectFill) Room {
 			w,
 			h,
 		),
-		Center: types.Coords{w / 2, h /2 },
+		Center: types.Coords{X: w / 2, Y: h /2 },
 		Geometry: make([]func()*Tile, w*h),
 	}
 	newRoom.Blit(fillage, &newRoom)
 	//add connectors
 	newRoom.Connectors = append(
 		newRoom.Connectors,
-		types.Coords{rng.Range(1, w - 2), 1},
-		types.Coords{rng.Range(1, w - 2), h -2},
-		types.Coords{1,  rng.Range(1, h - 2)},
-		types.Coords{w - 2,  rng.Range(1, h - 2)},
+		types.Coords{X: rng.Range(1, w - 2), Y: 1},
+		types.Coords{X: rng.Range(1, w - 2), Y: h -2},
+		types.Coords{X: 1,  Y: rng.Range(1, h - 2)},
+		types.Coords{X: w - 2,  Y: rng.Range(1, h - 2)},
 	)
 	return newRoom
 }
@@ -104,7 +105,7 @@ func (r *Room) String() string {
 	return strings.Join([]string{
 		"room: ",
 		"\t" + fmt.Sprintf(" rect: X: %d, Y: %d, maxX: %d, maxY: %d", r.Rect.X, r.Rect.Y, r.Rect.W + r.X - 1, r.Rect.H + r.Y - 1),
-		"\t" + fmt.Sprintf(" center:", r.Center.X, r.Center.Y),
+        "\t" + fmt.Sprintf(" center: %d, %d", r.Center.X, r.Center.Y),
 		"\t" + fmt.Sprintf(" Connectors: %v", r.Connectors),
 	},"\n") + "\n"
-}
\ No newline at end of file
+}
diff --git a/engine/gamemap/tile.go b/engine/gamemap/tile.go
index 80b4d22..1868cb0 100644
--- a/engine/gamemap/tile.go
+++ b/engine/gamemap/tile.go
@@ -37,21 +37,22 @@ func (t *Tile) GetRawBgColor() uint32 {
 
 func NewWall() *Tile {
 	return &Tile{
+		Appearance:  &Appearance{
+            Glyph: &PlainGlyphHolder{Glyph: "#"},
+            ColorSet: TileColorSet{
+                Fg: &PlainColorHolder{A: 255, R: 130, G: 110, B: 150},
+                Bg: &PlainColorHolder{A: 255, R: 172, G: 170, B: 173},
+                DarkFg: &PlainColorHolder{A: 255, R: 20, G: 20, B: 68},
+                DarkBg: &PlainColorHolder{A: 255, R: 7, G: 7, B: 30},
+            },
+        },
 		Name:        "Wall",
 		Description: "A dull rock wall",
 		BlocksPass:  true,
 		BlocksSight: true,
 		Explored:    false,
 		MustDraw:    false,
-		Appearance: &Appearance{
-			Glyph: &PlainGlyphHolder{"#"},
-			ColorSet: TileColorSet{
-				Fg:     &PlainColorHolder{255, 130, 110, 150},
-				Bg:     &PlainColorHolder{255, 172, 170, 173},
-				DarkFg: &PlainColorHolder{255, 20, 20, 68},
-				DarkBg: &PlainColorHolder{255, 7, 7, 30},
-			},
-		},
+		Visible:     false,
 	}
 }
 
@@ -64,18 +65,18 @@ func NewDecoratedWall() *Tile {
 		Explored:    false,
 		MustDraw:    false,
 		Appearance: &Appearance{
-			Glyph: &PlainGlyphHolder{"#"},
+			Glyph: &PlainGlyphHolder{Glyph: "#"},
 			ColorSet: TileColorSet{
-				Fg:     &PlainColorHolder{255, 130, 110, 150},
+				Fg:     &PlainColorHolder{A: 255, R: 130, G: 110, B: 150},
 				//Bg:     &PlainColorHolder{255, 172, 170, 173},
 				Bg:     &DanceColorHolder{
-					255,
-					DeviatedColorRing(172, -15, 10),
-					DeviatedColorRing(170, -5, 15),
-					DeviatedColorRing(173, -10, 10),
+					A: 255,
+					R: DeviatedColorRing(172, -15, 10),
+					G: DeviatedColorRing(170, -5, 15),
+					B: DeviatedColorRing(173, -10, 10),
 				},
-				DarkFg: &PlainColorHolder{255, 20, 20, 68},
-				DarkBg: &PlainColorHolder{255, 7, 7, 30},
+				DarkFg: &PlainColorHolder{A: 255, R: 20, G: 20, B: 68},
+				DarkBg: &PlainColorHolder{A: 255, R: 7, G: 7, B: 30},
 			},
 		},
 	}
@@ -90,12 +91,12 @@ func NewFloor() *Tile {
 		Explored:    false,
 		MustDraw:    false,
 		Appearance: &Appearance{
-			Glyph: &PlainGlyphHolder{"."},
+			Glyph: &PlainGlyphHolder{Glyph: "."},
 			ColorSet: TileColorSet{
-				Fg:     &PlainColorHolder{255, 220, 220, 250},
-				Bg:     &PlainColorHolder{255, 19, 19, 70},
-				DarkFg: &PlainColorHolder{255, 30, 20, 50},
-				DarkBg: &PlainColorHolder{255, 7, 7, 30},
+				Fg:     &PlainColorHolder{A: 255, R: 220, G: 220, B: 250},
+				Bg:     &PlainColorHolder{A: 255, R: 19, G: 19, B: 70},
+				DarkFg: &PlainColorHolder{A: 255, R: 30, G: 20, B: 50},
+				DarkBg: &PlainColorHolder{A: 255, R: 7, G: 7, B: 30},
 			},
 		},
 	}
@@ -111,17 +112,17 @@ func NewWaterTile() *Tile {
 		Explored:    false,
 		MustDraw:    true, //fixme debug
 		Appearance: &Appearance{
-			Glyph: &PlainGlyphHolder{" "},
+			Glyph: &PlainGlyphHolder{Glyph: " "},
 			ColorSet: TileColorSet{
-				Fg: &PlainColorHolder{255, 220, 220, 250},
+				Fg: &PlainColorHolder{A: 255, R: 220, G: 220, B: 250},
 				Bg: &DanceColorHolder{
-					255,
-					SingleColorRing(5),
-					FillColorRing(2, 2, 42, 4),
-					FillColorRing(154, 150, 229, 12),
+					A: 255,
+					R: SingleColorRing(5),
+					G: FillColorRing(2, 2, 42, 4),
+					B: FillColorRing(154, 150, 229, 12),
 				},
-				DarkFg: &PlainColorHolder{255, 30, 20, 50},
-				DarkBg: &PlainColorHolder{255, 7, 7, 30},
+				DarkFg: &PlainColorHolder{A: 255, R: 30, G: 20, B: 50},
+				DarkBg: &PlainColorHolder{A: 255, R: 7, G: 7, B: 30},
 			},
 		},
 
@@ -131,27 +132,21 @@ func NewWaterTile() *Tile {
 func NewDeepWaterTile() *Tile {
 	//ch := &ColorHolder{5, 2, 154}
 	return &Tile{
+		Appearance:  &Appearance{
+            Glyph: &PlainGlyphHolder{Glyph: " "},
+            ColorSet: TileColorSet{
+                Fg: &PlainColorHolder{A: 255, R: 220, G: 220, B: 250},
+                Bg: &DanceColorHolder{A: 255, R: SingleColorRing(19), G: FillColorRing(19, 0, 15, 2), B: FillColorRing(127, 120, 176, 12)},
+                DarkFg: &PlainColorHolder{A: 255, R: 30, G: 20, B: 50},
+                DarkBg: &PlainColorHolder{A: 255, R: 7, G: 7, B: 30},
+            },
+        },
 		Name:        "Deep Water",
 		Description: "Deep water",
 		BlocksPass:  false,
 		BlocksSight: false,
 		Explored:    false,
-		MustDraw:    true, //fixme debug
-
-		Appearance: &Appearance{
-			Glyph: &PlainGlyphHolder{" "},
-			ColorSet: TileColorSet{
-				Fg: &PlainColorHolder{255, 220, 220, 250},
-				Bg: &DanceColorHolder{
-					255,
-					SingleColorRing(19),
-					FillColorRing(19, 0, 15, 2),
-					FillColorRing(127, 120, 176, 12),
-				},
-				DarkFg: &PlainColorHolder{255, 30, 20, 50},
-				DarkBg: &PlainColorHolder{255, 7, 7, 30},
-			},
-		},
-
+		MustDraw:    true,
+		Visible:     false,
 	}
 }
diff --git a/engine/items/itemprops/ip_test.go b/engine/items/itemprops/ip_test.go
index ff36531..771558f 100644
--- a/engine/items/itemprops/ip_test.go
+++ b/engine/items/itemprops/ip_test.go
@@ -1,14 +1,15 @@
 package itemprops
 
 import (
-    "encoding/json"
-    "github.com/rs/zerolog"
-    "github.com/rs/zerolog/log"
-    "github.com/shopspring/decimal"
-    "github.com/stretchr/testify/suite"
-    "os"
-    "testing"
-    "time"
+	"encoding/json"
+	"os"
+	"testing"
+	"time"
+
+	"github.com/rs/zerolog"
+	"github.com/rs/zerolog/log"
+	"github.com/shopspring/decimal"
+	"github.com/stretchr/testify/suite"
 )
 
 type IpTestSuite struct {
@@ -67,8 +68,8 @@ func (suite *IpTestSuite) TestMaterialWeightAndVolume() {
         Flags:             metalMaterialFlags,
         Density:           DimensionItemDensity{decimal.NewFromInt(7800)},
         FractureToughness: DimensionFractureToughness{decimal.NewFromInt(30)},
-        MeltingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{decimal.NewFromInt(1400), true}},
-        BoilingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{decimal.NewFromInt(3200), true}},
+        MeltingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(1400), Valid: true}},
+        BoilingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(3200), Valid: true}},
     }
 
     testOakWood := Material{
@@ -77,7 +78,7 @@ func (suite *IpTestSuite) TestMaterialWeightAndVolume() {
         Flags:             woodMaterialFlags,
         Density:           DimensionItemDensity{decimal.NewFromInt(700)},
         FractureToughness: DimensionFractureToughness{decimal.NewFromFloat(4.5)},
-        MeltingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{decimal.NewFromInt(600), true}}, //загорается при 600 град Цельсия
+        MeltingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(600), Valid: true}}, //загорается при 600 град Цельсия
     }
 
     testCube := ItemPhysics{
@@ -156,8 +157,8 @@ func (suite *IpTestSuite) TestMaterialSerialization() {
         Flags:             metalMaterialFlags,
         Density:           DimensionItemDensity{decimal.NewFromInt(7800)},
         FractureToughness: DimensionFractureToughness{decimal.NewFromInt(30)},
-        MeltingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{decimal.NewFromInt(1400), true}},
-        BoilingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{decimal.NewFromInt(3200), true}},
+        MeltingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(1400), Valid: true}},
+        BoilingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(3200), Valid: true}},
     }
 
     testOakWood := Material{
@@ -166,7 +167,7 @@ func (suite *IpTestSuite) TestMaterialSerialization() {
         Flags:             woodMaterialFlags,
         Density:           DimensionItemDensity{decimal.NewFromInt(700)},
         FractureToughness: DimensionFractureToughness{decimal.NewFromFloat(4.5)},
-        MeltingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{decimal.NewFromInt(600), true}}, //загорается при 600 град Цельсия
+        MeltingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(600), Valid: true}}, //загорается при 600 град Цельсия
     }
     bytes, err := json.Marshal(teststeel)
     suite.NoError(err)
@@ -204,8 +205,8 @@ func (suite *IpTestSuite) TestMaterialDeserialization() {
         Flags:             metalMaterialFlags,
         Density:           DimensionItemDensity{decimal.NewFromInt(7800)},
         FractureToughness: DimensionFractureToughness{decimal.NewFromInt(30)},
-        MeltingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{decimal.NewFromInt(1400), true}},
-        BoilingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{decimal.NewFromInt(3200), true}},
+        MeltingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(1400), Valid: true}},
+        BoilingPoint:      DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(3200), Valid: true}},
     }
 
     loadedsteel := mm["steel"]
diff --git a/engine/items/itemprops/material.go b/engine/items/itemprops/material.go
index cb47d1b..147074c 100644
--- a/engine/items/itemprops/material.go
+++ b/engine/items/itemprops/material.go
@@ -1,13 +1,13 @@
 package itemprops
 
 import (
-    "encoding/json"
-    "fmt"
-    "github.com/rs/zerolog"
-    "io/ioutil"
-    "os"
-    "path/filepath"
-    "strings"
+	"encoding/json"
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/rs/zerolog"
 )
 
 type Material struct {
@@ -50,7 +50,7 @@ func NewMaterialMap(path string, logger zerolog.Logger) (MaterialMap, error) {
             if strings.HasSuffix(path, ".json") {
                 splt := strings.Split(path, "/")
                 logger.Info().Msgf("loading %s %d", splt[len(splt)-1], info.Size())
-                bytes, err := ioutil.ReadFile(path)
+                bytes, err := os.ReadFile(path)
                 if err != nil {
                     return err
                 }
@@ -60,7 +60,7 @@ func NewMaterialMap(path string, logger zerolog.Logger) (MaterialMap, error) {
                 if err != nil {
                     return err
                 }
-                for idx, _ := range ttmp {
+                for idx := range ttmp {
                     tmp[idx] = append(tmp[idx], ttmp[idx]...)
                 }
             }
diff --git a/engine/matertals/properties.go b/engine/matertals/properties.go
index e8604bc..9760fac 100644
--- a/engine/matertals/properties.go
+++ b/engine/matertals/properties.go
@@ -50,7 +50,7 @@ func (ms MatterState) Change(from MatterState, to MatterState) bool {
 			return false
 		}(transitions[from], to)
 		if !newStateFound {
-			log.Warn().Msgf("Transition %s -> %s is impossible", from, to)
+			log.Warn().Msgf(`Transition %d -> %d is impossible`, from, to)
 			return false
 		}
 		// check temperatures/conditions, see template
@@ -79,4 +79,4 @@ func (ms MatterState) Change(from MatterState, to MatterState) bool {
 
 	return true
 
-}
\ No newline at end of file
+}
diff --git a/engine/mob/movement/movement.go b/engine/mob/movement/movement.go
index a383a92..836119e 100644
--- a/engine/mob/movement/movement.go
+++ b/engine/mob/movement/movement.go
@@ -23,11 +23,11 @@ func (mov Moveable) Walk() {
 
 //fixme change it to WhatsOnTile
 func (mov Moveable) IsBlocked(c types.Coords) bool {
-	if mov.Level.GetTile(c).BlocksPass == true {
+	if mov.Level.GetTile(c).BlocksPass {
 		return true
 	}
 	list :=  mov.Controller.GetEntitiesWithComponent(ecs.MobComponent)
-	for idx, _ := range list {
+	for idx := range list {
 		coords := mov.Controller.GetComponent(list[idx], ecs.CoordsComponent)
 		if coords == nil {
 			continue
@@ -50,7 +50,7 @@ func (mov Moveable) IsBlocked(c types.Coords) bool {
 func Walk(entity ecs.Entity, state *gamestate.GameState, dx, dy int) {
 	controller := state.Controller
 	coords := controller.GetComponent(state.Player, ecs.CoordsComponent).(types.Coords)
-	newCoords := types.Coords{coords.X + dx, coords.Y + dy}
+	newCoords := types.Coords{X: coords.X + dx, Y: coords.Y + dy}
 	if !state.Level.InBounds(newCoords) {
 		return
 	}
diff --git a/engine/screens/devmenu.go b/engine/screens/devmenu.go
index 21c3084..78290e8 100644
--- a/engine/screens/devmenu.go
+++ b/engine/screens/devmenu.go
@@ -1,15 +1,16 @@
 package screens
 
 import (
-    "context"
-    "fmt"
-    "lab.zaar.be/thefish/alchemyst-go/effects"
-    "lab.zaar.be/thefish/alchemyst-go/engine/ecs"
-    "lab.zaar.be/thefish/alchemyst-go/engine/gamestate"
-    "lab.zaar.be/thefish/alchemyst-go/engine/types"
-    "lab.zaar.be/thefish/alchemyst-go/ui/mainwindow"
-    "lab.zaar.be/thefish/alchemyst-go/util/appctx"
-    "strings"
+	"context"
+	"fmt"
+	"strings"
+
+	"lab.zaar.be/thefish/alchemyst-go/effects"
+	"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
+	"lab.zaar.be/thefish/alchemyst-go/engine/gamestate"
+	"lab.zaar.be/thefish/alchemyst-go/engine/types"
+	"lab.zaar.be/thefish/alchemyst-go/ui/mainwindow"
+	"lab.zaar.be/thefish/alchemyst-go/util/appctx"
 )
 
 type DevmenuScreen struct {
diff --git a/engine/screens/inventory.go b/engine/screens/inventory.go
index e3eece5..6c4f056 100644
--- a/engine/screens/inventory.go
+++ b/engine/screens/inventory.go
@@ -146,7 +146,12 @@ func (is *InventoryScreen) InventoryRender() {
 		footerHeight = footerHeight + 2
 	}
 	_, headerHeight := menuLayer.PrintInside(is.Rect, is.header, blt.TK_ALIGN_LEFT)
-	itemField := types.Rect{is.X, is.Y + headerHeight + 1, is.W, is.H - headerHeight - footerHeight}
+	itemField := types.Rect{
+        X: is.X,
+        Y: is.Y + headerHeight + 1,
+        W: is.W,
+        H: is.H - headerHeight - footerHeight,
+    }
 	_ = itemField
 	is.pageSize = itemField.H - 2
 
diff --git a/story/linux_go_blt_install_quickstart.md b/story/linux_go_blt_install_quickstart.md
index c15a317..7758c14 100644
--- a/story/linux_go_blt_install_quickstart.md
+++ b/story/linux_go_blt_install_quickstart.md
@@ -150,4 +150,4 @@ func renderSuperEffect() {
 выполняется в main loop. В целом картина именно такая, но больше подробностей можно
 найти по ссылкам в комментариях.
 
-[1]: Если такой контейнер аккуратно сериализовать (рекурсивно вместе со всем содержимым) и записать на диск... То потом можно его прочитать и десериализовать. Получив тем самым почти бесплатно Save / Load. 
\ No newline at end of file
+[1]: Если такой контейнер аккуратно сериализовать (рекурсивно вместе со всем содержимым) и записать на диск... То потом можно его прочитать и десериализовать. Получив тем самым почти бесплатно Save / Load. 
diff --git a/ui/mainwindow/viewport.go b/ui/mainwindow/viewport.go
index 48f1010..e35b538 100644
--- a/ui/mainwindow/viewport.go
+++ b/ui/mainwindow/viewport.go
@@ -13,7 +13,7 @@ type ViewPort struct {
 
 func NewViewPort(x, y, w, h int) *ViewPort {
 	vp := ViewPort{
-		Rect:  types.Rect{x, y, w, h},
+		Rect:  types.Rect{X: x, Y: y, W: w, H: h},
 	}
 	return &vp
 }
@@ -47,8 +47,8 @@ func (vp *ViewPort) ToVPCoords(c types.Coords) (newCoords types.Coords, err erro
 	//coords on map to coords on vp
 	x, y := c.X-vp.CameraCoords.X, c.Y-vp.CameraCoords.Y
 	if x < 0 || y < 0 || x > vp.W || y > vp.H {
-		return types.Coords{-1, -1}, fmt.Errorf("Not in viewport: {%d, %d}", x, y)
+		return types.Coords{X: -1, Y: -1}, fmt.Errorf("Not in viewport: {%d, %d}", x, y)
 	}
-	return types.Coords{x, y}, nil
+	return types.Coords{X: x, Y: y}, nil
 }
 
diff --git a/util/delaunay/delaunay.go b/util/delaunay/delaunay.go
index 58ac466..3b4697e 100644
--- a/util/delaunay/delaunay.go
+++ b/util/delaunay/delaunay.go
@@ -6,6 +6,7 @@ import "lab.zaar.be/thefish/alchemyst-go/engine/types"
 
 var nodeId = 0
 var nodeList = make(map[types.Coords]Node, 0)
+
 // Node defines a struct having as components the node X and Y coordinate position.
 type Node struct {
 	Id int
@@ -129,17 +130,27 @@ func (d *Delaunay) Init(width, height int) *Delaunay {
 }
 
 var supertriangle1, supertriangle2 Triangle
+
 // clear method clears the delaunay triangles slice.
 func (d *Delaunay) clear() {
-	p0 := newNode(types.Coords{0,0})
-	p1 := newNode(types.Coords{d.width, 0})
-	p2 := newNode(types.Coords{d.width, d.height})
-	p3 := newNode(types.Coords{0, d.height})
+	p0 := newNode(types.Coords{X: 0, Y: 0})
+	p1 := newNode(types.Coords{X: d.width, Y: 0})
+	p2 := func() Node {
+		var coords types.Coords = types.Coords{X: d.width, Y: d.height}
+		if n, ok := nodeList[coords]; ok {
+			return n
+		}
+		neue := Node{Id: nodeId, Coords: coords}
+		nodeList[coords] = neue
+		nodeId++
+		return neue
+	}()
+	p3 := newNode(types.Coords{X: 0, Y: d.height})
 
 	// Create the supertriangle, an artificial triangle which encompasses all the points.
 	// At the end of the triangulation process any triangles which share Edges with the supertriangle are deleted from the triangle list.
-	supertriangle1 = t.newTriangle(p0,p1,p2)
-	supertriangle2 = t.newTriangle(p0,p2,p3)
+	supertriangle1 = t.newTriangle(p0, p1, p2)
+	supertriangle2 = t.newTriangle(p0, p2, p3)
 	d.triangles = []Triangle{supertriangle1, supertriangle2}
 }
 
@@ -199,7 +210,7 @@ func (d *Delaunay) Insert(points []types.Coords) *Delaunay {
 		}
 		for i = 0; i < len(polygon); i++ {
 			edge := polygon[i]
-			temps = append(temps, t.newTriangle(edge.Nodes[0], edge.Nodes[1], newNode(types.Coords{x, y})))
+			temps = append(temps, t.newTriangle(edge.Nodes[0], edge.Nodes[1], newNode(types.Coords{X: x, Y: y})))
 		}
 		d.triangles = temps
 	}
@@ -245,12 +256,9 @@ func (d *Delaunay) GetTriangles() []Triangle {
 }
 
 func (d *Delaunay) GetEdges() []Edge {
-	edges := make([]Edge, 0)
-	for _, trs := range d.triangles {
-		for _, e := range trs.Edges {
-			edges = append(edges, e)
-		}
-
-	}
-	return edges
+    edges := make([]Edge, 0)
+    for _, trs := range d.triangles {
+        edges = append(edges, trs.Edges...)
+    }
+    return edges
 }
diff --git a/util/delaunay/mst.go b/util/delaunay/mst.go
index aeb3551..8f5a75f 100644
--- a/util/delaunay/mst.go
+++ b/util/delaunay/mst.go
@@ -11,7 +11,7 @@ func GetTriangles(coords []types.Coords, w, h int) []types.Edge {
 	edges := d.Init(100, 100).Insert(coords).GetEdges()
 	output := make([]types.Edge, 0)
 	for _, e := range edges{
-		output = append(output, types.Edge{e.Nodes[0].Coords, e.Nodes[1].Coords})
+		output = append(output, types.Edge{From: e.Nodes[0].Coords, To: e.Nodes[1].Coords})
 	}
 	return output
 }
@@ -46,16 +46,16 @@ func GetMst(coords []types.Coords, w, h, negativeWeight int) []types.Edge {
 		graph = append(
 			graph,
 			kruskals.SimpleWeightedEdge{
-				nodeMap[e.Nodes[0].Id],
-				nodeMap[e.Nodes[1].Id],
-				negativeWeight - int(e.Nodes[0].Coords.DistanceTo(e.Nodes[1].Coords))},
+				F: nodeMap[e.Nodes[0].Id],
+				T: nodeMap[e.Nodes[1].Id],
+				W: negativeWeight - int(e.Nodes[0].Coords.DistanceTo(e.Nodes[1].Coords))},
 		)
 	}
 
 	result := kruskals.MinimumSpanningTree(graph)
 	output := make([]types.Edge, 0)
 	for _, we := range result{
-		output = append(output, types.Edge{nodeList[we.From()].Coords, nodeList[we.To()].Coords})
+		output = append(output, types.Edge{From: nodeList[we.From()].Coords, To: nodeList[we.To()].Coords})
 	}
 	return output
 }