diff --git a/arcade/application.py b/arcade/application.py
index 9c5a16a58..ca7be7197 100644
--- a/arcade/application.py
+++ b/arcade/application.py
@@ -8,19 +8,20 @@
 import logging
 import os
 import time
-from typing import TYPE_CHECKING
+from typing import Sequence, TYPE_CHECKING
 
 import pyglet
 import pyglet.gl as gl
 import pyglet.window.mouse
 from pyglet.display.base import Screen, ScreenMode
+from pyglet.event import EVENT_HANDLE_STATE, EVENT_UNHANDLED
 from pyglet.window import MouseCursor
 
 import arcade
 from arcade.clock import GLOBAL_CLOCK, GLOBAL_FIXED_CLOCK, _setup_clock, _setup_fixed_clock
 from arcade.color import BLACK
 from arcade.context import ArcadeContext
-from arcade.types import LBWH, Color, Rect, RGBANormalized, RGBOrA255
+from arcade.types import Color, LBWH, RGBANormalized, RGBOrA255, Rect
 from arcade.utils import is_raspberry_pi
 from arcade.window_commands import get_display_size, set_window
 
@@ -29,7 +30,6 @@
     from arcade.camera.default import DefaultProjector
     from arcade.start_finish_data import StartFinishRenderData
 
-
 LOG = logging.getLogger(__name__)
 
 MOUSE_BUTTON_LEFT = 1
@@ -180,7 +180,7 @@ def __init__(
         # Attempt to make window with antialiasing
         if antialiasing:
             try:
-                config = pyglet.gl.Config(
+                config = gl.Config(
                     major_version=gl_version[0],
                     minor_version=gl_version[1],
                     opengl_api=gl_api,  # type: ignore  # pending: upstream fix
@@ -204,7 +204,7 @@ def __init__(
                 antialiasing = False
         # If we still don't have a config
         if not config:
-            config = pyglet.gl.Config(
+            config = gl.Config(
                 major_version=gl_version[0],
                 minor_version=gl_version[1],
                 opengl_api=gl_api,  # type: ignore  # pending: upstream fix
@@ -239,7 +239,7 @@ def __init__(
         if antialiasing:
             try:
                 gl.glEnable(gl.GL_MULTISAMPLE_ARB)
-            except pyglet.gl.GLException:
+            except gl.GLException:
                 LOG.warning("Warning: Anti-aliasing not supported on this computer.")
 
         _setup_clock()
@@ -338,7 +338,7 @@ def ctx(self) -> ArcadeContext:
         """
         return self._ctx
 
-    def clear(
+    def clear(  # type: ignore # not sure what to do here, BaseWindow.clear is static
         self,
         color: RGBOrA255 | None = None,
         color_normalized: RGBANormalized | None = None,
@@ -554,7 +554,7 @@ def set_draw_rate(self, rate: float) -> None:
         pyglet.clock.unschedule(pyglet.app.event_loop._redraw_windows)
         pyglet.clock.schedule_interval(pyglet.app.event_loop._redraw_windows, self._draw_rate)
 
-    def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> bool | None:
+    def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> EVENT_HANDLE_STATE:
         """
         Called repeatedly while the mouse is moving in the window area.
 
@@ -568,7 +568,7 @@ def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> bool | None:
         """
         pass
 
-    def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> bool | None:
+    def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> EVENT_HANDLE_STATE:
         """
         Called once whenever a mouse button gets pressed down.
 
@@ -596,7 +596,7 @@ def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> bool |
 
     def on_mouse_drag(
         self, x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int
-    ) -> bool | None:
+    ) -> EVENT_HANDLE_STATE:
         """
         Called repeatedly while the mouse moves with a button down.
 
@@ -619,7 +619,7 @@ def on_mouse_drag(
         """
         return self.on_mouse_motion(x, y, dx, dy)
 
-    def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> bool | None:
+    def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> EVENT_HANDLE_STATE:
         """
         Called once whenever a mouse button gets released.
 
@@ -642,9 +642,11 @@ def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> bool
                 Bitwise 'and' of all modifiers (shift, ctrl, num lock)
                 active during this event. See :ref:`keyboard_modifiers`.
         """
-        return False
+        return EVENT_UNHANDLED
 
-    def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int) -> bool | None:
+    def on_mouse_scroll(
+        self, x: int, y: int, scroll_x: float, scroll_y: float
+    ) -> EVENT_HANDLE_STATE:
         """
         Called repeatedly while a mouse scroll wheel moves.
 
@@ -676,7 +678,7 @@ def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int) -> bool
             scroll_y:
                 Number of steps scrolled vertically since the last call of this function
         """
-        return False
+        return EVENT_UNHANDLED
 
     def set_mouse_visible(self, visible: bool = True) -> None:
         """
@@ -724,7 +726,7 @@ def on_action(self, action_name: str, state) -> None:
         """
         pass
 
-    def on_key_press(self, symbol: int, modifiers: int) -> bool | None:
+    def on_key_press(self, symbol: int, modifiers: int) -> EVENT_HANDLE_STATE:
         """
         Called once when a key gets pushed down.
 
@@ -741,9 +743,9 @@ def on_key_press(self, symbol: int, modifiers: int) -> bool | None:
                 Bitwise 'and' of all modifiers (shift, ctrl, num lock)
                 active during this event. See :ref:`keyboard_modifiers`.
         """
-        return False
+        return EVENT_UNHANDLED
 
-    def on_key_release(self, symbol: int, modifiers: int) -> bool | None:
+    def on_key_release(self, symbol: int, modifiers: int) -> EVENT_HANDLE_STATE:
         """
         Called once when a key gets released.
 
@@ -763,9 +765,9 @@ def on_key_release(self, symbol: int, modifiers: int) -> bool | None:
                       ctrl, num lock) active during this event.
                       See :ref:`keyboard_modifiers`.
         """
-        return False
+        return EVENT_UNHANDLED
 
-    def on_draw(self) -> bool | None:
+    def on_draw(self) -> EVENT_HANDLE_STATE:
         """
         Override this function to add your custom drawing code.
 
@@ -781,9 +783,9 @@ def on_draw(self) -> bool | None:
             self._start_finish_render_data.draw()
             return True
 
-        return False
+        return EVENT_UNHANDLED
 
-    def _on_resize(self, width: int, height: int) -> bool | None:
+    def _on_resize(self, width: int, height: int) -> EVENT_HANDLE_STATE:
         """
         The internal method called when the window is resized.
 
@@ -799,9 +801,9 @@ def _on_resize(self, width: int, height: int) -> bool | None:
         # Retain viewport
         self.viewport = (0, 0, width, height)
 
-        return False
+        return EVENT_UNHANDLED
 
-    def on_resize(self, width: int, height: int) -> bool | None:
+    def on_resize(self, width: int, height: int) -> EVENT_HANDLE_STATE:
         """
         Override this method to add custom actions when the window is resized.
 
@@ -855,7 +857,7 @@ def get_size(self) -> tuple[int, int]:
 
     def get_location(self) -> tuple[int, int]:
         """Get the current X/Y coordinates of the window."""
-        return super().get_location()
+        return super().get_location()  # type: ignore # Window typed at runtime
 
     def set_visible(self, visible: bool = True):
         """
@@ -1038,34 +1040,34 @@ def flip(self) -> None:
         num_collected = self.ctx.gc()
         LOG.debug("Garbage collected %s OpenGL resource(s)", num_collected)
 
-        super().flip()
+        super().flip()  # type: ignore # Window typed at runtime
 
     def switch_to(self) -> None:
         """Switch the this window context.
 
         This is normally only used in multi-window applications.
         """
-        super().switch_to()
+        super().switch_to()  # type: ignore # Window typed at runtime
 
     def set_caption(self, caption) -> None:
         """Set the caption/title of the window."""
-        super().set_caption(caption)
+        super().set_caption(caption)  # type: ignore # Window typed at runtime
 
     def set_location(self, x, y) -> None:
         """Set location of the window."""
-        super().set_location(x, y)
+        super().set_location(x, y)  # type: ignore # Window typed at runtime
 
     def activate(self) -> None:
         """Activate this window."""
-        super().activate()
+        super().activate()  # type: ignore # Window typed at runtime
 
     def minimize(self) -> None:
         """Minimize the window."""
-        super().minimize()
+        super().minimize()  # type: ignore # Window typed at runtime
 
     def maximize(self) -> None:
         """Maximize  the window."""
-        super().maximize()
+        super().maximize()  # type: ignore # Window typed at runtime
 
     def set_vsync(self, vsync: bool) -> None:
         """Set if we sync our draws to the monitors vertical sync rate."""
@@ -1097,9 +1099,9 @@ def get_system_mouse_cursor(self, name) -> MouseCursor:
 
     def dispatch_events(self) -> None:
         """Dispatch events"""
-        super().dispatch_events()
+        super().dispatch_events()  # type: ignore # Window typed at runtime
 
-    def on_mouse_enter(self, x: int, y: int) -> bool | None:
+    def on_mouse_enter(self, x: int, y: int) -> EVENT_HANDLE_STATE:
         """
         Called once whenever the mouse enters the window area on screen.
 
@@ -1112,7 +1114,7 @@ def on_mouse_enter(self, x: int, y: int) -> bool | None:
         """
         pass
 
-    def on_mouse_leave(self, x: int, y: int) -> bool | None:
+    def on_mouse_leave(self, x: int, y: int) -> EVENT_HANDLE_STATE:
         """
         Called once whenever the mouse leaves the window area on screen.
 
@@ -1183,6 +1185,15 @@ def fixed_delta_time(self) -> float:
         """The configured fixed update rate"""
         return self._fixed_rate
 
+    # required because pyglet marks the method as abstract methods,
+    # but resolves class during runtime
+    def _create(self) -> None:
+        """Internal method to create the window."""
+        super()._create()  # type: ignore
+
+    def _recreate(self, changes: Sequence[str]) -> None:
+        super()._recreate(changes)  # type: ignore
+
 
 def open_window(
     width: int,
diff --git a/arcade/camera/camera_2d.py b/arcade/camera/camera_2d.py
index 5f4c3319f..47b177479 100644
--- a/arcade/camera/camera_2d.py
+++ b/arcade/camera/camera_2d.py
@@ -2,15 +2,15 @@
 
 from contextlib import contextmanager
 from math import atan2, cos, degrees, radians, sin
-from typing import TYPE_CHECKING, Generator
+from typing import Generator, TYPE_CHECKING
 
 from pyglet.math import Vec2, Vec3
 from typing_extensions import Self
 
 from arcade.camera.data_types import (
+    CameraData,
     DEFAULT_FAR,
     DEFAULT_NEAR_ORTHO,
-    CameraData,
     OrthographicProjectionData,
     ZeroProjectionDimension,
 )
@@ -20,7 +20,7 @@
     project_orthographic,
     unproject_orthographic,
 )
-from arcade.types import LBWH, LRBT, XYWH, Point, Rect
+from arcade.types import LBWH, LRBT, Point, Rect, XYWH
 from arcade.types.vector_like import Point2
 from arcade.window_commands import get_window
 
@@ -544,10 +544,12 @@ def position(self) -> Vec2:
         """The 2D world position of the camera along the X and Y axes."""
         return Vec2(self._camera_data.position[0], self._camera_data.position[1])
 
+    # Setter with different signature will cause mypy issues
+    # https://github.com/python/mypy/issues/3004
     @position.setter
     def position(self, _pos: Point) -> None:
-        x, y, *z = _pos
-        z = self._camera_data.position[2] if not z else z[0]
+        x, y, *_z = _pos
+        z = self._camera_data.position[2] if not _z else _z[0]
         self._camera_data.position = (x, y, z)
 
     @property
@@ -900,7 +902,7 @@ def top_left(self, new_corner: Point2):
         left = self.left
 
         x, y = new_corner
-        self.position = (x - ux * top - rx * left, y - uy * top - ry * left)
+        self.position = (x - ux * top - rx * left, y - uy * top - ry * left)  # type: ignore
 
     # top_center
     @property
@@ -918,7 +920,7 @@ def top_center(self, new_top: Point2):
         top = self.top
 
         x, y = new_top
-        self.position = x - ux * top, y - uy * top
+        self.position = x - ux * top, y - uy * top  # type: ignore
 
     # top_right
     @property
@@ -942,7 +944,7 @@ def top_right(self, new_corner: Point2):
         right = self.right
 
         x, y = new_corner
-        self.position = (x - ux * top - rx * right, y - uy * top - ry * right)
+        self.position = (x - ux * top - rx * right, y - uy * top - ry * right)  # type: ignore
 
     # center_right
     @property
@@ -959,7 +961,7 @@ def center_right(self, new_right: Point2):
         right = self.right
 
         x, y = new_right
-        self.position = x - uy * right, y + ux * right
+        self.position = x - uy * right, y + ux * right  # type: ignore
 
     # bottom_right
     @property
@@ -985,7 +987,7 @@ def bottom_right(self, new_corner: Point2):
         self.position = (
             x - ux * bottom - rx * right,
             y - uy * bottom - ry * right,
-        )
+        )  # type: ignore
 
     # bottom_center
     @property
@@ -995,7 +997,7 @@ def bottom_center(self) -> Vec2:
         ux, uy, *_ = self._camera_data.up
         bottom = self.bottom
 
-        return Vec2(pos.x + ux * bottom, pos.y + uy * bottom)
+        return pos.x + ux * bottom, pos.y + uy * bottom  # type: ignore
 
     @bottom_center.setter
     def bottom_center(self, new_bottom: Point2):
@@ -1003,7 +1005,7 @@ def bottom_center(self, new_bottom: Point2):
         bottom = self.bottom
 
         x, y = new_bottom
-        self.position = x - ux * bottom, y - uy * bottom
+        self.position = x - ux * bottom, y - uy * bottom  # type: ignore
 
     # bottom_left
     @property
@@ -1027,7 +1029,7 @@ def bottom_left(self, new_corner: Point2):
         left = self.left
 
         x, y = new_corner
-        self.position = (x - ux * bottom - rx * left, y - uy * bottom - ry * left)
+        self.position = x - ux * bottom - rx * left, y - uy * bottom - ry * left  # type: ignore
 
     # center_left
     @property
@@ -1044,4 +1046,4 @@ def center_left(self, new_left: Point2):
         left = self.left
 
         x, y = new_left
-        self.position = x - uy * left, y + ux * left
+        self.position = Vec2(x - uy * left, y + ux * left)
diff --git a/arcade/camera/default.py b/arcade/camera/default.py
index 2ef4a7744..0ba9044b3 100644
--- a/arcade/camera/default.py
+++ b/arcade/camera/default.py
@@ -92,8 +92,8 @@ def unproject(self, screen_coordinate: Point) -> Vec3:
 
         Due to the nature of viewport projector this does not do anything.
         """
-        x, y, *z = screen_coordinate
-        z = 0.0 if not z else z[0]
+        x, y, *_z = screen_coordinate
+        z = 0.0 if not _z else _z[0]
 
         return Vec3(x, y, z)
 
diff --git a/arcade/camera/perspective.py b/arcade/camera/perspective.py
index b65b86cbf..1c51dfa05 100644
--- a/arcade/camera/perspective.py
+++ b/arcade/camera/perspective.py
@@ -182,15 +182,15 @@ def project(self, world_coordinate: Point) -> Vec2:
         Returns:
             A 2D screen pixel coordinate.
         """
-        x, y, *z = world_coordinate
+        x, y, *_z = world_coordinate
         z = (
             (
                 0.5
                 * self.viewport.height
                 / tan(radians(0.5 * self._projection.fov / self._view.zoom))
             )
-            if not z
-            else z[0]
+            if not _z
+            else _z[0]
         )
 
         _projection = generate_perspective_matrix(self._projection, self._view.zoom)
@@ -214,15 +214,15 @@ def unproject(self, screen_coordinate: Point) -> Vec3:
         Returns: A 3D vector in world space.
 
         """
-        x, y, *z = screen_coordinate
+        x, y, *_z = screen_coordinate
         z = (
             (
                 0.5
                 * self.viewport.height
                 / tan(radians(0.5 * self._projection.fov / self._view.zoom))
             )
-            if not z
-            else z[0]
+            if not _z
+            else _z[0]
         )
 
         _projection = generate_perspective_matrix(self._projection, self._view.zoom)
diff --git a/arcade/camera/projection_functions.py b/arcade/camera/projection_functions.py
index 5a96b9f31..2745fb90f 100644
--- a/arcade/camera/projection_functions.py
+++ b/arcade/camera/projection_functions.py
@@ -125,8 +125,8 @@ def project_orthographic(
     view_matrix: Mat4,
     projection_matrix: Mat4,
 ) -> Vec2:
-    x, y, *z = world_coordinate
-    z = 0.0 if not z else z[0]
+    x, y, *_z = world_coordinate
+    z = 0.0 if not _z else _z[0]
 
     world_position = Vec4(x, y, z, 1.0)
 
@@ -144,8 +144,8 @@ def unproject_orthographic(
     view_matrix: Mat4,
     projection_matrix: Mat4,
 ) -> Vec3:
-    x, y, *z = screen_coordinate
-    z = 0.0 if not z else z[0]
+    x, y, *_z = screen_coordinate
+    z = 0.0 if not _z else _z[0]
 
     screen_x = 2.0 * (x - viewport[0]) / viewport[2] - 1
     screen_y = 2.0 * (y - viewport[1]) / viewport[3] - 1
@@ -165,8 +165,8 @@ def project_perspective(
     view_matrix: Mat4,
     projection_matrix: Mat4,
 ) -> Vec2:
-    x, y, *z = world_coordinate
-    z = 1.0 if not z else z[0]
+    x, y, *_z = world_coordinate
+    z = 1.0 if not _z else _z[0]
 
     world_position = Vec4(x, y, z, 1.0)
 
@@ -188,8 +188,8 @@ def unproject_perspective(
     view_matrix: Mat4,
     projection_matrix: Mat4,
 ) -> Vec3:
-    x, y, *z = screen_coordinate
-    z = 1.0 if not z else z[0]
+    x, y, *_z = screen_coordinate
+    z = 1.0 if not _z else _z[0]
 
     screen_x = 2.0 * (x - viewport[0]) / viewport[2] - 1
     screen_y = 2.0 * (y - viewport[1]) / viewport[3] - 1
diff --git a/arcade/examples/gl/3d_sphere.py b/arcade/examples/gl/3d_sphere.py
index 1b155f758..249bdcf39 100644
--- a/arcade/examples/gl/3d_sphere.py
+++ b/arcade/examples/gl/3d_sphere.py
@@ -16,7 +16,6 @@
 
 
 class Sphere3D(arcade.Window):
-
     def __init__(self, width, height, title):
         super().__init__(width, height, title, resizable=True)
         self.sphere = geometry.sphere(1.0, 32, 32, uvs=False)
@@ -69,20 +68,36 @@ def __init__(self, width, height, title):
 
         self.text_batch = Batch()
         self.text_cull = arcade.Text(
-            "F2: Toggle cull face (True)", x=10, y=10, font_size=15, color=arcade.color.WHITE,
-            batch=self.text_batch
+            "F2: Toggle cull face (True)",
+            x=10,
+            y=10,
+            font_size=15,
+            color=arcade.color.WHITE,
+            batch=self.text_batch,
         )
         self.text_depth = arcade.Text(
-            "F1: Toggle depth test (True)", x=10, y=30, font_size=15, color=arcade.color.WHITE,
-            batch=self.text_batch
+            "F1: Toggle depth test (True)",
+            x=10,
+            y=30,
+            font_size=15,
+            color=arcade.color.WHITE,
+            batch=self.text_batch,
         )
         self.text_wireframe = arcade.Text(
-            "SPACE: Toggle wireframe (False)", x=10, y=50, font_size=15, color=arcade.color.WHITE,
-            batch=self.text_batch
+            "SPACE: Toggle wireframe (False)",
+            x=10,
+            y=50,
+            font_size=15,
+            color=arcade.color.WHITE,
+            batch=self.text_batch,
         )
         self.text_fs = arcade.Text(
-            "F: Toggle fullscreen (False)", x=10, y=70, font_size=15, color=arcade.color.WHITE,
-            batch=self.text_batch
+            "F: Toggle fullscreen (False)",
+            x=10,
+            y=70,
+            font_size=15,
+            color=arcade.color.WHITE,
+            batch=self.text_batch,
         )
         self.text_vert_count = arcade.Text(
             "Use mouse wheel to add/remove vertices",
@@ -169,7 +184,7 @@ def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
     def on_mouse_release(self, x, y, button, modifiers):
         self.drag_time = None
 
-    def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int):
+    def on_mouse_scroll(self, x: int, y: int, scroll_x: float, scroll_y: float):
         self.vert_count = clamp(self.vert_count + scroll_y / 500, 0.0, 1.0)
 
 
diff --git a/arcade/examples/gl/normal_mapping_simple.py b/arcade/examples/gl/normal_mapping_simple.py
index 93f6d678e..3503cd69d 100644
--- a/arcade/examples/gl/normal_mapping_simple.py
+++ b/arcade/examples/gl/normal_mapping_simple.py
@@ -21,7 +21,6 @@
 
 
 class NormalMapping(arcade.Window):
-
     def __init__(self):
         super().__init__(512, 512, "Normal Mapping")
 
@@ -130,7 +129,7 @@ def on_mouse_motion(self, x: int, y: int, dx: int, dy: int):
         # (0.0, 0.0) is bottom left, (1.0, 1.0) is top right
         self.mouse_x, self.mouse_y = x / self.width, y / self.height
 
-    def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int):
+    def on_mouse_scroll(self, x: int, y: int, scroll_x: float, scroll_y: float):
         """Zoom in/out with the mouse wheel."""
         self.mouse_z += scroll_y * 0.05
 
diff --git a/arcade/examples/gui/own_layout.py b/arcade/examples/gui/own_layout.py
index ee3797498..8550e4389 100644
--- a/arcade/examples/gui/own_layout.py
+++ b/arcade/examples/gui/own_layout.py
@@ -11,10 +11,13 @@
 from __future__ import annotations
 
 from math import cos, sin
+from typing import TypeVar
 
 import arcade
 from arcade.gui import UIAnchorLayout, UIFlatButton, UILayout, UIView, UIWidget
 
+W = TypeVar("W", bound="UIWidget")
+
 
 class CircleLayout(UILayout):
     """A custom progress bar widget.
@@ -27,7 +30,7 @@ def __init__(self, size_hint=(1, 1), **kwargs):
         super().__init__(size_hint=size_hint, **kwargs)
         self._time = 0  # used for rotation
 
-    def add(self, child: UIWidget, **kwargs) -> UIWidget:
+    def add(self, child: W, **kwargs) -> W:
         """Add a widget to the layout.
 
         The widget is placed in a circle around the center of the screen.
diff --git a/arcade/experimental/crt_filter.py b/arcade/experimental/crt_filter.py
index a26443453..10667a414 100644
--- a/arcade/experimental/crt_filter.py
+++ b/arcade/experimental/crt_filter.py
@@ -25,7 +25,7 @@ def __init__(
         resolution_down_scale: float = 6.0,
         hard_scan: float = -8.0,
         hard_pix: float = -3.0,
-        display_warp: Vec2 = (1.0 / 32.0, 1.0 / 24.0),
+        display_warp: Vec2 = Vec2(1.0 / 32.0, 1.0 / 24.0),
         mask_dark: float = 0.5,
         mask_light: float = 1.5,
     ):
diff --git a/arcade/gl/framebuffer.py b/arcade/gl/framebuffer.py
index 982ba667a..b62027d9f 100644
--- a/arcade/gl/framebuffer.py
+++ b/arcade/gl/framebuffer.py
@@ -2,13 +2,12 @@
 
 import weakref
 from contextlib import contextmanager
-from ctypes import c_int, string_at
-from typing import TYPE_CHECKING, Generator
+from ctypes import Array, c_int, c_uint, string_at
+from typing import Generator, TYPE_CHECKING
 
 from pyglet import gl
 
 from arcade.types import RGBOrA255, RGBOrANormalized
-
 from .texture import Texture2D
 from .types import pixel_formats
 
@@ -124,7 +123,7 @@ def __init__(
         # we use in the use() method to activate the different color attachment layers
         layers = [gl.GL_COLOR_ATTACHMENT0 + i for i, _ in enumerate(self._color_attachments)]
         # pyglet wants this as a ctypes thingy, so let's prepare it
-        self._draw_buffers = (gl.GLuint * len(layers))(*layers)
+        self._draw_buffers: Array[c_uint] | None = (gl.GLuint * len(layers))(*layers)
 
         # Restore the original bound framebuffer to avoid confusion
         self.ctx.active_framebuffer.use(force=True)
diff --git a/arcade/gui/ui_manager.py b/arcade/gui/ui_manager.py
index 4b047fb68..4f36c6cce 100644
--- a/arcade/gui/ui_manager.py
+++ b/arcade/gui/ui_manager.py
@@ -169,7 +169,7 @@ def clear(self):
                 self.remove(widget)
 
     def get_widgets_at(
-        self, pos: Point2, cls: type[W] = UIWidget, layer=DEFAULT_LAYER
+        self, pos: Point2, cls: type[W] | type[UIWidget] = UIWidget, layer=DEFAULT_LAYER
     ) -> Iterable[W]:
         """Yields all widgets containing a position, returns first top laying widgets
         which is instance of cls.
diff --git a/arcade/perf_info.py b/arcade/perf_info.py
index c25451f1b..efb1b67e3 100644
--- a/arcade/perf_info.py
+++ b/arcade/perf_info.py
@@ -151,7 +151,7 @@ def enable_timings(max_history: int = 100) -> None:
     _pyglets_dispatch_event = pyglet.window.BaseWindow.dispatch_event
 
     # Override the pyglet dispatch event function
-    pyglet.window.BaseWindow.dispatch_event = _dispatch_event
+    pyglet.window.BaseWindow.dispatch_event = _dispatch_event  # type: ignore
     _max_history = max_history
 
 
diff --git a/arcade/sound.py b/arcade/sound.py
index 3cf687e81..8b60d45c3 100644
--- a/arcade/sound.py
+++ b/arcade/sound.py
@@ -143,7 +143,7 @@ def _on_player_eos():
             # we need to delete this function.
             player.on_player_eos = None  # type: ignore  # pending https://github.com/pyglet/pyglet/issues/845
 
-        player.on_player_eos = _on_player_eos
+        player.on_player_eos = _on_player_eos  # type: ignore
         return player
 
     def stop(self, player: media.Player) -> None:
diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py
index 614d0ae1d..46dfcca15 100644
--- a/arcade/sprite/base.py
+++ b/arcade/sprite/base.py
@@ -7,7 +7,7 @@
 from arcade.exceptions import ReplacementWarning, warning
 from arcade.hitbox import HitBox
 from arcade.texture import Texture
-from arcade.types import LRBT, RGBA255, AsFloat, Color, Point, Point2, PointList, Rect, RGBOrA255
+from arcade.types import LRBT, Point2List, RGBA255, AsFloat, Color, Point, Point2, Rect, RGBOrA255
 from arcade.utils import copy_dunders_unimplemented
 
 if TYPE_CHECKING:
@@ -437,7 +437,6 @@ def rgb(self) -> tuple[int, int, int]:
 
     @rgb.setter
     def rgb(self, color: RGBOrA255):
-
         # Fast validation of size by unpacking channel values
         try:
             r, g, b, *_a = color
@@ -775,7 +774,7 @@ def draw_hit_box(self, color: RGBA255 = BLACK, line_thickness: float = 2.0) -> N
             line_thickness:
                 How thick the box should be
         """
-        points: PointList = self.hit_box.get_adjusted_points()
+        points: Point2List = self.hit_box.get_adjusted_points()
         # NOTE: This is a COPY operation. We don't want to modify the points.
         points = tuple(points) + tuple(points[:-1])
         arcade.draw_line_strip(points, color=color, line_width=line_thickness)
diff --git a/arcade/sprite/sprite.py b/arcade/sprite/sprite.py
index 59b9e6b1f..3e6b120ff 100644
--- a/arcade/sprite/sprite.py
+++ b/arcade/sprite/sprite.py
@@ -150,8 +150,8 @@ def __init__(
 
         self._hit_box: RotatableHitBox = self._hit_box.create_rotatable(angle=self._angle)
 
-        self._width = self._texture.width * scale
-        self._height = self._texture.height * scale
+        self._width = self._texture.width * self.scale[0]
+        self._height = self._texture.height * self.scale[1]
 
     # --- Properties ---
 
diff --git a/arcade/types/rect.py b/arcade/types/rect.py
index 8ee9fe08c..787c4bc82 100644
--- a/arcade/types/rect.py
+++ b/arcade/types/rect.py
@@ -3,12 +3,13 @@
 from __future__ import annotations
 
 import math
-from typing import NamedTuple, TypedDict
+from typing import Any, NamedTuple, TypedDict
 
 from pyglet.math import Vec2
 
 from arcade.types.numbers import AsFloat
 from arcade.types.vector_like import AnchorPoint, Point2
+from arcade.utils import is_iterable
 
 RectParams = tuple[AsFloat, AsFloat, AsFloat, AsFloat]
 ViewportParams = tuple[int, int, int, int]
@@ -462,12 +463,15 @@ def point_in_bounds(self, point: Point2) -> bool:
         px, py = point
         return (self.left < px < self.right) and (self.bottom < py < self.top)
 
-    def __contains__(self, point: Point2) -> bool:
+    def __contains__(self, point: Point2 | Any) -> bool:
         """Shorthand for :py:meth:`rect.point_in_rect(point) <point_in_rect>`.
 
         Args:
             point: A tuple of :py:class:`int` or :py:class:`float` values.
         """
+        if not is_iterable(point):
+            return False
+
         return self.point_in_rect(point)
 
     def distance_from_bounds(self, point: Point2) -> float:
@@ -487,6 +491,7 @@ def point_on_bounds(self, point: Point2, tolerance: float) -> bool:
 
         Args:
             point: The point to check.
+            tolerance: The maximum distance the point can be from the bounds.
         """
         return abs(self.distance_from_bounds(point)) < tolerance
 
diff --git a/arcade/types/vector_like.py b/arcade/types/vector_like.py
index fe31da458..e09439b37 100644
--- a/arcade/types/vector_like.py
+++ b/arcade/types/vector_like.py
@@ -9,14 +9,14 @@
 
 from __future__ import annotations
 
-from typing import Sequence, Union
+from typing import Sequence, Tuple, Union
 
 from pyglet.math import Vec2, Vec3
 
 from arcade.types.numbers import AsFloat
 
 #: Matches both :py:class:`~pyglet.math.Vec2` and tuples of two numbers.
-Point2 = Union[tuple[AsFloat, AsFloat], Vec2]
+Point2 = Union[Tuple[AsFloat, AsFloat], Vec2]
 
 #: Matches both :py:class:`~pyglet.math.Vec3` and tuples of three numbers.
 Point3 = Union[tuple[AsFloat, AsFloat, AsFloat], Vec3]