Loading...
Loading...
Use when building a 2D game in Godot 4.7: make a platformer or top-down controller that feels right (coyote time, jump buffer, jump height), TileMapLayer and TileSet in code, terrains and autotiles that pick wrong tiles, a dual grid, a camera that jitters or stutters, pixel art that looks blurry or uneven, stretch and integer scaling, 2D lights and shadows, y-sort order wrong, parallax gaps, or importing AI-generated sprites and tilesets from Scenario.
npx skill4agent add scenario-labs/skills scenario-godot-2dnpx skills add scenario-labs/skills --skill <name>gd_envgd_rungd_reviewmove_towardlimit_lengthCamera2D.zoomCamera2D.process_callbackCAMERA2D_PROCESS_PHYSICSviewportcanvas_itemslayer_names/2d_physics/layer_N| Question | Why it changes the plan | Default |
|---|---|---|
| Pixel art or smooth 2D? | stretch mode, filter, light resolution, camera method | pixel art: base 640x360 (320x180 for very small art), |
| Locked grid or smooth camera over pixels? | | smooth camera via |
| Platformer or top-down? | GROUNDED or FLOATING, which kit body | from the brief |
| Tile size and terrain style | 47-blob, 16-tile sides, or dual grid | 16 px, 47-blob terrain |
| Target displays | integer factors and bars | 1280x720, 1366x768, 1920x1080, 2560x1440, 3840x2160 |
| Refresh and networking | physics interpolation on or off | on (off for networked games with their own smoothing, docs) |
| Art source | Scenario manifest, hand-made, placeholder | |
P = gd_env.base_project("2d", ...)gd_2d.install_kit(P)gd_2d.pixel_art_settings(P, ...)gd_run.import_project(P)stretch_matrix.gdgd_2d.integer_scalesdetect_pixel_scalepixel_grid_checksnap_to_gridaudit_importssprite_frames_builder.gdregister()key_fringetileset_builder.gd.tresset_cells_terrain_connectdual_grid.gdterrain_tools.audit_layerplatformer_body.gdplatformer_tuning.gdtopdown_body.gd--fixed-fps 60await body.steppedfollow_camera_2d.gdpixel_viewport.gd--fixed-fps 144audit_2d.gd:scenesgd_run.check_allkit_compile.gd| Value | Measured or source | Relative to |
|---|---|---|
| Base 320x180, integer: 4x at 1280x720 and 1366x768 (bars 43, 24), 6x at 1080p, 8x at 1440p, 12x at 4K, 3x at 1170x2532 | live | window size |
| Base 640x360, integer: 2x at 720p and 1366x768 (bars 43, 24), 3x at 1080p, 4x at 1440p, 6x at 4K; 3840x2159 gives 5x with 320 and 180 px bars | live | window size |
| Jump 56 px, apex 0.35 s, fall 0.28 s: g up 914.3, g down 1428.6 px/s², take-off 327.6 px/s with compensation | live, kit defaults [added] | 16 px tiles, 60 ticks |
| Jump cut 0.4: a one-tick tap rises 12.79 px (under a tile); minimum height is about (cut·v)²/2g | live, kit defaults | 16 px tiles |
| Coyote 0.1 s = 6 airborne moves; buffer 0.1 s = 5 moves before landing | live | 60 ticks |
| Corner correction 4 px: a 3 px head clip goes from 34 px to the full 56 px | live | 10x14 body |
| 120 px/s run, 56 px jump: clears 4 tiles, not 5 | live | 16 px tiles |
| Top-down 120 px/s, accel 900, decel 1200: 8 moves to max, 6 to stop | live, kit defaults | 60 ticks |
| Camera2D smoothing speed: default 5, about 3 felt right, 10 felt like none | DevWorm; default read live | px/s smoothing units |
| Exponential damping 8/s: 90% of a jump closed in 0.30 s at 30, 60 or 144 Hz; lag = speed / damping | live | frame rate |
| Jitter floor 0.289 px RMS (interpolation on) vs 0.55 (off) at 144 Hz | live | screen px |
| Sub-pixel camera at 4x: 1 px steps vs 4 px snapped | live | screen px |
| Parallax repeat_times for a plane as wide as the view: zoom 1 needs 1, 0.5 needs 3, 0.25 needs 5 | live | Camera2D zoom |
Banded light: a 4-stop Gradient with | live | PointLight2D over CanvasModulate |
Fringe: 73 tinted px without | live | 96 px frame at 0.7x |
| Mistake | What it looks like | Fix |
|---|---|---|
| Hand-written project.godot | stretch | |
| 16-tile sides set in Match Corners and Sides | holes and wrong edges (32 + 10 mismatches) | Match Sides, or draw the 47-blob set |
| Peering bits typed by hand | random edge pieces | derive from tile alpha, audit |
| Jump from the formula only | apex 2.5 px short, a gap that should clear does not | compensate g·dt/2 or measure and tune |
| Camera2D as child of the player and nothing else | static, short-sighted, jumpy | |
| Idle camera smoothing, interpolation off | player shakes against the background at 144 Hz | physics interpolation on |
| Camera2D inside a pixel SubViewport with interpolation on | image jumps -5, +3 px | set |
| Snap shader expected to pixelate light | falloff still smooth | |
| Occluder owner goes dark | wall or sprite unlit | flip cull mode (screen winding decides), check against a control |
| Centered sprite origin in a y-sorted container | player drawn over a tree it stands behind | origin at the feet, art moved with |
| Zoom by changing the viewport or window size | UI and pixel scale change with it | |
| Fullscreen (mode 3) for integer pixel art | factor drops one step on a 1 px strip | Exclusive Fullscreen (mode 4) |
| Shadow baked into the character sprite | shadow drawn over the tree trunk behind | separate shadow Sprite2D, |
| Tile animation over a neighboring tile | "tiles are already present", 1 frame kept | erase the neighbors first (DevWorm, ZutpG0_CYrQ [00:24:13]) |
| Parallax with repeat_times 1 and zoom out | magenta or black gaps | |
| Keyed sprite loaded at runtime with linear filtering | magenta outline | import it, or |
| old texture still used | |
frameswhgroundjumpedlandedsteppedpixel_viewport.world_to_screenlandedset_cellphysics_quadrant_sizeone_way_collision_directionenabledmake_current()position_smoothing_enabledignore_rotationfix_alpha_borderdetect_3d/compress_toKinematicBody2DYSortLight2Dset_cellvworld_to_mapCamera2D.currentreferences/procedures.mdexpert-notes.mdcritique.mdgui-paths.mdsources.mdscripts/gd_2d.pyscripts/agentkit/2d/