Repository: mlange-42/arche
Pull request #89 (2023-02-15 22:44:38)

Rework generic mapping and mutation


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d51d9b2..3de2acf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,12 +7,12 @@
 * Generic queries support optional, additional and excluded components (#53, #56, #58, #59, #60, #63)
 * Logic filters for complex queries (#54, #58, #61)
 * `Query` and `World` have a method `Mask(Entity)` to access archetype masks (#65)
-* Generic query `GetAll` methods return the entity as first element (#83)
+* Generic query `Get` method returns the entity as first element (#83)
 * Added method `World.Stats()` for inspecting otherwise inaccessible world statistics (#67)
 * Entities can be initialized with components, via ID as well as using generics (#76)
 * A listener function can be registered to the world, for notification on entity changes (#77)
 * Support for up to 128 distinct component types per world (was limited to 64 before) (#78)
-* Generic entity manipulation through types `Mutate1`, `Mutate2`, ... (#79)
+* Generic entity manipulation through types `Map1`, `Map2`, ... and `Mutate` (#79, #84, #87)
 
 ### Other
 
@@ -20,6 +20,7 @@
 * Generic queries are compiled to masks and cached on first build (#62)
 * Boilerplate code for generic filters and queries is auto-generated with `go generate` (#64)
 * Ensure 100% test coverage by adding a CI check for it (#68)
+* `World.RemEntity(Entity)` is now `World.RemoveEntity(Entity)` (#87)
 
 ## [[v0.3.1]](https://github.com/mlange-42/arche/compare/v0.3.0...v0.3.1)
 
diff --git a/README.md b/README.md
index d71ac72..aba7439 100644
--- a/README.md
+++ b/README.md
@@ -64,13 +64,13 @@ func main() {
 	// Create a World.
 	world := ecs.NewWorld()
 
-	// Create a generic entity mutation helper.
-	mutator := generic.NewMutate2[Position, Velocity](&world)
+	// Create a component mapper.
+	mapper := generic.NewMap2[Position, Velocity](&world)
 
 	// Create entities.
 	for i := 0; i < 1000; i++ {
 		// Create a new Entity with components.
-		_, pos, vel := mutator.NewEntity()
+		_, pos, vel := mapper.NewEntity()
 
 		// Initialize component fields.
 		pos.X = rand.Float64() * 100
@@ -89,7 +89,7 @@ func main() {
 		// Iterate it
 		for query.Next() {
 			// Component access through the Query.
-			_, pos, vel := query.GetAll()
+			_, pos, vel := query.Get()
 			// Update component fields.
 			pos.X += vel.X
 			pos.Y += vel.Y
diff --git a/ecs/world.go b/ecs/world.go
index 92b72a0..5ff0ccc 100644
--- a/ecs/world.go
+++ b/ecs/world.go
@@ -133,11 +133,11 @@ func (w *World) NewEntityWith(comps ...Component) Entity {
 	return entity
 }
 
-// RemEntity removes and recycles an [Entity].
+// RemoveEntity removes and recycles an [Entity].
 //
 // Panics when called on a locked world or for an already removed entity.
 // Do not use during [Query] iteration!
-func (w *World) RemEntity(entity Entity) {
+func (w *World) RemoveEntity(entity Entity) {
 	w.checkLocked()
 
 	index := w.entities[entity.id]
diff --git a/examples/change_listener/main.go b/examples/change_listener/main.go
index 1d55c5e..1be87e4 100644
--- a/examples/change_listener/main.go
+++ b/examples/change_listener/main.go
@@ -59,6 +59,6 @@ func main() {
 
 	world.Remove(e1, posID, velID)
 
-	world.RemEntity(e0)
-	world.RemEntity(e1)
+	world.RemoveEntity(e0)
+	world.RemoveEntity(e1)
 }
diff --git a/examples/generic/main.go b/examples/generic/main.go
index 48d6c9a..852fba7 100644
--- a/examples/generic/main.go
+++ b/examples/generic/main.go
@@ -34,13 +34,13 @@ func main() {
 	// Create a World.
 	world := ecs.NewWorld()
 
-	// Create a generic entity mutation helper.
-	mutator := generic.NewMutate4[Position, Velocity, Rotation, Elevation](&world)
+	// Create a component mapper.
+	mapper := generic.NewMap4[Position, Velocity, Rotation, Elevation](&world)
 
 	// Create entities.
 	for i := 0; i < 1000; i++ {
 		// Create a new Entity with components.
-		_, pos, vel, _, _ := mutator.NewEntity()
+		_, pos, vel, _, _ := mapper.NewEntity()
 
 		// Initialize component fields.
 		pos.X = rand.Float64() * 100
@@ -61,7 +61,7 @@ func main() {
 		// Iterate it.
 		for query.Next() {
 			// Component access through the Query.
-			_, pos, vel := query.GetAll()
+			_, pos, vel := query.Get()
 			// Update component fields.
 			pos.X += vel.X
 			pos.Y += vel.Y
@@ -71,15 +71,15 @@ func main() {
 	// A more complex generic query using optional and excluded components:
 	filter =
 		generic.
-			NewFilter2[Position, Velocity]().    // Components provided through Get... methods
-			Optional(generic.Mask1[Velocity]()). // but those may be nil
-			With(generic.Mask1[Elevation]()).    // additional required components
-			Without(generic.Mask1[Rotation]())   // entities with any of these are excluded.
+			NewFilter2[Position, Velocity](). // Components provided through Get... methods
+			Optional(generic.T[Velocity]()).  // but those may be nil
+			With(generic.T[Elevation]()).     // additional required components
+			Without(generic.T[Rotation]())    // entities with any of these are excluded.
 
 	q := filter.Query(&world)
 
 	for q.Next() {
-		_, pos, vel := q.GetAll()
+		_, pos, vel := q.Get()
 		pos.X += vel.X
 		pos.Y += vel.Y
 	}
diff --git a/examples/locked_world/main.go b/examples/locked_world/main.go
index 6c9d0a9..1b2f9f9 100644
--- a/examples/locked_world/main.go
+++ b/examples/locked_world/main.go
@@ -33,13 +33,14 @@ func main() {
 	// Create a World.
 	world := ecs.NewWorld()
 
-	// Create a generic entity mutation helper.
-	mutator := generic.NewMutate2[Position, Energy](&world)
+	// Create a component mapper.
+	mapper := generic.NewMap2[Position, Energy](&world)
 
 	// Create entities.
 	for i := 0; i < 1000; i++ {
-		// Create a new Entity.
-		_, pos, en := mutator.NewEntity()
+		// Create a new Entity with components.
+		_, pos, en := mapper.NewEntity()
+
 		pos.X = rand.Float64() * 100
 		pos.Y = rand.Float64() * 100
 		en.Value = rand.Float64()
@@ -65,7 +66,7 @@ func main() {
 		// Thus, it is not possible to add or remove entities or components.
 		for query.Next() {
 			// Component access through the Query.
-			entity, pos, ene := query.GetAll()
+			entity, pos, ene := query.Get()
 			// Do model logic.
 			ene.Value += rand.NormFloat64() * 0.05
 
@@ -92,7 +93,7 @@ func main() {
 
 		// Remove entities that are to die
 		for _, entity := range toDie {
-			world.RemEntity(entity)
+			world.RemoveEntity(entity)
 		}
 
 		// Create entities through reproduction
@@ -100,7 +101,8 @@ func main() {
 			// Create offspring entities.
 			for i := 0; i < repro.Offspring; i++ {
 				// Create a new Entity and initialize it.
-				_, pos, en := mutator.NewEntity()
+				_, pos, en := mapper.NewEntity()
+
 				pos.X = repro.X + rand.NormFloat64()
 				pos.Y = repro.Y + rand.NormFloat64()
 				en.Value = rand.Float64() * 0.5
diff --git a/examples/readme/main.go b/examples/readme/main.go
index c70243a..8079ba6 100644
--- a/examples/readme/main.go
+++ b/examples/readme/main.go
@@ -26,13 +26,13 @@ func main() {
 	// Create a World.
 	world := ecs.NewWorld()
 
-	// Create a generic entity mutation helper.
-	mutator := generic.NewMutate2[Position, Velocity](&world)
+	// Create a component mapper.
+	mapper := generic.NewMap2[Position, Velocity](&world)
 
 	// Create entities.
 	for i := 0; i < 1000; i++ {
 		// Create a new Entity with components.
-		_, pos, vel := mutator.NewEntity()
+		_, pos, vel := mapper.NewEntity()
 
 		// Initialize component fields.
 		pos.X = rand.Float64() * 100
@@ -51,7 +51,7 @@ func main() {
 		// Iterate it
 		for query.Next() {
 			// Component access through the Query.
-			_, pos, vel := query.GetAll()
+			_, pos, vel := query.Get()
 			// Update component fields.
 			pos.X += vel.X
 			pos.Y += vel.Y
diff --git a/generic/compiled.go b/generic/compiled.go
index 810332e..f81b845 100644
--- a/generic/compiled.go
+++ b/generic/compiled.go
@@ -1,8 +1,6 @@
 package generic
 
 import (
-	"reflect"
-
 	"github.com/mlange-42/arche/ecs"
 )
 
@@ -13,7 +11,7 @@ type compiledQuery struct {
 	compiled bool
 }
 
-func (q *compiledQuery) Compile(w *ecs.World, include, optional, exclude []reflect.Type) {
+func (q *compiledQuery) Compile(w *ecs.World, include, optional, exclude []Comp) {
 	if q.compiled {
 		return
 	}
diff --git a/generic/generate/main.go b/generic/generate/main.go
index e6b1430..6ce38ec 100644
--- a/generic/generate/main.go
+++ b/generic/generate/main.go
@@ -33,16 +33,16 @@ type getter struct {
 
 func main() {
 	generateQueries()
-	generateMutates()
+	generateMaps()
 }
 
-func generateMutates() {
-	fmt.Println("Generating mutates")
+func generateMaps() {
+	fmt.Println("Generating maps")
 
 	maxIndex := len(typeLetters)
 	text := bytes.Buffer{}
 
-	header, err := template.ParseFiles("./generate/mutate_header.go.txt")
+	header, err := template.ParseFiles("./generate/map_header.go.txt")
 	if err != nil {
 		panic(err)
 	}
@@ -51,20 +51,29 @@ func generateMutates() {
 		panic(err)
 	}
 
-	mutate, err := template.ParseFiles("./generate/mutate.go.txt")
+	mutate, err := template.ParseFiles("./generate/map.go.txt")
 	if err != nil {
 		panic(err)
 	}
 
 	for i := 1; i <= maxIndex; i++ {
+		types := ""
+		returnTypes := ""
+		fullTypes := ""
 		returnAll := ""
+		include := ""
 		components := ""
 		arguments := ""
 
-		types := "[" + strings.Join(typeLetters[:i], ", ") + "]"
-		returnTypes := "*" + strings.Join(typeLetters[:i], ", *")
-		fullTypes := "[" + strings.Join(typeLetters[:i], " any, ") + " any]"
-		include := "[]ecs.ID{ecs.ComponentID[" + strings.Join(typeLetters[:i], "](w), ecs.ComponentID[") + "](w)}"
+		if i > 0 {
+			types = "[" + strings.Join(typeLetters[:i], ", ") + "]"
+			returnTypes = "*" + strings.Join(typeLetters[:i], ", *")
+			fullTypes = "[" + strings.Join(typeLetters[:i], " any, ") + " any]"
+			include = "[]ecs.ID{ecs.ComponentID[" + strings.Join(typeLetters[:i], "](w), ecs.ComponentID[") + "](w)}"
+		} else {
+			include = "[]ecs.ID{}"
+		}
+
 		for j := 0; j < i; j++ {
 			returnAll += fmt.Sprintf("(*%s)(m.world.Get(entity, m.ids[%d]))", typeLetters[j], j)
 			arguments += fmt.Sprintf("%s *%s", strings.ToLower(typeLetters[j]), typeLetters[j])
@@ -92,7 +101,7 @@ func generateMutates() {
 		}
 	}
 
-	if err := os.WriteFile("mutate_generated.go", text.Bytes(), 0666); err != nil {
+	if err := os.WriteFile("map_generated.go", text.Bytes(), 0666); err != nil {
 		panic(err)
 	}
 }
@@ -136,7 +145,7 @@ func generateQueries() {
 			types = "[" + strings.Join(typeLetters[:i], ", ") + "]"
 			returnTypes = "*" + strings.Join(typeLetters[:i], ", *")
 			fullTypes = "[" + strings.Join(typeLetters[:i], " any, ") + " any]"
-			include = "[]reflect.Type{typeOf[" + strings.Join(typeLetters[:i], "](), typeOf[") + "]()}"
+			include = "[]Comp{typeOf[" + strings.Join(typeLetters[:i], "](), typeOf[") + "]()}"
 			for j := 0; j < i; j++ {
 				returnAll += fmt.Sprintf("(*%s)(q.Query.Get(q.ids[%d]))", typeLetters[j], j)
 				if j < i-1 {
@@ -144,7 +153,7 @@ func generateQueries() {
 				}
 			}
 		} else {
-			include = "[]reflect.Type{}"
+			include = "[]Comp{}"
 		}
 		data := query{
 			Index:       i,
diff --git a/generic/generate/map.go.txt b/generic/generate/map.go.txt
new file mode 100644
index 0000000..833741a
--- /dev/null
+++ b/generic/generate/map.go.txt
@@ -0,0 +1,68 @@
+
+//////////////////////////////////////////////////////////////////////////
+
+// Map{{ .Index }} is a helper for mapping {{ .NumberStr }} components.
+type Map{{ .Index }}{{ .TypesFull }} struct {
+	ids    []ecs.ID
+	world  *ecs.World
+}
+
+// NewMap{{ .Index }} creates a new Map{{ .Index }} object.
+func NewMap{{ .Index }}{{ .TypesFull }}(w *ecs.World) Map{{ .Index }}{{ .Types }} {
+	return Map{{ .Index }}{{ .Types }}{
+		ids:   {{ .Include }},
+		world: w,
+	}
+}
+
+// Get all the Map{{ .Index }}'s components for the given entity.
+//
+// See also [ecs.World.Get].
+func (m *Map{{ .Index }}{{ .Types }}) Get(entity ecs.Entity) ({{ .TypesReturn }}) {
+	return {{ .ReturnAll }}
+}
+
+// NewEntity creates a new [ecs.Entity] with the Mutate{{ .Index }}'s components.
+//
+// See also [ecs.World.NewEntity].
+func (m *Map{{ .Index }}{{ .Types }}) NewEntity() (ecs.Entity, {{ .TypesReturn }}) {
+	entity := m.world.NewEntity(m.ids...)
+	return entity{{if .ReturnAll}}, {{ .ReturnAll }}{{ end }}
+}
+
+{{if .ReturnAll}}
+// NewEntityWith creates a new [ecs.Entity] with the Map{{ .Index }}'s components, using the supplied values.
+//
+// See also [ecs.World.NewEntityWith].
+func (m *Map{{ .Index }}{{ .Types }}) NewEntityWith({{ .Arguments }}) (ecs.Entity, {{ .TypesReturn }}) {
+	entity := m.world.NewEntityWith(
+		{{ .Components }}
+	)
+	return entity{{if .ReturnAll}}, {{ .ReturnAll }}{{ end }}
+}
+
+// Add the Map{{ .Index }}'s components to the given entity.
+//
+// See also [ecs.World.Add].
+func (m *Map{{ .Index }}{{ .Types }}) Add(entity ecs.Entity) ({{ .TypesReturn }}) {
+	m.world.Add(entity, m.ids...)
+	return {{ .ReturnAll }}
+}
+
+// Assign the Map{{ .Index }}'s components to the given entity, using the supplied values.
+//
+// See also [ecs.World.Assign] and [ecs.World.AssignN].
+func (m *Map{{ .Index }}{{ .Types }}) Assign(entity ecs.Entity, {{ .Arguments }}) ({{ .TypesReturn }}) {
+	m.world.AssignN(entity,
+		{{ .Components }}
+	)
+	return {{ .ReturnAll }}
+}
+{{ end }}
+
+// Remove the components set via [Map{{ .Index }}.WithRemove] from the given entity.
+//
+// See also [ecs.World.Remove].
+func (m *Map{{ .Index }}{{ .Types }}) Remove(entity ecs.Entity) {
+	m.world.Remove(entity, m.ids...)
+}
\ No newline at end of file
diff --git a/generic/generate/mutate_header.go.txt b/generic/generate/map_header.go.txt
similarity index 100%
rename from generic/generate/mutate_header.go.txt
rename to generic/generate/map_header.go.txt
diff --git a/generic/generate/mutate.go.txt b/generic/generate/mutate.go.txt
deleted file mode 100644
index 8663c67..0000000
--- a/generic/generate/mutate.go.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-
-//////////////////////////////////////////////////////////////////////////
-
-// Mutate{{ .Index }} is a helper for mutating {{ .NumberStr }} components.
-//
-// It can be used to create entities ([Mutate{{ .Index }}.NewEntity] and [Mutate{{ .Index }}.NewEntityWith]),
-// and to add or remove components ([Mutate{{ .Index }}.Add], [Mutate{{ .Index }}.Assign] and [Mutate{{ .Index }}.Remove]).
-type Mutate{{ .Index }}{{ .TypesFull }} struct {
-	ids   []ecs.ID
-	world *ecs.World
-}
-
-// NewMutate{{ .Index }} creates a new Mutate{{ .Index }} object.
-func NewMutate{{ .Index }}{{ .TypesFull }}(w *ecs.World) Mutate{{ .Index }}{{ .Types }} {
-	return Mutate{{ .Index }}{{ .Types }}{
-		ids:   {{ .Include }},
-		world: w,
-	}
-}
-
-// NewEntity creates a new [ecs.Entity] with the Mutate{{ .Index }}'s components.
-//
-// See also [ecs.World.NewEntity].
-func (m *Mutate{{ .Index }}{{ .Types }}) NewEntity() (ecs.Entity, {{ .TypesReturn }}) {
-	entity := m.world.NewEntity(m.ids...)
-	return entity, {{ .ReturnAll }}
-}
-
-// NewEntityWith creates a new [ecs.Entity] with the Mutate{{ .Index }}'s components, using the supplied values.
-//
-// See also [ecs.World.NewEntityWith].
-func (m *Mutate{{ .Index }}{{ .Types }}) NewEntityWith({{ .Arguments }}) (ecs.Entity, {{ .TypesReturn }}) {
-	entity := m.world.NewEntityWith(
-		{{ .Components }}
-	)
-	return entity, {{ .ReturnAll }}
-}
-
-// Add the Mutate{{ .Index }}'s components to the given entity.
-//
-// See also [ecs.World.Add].
-func (m *Mutate{{ .Index }}{{ .Types }}) Add(entity ecs.Entity) ({{ .TypesReturn }}) {
-	m.world.Add(entity, m.ids...)
-	return {{ .ReturnAll }}
-}
-
-// Assign the Mutate{{ .Index }}'s components to the given entity, using the supplied values.
-//
-// See also [ecs.World.Assign] and [ecs.World.AssignN].
-func (m *Mutate{{ .Index }}{{ .Types }}) Assign(entity ecs.Entity, {{ .Arguments }}) ({{ .TypesReturn }}) {
-	m.world.AssignN(entity,
-		{{ .Components }}
-	)
-	return {{ .ReturnAll }}
-}
-
-// Remove the Mutate{{ .Index }}'s components from the given entity.
-//
-// See also [ecs.World.Remove].
-func (m *Mutate{{ .Index }}{{ .Types }}) Remove(entity ecs.Entity) {
-	m.world.Remove(entity, m.ids...)
-}
diff --git a/generic/generate/query.go.txt b/generic/generate/query.go.txt
index 245a7a7..79792d5 100644
--- a/generic/generate/query.go.txt
+++ b/generic/generate/query.go.txt
@@ -3,9 +3,9 @@
 
 // Filter{{ .Index }} is a helper for building [Query{{ .Index }}] query iterators.
 type Filter{{ .Index }}{{ .TypesFull }} struct {
-	include  []reflect.Type
-	optional []reflect.Type
-	exclude  []reflect.Type
+	include  []Comp
+	optional []Comp
+	exclude  []Comp
 	compiled compiledQuery
 }
 
@@ -18,21 +18,23 @@ func NewFilter{{ .Index }}{{ .TypesFull }}() *Filter{{ .Index }}{{ .Types }} {
 	}
 }
 
+{{if .Types}}
 // Optional makes some of the query's components optional.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
+// Create the required mask items with [T].
 //
 // Only affects component types that were specified in the query.
-func (q *Filter{{ .Index }}{{ .Types }}) Optional(mask []reflect.Type) *Filter{{ .Index }}{{ .Types }} {
+func (q *Filter{{ .Index }}{{ .Types }}) Optional(mask ...Comp) *Filter{{ .Index }}{{ .Types }} {
 	q.optional = append(q.optional, mask...)
 	q.compiled.Reset()
 	return q
 }
+{{ end }}
 
 // With adds more required components that are not accessible using Get... methods.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter{{ .Index }}{{ .Types }}) With(mask []reflect.Type) *Filter{{ .Index }}{{ .Types }} {
+// Create the required mask items with [T].
+func (q *Filter{{ .Index }}{{ .Types }}) With(mask ...Comp) *Filter{{ .Index }}{{ .Types }} {
 	q.include = append(q.include, mask...)
 	q.compiled.Reset()
 	return q
@@ -40,8 +42,8 @@ func (q *Filter{{ .Index }}{{ .Types }}) With(mask []reflect.Type) *Filter{{ .In
 
 // Without excludes entities with any of the given components from the query.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter{{ .Index }}{{ .Types }}) Without(mask []reflect.Type) *Filter{{ .Index }}{{ .Types }} {
+// Create the required mask items with [T].
+func (q *Filter{{ .Index }}{{ .Types }}) Without(mask ...Comp) *Filter{{ .Index }}{{ .Types }} {
 	q.exclude = append(q.exclude, mask...)
 	q.compiled.Reset()
 	return q
@@ -67,7 +69,7 @@ func (q *Filter{{ .Index }}{{ .Types }}) Filter(w *ecs.World) ecs.MaskPair {
 
 // Query{{ .Index }} is a generic query iterator for {{ .NumberStr }} components.
 //
-// Create one with [NewFilter{{ .Index }}] and [Filter{{ .Index }}.Query]
+// Create it with [NewFilter{{ .Index }}] and [Filter{{ .Index }}.Query]
 type Query{{ .Index }}{{ .TypesFull }} struct {
 	ecs.Query
 	ids []ecs.ID
diff --git a/generic/generate/query_getall.go.txt b/generic/generate/query_getall.go.txt
index d6aaecd..5c6f708 100644
--- a/generic/generate/query_getall.go.txt
+++ b/generic/generate/query_getall.go.txt
@@ -1,5 +1,5 @@
 
-// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
-func (q *Query{{ .Index }}{{ .Types }}) GetAll() (ecs.Entity, {{ .TypesReturn }}) {
+// Get returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query{{ .Index }}{{ .Types }}) Get() (ecs.Entity, {{ .TypesReturn }}) {
 	return q.Entity(), {{ .ReturnAll }}
 }
diff --git a/generic/generate/query_header.go.txt b/generic/generate/query_header.go.txt
index d9fe156..d5b41eb 100644
--- a/generic/generate/query_header.go.txt
+++ b/generic/generate/query_header.go.txt
@@ -3,7 +3,5 @@ package generic
 // Code generated by go generate; DO NOT EDIT.
 
 import (
-	"reflect"
-
 	"github.com/mlange-42/arche/ecs"
 )
diff --git a/generic/mutate_generated.go b/generic/map_generated.go
similarity index 58%
rename from generic/mutate_generated.go
rename to generic/map_generated.go
index ad8f745..6cb1929 100644
--- a/generic/mutate_generated.go
+++ b/generic/map_generated.go
@@ -8,97 +8,105 @@ import (
 
 //////////////////////////////////////////////////////////////////////////
 
-// Mutate1 is a helper for mutating one components.
-//
-// It can be used to create entities ([Mutate1.NewEntity] and [Mutate1.NewEntityWith]),
-// and to add or remove components ([Mutate1.Add], [Mutate1.Assign] and [Mutate1.Remove]).
-type Mutate1[A any] struct {
+// Map1 is a helper for mapping one components.
+type Map1[A any] struct {
 	ids   []ecs.ID
 	world *ecs.World
 }
 
-// NewMutate1 creates a new Mutate1 object.
-func NewMutate1[A any](w *ecs.World) Mutate1[A] {
-	return Mutate1[A]{
+// NewMap1 creates a new Map1 object.
+func NewMap1[A any](w *ecs.World) Map1[A] {
+	return Map1[A]{
 		ids:   []ecs.ID{ecs.ComponentID[A](w)},
 		world: w,
 	}
 }
 
+// Get all the Map1's components for the given entity.
+//
+// See also [ecs.World.Get].
+func (m *Map1[A]) Get(entity ecs.Entity) *A {
+	return (*A)(m.world.Get(entity, m.ids[0]))
+}
+
 // NewEntity creates a new [ecs.Entity] with the Mutate1's components.
 //
 // See also [ecs.World.NewEntity].
-func (m *Mutate1[A]) NewEntity() (ecs.Entity, *A) {
+func (m *Map1[A]) NewEntity() (ecs.Entity, *A) {
 	entity := m.world.NewEntity(m.ids...)
 	return entity, (*A)(m.world.Get(entity, m.ids[0]))
 }
 
-// NewEntityWith creates a new [ecs.Entity] with the Mutate1's components, using the supplied values.
+// NewEntityWith creates a new [ecs.Entity] with the Map1's components, using the supplied values.
 //
 // See also [ecs.World.NewEntityWith].
-func (m *Mutate1[A]) NewEntityWith(a *A) (ecs.Entity, *A) {
+func (m *Map1[A]) NewEntityWith(a *A) (ecs.Entity, *A) {
 	entity := m.world.NewEntityWith(
 		ecs.Component{ID: m.ids[0], Component: a},
 	)
 	return entity, (*A)(m.world.Get(entity, m.ids[0]))
 }
 
-// Add the Mutate1's components to the given entity.
+// Add the Map1's components to the given entity.
 //
 // See also [ecs.World.Add].
-func (m *Mutate1[A]) Add(entity ecs.Entity) *A {
+func (m *Map1[A]) Add(entity ecs.Entity) *A {
 	m.world.Add(entity, m.ids...)
 	return (*A)(m.world.Get(entity, m.ids[0]))
 }
 
-// Assign the Mutate1's components to the given entity, using the supplied values.
+// Assign the Map1's components to the given entity, using the supplied values.
 //
 // See also [ecs.World.Assign] and [ecs.World.AssignN].
-func (m *Mutate1[A]) Assign(entity ecs.Entity, a *A) *A {
+func (m *Map1[A]) Assign(entity ecs.Entity, a *A) *A {
 	m.world.AssignN(entity,
 		ecs.Component{ID: m.ids[0], Component: a},
 	)
 	return (*A)(m.world.Get(entity, m.ids[0]))
 }
 
-// Remove the Mutate1's components from the given entity.
+// Remove the components set via [Map1.WithRemove] from the given entity.
 //
 // See also [ecs.World.Remove].
-func (m *Mutate1[A]) Remove(entity ecs.Entity) {
+func (m *Map1[A]) Remove(entity ecs.Entity) {
 	m.world.Remove(entity, m.ids...)
 }
 
 //////////////////////////////////////////////////////////////////////////
 
-// Mutate2 is a helper for mutating two components.
-//
-// It can be used to create entities ([Mutate2.NewEntity] and [Mutate2.NewEntityWith]),
-// and to add or remove components ([Mutate2.Add], [Mutate2.Assign] and [Mutate2.Remove]).
-type Mutate2[A any, B any] struct {
+// Map2 is a helper for mapping two components.
+type Map2[A any, B any] struct {
 	ids   []ecs.ID
 	world *ecs.World
 }
 
-// NewMutate2 creates a new Mutate2 object.
-func NewMutate2[A any, B any](w *ecs.World) Mutate2[A, B] {
-	return Mutate2[A, B]{
+// NewMap2 creates a new Map2 object.
+func NewMap2[A any, B any](w *ecs.World) Map2[A, B] {
+	return Map2[A, B]{
 		ids:   []ecs.ID{ecs.ComponentID[A](w), ecs.ComponentID[B](w)},
 		world: w,
 	}
 }
 
+// Get all the Map2's components for the given entity.
+//
+// See also [ecs.World.Get].
+func (m *Map2[A, B]) Get(entity ecs.Entity) (*A, *B) {
+	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1]))
+}
+
 // NewEntity creates a new [ecs.Entity] with the Mutate2's components.
 //
 // See also [ecs.World.NewEntity].
-func (m *Mutate2[A, B]) NewEntity() (ecs.Entity, *A, *B) {
+func (m *Map2[A, B]) NewEntity() (ecs.Entity, *A, *B) {
 	entity := m.world.NewEntity(m.ids...)
 	return entity, (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1]))
 }
 
-// NewEntityWith creates a new [ecs.Entity] with the Mutate2's components, using the supplied values.
+// NewEntityWith creates a new [ecs.Entity] with the Map2's components, using the supplied values.
 //
 // See also [ecs.World.NewEntityWith].
-func (m *Mutate2[A, B]) NewEntityWith(a *A, b *B) (ecs.Entity, *A, *B) {
+func (m *Map2[A, B]) NewEntityWith(a *A, b *B) (ecs.Entity, *A, *B) {
 	entity := m.world.NewEntityWith(
 		ecs.Component{ID: m.ids[0], Component: a},
 		ecs.Component{ID: m.ids[1], Component: b},
@@ -106,18 +114,18 @@ func (m *Mutate2[A, B]) NewEntityWith(a *A, b *B) (ecs.Entity, *A, *B) {
 	return entity, (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1]))
 }
 
-// Add the Mutate2's components to the given entity.
+// Add the Map2's components to the given entity.
 //
 // See also [ecs.World.Add].
-func (m *Mutate2[A, B]) Add(entity ecs.Entity) (*A, *B) {
+func (m *Map2[A, B]) Add(entity ecs.Entity) (*A, *B) {
 	m.world.Add(entity, m.ids...)
 	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1]))
 }
 
-// Assign the Mutate2's components to the given entity, using the supplied values.
+// Assign the Map2's components to the given entity, using the supplied values.
 //
 // See also [ecs.World.Assign] and [ecs.World.AssignN].
-func (m *Mutate2[A, B]) Assign(entity ecs.Entity, a *A, b *B) (*A, *B) {
+func (m *Map2[A, B]) Assign(entity ecs.Entity, a *A, b *B) (*A, *B) {
 	m.world.AssignN(entity,
 		ecs.Component{ID: m.ids[0], Component: a},
 		ecs.Component{ID: m.ids[1], Component: b},
@@ -125,44 +133,48 @@ func (m *Mutate2[A, B]) Assign(entity ecs.Entity, a *A, b *B) (*A, *B) {
 	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1]))
 }
 
-// Remove the Mutate2's components from the given entity.
+// Remove the components set via [Map2.WithRemove] from the given entity.
 //
 // See also [ecs.World.Remove].
-func (m *Mutate2[A, B]) Remove(entity ecs.Entity) {
+func (m *Map2[A, B]) Remove(entity ecs.Entity) {
 	m.world.Remove(entity, m.ids...)
 }
 
 //////////////////////////////////////////////////////////////////////////
 
-// Mutate3 is a helper for mutating three components.
-//
-// It can be used to create entities ([Mutate3.NewEntity] and [Mutate3.NewEntityWith]),
-// and to add or remove components ([Mutate3.Add], [Mutate3.Assign] and [Mutate3.Remove]).
-type Mutate3[A any, B any, C any] struct {
+// Map3 is a helper for mapping three components.
+type Map3[A any, B any, C any] struct {
 	ids   []ecs.ID
 	world *ecs.World
 }
 
-// NewMutate3 creates a new Mutate3 object.
-func NewMutate3[A any, B any, C any](w *ecs.World) Mutate3[A, B, C] {
-	return Mutate3[A, B, C]{
+// NewMap3 creates a new Map3 object.
+func NewMap3[A any, B any, C any](w *ecs.World) Map3[A, B, C] {
+	return Map3[A, B, C]{
 		ids:   []ecs.ID{ecs.ComponentID[A](w), ecs.ComponentID[B](w), ecs.ComponentID[C](w)},
 		world: w,
 	}
 }
 
+// Get all the Map3's components for the given entity.
+//
+// See also [ecs.World.Get].
+func (m *Map3[A, B, C]) Get(entity ecs.Entity) (*A, *B, *C) {
+	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2]))
+}
+
 // NewEntity creates a new [ecs.Entity] with the Mutate3's components.
 //
 // See also [ecs.World.NewEntity].
-func (m *Mutate3[A, B, C]) NewEntity() (ecs.Entity, *A, *B, *C) {
+func (m *Map3[A, B, C]) NewEntity() (ecs.Entity, *A, *B, *C) {
 	entity := m.world.NewEntity(m.ids...)
 	return entity, (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2]))
 }
 
-// NewEntityWith creates a new [ecs.Entity] with the Mutate3's components, using the supplied values.
+// NewEntityWith creates a new [ecs.Entity] with the Map3's components, using the supplied values.
 //
 // See also [ecs.World.NewEntityWith].
-func (m *Mutate3[A, B, C]) NewEntityWith(a *A, b *B, c *C) (ecs.Entity, *A, *B, *C) {
+func (m *Map3[A, B, C]) NewEntityWith(a *A, b *B, c *C) (ecs.Entity, *A, *B, *C) {
 	entity := m.world.NewEntityWith(
 		ecs.Component{ID: m.ids[0], Component: a},
 		ecs.Component{ID: m.ids[1], Component: b},
@@ -171,18 +183,18 @@ func (m *Mutate3[A, B, C]) NewEntityWith(a *A, b *B, c *C) (ecs.Entity, *A, *B,
 	return entity, (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2]))
 }
 
-// Add the Mutate3's components to the given entity.
+// Add the Map3's components to the given entity.
 //
 // See also [ecs.World.Add].
-func (m *Mutate3[A, B, C]) Add(entity ecs.Entity) (*A, *B, *C) {
+func (m *Map3[A, B, C]) Add(entity ecs.Entity) (*A, *B, *C) {
 	m.world.Add(entity, m.ids...)
 	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2]))
 }
 
-// Assign the Mutate3's components to the given entity, using the supplied values.
+// Assign the Map3's components to the given entity, using the supplied values.
 //
 // See also [ecs.World.Assign] and [ecs.World.AssignN].
-func (m *Mutate3[A, B, C]) Assign(entity ecs.Entity, a *A, b *B, c *C) (*A, *B, *C) {
+func (m *Map3[A, B, C]) Assign(entity ecs.Entity, a *A, b *B, c *C) (*A, *B, *C) {
 	m.world.AssignN(entity,
 		ecs.Component{ID: m.ids[0], Component: a},
 		ecs.Component{ID: m.ids[1], Component: b},
@@ -191,44 +203,48 @@ func (m *Mutate3[A, B, C]) Assign(entity ecs.Entity, a *A, b *B, c *C) (*A, *B,
 	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2]))
 }
 
-// Remove the Mutate3's components from the given entity.
+// Remove the components set via [Map3.WithRemove] from the given entity.
 //
 // See also [ecs.World.Remove].
-func (m *Mutate3[A, B, C]) Remove(entity ecs.Entity) {
+func (m *Map3[A, B, C]) Remove(entity ecs.Entity) {
 	m.world.Remove(entity, m.ids...)
 }
 
 //////////////////////////////////////////////////////////////////////////
 
-// Mutate4 is a helper for mutating four components.
-//
-// It can be used to create entities ([Mutate4.NewEntity] and [Mutate4.NewEntityWith]),
-// and to add or remove components ([Mutate4.Add], [Mutate4.Assign] and [Mutate4.Remove]).
-type Mutate4[A any, B any, C any, D any] struct {
+// Map4 is a helper for mapping four components.
+type Map4[A any, B any, C any, D any] struct {
 	ids   []ecs.ID
 	world *ecs.World
 }
 
-// NewMutate4 creates a new Mutate4 object.
-func NewMutate4[A any, B any, C any, D any](w *ecs.World) Mutate4[A, B, C, D] {
-	return Mutate4[A, B, C, D]{
+// NewMap4 creates a new Map4 object.
+func NewMap4[A any, B any, C any, D any](w *ecs.World) Map4[A, B, C, D] {
+	return Map4[A, B, C, D]{
 		ids:   []ecs.ID{ecs.ComponentID[A](w), ecs.ComponentID[B](w), ecs.ComponentID[C](w), ecs.ComponentID[D](w)},
 		world: w,
 	}
 }
 
+// Get all the Map4's components for the given entity.
+//
+// See also [ecs.World.Get].
+func (m *Map4[A, B, C, D]) Get(entity ecs.Entity) (*A, *B, *C, *D) {
+	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3]))
+}
+
 // NewEntity creates a new [ecs.Entity] with the Mutate4's components.
 //
 // See also [ecs.World.NewEntity].
-func (m *Mutate4[A, B, C, D]) NewEntity() (ecs.Entity, *A, *B, *C, *D) {
+func (m *Map4[A, B, C, D]) NewEntity() (ecs.Entity, *A, *B, *C, *D) {
 	entity := m.world.NewEntity(m.ids...)
 	return entity, (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3]))
 }
 
-// NewEntityWith creates a new [ecs.Entity] with the Mutate4's components, using the supplied values.
+// NewEntityWith creates a new [ecs.Entity] with the Map4's components, using the supplied values.
 //
 // See also [ecs.World.NewEntityWith].
-func (m *Mutate4[A, B, C, D]) NewEntityWith(a *A, b *B, c *C, d *D) (ecs.Entity, *A, *B, *C, *D) {
+func (m *Map4[A, B, C, D]) NewEntityWith(a *A, b *B, c *C, d *D) (ecs.Entity, *A, *B, *C, *D) {
 	entity := m.world.NewEntityWith(
 		ecs.Component{ID: m.ids[0], Component: a},
 		ecs.Component{ID: m.ids[1], Component: b},
@@ -238,18 +254,18 @@ func (m *Mutate4[A, B, C, D]) NewEntityWith(a *A, b *B, c *C, d *D) (ecs.Entity,
 	return entity, (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3]))
 }
 
-// Add the Mutate4's components to the given entity.
+// Add the Map4's components to the given entity.
 //
 // See also [ecs.World.Add].
-func (m *Mutate4[A, B, C, D]) Add(entity ecs.Entity) (*A, *B, *C, *D) {
+func (m *Map4[A, B, C, D]) Add(entity ecs.Entity) (*A, *B, *C, *D) {
 	m.world.Add(entity, m.ids...)
 	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3]))
 }
 
-// Assign the Mutate4's components to the given entity, using the supplied values.
+// Assign the Map4's components to the given entity, using the supplied values.
 //
 // See also [ecs.World.Assign] and [ecs.World.AssignN].
-func (m *Mutate4[A, B, C, D]) Assign(entity ecs.Entity, a *A, b *B, c *C, d *D) (*A, *B, *C, *D) {
+func (m *Map4[A, B, C, D]) Assign(entity ecs.Entity, a *A, b *B, c *C, d *D) (*A, *B, *C, *D) {
 	m.world.AssignN(entity,
 		ecs.Component{ID: m.ids[0], Component: a},
 		ecs.Component{ID: m.ids[1], Component: b},
@@ -259,44 +275,48 @@ func (m *Mutate4[A, B, C, D]) Assign(entity ecs.Entity, a *A, b *B, c *C, d *D)
 	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3]))
 }
 
-// Remove the Mutate4's components from the given entity.
+// Remove the components set via [Map4.WithRemove] from the given entity.
 //
 // See also [ecs.World.Remove].
-func (m *Mutate4[A, B, C, D]) Remove(entity ecs.Entity) {
+func (m *Map4[A, B, C, D]) Remove(entity ecs.Entity) {
 	m.world.Remove(entity, m.ids...)
 }
 
 //////////////////////////////////////////////////////////////////////////
 
-// Mutate5 is a helper for mutating five components.
-//
-// It can be used to create entities ([Mutate5.NewEntity] and [Mutate5.NewEntityWith]),
-// and to add or remove components ([Mutate5.Add], [Mutate5.Assign] and [Mutate5.Remove]).
-type Mutate5[A any, B any, C any, D any, E any] struct {
+// Map5 is a helper for mapping five components.
+type Map5[A any, B any, C any, D any, E any] struct {
 	ids   []ecs.ID
 	world *ecs.World
 }
 
-// NewMutate5 creates a new Mutate5 object.
-func NewMutate5[A any, B any, C any, D any, E any](w *ecs.World) Mutate5[A, B, C, D, E] {
-	return Mutate5[A, B, C, D, E]{
+// NewMap5 creates a new Map5 object.
+func NewMap5[A any, B any, C any, D any, E any](w *ecs.World) Map5[A, B, C, D, E] {
+	return Map5[A, B, C, D, E]{
 		ids:   []ecs.ID{ecs.ComponentID[A](w), ecs.ComponentID[B](w), ecs.ComponentID[C](w), ecs.ComponentID[D](w), ecs.ComponentID[E](w)},
 		world: w,
 	}
 }
 
+// Get all the Map5's components for the given entity.
+//
+// See also [ecs.World.Get].
+func (m *Map5[A, B, C, D, E]) Get(entity ecs.Entity) (*A, *B, *C, *D, *E) {
+	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4]))
+}
+
 // NewEntity creates a new [ecs.Entity] with the Mutate5's components.
 //
 // See also [ecs.World.NewEntity].
-func (m *Mutate5[A, B, C, D, E]) NewEntity() (ecs.Entity, *A, *B, *C, *D, *E) {
+func (m *Map5[A, B, C, D, E]) NewEntity() (ecs.Entity, *A, *B, *C, *D, *E) {
 	entity := m.world.NewEntity(m.ids...)
 	return entity, (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4]))
 }
 
-// NewEntityWith creates a new [ecs.Entity] with the Mutate5's components, using the supplied values.
+// NewEntityWith creates a new [ecs.Entity] with the Map5's components, using the supplied values.
 //
 // See also [ecs.World.NewEntityWith].
-func (m *Mutate5[A, B, C, D, E]) NewEntityWith(a *A, b *B, c *C, d *D, e *E) (ecs.Entity, *A, *B, *C, *D, *E) {
+func (m *Map5[A, B, C, D, E]) NewEntityWith(a *A, b *B, c *C, d *D, e *E) (ecs.Entity, *A, *B, *C, *D, *E) {
 	entity := m.world.NewEntityWith(
 		ecs.Component{ID: m.ids[0], Component: a},
 		ecs.Component{ID: m.ids[1], Component: b},
@@ -307,18 +327,18 @@ func (m *Mutate5[A, B, C, D, E]) NewEntityWith(a *A, b *B, c *C, d *D, e *E) (ec
 	return entity, (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4]))
 }
 
-// Add the Mutate5's components to the given entity.
+// Add the Map5's components to the given entity.
 //
 // See also [ecs.World.Add].
-func (m *Mutate5[A, B, C, D, E]) Add(entity ecs.Entity) (*A, *B, *C, *D, *E) {
+func (m *Map5[A, B, C, D, E]) Add(entity ecs.Entity) (*A, *B, *C, *D, *E) {
 	m.world.Add(entity, m.ids...)
 	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4]))
 }
 
-// Assign the Mutate5's components to the given entity, using the supplied values.
+// Assign the Map5's components to the given entity, using the supplied values.
 //
 // See also [ecs.World.Assign] and [ecs.World.AssignN].
-func (m *Mutate5[A, B, C, D, E]) Assign(entity ecs.Entity, a *A, b *B, c *C, d *D, e *E) (*A, *B, *C, *D, *E) {
+func (m *Map5[A, B, C, D, E]) Assign(entity ecs.Entity, a *A, b *B, c *C, d *D, e *E) (*A, *B, *C, *D, *E) {
 	m.world.AssignN(entity,
 		ecs.Component{ID: m.ids[0], Component: a},
 		ecs.Component{ID: m.ids[1], Component: b},
@@ -329,44 +349,48 @@ func (m *Mutate5[A, B, C, D, E]) Assign(entity ecs.Entity, a *A, b *B, c *C, d *
 	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4]))
 }
 
-// Remove the Mutate5's components from the given entity.
+// Remove the components set via [Map5.WithRemove] from the given entity.
 //
 // See also [ecs.World.Remove].
-func (m *Mutate5[A, B, C, D, E]) Remove(entity ecs.Entity) {
+func (m *Map5[A, B, C, D, E]) Remove(entity ecs.Entity) {
 	m.world.Remove(entity, m.ids...)
 }
 
 //////////////////////////////////////////////////////////////////////////
 
-// Mutate6 is a helper for mutating six components.
-//
-// It can be used to create entities ([Mutate6.NewEntity] and [Mutate6.NewEntityWith]),
-// and to add or remove components ([Mutate6.Add], [Mutate6.Assign] and [Mutate6.Remove]).
-type Mutate6[A any, B any, C any, D any, E any, F any] struct {
+// Map6 is a helper for mapping six components.
+type Map6[A any, B any, C any, D any, E any, F any] struct {
 	ids   []ecs.ID
 	world *ecs.World
 }
 
-// NewMutate6 creates a new Mutate6 object.
-func NewMutate6[A any, B any, C any, D any, E any, F any](w *ecs.World) Mutate6[A, B, C, D, E, F] {
-	return Mutate6[A, B, C, D, E, F]{
+// NewMap6 creates a new Map6 object.
+func NewMap6[A any, B any, C any, D any, E any, F any](w *ecs.World) Map6[A, B, C, D, E, F] {
+	return Map6[A, B, C, D, E, F]{
 		ids:   []ecs.ID{ecs.ComponentID[A](w), ecs.ComponentID[B](w), ecs.ComponentID[C](w), ecs.ComponentID[D](w), ecs.ComponentID[E](w), ecs.ComponentID[F](w)},
 		world: w,
 	}
 }
 
+// Get all the Map6's components for the given entity.
+//
+// See also [ecs.World.Get].
+func (m *Map6[A, B, C, D, E, F]) Get(entity ecs.Entity) (*A, *B, *C, *D, *E, *F) {
+	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5]))
+}
+
 // NewEntity creates a new [ecs.Entity] with the Mutate6's components.
 //
 // See also [ecs.World.NewEntity].
-func (m *Mutate6[A, B, C, D, E, F]) NewEntity() (ecs.Entity, *A, *B, *C, *D, *E, *F) {
+func (m *Map6[A, B, C, D, E, F]) NewEntity() (ecs.Entity, *A, *B, *C, *D, *E, *F) {
 	entity := m.world.NewEntity(m.ids...)
 	return entity, (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5]))
 }
 
-// NewEntityWith creates a new [ecs.Entity] with the Mutate6's components, using the supplied values.
+// NewEntityWith creates a new [ecs.Entity] with the Map6's components, using the supplied values.
 //
 // See also [ecs.World.NewEntityWith].
-func (m *Mutate6[A, B, C, D, E, F]) NewEntityWith(a *A, b *B, c *C, d *D, e *E, f *F) (ecs.Entity, *A, *B, *C, *D, *E, *F) {
+func (m *Map6[A, B, C, D, E, F]) NewEntityWith(a *A, b *B, c *C, d *D, e *E, f *F) (ecs.Entity, *A, *B, *C, *D, *E, *F) {
 	entity := m.world.NewEntityWith(
 		ecs.Component{ID: m.ids[0], Component: a},
 		ecs.Component{ID: m.ids[1], Component: b},
@@ -378,18 +402,18 @@ func (m *Mutate6[A, B, C, D, E, F]) NewEntityWith(a *A, b *B, c *C, d *D, e *E,
 	return entity, (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5]))
 }
 
-// Add the Mutate6's components to the given entity.
+// Add the Map6's components to the given entity.
 //
 // See also [ecs.World.Add].
-func (m *Mutate6[A, B, C, D, E, F]) Add(entity ecs.Entity) (*A, *B, *C, *D, *E, *F) {
+func (m *Map6[A, B, C, D, E, F]) Add(entity ecs.Entity) (*A, *B, *C, *D, *E, *F) {
 	m.world.Add(entity, m.ids...)
 	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5]))
 }
 
-// Assign the Mutate6's components to the given entity, using the supplied values.
+// Assign the Map6's components to the given entity, using the supplied values.
 //
 // See also [ecs.World.Assign] and [ecs.World.AssignN].
-func (m *Mutate6[A, B, C, D, E, F]) Assign(entity ecs.Entity, a *A, b *B, c *C, d *D, e *E, f *F) (*A, *B, *C, *D, *E, *F) {
+func (m *Map6[A, B, C, D, E, F]) Assign(entity ecs.Entity, a *A, b *B, c *C, d *D, e *E, f *F) (*A, *B, *C, *D, *E, *F) {
 	m.world.AssignN(entity,
 		ecs.Component{ID: m.ids[0], Component: a},
 		ecs.Component{ID: m.ids[1], Component: b},
@@ -401,44 +425,48 @@ func (m *Mutate6[A, B, C, D, E, F]) Assign(entity ecs.Entity, a *A, b *B, c *C,
 	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5]))
 }
 
-// Remove the Mutate6's components from the given entity.
+// Remove the components set via [Map6.WithRemove] from the given entity.
 //
 // See also [ecs.World.Remove].
-func (m *Mutate6[A, B, C, D, E, F]) Remove(entity ecs.Entity) {
+func (m *Map6[A, B, C, D, E, F]) Remove(entity ecs.Entity) {
 	m.world.Remove(entity, m.ids...)
 }
 
 //////////////////////////////////////////////////////////////////////////
 
-// Mutate7 is a helper for mutating seven components.
-//
-// It can be used to create entities ([Mutate7.NewEntity] and [Mutate7.NewEntityWith]),
-// and to add or remove components ([Mutate7.Add], [Mutate7.Assign] and [Mutate7.Remove]).
-type Mutate7[A any, B any, C any, D any, E any, F any, G any] struct {
+// Map7 is a helper for mapping seven components.
+type Map7[A any, B any, C any, D any, E any, F any, G any] struct {
 	ids   []ecs.ID
 	world *ecs.World
 }
 
-// NewMutate7 creates a new Mutate7 object.
-func NewMutate7[A any, B any, C any, D any, E any, F any, G any](w *ecs.World) Mutate7[A, B, C, D, E, F, G] {
-	return Mutate7[A, B, C, D, E, F, G]{
+// NewMap7 creates a new Map7 object.
+func NewMap7[A any, B any, C any, D any, E any, F any, G any](w *ecs.World) Map7[A, B, C, D, E, F, G] {
+	return Map7[A, B, C, D, E, F, G]{
 		ids:   []ecs.ID{ecs.ComponentID[A](w), ecs.ComponentID[B](w), ecs.ComponentID[C](w), ecs.ComponentID[D](w), ecs.ComponentID[E](w), ecs.ComponentID[F](w), ecs.ComponentID[G](w)},
 		world: w,
 	}
 }
 
+// Get all the Map7's components for the given entity.
+//
+// See also [ecs.World.Get].
+func (m *Map7[A, B, C, D, E, F, G]) Get(entity ecs.Entity) (*A, *B, *C, *D, *E, *F, *G) {
+	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5])), (*G)(m.world.Get(entity, m.ids[6]))
+}
+
 // NewEntity creates a new [ecs.Entity] with the Mutate7's components.
 //
 // See also [ecs.World.NewEntity].
-func (m *Mutate7[A, B, C, D, E, F, G]) NewEntity() (ecs.Entity, *A, *B, *C, *D, *E, *F, *G) {
+func (m *Map7[A, B, C, D, E, F, G]) NewEntity() (ecs.Entity, *A, *B, *C, *D, *E, *F, *G) {
 	entity := m.world.NewEntity(m.ids...)
 	return entity, (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5])), (*G)(m.world.Get(entity, m.ids[6]))
 }
 
-// NewEntityWith creates a new [ecs.Entity] with the Mutate7's components, using the supplied values.
+// NewEntityWith creates a new [ecs.Entity] with the Map7's components, using the supplied values.
 //
 // See also [ecs.World.NewEntityWith].
-func (m *Mutate7[A, B, C, D, E, F, G]) NewEntityWith(a *A, b *B, c *C, d *D, e *E, f *F, g *G) (ecs.Entity, *A, *B, *C, *D, *E, *F, *G) {
+func (m *Map7[A, B, C, D, E, F, G]) NewEntityWith(a *A, b *B, c *C, d *D, e *E, f *F, g *G) (ecs.Entity, *A, *B, *C, *D, *E, *F, *G) {
 	entity := m.world.NewEntityWith(
 		ecs.Component{ID: m.ids[0], Component: a},
 		ecs.Component{ID: m.ids[1], Component: b},
@@ -451,18 +479,18 @@ func (m *Mutate7[A, B, C, D, E, F, G]) NewEntityWith(a *A, b *B, c *C, d *D, e *
 	return entity, (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5])), (*G)(m.world.Get(entity, m.ids[6]))
 }
 
-// Add the Mutate7's components to the given entity.
+// Add the Map7's components to the given entity.
 //
 // See also [ecs.World.Add].
-func (m *Mutate7[A, B, C, D, E, F, G]) Add(entity ecs.Entity) (*A, *B, *C, *D, *E, *F, *G) {
+func (m *Map7[A, B, C, D, E, F, G]) Add(entity ecs.Entity) (*A, *B, *C, *D, *E, *F, *G) {
 	m.world.Add(entity, m.ids...)
 	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5])), (*G)(m.world.Get(entity, m.ids[6]))
 }
 
-// Assign the Mutate7's components to the given entity, using the supplied values.
+// Assign the Map7's components to the given entity, using the supplied values.
 //
 // See also [ecs.World.Assign] and [ecs.World.AssignN].
-func (m *Mutate7[A, B, C, D, E, F, G]) Assign(entity ecs.Entity, a *A, b *B, c *C, d *D, e *E, f *F, g *G) (*A, *B, *C, *D, *E, *F, *G) {
+func (m *Map7[A, B, C, D, E, F, G]) Assign(entity ecs.Entity, a *A, b *B, c *C, d *D, e *E, f *F, g *G) (*A, *B, *C, *D, *E, *F, *G) {
 	m.world.AssignN(entity,
 		ecs.Component{ID: m.ids[0], Component: a},
 		ecs.Component{ID: m.ids[1], Component: b},
@@ -475,44 +503,48 @@ func (m *Mutate7[A, B, C, D, E, F, G]) Assign(entity ecs.Entity, a *A, b *B, c *
 	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5])), (*G)(m.world.Get(entity, m.ids[6]))
 }
 
-// Remove the Mutate7's components from the given entity.
+// Remove the components set via [Map7.WithRemove] from the given entity.
 //
 // See also [ecs.World.Remove].
-func (m *Mutate7[A, B, C, D, E, F, G]) Remove(entity ecs.Entity) {
+func (m *Map7[A, B, C, D, E, F, G]) Remove(entity ecs.Entity) {
 	m.world.Remove(entity, m.ids...)
 }
 
 //////////////////////////////////////////////////////////////////////////
 
-// Mutate8 is a helper for mutating eight components.
-//
-// It can be used to create entities ([Mutate8.NewEntity] and [Mutate8.NewEntityWith]),
-// and to add or remove components ([Mutate8.Add], [Mutate8.Assign] and [Mutate8.Remove]).
-type Mutate8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
+// Map8 is a helper for mapping eight components.
+type Map8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
 	ids   []ecs.ID
 	world *ecs.World
 }
 
-// NewMutate8 creates a new Mutate8 object.
-func NewMutate8[A any, B any, C any, D any, E any, F any, G any, H any](w *ecs.World) Mutate8[A, B, C, D, E, F, G, H] {
-	return Mutate8[A, B, C, D, E, F, G, H]{
+// NewMap8 creates a new Map8 object.
+func NewMap8[A any, B any, C any, D any, E any, F any, G any, H any](w *ecs.World) Map8[A, B, C, D, E, F, G, H] {
+	return Map8[A, B, C, D, E, F, G, H]{
 		ids:   []ecs.ID{ecs.ComponentID[A](w), ecs.ComponentID[B](w), ecs.ComponentID[C](w), ecs.ComponentID[D](w), ecs.ComponentID[E](w), ecs.ComponentID[F](w), ecs.ComponentID[G](w), ecs.ComponentID[H](w)},
 		world: w,
 	}
 }
 
+// Get all the Map8's components for the given entity.
+//
+// See also [ecs.World.Get].
+func (m *Map8[A, B, C, D, E, F, G, H]) Get(entity ecs.Entity) (*A, *B, *C, *D, *E, *F, *G, *H) {
+	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5])), (*G)(m.world.Get(entity, m.ids[6])), (*H)(m.world.Get(entity, m.ids[7]))
+}
+
 // NewEntity creates a new [ecs.Entity] with the Mutate8's components.
 //
 // See also [ecs.World.NewEntity].
-func (m *Mutate8[A, B, C, D, E, F, G, H]) NewEntity() (ecs.Entity, *A, *B, *C, *D, *E, *F, *G, *H) {
+func (m *Map8[A, B, C, D, E, F, G, H]) NewEntity() (ecs.Entity, *A, *B, *C, *D, *E, *F, *G, *H) {
 	entity := m.world.NewEntity(m.ids...)
 	return entity, (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5])), (*G)(m.world.Get(entity, m.ids[6])), (*H)(m.world.Get(entity, m.ids[7]))
 }
 
-// NewEntityWith creates a new [ecs.Entity] with the Mutate8's components, using the supplied values.
+// NewEntityWith creates a new [ecs.Entity] with the Map8's components, using the supplied values.
 //
 // See also [ecs.World.NewEntityWith].
-func (m *Mutate8[A, B, C, D, E, F, G, H]) NewEntityWith(a *A, b *B, c *C, d *D, e *E, f *F, g *G, h *H) (ecs.Entity, *A, *B, *C, *D, *E, *F, *G, *H) {
+func (m *Map8[A, B, C, D, E, F, G, H]) NewEntityWith(a *A, b *B, c *C, d *D, e *E, f *F, g *G, h *H) (ecs.Entity, *A, *B, *C, *D, *E, *F, *G, *H) {
 	entity := m.world.NewEntityWith(
 		ecs.Component{ID: m.ids[0], Component: a},
 		ecs.Component{ID: m.ids[1], Component: b},
@@ -526,18 +558,18 @@ func (m *Mutate8[A, B, C, D, E, F, G, H]) NewEntityWith(a *A, b *B, c *C, d *D,
 	return entity, (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5])), (*G)(m.world.Get(entity, m.ids[6])), (*H)(m.world.Get(entity, m.ids[7]))
 }
 
-// Add the Mutate8's components to the given entity.
+// Add the Map8's components to the given entity.
 //
 // See also [ecs.World.Add].
-func (m *Mutate8[A, B, C, D, E, F, G, H]) Add(entity ecs.Entity) (*A, *B, *C, *D, *E, *F, *G, *H) {
+func (m *Map8[A, B, C, D, E, F, G, H]) Add(entity ecs.Entity) (*A, *B, *C, *D, *E, *F, *G, *H) {
 	m.world.Add(entity, m.ids...)
 	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5])), (*G)(m.world.Get(entity, m.ids[6])), (*H)(m.world.Get(entity, m.ids[7]))
 }
 
-// Assign the Mutate8's components to the given entity, using the supplied values.
+// Assign the Map8's components to the given entity, using the supplied values.
 //
 // See also [ecs.World.Assign] and [ecs.World.AssignN].
-func (m *Mutate8[A, B, C, D, E, F, G, H]) Assign(entity ecs.Entity, a *A, b *B, c *C, d *D, e *E, f *F, g *G, h *H) (*A, *B, *C, *D, *E, *F, *G, *H) {
+func (m *Map8[A, B, C, D, E, F, G, H]) Assign(entity ecs.Entity, a *A, b *B, c *C, d *D, e *E, f *F, g *G, h *H) (*A, *B, *C, *D, *E, *F, *G, *H) {
 	m.world.AssignN(entity,
 		ecs.Component{ID: m.ids[0], Component: a},
 		ecs.Component{ID: m.ids[1], Component: b},
@@ -551,9 +583,9 @@ func (m *Mutate8[A, B, C, D, E, F, G, H]) Assign(entity ecs.Entity, a *A, b *B,
 	return (*A)(m.world.Get(entity, m.ids[0])), (*B)(m.world.Get(entity, m.ids[1])), (*C)(m.world.Get(entity, m.ids[2])), (*D)(m.world.Get(entity, m.ids[3])), (*E)(m.world.Get(entity, m.ids[4])), (*F)(m.world.Get(entity, m.ids[5])), (*G)(m.world.Get(entity, m.ids[6])), (*H)(m.world.Get(entity, m.ids[7]))
 }
 
-// Remove the Mutate8's components from the given entity.
+// Remove the components set via [Map8.WithRemove] from the given entity.
 //
 // See also [ecs.World.Remove].
-func (m *Mutate8[A, B, C, D, E, F, G, H]) Remove(entity ecs.Entity) {
+func (m *Map8[A, B, C, D, E, F, G, H]) Remove(entity ecs.Entity) {
 	m.world.Remove(entity, m.ids...)
 }
diff --git a/generic/mask.go b/generic/mask.go
index 90f8d4e..e5bb3f8 100644
--- a/generic/mask.go
+++ b/generic/mask.go
@@ -2,57 +2,60 @@ package generic
 
 import "reflect"
 
-// Mask1 creates a component type list for one component type.
-func Mask1[A any]() []reflect.Type {
-	return []reflect.Type{typeOf[A]()}
+// Comp is an alias for component types.
+type Comp reflect.Type
+
+// T provides a component type from a generic type argument.
+func T[A any]() Comp {
+	return Comp(typeOf[A]())
 }
 
-// Mask2 creates a component type list for two component types.
-func Mask2[A any, B any]() []reflect.Type {
-	return []reflect.Type{typeOf[A](), typeOf[B]()}
+// T2 creates a component type list for two component types.
+func T2[A any, B any]() []Comp {
+	return []Comp{typeOf[A](), typeOf[B]()}
 }
 
-// Mask3 creates a component type list for three component types.
-func Mask3[A any, B any, C any]() []reflect.Type {
-	return []reflect.Type{
+// T3 creates a component type list for three component types.
+func T3[A any, B any, C any]() []Comp {
+	return []Comp{
 		typeOf[A](), typeOf[B](), typeOf[C](),
 	}
 }
 
-// Mask4 creates a component type list for four component types.
-func Mask4[A any, B any, C any, D any]() []reflect.Type {
-	return []reflect.Type{
+// T4 creates a component type list for four component types.
+func T4[A any, B any, C any, D any]() []Comp {
+	return []Comp{
 		typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](),
 	}
 }
 
-// Mask5 creates a component type list for five component types.
-func Mask5[A any, B any, C any, D any, E any]() []reflect.Type {
-	return []reflect.Type{
+// T5 creates a component type list for five component types.
+func T5[A any, B any, C any, D any, E any]() []Comp {
+	return []Comp{
 		typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](),
 		typeOf[E](),
 	}
 }
 
-// Mask6 creates a component type list for six component types.
-func Mask6[A any, B any, C any, D any, E any, F any]() []reflect.Type {
-	return []reflect.Type{
+// T6 creates a component type list for six component types.
+func T6[A any, B any, C any, D any, E any, F any]() []Comp {
+	return []Comp{
 		typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](),
 		typeOf[E](), typeOf[F](),
 	}
 }
 
-// Mask7 creates a component type list for seven component types.
-func Mask7[A any, B any, C any, D any, E any, F any, G any]() []reflect.Type {
-	return []reflect.Type{
+// T7 creates a component type list for seven component types.
+func T7[A any, B any, C any, D any, E any, F any, G any]() []Comp {
+	return []Comp{
 		typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](),
 		typeOf[E](), typeOf[F](), typeOf[G](),
 	}
 }
 
-// Mask8 creates a component type list for eight component types.
-func Mask8[A any, B any, C any, D any, E any, F any, G any, H any]() []reflect.Type {
-	return []reflect.Type{
+// T8 creates a component type list for eight component types.
+func T8[A any, B any, C any, D any, E any, F any, G any, H any]() []Comp {
+	return []Comp{
 		typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](),
 		typeOf[E](), typeOf[F](), typeOf[G](), typeOf[H](),
 	}
diff --git a/generic/mutate.go b/generic/mutate.go
new file mode 100644
index 0000000..936bb98
--- /dev/null
+++ b/generic/mutate.go
@@ -0,0 +1,65 @@
+package generic
+
+import "github.com/mlange-42/arche/ecs"
+
+// Mutate is a helper for mutating components.
+type Mutate struct {
+	add    []ecs.ID
+	remove []ecs.ID
+	world  *ecs.World
+}
+
+// NewMutate creates a new Mutate object.
+func NewMutate(w *ecs.World) *Mutate {
+	return &Mutate{
+		world: w,
+	}
+}
+
+// Adds sets components to add in calls to [Mutate.Add] and [Mutate.Exchange].
+//
+// Create the required mask items with [T].
+func (m *Mutate) Adds(add ...Comp) *Mutate {
+	m.add = toIds(m.world, add)
+	return m
+}
+
+// Removes sets components to remove in calls to [Mutate.Remove] and [Mutate.Exchange].
+//
+// Create the required mask items with [T].
+func (m *Mutate) Removes(remove ...Comp) *Mutate {
+	m.remove = toIds(m.world, remove)
+	return m
+}
+
+// NewEntity creates a new [ecs.Entity] with the components set via [Mutate.ToAdd].
+//
+// See also [ecs.World.NewEntity].
+func (m *Mutate) NewEntity() ecs.Entity {
+	entity := m.world.NewEntity(m.add...)
+	return entity
+}
+
+// Add the components set via [Mutate.Adds] to the given entity.
+//
+// See also [ecs.World.Add].
+func (m *Mutate) Add(entity ecs.Entity) {
+	m.world.Add(entity, m.add...)
+}
+
+// Remove the components set via [Mutate.Removes] from the given entity.
+//
+// See also [ecs.World.Remove].
+func (m *Mutate) Remove(entity ecs.Entity) {
+	m.world.Remove(entity, m.remove...)
+}
+
+// Exchange components on an entity.
+//
+// Removes the components set via [Mutate.Removes].
+// Adds the components set via [Mutate.Adds].
+//
+// See also [ecs.World.Exchange].
+func (m *Mutate) Exchange(entity ecs.Entity) {
+	m.world.Exchange(entity, m.add, m.remove)
+}
diff --git a/generic/query_generated.go b/generic/query_generated.go
index 8cbfda1..eb7cd8a 100644
--- a/generic/query_generated.go
+++ b/generic/query_generated.go
@@ -3,8 +3,6 @@ package generic
 // Code generated by go generate; DO NOT EDIT.
 
 import (
-	"reflect"
-
 	"github.com/mlange-42/arche/ecs"
 )
 
@@ -12,9 +10,9 @@ import (
 
 // Filter0 is a helper for building [Query0] query iterators.
 type Filter0 struct {
-	include  []reflect.Type
-	optional []reflect.Type
-	exclude  []reflect.Type
+	include  []Comp
+	optional []Comp
+	exclude  []Comp
 	compiled compiledQuery
 }
 
@@ -23,25 +21,14 @@ type Filter0 struct {
 // See also [ecs.World.Query].
 func NewFilter0() *Filter0 {
 	return &Filter0{
-		include: []reflect.Type{},
+		include: []Comp{},
 	}
 }
 
-// Optional makes some of the query's components optional.
-//
-// Create the required mask with [Mask1], [Mask2], etc.
-//
-// Only affects component types that were specified in the query.
-func (q *Filter0) Optional(mask []reflect.Type) *Filter0 {
-	q.optional = append(q.optional, mask...)
-	q.compiled.Reset()
-	return q
-}
-
 // With adds more required components that are not accessible using Get... methods.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter0) With(mask []reflect.Type) *Filter0 {
+// Create the required mask items with [T].
+func (q *Filter0) With(mask ...Comp) *Filter0 {
 	q.include = append(q.include, mask...)
 	q.compiled.Reset()
 	return q
@@ -49,8 +36,8 @@ func (q *Filter0) With(mask []reflect.Type) *Filter0 {
 
 // Without excludes entities with any of the given components from the query.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter0) Without(mask []reflect.Type) *Filter0 {
+// Create the required mask items with [T].
+func (q *Filter0) Without(mask ...Comp) *Filter0 {
 	q.exclude = append(q.exclude, mask...)
 	q.compiled.Reset()
 	return q
@@ -76,7 +63,7 @@ func (q *Filter0) Filter(w *ecs.World) ecs.MaskPair {
 
 // Query0 is a generic query iterator for zero components.
 //
-// Create one with [NewFilter0] and [Filter0.Query]
+// Create it with [NewFilter0] and [Filter0.Query]
 type Query0 struct {
 	ecs.Query
 	ids []ecs.ID
@@ -86,9 +73,9 @@ type Query0 struct {
 
 // Filter1 is a helper for building [Query1] query iterators.
 type Filter1[A any] struct {
-	include  []reflect.Type
-	optional []reflect.Type
-	exclude  []reflect.Type
+	include  []Comp
+	optional []Comp
+	exclude  []Comp
 	compiled compiledQuery
 }
 
@@ -97,16 +84,16 @@ type Filter1[A any] struct {
 // See also [ecs.World.Query].
 func NewFilter1[A any]() *Filter1[A] {
 	return &Filter1[A]{
-		include: []reflect.Type{typeOf[A]()},
+		include: []Comp{typeOf[A]()},
 	}
 }
 
 // Optional makes some of the query's components optional.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
+// Create the required mask items with [T].
 //
 // Only affects component types that were specified in the query.
-func (q *Filter1[A]) Optional(mask []reflect.Type) *Filter1[A] {
+func (q *Filter1[A]) Optional(mask ...Comp) *Filter1[A] {
 	q.optional = append(q.optional, mask...)
 	q.compiled.Reset()
 	return q
@@ -114,8 +101,8 @@ func (q *Filter1[A]) Optional(mask []reflect.Type) *Filter1[A] {
 
 // With adds more required components that are not accessible using Get... methods.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter1[A]) With(mask []reflect.Type) *Filter1[A] {
+// Create the required mask items with [T].
+func (q *Filter1[A]) With(mask ...Comp) *Filter1[A] {
 	q.include = append(q.include, mask...)
 	q.compiled.Reset()
 	return q
@@ -123,8 +110,8 @@ func (q *Filter1[A]) With(mask []reflect.Type) *Filter1[A] {
 
 // Without excludes entities with any of the given components from the query.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter1[A]) Without(mask []reflect.Type) *Filter1[A] {
+// Create the required mask items with [T].
+func (q *Filter1[A]) Without(mask ...Comp) *Filter1[A] {
 	q.exclude = append(q.exclude, mask...)
 	q.compiled.Reset()
 	return q
@@ -150,14 +137,14 @@ func (q *Filter1[A]) Filter(w *ecs.World) ecs.MaskPair {
 
 // Query1 is a generic query iterator for one components.
 //
-// Create one with [NewFilter1] and [Filter1.Query]
+// Create it with [NewFilter1] and [Filter1.Query]
 type Query1[A any] struct {
 	ecs.Query
 	ids []ecs.ID
 }
 
-// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
-func (q *Query1[A]) GetAll() (ecs.Entity, *A) {
+// Get returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query1[A]) Get() (ecs.Entity, *A) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0]))
 }
 
@@ -170,9 +157,9 @@ func (q *Query1[A]) Get1() *A {
 
 // Filter2 is a helper for building [Query2] query iterators.
 type Filter2[A any, B any] struct {
-	include  []reflect.Type
-	optional []reflect.Type
-	exclude  []reflect.Type
+	include  []Comp
+	optional []Comp
+	exclude  []Comp
 	compiled compiledQuery
 }
 
@@ -181,16 +168,16 @@ type Filter2[A any, B any] struct {
 // See also [ecs.World.Query].
 func NewFilter2[A any, B any]() *Filter2[A, B] {
 	return &Filter2[A, B]{
-		include: []reflect.Type{typeOf[A](), typeOf[B]()},
+		include: []Comp{typeOf[A](), typeOf[B]()},
 	}
 }
 
 // Optional makes some of the query's components optional.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
+// Create the required mask items with [T].
 //
 // Only affects component types that were specified in the query.
-func (q *Filter2[A, B]) Optional(mask []reflect.Type) *Filter2[A, B] {
+func (q *Filter2[A, B]) Optional(mask ...Comp) *Filter2[A, B] {
 	q.optional = append(q.optional, mask...)
 	q.compiled.Reset()
 	return q
@@ -198,8 +185,8 @@ func (q *Filter2[A, B]) Optional(mask []reflect.Type) *Filter2[A, B] {
 
 // With adds more required components that are not accessible using Get... methods.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter2[A, B]) With(mask []reflect.Type) *Filter2[A, B] {
+// Create the required mask items with [T].
+func (q *Filter2[A, B]) With(mask ...Comp) *Filter2[A, B] {
 	q.include = append(q.include, mask...)
 	q.compiled.Reset()
 	return q
@@ -207,8 +194,8 @@ func (q *Filter2[A, B]) With(mask []reflect.Type) *Filter2[A, B] {
 
 // Without excludes entities with any of the given components from the query.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter2[A, B]) Without(mask []reflect.Type) *Filter2[A, B] {
+// Create the required mask items with [T].
+func (q *Filter2[A, B]) Without(mask ...Comp) *Filter2[A, B] {
 	q.exclude = append(q.exclude, mask...)
 	q.compiled.Reset()
 	return q
@@ -234,14 +221,14 @@ func (q *Filter2[A, B]) Filter(w *ecs.World) ecs.MaskPair {
 
 // Query2 is a generic query iterator for two components.
 //
-// Create one with [NewFilter2] and [Filter2.Query]
+// Create it with [NewFilter2] and [Filter2.Query]
 type Query2[A any, B any] struct {
 	ecs.Query
 	ids []ecs.ID
 }
 
-// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
-func (q *Query2[A, B]) GetAll() (ecs.Entity, *A, *B) {
+// Get returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query2[A, B]) Get() (ecs.Entity, *A, *B) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1]))
 }
 
@@ -259,9 +246,9 @@ func (q *Query2[A, B]) Get2() *B {
 
 // Filter3 is a helper for building [Query3] query iterators.
 type Filter3[A any, B any, C any] struct {
-	include  []reflect.Type
-	optional []reflect.Type
-	exclude  []reflect.Type
+	include  []Comp
+	optional []Comp
+	exclude  []Comp
 	compiled compiledQuery
 }
 
@@ -270,16 +257,16 @@ type Filter3[A any, B any, C any] struct {
 // See also [ecs.World.Query].
 func NewFilter3[A any, B any, C any]() *Filter3[A, B, C] {
 	return &Filter3[A, B, C]{
-		include: []reflect.Type{typeOf[A](), typeOf[B](), typeOf[C]()},
+		include: []Comp{typeOf[A](), typeOf[B](), typeOf[C]()},
 	}
 }
 
 // Optional makes some of the query's components optional.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
+// Create the required mask items with [T].
 //
 // Only affects component types that were specified in the query.
-func (q *Filter3[A, B, C]) Optional(mask []reflect.Type) *Filter3[A, B, C] {
+func (q *Filter3[A, B, C]) Optional(mask ...Comp) *Filter3[A, B, C] {
 	q.optional = append(q.optional, mask...)
 	q.compiled.Reset()
 	return q
@@ -287,8 +274,8 @@ func (q *Filter3[A, B, C]) Optional(mask []reflect.Type) *Filter3[A, B, C] {
 
 // With adds more required components that are not accessible using Get... methods.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter3[A, B, C]) With(mask []reflect.Type) *Filter3[A, B, C] {
+// Create the required mask items with [T].
+func (q *Filter3[A, B, C]) With(mask ...Comp) *Filter3[A, B, C] {
 	q.include = append(q.include, mask...)
 	q.compiled.Reset()
 	return q
@@ -296,8 +283,8 @@ func (q *Filter3[A, B, C]) With(mask []reflect.Type) *Filter3[A, B, C] {
 
 // Without excludes entities with any of the given components from the query.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter3[A, B, C]) Without(mask []reflect.Type) *Filter3[A, B, C] {
+// Create the required mask items with [T].
+func (q *Filter3[A, B, C]) Without(mask ...Comp) *Filter3[A, B, C] {
 	q.exclude = append(q.exclude, mask...)
 	q.compiled.Reset()
 	return q
@@ -323,14 +310,14 @@ func (q *Filter3[A, B, C]) Filter(w *ecs.World) ecs.MaskPair {
 
 // Query3 is a generic query iterator for three components.
 //
-// Create one with [NewFilter3] and [Filter3.Query]
+// Create it with [NewFilter3] and [Filter3.Query]
 type Query3[A any, B any, C any] struct {
 	ecs.Query
 	ids []ecs.ID
 }
 
-// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
-func (q *Query3[A, B, C]) GetAll() (ecs.Entity, *A, *B, *C) {
+// Get returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query3[A, B, C]) Get() (ecs.Entity, *A, *B, *C) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2]))
 }
 
@@ -353,9 +340,9 @@ func (q *Query3[A, B, C]) Get3() *C {
 
 // Filter4 is a helper for building [Query4] query iterators.
 type Filter4[A any, B any, C any, D any] struct {
-	include  []reflect.Type
-	optional []reflect.Type
-	exclude  []reflect.Type
+	include  []Comp
+	optional []Comp
+	exclude  []Comp
 	compiled compiledQuery
 }
 
@@ -364,16 +351,16 @@ type Filter4[A any, B any, C any, D any] struct {
 // See also [ecs.World.Query].
 func NewFilter4[A any, B any, C any, D any]() *Filter4[A, B, C, D] {
 	return &Filter4[A, B, C, D]{
-		include: []reflect.Type{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D]()},
+		include: []Comp{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D]()},
 	}
 }
 
 // Optional makes some of the query's components optional.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
+// Create the required mask items with [T].
 //
 // Only affects component types that were specified in the query.
-func (q *Filter4[A, B, C, D]) Optional(mask []reflect.Type) *Filter4[A, B, C, D] {
+func (q *Filter4[A, B, C, D]) Optional(mask ...Comp) *Filter4[A, B, C, D] {
 	q.optional = append(q.optional, mask...)
 	q.compiled.Reset()
 	return q
@@ -381,8 +368,8 @@ func (q *Filter4[A, B, C, D]) Optional(mask []reflect.Type) *Filter4[A, B, C, D]
 
 // With adds more required components that are not accessible using Get... methods.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter4[A, B, C, D]) With(mask []reflect.Type) *Filter4[A, B, C, D] {
+// Create the required mask items with [T].
+func (q *Filter4[A, B, C, D]) With(mask ...Comp) *Filter4[A, B, C, D] {
 	q.include = append(q.include, mask...)
 	q.compiled.Reset()
 	return q
@@ -390,8 +377,8 @@ func (q *Filter4[A, B, C, D]) With(mask []reflect.Type) *Filter4[A, B, C, D] {
 
 // Without excludes entities with any of the given components from the query.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter4[A, B, C, D]) Without(mask []reflect.Type) *Filter4[A, B, C, D] {
+// Create the required mask items with [T].
+func (q *Filter4[A, B, C, D]) Without(mask ...Comp) *Filter4[A, B, C, D] {
 	q.exclude = append(q.exclude, mask...)
 	q.compiled.Reset()
 	return q
@@ -417,14 +404,14 @@ func (q *Filter4[A, B, C, D]) Filter(w *ecs.World) ecs.MaskPair {
 
 // Query4 is a generic query iterator for four components.
 //
-// Create one with [NewFilter4] and [Filter4.Query]
+// Create it with [NewFilter4] and [Filter4.Query]
 type Query4[A any, B any, C any, D any] struct {
 	ecs.Query
 	ids []ecs.ID
 }
 
-// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
-func (q *Query4[A, B, C, D]) GetAll() (ecs.Entity, *A, *B, *C, *D) {
+// Get returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query4[A, B, C, D]) Get() (ecs.Entity, *A, *B, *C, *D) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3]))
 }
 
@@ -452,9 +439,9 @@ func (q *Query4[A, B, C, D]) Get4() *D {
 
 // Filter5 is a helper for building [Query5] query iterators.
 type Filter5[A any, B any, C any, D any, E any] struct {
-	include  []reflect.Type
-	optional []reflect.Type
-	exclude  []reflect.Type
+	include  []Comp
+	optional []Comp
+	exclude  []Comp
 	compiled compiledQuery
 }
 
@@ -463,16 +450,16 @@ type Filter5[A any, B any, C any, D any, E any] struct {
 // See also [ecs.World.Query].
 func NewFilter5[A any, B any, C any, D any, E any]() *Filter5[A, B, C, D, E] {
 	return &Filter5[A, B, C, D, E]{
-		include: []reflect.Type{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](), typeOf[E]()},
+		include: []Comp{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](), typeOf[E]()},
 	}
 }
 
 // Optional makes some of the query's components optional.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
+// Create the required mask items with [T].
 //
 // Only affects component types that were specified in the query.
-func (q *Filter5[A, B, C, D, E]) Optional(mask []reflect.Type) *Filter5[A, B, C, D, E] {
+func (q *Filter5[A, B, C, D, E]) Optional(mask ...Comp) *Filter5[A, B, C, D, E] {
 	q.optional = append(q.optional, mask...)
 	q.compiled.Reset()
 	return q
@@ -480,8 +467,8 @@ func (q *Filter5[A, B, C, D, E]) Optional(mask []reflect.Type) *Filter5[A, B, C,
 
 // With adds more required components that are not accessible using Get... methods.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter5[A, B, C, D, E]) With(mask []reflect.Type) *Filter5[A, B, C, D, E] {
+// Create the required mask items with [T].
+func (q *Filter5[A, B, C, D, E]) With(mask ...Comp) *Filter5[A, B, C, D, E] {
 	q.include = append(q.include, mask...)
 	q.compiled.Reset()
 	return q
@@ -489,8 +476,8 @@ func (q *Filter5[A, B, C, D, E]) With(mask []reflect.Type) *Filter5[A, B, C, D,
 
 // Without excludes entities with any of the given components from the query.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter5[A, B, C, D, E]) Without(mask []reflect.Type) *Filter5[A, B, C, D, E] {
+// Create the required mask items with [T].
+func (q *Filter5[A, B, C, D, E]) Without(mask ...Comp) *Filter5[A, B, C, D, E] {
 	q.exclude = append(q.exclude, mask...)
 	q.compiled.Reset()
 	return q
@@ -516,14 +503,14 @@ func (q *Filter5[A, B, C, D, E]) Filter(w *ecs.World) ecs.MaskPair {
 
 // Query5 is a generic query iterator for five components.
 //
-// Create one with [NewFilter5] and [Filter5.Query]
+// Create it with [NewFilter5] and [Filter5.Query]
 type Query5[A any, B any, C any, D any, E any] struct {
 	ecs.Query
 	ids []ecs.ID
 }
 
-// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
-func (q *Query5[A, B, C, D, E]) GetAll() (ecs.Entity, *A, *B, *C, *D, *E) {
+// Get returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query5[A, B, C, D, E]) Get() (ecs.Entity, *A, *B, *C, *D, *E) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4]))
 }
 
@@ -556,9 +543,9 @@ func (q *Query5[A, B, C, D, E]) Get5() *E {
 
 // Filter6 is a helper for building [Query6] query iterators.
 type Filter6[A any, B any, C any, D any, E any, F any] struct {
-	include  []reflect.Type
-	optional []reflect.Type
-	exclude  []reflect.Type
+	include  []Comp
+	optional []Comp
+	exclude  []Comp
 	compiled compiledQuery
 }
 
@@ -567,16 +554,16 @@ type Filter6[A any, B any, C any, D any, E any, F any] struct {
 // See also [ecs.World.Query].
 func NewFilter6[A any, B any, C any, D any, E any, F any]() *Filter6[A, B, C, D, E, F] {
 	return &Filter6[A, B, C, D, E, F]{
-		include: []reflect.Type{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](), typeOf[E](), typeOf[F]()},
+		include: []Comp{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](), typeOf[E](), typeOf[F]()},
 	}
 }
 
 // Optional makes some of the query's components optional.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
+// Create the required mask items with [T].
 //
 // Only affects component types that were specified in the query.
-func (q *Filter6[A, B, C, D, E, F]) Optional(mask []reflect.Type) *Filter6[A, B, C, D, E, F] {
+func (q *Filter6[A, B, C, D, E, F]) Optional(mask ...Comp) *Filter6[A, B, C, D, E, F] {
 	q.optional = append(q.optional, mask...)
 	q.compiled.Reset()
 	return q
@@ -584,8 +571,8 @@ func (q *Filter6[A, B, C, D, E, F]) Optional(mask []reflect.Type) *Filter6[A, B,
 
 // With adds more required components that are not accessible using Get... methods.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter6[A, B, C, D, E, F]) With(mask []reflect.Type) *Filter6[A, B, C, D, E, F] {
+// Create the required mask items with [T].
+func (q *Filter6[A, B, C, D, E, F]) With(mask ...Comp) *Filter6[A, B, C, D, E, F] {
 	q.include = append(q.include, mask...)
 	q.compiled.Reset()
 	return q
@@ -593,8 +580,8 @@ func (q *Filter6[A, B, C, D, E, F]) With(mask []reflect.Type) *Filter6[A, B, C,
 
 // Without excludes entities with any of the given components from the query.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter6[A, B, C, D, E, F]) Without(mask []reflect.Type) *Filter6[A, B, C, D, E, F] {
+// Create the required mask items with [T].
+func (q *Filter6[A, B, C, D, E, F]) Without(mask ...Comp) *Filter6[A, B, C, D, E, F] {
 	q.exclude = append(q.exclude, mask...)
 	q.compiled.Reset()
 	return q
@@ -620,14 +607,14 @@ func (q *Filter6[A, B, C, D, E, F]) Filter(w *ecs.World) ecs.MaskPair {
 
 // Query6 is a generic query iterator for six components.
 //
-// Create one with [NewFilter6] and [Filter6.Query]
+// Create it with [NewFilter6] and [Filter6.Query]
 type Query6[A any, B any, C any, D any, E any, F any] struct {
 	ecs.Query
 	ids []ecs.ID
 }
 
-// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
-func (q *Query6[A, B, C, D, E, F]) GetAll() (ecs.Entity, *A, *B, *C, *D, *E, *F) {
+// Get returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query6[A, B, C, D, E, F]) Get() (ecs.Entity, *A, *B, *C, *D, *E, *F) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4])), (*F)(q.Query.Get(q.ids[5]))
 }
 
@@ -665,9 +652,9 @@ func (q *Query6[A, B, C, D, E, F]) Get6() *F {
 
 // Filter7 is a helper for building [Query7] query iterators.
 type Filter7[A any, B any, C any, D any, E any, F any, G any] struct {
-	include  []reflect.Type
-	optional []reflect.Type
-	exclude  []reflect.Type
+	include  []Comp
+	optional []Comp
+	exclude  []Comp
 	compiled compiledQuery
 }
 
@@ -676,16 +663,16 @@ type Filter7[A any, B any, C any, D any, E any, F any, G any] struct {
 // See also [ecs.World.Query].
 func NewFilter7[A any, B any, C any, D any, E any, F any, G any]() *Filter7[A, B, C, D, E, F, G] {
 	return &Filter7[A, B, C, D, E, F, G]{
-		include: []reflect.Type{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](), typeOf[E](), typeOf[F](), typeOf[G]()},
+		include: []Comp{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](), typeOf[E](), typeOf[F](), typeOf[G]()},
 	}
 }
 
 // Optional makes some of the query's components optional.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
+// Create the required mask items with [T].
 //
 // Only affects component types that were specified in the query.
-func (q *Filter7[A, B, C, D, E, F, G]) Optional(mask []reflect.Type) *Filter7[A, B, C, D, E, F, G] {
+func (q *Filter7[A, B, C, D, E, F, G]) Optional(mask ...Comp) *Filter7[A, B, C, D, E, F, G] {
 	q.optional = append(q.optional, mask...)
 	q.compiled.Reset()
 	return q
@@ -693,8 +680,8 @@ func (q *Filter7[A, B, C, D, E, F, G]) Optional(mask []reflect.Type) *Filter7[A,
 
 // With adds more required components that are not accessible using Get... methods.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter7[A, B, C, D, E, F, G]) With(mask []reflect.Type) *Filter7[A, B, C, D, E, F, G] {
+// Create the required mask items with [T].
+func (q *Filter7[A, B, C, D, E, F, G]) With(mask ...Comp) *Filter7[A, B, C, D, E, F, G] {
 	q.include = append(q.include, mask...)
 	q.compiled.Reset()
 	return q
@@ -702,8 +689,8 @@ func (q *Filter7[A, B, C, D, E, F, G]) With(mask []reflect.Type) *Filter7[A, B,
 
 // Without excludes entities with any of the given components from the query.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter7[A, B, C, D, E, F, G]) Without(mask []reflect.Type) *Filter7[A, B, C, D, E, F, G] {
+// Create the required mask items with [T].
+func (q *Filter7[A, B, C, D, E, F, G]) Without(mask ...Comp) *Filter7[A, B, C, D, E, F, G] {
 	q.exclude = append(q.exclude, mask...)
 	q.compiled.Reset()
 	return q
@@ -729,14 +716,14 @@ func (q *Filter7[A, B, C, D, E, F, G]) Filter(w *ecs.World) ecs.MaskPair {
 
 // Query7 is a generic query iterator for seven components.
 //
-// Create one with [NewFilter7] and [Filter7.Query]
+// Create it with [NewFilter7] and [Filter7.Query]
 type Query7[A any, B any, C any, D any, E any, F any, G any] struct {
 	ecs.Query
 	ids []ecs.ID
 }
 
-// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
-func (q *Query7[A, B, C, D, E, F, G]) GetAll() (ecs.Entity, *A, *B, *C, *D, *E, *F, *G) {
+// Get returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query7[A, B, C, D, E, F, G]) Get() (ecs.Entity, *A, *B, *C, *D, *E, *F, *G) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4])), (*F)(q.Query.Get(q.ids[5])), (*G)(q.Query.Get(q.ids[6]))
 }
 
@@ -779,9 +766,9 @@ func (q *Query7[A, B, C, D, E, F, G]) Get7() *G {
 
 // Filter8 is a helper for building [Query8] query iterators.
 type Filter8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
-	include  []reflect.Type
-	optional []reflect.Type
-	exclude  []reflect.Type
+	include  []Comp
+	optional []Comp
+	exclude  []Comp
 	compiled compiledQuery
 }
 
@@ -790,16 +777,16 @@ type Filter8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
 // See also [ecs.World.Query].
 func NewFilter8[A any, B any, C any, D any, E any, F any, G any, H any]() *Filter8[A, B, C, D, E, F, G, H] {
 	return &Filter8[A, B, C, D, E, F, G, H]{
-		include: []reflect.Type{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](), typeOf[E](), typeOf[F](), typeOf[G](), typeOf[H]()},
+		include: []Comp{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](), typeOf[E](), typeOf[F](), typeOf[G](), typeOf[H]()},
 	}
 }
 
 // Optional makes some of the query's components optional.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
+// Create the required mask items with [T].
 //
 // Only affects component types that were specified in the query.
-func (q *Filter8[A, B, C, D, E, F, G, H]) Optional(mask []reflect.Type) *Filter8[A, B, C, D, E, F, G, H] {
+func (q *Filter8[A, B, C, D, E, F, G, H]) Optional(mask ...Comp) *Filter8[A, B, C, D, E, F, G, H] {
 	q.optional = append(q.optional, mask...)
 	q.compiled.Reset()
 	return q
@@ -807,8 +794,8 @@ func (q *Filter8[A, B, C, D, E, F, G, H]) Optional(mask []reflect.Type) *Filter8
 
 // With adds more required components that are not accessible using Get... methods.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter8[A, B, C, D, E, F, G, H]) With(mask []reflect.Type) *Filter8[A, B, C, D, E, F, G, H] {
+// Create the required mask items with [T].
+func (q *Filter8[A, B, C, D, E, F, G, H]) With(mask ...Comp) *Filter8[A, B, C, D, E, F, G, H] {
 	q.include = append(q.include, mask...)
 	q.compiled.Reset()
 	return q
@@ -816,8 +803,8 @@ func (q *Filter8[A, B, C, D, E, F, G, H]) With(mask []reflect.Type) *Filter8[A,
 
 // Without excludes entities with any of the given components from the query.
 //
-// Create the required mask with [Mask1], [Mask2], etc.
-func (q *Filter8[A, B, C, D, E, F, G, H]) Without(mask []reflect.Type) *Filter8[A, B, C, D, E, F, G, H] {
+// Create the required mask items with [T].
+func (q *Filter8[A, B, C, D, E, F, G, H]) Without(mask ...Comp) *Filter8[A, B, C, D, E, F, G, H] {
 	q.exclude = append(q.exclude, mask...)
 	q.compiled.Reset()
 	return q
@@ -843,14 +830,14 @@ func (q *Filter8[A, B, C, D, E, F, G, H]) Filter(w *ecs.World) ecs.MaskPair {
 
 // Query8 is a generic query iterator for eight components.
 //
-// Create one with [NewFilter8] and [Filter8.Query]
+// Create it with [NewFilter8] and [Filter8.Query]
 type Query8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
 	ecs.Query
 	ids []ecs.ID
 }
 
-// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
-func (q *Query8[A, B, C, D, E, F, G, H]) GetAll() (ecs.Entity, *A, *B, *C, *D, *E, *F, *G, *H) {
+// Get returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query8[A, B, C, D, E, F, G, H]) Get() (ecs.Entity, *A, *B, *C, *D, *E, *F, *G, *H) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4])), (*F)(q.Query.Get(q.ids[5])), (*G)(q.Query.Get(q.ids[6])), (*H)(q.Query.Get(q.ids[7]))
 }
 
diff --git a/generic/util.go b/generic/util.go
index ca7368d..84a61fb 100644
--- a/generic/util.go
+++ b/generic/util.go
@@ -6,11 +6,11 @@ import (
 	"github.com/mlange-42/arche/ecs"
 )
 
-func typeOf[T any]() reflect.Type {
+func typeOf[T any]() Comp {
 	return reflect.TypeOf((*T)(nil)).Elem()
 }
 
-func toIds(w *ecs.World, types []reflect.Type) []ecs.ID {
+func toIds(w *ecs.World, types []Comp) []ecs.ID {
 	ids := make([]ecs.ID, len(types))
 	for i, t := range types {
 		ids[i] = ecs.TypeID(w, t)
@@ -18,7 +18,7 @@ func toIds(w *ecs.World, types []reflect.Type) []ecs.ID {
 	return ids
 }
 
-func toMask(w *ecs.World, types []reflect.Type) ecs.Mask {
+func toMask(w *ecs.World, types []Comp) ecs.Mask {
 	mask := ecs.BitMask{}
 	for _, t := range types {
 		mask.Set(ecs.TypeID(w, t), true)
@@ -26,7 +26,7 @@ func toMask(w *ecs.World, types []reflect.Type) ecs.Mask {
 	return ecs.Mask{BitMask: mask}
 }
 
-func toMaskOptional(w *ecs.World, include []ecs.ID, optional []reflect.Type) ecs.Mask {
+func toMaskOptional(w *ecs.World, include []ecs.ID, optional []Comp) ecs.Mask {
 	mask := ecs.NewBitMask(include...)
 	for _, t := range optional {
 		mask.Set(ecs.TypeID(w, t), false)


Test patch:
diff --git a/benchmark/add/arche_test.go b/benchmark/add/arche_test.go
index ac1f948..72f6b61 100644
--- a/benchmark/add/arche_test.go
+++ b/benchmark/add/arche_test.go
@@ -26,7 +26,7 @@ func addArcheGeneric(b *testing.B, count int) {
 	for i := 0; i < b.N; i++ {
 		b.StopTimer()
 		world := ecs.NewWorld()
-		mut := generic.NewMutate2[position, rotation](&world)
+		mut := generic.NewMap2[position, rotation](&world)
 		b.StartTimer()
 
 		for i := 0; i < count; i++ {
diff --git a/ecs/world_test.go b/ecs/world_test.go
index 6ee2a81..1a61f9d 100644
--- a/ecs/world_test.go
+++ b/ecs/world_test.go
@@ -19,7 +19,7 @@ func TestWorldEntites(t *testing.T) {
 	assert.Equal(t, 0, int(w.entities[1].index))
 	assert.Equal(t, 1, int(w.entities[2].index))
 	assert.Equal(t, 2, int(w.entities[3].index))
-	w.RemEntity(newEntityGen(2, 0))
+	w.RemoveEntity(newEntityGen(2, 0))
 	assert.False(t, w.Alive(newEntityGen(2, 0)))
 
 	assert.Equal(t, 0, int(w.entities[1].index))
@@ -31,13 +31,13 @@ func TestWorldEntites(t *testing.T) {
 
 	assert.Equal(t, 2, int(w.entities[2].index))
 
-	w.RemEntity(newEntityGen(3, 0))
-	w.RemEntity(newEntityGen(2, 1))
-	w.RemEntity(newEntityGen(1, 0))
+	w.RemoveEntity(newEntityGen(3, 0))
+	w.RemoveEntity(newEntityGen(2, 1))
+	w.RemoveEntity(newEntityGen(1, 0))
 
-	assert.Panics(t, func() { w.RemEntity(newEntityGen(3, 0)) })
-	assert.Panics(t, func() { w.RemEntity(newEntityGen(2, 1)) })
-	assert.Panics(t, func() { w.RemEntity(newEntityGen(1, 0)) })
+	assert.Panics(t, func() { w.RemoveEntity(newEntityGen(3, 0)) })
+	assert.Panics(t, func() { w.RemoveEntity(newEntityGen(2, 1)) })
+	assert.Panics(t, func() { w.RemoveEntity(newEntityGen(1, 0)) })
 }
 
 func TestWorldNewEntites(t *testing.T) {
@@ -69,10 +69,10 @@ func TestWorldNewEntites(t *testing.T) {
 	assert.Equal(t, &velocity{3, 4}, vel)
 	assert.Equal(t, &rotation{5}, rot)
 
-	w.RemEntity(e0)
-	w.RemEntity(e1)
-	w.RemEntity(e2)
-	w.RemEntity(e3)
+	w.RemoveEntity(e0)
+	w.RemoveEntity(e1)
+	w.RemoveEntity(e2)
+	w.RemoveEntity(e3)
 
 	for i := 0; i < 35; i++ {
 		e := w.NewEntityWith(
@@ -156,7 +156,7 @@ func TestWorldComponents(t *testing.T) {
 	w.Add(e0)
 	w.Remove(e0)
 
-	w.RemEntity(e0)
+	w.RemoveEntity(e0)
 	assert.Panics(t, func() { w.Has(newEntityGen(1, 0), posID) })
 	assert.Panics(t, func() { w.Get(newEntityGen(1, 0), posID) })
 }
@@ -298,7 +298,7 @@ func TestWorldGetComponents(t *testing.T) {
 	assert.Equal(t, &position{}, pos0)
 	assert.Equal(t, &position{100, 101}, pos1)
 
-	w.RemEntity(e0)
+	w.RemoveEntity(e0)
 
 	pos1 = (*position)(w.Get(e1, posID))
 	assert.Equal(t, &position{100, 101}, pos1)
@@ -366,7 +366,7 @@ func TestWorldLock(t *testing.T) {
 	query1 = world.Query(All(posID))
 
 	assert.Panics(t, func() { world.NewEntity() })
-	assert.Panics(t, func() { world.RemEntity(entity) })
+	assert.Panics(t, func() { world.RemoveEntity(entity) })
 	assert.Panics(t, func() { world.Add(entity, rotID) })
 	assert.Panics(t, func() { world.Remove(entity, posID) })
 }
@@ -441,7 +441,7 @@ func TestWorldListener(t *testing.T) {
 		Entity: e0, AddedRemoved: 1,
 	}, events[len(events)-1])
 
-	w.RemEntity(e0)
+	w.RemoveEntity(e0)
 	assert.Equal(t, 2, len(events))
 	assert.Equal(t, ChangeEvent{
 		Entity: e0, AddedRemoved: -1,
@@ -457,7 +457,7 @@ func TestWorldListener(t *testing.T) {
 		AddedRemoved: 1,
 	}, events[len(events)-1])
 
-	w.RemEntity(e0)
+	w.RemoveEntity(e0)
 	assert.Equal(t, 4, len(events))
 	assert.Equal(t, ChangeEvent{
 		Entity:       e0,
diff --git a/generic/map_generated_test.go b/generic/map_generated_test.go
new file mode 100644
index 0000000..251feeb
--- /dev/null
+++ b/generic/map_generated_test.go
@@ -0,0 +1,321 @@
+package generic
+
+import (
+	"testing"
+
+	"github.com/mlange-42/arche/ecs"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestMap1Generated(t *testing.T) {
+	w := ecs.NewWorld()
+	registerAll(&w)
+
+	mut := NewMap1[testStruct0](&w)
+	map0 := NewMap[testStruct0](&w)
+
+	e, s0 := mut.NewEntity()
+	assert.NotNil(t, s0)
+
+	mut.Remove(e)
+	assert.False(t, map0.Has(e))
+
+	s0 = mut.Add(e)
+	assert.NotNil(t, s0)
+
+	e = w.NewEntity()
+	_ = mut.Assign(e, &testStruct0{})
+	assert.True(t, map0.Has(e))
+
+	e, _ = mut.NewEntityWith(&testStruct0{})
+	assert.True(t, map0.Has(e))
+
+	s0 = mut.Get(e)
+	assert.NotNil(t, s0)
+}
+
+func TestMap2Generated(t *testing.T) {
+	w := ecs.NewWorld()
+	registerAll(&w)
+
+	mut := NewMap2[testStruct0, testStruct1](&w)
+	map0 := NewMap[testStruct0](&w)
+	map1 := NewMap[testStruct1](&w)
+
+	e, s0, s1 := mut.NewEntity()
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+
+	mut.Remove(e)
+	assert.False(t, map0.Has(e))
+	assert.False(t, map1.Has(e))
+
+	s0, s1 = mut.Add(e)
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+
+	e = w.NewEntity()
+	_, _ = mut.Assign(e, &testStruct0{}, &testStruct1{})
+	assert.True(t, map0.Has(e))
+	assert.True(t, map1.Has(e))
+
+	e, _, _ = mut.NewEntityWith(&testStruct0{}, &testStruct1{})
+	assert.True(t, map0.Has(e))
+	assert.True(t, map1.Has(e))
+
+	s0, s1 = mut.Get(e)
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+}
+
+func TestMap3Generated(t *testing.T) {
+	w := ecs.NewWorld()
+	registerAll(&w)
+
+	mut := NewMap3[
+		testStruct0, testStruct1, testStruct2,
+	](&w)
+	map0 := NewMap[testStruct0](&w)
+	map1 := NewMap[testStruct1](&w)
+
+	e, s0, s1, _ := mut.NewEntity()
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+
+	mut.Remove(e)
+	assert.False(t, map0.Has(e))
+	assert.False(t, map1.Has(e))
+
+	s0, s1, _ = mut.Add(e)
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+
+	e = w.NewEntity()
+	_, _, _ = mut.Assign(e,
+		&testStruct0{}, &testStruct1{}, &testStruct2{},
+	)
+	assert.True(t, map0.Has(e))
+	assert.True(t, map1.Has(e))
+
+	e, _, _, _ = mut.NewEntityWith(
+		&testStruct0{}, &testStruct1{}, &testStruct2{},
+	)
+	assert.True(t, map0.Has(e))
+	assert.True(t, map1.Has(e))
+
+	s0, s1, _ = mut.Get(e)
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+}
+
+func TestMap4Generated(t *testing.T) {
+	w := ecs.NewWorld()
+	registerAll(&w)
+
+	mut := NewMap4[
+		testStruct0, testStruct1, testStruct2, testStruct3,
+	](&w)
+	map0 := NewMap[testStruct0](&w)
+	map1 := NewMap[testStruct1](&w)
+
+	e, s0, s1, _, _ := mut.NewEntity()
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+
+	mut.Remove(e)
+	assert.False(t, map0.Has(e))
+	assert.False(t, map1.Has(e))
+
+	s0, s1, _, _ = mut.Add(e)
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+
+	e = w.NewEntity()
+	_, _, _, _ = mut.Assign(e,
+		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
+	)
+	assert.True(t, map0.Has(e))
+	assert.True(t, map1.Has(e))
+
+	e, _, _, _, _ = mut.NewEntityWith(
+		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
+	)
+	assert.True(t, map0.Has(e))
+	assert.True(t, map1.Has(e))
+
+	s0, s1, _, _ = mut.Get(e)
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+}
+
+func TestMap5Generated(t *testing.T) {
+	w := ecs.NewWorld()
+	registerAll(&w)
+
+	mut := NewMap5[
+		testStruct0, testStruct1, testStruct2, testStruct3,
+		testStruct4,
+	](&w)
+	map0 := NewMap[testStruct0](&w)
+	map1 := NewMap[testStruct1](&w)
+
+	e, s0, s1, _, _, _ := mut.NewEntity()
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+
+	mut.Remove(e)
+	assert.False(t, map0.Has(e))
+	assert.False(t, map1.Has(e))
+
+	s0, s1, _, _, _ = mut.Add(e)
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+
+	e = w.NewEntity()
+	_, _, _, _, _ = mut.Assign(e,
+		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
+		&testStruct4{},
+	)
+	assert.True(t, map0.Has(e))
+	assert.True(t, map1.Has(e))
+
+	e, _, _, _, _, _ = mut.NewEntityWith(
+		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
+		&testStruct4{},
+	)
+	assert.True(t, map0.Has(e))
+	assert.True(t, map1.Has(e))
+
+	s0, s1, _, _, _ = mut.Get(e)
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+}
+
+func TestMap6Generated(t *testing.T) {
+	w := ecs.NewWorld()
+	registerAll(&w)
+
+	mut := NewMap6[
+		testStruct0, testStruct1, testStruct2, testStruct3,
+		testStruct4, testStruct5,
+	](&w)
+	map0 := NewMap[testStruct0](&w)
+	map1 := NewMap[testStruct1](&w)
+
+	e, s0, s1, _, _, _, _ := mut.NewEntity()
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+
+	mut.Remove(e)
+	assert.False(t, map0.Has(e))
+	assert.False(t, map1.Has(e))
+
+	s0, s1, _, _, _, _ = mut.Add(e)
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+
+	e = w.NewEntity()
+	_, _, _, _, _, _ = mut.Assign(e,
+		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
+		&testStruct4{}, &testStruct5{},
+	)
+	assert.True(t, map0.Has(e))
+	assert.True(t, map1.Has(e))
+
+	e, _, _, _, _, _, _ = mut.NewEntityWith(
+		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
+		&testStruct4{}, &testStruct5{},
+	)
+	assert.True(t, map0.Has(e))
+	assert.True(t, map1.Has(e))
+
+	s0, s1, _, _, _, _ = mut.Get(e)
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+}
+
+func TestMap7Generated(t *testing.T) {
+	w := ecs.NewWorld()
+	registerAll(&w)
+
+	mut := NewMap7[
+		testStruct0, testStruct1, testStruct2, testStruct3,
+		testStruct4, testStruct5, testStruct6,
+	](&w)
+	map0 := NewMap[testStruct0](&w)
+	map1 := NewMap[testStruct1](&w)
+
+	e, s0, s1, _, _, _, _, _ := mut.NewEntity()
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+
+	mut.Remove(e)
+	assert.False(t, map0.Has(e))
+	assert.False(t, map1.Has(e))
+
+	s0, s1, _, _, _, _, _ = mut.Add(e)
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+
+	e = w.NewEntity()
+	_, _, _, _, _, _, _ = mut.Assign(e,
+		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
+		&testStruct4{}, &testStruct5{}, &testStruct6{},
+	)
+	assert.True(t, map0.Has(e))
+	assert.True(t, map1.Has(e))
+
+	e, _, _, _, _, _, _, _ = mut.NewEntityWith(
+		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
+		&testStruct4{}, &testStruct5{}, &testStruct6{},
+	)
+	assert.True(t, map0.Has(e))
+	assert.True(t, map1.Has(e))
+
+	s0, s1, _, _, _, _, _ = mut.Get(e)
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+}
+
+func TestMap8Generated(t *testing.T) {
+	w := ecs.NewWorld()
+	registerAll(&w)
+
+	mut := NewMap8[
+		testStruct0, testStruct1, testStruct2, testStruct3,
+		testStruct4, testStruct5, testStruct6, testStruct7,
+	](&w)
+	map0 := NewMap[testStruct0](&w)
+	map1 := NewMap[testStruct1](&w)
+
+	e, s0, s1, _, _, _, _, _, _ := mut.NewEntity()
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+
+	mut.Remove(e)
+	assert.False(t, map0.Has(e))
+	assert.False(t, map1.Has(e))
+
+	s0, s1, _, _, _, _, _, _ = mut.Add(e)
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+
+	e = w.NewEntity()
+	_, _, _, _, _, _, _, _ = mut.Assign(e,
+		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
+		&testStruct4{}, &testStruct5{}, &testStruct6{}, &testStruct7{},
+	)
+	assert.True(t, map0.Has(e))
+	assert.True(t, map1.Has(e))
+
+	e, _, _, _, _, _, _, _, _ = mut.NewEntityWith(
+		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
+		&testStruct4{}, &testStruct5{}, &testStruct6{}, &testStruct7{},
+	)
+	assert.True(t, map0.Has(e))
+	assert.True(t, map1.Has(e))
+
+	s0, s1, _, _, _, _, _, _ = mut.Get(e)
+	assert.NotNil(t, s0)
+	assert.NotNil(t, s1)
+}
diff --git a/generic/map_test.go b/generic/map_test.go
index d3a18b1..c7fcc8c 100644
--- a/generic/map_test.go
+++ b/generic/map_test.go
@@ -10,7 +10,7 @@ import (
 func TestGenericMap(t *testing.T) {
 	w := ecs.NewWorld()
 	get := NewMap[testStruct0](&w)
-	mut := NewMutate1[testStruct0](&w)
+	mut := NewMutate(&w).Adds(T[testStruct0]())
 
 	assert.Equal(t, ecs.ComponentID[testStruct0](&w), get.ID())
 
diff --git a/generic/mask_test.go b/generic/mask_test.go
index 6761de2..77f58d8 100644
--- a/generic/mask_test.go
+++ b/generic/mask_test.go
@@ -1,7 +1,6 @@
 package generic
 
 import (
-	"reflect"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -9,23 +8,21 @@ import (
 
 func TestGenericMask(t *testing.T) {
 	assert.Equal(t,
-		Mask1[testStruct0](),
-		[]reflect.Type{
-			typeOf[testStruct0](),
-		},
+		T[testStruct0](),
+		Comp(typeOf[testStruct0]()),
 	)
 
 	assert.Equal(t,
-		Mask2[testStruct0, testStruct1](),
-		[]reflect.Type{
+		T2[testStruct0, testStruct1](),
+		[]Comp{
 			typeOf[testStruct0](),
 			typeOf[testStruct1](),
 		},
 	)
 
 	assert.Equal(t,
-		Mask3[testStruct0, testStruct1, testStruct2](),
-		[]reflect.Type{
+		T3[testStruct0, testStruct1, testStruct2](),
+		[]Comp{
 			typeOf[testStruct0](),
 			typeOf[testStruct1](),
 			typeOf[testStruct2](),
@@ -33,8 +30,8 @@ func TestGenericMask(t *testing.T) {
 	)
 
 	assert.Equal(t,
-		Mask4[testStruct0, testStruct1, testStruct2, testStruct3](),
-		[]reflect.Type{
+		T4[testStruct0, testStruct1, testStruct2, testStruct3](),
+		[]Comp{
 			typeOf[testStruct0](),
 			typeOf[testStruct1](),
 			typeOf[testStruct2](),
@@ -43,9 +40,9 @@ func TestGenericMask(t *testing.T) {
 	)
 
 	assert.Equal(t,
-		Mask5[testStruct0, testStruct1, testStruct2, testStruct3,
+		T5[testStruct0, testStruct1, testStruct2, testStruct3,
 			testStruct4](),
-		[]reflect.Type{
+		[]Comp{
 			typeOf[testStruct0](),
 			typeOf[testStruct1](),
 			typeOf[testStruct2](),
@@ -55,9 +52,9 @@ func TestGenericMask(t *testing.T) {
 	)
 
 	assert.Equal(t,
-		Mask6[testStruct0, testStruct1, testStruct2, testStruct3,
+		T6[testStruct0, testStruct1, testStruct2, testStruct3,
 			testStruct4, testStruct5](),
-		[]reflect.Type{
+		[]Comp{
 			typeOf[testStruct0](),
 			typeOf[testStruct1](),
 			typeOf[testStruct2](),
@@ -68,9 +65,9 @@ func TestGenericMask(t *testing.T) {
 	)
 
 	assert.Equal(t,
-		Mask7[testStruct0, testStruct1, testStruct2, testStruct3,
+		T7[testStruct0, testStruct1, testStruct2, testStruct3,
 			testStruct4, testStruct5, testStruct6](),
-		[]reflect.Type{
+		[]Comp{
 			typeOf[testStruct0](),
 			typeOf[testStruct1](),
 			typeOf[testStruct2](),
@@ -82,9 +79,9 @@ func TestGenericMask(t *testing.T) {
 	)
 
 	assert.Equal(t,
-		Mask8[testStruct0, testStruct1, testStruct2, testStruct3,
+		T8[testStruct0, testStruct1, testStruct2, testStruct3,
 			testStruct4, testStruct5, testStruct6, testStruct7](),
-		[]reflect.Type{
+		[]Comp{
 			typeOf[testStruct0](),
 			typeOf[testStruct1](),
 			typeOf[testStruct2](),
diff --git a/generic/mutate_test.go b/generic/mutate_test.go
index 1b99a0d..6d98556 100644
--- a/generic/mutate_test.go
+++ b/generic/mutate_test.go
@@ -7,284 +7,40 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-func TestMutate1(t *testing.T) {
+func TestMutate(t *testing.T) {
 	w := ecs.NewWorld()
 	registerAll(&w)
 
-	mut := NewMutate1[testStruct0](&w)
-	map0 := NewMap[testStruct0](&w)
-
-	e, s0 := mut.NewEntity()
-	assert.NotNil(t, s0)
-
-	mut.Remove(e)
-	assert.False(t, map0.Has(e))
-
-	s0 = mut.Add(e)
-	assert.NotNil(t, s0)
-
-	e = w.NewEntity()
-	_ = mut.Assign(e, &testStruct0{})
-	assert.True(t, map0.Has(e))
-
-	e, _ = mut.NewEntityWith(&testStruct0{})
-	assert.True(t, map0.Has(e))
-}
-
-func TestMutate2(t *testing.T) {
-	w := ecs.NewWorld()
-	registerAll(&w)
-
-	mut := NewMutate2[testStruct0, testStruct1](&w)
-	map0 := NewMap[testStruct0](&w)
-	map1 := NewMap[testStruct1](&w)
-
-	e, s0, s1 := mut.NewEntity()
-	assert.NotNil(t, s0)
-	assert.NotNil(t, s1)
-
-	mut.Remove(e)
-	assert.False(t, map0.Has(e))
-	assert.False(t, map1.Has(e))
-
-	s0, s1 = mut.Add(e)
-	assert.NotNil(t, s0)
-	assert.NotNil(t, s1)
-
-	e = w.NewEntity()
-	_, _ = mut.Assign(e, &testStruct0{}, &testStruct1{})
-	assert.True(t, map0.Has(e))
-	assert.True(t, map1.Has(e))
-
-	e, _, _ = mut.NewEntityWith(&testStruct0{}, &testStruct1{})
-	assert.True(t, map0.Has(e))
-	assert.True(t, map1.Has(e))
-}
-
-func TestMutate3(t *testing.T) {
-	w := ecs.NewWorld()
-	registerAll(&w)
-
-	mut := NewMutate3[
-		testStruct0, testStruct1, testStruct2,
-	](&w)
-	map0 := NewMap[testStruct0](&w)
-	map1 := NewMap[testStruct1](&w)
-
-	e, s0, s1, _ := mut.NewEntity()
-	assert.NotNil(t, s0)
-	assert.NotNil(t, s1)
-
-	mut.Remove(e)
-	assert.False(t, map0.Has(e))
-	assert.False(t, map1.Has(e))
-
-	s0, s1, _ = mut.Add(e)
-	assert.NotNil(t, s0)
-	assert.NotNil(t, s1)
-
-	e = w.NewEntity()
-	_, _, _ = mut.Assign(e,
-		&testStruct0{}, &testStruct1{}, &testStruct2{},
-	)
-	assert.True(t, map0.Has(e))
-	assert.True(t, map1.Has(e))
-
-	e, _, _, _ = mut.NewEntityWith(
-		&testStruct0{}, &testStruct1{}, &testStruct2{},
-	)
-	assert.True(t, map0.Has(e))
-	assert.True(t, map1.Has(e))
-}
-
-func TestMutate4(t *testing.T) {
-	w := ecs.NewWorld()
-	registerAll(&w)
-
-	mut := NewMutate4[
-		testStruct0, testStruct1, testStruct2, testStruct3,
-	](&w)
-	map0 := NewMap[testStruct0](&w)
-	map1 := NewMap[testStruct1](&w)
-
-	e, s0, s1, _, _ := mut.NewEntity()
-	assert.NotNil(t, s0)
-	assert.NotNil(t, s1)
-
-	mut.Remove(e)
-	assert.False(t, map0.Has(e))
-	assert.False(t, map1.Has(e))
-
-	s0, s1, _, _ = mut.Add(e)
-	assert.NotNil(t, s0)
-	assert.NotNil(t, s1)
+	mut := NewMutate(&w).Adds(T2[testStruct0, testStruct1]()...)
+	mutR := NewMutate(&w).Removes(T2[testStruct0, testStruct1]()...)
+	mutEx := NewMutate(&w).
+		Removes(T2[testStruct0, testStruct1]()...).
+		Adds(T2[testStruct2, testStruct3]()...)
 
-	e = w.NewEntity()
-	_, _, _, _ = mut.Assign(e,
-		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
-	)
-	assert.True(t, map0.Has(e))
-	assert.True(t, map1.Has(e))
-
-	e, _, _, _, _ = mut.NewEntityWith(
-		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
-	)
-	assert.True(t, map0.Has(e))
-	assert.True(t, map1.Has(e))
-}
-
-func TestMutate5(t *testing.T) {
-	w := ecs.NewWorld()
-	registerAll(&w)
-
-	mut := NewMutate5[
-		testStruct0, testStruct1, testStruct2, testStruct3,
-		testStruct4,
-	](&w)
+	mapper := NewMap2[testStruct0, testStruct1](&w)
+	mapper2 := NewMap2[testStruct2, testStruct3](&w)
 	map0 := NewMap[testStruct0](&w)
 	map1 := NewMap[testStruct1](&w)
 
-	e, s0, s1, _, _, _ := mut.NewEntity()
+	e := mut.NewEntity()
+	s0, s1 := mapper.Get(e)
 	assert.NotNil(t, s0)
 	assert.NotNil(t, s1)
 
-	mut.Remove(e)
+	mutR.Remove(e)
 	assert.False(t, map0.Has(e))
 	assert.False(t, map1.Has(e))
 
-	s0, s1, _, _, _ = mut.Add(e)
+	mut.Add(e)
+	s0, s1 = mapper.Get(e)
 	assert.NotNil(t, s0)
 	assert.NotNil(t, s1)
 
-	e = w.NewEntity()
-	_, _, _, _, _ = mut.Assign(e,
-		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
-		&testStruct4{},
-	)
-	assert.True(t, map0.Has(e))
-	assert.True(t, map1.Has(e))
-
-	e, _, _, _, _, _ = mut.NewEntityWith(
-		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
-		&testStruct4{},
-	)
-	assert.True(t, map0.Has(e))
-	assert.True(t, map1.Has(e))
-}
-
-func TestMutate6(t *testing.T) {
-	w := ecs.NewWorld()
-	registerAll(&w)
-
-	mut := NewMutate6[
-		testStruct0, testStruct1, testStruct2, testStruct3,
-		testStruct4, testStruct5,
-	](&w)
-	map0 := NewMap[testStruct0](&w)
-	map1 := NewMap[testStruct1](&w)
-
-	e, s0, s1, _, _, _, _ := mut.NewEntity()
-	assert.NotNil(t, s0)
-	assert.NotNil(t, s1)
-
-	mut.Remove(e)
-	assert.False(t, map0.Has(e))
-	assert.False(t, map1.Has(e))
-
-	s0, s1, _, _, _, _ = mut.Add(e)
-	assert.NotNil(t, s0)
-	assert.NotNil(t, s1)
-
-	e = w.NewEntity()
-	_, _, _, _, _, _ = mut.Assign(e,
-		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
-		&testStruct4{}, &testStruct5{},
-	)
-	assert.True(t, map0.Has(e))
-	assert.True(t, map1.Has(e))
-
-	e, _, _, _, _, _, _ = mut.NewEntityWith(
-		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
-		&testStruct4{}, &testStruct5{},
-	)
-	assert.True(t, map0.Has(e))
-	assert.True(t, map1.Has(e))
-}
-
-func TestMutate7(t *testing.T) {
-	w := ecs.NewWorld()
-	registerAll(&w)
-
-	mut := NewMutate7[
-		testStruct0, testStruct1, testStruct2, testStruct3,
-		testStruct4, testStruct5, testStruct6,
-	](&w)
-	map0 := NewMap[testStruct0](&w)
-	map1 := NewMap[testStruct1](&w)
-
-	e, s0, s1, _, _, _, _, _ := mut.NewEntity()
-	assert.NotNil(t, s0)
-	assert.NotNil(t, s1)
-
-	mut.Remove(e)
-	assert.False(t, map0.Has(e))
-	assert.False(t, map1.Has(e))
-
-	s0, s1, _, _, _, _, _ = mut.Add(e)
-	assert.NotNil(t, s0)
-	assert.NotNil(t, s1)
-
-	e = w.NewEntity()
-	_, _, _, _, _, _, _ = mut.Assign(e,
-		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
-		&testStruct4{}, &testStruct5{}, &testStruct6{},
-	)
-	assert.True(t, map0.Has(e))
-	assert.True(t, map1.Has(e))
-
-	e, _, _, _, _, _, _, _ = mut.NewEntityWith(
-		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
-		&testStruct4{}, &testStruct5{}, &testStruct6{},
-	)
-	assert.True(t, map0.Has(e))
-	assert.True(t, map1.Has(e))
-}
-
-func TestMutate8(t *testing.T) {
-	w := ecs.NewWorld()
-	registerAll(&w)
-
-	mut := NewMutate8[
-		testStruct0, testStruct1, testStruct2, testStruct3,
-		testStruct4, testStruct5, testStruct6, testStruct7,
-	](&w)
-	map0 := NewMap[testStruct0](&w)
-	map1 := NewMap[testStruct1](&w)
-
-	e, s0, s1, _, _, _, _, _, _ := mut.NewEntity()
-	assert.NotNil(t, s0)
-	assert.NotNil(t, s1)
-
-	mut.Remove(e)
-	assert.False(t, map0.Has(e))
-	assert.False(t, map1.Has(e))
-
-	s0, s1, _, _, _, _, _, _ = mut.Add(e)
-	assert.NotNil(t, s0)
-	assert.NotNil(t, s1)
-
-	e = w.NewEntity()
-	_, _, _, _, _, _, _, _ = mut.Assign(e,
-		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
-		&testStruct4{}, &testStruct5{}, &testStruct6{}, &testStruct7{},
-	)
-	assert.True(t, map0.Has(e))
-	assert.True(t, map1.Has(e))
-
-	e, _, _, _, _, _, _, _, _ = mut.NewEntityWith(
-		&testStruct0{}, &testStruct1{}, &testStruct2{}, &testStruct3{},
-		&testStruct4{}, &testStruct5{}, &testStruct6{}, &testStruct7{},
-	)
-	assert.True(t, map0.Has(e))
-	assert.True(t, map1.Has(e))
+	mutEx.Exchange(e)
+	s0, s1 = mapper.Get(e)
+	assert.Nil(t, s0)
+	assert.Nil(t, s1)
+	s2, s3 := mapper2.Get(e)
+	assert.NotNil(t, s2)
+	assert.NotNil(t, s3)
 }
diff --git a/generic/query_test.go b/generic/query_test.go
index e321284..362cd36 100644
--- a/generic/query_test.go
+++ b/generic/query_test.go
@@ -36,21 +36,21 @@ func TestQueryOptionalNot(t *testing.T) {
 	}
 	assert.Equal(t, 3, cnt)
 
-	query2 = NewFilter2[testStruct0, testStruct1]().Without(Mask1[testStruct9]()).Query(&w)
+	query2 = NewFilter2[testStruct0, testStruct1]().Without(T[testStruct9]()).Query(&w)
 	cnt = 0
 	for query2.Next() {
 		cnt++
 	}
 	assert.Equal(t, 2, cnt)
 
-	query2 = NewFilter2[testStruct0, testStruct1]().Without(Mask2[testStruct8, testStruct9]()).Query(&w)
+	query2 = NewFilter2[testStruct0, testStruct1]().Without(T[testStruct8](), T[testStruct9]()).Query(&w)
 	cnt = 0
 	for query2.Next() {
 		cnt++
 	}
 	assert.Equal(t, 1, cnt)
 
-	query2 = NewFilter2[testStruct0, testStruct1]().With(Mask1[testStruct2]()).Without(Mask1[testStruct9]()).Query(&w)
+	query2 = NewFilter2[testStruct0, testStruct1]().With(T[testStruct2]()).Without(T[testStruct9]()).Query(&w)
 	cnt = 0
 	for query2.Next() {
 		cnt++
@@ -64,7 +64,7 @@ func TestQueryOptionalNot(t *testing.T) {
 	}
 	assert.Equal(t, 1, cnt)
 
-	query3 = NewFilter3[testStruct0, testStruct1, testStruct9]().Optional(Mask1[testStruct9]()).Query(&w)
+	query3 = NewFilter3[testStruct0, testStruct1, testStruct9]().Optional(T[testStruct9]()).Query(&w)
 	cnt = 0
 	for query3.Next() {
 		cnt++
@@ -92,9 +92,8 @@ func TestQuery0(t *testing.T) {
 	cnt := 0
 	filter :=
 		NewFilter0().
-			Optional(Mask1[testStruct1]()).
-			With(Mask1[testStruct8]()).
-			Without(Mask1[testStruct9]())
+			With(T[testStruct8]()).
+			Without(T[testStruct9]())
 
 	assert.Equal(t, ecs.All(8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
@@ -126,15 +125,15 @@ func TestQuery1(t *testing.T) {
 	cnt := 0
 	filter :=
 		NewFilter1[testStruct0]().
-			Optional(Mask1[testStruct9]()).
-			With(Mask1[testStruct8]()).
-			Without(Mask1[testStruct9]())
+			Optional(T[testStruct9]()).
+			With(T[testStruct8]()).
+			Without(T[testStruct9]())
 
 	assert.Equal(t, ecs.All(0, 8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
 	for query.Next() {
 		c0 := query.Get1()
-		_, c02 := query.GetAll()
+		_, c02 := query.Get()
 		assert.Equal(t, c0, c02)
 		assert.Equal(t, cnt+1, int(c0.val))
 		cnt++
@@ -165,9 +164,9 @@ func TestQuery2(t *testing.T) {
 
 	filter :=
 		NewFilter2[testStruct0, testStruct1]().
-			Optional(Mask1[testStruct1]()).
-			With(Mask1[testStruct8]()).
-			Without(Mask1[testStruct9]())
+			Optional(T[testStruct1]()).
+			With(T[testStruct8]()).
+			Without(T[testStruct9]())
 
 	assert.Equal(t, ecs.All(0, 8).Without(9), filter.Filter(&w))
 
@@ -180,7 +179,7 @@ func TestQuery2(t *testing.T) {
 			assert.Equal(t, cnt+1, int(c1.val))
 			assert.Equal(t, cnt+2, int(c2.val))
 
-			_, c12, c22 := q.GetAll()
+			_, c12, c22 := q.Get()
 			assert.Equal(t, c1, c12)
 			assert.Equal(t, c2, c22)
 			cnt++
@@ -217,9 +216,9 @@ func TestQuery3(t *testing.T) {
 	cnt := 0
 	filter :=
 		NewFilter3[testStruct0, testStruct1, testStruct2]().
-			Optional(Mask1[testStruct1]()).
-			With(Mask1[testStruct8]()).
-			Without(Mask1[testStruct9]())
+			Optional(T[testStruct1]()).
+			With(T[testStruct8]()).
+			Without(T[testStruct9]())
 
 	assert.Equal(t, ecs.All(0, 2, 8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
@@ -231,7 +230,7 @@ func TestQuery3(t *testing.T) {
 		assert.Equal(t, cnt+2, int(c2.val))
 		assert.Equal(t, cnt+3, int(c3.val))
 
-		_, c12, c22, c32 := query.GetAll()
+		_, c12, c22, c32 := query.Get()
 		assert.Equal(t, c1, c12)
 		assert.Equal(t, c2, c22)
 		assert.Equal(t, c3, c32)
@@ -272,9 +271,9 @@ func TestQuery4(t *testing.T) {
 	cnt := 0
 	filter :=
 		NewFilter4[testStruct0, testStruct1, testStruct2, testStruct3]().
-			Optional(Mask1[testStruct1]()).
-			With(Mask1[testStruct8]()).
-			Without(Mask1[testStruct9]())
+			Optional(T[testStruct1]()).
+			With(T[testStruct8]()).
+			Without(T[testStruct9]())
 
 	assert.Equal(t, ecs.All(0, 2, 3, 8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
@@ -288,7 +287,7 @@ func TestQuery4(t *testing.T) {
 		assert.Equal(t, cnt+3, int(c3.val))
 		assert.Equal(t, cnt+4, int(c4.val))
 
-		_, c12, c22, c32, c42 := query.GetAll()
+		_, c12, c22, c32, c42 := query.Get()
 		assert.Equal(t, c1, c12)
 		assert.Equal(t, c2, c22)
 		assert.Equal(t, c3, c32)
@@ -334,9 +333,9 @@ func TestQuery5(t *testing.T) {
 	cnt := 0
 	filter :=
 		NewFilter5[testStruct0, testStruct1, testStruct2, testStruct3, testStruct4]().
-			Optional(Mask1[testStruct1]()).
-			With(Mask1[testStruct8]()).
-			Without(Mask1[testStruct9]())
+			Optional(T[testStruct1]()).
+			With(T[testStruct8]()).
+			Without(T[testStruct9]())
 
 	assert.Equal(t, ecs.All(0, 2, 3, 4, 8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
@@ -352,7 +351,7 @@ func TestQuery5(t *testing.T) {
 		assert.Equal(t, cnt+4, int(c4.val))
 		assert.Equal(t, cnt+5, int(c5.val))
 
-		_, c12, c22, c32, c42, c52 := query.GetAll()
+		_, c12, c22, c32, c42, c52 := query.Get()
 		assert.Equal(t, c1, c12)
 		assert.Equal(t, c2, c22)
 		assert.Equal(t, c3, c32)
@@ -403,9 +402,9 @@ func TestQuery6(t *testing.T) {
 	cnt := 0
 	filter :=
 		NewFilter6[testStruct0, testStruct1, testStruct2, testStruct3, testStruct4, testStruct5]().
-			Optional(Mask1[testStruct1]()).
-			With(Mask1[testStruct8]()).
-			Without(Mask1[testStruct9]())
+			Optional(T[testStruct1]()).
+			With(T[testStruct8]()).
+			Without(T[testStruct9]())
 
 	assert.Equal(t, ecs.All(0, 2, 3, 4, 5, 8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
@@ -423,7 +422,7 @@ func TestQuery6(t *testing.T) {
 		assert.Equal(t, cnt+5, int(c5.val))
 		assert.Equal(t, cnt+6, int(c6.val))
 
-		_, c12, c22, c32, c42, c52, c62 := query.GetAll()
+		_, c12, c22, c32, c42, c52, c62 := query.Get()
 		assert.Equal(t, c1, c12)
 		assert.Equal(t, c2, c22)
 		assert.Equal(t, c3, c32)
@@ -482,9 +481,9 @@ func TestQuery7(t *testing.T) {
 			testStruct0, testStruct1, testStruct2, testStruct3, testStruct4,
 			testStruct5, testStruct6,
 		]().
-			Optional(Mask1[testStruct1]()).
-			With(Mask1[testStruct8]()).
-			Without(Mask1[testStruct9]())
+			Optional(T[testStruct1]()).
+			With(T[testStruct8]()).
+			Without(T[testStruct9]())
 
 	assert.Equal(t, ecs.All(0, 2, 3, 4, 5, 6, 8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
@@ -504,7 +503,7 @@ func TestQuery7(t *testing.T) {
 		assert.Equal(t, cnt+6, int(c6.val))
 		assert.Equal(t, cnt+7, int(c7.val))
 
-		_, c12, c22, c32, c42, c52, c62, c72 := query.GetAll()
+		_, c12, c22, c32, c42, c52, c62, c72 := query.Get()
 		assert.Equal(t, c1, c12)
 		assert.Equal(t, c2, c22)
 		assert.Equal(t, c3, c32)
@@ -560,9 +559,9 @@ func TestQuery8(t *testing.T) {
 			testStruct0, testStruct1, testStruct2, testStruct3,
 			testStruct4, testStruct5, testStruct6, testStruct7,
 		]().
-			Optional(Mask1[testStruct1]()).
-			With(Mask1[testStruct8]()).
-			Without(Mask1[testStruct9]())
+			Optional(T[testStruct1]()).
+			With(T[testStruct8]()).
+			Without(T[testStruct9]())
 
 	assert.Equal(t, ecs.All(0, 2, 3, 4, 5, 6, 7, 8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
@@ -584,7 +583,7 @@ func TestQuery8(t *testing.T) {
 		assert.Equal(t, cnt+7, int(c7.val))
 		assert.Equal(t, cnt+8, int(c8.val))
 
-		_, c12, c22, c32, c42, c52, c62, c72, c82 := query.GetAll()
+		_, c12, c22, c32, c42, c52, c62, c72, c82 := query.Get()
 		assert.Equal(t, c1, c12)
 		assert.Equal(t, c2, c22)
 		assert.Equal(t, c3, c32)