A retro game engine for Python
This report summarizes scanner evidence for kitao/pyxel, a Rust project with 18,480 GitHub stars. SynthScan examined 158,899 lines of code across 372 source files, recording 956 pattern matches distributed across 11 syntactic categories. The legacy adjusted pattern signal is 7.1 (Moderate pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Payload schema: 1.0.0 · Engine: 2.0.0 · Scoring: heuristic-density-v1 · Scan date: 2026-10-31.
Can maintainers explain intent, assumptions, and trade-offs? 895 finding(s).
Are imports declared and package/API names verified? 50 finding(s).
Are wrappers, guards, and repeated structures necessary? 875 finding(s).
Which changes need focused human review? 956 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 956 distinct pattern matches across 11 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | python/pyxel/cli.py | 90 | def watch_and_run_python_script(watch_dir: str, python_script_file: str) -> None: | CODE |
| LOW | python/pyxel/cli.py | 246 | def create_executable_from_pyxel_app(pyxel_app_file: str) -> None: | CODE |
| LOW | python/pyxel/cli.py | 304 | def create_html_from_pyxel_app(pyxel_app_file: str) -> None: | CODE |
| LOW | python/pyxel/cli.py | 396 | def _resolve_pyxel_app_startup_path( | CODE |
| LOW | python/pyxel/cli.py | 473 | def _run_python_script_in_separate_process(python_script_file): | CODE |
| LOW | python/pyxel/editor/tilemap_editor.py | 112 | def __on_tilemap_picker_change(self, value): | CODE |
| LOW | python/pyxel/editor/tilemap_editor.py | 115 | def __on_tilemap_picker_mouse_hover(self, _x, _y): | CODE |
| LOW⚡ | python/pyxel/editor/sound_editor.py | 202 | def __on_sound_picker_mouse_hover(self, _x, _y): | CODE |
| LOW⚡ | python/pyxel/editor/sound_editor.py | 211 | def __on_play_button_mouse_hover(self, _x, _y): | CODE |
| LOW⚡ | python/pyxel/editor/sound_editor.py | 217 | def __on_stop_button_mouse_hover(self, _x, _y): | CODE |
| LOW⚡ | python/pyxel/editor/sound_editor.py | 220 | def __on_loop_button_mouse_hover(self, _x, _y): | CODE |
| LOW⚡ | python/pyxel/editor/music_editor.py | 150 | def __on_music_picker_mouse_hover(self, _x, _y): | CODE |
| LOW⚡ | python/pyxel/editor/music_editor.py | 156 | def __on_play_button_mouse_hover(self, _x, _y): | CODE |
| LOW⚡ | python/pyxel/editor/music_editor.py | 162 | def __on_stop_button_mouse_hover(self, _x, _y): | CODE |
| LOW⚡ | python/pyxel/editor/music_editor.py | 165 | def __on_loop_button_mouse_hover(self, _x, _y): | CODE |
| LOW⚡ | python/pyxel/editor/app.py | 138 | def __on_editor_button_change(self, value): | CODE |
| LOW⚡ | python/pyxel/editor/app.py | 142 | def __on_editor_button_mouse_hover(self, _x, _y): | CODE |
| LOW⚡ | python/pyxel/editor/app.py | 148 | def __on_undo_button_mouse_hover(self, _x, _y): | CODE |
| LOW⚡ | python/pyxel/editor/app.py | 154 | def __on_redo_button_mouse_hover(self, _x, _y): | CODE |
| LOW⚡ | python/pyxel/editor/app.py | 166 | def __on_save_button_mouse_hover(self, _x, _y): | CODE |
| LOW | python/pyxel/editor/image_editor.py | 94 | def __on_color_picker_mouse_hover(self, _x, _y): | CODE |
| LOW | python/pyxel/editor/image_editor.py | 97 | def __on_image_picker_mouse_hover(self, _x, _y): | CODE |
| LOW | python/pyxel/editor/editor_base.py | 83 | def check_tool_button_shortcuts(self): | CODE |
| LOW⚡ | python/pyxel/editor/editor_base.py | 107 | def __on_number_picker_dec_mouse_hover(self, _x, _y): | CODE |
| LOW⚡ | python/pyxel/editor/editor_base.py | 110 | def __on_number_picker_inc_mouse_hover(self, _x, _y): | CODE |
| LOW⚡ | python/pyxel/editor/editor_base.py | 113 | def __on_tool_button_mouse_hover(self, x, y): | CODE |
| LOW | python/pyxel/editor/widgets/widget.py | 270 | def remove_var_event_listener(self, name, event, listener): | CODE |
| LOW | python/tests/test_music.py | 24 | def test_set_preserves_data_and_pads_channels(self, seqs, expected): | CODE |
| LOW | python/tests/test_music.py | 34 | def test_save_is_byte_deterministic(self, tmp_path): | CODE |
| LOW | python/tests/test_music.py | 72 | def test_set_overwrites_previous(self): | CODE |
| LOW | python/tests/test_music.py | 79 | def test_snds_list_aliases_seqs_deprecated(self, capfd): | CODE |
| LOW⚡ | python/tests/test_music.py | 121 | def test_removed_channel_view_raises(self, method, args): | CODE |
| LOW⚡ | python/tests/test_music.py | 129 | def test_comparison_with_removed_channel_view_raises(self): | CODE |
| LOW⚡ | python/tests/test_music.py | 138 | def test_index_conversion_can_remove_channel(self, slice_key): | CODE |
| LOW | python/tests/test_music.py | 152 | def test_value_conversion_can_remove_channel(self): | CODE |
| LOW⚡ | python/tests/test_music.py | 171 | def test_seqs_inner_seq_access(self): | CODE |
| LOW⚡ | python/tests/test_music.py | 180 | def test_seqs_inner_seq_setitem(self): | CODE |
| LOW⚡ | python/tests/test_music.py | 187 | def test_seqs_inner_seq_append(self): | CODE |
| LOW⚡ | python/tests/test_music.py | 195 | def test_seqs_inner_seq_delitem(self): | CODE |
| LOW⚡ | python/tests/test_music.py | 202 | def test_seqs_append_new_channel(self): | CODE |
| LOW⚡ | python/tests/test_music.py | 210 | def test_seqs_setitem_channel(self): | CODE |
| LOW⚡ | python/tests/test_music.py | 219 | def test_seqs_self_assignment(self): | CODE |
| LOW | python/tests/test_music.py | 255 | def test_seqs_reversed_step_one_slice_assignment_inserts(self): | STRING |
| LOW | python/tests/test_music.py | 304 | def test_seqs_result_allows_garbage_collection_reentry(self, operation, expected): | STRING |
| LOW | python/tests/test_music.py | 371 | def test_seqs_from_list_deprecated(self, capfd): | STRING |
| LOW | python/tests/test_music.py | 378 | def test_seqs_to_list_deprecated(self, capfd): | STRING |
| LOW⚡ | python/tests/test_tilemap.py | 15 | def test_new_with_image_instance(self): | CODE |
| LOW⚡ | python/tests/test_tilemap.py | 21 | def test_imgsrc_read_write_int(self): | CODE |
| LOW⚡ | python/tests/test_tilemap.py | 28 | def test_imgsrc_read_write_image(self): | CODE |
| LOW⚡ | python/tests/test_tilemap.py | 34 | def test_pset_pget_returns_tuple(self): | CODE |
| LOW | python/tests/test_tilemap.py | 70 | def test_empty_draw_does_not_resolve_imgsrc(self, operation, use_bank): | CODE |
| LOW | python/tests/test_tilemap.py | 162 | def test_empty_self_blit_preserves_tiles(self, bank_source, extent, zero_height): | CODE |
| LOW | python/tests/test_tilemap.py | 181 | def test_self_blit_matches_source_snapshot(self, rotate, source_pos): | CODE |
| LOW | python/tests/test_tilemap.py | 201 | def test_blt_with_tilemap_instance(self): | CODE |
| LOW | python/tests/test_tilemap.py | 244 | def test_clip_restricts_drawing(self): | CODE |
| LOW | python/tests/test_tilemap.py | 253 | def test_camera_offsets_drawing(self): | CODE |
| LOW | python/tests/test_tilemap.py | 270 | def test_from_tmx_masks_tile_flip_flags(self, tmp_path): | CODE |
| LOW | python/tests/test_tilemap.py | 296 | def test_from_tmx_rejects_invalid_configuration( | CODE |
| LOW⚡ | python/tests/test_tilemap.py | 435 | def test_collide_entering_map(self, x, y, width, height, dx, dy, expected): | STRING |
| LOW⚡ | python/tests/test_tilemap.py | 445 | def test_collide_horizontal_wall(self): | STRING |
| 803 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | python/pyxel/examples/cube/c03_custom_shapes.py | 161 | side = side.normalize() if side.length() > 1e-6 else right | CODE |
| HIGH | python/pyxel/examples/cube/c05_3d_collision.py | 88 | if move.length() > 0: | CODE |
| HIGH | python/pyxel/examples/cube/c05_3d_collision.py | 107 | self.animate(move.length() > 0) | CODE |
| HIGH⚡ | python/pyxel/examples/cube/c05_3d_collision.py | 242 | if candidate.length() > offset.length(): | CODE |
| HIGH⚡ | python/pyxel/examples/cube/c05_3d_collision.py | 244 | if offset.length() >= CAMERA_MIN_DISTANCE: | CODE |
| HIGH⚡ | python/pyxel/examples/cube/c05_3d_collision.py | 252 | distance = previous.length() + (offset.length() - previous.length()) * 0.25 | CODE |
| HIGH⚡ | python/pyxel/examples/cube/c05_3d_collision.py | 255 | if clipped.length() >= CAMERA_MIN_DISTANCE: | CODE |
| HIGH⚡ | python/pyxel/examples/cube/c05_3d_collision.py | 263 | hit = self.raycast(start, delta, delta.length(), tags={"ground"}) | CODE |
| HIGH⚡ | python/pyxel/examples/cube/c05_3d_collision.py | 273 | hit = self.raycast(focus, offset, offset.length(), tags={"ground"}) | CODE |
| HIGH | python/pyxel/examples/cube/c05_3d_collision.py | 286 | if self.player.on_floor and self.player.move.length() > 0: | CODE |
| HIGH | python/tests/test_examples.py | 714 | assert offset.length() >= 48 | CODE |
| HIGH | python/tests/test_examples.py | 715 | assert scene.raycast(focus, offset, offset.length(), tags={"ground"}) is None | CODE |
| HIGH⚡ | python/tests/test_examples.py | 749 | assert offset.length() >= 48 | CODE |
| HIGH⚡ | python/tests/test_examples.py | 753 | if scene.raycast(focus, offset, offset.length(), tags={"ground"}): | CODE |
| HIGH⚡ | python/tests/test_examples.py | 758 | hit = scene.raycast(eye, -offset, offset.length(), tags={"ground"}) | CODE |
| HIGH⚡ | python/tests/test_examples.py | 765 | assert scene.raycast(focus, offset, offset.length(), tags={"ground"}) is None | CODE |
| HIGH | python/tests/test_examples.py | 783 | assert offset.length() >= 48 | CODE |
| HIGH | python/tests/test_examples.py | 790 | scene.raycast(player.transform.pos, offset, offset.length(), tags={"ground"}) | CODE |
| HIGH | python/tests/test_examples.py | 810 | assert offset.length() >= 48 | CODE |
| HIGH | python/tests/test_examples.py | 811 | assert scene.raycast(focus, offset, offset.length(), tags={"ground"}) is None | CODE |
| HIGH⚡ | python/tests/cube/test_primitive.py | 128 | assert normal.length() == pytest.approx(1, abs=1e-6) | CODE |
| HIGH⚡ | python/tests/cube/test_mat4.py | 119 | assert isclose(m.rot.length(), 1, abs_tol=1e-6) | CODE |
| HIGH | python/tests/cube/test_mat4.py | 88 | assert isclose(m.rot.length(), 1, abs_tol=1e-6) | CODE |
| HIGH⚡ | python/tests/cube/test_quat.py | 209 | assert quat.length() == pytest.approx(5 * scale, rel=2e-6, abs=0) | CODE |
| HIGH⚡ | python/tests/cube/test_quat.py | 219 | assert quat.length() == pytest.approx(1, abs=1e-6) | CODE |
| HIGH⚡ | python/tests/cube/test_quat.py | 227 | assert quat.length() == pytest.approx(1, abs=1e-6) | CODE |
| HIGH⚡ | python/tests/cube/test_quat.py | 235 | assert quat.length() == pytest.approx(1, abs=1e-6) | CODE |
| HIGH⚡ | python/tests/cube/test_quat.py | 242 | assert quat.length() == pytest.approx(1, abs=1e-6) | CODE |
| HIGH⚡ | python/tests/cube/test_quat.py | 255 | assert rotation.length() == pytest.approx(1, abs=1e-6) | CODE |
| HIGH⚡ | python/tests/cube/test_quat.py | 266 | assert rotation.length() == pytest.approx(1, abs=1e-6) | CODE |
| HIGH⚡ | python/tests/cube/test_vec3.py | 146 | assert n.length() == 1.0 | CODE |
| HIGH⚡ | python/tests/cube/test_vec3.py | 220 | assert vector.length() == pytest.approx(5 * scale, rel=2e-6, abs=0) | CODE |
| HIGH⚡ | python/tests/cube/test_vec3.py | 251 | assert isinf(vector.length()) | CODE |
| HIGH⚡ | python/tests/cube/test_vec3.py | 259 | assert target.length() == 1 | CODE |
| HIGH | python/tests/cube/test_vec3.py | 183 | assert isclose(v.length(), 1.0, abs_tol=1e-5) | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | python/pyxel/cli.py | 90 | CODE | |
| LOW | python/pyxel/cli.py | 182 | CODE | |
| LOW | python/pyxel/cli.py | 508 | CODE | |
| LOW | python/pyxel/utils.py | 23 | CODE | |
| LOW | python/pyxel/examples/10_platformer.py | 44 | CODE | |
| LOW | python/pyxel/examples/06_click_game.py | 59 | CODE | |
| LOW | python/pyxel/examples/07_snake.py | 123 | CODE | |
| LOW | python/pyxel/examples/cube/c05_3d_collision.py | 221 | CODE | |
| LOW | python/pyxel/examples/cube/c06_3d_physics.py | 18 | CODE | |
| LOW | python/pyxel/examples/cube/c06_3d_physics.py | 119 | CODE | |
| LOW | python/pyxel/editor/canvas_panel.py | 181 | CODE | |
| LOW | python/pyxel/editor/canvas_panel.py | 291 | CODE | |
| LOW | python/pyxel/editor/piano_keyboard.py | 159 | CODE | |
| LOW | python/pyxel/editor/app.py | 169 | CODE | |
| LOW | python/pyxel/editor/image_editor.py | 120 | CODE | |
| LOW | python/pyxel/editor/editor_base.py | 83 | CODE | |
| LOW | python/tests/test_tilemap.py | 70 | CODE | |
| LOW | python/tests/test_api_reference.py | 17 | CODE | |
| LOW | python/tests/test_api_reference.py | 66 | CODE | |
| LOW | python/tests/_runner.py | 22 | CODE | |
| LOW | python/tests/_runner.py | 107 | CODE | |
| LOW | python/tests/cube/test_scene.py | 871 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | python/pyxel/__init__.py | 19 | CODE | |
| LOW | python/pyxel/editor/__init__.py | 1 | CODE | |
| LOW | python/pyxel/editor/__init__.py | 2 | CODE | |
| LOW | python/pyxel/editor/widgets/__init__.py | 1 | CODE | |
| LOW | python/pyxel/editor/widgets/__init__.py | 2 | CODE | |
| LOW | python/pyxel/editor/widgets/__init__.py | 3 | CODE | |
| LOW | python/pyxel/editor/widgets/__init__.py | 4 | CODE | |
| LOW | python/pyxel/editor/widgets/__init__.py | 5 | CODE | |
| LOW | python/pyxel/editor/widgets/__init__.py | 6 | CODE | |
| LOW | python/pyxel/editor/widgets/__init__.py | 7 | CODE | |
| LOW | python/pyxel/editor/widgets/__init__.py | 8 | CODE | |
| LOW | python/pyxel/editor/widgets/__init__.py | 9 | CODE | |
| LOW | python/pyxel/editor/widgets/__init__.py | 10 | CODE | |
| LOW | python/tests/cube/_glb_fixtures.py | 1 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | python/pyxel/__init__.py | 15 | except OSError: | CODE |
| HIGH | python/tests/_runner.py | 79 | except _FlipCapture: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | python/pyxel/examples/09_shooter.py | 188 | # Create the player sprite | COMMENT |
| MEDIUM | python/pyxel/examples/09_shooter.py | 204 | # Create the enemy sprite | COMMENT |
| MEDIUM | python/pyxel/examples/04_sound_api.py | 8 | # Create the note icon sprite | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | python/pyxel/editor/tilemap_editor.py | 132 | except Exception as e: # noqa: BLE001 - Native loaders raise plain Exception. | CODE |
| MEDIUM | python/pyxel/editor/tilemap_editor.py | 127 | def __on_drop(self, filename): | CODE |
| LOW⚡ | python/pyxel/editor/app.py | 160 | except Exception as e: # noqa: BLE001 - Native savers raise plain Exception. | CODE |
| LOW | python/pyxel/editor/app.py | 190 | except Exception as e: # noqa: BLE001 - Native loaders raise plain Exception. | CODE |
| MEDIUM | python/pyxel/editor/app.py | 157 | def __on_save_button_press(self): | CODE |
| LOW | python/pyxel/editor/image_editor.py | 115 | except Exception as e: # noqa: BLE001 - Native loaders raise plain Exception. | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | crates/pyxel-core/src/bgm_generator.rs | 21 | // Struct field names form the Pyxel Composer JSON wire contract. | COMMENT |
| LOW | crates/pyxel-core/src/bgm_generator.rs | 61 | // Optional 12-digit per-semitone weight string. | COMMENT |
| LOW | crates/pyxel-core/src/cube/collision.rs | 2921 | } | COMMENT |
| LOW | python/pyxel/editor/canvas_panel.py | 21 | # Variables: | COMMENT |
| LOW | python/pyxel/editor/sound_editor.py | 21 | COMMENT | |
| LOW | python/pyxel/editor/widgets/widget.py | 21 | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | web/tests/browser/app2html.spec.js | 38 | print(json.dumps(pages)) | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | python/pyxel/cube/__init__.py | 21 | __all__ = [ | CODE |
| LOW | python/pyxel/editor/__init__.py | 4 | __all__ = ["App", "extensions"] | CODE |
| LOW | python/pyxel/editor/widgets/__init__.py | 12 | __all__ = [ | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | python/tests/cube/_glb_fixtures.py | 324 | CODE |