
Godot Auditor
- 96 installs
- 454 repo stars
- Updated July 28, 2026
- thedivergentai/gd-agentic-skills
Helps with ai & agent building tasks during AI-assisted development.
About
godot-auditor is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- godot-auditor
- AI & Agent Building
- AI-coding skill
Godot Auditor by the numbers
- 96 all-time installs (skills.sh)
- +20 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #4,561 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-auditorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 96 |
|---|---|
| repo stars | ★ 454 |
| Last updated | July 28, 2026 |
| Repository | thedivergentai/gd-agentic-skills ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
📜 Aurelius Expert Audit Standards (Godot 4.6+)
This document defines the technical benchmarks for the Aurelius Protocol. These standards represent the "Gold Standard" for professional-grade Godot 4.6 development.
---
🏛️ Architectural Integrity (The "Foundational Pillars")
1. The Bridge Pattern (UI-to-Logic)
- Standard: Direct node references between UI and Game Logic are PROHIBITED.
- Expert Pattern: Use a "Bridge" Resource or a dedicated "UIController" that listens for Signal Bus events.
- Reasoning: Decouples UI skinning from core mechanics, allowing for easy UI redesigns without breaking game logic.
2. Signal Topology (The "Signal-Up" Mandate)
- Standard: Signals must flow UP the scene tree. Calls must flow DOWN.
- Violation: A child node calling
get_parent().update_score(). - Correct Protocol: Child emits
score_changed(delta); Parent connects to its child and handles the method call.
3. Composition via Node-Components
- Standard: Favor shallow inheritance (max 3 levels). Use "Actor Components" (Node-based) for reusable behaviors.
- Expert Pattern:
HitboxComponent,HealthComponent,AIControllerComponent.
---
⚡ Performance Protocol (Godot 4.6 Nuances)
1. The "Main Thread" Sanctuary
- Standard: Any operation taking > 2ms (e.g., massive JSON parsing, long-distance pathfinding) MUST be offloaded.
- Expert Pattern: Use
WorkerThreadPool.add_task()for data-heavy tasks. UseThreadonly for dedicated long-running background loops.
2. RID-Level Management (Rendering Slop)
- Standard: Direct
RenderingServercalls for thousands of objects instead of тысячиSprite2Dnodes. - Expert Pattern: Use
RenderingServer.canvas_item_create()and RIDs for high-density particle/projectile systems outside of GPUParticles.
3. Type Safety & Hashing
- Standard: Typed Dictionaries and Arrays for ALL public APIs.
- Expert Pattern: Use
StringName(&"name") for all dictionary keys, signal names, and animation calls to avoid redundant hashing at runtime.
---
🛡️ Never vs Always (Expert Checklist)
| Topic | ❌ NEVER (Legacy Slop) | ✅ ALWAYS (Expert Protocol) |
|---|---|---|
| Signals | connect("string", ...) | signal_object.connect(callable) |
| Containers | var data := {} | var data: Dictionary[int, Resource] = {} |
| Nodes | get_node("../Sibling") | @export var sibling: Node |
| Strings | var x = "name" | var x = &"name" (StringName) |
| Timers | get_tree().create_timer() | Reusable Timer node or manual delta accumulation. |
| Loading | load("res://path") | preload("res://path") or ResourceLoader background tasks. |
--- Reference version 2.0.0 | Aurelius Protocol Authorized | Godot 4.6+ Verified
Aurelius Protocol: 2D Animation NEVER List
- NEVER use AnimatedTexture — This class is deprecated, highly inefficient in modern renderers, and may be removed in future Godot versions. Use AnimatedSprite2D or AnimationPlayer instead.
- NEVER allow Tweens to fight over the same property — If multiple Tweens animate the same property, the last one created forcibly takes priority. Always assign your Tween to a variable and call
kill()on the previous instance before creating a new one. - NEVER process kinematic movement outside the physics tick — If your AnimationPlayer moves a CharacterBody2D, ensure the AnimationPlayer's callback mode is set to Physics. Animating physics bodies during the Idle (render) frame breaks fixed timestep physics interpolation and causes stutter.
- NEVER use `animation_finished` for looping animations — The signal only fires on non-looping animations. Use
animation_loopedinstead for loop detection. - NEVER call `play()` and expect instant state changes — AnimatedSprite2D applies
play()on the next process frame. Calladvance(0)immediately afterplay()if you need synchronous property updates (e.g., when changing animation + flip_h simultaneously). - NEVER set `frame` directly when preserving animation progress — Setting
frameresetsframe_progressto 0.0. Useset_frame_and_progress(frame, progress)to maintain smooth transitions when swapping animations mid-frame. - NEVER forget to cache `@onready var anim_sprite` — The node lookup getter is surprisingly slow in hot paths like
_physics_process(). Always use@onready. - NEVER mix AnimationPlayer tracks with code-driven AnimatedSprite2D — Choose one animation authority per sprite. Mixing causes flickering and state conflicts.
- NEVER use paper-thin skeletons for deformation — 2D meshes require balanced vertex density. If your mesh deforms poorly, increase the vertex count near joints in the Mesh2D editor.
Aurelius Protocol: 2D Physics NEVER List
- NEVER scale `CollisionShape2D` nodes — Use the shape handles in the editor, NOT the Node2D scale property. Scaling causes unpredictable physics behavior and incorrect collision normals [12].
- NEVER confuse `collision_layer` with `collision_mask` — Layer = "What AM I?", Mask = "What do I DETECT?". Setting both to the same value is usually wrong [13].
- NEVER multiply velocity by delta when using `move_and_slide()` —
move_and_slide()automatically includes timestep. Only multiply gravity/acceleration by delta [14]. - NEVER forget `force_raycast_update()` for manual mid-frame raycasts — Raycasts update once per physics frame. If you change target_position, you MUST force an update [15].
- NEVER use `get_overlapping_bodies()` every frame — It is expensive. Cache results with
body_entered/body_exitedsignals instead [16]. - NEVER modify `RigidBody2D` state directly in `_process` — Use
_integrate_forces()for safe, synchronized access toPhysicsDirectBodyState2D[17, 411]. - NEVER move `PhysicsBody2D` nodes in `_process()` — Use
_physics_process(). Moving bodies outside the physics step causes stutter and unreliable collision detection. - NEVER use `RigidBody2D` for 1000+ simple entities — Use
PhysicsServer2Dto bypass node overhead for massive performance gains (Swarms/Bullets) [18, 397]. - NEVER use `Area2D` for high-frequency blocking (Bullets) — Area signals can be delayed. Use
move_and_collide()orShapeCast2Dfor frame-perfect results [19]. - NEVER ignore 'Physics Jitter' on high-refresh monitors — Enable Physics Interpolation to prevent micro-stutter in motion [21, 400].
- NEVER scale collision shapes directly at runtime — It causes major instability. Resize the shape resource (size/radius) instead.
- NEVER use `set_deferred` for immediate physics transform logic — It happens at the end of the frame. Use
force_raycast_update()orPhysicsServer2Dinstead. - NEVER leave Continuous CD (CCD) enabled for slow objects — It adds significant CPU overhead. Reserve it for high-speed projectiles to prevent tunneling.
- NEVER use a single collision layer for all tiles/entities — Separate layers (Ground, Walls, Enemies) to allow selective filtering via masks.
- NEVER forget to free `PhysicsServer2D` RIDs manually — They are not garbage collected and will leak memory permanently.
Aurelius Protocol: 3D Lighting NEVER List
- NEVER use VoxelGI without setting a proper extents — Unbound VoxelGI tanks performance. Always set
sizeto tightly fit your scene. - NEVER enable shadows on every light — Each shadow-casting light is expensive. Use shadows sparingly: 1-2 DirectionalLights, ~3-5 OmniLights max.
- NEVER forget directional_shadow_mode — Default is ORTHOGONAL. For large outdoor scenes, use PARALLEL_4_SPLITS for better shadow quality at distance.
- NEVER use LightmapGI for fully dynamic scenes — Lightmaps are baked. Moving geometry won't receive updated lighting. Use VoxelGI or SDFGI instead.
- NEVER set omni_range too large — Light attenuation is quadratic. A range of 500 affects 785,000 sq units. Keep range as small as visually acceptable.
- NEVER hide a Light node using the Visible property to exclude it from a Lightmap bake — Hiding a light has no effect on the baker. You must change the light's Bake Mode to Disabled.
- NEVER use VoxelGI with paper-thin walls — VoxelGI evaluates lighting using a 3D grid. Thin walls (less than one voxel thick) will cause severe light leaking. Seal your geometry or place hidden thick MeshInstance3D blocks around the exterior.
- NEVER leave shadow bias at default for cascades — Default bias often causes Peter Panning or light leaking at split transitions. Tune bias per-light based on your scene's scale.
- NEVER bake LightmapGI without a Denoiser — Godot's baked lightmaps are noisy by default. Use OIDN or JNLM (in Project Settings) for professional results.
- NEVER use real-time SDFGI on Mobile/Compatibility renderers — It is a Forward+ exclusive feature. Use fake GI bounce lights for lower-end platforms.
- NEVER use 'Update Continuity' in ReflectionProbes for performance — Keep ReflectionProbes on 'Update Once' and trigger manual updates only when necessary.
Aurelius Protocol: 3D Materials NEVER List
- NEVER use separate metallic/roughness/AO textures — Use ORM packing (1 RGB texture with Occlusion/Roughness/Metallic channels) to save texture slots and memory.
- NEVER forget to enable normal_enabled — Normal maps don't work unless you set
normal_enabled = true. Silent failure is common. - NEVER use TRANSPARENCY_ALPHA for cutout materials — Use TRANSPARENCY_ALPHA_SCISSOR or TRANSPARENCY_ALPHA_HASH instead. Full alpha blending is expensive and causes sorting issues.
- NEVER set metallic = 0.5 — Materials are either metallic (1.0) or dielectric (0.0). Values between are physically incorrect except for rust/dirt transitions.
- NEVER use emission without HDR — Emission values > 1.0 only work with HDR rendering enabled in Project Settings.
- NEVER use transparent materials for large environmental surfaces — Transparent objects cannot rely on the Z-buffer for early fragment rejection, resulting in massive overdraw. If only a tiny part of a mesh is transparent, split the mesh into two surfaces: one opaque, one transparent.
- NEVER create hundreds of slightly varied StandardMaterial3D resources if performance is dropping — Godot minimizes GPU state changes by automatically reusing the underlying shader for materials that share the exact same configuration flags (checkboxes). Try to group your material configurations.
- NEVER attempt to fix Z-fighting strictly by moving objects further apart — Floating-point precision degrades over distance. To fix flickering textures, increase your Camera3D's
Nearplane property and decrease theFarproperty to compress the precision range. - NEVER use unique Material resources per MeshInstance3D — This breaks draw call batching. Use 'Instance Uniforms' to vary parameters while keeping a single shared material.
- NEVER use Decals on dynamic moving actors without a Cull Mask — Bullet holes should not stick to the player's face as they walk over them. Mask out character layers.
Aurelius Protocol: 3D World Building NEVER List
- NEVER forget to bake GridMap navigation — GridMaps don't auto-generate navigation meshes. Use EditorPlugin or manual NavigationRegion3D.
- NEVER use CSG for final game geometry — CSG is for prototyping. Convert to static meshes for performance (use "Bake CSG Mesh" in editor).
- NEVER scale GridMap cell size after placing tiles — Changing
cell_sizedoesn't update existing tiles, causing misalignment. Set it once at the start. - NEVER use MeshLibrary without collision shapes — Items without collision spawn visual-only geometry that players fall through.
- NEVER enable volumetric fog without DirectionalLight3D — Volumetric fog requires at least one light to scatter. No lights = no visible fog.
- NEVER animate CSG nodes during gameplay — Moving a CSG node within another forces the CPU to recalculate the boolean geometry, causing significant performance drops.
- NEVER place generic logic nodes in a GridMap — GridMap is highly optimized only for meshes, navigation, and collision. It is not a general-purpose system for placing arbitrary node structures on a grid.
- NEVER use non-manifold meshes in CSG — If you import a custom mesh for CSGMesh3D, it must be manifold (closed, no self-intersections, no interior faces, no negative volume). Non-manifold meshes will break the CSG algorithm and are completely unsupported.
Aurelius Protocol: Ability System NEVER List
- NEVER use _process() for cooldown tracking — Use timers or manual delta tracking in _physics_process(). _process() has variable delta and causes cooldown desync in slow frames.
- NEVER forget global cooldown (GCD) — Without GCD, players spam instant abilities. Add a small universal cooldown (0.5-1.5s) between all ability casts.
- NEVER hardcode ability effects in manager code — Use the Strategy pattern. Each ability is a Resource with execute() method, not a giant switch statement.
- NEVER allow ability use during animation lock — Check
is_castingoranimation_playingbefore allowing new casts. Interrupting animations breaks state machines. - NEVER save cooldown state without time normalization — Save "cooldown_end_time" (OS.get_unix_time() + remaining), not "remaining_time". Prevents exploits (change system clock, reload game).
- NEVER use Singletons (Autoloads) for combat managers — Centralizing combat state in a global object makes tracking bugs difficult and breaks encapsulation. Keep abilities and stats scoped to the scenes that actually use them.
- NEVER use Object Pooling with GDScript — GDScript uses reference counting memory management, so you generally do not need to pool instantiated abilities or projectiles. Simply instantiate and queue_free().
- NEVER rely on deep inheritance trees — Avoid having a BaseAbility -> MagicAbility -> FireAbility inheritance hell. Use node composition instead.
Aurelius Protocol: Adapt 2D To 3D NEVER List
- NEVER directly replace Vector2 with Vector3(x, y, 0) — This creates a "flat 3D" game with no depth gameplay. Add Z-axis movement or camera rotation to justify 3D.
- NEVER keep 2D collision layers — 2D and 3D physics use separate layer systems. You must reconfigure collision_layer/collision_mask for 3D nodes.
- NEVER forget to add lighting — 3D without lights is pitch black (unless using unlit materials). Add at least one DirectionalLight3D.
- NEVER use Camera2D follow logic in 3D — Camera3D needs spring arm or look-at logic. Direct position copying causes clipping and disorientation.
- NEVER assume same performance — 3D is 5-10x more demanding. Budget for lower draw calls, smaller viewport resolution on mobile.
- NEVER use the rotation property for complex 3D logic — 3D rotation uses Euler angles. Interpolating Euler angles causes unpredictable paths and Gimbal Lock. Always use
Quaternionfor 3D rotation interpolation or theBasismatrix for directional vectors. - NEVER ignore metric scaling — 3D physics and lighting assume 1 unit = 1 meter. Scaling models inside the engine introduces precision errors. Export assets from DCCs at the correct metric scale.
- NEVER disable physics interpolation when using custom camera follow scripts — Updating camera position in
_processto follow a body moving in_physics_processcauses jitter. UseNode3D.get_global_transform_interpolated()for smooth transforms.
Aurelius Protocol: Adapt 3D To 2D NEVER List
- NEVER remove Z-axis without gameplay compensation — Blindly flattening 3D to 2D removes spatial strategy. Add other depth mechanics (layers, jump height variations).
- NEVER keep 3D collision shapes — Use simpler 2D shapes (CapsuleShape2D, RectangleShape2D). 3D shapes don't convert automatically.
- NEVER use orthographic Camera3D as "2D mode" — Use actual Camera2D for proper 2D rendering pipeline and performance.
- NEVER assume automatic performance gain — Poorly optimized 2D (too many draw calls, large sprite sheets) can be slower than optimized 3D.
- NEVER forget to adjust gravity — 3D gravity is Vector3(0, -9.8, 0). 2D gravity is float (980 pixels/s²). Scale appropriately.
Aurelius Protocol: Adapt Desktop To Mobile NEVER List
- NEVER use mouse position directly — Touch has no "hover" state. Replace mouse_motion with screen_drag and check InputEventScreenTouch.pressed.
- NEVER keep small UI elements — Apple HIG requires 44pt minimum touch targets. Android Material: 48dp. Scale up buttons 2-3x.
- NEVER forget finger occlusion — User's finger blocks 50-100px radius. Position critical info ABOVE touch controls, not below.
- NEVER run at full performance when backgrounded — Mobile OSs kill apps that drain battery in background. Pause physics, reduce FPS to 1-5 when app loses focus.
- NEVER use desktop-only features — Mouse hover, right-click, keyboard shortcuts, scroll wheel don't exist on mobile. Provide touch alternatives.
Aurelius Protocol: Adapt Mobile To Desktop NEVER List
- NEVER keep touch-only controls — Add mouse/keyboard alternatives. Touch controls on desktop feel awkward and limit precision.
- NEVER lock to mobile resolution — Desktop can handle 1920x1080+ and higher frame rates. Upscale UI, increase render distance.
- NEVER hide graphics settings — Desktop players expect quality options (resolution, VSync, shadows, anti-aliasing).
- NEVER use mobile-sized UI — Touch targets (44pt) are too large for mouse. Reduce button/text size by 30-50%.
- NEVER forget window management — Players expect fullscreen, borderless, maximize, and multi-monitor support.
Aurelius Protocol: Adapt Single To Multiplayer NEVER List
- NEVER trust client-reported state — Clients own their 'Input', NOT their 'Position' or 'Health'. Server must validate every coordinate and health change.
- NEVER use `get_tree()` groups for authority checks — Use
is_multiplayer_authority(). Group registration is non-deterministic in high-latency joins. - NEVER allow unrestricted RPC rates — A malicious client can call a 'FireWeapon' RPC 10,000 times per second. Always implement rate-limiting (
net_rpc_rate_limiter.gd). - NEVER skip Client-Side Prediction — Movement without prediction feels 'heavy' and unresponsive. Predict movement locally, then correct only on server disagreement.
- NEVER sync peers at 60Hz — Sending entire state every frame will saturate client bandwidth. Use a lower tick-rate (20-30Hz) and interpolate between packets.
- NEVER snap peer positions — Abrupt position updates cause 'jitter'. Store a buffer of past states and lerp between them with a 100ms delay.
- NEVER sync 'Full Floats' if possible — Quantize Vector3 data (truncating decimals) to save 50%+ bandwidth. Use
MultiplayerSynchronizerwith delta-sync enabled. - NEVER ignore 'Late Joiners' — Players who join mid-game won't see existing environmental changes. Broadcast a full world-state 'Snapshot' on peer connection.
- NEVER test on 0ms ping — Everything works on localhost. Use a simulator (
net_latency_simulator.gd) with 150ms ping to identify sync bugs.
Aurelius Protocol: Animation Player NEVER List
- NEVER forget RESET tracks — Without a RESET track, animated properties don't restore to initial values when changing scenes. Create RESET animation with all default states [12].
- NEVER use `Animation.CALL_MODE_CONTINUOUS` for function calls — This calls the method EVERY frame during the keyframe. Use
CALL_MODE_DISCRETE(calls once) to avoid logic spam [13, 77]. - NEVER animate resource properties directly — Animating
material.albedo_colorcreates embedded resources that bloat file size. Store the material in a variable or useinstance uniforminstead [14]. - NEVER use `animation_finished` for looping animations — This signal doesn't fire for looped animations. Use
animation_loopedor checkcurrent_animationin_process(). - NEVER hardcode animation names as strings across large codebases — Use constants or enums. Typos cause silent failures.
- NEVER use `seek()` without `update=true` for same-frame logic — If you need properties to update immediately (e.g., for physics checks), you MUST set the
updateparameter totrue. - NEVER leave unnecessary AnimationPlayers `active` — If an entity is off-screen and its animation is purely visual (no logic tracks), set
active = falseto save significant CPU/GPU processing [317]. - NEVER change `AnimationLibrary` content while it is playing — This causes immediate crashes or undefined transform states. Stop the player or wait for the
finishedsignal before swapping libraries. - NEVER rely on `speed_scale` for long-term synchronization — For multiplayer or rhythm games, use
seek()with a global time reference to prevent frame-drift.
Aurelius Protocol: Animation Tree Mastery NEVER List
- NEVER call `play()` on AnimationPlayer when using AnimationTree — AnimationTree controls the player. Directly calling
play()causes conflicts and jitter. Useset("parameters/transition_request")ortravel()instead [12]. - NEVER forget to set `active = true` — AnimationTree is inactive by default. Animations won't play until
$AnimationTree.active = true[13]. - NEVER use absolute paths for parameter access — Use relative paths like
"parameters/StateMachine/transition_request". This ensures compatibility when nodes move in the hierarchy [14]. - NEVER leave `auto_advance` enabled for interactive states — It causes immediate transitions. Use it only for automated sequences like combo chains or death-to-respawn [15, 121].
- NEVER use `BlendSpace2D` for 1D blending — Blending only speed? Use
BlendSpace1D. Blending only two states? UseBlend2.BlendSpace2Dis specifically for X+Y directional inputs (strafe) [16, 142]. - NEVER update `AnimationTree` parameters every frame without a guard — Setting parameters via
set()every frame regardless of change causes cache invalidation and potential stutter. Check equality first. - NEVER use deep, nested `BlendTrees` for simple logic — Every layer adds CPU overhead. If logic can be handled in a
StateMachineor a simple script-drivenBlend2, do it there. - NEVER forget to handle `await get_tree().process_frame` when updating parameters synchronously — Sometimes the tree needs one frame to reconcile state before the next parameter change takes effect.
- NEVER rely on `auto_advance` for long cutscenes — If an animation is interrupted,
auto_advancecan put the character in a broken state. UseMethod Tracksto signal state completion instead. - NEVER use `Sync` groups for animations with wildly different lengths — It forces one animation to play at an extreme speed. Use
TimeScaleor separate layers for mismatching cycles.
Aurelius Protocol: Audio Systems NEVER List
- NEVER set bus volume with linear values —
set_bus_volume_db()is logarithmic. Uselinear_to_db()for sliders OR everything will sound too loud until the last 5%. - NEVER skip 'Bus Routing' — Playing music on the 'SFX' bus makes volume menus useless. Strictly route every player to its dedicated sub-bus (Music, SFX, UI, Voice).
- NEVER use 'Master' for gameplay sounds — Dedicate Master to final limiting. Route all gameplay to sub-groups so you can mute/duck categories.
- NEVER use 3D players without an Attenuation Model — Default is NONE. If you don't set it to
Inverse Distance, a whisper on the other side of the map will be global volume. - NEVER play 3D sounds exactly on top of the listener — Causes "Panning Jitter" where the sound snaps between Left/Right speakers. Offset by
0.1units. - NEVER forget Doppler for high-speed objects — A car flying by without
DOPPLER_TRACKING_PHYSICS_STEPfeels flat and static. - NEVER spam same-frame sounds — Playing 50 explosions at once causes constructive interference (clipping/distortion). Use a
Limiter(audio_voice_limiter_manager.gd). - NEVER instantiate nodes for one-shots — Creating a node, playing a 0.5s clap, and
queue_free()ing causes frame-time spikes. Use a Pool. - NEVER skip Crossfades/Transitions — Abrupt music cuts break immersion. Always use a 0.5s-1.0s
Tweento bridge tracks.
Aurelius Protocol: Auditor Never_List_Encyclopedia NEVER List
- NEVER: Call
RenderingServer.mesh_create(),PhysicsServer3D.shape_create(), orRenderingDevice.texture_buffer_create()without a correspondingfree_rid()call. - NEVER: Create a circular reference between two
RefCountedorResourceobjects without at least one being aWeakRef. - Expert Rationale: Godot's ref-counter cannot resolve local cycles. Two resources pointing to each other will never reach zero count and will leak indefinitely.
- NEVER: Acquire a
Mutex.lock()inside a high-frequency loop (e.g.,for i in 10000). - NEVER: Call
RenderingServer.texture_get_data()orRenderingDevice.buffer_get_data()inside_processor_physics_process. - NEVER: Re-assign
textureormaterialproperties on a per-instance basis inside a hot loop for 2D sprites. - NEVER: Use a
Sprite2Dfor a massive static background (e.g., 2048x2048) if 70% of the image is transparent. - NEVER: Use
get_parent().some_method()orget_node("../../Other"). - NEVER: Use an
AutoLoadsingleton to track transient gameplay nodes (e.g.,Globals.current_player = self). - NEVER: Use
get_var(true)on data received viaPacketPeerorStreamPeer. - NEVER: Enable
allow_object_decoding = trueon theMultiplayerAPIfor public servers. - NEVER: Reference a file with mismatched casing (e.g.,
res://Player.pngwhen the file isplayer.png).
Aurelius Protocol: Auditor NEVER List
- NEVER use
get_parent(). It assumes structural dominance that you do not have. Use Signals (upward) or Exports (downward). - NEVER use
Input.is_action_pressedin_processfor non-continuous actions. Use_unhandled_inputto avoid polling overhead. - NEVER store gameplay state in a AutoLoad without strict type-hinting. Singletons are global pollutants if untyped.
- NEVER use absolute NodePaths (
/root/Main/Player). If the structure moves 1 inch, your code dies. Use Groups or Unique Names. - NEVER export a
Nodevariable without a specific class hint (@export var player: PlayerNOT@export var player: Node). Refuses to allow slop in the Inspector.
Aurelius Protocol: Autoload Architecture NEVER List
- NEVER access AutoLoads in `_init()` — AutoLoads are initialized sequentially. Accessing one in
_init()may find a null reference [12]. - NEVER modify a Singleton's size or children in `_ready()` — If multiple Singletons refer to each other's trees during boot, it can cause layout/sorting errors.
- NEVER store highly localized, scene-specific data in AutoLoads — This creates "God Objects" and introduces global side effects that are hard to debug [14].
- NEVER use `Parent.method()` calls from an Autoload — Autoloads sit at the root. They are the ultimate "top". Use signals to talk to the active scene.
- NEVER use an Autoload for pure data containers — If you don't need
_process()or signals, use astatic varin aclass_namescript instead [7]. - NEVER create circular dependencies between Singletons — If A needs B and B needs A, Godot will hang during the splash screen [13].
- NEVER free an Autoload node manually — Removing a singleton from the root can leave dangling references that crash the engine.
- NEVER use AutoLoads for UI elements that aren't global — Popups that only exist in one level should be in that level, not a global singleton.
- NEVER assume `get_tree().current_scene` is accurate in `_ready()` — In Autoloads, the active scene might still be initializing. Access it via
get_tree().root.get_child(-1)[6]. - NEVER skip `process_mode` configuration — If your global console or music manager needs to work while the game is paused, set
process_mode = PROCESS_MODE_ALWAYS.
Aurelius Protocol: Camera Systems NEVER List
- NEVER use `global_position = target.global_position` every frame — Instant position matching causes jittery movement. Use
lerp()orposition_smoothing_enabled = true[12]. - NEVER use `offset` for permanent camera positioning —
offsetis for shake, sway, or temporary recoil effects only. Usepositionfor permanent framing to avoid logic conflicts [14]. - NEVER forget `limit_smoothed = true` for `Camera2D` — Hard boundaries cause jarring visual stops. Smoothing against limits ensures a professional feel [13].
- NEVER enable multiple `Camera2D` nodes in the same viewport simultaneously — Only the last enabled camera takes precedence. Explicitly disable inactive cameras [15].
- NEVER use `SpringArm3D` without a collision mask — It will clip through terrain and walls. Set it to the world/environment layer [16].
- NEVER implement screen shake by randomizing `position` directly — This overwrites follow-logic. Use
offsetor a dedicated Trauma/Noise system to Layer shake over the follow-position [27, 28]. - NEVER parent the Camera directly to a high-speed physics body — Physics stutter or parent rotation will cause motion sickness. Use
RemoteTransform2D/3Dwith rotation sync disabled for a stable view [30]. - NEVER use `look_at()` in 3D without a fallback for the 'Up' vector — If the target is directly above/below, the camera will flip wildly. Use guards or
Quaternionmath for vertical tracking. - NEVER rely on `SubViewport` defaults for Mini-maps — Viewports are expensive; explicitly set
render_target_update_modetoUPDATE_WHEN_VISIBLEor a fixed lower framerate to save GPU [156]. - NEVER use linear interpolation for Zoom — It feels 'robotic'. Use exponential lerp or a
TweenwithTRANS_CUBICfor a more natural tactical feel.
Aurelius Protocol: Characterbody 2D NEVER List
- NEVER use `RigidBody2D` for standard player controllers — RigidBody is for physics-simulated objects. For responsive, feel-driven player movement, always use
CharacterBody2D. - NEVER multiply `velocity` by `delta` before `move_and_slide()` —
move_and_slide()handles delta internally. Manual multiplication makes movement framerate-dependent [12]. - NEVER use `global_position` updates for movement — Use
velocityandmove_and_slide(). Direct position updates bypass collision detection and floor snapping. - NEVER ignore the return value of `move_and_slide()` — While optional, checking
is_on_floor()orget_last_motion()immediately after is critical for state logic. - NEVER rely on default `floor_snap_length` for fast stair-climbing — Default snapping is too small for high-velocity characters. Use custom raycast-based stair logic for smooth transitions.
- NEVER apply gravity while `is_on_floor()` is true — Constant downward force on the floor can cause "micro-jitter" or prevent floor-snap from working correctly. Reset
velocity.yto 0 or a small constant. - NEVER use `Area2D` for ground detection — Real collisions (rays/shapecasts) are more precise.
is_on_floor()is highly optimized; only augment it if necessary. - NEVER forget Ceiling Bonk detection — If you don't reset
velocity.yto 0 whenis_on_ceiling(), the player will "float" against the ceiling until gravity pulls them down. - NEVER use high-precision physics for pixel art visuals — Keep physics math high-precision, but round your Sprite nodal positions in
_processto avoid visual sub-pixel jitter. - NEVER use `queue_free()` on characters every frame — Use object pooling for bullets or enemies to avoid SceneTree performance spikes.
Aurelius Protocol: Combat System NEVER List
- NEVER use direct damage references (`target.health -= 10`) — This bypasses armor, resistances, and invincibility logic. Always use a
DamageData+HealthComponentpattern for consistent results. - NEVER forget invincibility frames (i-frames) — Without them, multi-hit attacks deal damage every single frame. Always apply a brief invincibility period (0.1–0.5s) after taking a hit.
- NEVER keep hitboxes active permanently — This causes unintended "ghost" damage. Enable and disable hitboxes precisely using
AnimationPlayertracks or code-timed triggers. - NEVER use groups for physics-based hit filtering — Collision layers are evaluated in C++ and are significantly faster. Groups don't restrict physics intersections adequately for high-performance combat.
- NEVER emit damage signals without a DamageData object — A raw number loses critical context like damage type, source, and knockback direction.
- NEVER use try/catch blocks with validate targets — GDScript does not support exceptions. Use
has_method(&"take_damage")or theisoperator for safe type checking. - NEVER hardcode hitstun pauses using OS.delay_msec() — This blocks the entire OS thread and freezes the game. Use
create_tween()orEngine.time_scalefor visual hit-stop effects. - NEVER apply massive impulses to a RigidBody inside _process() — Physics-altering impulses must happen in
_physics_process()or_integrate_forces()to remain deterministic and stable. - NEVER couple UI lifebars directly inside the Player script — Use a
health_changedsignal. This keeps your combat logic clean and independent of UI implementation details. - NEVER leave CollisionShapes active on dead entities — Corpses will block players and towers. Disable them immediately using
set_deferred("disabled", true). - NEVER scale CollisionShapes non-uniformly — Non-uniform scaling breaks the physics engine's collision math. Always scale the internal resource (e.g.,
CircleShape2D.radius) instead. - NEVER use instanced Nodes for base stat data — Nodes carry unnecessary overhead. Use Godot's
Resourceclass for lightweight, efficient, and inspectable stat containers. - NEVER use raw strings for elemental damage types — Strings are slow and error-prone. Use
enumflags (optionally with@export_flags) to manage multi-type damage efficiently. - NEVER use standard strings for state names in high-frequency loops — Use
StringName(&"attacking", &"stunned") to drastically improve dictionary lookups and hash comparison speeds. - NEVER forget to duplicate() a shared Resource stats block — If you don't call
duplicate()when instancing a mob, all enemies of that type will share the same health pool.
Aurelius Protocol: Composition Apps NEVER List
- NEVER use get_parent() to fetch data — Components must be blind. If they need data, it must be injected via
@exportor passed into a function call. - NEVER talk sideways —
ComponentAmust never call functions onComponentB. High-coupling makes refactoring impossible. Always signal up to the Orchestrator. - NEVER use brittle Node Paths —
get_node("Child/Subchild/Node")breaks when you move a single node. Use@exportand the Inspector. - NEVER put business logic in the Orchestrator — The Orchestrator should only have
_on_signalmethods that delegate to other components. - NEVER store global state in individual components — Use a shared
ContextResource or the Global Autoload for cross-scene state. - NEVER assume a component's parent is of a specific type — If a
HealthComponentrequires its parent to be aCharacterBody2D, it fails the "Rock Test." - NEVER skip signal cleanup — Connecting signals dynamically without disconnecting can lead to memory leaks or multiple execution bugs.
- NEVER let Logic know about Visuals — A
CombatComponentshould never callAnimationPlayer.play(). It emitsattack_performed, and aSyncerorOrchestratorhandles the visual response.
Aurelius Protocol: Composition NEVER List
- NEVER use deep inheritance chains (e.g.,
Player > Entity > LivingThing > Node) — Creates brittle "God Classes" that are hard to refactor [21]. - NEVER use `get_node()` or `$` for components — This breaks if the scene tree is rearranged. Always use
@exportor%UniqueNames[22]. - NEVER let a component reference its parent script directly — This makes the component impossible to reuse. Use signals or dependency injection [23].
- NEVER mix Input, Physics, and Game Logic in one script — This violates Single Responsibility. Split them into specialized components [24, 13].
- NEVER create components that require a specific SceneTree structure — A component should be "selfish" and only care about its own properties and direct children.
- NEVER use inheritance to "add a feature" — If you want an enemy to shoot, add a
ShootingComponent, don't make it inherit fromShooterEnemy. - NEVER hardcode component dependencies — If
CombatComponentneedsHealthComponent, look it up in_ready()or inject it via the parent [11]. - NEVER treat Godot nodes as pure data — Nodes provide lifecycle (
_process) and signals. If you only need data, use aResource. - NEVER ignore the Node lifecycle in components — Use
_enter_tree()and_exit_tree()for setup/cleanup that must happen regardless of the parent's state. - NEVER hide component points of access — Expose
NodePathorCallableproperties so the parent can wire the component in the Inspector [13].
Aurelius Protocol: Debugging Profiling NEVER List
- NEVER use `print()` without descriptive context —
print(value)is useless. Useprint("Player health:", health)with labels. - NEVER leave debug prints in release builds — Wrap in
if OS.is_debug_build()or use custom DEBUG const. Prints slow down release. - NEVER ignore `push_warning()` messages — Warnings indicate potential bugs (null refs, deprecated APIs). Fix them before they become errors.
- NEVER use `assert()` for runtime validation in release — Asserts are disabled in release builds. Use
if not condition: push_error()for runtime checks. - NEVER profile in debug mode — Debug builds are 5-10x slower. Always profile with release exports or
--releaseflag. - NEVER assume `Engine.capture_script_backtraces(true)` is cheap — Capturing locals allocates significant memory and can prevent objects from being deallocated, causing artificial leaks [19].
- NEVER call `push_error()` or `print()` inside a custom `Logger._log_message` override — This causes infinite recursion and crashes as the logger intercepts its own output [20].
- NEVER leave the Visual Profiler running during gameplay tests — Continuous polling degrades framerates significantly, invalidating actual performance metrics [21].
- NEVER rely on `OS.get_ticks_msec()` for microbenchmarking — Milliseconds lack precision for logic timing; ALWAYS use
Time.get_ticks_usec()for microsecond precision [22]. - NEVER assume `OBJECT_ORPHAN_NODE_COUNT` works in production — This monitor is strictly debug-only; it safely returns 0 in release builds, potentially hiding leaks [23].
- NEVER benchmark with V-Sync enabled — V-Sync throttles metrics to the monitor refresh rate, masking the true CPU/GPU processing overhead [24].
- NEVER leave `print_stack()` or `print_debug()` in release builds — These are often stripped or useless outside the debugger. Use structured logging for production [25].
- NEVER strip debugging symbols if using external C++ profilers — Stripping destroys call stack readability for external tools like Perfetto or VerySleepy [26].
- NEVER forget to unregister an `EditorDebuggerPlugin` in `_exit_tree()` — Failing to clean up leaves "ghost" connections in the engine's debugging loop [27].
- NEVER trust the Visual Profiler on macOS when using the Compatibility renderer — Platform-specific driver limitations severely restrict OpenGL profiling accuracy on macOS [28].
Aurelius Protocol: Dialogue System NEVER List
- NEVER hardcode dialogue text directly in your GDScript files — This makes translation impossible. Store text in Resources or external JSON/CSV files [12].
- NEVER display choices that the player hasn't met the criteria for — Hidden choices should stay hidden unless they are "grayed out" intentionally to show a missed path [13].
- NEVER use loose strings for node transitions without validation — Typos in
next_node_idwill crash the dialogue mid-convo. Useassert()or a central ID registry [14]. - NEVER force a typewriter effect without a "Skip" option — Forcing players to read at a fixed speed leads to frustration. Always allow clicking to finish the line [15].
- NEVER store the current dialogue state inside a UI node — If the UI is closed or the scene changes, the player loses their place. Use an AutoLoad
DialogueManager[16]. - NEVER use `get_node()` to find dialogue UI from the NPC script — Use signals like
DialogueManager.start_dialogue(res)to maintain a decoupled architecture. - NEVER use complex regex for simple text tags — Godot's
RichTextLabelsupports BBCode tags natively. Use[b],[i], and[url]for formatting. - NEVER perform save/load operations inside a dialogue node — Conversation nodes should be pure data. Delegate persistence to a dedicated
SaveSystem. - NEVER block the main thread for text reveal timing — Never use
OS.delay_msec(). Usecreate_timer()orTweento maintain smooth 60fps performance. - NEVER hardcode portrait paths — Assign textures directly to the
DialogueNoderesource in the inspector or use a centralPortraitDatabase.
Aurelius Protocol: Economy System NEVER List
- NEVER use `int` for large-scale premium economies — Standard 32-bit integers cap at 2.1 billion. For massive quantities, use
floator a customBigIntstructure [12]. - NEVER forget to implement a Buy/Sell price spread — Allowing players to sell items for the same price they bought them creates infinite money exploits [13].
- NEVER skip "Currency Sinks" — Without mandatory costs (repairs, taxes, consumables), the game economy will suffer from hyper-inflation [14].
- NEVER perform currency validation only on the client — In multiplayer or persistent games, the server MUST be the source of truth for all financial transactions [15].
- NEVER hardcode loot drop percentages inside scripts — Changing drop rates should not require a recompile. Use Resources or outside data files for easy balancing [16].
- NEVER allow negative balances via underflow — Always check
if current >= amountBEFORE subtracting. Negative gold can break logic and save files. - NEVER modify the wallet balance directly from the UI — The UI should only request a transaction. The
WalletManagershould decide if it's valid and update the state. - NEVER use floating point math for exact currency counts —
0.1 + 0.2might equal0.30000000000000004, leading to discrepancies. Useintfor cents/smallest units. - NEVER ignore "Transaction Logs" in serious RPGs — If money disappears, you need a history of events to debug whether it was a bug or a legitimate game event.
- NEVER give rewards without checking "Max Limit" — If a player is capped at 999,999 gold, adding 1,000 should result in 999,999, not a wrapped negative number.
Aurelius Protocol: Export Builds NEVER List
- NEVER export to production without a 'Smoke Test' — "It runs in editor" is NOT enough. Web, Mobile, and Console have unique memory/shader constraints.
- NEVER skip macOS Notarization — Apple's Gatekeeper will block unsigned apps. Use
notarytoolOR distribute exclusively via Steam/App Store. - NEVER use ad-hoc file paths —
res://is read-only in builds. Useuser://for saves and logs, or paths will fail on locked file systems. - NEVER use 'Debug' templates for release — Debug binaries are bloated and slow. Always use
--export-releaseto strip profiling overhead. - NEVER include raw resources in builds — Check your export filters. If you include
.md,.txt, or.psdfiles, you're wasting player bandwidth and disk space. - NEVER ignore VRAM compression — Large textures in Web/Mobile builds will crash the GPU driver. Enable ASTC/ETC2 compression in Import settings.
- NEVER commit keystores or raw passwords to Git — Use Environment Variables and CI Secrets (
export_android_signing_env.ps1). - NEVER allow debug commands in Production — Use
OS.has_feature("release")to purge console/cheats from the final build.
Aurelius Protocol: Game Loop Collection NEVER List
- NEVER use free() to destroy an active state node or level — This can cause crashes if the node is still processing. Always use
queue_free()to safely dispose of it at the end of the frame. - NEVER calculate physics-dependent game state in _process() — Movement and precise collisions must happen in
_physics_process()to stay synced with the engine's fixed timestep. - NEVER execute heavy state transitions (like loading massive levels) synchronously — Calling
load()on a huge scene stalls the main thread. UseResourceLoader.load_threaded_request(). - NEVER use exact floating-point equality (==) for time-based states — Floating-point errors will eventually cause missed triggers. Use
is_equal_approx()or relative comparisons. - NEVER manipulate the active SceneTree from a background thread — The SceneTree is not thread-safe. Use
call_deferred()to push results back to the main thread. - NEVER rely on a monolithic "GameManager" with hardcoded absolute paths — This creates tight coupling. Use groups, signals, and exported references for a modular architecture.
- NEVER assume child nodes are ready before their parent —
_ready()executes from bottom-to-top. If you need child references, use@onreadyorawait ready. - NEVER use string-based signals for critical state transitions — Avoid
connect("signal", _on_func). Use the Signal object syntax (signal.connect(_on_func)) for compile-time validation. - NEVER poll for input state every frame for discrete menu events — Use the
_unhandled_input()callback to cleanly intercept events without wasting CPU cycles in_process(). - NEVER crash the engine intentionally via CRASH_NOW_MSG — Regular state handling should always recover gracefully. Crashing is for unrecoverable internal engine failures.
- NEVER hardcode spawn positions in code — Always use
Marker3DorCollisionShape3Dnodes in the scene so designers can adjust layout without touching code. - NEVER neglect "juice" before an item disappears — Immediate
queue_free()feels dry. Always spawn particles or play a sound before removal. - NEVER use global variables for local collection progress — Keep counts encapsulated within the
CollectionManagerand emit signals to update the UI. - NEVER leave orphaned nodes in the tree during state swaps — Always ensure the previous level/state is properly queued for deletion before instantiating the new one.
- NEVER scale collision shapes non-uniformly for collectibles — This breaks collision detection math. Adjust the internal shape resource properties instead.
Aurelius Protocol: Game Loop Harvest NEVER List
- NEVER use float variables to store massively accumulated harvest resources — Large floats lose precision, which can lead to "missing" resources in idle/clicker games. Always use
intfor core counts. - NEVER process gathering logic in _process() without multiplying rates by delta — If you don't use
delta, the harvesting speed will fluctuate wildly based on the player's hardware performance/framerate. - NEVER run heavy array mathematics for thousands of resources on the main thread — This will cause micro-stutters. Distribute heavy calculations using
WorkerThreadPool. - NEVER leave a gathering game running at full GPU utilization — For UI-heavy harvest games, enable
OS.low_processor_usage_modeto drastically reduce battery drain on mobile/laptops. - NEVER trust OS.get_ticks_msec() for offline progress — This only tracks system uptime. Rely on
Time.get_unix_time_from_system()to calculate real-world time passed between sessions. - NEVER use Timer nodes for precise audio-visual harvesting synchronization — Timer nodes are subject to framerate variations. For frame-perfect sync, use code-based timers or the animation system.
- NEVER couple your resource logic directly to UI counters — Use a signal bus or event system to notify the UI of changes, keeping the game logic decoupled from the presentation.
- NEVER constantly instantiate and destroy Label nodes for "floating numbers" — Frequent allocation/deallocation leads to memory fragmentation. Use an object pool for damage/harvest popups.
- NEVER modify a globally shared Resource without calling duplicate() — If you modify a shared
Resource(like a base crop yield), every instance using that resource will be updated. Useduplicate(true). - NEVER access shared harvest data from background threads without a Mutex — Simultaneous access will eventually corrupt your inventory data. Always use a
Mutexto lock sensitive blocks. - NEVER hardcode yield values in your gathering scripts — Use exports and custom
Resourcefiles so designers can balance the economy without touching the code. - NEVER use queue_free() on a harvested node before the VFX/SFX finish — You'll cut off the "juice." Hide the mesh and disable collision, then
queue_free()once the effect signals completion. - NEVER check tool requirements via string comparisons if possible — Use enums or class types. Strings are prone to typos and are slower for high-frequency checks.
- NEVER neglect to save the UNIX timestamp on exit — If you forget this, you lose the ability to calculate offline earnings when the player returns.
- NEVER scale collision shapes non-uniformly for harvestable objects — This breaks the underlying physics calculations. Adjust the shape resource dimensions instead.
Aurelius Protocol: Game Loop Time Trial NEVER List
- NEVER use OS.get_ticks_msec() for ultra-precise race timing — Millisecond resolution is too coarse for high-end racing games. Use
Time.get_ticks_usec()for microsecond precision. - NEVER rely exclusively on _process() for finish line triggers — Visual frames can skip during lag. Always evaluate physical overlaps in
_physics_process()to guarantee detection within the fixed physics step. - NEVER evaluate Area3D overlaps immediately after instantiation — The physics server requires at least one physics frame to synchronize.
await get_tree().physics_framebefore checking for players. - NEVER scale a CollisionShape3D on a checkpoint non-uniformly — This breaks the underlying SAT collision math. Always scale the internal shape resource (e.g.,
BoxShape3D.size) instead. - NEVER use TCP (reliable) for syncing positions in multiplayer racing — Congestion algorithms cause huge spikes. Use
ENetMultiplayerPeerwithTRANSFER_MODE_UNRELIABLEfor high-frequency position updates. - NEVER trust client-side finish line/lap crossing — Always validate triggers on the authoritative server using
multiplayer.is_server()to prevent cheating. - NEVER use standard float equality (==) for record lap times — Use
is_equal_approx()to account for precision loss in accumulated time variables. - NEVER hardcode input checks without flushing the buffer — For frame-perfect boost/stop responses, call
Input.flush_buffered_events()to ensure the engine has processed the latest raw input. - NEVER allocate new Vector3 arrays inside fast path-following loops — This triggers the garbage collector. Use
PackedVector3Arrayto maintain a contiguous memory block. - NEVER use dynamic string paths ($"../Checkpoint") in tight loops — Lookups are slow. Use
@onreadyto cache node references during initialization. - NEVER record the whole player object for ghosts — Only record core transforms (position/rotation). Recording the whole object is memory-intensive and unnecessary for visual ghosts.
- NEVER give the ghost collision — It should be a purely visual indicator (e.g., semi-transparent) to avoid disrupting the player's line.
- NEVER neglect checkpoint sequencing — Don't just check if the player hit the finish line. Verify they passed every intermediate checkpoint in the correct order.
- NEVER use Area3D without monitoring optimization — Checkpoints should only look for the
Playerphysics layer to minimize the number of physics overlap calculations. - NEVER use standard lerp for ghost rotation — Use
slerp()orQuaternion.slerp()to avoid gimbal lock and ensure smooth rotation interpolation.
Aurelius Protocol: Game Loop Waves NEVER List
- NEVER iterate through get_children() to find all enemies — This is extremely slow. Always add enemies to an "enemies" group and use
get_tree().get_nodes_in_group(&"enemies")for efficient access. - NEVER constantly instantiate() and queue_free() hundreds of enemies — This causes garbage collection stutters. Use an object pool to reuse existing enemy instances.
- NEVER spawn thousands of separate MeshInstance3D nodes for swarms — This will tank your draw calls. Use
MultiMeshInstance3Dto batch thousands of meshes into a single GPU call. - NEVER calculate pathfinding for hundreds of agents on the main thread — This will freeze your game. Enable
use_async_iterationson your navigation regions or useNavigationServer3D.query_path(). - NEVER forget to check is_inside_tree() before adding a child — If the spawner is queued for deletion, adding a child will crash. Always verify the spawner is still active in the tree.
- NEVER assign a preloaded resource (like stats.tres) directly to spawned mobs — They will all share the exact same health/stats. Always call
base_stats.duplicate_deep()to give each mob its own unique data. - NEVER use standard strings for high-frequency group calls — Always use
StringName(&"enemies", &"take_damage") for optimal hash performance and to avoid unnecessary string allocations. - NEVER spawn entities directly inside physics callbacks synchronously — Instantiating nodes during physics steps can corrupt the physics state. Always use
call_deferred(&"add_child", enemy). - NEVER leave CollisionShapes on dead enemies active — Corpses will block towers and navigation. Use
set_deferred("disabled", true)immediately upon death. - NEVER synchronize complex Object types via MultiplayerSynchronizer — It only supports primitive types. For complex data, sync a UID or ID and look up the data locally on the client.
- NEVER auto-start waves without player feedback — Always provide a UI countdown, a visual "Wave Incoming" effect, or a start button to maintain player agency.
- NEVER hardcode spawn positions at (0,0,0) — Use
Marker3Dnodes in the editor so you can visually adjust spawn points without digging into code. - NEVER check wave completion by counting children every frame — It's too expensive. Maintain a local counter or use a signal-based system to track active enemy counts.
- NEVER use the same navigation map for every entity type — If you have flying and walking enemies, use separate navigation maps to prevent pathing issues.
- NEVER scale collision shapes non-uniformly for spawners — This breaks the collision detection math. Adjust the shape resource properties instead.
Aurelius Protocol: Gdscript Mastery NEVER List
- NEVER use `@onready` and `@export` on the same variable — Initialization order will cause
@onreadyto overwrite the Inspector value [1]. - NEVER modify a Dictionary's size while iterating it — Use
dict.keys().duplicate()or iterate a clone to safely erase elements [2, 3]. - NEVER use string-based `connect("signal", ...)` — Always use the Signal object syntax (
button.pressed.connect(...)) for compile-time safety [4]. - NEVER attempt to override non-virtual native engine methods — Overriding
queue_free()orget_class()is unsupported and will be ignored by engine callbacks [5, 6]. - NEVER use dynamic `get_node()` or `$` inside `_process()` — Fetching paths every frame stalls the CPU. Cache and use
@onready[7, 8]. - NEVER use `Parent.method()` calls — Violates "Signal Up, Call Down". Use signals to communicate with parents.
- NEVER use `is` followed by a hard cast — If the type check passes but the object changes, it crashes. Use
asand check for null. - NEVER use `print()` for production debugging — Use
push_error(),push_warning(), or breakpoints to ensure errors are visible in the console/logs. - NEVER pre-load huge resources in `_ready()` — This causes frame stutters. Use
ResourceLoader.load_threaded_request()for async loading. - NEVER use global variables in Autoloads when `static var` is sufficient — Static variables offer better encapsulation and less project pollution [24].
- Pattern: "Signal Up, Call Down". Children should never call methods on parents; they should emit signals instead.
Aurelius Protocol: Genre Action Rpg NEVER List
- NEVER use linear damage scaling for progression; strictly use an exponential curve (e.g.,
base * pow(1.15, level)) to maintain the power fantasy. - NEVER allow defense stats to stack linearly to 100%; strictly use a Diminishing Returns formula (e.g.,
armor / (armor + 100.0)) to prevent invincibility. - NEVER skip Hit Recovery (Stagger); strictly implement a brief stagger state (0.2s - 0.5s) on significant hits to prevent "floaty" combat.
- NEVER hide critical stats from the player; strictly provide a detailed character sheet for theory-crafting (Crit Chance, Resistance, etc.).
- NEVER make loot drops visually identical; strictly differentiate rarities with color-coded beams (purple/gold) and distinct sound cues.
- NEVER calculate hitboxes, knockbacks, or combat movement in
_process(); strictly use_physics_process()for deterministic results. - NEVER evaluate exact floating-point equality (==) for combat thresholds; strictly use
is_equal_approx(). - NEVER use the ! (NOT) operator in AnimationTree Advance Condition expressions; strictly use explicit boolean equality (
is_walking == false). - NEVER store character stats or massive inventories as Nodes; strictly use Resource-based data containers for lightweight memory overhead.
- NEVER forget to call
duplicate()on shared Resources; modifying one goblin's stats must not affect all other instances. - NEVER rigidly couple combat detection to specific classes; strictly use Duck-Typing (e.g.,
if body.has_method(&"take_damage")) for interaction. - NEVER rely on the UI SceneTree as the source of truth for inventory; strictly separate data logic from visualization.
- NEVER recalculate stats every frame; strictly trigger recalculation only on gear changes or level-ups.
- NEVER parse massive RPG save files synchronously; strictly offload heavy parsing to the
WorkerThreadPool. - NEVER synchronize complex Resource types over the network; strictly serialize changes into primitive Dictionaries or PackedByteArrays.
- NEVER manage character state by coupling child nodes to parent existence; strictly use signals for loose coupling ("Signal Up, Call Down").
- NEVER use standard Strings for high-frequency AI state identifiers; strictly use
StringNamefor optimized hash comparisons. - NEVER instantiate/destroy hundreds of objects (projectiles, damage text) per second; strictly use Object Pooling.
- NEVER delete active combat entities via
free(); strictly usequeue_free()for safe deferred disposal. - NEVER calculate complex loot drops or parse massive late-game inventories on the main thread; strictly offload heavy RNG rolls and array iterations to the WorkerThreadPool.
- NEVER use nested if/elif blocks for complex Boss AI; strictly use a modular StateMachine or pattern matching.
- NEVER iterate through the SceneTree for global state changes; strictly use Signal Groups (
call_group()). - NEVER move
OccluderInstance3Dnodes attached to dynamic characters; this causes CPU BVH rebuild stalls.
Aurelius Protocol: Genre Battle Royale NEVER List
- NEVER sync all 100 players every frame; strictly use a Relevancy System to sync high-freq data only for players within ~100m. Far players sync at ~5Hz.
- NEVER use
TRANSFER_MODE_RELIABLEfor movement data; strictly use Unreliable to prevent packet backup and network congestion. - NEVER focus on client-side hit detection; strictly use Authoritative Server Validation where the server confirms "Did it hit?" based on state history.
- NEVER trust the client for game state; strictly validate all movement, looting, and inventory changes exclusively on the authoritative server.
- NEVER run a dedicated server with visuals; strictly use Headless Mode (
--headless) or dummy drivers to save massive CPU/GPU resources. - NEVER call RPCs before connection; strictly wait for the
connected_to_serversignal before attempting synchronization logic. - NEVER pick a fully random center for the Safe Zone; strictly target centers that ensure the new circle is completely contained within the current one.
- NEVER allow "Storm Tunneling"; strictly use a Distance-to-Center calculation rather than a simple collision perimeter to prevent skips at low tick rates.
- NEVER spawn loot without Object Pooling; strictly pre-instantiate and toggle visibility/collision to avoid GC spikes during dense spawns.
- NEVER ignore
VisibilityNotifier3D; strictly disableAnimationPlayer,_process(), and heavy AI logic for players that are not visible to the observer. - NEVER print in tight server loops; strictly avoid
print()as console I/O is blocking and will tank server performance in high-player-count matches. - NEVER export mobile clients without the INTERNET permission — Communication will silently fail on Android/iOS if the manifest is missing the networking permission [37].
- NEVER use `get_var(true)` on untrusted data — Deserializing arbitrary objects allows attackers to execute remote code on the server or other clients [31].
- NEVER synchronize `Object` or `Resource` types over network — Use the
MultiplayerSynchronizerstrictly for base types (int, float, vec) [39]. - NEVER assume `UNRELIABLE` packets arrive in order — Design state interpolation carefully to handle missing or out-of-order ticks [28].
- NEVER leave `multiplayer_poll` false without manual calling — If using custom threads, failing to call
multiplayer.poll()freezes all traffic [40].
Aurelius Protocol: Genre Card Game NEVER List
- NEVER hardcode card logic inside UI scripts; strictly encapsulate gameplay effects in `Callable` objects or Command resources pushed to a LIFO stack.
- NEVER perform board-state calculations (Power/Toughness) in
_process(); strictly use Signal-driven triggers or a centralizedEffectStackresolver. - NEVER forget LIFO Stack Resolution; strictly use `Array.push_back()` and `Array.pop_back()` to resolve reactions from top-to-bottom.
- NEVER skip Z-Index management during drag-and-drop; strictly raise the card to the front on click to prevent it sliding under other cards.
- NEVER allow instant card "teleportation" between piles; strictly use Tween animations (0.2s+) to give cards a tactile, physical feel.
- NEVER use
global_positionfor cards in hand; strictly position them using a `Curve2D` (Bezier) layout with `sample_baked()` for smooth, non-circular arcs. - NEVER allow instant card "teleportation" between piles; strictly use `create_tween()` and `tween_property` chainings (0.2s+) for juicy card-feel.
- NEVER forget to handle Empty Deck scenarios; strictly implement auto-reshuffle of the discard pile to prevent soft-locks.
- NEVER use floating point numbers for discrete card stats; strictly use
intfor Costs, Attack, and Health to avoid precision drift. - NEVER use standard Control nodes for mass tokens/battlefields; strictly use `_draw()` custom drawing to bypass SceneTree overhead when rendering 100+ cards or map icons.
- NEVER rely on SceneTree order for hand logic; strictly manage logical order in an Array and update visuals via `queue_redraw()`.
- NEVER erase array elements during a standard
forloop; strictly iterate in reverse or usefilter()to avoid indexing errors. - NEVER forget to provide parameterless constructors in
_init(); otherwise, Resources will fail to load in the Inspector.
Aurelius Protocol: Genre Educational NEVER List
- NEVER punish failure with a "Game Over"; strictly use "Try Again" or Contextual Hints to ensure a safe, encouraging learning environment.
- NEVER separate learning from gameplay ("Chocolate-covered broccoli"); strictly ensure the mechanic IS the learning (e.g., math-based trajectory calc).
- NEVER use walls of text for instructions; strictly use Show, Don't Tell methods: interactive diagrams, non-verbal tutorials, or 3-second looping GIFs.
- NEVER skip Spaced Repetition logic; strictly ensure successfully answered questions reappear at increasing intervals to verify long-term retention.
- NEVER focus on failure; strictly prominently display Mastery %, XP Bars, and Skill Trees to motivate through visible progress.
- NEVER use static difficulty; strictly implement Adaptive Scaling to maintain the "Flow State" (target ~70% success rate).
- NEVER hardcode text into UI; strictly use Translation Keys (PO files) for internationalization and classroom localized support.
- NEVER force TTS without user consent; strictly provide an in-game toggle and respect OS-level screen reader settings.
- NEVER use absolute pixel positioning; strictly use the Anchoring & Container system for responsive scaling across tablets and classroom laptops.
- NEVER perform heavy data grading on the main thread; strictly use WorkerThreadPool to prevent UI freezes during automated assessments.
- NEVER forget to handle IME updates; strictly monitor
NOTIFICATION_OS_IME_UPDATEfor complex character input support (e.g., East Asian). - NEVER ignore
mouse_filteron overlays; strictly set toPASSto prevent invisible containers from silently consuming clicks. - NEVER update static strings in
_process(); strictly update labels ONLY on state change events to save mobile/tablet battery. - NEVER embed sensitive database credentials in exports; strictly use Environment Variables or proxy APIs for student data security.
Aurelius Protocol: Genre Fighting NEVER List
- NEVER use variable framerates; strictly lock logic to a Deterministic Fixed Loop (using
_physics_processwith a frame-counter) and call `reset_physics_interpolation()` on teleport. - NEVER use standard Physics for hit detection; strictly use `PhysicsDirectSpaceState.intersect_shape()` to query hitboxes instantly without Area2D signal lag.
- NEVER skip Damage Scaling; strictly apply 10% reduction per hit in a combo to prevent infinite matches.
- NEVER make all moves safe on block; strictly ensure high-reward moves have Recovery Windows where the attacker is punishable.
- NEVER rely on
Area2D.get_overlapping_areas(); strictly use `intersect_shape()` for immediate, frame-perfect resolution. - NEVER forget Hitbox Proximity (Proximity Guard); strictly trigger guard states when a hitbox enters a nearby zone, even if it hasn't landed.
- NEVER use simple parenting (
scale.x = -1) for character flip; strictly adjust the dedicated Visuals node while managing hitbox offsets programmatically. - NEVER use string-based animation triggers; strictly use
AnimationMixerwithADVANCE_MANUALfor frame-synced playback. - NEVER use
yieldorawaitfor frame-critical logic; strictly use Integer Frame Counting within state machines to manage recovery/startup windows perfectly. - NEVER store frame data in raw scripts; strictly use `Resource` files (.tres) with delegated logic for damage scaling, cancels, and combo-state tracking.
- NEVER use deep node hierarchies for character parts; strictly keep skeletons shallow to reduce transformation overhead.
- NEVER skip Input Buffering; strictly implement a 5-10 frame buffer to ensure lenient, responsive execution for the player.
- NEVER leave
Input.use_accumulated_inputenabled; strictly disable it to preserve sub-frame timing for precise combo links. - NEVER use client-side hit detection for netplay; strictly use rollback netcode or server validation to prevent desyncs.
- NEVER use standard TCP for multiplayer; strictly use UDP/ENet to avoid head-of-line blocking during latency spikes.
- NEVER rely on the SceneTree for fighter transforms in netplay; strictly manage positions in a serializable data buffer.
Aurelius Protocol: Genre Horror NEVER List
- NEVER maintain 100% tension at all times; strictly use a Sawtooth Pacing model (buildup → peak/scare → dedicated relief period) to prevent player "numbing" and exhaustion.
- NEVER rely on jump-scares as the primary source of horror; focus on atmosphere, spatial audio cues, and the anticipation of a threat to build genuine dread.
- NEVER make environments pitch black to the point of frustrating navigation; darkness should obscure threats (details), not the floor. Use rim lighting or a limited-battery flashlight.
- NEVER grant the player unlimited resources; survival horror relies on Scarcity. Limited battery, rare ammo, and slow animations are mandatory to force stressful decision-making.
- NEVER allow AI to detect the player instantly; implement a Suspicion Meter or a 1-3s reaction window before the AI enters full aggression to avoid "unfair cheating" feel.
- NEVER use predictable AI paths; an enemy on a perfect loop is a puzzle, not a predator. Use the Director to periodically "hint" a new destination near the player.
- NEVER use Area3D overlap signals for instant, frame-perfect Line-of-Sight (LoS) checks; use nodeless raycasting via
PhysicsDirectSpaceState3D.intersect_ray()for fixed-physics sync. - NEVER calculate complex AI vision or pathfinding for monsters far outside the camera's frustum; use
VisibleOnScreenNotifier3Dto disable processing logic. - NEVER leave navigation avoidance layers unconfigured on chasing monsters; explicitly assign avoidance masks to prevent visual "stacking" in tight corridors.
- NEVER use the visual SceneTree (like GridContainer children) as the source of truth for inventory; strictly maintain a typed memory structure like
Dictionary[StringName, Resource]. - NEVER rely on instantiating standard Nodes to store base item stats/definitions; use custom
Resourcescripts to reduce memory overhead and allow direct Inspector editing. - NEVER forget to call
duplicate(true)on an item's Resource when adding to inventory; if items have mutable states (ammo/durability), you will overwrite the global resource otherwise. - NEVER parse massive JSON save files synchronously; strictly offload heavy parsing to the
WorkerThreadPoolto prevent auto-save freezes. - NEVER use standard strings for hot-path IDs (states, item types); strictly use
StringName(&"chasing") for pointer-speed comparisons. - NEVER evaluate exact floating-point equality (sanity == 0.0); strictly use
is_equal_approx()or threshold checks for deterministic triggers. - NEVER write screen-reading shaders expecting Godot 3
SCREEN_TEXTURE; strictly usesampler2Dwithhint_screen_texture. - NEVER instantiate detailed monster meshes or lights without culling; strictly configure
visibility_rangefor automatic HLOD efficiency. - NEVER rely on AnimationPlayer for random flickering; use
Tweenfor programmatic, clean energy manipulation. - NEVER load heavy scare scenes or 4K textures synchronously via
load(); strictly useResourceLoader.load_threaded_request()to prevent frame stalls. - NEVER scale CollisionShape3D non-uniformly; strictly adjust internal shape resource parameters (radius, height) to prevent erratic physics.
Aurelius Protocol: Genre Idle Clicker NEVER List
- NEVER use standard floats for currency; strictly implement a BigNumber (Mantissa/Exponent) system (e.g.,
1.5e300) to preventINFcrashes at 1e308. - NEVER use
Timernodes for revenue generation; strictly use a manual accumulator in_process(delta)to prevent drift during frame fluctuations. - NEVER hardcode generator costs or growth; strictly use an exponential formula:
Cost = BasePrice * pow(GrowthFactor, OwnedCount)(industry standard 1.15x). - NEVER evaluate exact float equality (
==); strictly useis_equal_approx()or>=to prevent "stuck" progress due to precision loss. - NEVER parse scientific notation strings with
to_int(); strictly useto_float()or a dedicated BigNumber parser. - NEVER update all UI labels every frame; strictly use Signals to update labels ONLY when values change, or throttle updates to 10 FPS.
- NEVER ignore Low Processor Usage Mode for mobile; strictly enable
OS.low_processor_usage_mode = trueto preserve battery life. - NEVER instantiate/delete hundreds of text nodes per second; strictly use Object Pooling or
MultiMeshInstancefor click-feedback. - NEVER update massive logs by modifying the
textproperty; strictly useappend_text()to prevent main thread blocking. - NEVER ignore Offline Progress; strictly calculate
seconds_offline * total_revenueusing system UNIX timestamps (Time.get_unix_time_from_system()). - NEVER make the "Prestige" reset feel like a loss; strictly provide a global multiplier that makes the next run significantly faster (2-5x).
- NEVER calculate offline time using
Time.get_ticks_msec(); strictly use Persistent UNIX timestamps as ticks reset on app restart. - NEVER use Node hierarchies for raw data; strictly use
RefCountedorResourceobjects for lightweight, serializable logic.
Aurelius Protocol: Genre Metroidvania NEVER List
- NEVER allow "Soft-Locks" where a player is trapped; if they enter via a one-way path ("valve"), they MUST be able to leave using current abilities. Always design fail-safe escape routes.
- NEVER create empty dead ends; if a player backtracks to a remote area, they MUST be rewarded with a collectible, lore, or currency. Empty rooms are design failures.
- NEVER make backtracking purely repetitive; as the player gains movement (Dash/Teleport), traversal through old areas MUST become faster. Open shortcuts to bypass long, early routes.
- NEVER hide the critical path without "crumbs"; use distinct Landmarks, unique lighting, or environmental storytelling to build the player's mental map.
- NEVER design abilities that serve only one purpose; strictly implement dual-use traversal and combat functionality (e.g., a "Dash" that crosses gaps and dodges attacks).
- NEVER forget to save persistent room state; if a player opens a chest or defeats a boss, that state MUST remain saved when they leave and return.
- NEVER load interconnected rooms synchronously via
load(); strictly useResourceLoader.load_threaded_request()for seamless transitions. - NEVER track global progression within localized room scripts; strictly use Autoload Singletons for global ability flags and world state.
- NEVER use floating-point types for grid coordinates (minimaps/fog); strictly use
Vector2ito prevent precision jitter. - NEVER manipulate the SceneTree directly from a background loading thread; strictly use
call_deferred(). - NEVER calculate jump arcs or dashes inside
_process(); strictly use_physics_process()to prevent stutter. - NEVER multiply
CharacterBody2Dvelocity bydeltabeforemove_and_slide(); the engine handles this internally. - NEVER poll
is_action_just_pressed()inside_physics_process()for buffering; strictly capture events in_unhandled_input(). - NEVER use standard strings for high-frequency ability checks; strictly use
StringName(&"dashing") for pointer-speed comparisons. - NEVER iterate through every node to broadcast updates; strictly use
SceneTree.call_group()for efficient mass communication. - NEVER delete active room/player nodes via
free(); strictly usequeue_free()to avoid segmentation faults.
Aurelius Protocol: Genre Moba NEVER List
- NEVER trust the client for damage calculation or resource costs; strictly validate mana, ranges, and hit detection on the authoritative server using
multiplayer.is_server(). - NEVER use
TRANSFER_MODE_RELIABLEfor continuous movement; strictly useUNRELIABLEorUNRELIABLE_ORDEREDfor position/velocity to prevent network congestion. - NEVER sync units at 60Hz; strictly use a lower tick rate (10-20Hz) via
MultiplayerSynchronizerand implement Interp/Client-Side Prediction for visual smoothness. - NEVER attach individual synchronizers to hundreds of minions; strictly batch state updates into compressed byte arrays via a central manager.
- NEVER synchronize complex Engine objects directly; strictly serialize state into primitive properties or Dictionaries for reliable peer-to-peer sync.
- NEVER use expensive pathfinding for all minions every frame; strictly use Time Slicing to spread
get_next_path_position()calls across multiple frames. - NEVER query
NavigationAgentpaths inside_process(); strictly use_physics_process()to interact with the navigation server and avoidance systems. - NEVER use complex visual geometry for NavMesh baking; parse simple primitives to avoid stalling the
RenderingServeror crashing the engine. - NEVER set
path_search_max_polygonstoo low in large maps; agents will stop or walk incorrectly if the limit is reached before the destination. - NEVER use
Area2Dfor high-performance Fog of War LOS; strictly use nodeless physics queries (intersect_ray) to bypass node overhead. - NEVER forget Tower "Dive" protection; towers MUST switch targets immediately if an enemy Hero damages an allied Hero within range (Priority: Hero attacking Ally > Minion > Hero).
- NEVER allow "Snowballing" without counter-play; strictly implement Comeback Mechanisms (Kill Bounties, Catch-up XP) to maintain competitive tension.
- NEVER manage hero stats as standard Node variables; strictly use custom
Resourcescripts for data separation and memory efficiency. - NEVER forget to call
duplicate(true)on shared ability Resources; modifying a buff on a shared resource will affect all heroes globally. - NEVER use standard strings for status checks (e.g., "stunned"); strictly use
StringName(&"stunned") for pointer-speed comparisons. - NEVER loop over massive Fog of War grids with floats; strictly use
Vector2iandTileMapLayerto prevent precision jitter. - NEVER execute heavy world/minimap logic on the main thread; strictly offload complex array math to
WorkerThreadPoolto maintain 60+ FPS. - NEVER rigidly couple UI cooldowns to Hero scripts; strictly use a Signal Bus or
Callablebindings for decoupled architecture. - NEVER evaluate exact floating-point equality (==); strictly use
is_equal_approx()for range, cooldown, and mana validations.
Aurelius Protocol: Genre Open World NEVER List
- NEVER prioritize Map Size over Density; empty landscapes are poor design. Strictly focus on Points of Interest (POIs) within every 30 seconds of travel.
- NEVER save the entire world state; strictly use Delta Persistence to record only unique changes (chopped trees, looted chests) to prevent massive save files.
- NEVER load large chunks or scenes synchronously; strictly use `ResourceLoader.load_threaded_request()` to prevent "Loading Hitches" and frame freezes.
- NEVER manipulate the active SceneTree directly from a background thread; strictly use `call_deferred()` to safely apply background thread chunk instantiations back to the main thread.
- NEVER keep distant, unloaded chunks in memory; strictly
queue_free()and nullify references to prevent Out-Of-Memory (OOM) crashes. - NEVER bake massive collision into one mesh; strictly break the world into chunks with local collision regions for efficient physics queries.
- NEVER save high-volume entity states in text formats (.tscn/.json); strictly use Binary Serialization (
store_var) for high-speed I/O. - NEVER ignore the "Floating Origin" jitter beyond 8,192 units; strictly implement a World-Shift system or enable Large World Coordinates (Double Precision) in project settings.
- NEVER process physics or AI at extreme distances; strictly use Spatial Partitioning to disable logic for entities in far-away, inactive chunks.
- NEVER calculate physics-sensitive state in
_process(); strictly use_physics_process()for deterministic interaction at fluctuating framerates. - NEVER spawn individual
MeshInstance3Dnodes for massive foliage; strictly use MultiMeshInstance3D to batch hundreds of thousands of meshes into a single GPU draw call. - NEVER move
OccluderInstance3Dnodes at runtime; this forces a CPU BVH rebuild and causes severe micro-stuttering. - NEVER leave
CSGShape3Dnodes active in exported builds; strictly bake them into staticArrayMeshgeometry before shipping. - NEVER compile complex shaders during gameplay; strictly perform "warm-up" during loading or enable project-wide caching.
- NEVER rely solely on automatic mesh decimation; strictly use VisibilityRange (HLOD) to substitute complex materials with cheap imposters or completely hide objects at extreme distances.
- NEVER perform global A* searches across the entire massive world; strictly use
NavigationPathQueryParameters3Dto limit pathfinding to localized active regions. - NEVER use
find_child()or deep tree iteration for global state (e.g., Time of Day); strictly use Scene Groups (call_group()) for optimized broadcasting. - NEVER synchronize complex Resource types over the network; strictly serialize world changes into primitive Dictionaries or PackedByteArrays.
Aurelius Protocol: Genre Party NEVER List
- NEVER hardcode player inputs to specific joypad IDs (e.g., 0 or 1); strictly query dynamically via
Input.get_connected_joypads(). - NEVER bake player-IDs into the input map (e.g., "p1_jump"); strictly use a Dynamic Input Router to map physical controllers to players at runtime.
- NEVER use
Input.is_action_pressed()for assigning new player joins; strictly parse rawInputEventJoypadButtonin_unhandled_input()for device metadata. - NEVER allow inconsistent controls between games; strictly standardize across all minigames (A = Accept/Action, B = Back/Cancel, Joystick = Move).
- NEVER assume a disconnected joypad removes a player; strictly connect to the
joy_connection_changedsignal to pause and handle dropouts gracefully. - NEVER use boolean polling for analog sticks; strictly use
Input.get_vector()for precision and deadzones. - NEVER use long text-based tutorials; strictly use a 3-second looping GIF + a single-sentence instruction overlay (e.g., "Mash A to fly!").
- NEVER ignore "Asymmetric" balance in 1v3 games; strictly provide the "One" with unique abilities or increased HP/speed to offset the numerical disadvantage.
- NEVER neglect Accessibility and Handicap systems; strictly implement optional support (e.g., speed boosts for lower-skilled players) to keep the competition social.
- NEVER leave UI Control nodes with
FOCUS_NONEfor gamepad menus; strictly set toFOCUS_ALLwith explicit focus neighbors for accessible navigation. - NEVER use heavy scene transitions; strictly keep minigame assets light and use Threaded Background Loading while the instructions screen is active.
- NEVER draw global
CanvasLayerUI for individual split-screen players; strictly use per-viewportCanvasLayerchildren. - NEVER manually set sizes on
SubViewportchildren; strictly useGridContainerorBoxContainerfor automatic split-screen layout. - NEVER store tournament state or scores inside minigame scenes; strictly use a Persistent Autoload (Singleton).
- NEVER use a static
Camera2Dfor shared-room games; strictly use a dynamic group camera that zooms/pans to fit all players in frame. - NEVER overlap
SubViewportContainernodes without settingmouse_filtertoPASS; otherwise, top viewports will block input.
Aurelius Protocol: Genre Platformer NEVER List
- NEVER multiply velocity by
deltabeforemove_and_slide(); the method internalizes the timestep. - NEVER skip Coyote Time (approx 0.1s); without this grace period, jumps will feel unresponsive when walking off ledges.
- NEVER ignore Jump Buffering (approx 0.15s); players expect to jump the instant they touch the ground if they pressed the button early.
- NEVER use a fixed jump height; strictly implement Variable Jump Height (cut velocity on release) for player expression.
- NEVER forget to scale gravity by
deltabefore adding to velocity; gravity is an acceleration and must be frame-rate independent. - NEVER rely on discrete collision for high-speed movement; strictly use
CCD_MODE_CAST_RAYto prevent tunneling through geometry. - NEVER use
move_and_collide()for standard traversal; it lacks the slope/stair handling ofmove_and_slide(). - NEVER check coyote or buffer timers using exact equality (== 0.0); strictly use
is_equal_approx()or>= 0.0. - NEVER use linear camera snapping; strictly use Camera Smoothing or
lerp()to prevent motion sickness. - NEVER skip Squash and Stretch on jump/land; movement feels weightless without these subtle visual "juice" cues.
- NEVER create Blind Jumps; strictly use camera look-ahead or zoom triggers to reveal landing zones.
- NEVER use individual
Sprite2Dnodes for level geometry; strictly use TileMapLayer for optimized collision and rendering. - NEVER use complex/concave
CollisionShape2Dfor the player; strictly favor primitive shapes (Capsule/Rectangle) for stability. - NEVER use
CharacterBody2Dfor simple moving platforms; strictly use AnimatableBody2D and enablesync_to_physics. - NEVER ignore
platform_on_leavefor descending platforms; usePLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITYto preserve jump impulse. - NEVER disable
recovery_as_collisionon the player character; it is required for correct floor snapping reports. - NEVER use the
!(NOT) operator in AnimationTree expressions; strictly useis_walking == false. - NEVER use standard Strings for high-frequency state checks; strictly use
StringName(e.g.,&"jumping"). - NEVER load heavy level chunks synchronously; strictly use
ResourceLoader.load_threaded_request()to prevent frame stutters.
Aurelius Protocol: Genre Puzzle NEVER List
- NEVER punish experimentation; strictly provide Undo/Reset functionality to allow risk-free hypothesis testing.
- NEVER require pixel-perfect input for logic puzzles; strictly use Grid Snapping or large, forgiving hitboxes.
- NEVER allow undetected Soft-Locks (unsolvable states); strictly notify the player or provide immediate backtracking.
- NEVER hide the rules of the world; strictly ensure visual feedback is instant and unambiguous (e.g., powered wires must glow).
- NEVER skip the Non-Verbal Tutorial phase; strictly introduce mechanics in isolation before combining them.
- NEVER use floating-point numbers (
Vector2) for grid coordinates; strictly use Vector2i to prevent precision drift. - NEVER use
_process()for grid-state or win-condition validation; strictly trigger checks only when a piece moves. - NEVER rely on the
SceneTreestructure as the source of truth; strictly maintain grid data in a separate script/dictionary. - NEVER modify a Dictionary or Array size while iterating over it; strictly use a copy or a separate queue for modifications.
- NEVER calculate heavy recursive solvers in
_process(); strictly cache results or use threaded workers for solve-checks. - NEVER ignore diagonal rules in pathfinding; strictly configure
AStarGrid2D.diagonal_modecorrectly. - NEVER program custom command history queues manually; strictly use Godot's built-in UndoRedo system for reliability.
- NEVER intermingle "do" and "undo" logic in the same function; strictly maintain separation for predictable rollbacks.
- NEVER use exact floating-point equality (==); strictly use
is_equal_approx()for spatial constraints. - NEVER use
load()for resetting large rooms dynamically; strictly useResourceLoader.load_threaded_request(). - NEVER leave Tween objects unreferenced; strictly kill active tweens before starting new movement on the same object.
Aurelius Protocol: Genre Racing NEVER List
- NEVER use a rigid camera attachment; strictly use a Smooth Follow pattern with
lerp()to prevent motion sickness. - NEVER prioritize realism over fun; strictly increase Gravity Scale (2x-3x) and keep friction high for responsive arcade feel.
- NEVER use
VehicleBody3Ddefault settings for karts; strictly rewrite suspension using Raycasts or custom spring/damper models. - NEVER apply steering torque directly to mass; strictly use a steering curve factored by lateral velocity.
- NEVER calculate suspension without a damper model; strictly include damping to prevent eternal oscillation (bouncing).
- NEVER ignore the Center of Mass property; strictly offset it downward to ensure stability during high-speed turns.
- NEVER multiply engine force by
delta; it is an integrated force in the physics solver. - NEVER rely on
is_action_pressed()for manual gear shifting; strictly useis_action_just_pressed()for single-tap accuracy. - NEVER use static AI speeds; strictly use Rubber-Banding to keep races competitive based on player distance.
- NEVER run AI pathfinding across the entire track every frame; strictly use a "Look-Ahead" point on a spline/path.
- NEVER ignore racing Checkpoints; strictly enforce sequential
Area3Dvalidation to prevent track shortcuts. - NEVER use standard
Area3Dfor slipstreaming without a Dot Product check to ensure the player is directly behind. - NEVER skip "Sense of Speed" effects; strictly implement dynamic FOV scaling, motion blur, and high-speed camera shake.
- NEVER update minimap transforms for static elements in
_process(); strictly update dynamic racers only. - NEVER serialize ghost cars as mass transform lists; strictly store positions/quaternions at fixed intervals.
- NEVER use constant pitch for engine sounds; strictly map RPM or engine load to
pitch_scale. - NEVER spawn particles for skid marks every frame; strictly use Trail3D or procedural strips for low-cost persistence.
- NEVER use standard Strings for surface detection; strictly use
StringName(e.g.,&"asphalt").
Aurelius Protocol: Genre Rhythm NEVER List
- NEVER use
Time.get_ticks_msec()for rhythm sync; strictly use `AudioServer.get_time_since_last_mix()` combined with latency offsets for sub-frame accuracy. - NEVER process song logic in
_process(); strictly use `_physics_process()` or a conductor loop to ensure deterministic timing regardless of render frames. - NEVER use
_process()to capture hit inputs; strictly use `_input(event)` to record the exact timestamp of the button press event. - NEVER scale engine time_scale for song speed; strictly use `AudioStreamPlayer.pitch_scale` to adjust speed and avoid globally breaking physics logic.
- NEVER ignore Audio Latency Calibration; strictly provide a manual offset menu to compensate for varied hardware (Bluetooth vs Wired).
- NEVER use
yieldorawaitfor beat timing; strictly use a sample-accurate Delta Accumulator tied to the audio clock. - NEVER assume a constant BPM; strictly build your conductor to handle a Tempo Map for complex track changes.
- NEVER judge inputs based on world position (pixels); strictly judge against the Song's Elapsed Time (ms) to ensure consistency across resolutions.
- NEVER play hit sounds with static pitch; strictly add ±5% Random Pitch Variation to hit sounds to avoid the "machine gun" effect.
- NEVER use tight timing windows (e.g., <25ms) for all players; strictly use Wider Windows for Beginners to prevent immediate frustration.
- NEVER instantiate note nodes every beat; strictly use Object Pooling to recycle note instances and prevent GC spikes during dense tracks.
- NEVER use standard Area2D signals for rhythmic hits; strictly Poll Inputs in the conductor loop to compare against target timestamps.
- NEVER calculate FFT for visualization on the main thread; strictly use AudioEffectSpectrumAnalyzerInstance for optimized engine-side analysis.
- NEVER allow note spamming/mashing; strictly penalize misses or break combos to maintain the game's integrity.
- NEVER use
load()dynamically during gameplay; strictly use ResourceLoader.load_threaded_request() to avoid thread stalling. - NEVER forget to pause the conductor/ highway; strictly sync with the audio player's pause state to prevent notes from scrolling while the music is stopped.
Aurelius Protocol: Genre Roguelike NEVER List
- NEVER make runs dependent on pure RNG; strictly provide mitigation (rerolls, shops, pity timers) to ensure every run is winnable.
- NEVER use unseeded RNG for world generation; strictly initialize isolated
RandomNumberGeneratorwith a predictable seed for daily runs/debugging. - NEVER rely on
@GlobalScope.randi()for critical logic; strictly use local RNG instances to prevent global state pollution. - NEVER use
Array.pick_random()for critical content drops; strictly use a Shuffle Bag to prevent statistically unfair streaks. - NEVER generate massive dungeons on the main thread; strictly use `WorkerThreadPool.add_task()` or `add_group_task()` to distribute generation across cores and prevent frame freezes.
- NEVER interact with the SceneTree from a background thread; strictly generate dungeon data in a thread-safe Array/PackedByteArray before parsing on the main thread.
- NEVER allow Save Scumming; strictly delete mid-run save files immediately upon loading to enforce permadeath.
- NEVER allow Run State to leak into Meta State; strictly use separate singletons or Resources for
RunManagerandMetaManager. - NEVER scale meta-progression to be overpowered (+100% damage); strictly keep upgrades subtle (+5-15%) to maintain skill-based play.
- NEVER forget to call
duplicate(true)on base stat Resources; failing to deep-duplicate causes all entities to share a single health instance. - NEVER save run states to
.tscnfiles; strictly serialize to JSON or binary inuser://to prevent bloat. - NEVER rely on the
SceneTreeas the source of truth for grid logic; strictly maintain grid data in a separate Dictionary or Array. - NEVER forget to handle Navigation re-baking; strictly rebake
NavigationRegion2DAFTER procedural tiles are placed. - NEVER use AStar2D for tile grids; strictly use `AStarGrid2D` with `jumping_enabled = true` (Jump Point Search) for O(1) queries and high-performance pathing across open areas.
- NEVER forget to call
update()onAStarGrid2Dafter modifying states; strictly ensures pathfinding queries aren't stale. - NEVER use floats (
Vector2) for discrete grid coordinates; strictly use Vector2i to prevent precision drift. - NEVER use Manhattan heuristics for 8-way movement; strictly use `HEURISTIC_CHEBYSHEV` or `HEURISTIC_OCTILE`.
- NEVER iterate over every cell coordinate (0 to W,H) in GDScript; strictly use
get_used_cells()for optimized tile access. - NEVER clear procedural levels using
free(); strictly usequeue_free()to avoid mid-frame segmentation faults. - NEVER broadcast mass state changes to a grid immediately; strictly use
call_deferred()or `call_group_flags` to avoid frame spikes during turn transitions. - NEVER use heavy TileMapLayer nodes for high-resolution Fog of War; strictly use a GPU Shader Mask via
ColorRectand anImageTextureupdated via `RenderingServer.texture_2d_update()`.
Aurelius Protocol: Genre Romance NEVER List
- NEVER create "Vending Machine" romance; strictly incorporate variables like NPC Mood, Timing, and Multi-Stat Thresholds to ensure characters feel autonomous.
- NEVER use binary Affection (Love/Hate); strictly use a Multi-Axial Model (Attraction, Trust, Comfort) for believable psychological depth.
- NEVER focus on 100% opaque stats; strictly provide Visible Indicators (heart UI, blushing text, pulsing hearts) to help players make informed choices.
- NEVER use the "Same Date Order" trap; strictly implement a Repetition Penalty (~30%) for visiting the same location twice in a row.
- NEVER forget "Missable" Milestones; strictly ensure meaningful consequences (e.g., missing events due to poor scheduling) to add weight to the experience.
- NEVER ignore NPC Autonomy; strictly allow NPCs to have their own Schedules and the ability to Reject the player based on low trust or conflicting events.
- NEVER use
_processfor typewriter text; strictly use Tweens on `visible_ratio` for frame-independent, smooth reveals. - NEVER parse massive narrative files on the main thread; strictly use `ResourceLoader.load_threaded_request()` to prevent transition stutters.
- NEVER use exact float math for affection checks; strictly use `is_equal_approx()` to avoid jitter-based logic failures.
- NEVER structure complex dialogue purely in code; strictly design dialogue trees as Custom `Resource` classes to decouple narrative data from logic.
- NEVER rely on the global OS clock for timed choices; strictly use `SceneTreeTimer` which respects
Engine.time_scaleand pause states. - NEVER leave invisible controls with
MOUSE_FILTER_STOP; strictly set toIGNOREorPASSon non-opaque layers to avoid blocking dialogue progression. - NEVER hardcode dialogue strings; strictly map text to Localization Keys and retrieve via
tr()for internationalization. - NEVER use absolute pixel positioning for interfaces; strictly rely on Anchoring & Containers for responsive scaling across devices.
Aurelius Protocol: Genre Rts NEVER List
- NEVER allow pathfinding "Jitter" when moving group units; strictly stagger path queries and enable RVO Avoidance only when units are in motion to save CPU cycles.
- NEVER update RVO avoidance every frame for all units; strictly use Avoidance Threading (Project Settings) and replace static units with
NavigationObstacle. - NEVER let units get stuck in infinite path loops; strictly implement a timeout and IDLE state if a destination is unreachable.
- NEVER use
_process()on hundreds of individual units; strictly use a central UnitManager or_physics_processonly when required. - NEVER calculate unit visibility manually for Fog of War; strictly use a Shader-based mask (SubViewport + ColorRect) for GPU efficiency.
- NEVER process unit AI or pathfinding synchronously for mass groups; strictly offload to `WorkerThreadPool` and stagger path updates.
- NEVER use high-poly visual meshes as NavMesh source geometry; strictly use simplified Collision Shapes for baking.
- NEVER forget Command Queuing (Shift-Click); strictly store an
Array[Command]and implement a "Force Move/Attack" bypass. - NEVER create excessive micromanagement; strictly automate low-level tasks like auto-aggro range and auto-return for resource gathering.
- NEVER use exact floating-point equality (==) for grid or timers; strictly use
is_equal_approx()for deterministic triggers. - NEVER rely on the visual SceneTree for selection data; strictly maintain a Typed Selection Set of
RefCountedorResourceobjects for deterministic serialization and netcode. - NEVER forget Command Queuing; strictly implement a Command Pattern using serializable
DictionaryorJSONstates for save-game and multiplayer playback. - NEVER forget to duplicate_deep() globally shared Resources; otherwise, modifying one unit's data (e.g., stats) affects all.
- NEVER render thousands of units using separate
MeshInstance3Dnodes; strictly use `MultiMeshInstance` with `INSTANCE_CUSTOM` data to drive unique GPU-side state animations (walking/attacking/color). - NEVER calculate transforms for mass units on the main thread; strictly use `WorkerThreadPool` to push buffers to
RenderingServer.multimesh_set_buffer(). - NEVER update every unit's navigation path in the same frame; strictly use random timers to stagger updates.
- NEVER use standard Strings for high-frequency AI state identifiers; strictly use StringName (&"harvesting") for pointer-speed comparisons.
- NEVER allow simulation coordinates to exceed 8192 units without float-precision management; strictly use world-origin shifts.
- NEVER use
CSGShape3Dfor building placement ghosts; strictly use optimized staticArrayMeshgeometry.
Aurelius Protocol: Genre Sandbox NEVER List
- NEVER use individual
RigidBodynodes for every block; strictly use Static Colliders for the world and reserve physics for dynamic props. - NEVER simulate the entire world every frame; strictly process "Dirty" chunks with active changes. Sleeping chunks must consume zero CPU.
- NEVER update
MultiMeshbuffers every frame; strictly batch changes and only rebuild the buffer when a modification completes (e.g., player stops painting). - NEVER use standard Godot
Nodesfor every grid cell; strictly use PackedInt32Arrays or typed Dictionaries to keep RAM overhead minimal. - NEVER raycast against every individual voxel for placement; strictly use Grid Quantization (
floor(pos/size)) for direct O(1) cell calculation. - NEVER render every block face in a chunk; strictly generate an
ArrayMeshthat only pushes visible exterior faces to the GPU (Culling/Greedy Meshing). - NEVER save raw arrays of every block transform; strictly use Run-Length Encoding (RLE) (e.g., "Air x 50,000") to compress uniform spaces.
- NEVER load massive terrain chunks synchronously; strictly use
ResourceLoader.load_threaded_request()to prevent frame stutter. - NEVER use standard text
.tscnfiles for voxel datasets; strictly use binary `.res` files for 10x faster parsing. - NEVER ignore Floating-Point Precision limits (32,768 units); strictly implement floating-origin shifting for massive worlds.
- NEVER hardcode element interactions (
if water and fire); strictly use a Property System where interactions emerge from material attributes (flammability, density). - NEVER trust client-side placement in multiplayer; strictly require the Server to validate bounds and resources.
- NEVER manipulate the SceneTree from background generation threads; strictly use
call_deferred()or Mutex locks for safety. - NEVER leave orphaned chunks in memory; strictly track loaded regions and call
queue_free()on discarded branches.
Aurelius Protocol: Genre Shooter Fps NEVER List
- NEVER use
_process()for hit detection; strictly use_physics_process()to maintain frame-rate independent accuracy. - NEVER apply recoil to the physical weapon model; strictly apply it to Camera Rotation (kick) and Weapon Bloom (spread).
- NEVER trust the client for hit registration in multiplayer; strictly use Server-Authoritative validation with lag compensation.
- NEVER synchronize every bullet over the network; strictly use Client-Side Prediction and send only initial "Fire" events.
- NEVER use
Area3Dormove_and_collide()for high-speed ballistics; strictly usePhysicsDirectSpaceState3D.intersect_ray()for 100x better performance. - NEVER forget to exclude the player's own RID from hitscan raycasts; otherwise, shots will collide instantly with the barrel.
- NEVER use exact floating-point equality (==) for weapon cooldowns or timers; strictly use
is_equal_approx(). - NEVER use a single
AudioStreamPlayerfor gunfire; strictly use Layered Audio (Mechanical + Shot + Reverb Tail). - NEVER instantiate and
free()hundreds of projectile nodes; strictly use Object Pooling or theRenderingServer. - NEVER use
Sprite3DorQuadMeshfor bullet impacts; strictly use the Decal node for surface-conforming texture projection. - NEVER leave decals in the scene indefinitely; strictly implement a fade-out and cleanup cycle.
- NEVER use
Transform3D.looking_at()for forward shooting vectors; strictly extract the direction from-transform.basis.z. - NEVER multiply velocity by
deltabeforemove_and_slide(); the method internalizes the timestep automatically. - NEVER poll mouse motion inside
_physics_process(); strictly use_input()for zero-latency camera look. - NEVER accumulate mouse rotation directly onto a
Transform3D; strictly store Yaw/Pitch variables to avoid gimbal lock. - NEVER hardcode weapon statistics (Damage, Recoil) inside logic; strictly use Resource-based WeaponData for balancing.
- NEVER tightly couple damage logic to specific classes; strictly use Duck-Typing (
has_method("take_damage")) for environment interactivity. - NEVER use standard Strings for high-frequency state identifiers; strictly use
StringName(e.g.,&"reloading"). - NEVER use the
!(NOT) operator in AnimationTree expressions; strictly useis_firing == false. - NEVER connect weapon signals via string-based calls; strictly use Signal-Object syntax (
fired.connect).
Aurelius Protocol: Genre Shooter NEVER List
- NEVER use
_process()for hit detection; strictly use `_physics_process()` to maintain frame-rate independent accuracy (aiming/firing are physics events). - NEVER apply recoil solely to the weapon model transform; strictly apply it to Camera Rotation (kick) and Weapon Bloom (spread).
- NEVER use
Area3Doverlap for high-speed hit detection; strictly use `PhysicsDirectSpaceState3D.intersect_ray()` for 100x better performance. - NEVER trust the client for hit registration in multiplayer; strictly use Server-Authoritative validation using lag compensation (rewinding).
- NEVER synchronize every bullet over the network; strictly use Client-Side Prediction for visual tracers and only send the initial "Fire" event.
- NEVER forget to exclude the player's own RID from hitscan raycasts; strictly use `add_exception()` to prevent shots colliding with the weapon barrel.
- NEVER use exact floating-point equality (==) for bullet damage or health; strictly use `is_equal_approx()` to mitigate precision loss.
- NEVER hardcode weapon statistics (Damage, Recoil) inside logic; strictly use Resource-based WeaponData for rapid balancing.
- NEVER use a single
AudioStreamPlayerfor gunfire; strictly use Layered Audio (Mechanical + Shot + Reverb Tail) for punchy feedback. - NEVER instantiate and
free()hundreds of projectile nodes; strictly use Object Pooling or thePhysicsServer3DAPI for stability. - NEVER use
Sprite3Dfor bullet impacts on surfaces; strictly use the Decal node for conforming, perspective-correct projection. - NEVER use absolute pixel positioning for crosshairs; strictly rely on Anchors & RectCenter to ensure accuracy across resolutions.
- NEVER scale
CollisionShape3Dnon-uniformly; strictly scale the Internal Shape Resource to maintain valid physics calculations. - NEVER use TCP for multiplayer shooter synchronization; strictly use ENet (UDP) with unreliable transfer modes to avoid latency spikes.
Aurelius Protocol: Genre Simulation NEVER List
- NEVER use floating-point for primary currency; strictly use Integer Cents (or fixed-point math) to prevent accumulated precision errors in financial models.
- NEVER process 1000+ entities individually in
_process(); strictly use a Tick Manager to batch updates or process entities in rotating pools. - NEVER rely on linear cost scaling; strictly use Exponential Growth (
Base * pow(1.15, Level)) to maintain challenge and strategic tension. - NEVER hide critical metrics from the player; strictly provide Detailed Breakdowns (Income vs. Expense) so players can make optimization-based decisions.
- NEVER allow infinite resource stacking; strictly enforce Logistical Caps (warehouses/silos) to create meaningful space-management gameplay loops.
- NEVER let the early game become a "Waiting Simulator"; strictly Front-Load Decisions and quick early wins to build player momentum.
- NEVER modify a shared Resource directly; strictly use `duplicate()` to avoid unintentionally updating every building of that type.
- NEVER tie simulation logic to the visual framerate; strictly use `_physics_process()` or delta accumulators for deterministic simulation results.
- NEVER update UI labels every frame; strictly use Event-Driven Signals to refresh UI ONLY when the underlying data changes.
- NEVER run heavy economic loops synchronously; strictly use WorkerThreadPool to offload complex calculations and prevent UI stutters.
- NEVER store massive resource data as Nodes; strictly use `RefCounted` or Data Resources to avoid the memory/CPU overhead of the SceneTree.
- NEVER ignore `OS.low_processor_usage_mode`; strictly enable it for stationary management screens to save massive CPU/Battery life.
- NEVER manipulate the SceneTree from background threads; strictly use `call_deferred()` for thread-safe UI updates.
- NEVER parse large JSON save files on the main thread; strictly use Threaded Serialization or optimized binary
.resformats. - NEVER use standard equality (==) for needs; strictly use `is_equal_approx()` to prevent floating-point jitter failures in logic gates.
Aurelius Protocol: Genre Sports NEVER List
- NEVER parent the ball directly to a player Transform; strictly keep it a standalone
RigidBody3Dand useapply_central_impulse()for realistic dribble physics. - NEVER allow the ball to "Tunnel" through goals; strictly enable Continuous CD (
continuous_cd = true) on the ball's properties for high-velocity validation. - NEVER scale a
CollisionShape3Dnon-uniformly; strictly adjust the resource radius to preserve the internal moment of inertia. - NEVER apply impulses in
_process(); strictly use_physics_process()or_integrate_forces()to prevent visual jitter. - NEVER use a single collision shape for characters; strictly use layered shapes for Head, Torso, and Legs to enable headers and chest-traps.
- NEVER allow all AI to chase the ball ("Kindergarten Soccer"); strictly implement Formation Slots (Defense/Attack) where only the closest 1-2 players engage.
- NEVER use perfect goalkeeper reflexes; strictly add a Reaction Delay (0.2s-0.5s) and an "Error Rate" based on shot angle and velocity.
- NEVER ignore Root Motion for movement; strictly use
AnimationTreewith root motion to ensure momentum and turns are visually grounded. - NEVER trust client-side goal validations; strictly require the Authoritative Server to validate physics and score logic.
- NEVER rely on the default physics tick rate (60 TPS) for fast-moving ballistics; strictly increase physics_ticks_per_second (e.g., to 120 or 240) to prevent tunneling.
- NEVER leave Physics Interpolation disabled if you want broadcast-quality smoothness; enable it in Project Settings to smooth ball transforms between ticks on high-refresh monitors.
- NEVER parent the ball directly to a player Transform; strictly keep it a standalone
RigidBody3Dand useapply_central_impulse()for realistic dribble physics. - NEVER skip vector normalization on joystick input; strictly normalize to prevent diagonal movement from being 1.4x faster.
- NEVER handle contextual buttons with
is_action_pressed(); strictly use a ContextManager to determine if Button A means "Pass", "Tackle", or "Switch". - NEVER evaluate an
Area3Dgoal trigger immediately; strictlyawait get_tree().physics_frameto allow the Physics Server to sync.
Aurelius Protocol: Genre Stealth NEVER List
- NEVER use binary "Seen/Not Seen" detection; strictly use a Gradual Detection Meter (0-100%) that builds based on distance, light level, and speed.
- NEVER use standard
RayCast3Dnodes for massive amounts of vision checks; strictly use `PhysicsDirectSpaceState3D.intersect_ray()` to query the PhysicsServer instantly and nodelessly. - NEVER allow AI to see through solid geometry; strictly use raycasts between AI eyes and player sample points (Head/Torso/Feet).
- NEVER use a single sample point for visibility; strictly sample at least 3 points (Head, Torso, Feet) to prevent detection bugs when partially in cover.
- NEVER forget to pass the guard's own RID into the raycast exclude array; if omitted, the ray will hit the guard's own body, causing false blocking.
- NEVER run complex AI detection for off-screen guards; strictly use
VisibleOnScreenNotifier3Dto pause heavy logic for distant enemies. - NEVER use a simple
distance_to()check for hearing; strictly calculate sound travel along the Navigation Path to determine if a wall blocks noise. - NEVER make combat as viable as stealth; strictly ensure "going loud" triggers intense reinforcements or high-lethality states to preserve the stealth loop.
- NEVER hide the "Why" of detection; strictly provide immediate feedback via UI icons (?, !) or audio barks ("What was that?").
- NEVER ignore the return value of
intersect_ray(); strictly checkis_empty()first to prevent runtime crashes. - NEVER assume a raycast won't hit the guard itself; strictly exclude the guard's RID from Query Parameters.
- NEVER tightly couple AI to player scripts; strictly use duck-typing (e.g.,
if body.has_method("get_detected")) so guards can spot decoys or dead bodies without brittle dependencies. - NEVER maintain hardcoded arrays to trigger base-wide alarms; strictly add guards to a "guards" group and use
get_tree().call_group()for dynamic notification. - NEVER use standard Strings for AI state; strictly use
StringName(&"alert") for O(1) pointer-level comparisons in high-frequency loops. - NEVER bake massive NavigationMeshes synchronously; strictly use
use_async_iterationsto prevent main thread stalls during runtime bakes. - NEVER rely on
Node.find_child()during gameplay; strictly use Groups or exported references for O(1) player tracking. - NEVER leave CollisionShapes enabled on incapacitated bodies; strictly disable them or move them to a "corpse" layer to prevent pathing interference.
Aurelius Protocol: Genre Survival NEVER List
- NEVER use constant "Needs" decay; strictly scale with activity (e.g., Sprinting drains hunger 3x faster than idling).
- NEVER use Instant Death for starvation/dehydration; strictly trigger gradual HP drain and provide distinct visual/audio warnings.
- NEVER use float timers for exact life-critical checks; strictly use
is_equal_approx()or<=to prevent 0.0 precision misses. - NEVER represent world time/day cycles within UI scripts; strictly use an AutoLoad (Singleton) to decouple state from visuals.
- NEVER make gathering tedious without progression; strictly implement Tiered Tool Scaling (e.g., Stone Axe = 1 wood/hit, Steel Axe = 5 wood/hit) to reward technical advancement.
- NEVER allow infinite inventory stacking; strictly use Weight Capacity or strict Stack Limits (e.g., 64 items) to force strategic resource management.
- NEVER force players to "Guess" crafting recipes; strictly use a Discovery System where recipes unlock upon acquiring materials.
- NEVER forget to duplicate(true) a shared Resource (like Item Durability); otherwise, all instances will break simultaneously.
- NEVER store heavy item/crafting definitions in Node properties; strictly use custom Resource containers for lightweight data.
- NEVER spawn threats at Respawn Points; strictly enforce a Safe Zone radius (Beds/Spawn) where enemy spawning is prohibited.
- NEVER instance 10,000 individual
MeshInstance3Dnodes for foliage; strictly use MultiMeshInstance3D for batched draw calls. - NEVER load massive world chunks synchronously; strictly use
ResourceLoader.load_threaded_request()to prevent hitches. - NEVER save complex dictionaries to standard text files; strictly use binary serialization for speed and size efficiency.
- NEVER run procedural terrain/noise algorithms on the main thread; strictly offload to the WorkerThreadPool.
- NEVER hardcode massive crafting tables in GDScript; strictly use
ConfigFileor JSON for easy balancing and modding.
Aurelius Protocol: Genre Tower Defense NEVER List
- NEVER make all towers have the same niche; strictly ensure distinct specialties: Aura Slow, Armor Piercing, Anti-Air, Burst Sniper, and Splash Damage.
- NEVER allow a "Death Spiral" with no exit; strictly provide small comeback bonuses or interest on saved gold to prevent early inevitable failure.
- NEVER make early waves feel like busywork; strictly provide an "Early Call" bonus to skip wait times and accelerate engagement.
- NEVER trust client-side economy updates; strictly require the authoritative server to validate currency addition and tower purchases in co-op.
- NEVER allow the player to "Seal" the exit in mazing games; strictly validate path existence with `NavigationServer2D.map_get_path()` before finalizing tower placement.
- NEVER use synchronous
bake_navigation_polygon()for mazing; strictly offload to a worker thread to prevent 100ms+ frame hitches during placement. - NEVER use global coordinates for grid logic; strictly convert to Vector2i/Vector3i to ensure pixel-perfect tower alignment.
- NEVER call
get_overlapping_bodies()every frame; strictly use signals (body_entered/body_exited) to maintain a local target cache. - NEVER use
_process()for projectile movement if count > 500; strictly use the PhysicsServer2D/3D directly for high-performance bullet-hell tiers. - NEVER spawn hundreds of projectiles as full Nodes; strictly use Object Pooling to reuse resources and avoid garbage collection stutters.
- NEVER use standard Strings for priorities; strictly use
StringName(&"first", &"strongest") for O(1) hash comparisons in targeting loops. - NEVER ignore the
progressproperty on PathFollow nodes; strictly use it as the O(1) way to identify the target closest to exit. - NEVER process tower search logic every frame; strictly throttle ACQUIRE searches (e.g., every 5-10 frames) to save significant CPU cycles.
- NEVER scale Tower
CollisionShapenon-uniformly; strictly adjust the radius property of the Shape resource to preserve collision math. - NEVER delete enemies immediately on death; strictly use set_deferred("disabled", true) and wait one frame to prevent physics server crashes.
- NEVER hardcode waves in huge switch statements; strictly use Custom Resources (.tres) for clean balancing and sequence editing.
Aurelius Protocol: Genre Visual Novel NEVER List
- NEVER create the "Illusion of Choice" exclusively; strictly provide Immediate Dialogue Variations or Flag Changes even if the plot converges later.
- NEVER skip mandatory QoL features; strictly implement Auto-Play, Fast-Forward, and Backlog/History for replayability.
- NEVER display "Walls of Text"; strictly limit dialogue boxes to 3-4 Lines max to avoid intimidating the reader.
- NEVER hardcode dialogue text inside GDScripts; strictly store narrative scripts in External Files (JSON, CSV, or custom Resources) for iteration.
- NEVER ignore the Rollback mechanic; strictly maintain a history stack so players can undo miss-clicks or reread missed lines.
- NEVER use plain text for emotional beats; strictly use RichTextLabel BBCode (e.g.,
[shake],[wave]) to add visual weight. - NEVER parse massive narrative files on the main thread; strictly use `ResourceLoader.load_threaded_request()` to prevent transition stutters.
- NEVER use standard Strings for frequently accessed game flags; strictly use `StringName` (&"met_alice") for faster dictionary lookups.
- NEVER use
_processfor letter-by-letter animation; strictly use a Tween on `visible_ratio` for smooth, frame-independent reveals. - NEVER neglect character Z-ordering; strictly ensure the active speaker is brought to the front (highest
z_index) for visual clarity. - NEVER use absolute pixel positioning for character sprites; strictly rely on Anchors & Percent-based Offsets for responsive scaling.
- NEVER allow text animations to continue when the player skips; strictly set `visible_ratio` to 1.0 instantly on input.
- NEVER leave orphaned character sprites; strictly use `queue_free()` when actors exit the stage to prevent memory leaks.
Aurelius Protocol: Input Handling NEVER List
- NEVER poll input in `_process()` for gameplay actions — Use
_physics_process()or_unhandled_input()._process()is frame-rate dependent, causing dropped inputs at low FPS [22]. - NEVER use hardcoded key checks (e.g., `KEY_W`) — Always use
InputMapactions. Hardcoded keys prevent rebinding and break compatibility with non-QWERTY layouts [23]. - NEVER ignore analog stick deadzones — Drifting sticks at 0.05 magnitude will cause unintended movement. Implement a radial deadzone (not axial) in code or settings [24].
- NEVER assume a single input device — Players may switch between Keyboard and Controller mid-session. Use
Input.joy_connection_changedto update UI prompts dynamically [25]. - NEVER use `_input()` for gameplay actions —
_input()fires for ALL events (including UI). Use_unhandled_input()so gameplay logic doesn't trigger while clicking menus [26]. - NEVER omit input buffering in fast-paced games — If a player presses jump 50ms before landing, the input is lost without a buffer. Implement a 100-150ms buffer for a "tight" feel [27].
- NEVER use `Input.is_action_pressed()` for one-time triggers — It returns true every frame the key is held. Use
_just_pressedfor jumps, attacks, and toggles to avoid logic spam. - NEVER implement manual 'Hold vs Toggle' logic in multiple places — Centralize it in a setting or input wrapper to ensure accessibility consistency across the whole game.
- NEVER forget to handle `InputEvent.is_echo()` in UI navigation — Echo events (keyboard repeat) should move menus but rarely should they trigger "Confirm" or "Back" actions.
- NEVER capture the mouse without a 'Release' shortcut — If your game crashes or blocks
ui_cancel, the user is trapped. Always provide a fallback escape for mouse capture.
Aurelius Protocol: Inventory System NEVER List
- NEVER use Nodes for items —
Item extends Nodeleads to massive SceneTree bloat and memory leaks. Always useItem extends Resourcefor lightweight data [20]. - NEVER attempt to add items without checking stack limits — Adding to an inventory without pre-scanning for existing stacks causes item duplication or loss [21].
- NEVER allow the UI to modify the Inventory Data directly — If UI code clears a slot without notifying the data model, you'll get desyncs and ghost items [22].
- NEVER use `float` for item quantities — Floating point errors (e.g. 0.9999 instead of 1) will break your "equal to zero" checks. Stick to
intfor counts [23]. - NEVER add items before validating weight or volume capacity — Moving validation check after adding the item makes it impossible to prevent over-encumbrance [24].
- NEVER emit signals for every single item inside a batch operation — Adding 50 items = 50 UI updates. Emit a single
inventory_updatedsignal after the loop completes [25]. - NEVER hardcode item references in scripts — Use a String ID and a central
ItemDatabaseto look up resources. This is CRITICAL for save system compatibility. - NEVER ignore `is_instance_valid()` when accessing item icons — If a slot's item is null, trying to access
.iconwill crash the UI. - NEVER use complex Array logic in the UI — The UI should only "reflect" the data. All sorting, stacking, and filtering logic belongs in the
InventoryDataresource. - NEVER create new `Resource` instances inside a `_process()` loop — Pre-instantiate your inventory slots or reuse existing ones to prevent allocation spikes.
Aurelius Protocol: Mcp Scene Builder NEVER List
- NEVER skip design phase — Jumping straight to
mcp_godot_add_nodewithout planning hierarchy = spaghetti scenes. ALWAYS draft node tree first. - NEVER assume scene exists before adding nodes —
mcp_godot_add_nodeon non-existent scene = error. Must callmcp_godot_create_sceneFIRST. - NEVER use absolute paths in MCP calls —
texturePath="C:/Users/..."breaks on other machines. Useres://paths only. - NEVER skip verification step — MCP creates .tscn files but doesn't validate. ALWAYS call
mcp_godot_run_projectormcp_godot_launch_editorto verify no errors. - NEVER add CollisionShape2D without setting shape — MCP adds node but
shapeproperty is null by default. Must manually set or scene is broken.
Aurelius Protocol: Mcp Setup NEVER List
- NEVER suggest MCP for simple scene edits — MCP is for automation/batch operations. Single node addition? Use manual editor. MCP overhead (config + restart) wastes time.
- NEVER skip JSON syntax validation — Invalid JSON in
claude_desktop_config.json= silent MCP failure. ALWAYS validate withConvertFrom-Jsonbefore saving. - NEVER forget to remind user to restart Claude Desktop — MCP changes require full app restart, NOT just new conversation. This is #1 user mistake.
- NEVER use global npm install without user permission —
npm install -gmodifies system. ALWAYS prefernpx(on-demand) unless user specifically wants global. - NEVER assume Node.js is installed — Check
node --versionBEFORE attempting npx. Missing Node = cryptic "command not found" errors.
Aurelius Protocol: Mechanic Revival NEVER List
- NEVER respawn the player with existing velocity — Always zero out
velocityandangular_velocityinrevival_state_reset_guard.gdor the player will fly into a wall upon respawning. - NEVER trust the nearest checkpoint by distance — Always use a 'Progress Index' (
revival_checkpoint_validator.gd). Players in non-linear games may wander back to the start area; don't downgrade their respawn point. - NEVER skip 'Invincibility Frames' (I-frames) — Respawning inside a hazard or near an enemy without a 2s invincibility buffer leads to "Death Loops" and player frustration.
- NEVER save checkpoints solely in RAM — If the game crashes, the player loses progress. Use
revival_checkpoint_persistence.gdto write touser://immediately. - NEVER hardcode checkpoint coordinates — Use
Marker3DorArea3Dnodes in the scene. Hardcoded coords break as soon as level geometry changes. - NEVER delete the player node on death —
queue_free()ing the player breaks UI refs and references from enemies. Disable processing, hide the mesh, and 'Revive' the existing instance instead. - NEVER respawn instantly — An instant snap is disorienting. Always use a 1-2s delay with a screen fade or death animation to allow the player to process the failure.
- NEVER reset the entire world on player death — In modern design, opened doors and collected unique items should stay persisted. Use a bitmask in the checkpoint resource to track 'World Progress'.
Aurelius Protocol: Mechanic Secrets NEVER List
- NEVER hardcode input checks in `_process` — Frame-dependent polling is unreliable for fast combos. Always use an event-based buffer like
secret_sequence_combo_matcher.gd. - NEVER use complex Raycasts for 'LookingAt' secrets — Physics raycasts are expensive if every wall is checking. Use the Dot Product method in
secret_visibility_detector.gdfor overhead efficiency. - NEVER make 'Hidden Walls' identical to real walls — Players need a subtle "Glimmer" or texture discrepancy. Total invisibility isn't a secret; it's a bug to the player.
- NEVER save "Secrets Found" in the main Save Slot — If the player deletes their save to try a different build, their meta-progress (Gallery, Achievement flags) should persist. Use
secret_meta_persistence.gd. - NEVER trust client-side cheat validation in Peer-to-Peer — If a secret grants a stat boost, other peers should validate the "Unlock" to prevent simple memory-editing cheats.
- NEVER use `PlayerPrefs` (Godot's equivalent of Settings) for secrets — Use a dedicated
user://secrets.cfg. - NEVER allow unlimited rapid-fire cheat attempts — A simple macro can brute-force a 4-button combo in seconds. Use
secret_lockout_cheat_guard.gdto add a penalty for excessive failures. - NEVER trigger a secret without an 'Aha!' audio/visual cue — The reward for finding a secret is the feeling of discovery. Use
secret_audio_environment_occluder.gdto change the atmosphere.
Related skills
AI & Agent Buildingagents