@ericrisco/rsc 0.1.35 → 0.1.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/manifest.json +264 -2
- package/package.json +1 -1
- package/scripts/lib/domains.js +2 -1
- package/scripts/lib/recommend.js +5 -0
- package/skills/fable-operator/SKILL.md +170 -0
- package/skills/fable-operator/evals/README.md +8 -0
- package/skills/fable-operator/evals/cases.yaml +52 -0
- package/skills/game-design/SKILL.md +170 -0
- package/skills/game-design/evals/README.md +13 -0
- package/skills/game-design/evals/cases.yaml +47 -0
- package/skills/game-design/references/mechanics-and-loops.md +78 -0
- package/skills/game-design/references/playtesting-and-scope.md +58 -0
- package/skills/game-design/references/progression-and-economy.md +70 -0
- package/skills/game-storytelling/SKILL.md +159 -0
- package/skills/game-storytelling/evals/README.md +28 -0
- package/skills/game-storytelling/evals/cases.yaml +51 -0
- package/skills/game-storytelling/references/branching-and-state.md +134 -0
- package/skills/game-storytelling/references/dialogue-tools.md +117 -0
- package/skills/game-storytelling/references/environmental-storytelling.md +71 -0
- package/skills/gamedev-multiplayer/SKILL.md +250 -0
- package/skills/gamedev-multiplayer/evals/README.md +12 -0
- package/skills/gamedev-multiplayer/evals/cases.yaml +44 -0
- package/skills/gamedev-multiplayer/references/godot-high-level-multiplayer.md +133 -0
- package/skills/gamedev-multiplayer/references/prediction-and-latency.md +104 -0
- package/skills/gamedev-multiplayer/references/unity-and-unreal-netcode.md +166 -0
- package/skills/gamedev-pathing/SKILL.md +242 -0
- package/skills/gamedev-pathing/evals/README.md +14 -0
- package/skills/gamedev-pathing/evals/cases.yaml +49 -0
- package/skills/gamedev-pathing/references/navmesh-workflow.md +110 -0
- package/skills/gamedev-pathing/references/search-algorithms.md +135 -0
- package/skills/gamedev-pathing/references/steering-and-avoidance.md +120 -0
- package/skills/gamedev-physics/SKILL.md +225 -0
- package/skills/gamedev-physics/evals/README.md +12 -0
- package/skills/gamedev-physics/evals/cases.yaml +54 -0
- package/skills/gamedev-physics/references/character-controllers.md +120 -0
- package/skills/gamedev-physics/references/determinism-and-queries.md +124 -0
- package/skills/gamedev-physics/references/layers-and-masks.md +115 -0
- package/skills/gamedev-shaders/SKILL.md +252 -0
- package/skills/gamedev-shaders/evals/README.md +14 -0
- package/skills/gamedev-shaders/evals/cases.yaml +45 -0
- package/skills/gamedev-shaders/references/effect-recipes.md +205 -0
- package/skills/gamedev-shaders/references/godot-shading-language.md +133 -0
- package/skills/gamedev-shaders/references/unity-and-unreal-shaders.md +169 -0
- package/skills/gamedev-shipping/SKILL.md +236 -0
- package/skills/gamedev-shipping/evals/README.md +9 -0
- package/skills/gamedev-shipping/evals/cases.yaml +55 -0
- package/skills/gamedev-shipping/references/mobile-and-desktop.md +127 -0
- package/skills/gamedev-shipping/references/stores-and-ci.md +162 -0
- package/skills/gamedev-shipping/references/web-export-headers.md +140 -0
- package/skills/godot/SKILL.md +319 -0
- package/skills/godot/evals/README.md +13 -0
- package/skills/godot/evals/cases.yaml +50 -0
- package/skills/godot/references/export-and-testing.md +102 -0
- package/skills/godot/references/gdscript-style.md +84 -0
- package/skills/godot/references/godot3-to-4-traps.md +89 -0
- package/skills/godot/references/nodes-scenes-resources.md +109 -0
- package/skills/level-design/SKILL.md +175 -0
- package/skills/level-design/evals/README.md +35 -0
- package/skills/level-design/evals/cases.yaml +58 -0
- package/skills/level-design/references/blockout-to-art.md +118 -0
- package/skills/level-design/references/guidance-and-readability.md +152 -0
- package/skills/level-design/references/pacing-and-encounters.md +142 -0
- package/skills/roast-me/tools/adapters/__pycache__/__init__.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/base.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/claude.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/codex.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/gemini.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/registry.cpython-312.pyc +0 -0
- package/skills/unity/SKILL.md +282 -0
- package/skills/unity/evals/README.md +8 -0
- package/skills/unity/evals/cases.yaml +43 -0
- package/skills/unity/references/build-and-platforms.md +65 -0
- package/skills/unity/references/input-system.md +102 -0
- package/skills/unity/references/lifecycle-deep-dive.md +75 -0
- package/skills/unreal/SKILL.md +270 -0
- package/skills/unreal/evals/README.md +12 -0
- package/skills/unreal/evals/cases.yaml +45 -0
- package/skills/unreal/references/blueprint-cpp-parity.md +109 -0
- package/skills/unreal/references/gameplay-framework.md +95 -0
- package/skills/unreal/references/packaging.md +83 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# GDScript style & formatting cheat-sheet (Godot 4.x)
|
|
2
|
+
|
|
3
|
+
Mirrors the official GDScript style guide. When in doubt, run the editor's built-in formatter
|
|
4
|
+
(Ctrl/Cmd+Shift+I) and `gdformat` (from `gdtoolkit`) in CI.
|
|
5
|
+
|
|
6
|
+
## Naming
|
|
7
|
+
|
|
8
|
+
| Thing | Case | Example |
|
|
9
|
+
| --- | --- | --- |
|
|
10
|
+
| File (script/scene) | `snake_case` | `player_controller.gd`, `main_menu.tscn` |
|
|
11
|
+
| `class_name` / type | `PascalCase` | `class_name EnemyStats` |
|
|
12
|
+
| Node name in tree | `PascalCase` | `HealthBar`, `AttackTimer` |
|
|
13
|
+
| Variable / function | `snake_case` | `var max_health`, `func take_damage()` |
|
|
14
|
+
| Signal | `snake_case`, past tense | `signal health_depleted` |
|
|
15
|
+
| Constant | `CONSTANT_CASE` | `const MAX_SPEED := 400.0` |
|
|
16
|
+
| Enum type / members | `PascalCase` / `CONSTANT_CASE` | `enum State { IDLE, RUN }` |
|
|
17
|
+
| Private (convention) | leading underscore | `var _internal_timer` |
|
|
18
|
+
| Virtual/lifecycle | leading underscore | `_ready`, `_process`, `_on_body_entered` |
|
|
19
|
+
|
|
20
|
+
## Formatting
|
|
21
|
+
|
|
22
|
+
- **Tabs** for indentation (not spaces). Editor default.
|
|
23
|
+
- Lines **< 100 columns**.
|
|
24
|
+
- One space around binary operators (`a + b`, `x := 1`), none inside call parens.
|
|
25
|
+
- Two blank lines between functions at top level; one inside classes as needed.
|
|
26
|
+
- Prefer `:=` (inferred) when the RHS makes the type obvious; `: Type =` when it does not.
|
|
27
|
+
|
|
28
|
+
## Typed by default
|
|
29
|
+
|
|
30
|
+
```gdscript
|
|
31
|
+
var speed: float = 300.0 # explicit annotation
|
|
32
|
+
var dir := Vector2.ZERO # inferred
|
|
33
|
+
var slots: Array[Item] = [] # typed collection
|
|
34
|
+
const GRAVITY := 980.0
|
|
35
|
+
|
|
36
|
+
func heal(amount: int) -> void: # typed params AND return
|
|
37
|
+
_health = mini(_health + amount, _max_health)
|
|
38
|
+
|
|
39
|
+
func find_target() -> Node2D: # return type declared
|
|
40
|
+
return get_tree().get_first_node_in_group("player")
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- Declare `-> void` on functions that return nothing; declare the real type otherwise.
|
|
44
|
+
- Use `as` for safe downcasts: `var e := body as Enemy` → `null` on mismatch (no crash).
|
|
45
|
+
- Avoid untyped `var x` and `Variant` params — they disable the compiler's checks and the VM's
|
|
46
|
+
typed fast paths.
|
|
47
|
+
|
|
48
|
+
## Script layout order (recommended top-to-bottom)
|
|
49
|
+
|
|
50
|
+
1. `@tool` (if any) — must be the very first line.
|
|
51
|
+
2. `class_name` then `extends` (or `extends` alone).
|
|
52
|
+
3. `## docstring` comment.
|
|
53
|
+
4. `signal` declarations.
|
|
54
|
+
5. `enum` / `const`.
|
|
55
|
+
6. `@export` vars, then plain member vars, then `@onready` vars.
|
|
56
|
+
7. Built-in virtuals: `_init`, `_ready`, `_process`, `_physics_process`, `_input`, …
|
|
57
|
+
8. Public methods, then private (`_underscore`) methods, then signal handlers (`_on_*`).
|
|
58
|
+
|
|
59
|
+
```gdscript
|
|
60
|
+
@tool
|
|
61
|
+
class_name Turret extends Node2D
|
|
62
|
+
## Auto-aiming turret; @export the fire rate in the inspector.
|
|
63
|
+
|
|
64
|
+
signal fired(at: Vector2)
|
|
65
|
+
|
|
66
|
+
const MAX_RANGE := 600.0
|
|
67
|
+
enum Mode { IDLE, TRACKING }
|
|
68
|
+
|
|
69
|
+
@export var fire_rate := 2.0
|
|
70
|
+
var _cooldown := 0.0
|
|
71
|
+
@onready var muzzle: Marker2D = %Muzzle
|
|
72
|
+
|
|
73
|
+
func _physics_process(delta: float) -> void:
|
|
74
|
+
_cooldown = maxf(_cooldown - delta, 0.0)
|
|
75
|
+
|
|
76
|
+
func _on_area_entered(_area: Area2D) -> void:
|
|
77
|
+
pass
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Common built-in math helpers (Godot 4 names)
|
|
81
|
+
|
|
82
|
+
`absf/absi`, `minf/mini`, `maxf/maxi`, `clampf/clampi`, `snappedf`, `lerpf`, `move_toward`,
|
|
83
|
+
`deg_to_rad` / `rad_to_deg`, `randf_range`, `randi_range`. The unsuffixed `abs/min/max/clamp` still
|
|
84
|
+
work on Variants but the typed suffixed forms are faster and clearer.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Godot 3 → 4.x migration ban-list (full table)
|
|
2
|
+
|
|
3
|
+
Godot 4 is a hard break from 3.x. The engine ships a project converter, but it does **not** catch
|
|
4
|
+
everything — and an agent generating fresh code must simply never emit the left column. Use this as
|
|
5
|
+
the authoritative reference when porting or reviewing.
|
|
6
|
+
|
|
7
|
+
## Won't-parse renames (hard errors)
|
|
8
|
+
|
|
9
|
+
| Godot 3 | Godot 4.x | Note |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| `yield(obj, "signal")` | `await obj.signal` | Coroutines are now `await`; the function must not need `yield`'s return-value trick. |
|
|
12
|
+
| `yield(get_tree().create_timer(1),"timeout")` | `await get_tree().create_timer(1.0).timeout` | |
|
|
13
|
+
| `onready var` | `@onready var` | Annotation. |
|
|
14
|
+
| `export var` / `export(int) var` | `@export var` / `@export_range(...) var` | Typed annotations replace the `export(Type)` hint syntax. |
|
|
15
|
+
| `tool` | `@tool` | Must be the first line. |
|
|
16
|
+
| `remote`/`master`/`puppet func` | `@rpc(...)` annotations | Networking model changed entirely. |
|
|
17
|
+
| `setget set_fn, get_fn` | `set(v): ...` / `get: ...` inline accessors | |
|
|
18
|
+
|
|
19
|
+
## Node / class renames
|
|
20
|
+
|
|
21
|
+
| Godot 3 | Godot 4.x |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| `Spatial` | `Node3D` |
|
|
24
|
+
| `KinematicBody` / `KinematicBody2D` | `CharacterBody3D` / `CharacterBody2D` |
|
|
25
|
+
| `Area` | `Area3D` |
|
|
26
|
+
| `RigidBody` / `StaticBody` | `RigidBody3D` / `StaticBody3D` |
|
|
27
|
+
| `Sprite` | `Sprite2D` |
|
|
28
|
+
| `Sprite3D` | `Sprite3D` (unchanged) |
|
|
29
|
+
| `AnimatedSprite` | `AnimatedSprite2D` |
|
|
30
|
+
| `CollisionShape` | `CollisionShape3D` |
|
|
31
|
+
| `Camera` | `Camera3D` |
|
|
32
|
+
| `Light2D` (old) / `Light` | `PointLight2D` / `DirectionalLight2D` / `OmniLight3D` etc. |
|
|
33
|
+
| `Viewport` (as node) | `SubViewport` (embedded) |
|
|
34
|
+
| `YSort` (node) | `y_sort_enabled` property on `Node2D`/`CanvasItem` |
|
|
35
|
+
| `ARVROrigin` / `ARVRCamera` | `XROrigin3D` / `XRCamera3D` |
|
|
36
|
+
| `Reference` | `RefCounted` |
|
|
37
|
+
| `TileMap` | `TileMapLayer` (one per layer; `TileMap` deprecated 4.3+) |
|
|
38
|
+
|
|
39
|
+
## Method / API changes
|
|
40
|
+
|
|
41
|
+
| Godot 3 | Godot 4.x |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| `scene.instance()` | `scene.instantiate()` |
|
|
44
|
+
| `move_and_slide(velocity, up_direction)` | set `velocity` property → `move_and_slide()` (no args) |
|
|
45
|
+
| `move_and_slide_with_snap(...)` | set `floor_snap_length` → `move_and_slide()` |
|
|
46
|
+
| `connect("sig", obj, "method", [args])` | `obj.sig.connect(method.bind(args))` (Callable) |
|
|
47
|
+
| `disconnect("sig", obj, "method")` | `obj.sig.disconnect(method)` |
|
|
48
|
+
| `emit_signal("sig", a)` | `sig.emit(a)` (string form still exists but prefer the property) |
|
|
49
|
+
| `is_connected("sig", obj, "m")` | `sig.is_connected(m)` |
|
|
50
|
+
| `call_deferred("method", a)` | `method.bind(a).call_deferred()` or `call_deferred("method", a)` |
|
|
51
|
+
| `File.new()` + `open()` | `FileAccess.open(path, FileAccess.READ)` |
|
|
52
|
+
| `Directory.new()` | `DirAccess.open(path)` / `DirAccess.dir_exists_absolute(...)` |
|
|
53
|
+
| `OS.get_ticks_msec()` | `Time.get_ticks_msec()` |
|
|
54
|
+
| `OS.get_datetime()` | `Time.get_datetime_dict_from_system()` |
|
|
55
|
+
| `PoolByteArray` / `PoolStringArray` / `PoolVector2Array` | `PackedByteArray` / `PackedStringArray` / `PackedVector2Array` |
|
|
56
|
+
| `Tween` node + `interpolate_property` | `var t := create_tween(); t.tween_property(node, "position", target, 0.5)` |
|
|
57
|
+
| `rand_range(a, b)` | `randf_range(a, b)` (float) / `randi_range(a, b)` (int) |
|
|
58
|
+
| `deg2rad` / `rad2deg` | `deg_to_rad` / `rad_to_deg` |
|
|
59
|
+
| `stepify(x, s)` | `snapped(x, s)` |
|
|
60
|
+
| `.empty()` | `.is_empty()` |
|
|
61
|
+
| `get_node("Path")` still valid | prefer `%UniqueName` for refactor-safety |
|
|
62
|
+
| `KEY_*` / input constants mostly renamed | check `Key`, `MouseButton` enums |
|
|
63
|
+
|
|
64
|
+
## Silent behavior changes (compile clean, act wrong)
|
|
65
|
+
|
|
66
|
+
- **`Array.slice(begin, end, step, deep)`** — `end` is **exclusive** in Godot 4 (was inclusive in 3).
|
|
67
|
+
`[10,20,30,40].slice(1,3)` → `[20,30]`.
|
|
68
|
+
- **`Camera2D.zoom`** — meaning **inverted**. Larger value = zoom **in**. `zoom = Vector2(2,2)`
|
|
69
|
+
magnifies 2×; in Godot 3 that zoomed out. To zoom out now, use values **below** 1.
|
|
70
|
+
- **Y-sort** is a property (`y_sort_enabled`), not a node — porting a `YSort` parent silently loses
|
|
71
|
+
sorting unless you set the property.
|
|
72
|
+
- **Physics interpolation / gravity** — read gravity via `get_gravity()` (2D/3D) or
|
|
73
|
+
`ProjectSettings`; the old default constants changed.
|
|
74
|
+
- **Signal argument order** on some built-in signals changed; verify against the 4.x docs, don't
|
|
75
|
+
assume the 3.x signature.
|
|
76
|
+
- **`_ready`/`_process` no longer auto-call the base** — you must `super()` when extending a script
|
|
77
|
+
that defines them.
|
|
78
|
+
- **Integer division** with typed ints truncates as expected; mixing float/int in Godot 4 follows
|
|
79
|
+
stricter typed rules — annotate to avoid surprises.
|
|
80
|
+
|
|
81
|
+
## Porting workflow
|
|
82
|
+
|
|
83
|
+
1. Open the Godot 3 project in Godot 4 → run the built-in **Project Converter** (backs up first).
|
|
84
|
+
2. Fix red parse errors top-down (renames above).
|
|
85
|
+
3. Search the codebase for each string-form `connect(`, `yield(`, `.instance()`, `File.new`,
|
|
86
|
+
`Directory.new`, `Pool*Array`, `move_and_slide(` with args — the converter misses some.
|
|
87
|
+
4. Fix the silent-breakers deliberately (slice bounds, Camera2D zoom, y-sort) — tests or a manual
|
|
88
|
+
pass, since nothing errors.
|
|
89
|
+
5. Re-open every scene once; a converter-mangled `.tscn` fails loudly in the editor.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Nodes, scenes, scripts & custom Resources (Godot 4.x)
|
|
2
|
+
|
|
3
|
+
The four building blocks and when each is the right tool. Getting this decomposition right is what
|
|
4
|
+
separates a maintainable Godot project from a monolithic scene that nobody can touch.
|
|
5
|
+
|
|
6
|
+
## The mental model
|
|
7
|
+
|
|
8
|
+
- **Node** — a live object in the running tree. It has a transform (2D/3D), can render, process,
|
|
9
|
+
collide, receive input. Everything on screen is a node. Pick the most specific typed subclass
|
|
10
|
+
(`Sprite2D`, `Area3D`, `CharacterBody2D`, `Timer`, `AudioStreamPlayer`).
|
|
11
|
+
- **Scene** (`.tscn`) — a saved tree of nodes with a designated **root**, instanceable N times. The
|
|
12
|
+
reusable unit of a Godot game. A scene can instance other scenes (composition).
|
|
13
|
+
- **Script** (`.gd` / `.cs`) — code attached to one node, giving it behavior. Attach to the scene
|
|
14
|
+
root; treat children as parts the root drives.
|
|
15
|
+
- **Resource** (`.tres` / `.res`) — a reference-counted **data** object, not in the tree. Textures,
|
|
16
|
+
audio, materials are Resources; so are your **custom** data classes.
|
|
17
|
+
|
|
18
|
+
## Composition over inheritance / deep trees
|
|
19
|
+
|
|
20
|
+
Prefer assembling small scenes over one giant tree or a deep script inheritance chain.
|
|
21
|
+
|
|
22
|
+
- A `Player` scene = `CharacterBody2D` root + `Sprite2D` + `CollisionShape2D` + `Camera2D` +
|
|
23
|
+
instanced `HealthComponent` + `HurtboxComponent` sub-scenes.
|
|
24
|
+
- Behaviors as **components**: a `HealthComponent` (its own scene/script exposing `signal died`) can
|
|
25
|
+
be dropped onto a player, an enemy, or a crate — no shared base class needed.
|
|
26
|
+
- Reach for `extends MyBase` only for genuine "is-a" specialization; reach for composed child nodes
|
|
27
|
+
for "has-a" behavior. The latter is the Godot-idiomatic default.
|
|
28
|
+
|
|
29
|
+
## `class_name` — when to register a global type
|
|
30
|
+
|
|
31
|
+
```gdscript
|
|
32
|
+
class_name HealthComponent extends Node
|
|
33
|
+
signal died
|
|
34
|
+
@export var max_health := 100
|
|
35
|
+
var _current := max_health
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- Register (`class_name`) reusable scripts and **all** custom Resources — it enables `is`/`as`
|
|
39
|
+
checks, `HealthComponent.new()`, and a proper inspector type/slot.
|
|
40
|
+
- Skip it for one-off scene-root scripts that nothing else references by type.
|
|
41
|
+
- Names are global and must be unique across the project.
|
|
42
|
+
|
|
43
|
+
## Custom Resources — typed game data
|
|
44
|
+
|
|
45
|
+
Use a custom `Resource` instead of loose `Dictionary`/JSON whenever you have structured game data:
|
|
46
|
+
stats, items, dialogue lines, wave definitions, ability configs. You get inspector editing, type
|
|
47
|
+
safety, `@export` slots, and save/load for free.
|
|
48
|
+
|
|
49
|
+
```gdscript
|
|
50
|
+
# item.gd
|
|
51
|
+
class_name Item extends Resource
|
|
52
|
+
@export var display_name: String = ""
|
|
53
|
+
@export var icon: Texture2D
|
|
54
|
+
@export var max_stack: int = 99
|
|
55
|
+
@export var value: int = 0
|
|
56
|
+
```
|
|
57
|
+
```gdscript
|
|
58
|
+
# Use it as a typed @export slot on any node:
|
|
59
|
+
@export var starting_items: Array[Item] = []
|
|
60
|
+
|
|
61
|
+
# Create/save/load in code:
|
|
62
|
+
var potion := Item.new()
|
|
63
|
+
potion.display_name = "Potion"
|
|
64
|
+
ResourceSaver.save(potion, "res://data/potion.tres")
|
|
65
|
+
var loaded := load("res://data/potion.tres") as Item
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Gotcha — shared vs unique**: a Resource assigned in the inspector is **shared by reference** across
|
|
69
|
+
all instances by default. If each node must own its copy (e.g. runtime-mutated stats), enable
|
|
70
|
+
**Local to Scene** on the resource, or `duplicate()` it in `_ready()`. Otherwise mutating one
|
|
71
|
+
enemy's `stats.health` mutates every enemy sharing that `.tres`.
|
|
72
|
+
|
|
73
|
+
## `preload` vs `load`
|
|
74
|
+
|
|
75
|
+
| | `preload("res://x")` | `load("res://x")` |
|
|
76
|
+
| --- | --- | --- |
|
|
77
|
+
| Resolved | parse/compile time | runtime, when the line runs |
|
|
78
|
+
| Path | must be a constant literal | can be a variable/computed |
|
|
79
|
+
| Use for | assets you always need; breaks fast if the path is wrong | dynamic/optional assets, avoiding circular preloads |
|
|
80
|
+
| Returns | the Resource/`PackedScene` | same |
|
|
81
|
+
|
|
82
|
+
```gdscript
|
|
83
|
+
const BULLET := preload("res://bullet.tscn") # PackedScene, baked in
|
|
84
|
+
func shoot() -> void:
|
|
85
|
+
var b := BULLET.instantiate() # -> a Node
|
|
86
|
+
add_child(b)
|
|
87
|
+
|
|
88
|
+
# runtime path
|
|
89
|
+
var scene := load("res://enemies/%s.tscn" % enemy_id) as PackedScene
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Instancing & freeing lifecycle
|
|
93
|
+
|
|
94
|
+
- `PackedScene.instantiate()` → a detached node; add it with `add_child(node)` (or
|
|
95
|
+
`add_sibling`) to bring it into the tree and trigger `_ready`.
|
|
96
|
+
- Free with `queue_free()` (deferred to end of frame — safe during signals/physics). Avoid `free()`
|
|
97
|
+
unless you know the node is out of the tree and not mid-callback.
|
|
98
|
+
- After freeing, guard any retained reference with `is_instance_valid(node)` before touching it.
|
|
99
|
+
- `add_child(node, true)` forces a readable unique name; useful when spawning many of one scene.
|
|
100
|
+
|
|
101
|
+
## `.tscn` / `.tres` are strict text — validation rule
|
|
102
|
+
|
|
103
|
+
Both formats are line-oriented with a header (`[gd_scene load_steps=N format=3 ...]`),
|
|
104
|
+
`[ext_resource ...]` / `[sub_resource ...]` blocks, and `[node ...]` / property lines. A wrong
|
|
105
|
+
`load_steps` count, a dangling `ExtResource("x")` id, or a malformed `[node]` path makes Godot
|
|
106
|
+
refuse to open the file. **Do not machine-generate or hand-edit these beyond trivial value tweaks,
|
|
107
|
+
and always open the project in the editor once before relying on a changed scene** — the editor is
|
|
108
|
+
the only reliable validator. Build data-Resources in code + `ResourceSaver.save()` instead of
|
|
109
|
+
writing `.tres` by hand.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: level-design
|
|
3
|
+
description: "Use when designing a game level, map, arena, or encounter — laying out a blockout/greybox, fixing pacing that drags or spikes, guiding players without hand-holding, placing secrets and rewards, or diagnosing a level that plays as boring, confusing, or where players get lost or stuck. Engine-agnostic craft: the blockout->greybox->playtest->art pipeline, sightlines and landmarks, tension/release rhythm, the introduce->develop->twist->combine encounter progression, readability via light/color/composition, and traversal heatmaps. Triggers: 'design this level', 'my level is boring/confusing', 'players keep getting lost', 'how do I pace this', 'blockout', 'greybox', 'encounter design', 'where do I put the secret'. NOT systemic mechanics or economy tuning (that's game-design), NOT narrative or story beats (that's game-storytelling), and NOT engine-specific level tooling — nav meshes, occlusion, tilemap editors, lightmap baking (that's the godot/unity/unreal skill)."
|
|
4
|
+
tags: [level-design, blockout, pacing, encounter, playtest]
|
|
5
|
+
recommends: [game-design, godot, unity, unreal]
|
|
6
|
+
profiles: [full]
|
|
7
|
+
origin: risco
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Level design — space that plays before it's pretty
|
|
11
|
+
|
|
12
|
+
*Shape the space, the rhythm, and the encounters so the player always knows where to go, never gets bored, and feels smart for exploring. Prove it in grey boxes; add art last.*
|
|
13
|
+
|
|
14
|
+
This skill owns the **craft of physical space and its play**: how a level is laid out, how it reads, how its intensity rises and falls, how encounters teach, and where reward hides. It is **engine-agnostic** — every technique here is validated in a blockout, then handed to an engine skill for the actual tooling (nav meshes, occlusion, lightmaps, tilemaps). It does not design the mechanics the level exercises (that's the systemic layer) or write the story it tells.
|
|
15
|
+
|
|
16
|
+
## When to use / When NOT to use
|
|
17
|
+
|
|
18
|
+
**Use when:** blocking out a new level/map/arena; a level playtests as boring, confusing, or too hard/easy; players get lost or stuck; you need to pace a level, space encounters, or add breathers; you're guiding players without arrows/waypoints; placing secrets, rewards, or shortcuts; teaching a mechanic through the space itself.
|
|
19
|
+
|
|
20
|
+
**Do NOT use for:**
|
|
21
|
+
|
|
22
|
+
- **Systemic / mechanic design** — the verbs, rules, economy, and numbers the player brings *into* the level (jump height as a rule, weapon balance, loot tables, progression systems). That's `game-design`. This skill *exercises* those verbs in space; it doesn't invent or tune them.
|
|
23
|
+
- **Narrative, quests, dialogue, environmental story beats** — what the space *says*. That's `game-storytelling`. Level design places the beat; storytelling writes it.
|
|
24
|
+
- **Engine-specific level tooling** — nav-mesh baking, occlusion culling, terrain/tilemap/ProBuilder editors, lightmap/GI bakes, streaming volumes, collision setup. Defer to `godot` / `unity` / `unreal`. This skill decides *what* the space must do; the engine skill implements *how*.
|
|
25
|
+
|
|
26
|
+
## The craft laws (non-negotiable)
|
|
27
|
+
|
|
28
|
+
1. **Art last.** Never model or texture a space you haven't proven fun in blockout. Art-first means reworking expensive assets when the layout inevitably changes.
|
|
29
|
+
2. **Metrics before geometry.** Lock the player's dimensions (height, jump, reach, cover) first; build everything as multiples of them. → `references/blockout-to-art.md`
|
|
30
|
+
3. **The player always knows where to go, never how it ends.** Guide the critical path; leave exploration to earn its own reward. Lostness is a readability bug, not player error.
|
|
31
|
+
4. **Watch, don't tell.** A level is only as good as it plays for someone you didn't coach. Every claim ("this is obvious", "the fight is fun") is a hypothesis until a fresh player validates it.
|
|
32
|
+
5. **Rhythm, not a flat line.** Intensity must rise and fall. Sustained peak = fatigue; sustained calm = boredom. Design the graph, not just the rooms.
|
|
33
|
+
6. **Teach through space, not text.** Introduce a threat where it's safe to learn it, before it can kill.
|
|
34
|
+
|
|
35
|
+
## The pipeline: blockout -> greybox -> playtest -> art (never art-first)
|
|
36
|
+
|
|
37
|
+
| Stage | You build | You answer | Gate to next |
|
|
38
|
+
|---|---|---|---|
|
|
39
|
+
| **Blockout** | Primitive geometry only (boxes/planes at true metrics). No materials, no props. | Does the space flow? Are timings/distances right? Can I find my way? | Layout & traversal feel right. |
|
|
40
|
+
| **Greybox** | Blockout + temp neutral materials, placeholder lighting, stand-in enemies/interactables. | Does it *read*? Does the fight/encounter work? Is pacing right? | Encounters and readability hold up in playtest. |
|
|
41
|
+
| **Playtest** | Nothing — you watch fresh players. | Where do they hesitate, get lost, die, skip? | Fixes are cheap because it's still grey. |
|
|
42
|
+
| **Art pass** | Meshes, materials, VFX, final lighting, audio — *serving* the proven layout. | Does art reinforce the guidance the greybox already established? | Ship. |
|
|
43
|
+
|
|
44
|
+
Iterate blockout↔playtest many times before art. Changing a grey box is minutes; changing a finished art set-piece is days. Full stage detail, the metrics block, and the art-pass handoff checklist → `references/blockout-to-art.md`.
|
|
45
|
+
|
|
46
|
+
## Spatial composition — leading the eye
|
|
47
|
+
|
|
48
|
+
- **Sightlines are your steering wheel.** Control what's visible from each point: frame the objective in a doorway/arch, block distracting views, open a reveal at the moment of a decision.
|
|
49
|
+
- **Landmarks (the "weenie").** One large, distinct, distant silhouette per area that the player orients toward (tower, spire, mountain) — Disney's term for the visual magnet that pulls you forward. Self-locating beats a minimap.
|
|
50
|
+
- **Lead the eye** with converging lines (rails, beams), framing (foreground arches), contrast (a bright end to a dark corridor), and motion. The eye goes to the brightest, highest-contrast, most-different thing — put that on the path you want taken.
|
|
51
|
+
- **Silhouette readability.** Enemies, interactables, and hazards must read by shape alone at a glance. Two things sharing a silhouette is an unintended trap.
|
|
52
|
+
- **Golden path vs exploration.** The **critical path** is the always-legible guaranteed route to the objective; **exploration** is optional branches and loops off it. Prefer loops that return the player forward (avoid dead-end backtracking); breadcrumb side routes with a visible reward.
|
|
53
|
+
|
|
54
|
+
Framing, contrast, and layout topologies (loops, hubs, gates) → `references/guidance-and-readability.md`.
|
|
55
|
+
|
|
56
|
+
## Pacing & rhythm — tension and release
|
|
57
|
+
|
|
58
|
+
Design the **intensity graph** for the whole level, not room by room. A good level is a sawtooth trending upward: each peak (combat, platforming gauntlet, chase) followed by a valley — a **safe room / breather** with no threat, low stimulus, often a save/restock.
|
|
59
|
+
|
|
60
|
+
- **Space encounters in time and distance, and *vary* both** — three identical-length fights back to back feel like one long slog.
|
|
61
|
+
- **Breathers earn the next peak.** The calm between (Halo's cadence is often described as "thirty seconds of fun" on repeat) is what makes the fun read as fun. Use it to let adrenaline drop, reward observation, and telegraph the next escalation.
|
|
62
|
+
- **Difficulty within the level** trends up but resets at checkpoints — re-enter competent, then ramp. End on the hardest, most spectacular test, not a whimper.
|
|
63
|
+
- **Contrast the modes** (fast↔slow, loud↔quiet, open↔tight, combat↔traversal↔puzzle). Monotony of *any* mode reads as boredom even if each moment is individually good.
|
|
64
|
+
|
|
65
|
+
Intensity-graph template, breather patterns, and difficulty-curve worked example → `references/pacing-and-encounters.md`.
|
|
66
|
+
|
|
67
|
+
## Encounter design — introduce, develop, twist, combine
|
|
68
|
+
|
|
69
|
+
The four-beat progression teaches a mechanic/threat through space (the pattern behind Portal, Half-Life 2, and Mario level craft):
|
|
70
|
+
|
|
71
|
+
1. **Introduce** — meet the new element somewhere it *can't* hurt you. A single turret across a safe gap; one platform of the new hazard. Learn it risk-free.
|
|
72
|
+
2. **Develop** — use it for real, low stakes. The turret now guards a corridor you must cross.
|
|
73
|
+
3. **Twist** — recontextualize it. Two turrets flanking; the turret is *behind* glass; you must use the turret against enemies. The rule bends.
|
|
74
|
+
4. **Combine** — the mastery test: the new element plus everything learned earlier, at full intensity.
|
|
75
|
+
|
|
76
|
+
Design rules for the **arena** (the shape a fight happens in):
|
|
77
|
+
|
|
78
|
+
- **Match sightline length to weapon/threat range** — long lanes favor ranged, tight rooms favor melee/shotgun. The geometry *is* the difficulty knob.
|
|
79
|
+
- **Cover rhythm, flanks, verticality.** Space cover so the player advances in beats; give at least one flank so a fight isn't a static peek-war; use height for pressure and reward (the Doom-2016 arena: multi-tier, resources placed to pull the player *through* the space, not hunker).
|
|
80
|
+
- **Chokepoints need release valves** — pair a choke with an exit or a way to break the standoff, or the fight stalls.
|
|
81
|
+
- **An encounter = enemy composition × space × objective × resources.** Change any one for a "new" encounter without new assets.
|
|
82
|
+
|
|
83
|
+
Encounter template, arena patterns, and a full introduce→develop→twist→combine example → `references/pacing-and-encounters.md`.
|
|
84
|
+
|
|
85
|
+
## Guidance & readability — direct without hand-holding
|
|
86
|
+
|
|
87
|
+
Guide with the environment so you never need a floating arrow:
|
|
88
|
+
|
|
89
|
+
- **Light leads.** Players move toward light (the moth effect) and higher value-contrast. Light the path, objective, and exit; keep dead-ends dim. Placeholder lighting is a greybox *design* tool, not a final-art afterthought.
|
|
90
|
+
- **Reserve one accent color for "you can interact / go here"** (Mirror's Edge runner red, Dishonored's usable glint) and **never** use it decoratively. Consistency is the whole point; break it once and you've lied to the player.
|
|
91
|
+
- **Composition** — framing, leading lines, and negative space point the eye like a photographer's shot. The critical path should be the most-framed, highest-contrast route from any decision point.
|
|
92
|
+
- **Affordances & signifiers** (Norman/Gibson): a ledge that looks grabbable must be grabbable. Establish the visual language early and hold it — if a trim means "climb here", it appears *only* where you can climb. Inconsistent affordances are the #1 cause of "I didn't know I could do that."
|
|
93
|
+
- **Deny wrong turns visually** (subtle dead-ends, unlit gaps, a "not-a-path" material) rather than with invisible collision.
|
|
94
|
+
|
|
95
|
+
Full catalog — lighting/color/composition, the affordance language, the "critical-path readability" self-test → `references/guidance-and-readability.md`.
|
|
96
|
+
|
|
97
|
+
## Metrics & playtesting — where players get lost and stuck
|
|
98
|
+
|
|
99
|
+
You cannot see your own level fresh. **Observe, don't coach:**
|
|
100
|
+
|
|
101
|
+
- **Watch a first-timer play, silent.** Note every hesitation (readability gap), wrong turn (navigation gap), repeated death (telegraph/difficulty gap), and skipped content (reward-placement gap). Do **not** answer "where do I go?" — that question *is* the finding.
|
|
102
|
+
- **Traversal telemetry** turns anecdote into pattern: **position heatmaps** (cold zones players never enter = wasted level), **death heatmaps** (clusters = unfair/unreadable threats), **path traces** (golden path or lost?), **dwell time** at forks (long dwell = unclear guidance), and **look/aim heatmaps** (did they even see the landmark?).
|
|
103
|
+
- **Read the map:** a cold region means the space doesn't pull the player there — re-light, add a landmark/reward, or cut it. A death cluster means fix the telegraph or arena, not the player. A branch nobody takes needs a visible reward at its mouth.
|
|
104
|
+
|
|
105
|
+
Playtest protocol, question scripts, and turning heatmaps into fixes → `references/guidance-and-readability.md`.
|
|
106
|
+
|
|
107
|
+
## Reward & secret placement, risk vs reward
|
|
108
|
+
|
|
109
|
+
- **Reward the wandering eye.** Put secrets where a *curious* player naturally looks — behind the waterfall, up the ledge you already lit and framed, down the branch you breadcrumbed. Reward observation, not pixel-hunting; a secret nobody can reasonably find just frustrates.
|
|
110
|
+
- **Breadcrumb the secret** with a glint, an out-of-place object, a suspicious seam, an "impossible" bit of geometry visible from the path. The player should feel *clever* — which means the game showed them the thread first.
|
|
111
|
+
- **Risk vs reward.** Gate the best optional reward behind the biggest optional risk or detour. Keep the *critical path* rewarding on its own so risk-averse players aren't punished; put the *extra* behind the extra effort, both visible before committing.
|
|
112
|
+
- **Never hide mandatory progression like a secret** — a required key/door disguised as optional is a stuck-player generator. Secrets are optional by definition.
|
|
113
|
+
- **Vary reward types**: power/upgrade, resources, lore/collectible, a **shortcut unlock** (best long-term — reshapes the level), and pure spectacle.
|
|
114
|
+
|
|
115
|
+
Reward taxonomy, secret-signposting, and risk/reward tuning → `references/guidance-and-readability.md`.
|
|
116
|
+
|
|
117
|
+
## Anti-patterns / rationalizations -> STOP
|
|
118
|
+
|
|
119
|
+
| Rationalization | Reality / Fix |
|
|
120
|
+
|---|---|
|
|
121
|
+
| "Let's make it look good first, then tune the layout." | Art-first burns days reworking assets when the layout changes. Blockout, playtest, *then* art. |
|
|
122
|
+
| "It's obvious where to go." | Obvious to *you*, the author. Fresh players get lost. Watch one before you believe it. |
|
|
123
|
+
| "I'll just add a waypoint arrow / big text prompt." | That's a patch over a readability failure. Fix it with light, framing, and a landmark first. |
|
|
124
|
+
| "The whole level is intense — it's exciting!" | Sustained peak = fatigue and it all flattens into noise. Add breathers so the peaks read. |
|
|
125
|
+
| "Backtracking reuses the space for free." | Repeated dead-end backtracking reads as padding. Use loops that return the player forward. |
|
|
126
|
+
| "Players will figure the new mechanic out." | Not while it's killing them. Introduce it where it's safe, then develop/twist/combine. |
|
|
127
|
+
| "Yellow paint everywhere so they see the ledges." | Only if yellow means *exactly* climbable and appears nowhere else. Inconsistent affordances lie. |
|
|
128
|
+
| "The secret's hidden well — no one will find it." | A secret with no breadcrumb is just frustration. Show the thread; reward the curious eye. |
|
|
129
|
+
| "The gap/cover/door width feels about right." | Guessing metrics breaks traversal later. Set the metrics block first; build to multiples. |
|
|
130
|
+
|
|
131
|
+
## Quick reference
|
|
132
|
+
|
|
133
|
+
| Lever | Default | Where |
|
|
134
|
+
|---|---|---|
|
|
135
|
+
| Build order | blockout → greybox → playtest → art (art last) | `references/blockout-to-art.md` |
|
|
136
|
+
| Metrics block | lock player height/jump/reach/cover first; build to multiples | `references/blockout-to-art.md` |
|
|
137
|
+
| Navigation | one dominant landmark per area; legible critical path + breadcrumbed loops | `references/guidance-and-readability.md` |
|
|
138
|
+
| Pacing | sawtooth: peak → breather (safe room) → higher peak | `references/pacing-and-encounters.md` |
|
|
139
|
+
| Encounter teaching | introduce → develop → twist → combine | `references/pacing-and-encounters.md` |
|
|
140
|
+
| Arena shape | sightline length matched to threat range; flanks + verticality | `references/pacing-and-encounters.md` |
|
|
141
|
+
| Guidance | light leads; one reserved interact color; consistent affordances | `references/guidance-and-readability.md` |
|
|
142
|
+
| Playtest | watch silent; log hesitation/lost/death/skip; read heatmaps | `references/guidance-and-readability.md` |
|
|
143
|
+
| Secrets / risk | breadcrumb them; best optional reward behind biggest optional risk | `references/guidance-and-readability.md` |
|
|
144
|
+
|
|
145
|
+
## Related skills
|
|
146
|
+
|
|
147
|
+
- **`game-design`** — the systemic layer: mechanics, verbs, economy, progression, difficulty *systems*. Level design exercises those verbs in space; if the request is about the rules themselves, route there.
|
|
148
|
+
- **`game-storytelling`** — narrative, quests, dialogue, and the meaning of environmental beats. Level design places the beat; storytelling authors it.
|
|
149
|
+
- **`godot` / `unity` / `unreal`** — the engine tooling that *implements* a proven layout: nav meshes, occlusion, terrain/tilemap editors, lightmap/GI bakes, streaming, collision. Hand off here after the blockout plays well.
|
|
150
|
+
- **`harness`** — the `02-DOCS` Karpathy-wiki this skill records level conventions into.
|
|
151
|
+
- **References:** `references/blockout-to-art.md` (pipeline, metrics block, art handoff, playtesting the blockout); `references/pacing-and-encounters.md` (intensity graph, encounter template, arena patterns, difficulty curve); `references/guidance-and-readability.md` (light/color/composition, affordances, playtest protocol, telemetry, reward & secrets).
|
|
152
|
+
|
|
153
|
+
## Checklist
|
|
154
|
+
|
|
155
|
+
- [ ] Player metrics block locked (height, jump, reach, cover, door/corridor widths) before geometry.
|
|
156
|
+
- [ ] Layout proven in blockout/greybox — never modeled or textured before it plays well.
|
|
157
|
+
- [ ] Critical path is legible from every decision point; a fresh player can find the objective without being told.
|
|
158
|
+
- [ ] One dominant landmark orients each area; light and framing lead the eye along the intended path.
|
|
159
|
+
- [ ] Intensity graph is a sawtooth (peaks + breathers), not a flat line; encounters vary in length and spacing.
|
|
160
|
+
- [ ] At least one safe room / breather follows each major peak.
|
|
161
|
+
- [ ] Every new mechanic/threat is introduced safely, then developed, twisted, and combined.
|
|
162
|
+
- [ ] Arenas match sightline length to threat range and offer a flank/verticality option, not a static peek-war.
|
|
163
|
+
- [ ] One reserved accent color for interactables/path, used consistently and never decoratively; affordances hold everywhere.
|
|
164
|
+
- [ ] Played by a fresh, uncoached tester (and/or telemetry): hesitations/lost/deaths/skips logged, no dead cold-zones, no unfair death clusters, no ignored branches.
|
|
165
|
+
- [ ] Secrets are breadcrumbed and reward observation; no mandatory progression hidden as a secret; best optional reward sits behind the biggest optional risk.
|
|
166
|
+
|
|
167
|
+
## Project grounding (02-DOCS + CLAUDE.md)
|
|
168
|
+
|
|
169
|
+
When this skill runs in a project with a `02-DOCS/` layer (the [`harness`](../harness/SKILL.md) Karpathy wiki), record the level-design conventions there and index them from the root `CLAUDE.md`, so the next agent inherits them instead of re-deriving:
|
|
170
|
+
|
|
171
|
+
1. **Find the article** `02-DOCS/wiki/stack/level-design.md`, indexed in `02-DOCS/wiki/index.md` (the Knowledge map).
|
|
172
|
+
2. **If missing or stale**, create/update it with the project's real conventions — the metrics block, the reserved interact-color, the pacing/breather cadence, the encounter-teaching pattern, and any per-level intensity graphs — then index it.
|
|
173
|
+
3. **Read it first on every use** and stay consistent; when a convention changes, update the article (bump its `Updated` date) in the same change.
|
|
174
|
+
|
|
175
|
+
No `02-DOCS/` layer? Skip silently (optionally suggest `harness`). Conventions are *recorded, not gated* — never block the design work on this.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Eval harness — level-design
|
|
2
|
+
|
|
3
|
+
These evals assert two things about the `level-design` skill. **Triggering:** it
|
|
4
|
+
fires on level layout, pacing, encounter, guidance, and reward requests, and
|
|
5
|
+
stays out of systemic mechanic/economy design (`game-design`), narrative
|
|
6
|
+
(`game-storytelling`), and engine-specific level tooling (`godot`/`unity`/
|
|
7
|
+
`unreal`). **Capability:** when engaged, it delivers the craft — the
|
|
8
|
+
blockout→art pipeline, the sawtooth intensity graph with breathers, the
|
|
9
|
+
introduce→develop→twist→combine teaching pattern, light/color/affordance
|
|
10
|
+
guidance, and observe-don't-coach playtesting — rather than generic advice.
|
|
11
|
+
|
|
12
|
+
## How to run
|
|
13
|
+
|
|
14
|
+
Run through an agent harness with skills loadable on demand; `cases.yaml` is the
|
|
15
|
+
fixture. Use the same model for every trial; vary only which skills are loaded.
|
|
16
|
+
|
|
17
|
+
- **Triggering:** load the full catalog so the agent can route to siblings; feed
|
|
18
|
+
each `should_trigger` / `should_not_trigger` prompt verbatim and record which
|
|
19
|
+
skill fires. Run 3–5 trials per prompt (the choice is stochastic).
|
|
20
|
+
- Pass: `should_trigger` selects **level-design** in the majority of trials;
|
|
21
|
+
`should_not_trigger` does not (ideally routes to the listed `route_to`).
|
|
22
|
+
- Bar: **≥90%** trigger accuracy across all prompts.
|
|
23
|
+
- **Capability:** run each scenario WITH only level-design loaded vs WITHOUT any
|
|
24
|
+
skill (baseline), 3 times each. Grade responses against the `must_include`
|
|
25
|
+
rubric, one point per checkable item genuinely present.
|
|
26
|
+
- Bar: WITH covers **≥80%** of items on average AND beats WITHOUT by **≥25**
|
|
27
|
+
percentage points (a skill that doesn't move the needle fails).
|
|
28
|
+
|
|
29
|
+
## Notes / honesty
|
|
30
|
+
|
|
31
|
+
- LLM-graded and stochastic — re-run on edits; treat small deltas as noise.
|
|
32
|
+
- `route_to` targets assume the sibling skills (`game-design`,
|
|
33
|
+
`game-storytelling`, `godot`, `unity`, `unreal`) exist in the catalog; a
|
|
34
|
+
missing sibling can cause a near-miss to mis-route without it being a
|
|
35
|
+
level-design fault — note it, don't count it against this skill.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
skill: level-design
|
|
2
|
+
|
|
3
|
+
should_trigger:
|
|
4
|
+
- prompt: "I've built the first level of my platformer but playtesters say it's boring in the middle and then brutal at the end. How do I fix the pacing?"
|
|
5
|
+
why: "Direct pacing complaint on a built level — the intensity-graph / sawtooth + breather guidance. 'Boring in the middle, brutal at the end' is a flat-then-spike curve the skill diagnoses."
|
|
6
|
+
- prompt: "Players keep getting lost in my second map — they wander into dead ends and can't find the exit. What am I doing wrong?"
|
|
7
|
+
why: "Navigation/readability failure ('players get lost') — the skill's guidance layer: landmarks, light-led critical path, denying wrong turns visually. Lostness is a readability bug the skill owns."
|
|
8
|
+
- prompt: "How should I lay out the blockout for a new FPS arena before I start making art?"
|
|
9
|
+
why: "Explicit blockout request and the blockout->greybox->playtest->art pipeline plus metrics block and arena-shape design. Core Use-when trigger."
|
|
10
|
+
- prompt: "I want to teach the player how a new grappling-hook mechanic works through the level itself, without a tutorial popup. How do I structure that?"
|
|
11
|
+
why: "Teaching a mechanic through space = introduce->develop->twist->combine. The mechanic itself is game-design's, but structuring the SPACE that teaches it is level design."
|
|
12
|
+
- prompt: "Where should I put the secret rooms and the best loot in my dungeon so exploring feels rewarding but not frustrating?"
|
|
13
|
+
why: "Reward & secret placement + risk/reward + breadcrumbing. 'Rewarding but not frustrating' is exactly the reward-the-observation-not-the-pixel-hunt guidance."
|
|
14
|
+
- prompt: "My combat arena feels like everyone just hides behind one wall and pokes out. How do I make the fights more dynamic?"
|
|
15
|
+
why: "Arena-shape design: static peek-war means missing flanks/verticality and bad cover rhythm. The skill's encounter/arena section addresses this directly."
|
|
16
|
+
- prompt: "How do I guide players toward the objective using lighting and color instead of a giant waypoint marker?"
|
|
17
|
+
why: "Guidance without hand-holding via light/color/composition and the reserved interact-color language. Explicit 'instead of a waypoint' framing is the skill's core."
|
|
18
|
+
|
|
19
|
+
should_not_trigger:
|
|
20
|
+
- prompt: "How high should the player be able to jump and how much should double-jump cost stamina? I'm balancing the movement system."
|
|
21
|
+
route_to: "game-design"
|
|
22
|
+
why: "This is the movement RULE/economy itself (systemic mechanic + stamina cost tuning), which game-design owns. Level design consumes the jump metric; it doesn't set or balance it."
|
|
23
|
+
- prompt: "Write the environmental storytelling and the audio-log script for the abandoned lab area to reveal the backstory."
|
|
24
|
+
route_to: "game-storytelling"
|
|
25
|
+
why: "Narrative content — what the space SAYS (backstory, audio-log writing). Level design places the beat; game-storytelling authors it."
|
|
26
|
+
- prompt: "How do I bake the nav mesh and set the agent radius so enemies path around my level geometry in Unity?"
|
|
27
|
+
route_to: "unity"
|
|
28
|
+
why: "Engine-specific level tooling (nav-mesh bake, agent radius in Unity). Explicitly out of scope; the engine skill implements the layout the design decided."
|
|
29
|
+
- prompt: "My Godot TileMap isn't showing collision on the ground layer and the player falls through. How do I fix it?"
|
|
30
|
+
route_to: "godot"
|
|
31
|
+
why: "Engine tooling bug — TileMap collision setup in Godot. This is implementation, not the craft of layout/pacing/readability."
|
|
32
|
+
- prompt: "How should I design the loot rarity tiers and drop-rate curves for the whole game's economy?"
|
|
33
|
+
route_to: "game-design"
|
|
34
|
+
why: "Loot-table / economy systems design across the whole game — a systemic concern game-design owns, not the placement of a reward within one level's space."
|
|
35
|
+
- prompt: "How do I optimize the frame rate in my Unreal level — the shadows and draw calls are tanking performance?"
|
|
36
|
+
route_to: "unreal"
|
|
37
|
+
why: "Engine performance/rendering optimization (draw calls, shadow cost) is engine tooling, owned by the unreal skill, not level-design craft."
|
|
38
|
+
|
|
39
|
+
capability:
|
|
40
|
+
- scenario: "A designer says: 'My level's first playthrough is fun but by the middle testers get bored and then the final room feels unfairly hard. It's already fully textured and lit. How do I fix it?'"
|
|
41
|
+
must_include:
|
|
42
|
+
- "Diagnoses a flawed intensity curve (flat/boring middle, spike at the end) and prescribes a sawtooth: peaks with breathers/safe rooms between, difficulty trending up with checkpoint resets."
|
|
43
|
+
- "Recommends adding a breather/safe room after peaks so intensity drops and the next peak reads, and varying encounter length/spacing to kill the monotony."
|
|
44
|
+
- "Flags that the level is already textured/lit as a process problem — layout changes should be validated in blockout/greybox, and warns that art-first makes pacing fixes expensive."
|
|
45
|
+
- "Frames the final-room spike as a telegraph/difficulty-curve issue (signpost the ramp, reset at a checkpoint) rather than just lowering difficulty."
|
|
46
|
+
- scenario: "A developer asks: 'Players keep getting lost in my level and walk right past the exit. I don't want to add a waypoint arrow. How do I guide them?'"
|
|
47
|
+
must_include:
|
|
48
|
+
- "Treats lostness as a readability/guidance bug, not player error, and keeps guidance diegetic (no waypoint)."
|
|
49
|
+
- "Uses light to lead (players move toward light/contrast; light the critical path, objective, and exit; keep dead-ends dim)."
|
|
50
|
+
- "Establishes a dominant landmark per area for self-location and frames the exit with composition/leading lines."
|
|
51
|
+
- "Recommends a reserved, consistent accent color for interactables/path used nowhere decoratively, and consistent affordances."
|
|
52
|
+
- "Prescribes watching a fresh, uncoached playtester (and/or position/dwell heatmaps) to locate exactly where players hesitate or diverge, without answering 'where do I go?'."
|
|
53
|
+
- scenario: "A designer asks: 'I have a new mechanic — a portal gun — and I want the level to teach it without any text tutorial.'"
|
|
54
|
+
must_include:
|
|
55
|
+
- "Lays out the introduce -> develop -> twist -> combine progression (or equivalent teach-through-space structure)."
|
|
56
|
+
- "Introduces the mechanic somewhere it cannot hurt the player (safe, zero-risk first encounter) before any real stakes."
|
|
57
|
+
- "Builds up through low-stakes use, a recontextualizing twist, and a final combine/mastery test that layers earlier learning."
|
|
58
|
+
- "Notes that the space itself teaches (no tutorial popup) and that the mechanic's rules belong to game-design while the teaching layout is level design."
|