Skip to content

Show numbers on the wheel, streamline UI, add SFX#2

Merged
InstaZDLL merged 3 commits into
mainfrom
feat/wheel-numbers-and-sfx
Jun 6, 2026
Merged

Show numbers on the wheel, streamline UI, add SFX#2
InstaZDLL merged 3 commits into
mainfrom
feat/wheel-numbers-and-sfx

Conversation

@InstaZDLL

@InstaZDLL InstaZDLL commented Jun 6, 2026

Copy link
Copy Markdown
Owner

This pull request introduces a self-contained audio engine for sound effects, updates the application architecture to include audio, and refactors the UI and data model to improve performance and maintainability. It also includes visual improvements to the roulette wheel and table rendering.

Audio engine integration and architecture updates:

  • Added a new audio module (src/audio.zig) that provides synthesized sound effects (chip, spin, win), loads PulseAudio at runtime via dlopen, and ensures sound is optional and non-blocking. The Audio instance is now part of AppState and is properly initialized and deinitialized. [1] [2] [3] [4] [5] [6] [7]

UI and data model refactoring:

  • Replaced heap-allocated history entries with a simpler, value-based HistoryEntry struct, reducing memory management complexity and improving performance. The history is now displayed as colored chips, with color derived from the number, and the corresponding UI widget was renamed for clarity. [1] [2] [3]

GTK and Cairo API enhancements:

  • Extended gtk.zig with additional widget and drawing bindings (e.g., GtkScrolledWindow, gtk_box_remove, gtk_button_set_label, new Cairo functions) to support richer UI features and improved rendering. [1] [2] [3] [4] [5]

Visual improvements:

  • Enhanced the roulette wheel rendering to be more visually accurate and appealing: adjusted wheel and hub proportions, added a dark outer rim, improved background and pocket coloring, and now draws pocket numbers radially to match real wheels. The last result is shown in the hub only when not spinning. Table background color was also updated for better aesthetics. [1] [2] [3]

These changes collectively modernize the codebase, improve user experience with sound and visuals, and simplify internal data handling.- render: draw each pocket number rotated radially; brighter Stake-style palette; last result large in the hub centre

  • ui: replace the bulky right sidebar with a slim left control rail (amount + ½/2×, Lancer) and a top bar (balance pill + recent-numbers chip strip); bet by clicking the table directly
  • audio: new self-contained SFX engine, loads libpulse-simple via dlopen (no link-time dep, degrades silently); synthesised chip/spin/win cues played on detached threads; mute toggle
  • simplify HistoryEntry to value-only (no heap strings)

Summary by CodeRabbit

  • New Features

    • Lightweight sound-effects engine with mute/unmute and fire‑and‑forget playback for game actions.
    • Staked bets now display as chips directly on betting zones.
  • UI/UX Improvements

    • Reorganized layout to a control rail + play area; streamlined top/bottom bars.
    • Compact history rendered as a colored chip strip; balance label updates.
    • Refined wheel/table visuals, pocket numbering, and number/color styling.
  • Documentation

    • Updated architecture and resource-lifecycle guidance.

- render: draw each pocket number rotated radially; brighter Stake-style
  palette; last result large in the hub centre
- ui: replace the bulky right sidebar with a slim left control rail
  (amount + ½/2×, Lancer) and a top bar (balance pill + recent-numbers
  chip strip); bet by clicking the table directly
- audio: new self-contained SFX engine, loads libpulse-simple via dlopen
  (no link-time dep, degrades silently); synthesised chip/spin/win cues
  played on detached threads; mute toggle
- simplify HistoryEntry to value-only (no heap strings)
@InstaZDLL InstaZDLL self-assigned this Jun 6, 2026
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a runtime-loaded audio SFX engine, integrates it into AppState, replaces heap-allocated history strings with numeric entries, restructures the UI from a sidebar to a control rail + play area, and updates rendering and styling to match the new layout.

Changes

Roulette UI Reorganization with Audio Engine

Layer / File(s) Summary
Architecture and Design Documentation
CLAUDE.md
Updated architecture notes documenting the new audio module as a self-contained runtime-loaded SFX engine and revised AppState init/deinit lifecycle.
Audio Engine Implementation
src/audio.zig
New self-contained sound effects engine with runtime-loaded libpulse-simple support, precomputed PCM buffers for three effects (chip, spin, win), detached-thread playback, and lifecycle/control APIs.
GTK and Cairo Bindings Extensions
src/gtk.zig
Added GTK policy constants, GtkScrolledWindow opaque type, widget manipulation externs (gtk_box_remove, gtk_button_set_label, scrolled window APIs) and Cairo transform/color externs.
AppState Redesign and Memory Model
src/app.zig
AppState now contains audio and history_strip; HistoryEntry uses number and profit value fields; AppState.init initializes audio and AppState.deinit calls audio.deinit() first; clearHistory no longer frees per-entry strings.
Rendering Updates for Wheel and Table
src/render.zig
Reworked wheel rendering with radial pocket numbers and layered hub; table zones use inset fills, updated color/stroke logic, and show staked chips; number color mapping updated.
CSS Styling Refactoring
src/style.css
Replaced sidebar/history styles with .play-area and .control-rail, added pill/chip classes and flat button/muted-label styling, removed legacy history/profit classes.
UI Layout Construction
src/ui.zig (lines 79–187)
Rebuilt UI as left control rail + main play area with top bar (sound toggle, balance, history strip) and bottom bar (undo/clear); wired render areas to drawing functions.
UI Logic and Sound Integration
src/ui.zig (lines 238–452)
Added sound-triggered callbacks for amount scaling, undo, bets, spin, and wins; simplified history storage to numeric entries; refactored refreshUi to rebuild history chip strip and queue redraws.

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I hopped to code a tiny chime,
Pre-baked beams of PCM in time,
Control rails hum, the chips all sing,
A spin, a blip, a winner's ring,
Hop—chip—spin—win! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the three main changes: displaying numbers on the wheel, streamlining the UI, and adding sound effects.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/wheel-numbers-and-sfx

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/render.zig (1)

132-146: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Route table labels through enum label() methods instead of hardcoded literals.

drawTable still embeds UI text directly ("PAIR", "ROUGE", "NOIR", "IMPAIR", "COL 1", etc.). Please move these strings behind label() methods on the relevant game enums and call those methods here to keep localization and terminology centralized.

As per coding guidelines: "**/*.{zig,css}: UI strings must be in French ...; provide these strings via label() methods on game enums".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/render.zig` around lines 132 - 146, The drawZone calls embed UI strings
directly; add label() methods on the relevant enums (dozen, range, parity,
color, column) that return the French label strings, then replace the literal
arguments in drawZone with calls to those enum label() methods (e.g., .{ .parity
= .even }.parity.label(), .{ .color = .red }.color.label(), .{ .column = .first
}.column.label(), .{ .dozen = .first }.dozen.label(), .{ .range = .low
}.range.label()) so all UI text is centralized behind enum.label().

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app.zig`:
- Line 81: The call to self.audio.deinit() can free PCM slices/dynlib while
detached threads spawned by Audio.play are still running; modify the Audio type
to track in-flight workers (atomic counter) and a shutting_down flag, increment
the counter at the start of each detached worker created by Audio.play and
decrement on worker exit, have workers check the shutting_down flag as
appropriate, and change Audio.deinit to set shutting_down=true, wait for the
in-flight counter to reach zero (spin/sleep or use a condition/async wait) and
only then free PCM buffers and close the dynamic library so no live worker can
access freed resources.

In `@src/style.css`:
- Line 57: The CSS currently uses a GTK type selector "spinbutton" which doesn't
match the widget because state.amount_spin has no class; add a CSS class to the
GtkSpinButton in src/ui.zig (e.g., add "amount-spin" or "spin-button" to
state.amount_spin via its style context) and then update src/style.css to target
that class instead of the type selector (e.g., change ".control-rail spinbutton
{" to ".control-rail .amount-spin {"), ensuring the class name matches exactly
between the Zig code and the CSS.

In `@src/ui.zig`:
- Around line 98-105: Replace symbol-only labels with French text by using the
enum label() helpers or explicit French strings when creating the buttons:
instead of gtk_button_new_with_label("½") and gtk_button_new_with_label("2×")
(the half_button/double_button created around halveClicked and doubleClicked),
call the enum's label() or pass French labels like "Réduire de moitié" and
"Multiplier par deux"; do the same for the volume buttons (replace "🔊"/"🔇"
with "Activer le son"/"Désactiver le son" or use the label() accessor). If you
must keep glyphs visually, also set an explicit French accessible name via the
appropriate GTK accessible API so assistive tech sees the French action. Ensure
all changes use the same label() method pattern used elsewhere in the UI code.

---

Outside diff comments:
In `@src/render.zig`:
- Around line 132-146: The drawZone calls embed UI strings directly; add label()
methods on the relevant enums (dozen, range, parity, color, column) that return
the French label strings, then replace the literal arguments in drawZone with
calls to those enum label() methods (e.g., .{ .parity = .even }.parity.label(),
.{ .color = .red }.color.label(), .{ .column = .first }.column.label(), .{
.dozen = .first }.dozen.label(), .{ .range = .low }.range.label()) so all UI
text is centralized behind enum.label().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fbd30ed3-79e4-4de9-9ca1-2026db846aea

📥 Commits

Reviewing files that changed from the base of the PR and between 652afa4 and 3b407bb.

📒 Files selected for processing (7)
  • CLAUDE.md
  • src/app.zig
  • src/audio.zig
  • src/gtk.zig
  • src/render.zig
  • src/style.css
  • src/ui.zig

Comment thread src/app.zig
Comment thread src/style.css
Comment thread src/ui.zig
Detached play() threads read the PCM buffers and the dlopen'd lib; deinit
could free them mid-playback (use-after-free at shutdown). Track live
workers with an atomic counter (incremented before spawn, decremented on
worker exit) and have deinit yield until it reaches zero before freeing.
Comment thread src/audio.zig Fixed
Opengrep zig-swallowed-error flagged the 'catch {}' on std.Thread.yield().
Replace the fallible yield with a non-fallible 1ms nanosleep syscall: no
error to swallow, lower CPU than a busy spin, same shutdown-wait behaviour.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/audio.zig`:
- Around line 95-96: Replace the Linux-specific nanosleep loop with the
cross-platform std.time.sleep: stop constructing the local `poll` timespec and
calling `std.os.linux.nanosleep`; instead, when waiting for
`self.in_flight.load(.acquire) != 0` call `std.time.sleep` with the desired
millisecond duration (e.g., 1ms) to simplify and make the wait portable while
preserving the same backoff behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0fbed31c-57a9-4877-b9a1-965b2c6f4cf1

📥 Commits

Reviewing files that changed from the base of the PR and between 7d8dadb and 92827a1.

📒 Files selected for processing (1)
  • src/audio.zig

Comment thread src/audio.zig
@InstaZDLL InstaZDLL merged commit fd8d3eb into main Jun 6, 2026
3 checks passed
@InstaZDLL InstaZDLL deleted the feat/wheel-numbers-and-sfx branch June 6, 2026 20:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants