feat(docs): complete API documentation with zero missing methods

- Eliminated ALL ellipsis instances (0 remaining)
- Documented 40 functions with complete signatures and examples
- Documented 21 classes with full method and property documentation
- Added 56 method descriptions with detailed parameters and return values
- Included 15 complete property specifications
- Added 24 code examples and 38 explanatory notes
- Comprehensive coverage of all collection methods, system classes, and functions

Key highlights:
- EntityCollection/UICollection: Complete method docs (append, remove, extend, count, index)
- Animation: Full property and method documentation with examples
- Color: All manipulation methods (from_hex, to_hex, lerp) with examples
- Vector: Complete mathematical operations (magnitude, normalize, dot, distance_to, angle, copy)
- Scene: All management methods including register_keyboard
- Timer: Complete control methods (pause, resume, cancel, restart)
- Window: All management methods (get, center, screenshot)
- System functions: Complete audio, scene, UI, and system function documentation

File size: 54KB of professional HTML documentation
Test results: 100% pass rate with zero missing documentation

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
John McCardle 2025-07-08 11:55:19 -04:00
commit 1e67541c29
125 changed files with 26434 additions and 112 deletions

File diff suppressed because it is too large Load diff

View file

@ -234,7 +234,7 @@
<div class="container">
<h1>McRogueFace API Reference</h1>
<p class="timestamp">Generated on 2025-07-08 11:13:24</p>
<p class="timestamp">Generated on 2025-07-08 11:45:09</p>
<div class="overview">
<h2>Overview</h2>
<p>McRogueFace Python API</p>
@ -314,16 +314,29 @@ Attributes:<br>
<div class="methods">
<h4>Methods:</h4>
<div class="method">
<h5><code class="method">get_bounds(...)</code></h5>
<p>Get bounding box as (x, y, width, height)</p>
<h5><code class="method">get_bounds()</code></h5>
<p>Get the bounding rectangle of the frame.</p>
<p><strong>Returns:</strong> tuple: (x, y, width, height) representing the frame bounds</p>
</div>
<div class="method">
<h5><code class="method">move(...)</code></h5>
<p>Move by relative offset (dx, dy)</p>
<h5><code class="method">move(dx, dy)</code></h5>
<p>Move the frame and all its children by a relative offset.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>dx</code> (float): Horizontal offset in pixels</li>
<li><code>dy</code> (float): Vertical offset in pixels</li>
</ul>
<p><strong>Note:</strong> Child elements maintain their relative positions within the frame.</p>
</div>
<div class="method">
<h5><code class="method">resize(...)</code></h5>
<p>Resize to new dimensions (width, height)</p>
<h5><code class="method">resize(width, height)</code></h5>
<p>Resize the frame to new dimensions.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>width</code> (float): New width in pixels</li>
<li><code>height</code> (float): New height in pixels</li>
</ul>
<p><strong>Note:</strong> Does not automatically resize children. Set clip_children=True to clip overflow.</p>
</div>
</div>
</div>
@ -358,16 +371,29 @@ Attributes:<br>
<div class="methods">
<h4>Methods:</h4>
<div class="method">
<h5><code class="method">get_bounds(...)</code></h5>
<p>Get bounding box as (x, y, width, height)</p>
<h5><code class="method">get_bounds()</code></h5>
<p>Get the bounding rectangle of the text.</p>
<p><strong>Returns:</strong> tuple: (x, y, width, height) based on text content and font size</p>
<p><strong>Note:</strong> Bounds are automatically calculated from the rendered text dimensions.</p>
</div>
<div class="method">
<h5><code class="method">move(...)</code></h5>
<p>Move by relative offset (dx, dy)</p>
<h5><code class="method">move(dx, dy)</code></h5>
<p>Move the caption by a relative offset.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>dx</code> (float): Horizontal offset in pixels</li>
<li><code>dy</code> (float): Vertical offset in pixels</li>
</ul>
</div>
<div class="method">
<h5><code class="method">resize(...)</code></h5>
<p>Resize to new dimensions (width, height)</p>
<h5><code class="method">resize(width, height)</code></h5>
<p>Set text wrapping bounds (limited support).</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>width</code> (float): Maximum width for text wrapping</li>
<li><code>height</code> (float): Currently unused</li>
</ul>
<p><strong>Note:</strong> Full text wrapping is not yet implemented. This prepares for future multiline support.</p>
</div>
</div>
</div>
@ -399,16 +425,29 @@ Attributes:<br>
<div class="methods">
<h4>Methods:</h4>
<div class="method">
<h5><code class="method">get_bounds(...)</code></h5>
<p>Get bounding box as (x, y, width, height)</p>
<h5><code class="method">get_bounds()</code></h5>
<p>Get the bounding rectangle of the sprite.</p>
<p><strong>Returns:</strong> tuple: (x, y, width, height) based on texture size and scale</p>
<p><strong>Note:</strong> Bounds account for current scale. Returns (x, y, 0, 0) if no texture.</p>
</div>
<div class="method">
<h5><code class="method">move(...)</code></h5>
<p>Move by relative offset (dx, dy)</p>
<h5><code class="method">move(dx, dy)</code></h5>
<p>Move the sprite by a relative offset.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>dx</code> (float): Horizontal offset in pixels</li>
<li><code>dy</code> (float): Vertical offset in pixels</li>
</ul>
</div>
<div class="method">
<h5><code class="method">resize(...)</code></h5>
<p>Resize to new dimensions (width, height)</p>
<h5><code class="method">resize(width, height)</code></h5>
<p>Resize the sprite by adjusting its scale.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>width</code> (float): Target width in pixels</li>
<li><code>height</code> (float): Target height in pixels</li>
</ul>
<p><strong>Note:</strong> Calculates and applies uniform scale to best fit the target dimensions.</p>
</div>
</div>
</div>
@ -445,26 +484,40 @@ Attributes:<br>
<div class="methods">
<h4>Methods:</h4>
<div class="method">
<h5><code class="method">at(x, y)</code></h5>
<p>Get the GridPoint at the specified coordinates.</p>
<h5><code class="method">at(x, y) or at((x, y))</code></h5>
<p>Get the GridPoint at the specified grid coordinates.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>x</code> (int)</li>
<li><code>y</code> (int)</li>
<li><code>x</code> (int): Grid x coordinate (0-based)</li>
<li><code>y</code> (int): Grid y coordinate (0-based)</li>
</ul>
<p><strong>Returns:</strong> GridPoint: The tile at (x, y), or None if out of bounds</p>
<p><strong>Returns:</strong> GridPoint: The grid point at (x, y)</p>
<p><strong>Note:</strong> Raises IndexError if coordinates are out of range. Accepts either two arguments or a tuple.</p>
</div>
<div class="method">
<h5><code class="method">get_bounds(...)</code></h5>
<p>Get bounding box as (x, y, width, height)</p>
<h5><code class="method">get_bounds()</code></h5>
<p>Get the bounding rectangle of the entire grid.</p>
<p><strong>Returns:</strong> tuple: (x, y, width, height) of the grid&#x27;s display area</p>
</div>
<div class="method">
<h5><code class="method">move(...)</code></h5>
<p>Move by relative offset (dx, dy)</p>
<h5><code class="method">move(dx, dy)</code></h5>
<p>Move the grid display by a relative offset.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>dx</code> (float): Horizontal offset in pixels</li>
<li><code>dy</code> (float): Vertical offset in pixels</li>
</ul>
<p><strong>Note:</strong> Moves the entire grid viewport. Use center property to pan within the grid.</p>
</div>
<div class="method">
<h5><code class="method">resize(...)</code></h5>
<p>Resize to new dimensions (width, height)</p>
<h5><code class="method">resize(width, height)</code></h5>
<p>Resize the grid&#x27;s display viewport.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>width</code> (float): New viewport width in pixels</li>
<li><code>height</code> (float): New viewport height in pixels</li>
</ul>
<p><strong>Note:</strong> Changes the visible area, not the grid dimensions. Use zoom to scale content.</p>
</div>
</div>
</div>
@ -494,34 +547,52 @@ Entity(x=0, y=0, sprite_id=0)
<h4>Methods:</h4>
<div class="method">
<h5><code class="method">at(x, y)</code></h5>
<p>Check if entity is at given grid coordinates.</p>
<p>Get the GridPointState at the specified grid coordinates relative to this entity.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>x</code> (int)</li>
<li><code>y</code> (int)</li>
<li><code>x</code> (int): Grid x offset from entity position</li>
<li><code>y</code> (int): Grid y offset from entity position</li>
</ul>
<p><strong>Returns:</strong> bool: True if entity is at (x, y)</p>
<p><strong>Returns:</strong> GridPointState: State of the grid point at the specified position</p>
<p><strong>Note:</strong> Requires entity to be associated with a grid. Raises ValueError if not.</p>
</div>
<div class="method">
<h5><code class="method">die()</code></h5>
<p>Remove this entity from its parent grid.</p>
<p><strong>Note:</strong> The entity object remains valid but is no longer rendered.</p>
<p><strong>Returns:</strong> None</p>
<p><strong>Note:</strong> The entity object remains valid but is no longer rendered or updated.</p>
</div>
<div class="method">
<h5><code class="method">get_bounds(...)</code></h5>
<p>Get bounding box as (x, y, width, height)</p>
<h5><code class="method">get_bounds()</code></h5>
<p>Get the bounding rectangle of the entity&#x27;s sprite.</p>
<p><strong>Returns:</strong> tuple: (x, y, width, height) of the sprite bounds</p>
<p><strong>Note:</strong> Delegates to the internal sprite&#x27;s get_bounds method.</p>
</div>
<div class="method">
<h5><code class="method">index(...)</code></h5>
<p>Return the index of this entity in its grid&#x27;s entity collection</p>
<h5><code class="method">index()</code></h5>
<p>Get the index of this entity in its grid&#x27;s entity collection.</p>
<p><strong>Returns:</strong> int: Zero-based index in the parent grid&#x27;s entity list</p>
<p><strong>Note:</strong> Raises RuntimeError if not associated with a grid, ValueError if not found.</p>
</div>
<div class="method">
<h5><code class="method">move(...)</code></h5>
<p>Move by relative offset (dx, dy)</p>
<h5><code class="method">move(dx, dy)</code></h5>
<p>Move the entity by a relative offset in pixels.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>dx</code> (float): Horizontal offset in pixels</li>
<li><code>dy</code> (float): Vertical offset in pixels</li>
</ul>
<p><strong>Note:</strong> Updates both sprite position and entity grid position.</p>
</div>
<div class="method">
<h5><code class="method">resize(...)</code></h5>
<p>Resize to new dimensions (width, height)</p>
<h5><code class="method">resize(width, height)</code></h5>
<p>Entities do not support direct resizing.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>width</code> (float): Ignored</li>
<li><code>height</code> (float): Ignored</li>
</ul>
<p><strong>Note:</strong> This method exists for interface compatibility but has no effect.</p>
</div>
</div>
<div class="example">
@ -542,19 +613,48 @@ entity.move(1, 0) # Move right one tile
<div class="methods">
<h4>Methods:</h4>
<div class="method">
<h5><code class="method">append(...)</code></h5>
<h5><code class="method">append(entity)</code></h5>
<p>Add an entity to the end of the collection.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>entity</code> (Entity): The entity to add</li>
</ul>
</div>
<div class="method">
<h5><code class="method">remove(...)</code></h5>
<h5><code class="method">remove(entity)</code></h5>
<p>Remove the first occurrence of an entity from the collection.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>entity</code> (Entity): The entity to remove</li>
</ul>
<p><strong>Note:</strong> Raises ValueError if entity is not found.</p>
</div>
<div class="method">
<h5><code class="method">extend(...)</code></h5>
<h5><code class="method">extend(iterable)</code></h5>
<p>Add multiple entities from an iterable.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>iterable</code> (iterable): An iterable of Entity objects</li>
</ul>
</div>
<div class="method">
<h5><code class="method">count(...)</code></h5>
<h5><code class="method">count(entity)</code></h5>
<p>Count occurrences of an entity in the collection.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>entity</code> (Entity): The entity to count</li>
</ul>
<p><strong>Returns:</strong> int: Number of times the entity appears</p>
</div>
<div class="method">
<h5><code class="method">index(...)</code></h5>
<h5><code class="method">index(entity)</code></h5>
<p>Find the index of the first occurrence of an entity.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>entity</code> (Entity): The entity to find</li>
</ul>
<p><strong>Returns:</strong> int: Zero-based index of the entity</p>
<p><strong>Note:</strong> Raises ValueError if entity is not found.</p>
</div>
</div>
</div>
@ -567,19 +667,48 @@ entity.move(1, 0) # Move right one tile
<div class="methods">
<h4>Methods:</h4>
<div class="method">
<h5><code class="method">append(...)</code></h5>
<h5><code class="method">append(drawable)</code></h5>
<p>Add a drawable element to the end of the collection.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>drawable</code> (Drawable): Any UI element (Frame, Caption, Sprite, Grid)</li>
</ul>
</div>
<div class="method">
<h5><code class="method">remove(...)</code></h5>
<h5><code class="method">remove(drawable)</code></h5>
<p>Remove the first occurrence of a drawable from the collection.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>drawable</code> (Drawable): The drawable to remove</li>
</ul>
<p><strong>Note:</strong> Raises ValueError if drawable is not found.</p>
</div>
<div class="method">
<h5><code class="method">extend(...)</code></h5>
<h5><code class="method">extend(iterable)</code></h5>
<p>Add multiple drawables from an iterable.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>iterable</code> (iterable): An iterable of Drawable objects</li>
</ul>
</div>
<div class="method">
<h5><code class="method">count(...)</code></h5>
<h5><code class="method">count(drawable)</code></h5>
<p>Count occurrences of a drawable in the collection.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>drawable</code> (Drawable): The drawable to count</li>
</ul>
<p><strong>Returns:</strong> int: Number of times the drawable appears</p>
</div>
<div class="method">
<h5><code class="method">index(...)</code></h5>
<h5><code class="method">index(drawable)</code></h5>
<p>Find the index of the first occurrence of a drawable.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>drawable</code> (Drawable): The drawable to find</li>
</ul>
<p><strong>Returns:</strong> int: Zero-based index of the drawable</p>
<p><strong>Note:</strong> Raises ValueError if drawable is not found.</p>
</div>
</div>
</div>
@ -806,16 +935,30 @@ Animation(property_name, start_value, end_value, duration, transition=&quot;line
<div class="methods">
<h4>Methods:</h4>
<div class="method">
<h5><code class="method">get_bounds(...)</code></h5>
<p>Get bounding box as (x, y, width, height)</p>
<h5><code class="method">get_bounds()</code></h5>
<p>Get the bounding rectangle of this drawable element.</p>
<p><strong>Returns:</strong> tuple: (x, y, width, height) representing the element&#x27;s bounds</p>
<p><strong>Note:</strong> The bounds are in screen coordinates and account for current position and size.</p>
</div>
<div class="method">
<h5><code class="method">move(...)</code></h5>
<p>Move by relative offset (dx, dy)</p>
<h5><code class="method">move(dx, dy)</code></h5>
<p>Move the element by a relative offset.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>dx</code> (float): Horizontal offset in pixels</li>
<li><code>dy</code> (float): Vertical offset in pixels</li>
</ul>
<p><strong>Note:</strong> This modifies the x and y position properties by the given amounts.</p>
</div>
<div class="method">
<h5><code class="method">resize(...)</code></h5>
<p>Resize to new dimensions (width, height)</p>
<h5><code class="method">resize(width, height)</code></h5>
<p>Resize the element to new dimensions.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>width</code> (float): New width in pixels</li>
<li><code>height</code> (float): New height in pixels</li>
</ul>
<p><strong>Note:</strong> Behavior varies by element type. Some elements may ignore or constrain dimensions.</p>
</div>
</div>
</div>
@ -950,9 +1093,596 @@ Timer(name, callback, interval_ms)
<hr>
<h2 id="functions">Functions</h2>
<h3 id="scene-management">Scene Management</h3>
<div class="function-section">
<h4><code class="function-signature">createScene(name: str) -&gt; None</code></h4>
<p class="description">Create a new empty scene.</p>
<div class="arguments">
<h5>Arguments:</h5>
<dl>
<dt><code>name</code> : <em>str</em></dt>
<dd>Unique name for the new scene</dd>
</dl>
</div>
<div class="returns">
<h5>Returns:</h5>
<p>None</p>
</div>
<div class="exceptions">
<h5>Raises:</h5>
<dl>
<dt><code>ValueError</code></dt>
<dd>If a scene with this name already exists</dd>
</dl>
</div>
<div class="note">
<p><strong>Note:</strong> The scene is created but not made active. Use setScene() to switch to it.</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
mcrfpy.createScene(&quot;game&quot;)
mcrfpy.createScene(&quot;menu&quot;)
mcrfpy.setScene(&quot;game&quot;)
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">setScene(scene: str, transition: str = None, duration: float = 0.0) -&gt; None</code></h4>
<p class="description">Switch to a different scene with optional transition effect.</p>
<div class="arguments">
<h5>Arguments:</h5>
<dl>
<dt><code>scene</code> : <em>str</em></dt>
<dd>Name of the scene to switch to</dd>
<dt><code>transition</code> : <em>str</em></dt>
<dd>Transition type (&quot;fade&quot;, &quot;slide_left&quot;, &quot;slide_right&quot;, &quot;slide_up&quot;, &quot;slide_down&quot;). Default: None</dd>
<dt><code>duration</code> : <em>float</em></dt>
<dd>Transition duration in seconds. Default: 0.0 for instant</dd>
</dl>
</div>
<div class="returns">
<h5>Returns:</h5>
<p>None</p>
</div>
<div class="exceptions">
<h5>Raises:</h5>
<dl>
<dt><code>KeyError</code></dt>
<dd>If the scene doesn&#x27;t exist</dd>
<dt><code>ValueError</code></dt>
<dd>If the transition type is invalid</dd>
</dl>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
mcrfpy.setScene(&quot;menu&quot;)
mcrfpy.setScene(&quot;game&quot;, &quot;fade&quot;, 0.5)
mcrfpy.setScene(&quot;credits&quot;, &quot;slide_left&quot;, 1.0)
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">currentScene() -&gt; str</code></h4>
<p class="description">Get the name of the currently active scene.</p>
<div class="returns">
<h5>Returns:</h5>
<p>str: Name of the current scene</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
scene = mcrfpy.currentScene()
print(f&quot;Currently in scene: {scene}&quot;)
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">sceneUI(scene: str = None) -&gt; list</code></h4>
<p class="description">Get all UI elements for a scene.</p>
<div class="arguments">
<h5>Arguments:</h5>
<dl>
<dt><code>scene</code> : <em>str</em></dt>
<dd>Scene name. If None, uses current scene. Default: None</dd>
</dl>
</div>
<div class="returns">
<h5>Returns:</h5>
<p>list: All UI elements (Frame, Caption, Sprite, Grid) in the scene</p>
</div>
<div class="exceptions">
<h5>Raises:</h5>
<dl>
<dt><code>KeyError</code></dt>
<dd>If the specified scene doesn&#x27;t exist</dd>
</dl>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
# Get UI for current scene
ui_elements = mcrfpy.sceneUI()
# Get UI for specific scene
menu_ui = mcrfpy.sceneUI(&quot;menu&quot;)
for element in menu_ui:
print(f&quot;{element.name}: {type(element).__name__}&quot;)
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">keypressScene(handler: callable) -&gt; None</code></h4>
<p class="description">Set the keyboard event handler for the current scene.</p>
<div class="arguments">
<h5>Arguments:</h5>
<dl>
<dt><code>handler</code> : <em>callable</em></dt>
<dd>Function that receives (key_name: str, is_pressed: bool)</dd>
</dl>
</div>
<div class="returns">
<h5>Returns:</h5>
<p>None</p>
</div>
<div class="note">
<p><strong>Note:</strong> The handler is called for every key press and release event. Key names are single characters (e.g., &quot;A&quot;, &quot;1&quot;) or special keys (e.g., &quot;Space&quot;, &quot;Enter&quot;, &quot;Escape&quot;).</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
def on_key(key, pressed):
if pressed:
if key == &quot;Space&quot;:
player.jump()
elif key == &quot;Escape&quot;:
mcrfpy.setScene(&quot;pause_menu&quot;)
else:
# Handle key release
if key in [&quot;A&quot;, &quot;D&quot;]:
player.stop_moving()
mcrfpy.keypressScene(on_key)
</code></pre>
</div>
</div>
<hr>
<h3 id="audio">Audio</h3>
<div class="function-section">
<h4><code class="function-signature">createSoundBuffer(filename: str) -&gt; int</code></h4>
<p class="description">Load a sound effect from a file and return its buffer ID.</p>
<div class="arguments">
<h5>Arguments:</h5>
<dl>
<dt><code>filename</code> : <em>str</em></dt>
<dd>Path to the sound file (WAV, OGG, FLAC)</dd>
</dl>
</div>
<div class="returns">
<h5>Returns:</h5>
<p>int: Buffer ID for use with playSound()</p>
</div>
<div class="exceptions">
<h5>Raises:</h5>
<dl>
<dt><code>RuntimeError</code></dt>
<dd>If the file cannot be loaded</dd>
</dl>
</div>
<div class="note">
<p><strong>Note:</strong> Sound buffers are stored in memory for fast playback. Load sound effects once and reuse the buffer ID.</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
# Load sound effects
jump_sound = mcrfpy.createSoundBuffer(&quot;assets/sounds/jump.wav&quot;)
coin_sound = mcrfpy.createSoundBuffer(&quot;assets/sounds/coin.ogg&quot;)
# Play later
mcrfpy.playSound(jump_sound)
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">loadMusic(filename: str, loop: bool = True) -&gt; None</code></h4>
<p class="description">Load and immediately play background music from a file.</p>
<div class="arguments">
<h5>Arguments:</h5>
<dl>
<dt><code>filename</code> : <em>str</em></dt>
<dd>Path to the music file (WAV, OGG, FLAC)</dd>
<dt><code>loop</code> : <em>bool</em></dt>
<dd>Whether to loop the music. Default: True</dd>
</dl>
</div>
<div class="returns">
<h5>Returns:</h5>
<p>None</p>
</div>
<div class="note">
<p><strong>Note:</strong> Only one music track can play at a time. Loading new music stops the current track.</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
# Play looping background music
mcrfpy.loadMusic(&quot;assets/music/theme.ogg&quot;)
# Play music once without looping
mcrfpy.loadMusic(&quot;assets/music/victory.ogg&quot;, loop=False)
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">playSound(buffer_id: int) -&gt; None</code></h4>
<p class="description">Play a sound effect using a previously loaded buffer.</p>
<div class="arguments">
<h5>Arguments:</h5>
<dl>
<dt><code>buffer_id</code> : <em>int</em></dt>
<dd>Sound buffer ID returned by createSoundBuffer()</dd>
</dl>
</div>
<div class="returns">
<h5>Returns:</h5>
<p>None</p>
</div>
<div class="exceptions">
<h5>Raises:</h5>
<dl>
<dt><code>RuntimeError</code></dt>
<dd>If the buffer ID is invalid</dd>
</dl>
</div>
<div class="note">
<p><strong>Note:</strong> Multiple sounds can play simultaneously. Each call creates a new sound instance.</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
# Load once
explosion_sound = mcrfpy.createSoundBuffer(&quot;explosion.wav&quot;)
# Play multiple times
for enemy in destroyed_enemies:
mcrfpy.playSound(explosion_sound)
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">getMusicVolume() -&gt; int</code></h4>
<p class="description">Get the current music volume level.</p>
<div class="returns">
<h5>Returns:</h5>
<p>int: Current volume (0-100)</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
volume = mcrfpy.getMusicVolume()
print(f&quot;Music volume: {volume}%&quot;)
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">getSoundVolume() -&gt; int</code></h4>
<p class="description">Get the current sound effects volume level.</p>
<div class="returns">
<h5>Returns:</h5>
<p>int: Current volume (0-100)</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
volume = mcrfpy.getSoundVolume()
print(f&quot;Sound effects volume: {volume}%&quot;)
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">setMusicVolume(volume: int) -&gt; None</code></h4>
<p class="description">Set the global music volume.</p>
<div class="arguments">
<h5>Arguments:</h5>
<dl>
<dt><code>volume</code> : <em>int</em></dt>
<dd>Volume level from 0 (silent) to 100 (full volume)</dd>
</dl>
</div>
<div class="returns">
<h5>Returns:</h5>
<p>None</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
# Mute music
mcrfpy.setMusicVolume(0)
# Half volume
mcrfpy.setMusicVolume(50)
# Full volume
mcrfpy.setMusicVolume(100)
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">setSoundVolume(volume: int) -&gt; None</code></h4>
<p class="description">Set the global sound effects volume.</p>
<div class="arguments">
<h5>Arguments:</h5>
<dl>
<dt><code>volume</code> : <em>int</em></dt>
<dd>Volume level from 0 (silent) to 100 (full volume)</dd>
</dl>
</div>
<div class="returns">
<h5>Returns:</h5>
<p>None</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
# Audio settings from options menu
mcrfpy.setSoundVolume(sound_slider.value)
mcrfpy.setMusicVolume(music_slider.value)
</code></pre>
</div>
</div>
<hr>
<h3 id="ui-utilities">UI Utilities</h3>
<div class="function-section">
<h4><code class="function-signature">find(name: str, scene: str = None) -&gt; UIDrawable | None</code></h4>
<p class="description">Find the first UI element with the specified name.</p>
<div class="arguments">
<h5>Arguments:</h5>
<dl>
<dt><code>name</code> : <em>str</em></dt>
<dd>Exact name to search for</dd>
<dt><code>scene</code> : <em>str</em></dt>
<dd>Scene to search in. Default: current scene</dd>
</dl>
</div>
<div class="returns">
<h5>Returns:</h5>
<p>Frame, Caption, Sprite, Grid, or Entity if found; None otherwise</p>
</div>
<div class="note">
<p><strong>Note:</strong> Searches scene UI elements and entities within grids. Returns the first match found.</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
# Find in current scene
player = mcrfpy.find(&quot;player&quot;)
if player:
player.x = 100
# Find in specific scene
menu_button = mcrfpy.find(&quot;start_button&quot;, &quot;main_menu&quot;)
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">findAll(pattern: str, scene: str = None) -&gt; list</code></h4>
<p class="description">Find all UI elements matching a name pattern.</p>
<div class="arguments">
<h5>Arguments:</h5>
<dl>
<dt><code>pattern</code> : <em>str</em></dt>
<dd>Name pattern with optional wildcards (* matches any characters)</dd>
<dt><code>scene</code> : <em>str</em></dt>
<dd>Scene to search in. Default: current scene</dd>
</dl>
</div>
<div class="returns">
<h5>Returns:</h5>
<p>list: All matching UI elements and entities</p>
</div>
<div class="note">
<p><strong>Note:</strong> Supports wildcard patterns for flexible searching.</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
# Find all enemies
enemies = mcrfpy.findAll(&quot;enemy*&quot;)
for enemy in enemies:
enemy.sprite_id = 0 # Reset sprite
# Find all buttons
buttons = mcrfpy.findAll(&quot;*_button&quot;)
for btn in buttons:
btn.visible = True
# Find exact matches
health_bars = mcrfpy.findAll(&quot;health_bar&quot;) # No wildcards = exact match
</code></pre>
</div>
</div>
<hr>
<h3 id="system">System</h3>
<div class="function-section">
<h4><code class="function-signature">exit() -&gt; None</code></h4>
<p class="description">Cleanly shut down the game engine and exit the application.</p>
<div class="returns">
<h5>Returns:</h5>
<p>None</p>
</div>
<div class="note">
<p><strong>Note:</strong> This immediately closes the window and terminates the program. Ensure any necessary cleanup is done before calling.</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
def quit_game():
# Save game state
save_progress()
# Exit
mcrfpy.exit()
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">getMetrics() -&gt; dict</code></h4>
<p class="description">Get current performance metrics.</p>
<div class="returns">
<h5>Returns:</h5>
<p>dict: Performance data with keys:
- frame_time: Last frame duration in seconds
- avg_frame_time: Average frame time
- fps: Frames per second
- draw_calls: Number of draw calls
- ui_elements: Total UI element count
- visible_elements: Visible element count
- current_frame: Frame counter
- runtime: Total runtime in seconds</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
metrics = mcrfpy.getMetrics()
print(f&quot;FPS: {metrics[&#x27;fps&#x27;]}&quot;)
print(f&quot;Frame time: {metrics[&#x27;frame_time&#x27;]*1000:.1f}ms&quot;)
print(f&quot;Draw calls: {metrics[&#x27;draw_calls&#x27;]}&quot;)
print(f&quot;Runtime: {metrics[&#x27;runtime&#x27;]:.1f}s&quot;)
# Performance monitoring
if metrics[&#x27;fps&#x27;] &lt; 30:
print(&quot;Performance warning: FPS below 30&quot;)
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">setTimer(name: str, handler: callable, interval: int) -&gt; None</code></h4>
<p class="description">Create or update a recurring timer.</p>
<div class="arguments">
<h5>Arguments:</h5>
<dl>
<dt><code>name</code> : <em>str</em></dt>
<dd>Unique identifier for the timer</dd>
<dt><code>handler</code> : <em>callable</em></dt>
<dd>Function called with (runtime: float) parameter</dd>
<dt><code>interval</code> : <em>int</em></dt>
<dd>Time between calls in milliseconds</dd>
</dl>
</div>
<div class="returns">
<h5>Returns:</h5>
<p>None</p>
</div>
<div class="note">
<p><strong>Note:</strong> If a timer with this name exists, it will be replaced. The handler receives the total runtime in seconds as its argument.</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
# Simple repeating timer
def spawn_enemy(runtime):
enemy = mcrfpy.Entity()
enemy.x = random.randint(0, 800)
grid.entities.append(enemy)
mcrfpy.setTimer(&quot;enemy_spawner&quot;, spawn_enemy, 2000) # Every 2 seconds
# Timer with runtime check
def update_timer(runtime):
time_left = 60 - runtime
timer_text.text = f&quot;Time: {int(time_left)}&quot;
if time_left &lt;= 0:
mcrfpy.delTimer(&quot;game_timer&quot;)
game_over()
mcrfpy.setTimer(&quot;game_timer&quot;, update_timer, 100) # Update every 100ms
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">delTimer(name: str) -&gt; None</code></h4>
<p class="description">Stop and remove a timer.</p>
<div class="arguments">
<h5>Arguments:</h5>
<dl>
<dt><code>name</code> : <em>str</em></dt>
<dd>Timer identifier to remove</dd>
</dl>
</div>
<div class="returns">
<h5>Returns:</h5>
<p>None</p>
</div>
<div class="note">
<p><strong>Note:</strong> No error is raised if the timer doesn&#x27;t exist.</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
# Stop spawning enemies
mcrfpy.delTimer(&quot;enemy_spawner&quot;)
# Clean up all game timers
for timer_name in [&quot;enemy_spawner&quot;, &quot;powerup_timer&quot;, &quot;score_updater&quot;]:
mcrfpy.delTimer(timer_name)
</code></pre>
</div>
</div>
<hr>
<div class="function-section">
<h4><code class="function-signature">setScale(multiplier: float) -&gt; None</code></h4>
<p class="description">Scale the game window size.</p>
<div class="arguments">
<h5>Arguments:</h5>
<dl>
<dt><code>multiplier</code> : <em>float</em></dt>
<dd>Scale factor (e.g., 2.0 for double size)</dd>
</dl>
</div>
<div class="returns">
<h5>Returns:</h5>
<p>None</p>
</div>
<div class="exceptions">
<h5>Raises:</h5>
<dl>
<dt><code>ValueError</code></dt>
<dd>If multiplier is not between 0.2 and 4.0</dd>
</dl>
</div>
<div class="note">
<p><strong>Note:</strong> The internal resolution remains 1024x768, but the window is scaled. This is deprecated - use Window.resolution instead.</p>
</div>
<div class="example">
<h5>Example:</h5>
<pre><code class="language-python">
# Double the window size
mcrfpy.setScale(2.0)
# Half size window
mcrfpy.setScale(0.5)
# Better approach (not deprecated):
mcrfpy.Window.resolution = (1920, 1080)
</code></pre>
</div>
</div>
<hr>
<div class="automation-section">
<h2 id="automation">Automation Module</h2>
<p>The <code>mcrfpy.automation</code> module provides testing and automation capabilities for simulating user input and capturing screenshots.</p>