rich_engine 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37c9f68ab1fdc4951d70810a301758262203c270d81855259c04920194f44e21
4
- data.tar.gz: f2848e8b2cfb1e99437aa99d4622f16e077b68e8866815192731b2f74160d9d2
3
+ metadata.gz: 78e2cb0aa9a46a3a771739f12c82d372744b2425cf423bcf647807056bb26758
4
+ data.tar.gz: 1f0a91b2f173c9115e6573c76ea706e4bd644d56232e21da7360dab33d3b1e6f
5
5
  SHA512:
6
- metadata.gz: '01282dcff859e81e0cd7ac4ad4b266e450d317826e521f63603481d2c51a62ea4227582297db1abe26e1bfd05c8172e11f94706656a05e25552eb26009b4dad0'
7
- data.tar.gz: 929a78668eff88fce37a81e2df06d310dd305b54000175423e0f032195c074cc1d64372cefde49ab3a8e79090d5c41ab6e84408d8c446ba789ce4ad213e7b70f
6
+ metadata.gz: 4343141533689b538f7ea5fc87a2a281fc09915d260b6ef5f193b67dfa2d6f9f459ec4f22123a17d857212be9191e49fd926cc8a7248d3aa4fdb0f4e97638385
7
+ data.tar.gz: d198b768cd889f969ae6f27f47da48b3b2ec1990ef340e546e70dce6b2ecf98654e90b43567491799a21a8dfb7b184622656fa9ee2d109c867fdc276099a5ad5
@@ -11,18 +11,19 @@ jobs:
11
11
  runs-on: ubuntu-latest
12
12
  strategy:
13
13
  matrix:
14
- ruby: [2.6, 2.7, '3.0']
14
+ ruby: ['3.2', '3.3', '3.4']
15
15
 
16
16
  steps:
17
- - uses: actions/checkout@v2
18
- - name: Set up Ruby ${{ matrix.ruby }}
17
+ - uses: actions/checkout@v4
18
+ with:
19
+ persist-credentials: false
20
+ - name: Set up Ruby
19
21
  uses: ruby/setup-ruby@v1
20
22
  with:
21
23
  ruby-version: ${{ matrix.ruby }}
22
- - name: Build and test with Rake
23
- run: |
24
- gem install bundler
25
- bundle install --jobs 4 --retry 3
26
- bundle exec rake
24
+ bundler-cache: true
25
+ - name: Run tests
26
+ run: bundle exec rake
27
27
  - name: Linter
28
28
  run: bundle exec standardrb
29
+ continue-on-error: true
data/.gitignore CHANGED
@@ -1 +1,7 @@
1
- coverage/
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /tmp/
data/.yardopts ADDED
@@ -0,0 +1,6 @@
1
+ --markup markdown
2
+ --no-private
3
+ lib/**/*.rb
4
+ -
5
+ README.md
6
+ LICENSE.txt
data/Gemfile CHANGED
@@ -7,6 +7,7 @@ gemspec
7
7
  group :development do
8
8
  gem "standardrb"
9
9
  gem "solargraph"
10
+ gem "yard", require: false
10
11
  end
11
12
 
12
13
  group :test do
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rich_engine (0.1.0)
4
+ rich_engine (0.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -22,7 +22,8 @@ GEM
22
22
  ffi (1.17.2-x86_64-darwin)
23
23
  ffi (1.17.2-x86_64-linux-gnu)
24
24
  ffi (1.17.2-x86_64-linux-musl)
25
- formatador (1.1.0)
25
+ formatador (1.2.1)
26
+ reline
26
27
  guard (2.19.1)
27
28
  formatador (>= 0.2.4)
28
29
  listen (>= 2.7, < 4.0)
@@ -38,8 +39,9 @@ GEM
38
39
  guard-minitest (2.4.6)
39
40
  guard-compat (~> 1.2)
40
41
  minitest (>= 3.0)
42
+ io-console (0.8.1)
41
43
  jaro_winkler (1.6.1)
42
- json (2.12.2)
44
+ json (2.15.1)
43
45
  kramdown (2.5.1)
44
46
  rexml (>= 3.3.9)
45
47
  kramdown-parser-gfm (1.1.0)
@@ -50,9 +52,9 @@ GEM
50
52
  rb-fsevent (~> 0.10, >= 0.10.3)
51
53
  rb-inotify (~> 0.9, >= 0.9.10)
52
54
  logger (1.7.0)
53
- lumberjack (1.2.10)
55
+ lumberjack (1.4.2)
54
56
  method_source (1.1.0)
55
- minitest (5.25.5)
57
+ minitest (5.26.0)
56
58
  minitest-focus (1.4.0)
57
59
  minitest (>= 4, < 6)
58
60
  minitest-reporters (1.7.1)
@@ -61,32 +63,32 @@ GEM
61
63
  minitest (>= 5.0)
62
64
  ruby-progressbar
63
65
  nenv (0.3.0)
64
- nokogiri (1.18.8-aarch64-linux-gnu)
66
+ nokogiri (1.18.10-aarch64-linux-gnu)
65
67
  racc (~> 1.4)
66
- nokogiri (1.18.8-aarch64-linux-musl)
68
+ nokogiri (1.18.10-aarch64-linux-musl)
67
69
  racc (~> 1.4)
68
- nokogiri (1.18.8-arm-linux-gnu)
70
+ nokogiri (1.18.10-arm-linux-gnu)
69
71
  racc (~> 1.4)
70
- nokogiri (1.18.8-arm-linux-musl)
72
+ nokogiri (1.18.10-arm-linux-musl)
71
73
  racc (~> 1.4)
72
- nokogiri (1.18.8-arm64-darwin)
74
+ nokogiri (1.18.10-arm64-darwin)
73
75
  racc (~> 1.4)
74
- nokogiri (1.18.8-x86_64-darwin)
76
+ nokogiri (1.18.10-x86_64-darwin)
75
77
  racc (~> 1.4)
76
- nokogiri (1.18.8-x86_64-linux-gnu)
78
+ nokogiri (1.18.10-x86_64-linux-gnu)
77
79
  racc (~> 1.4)
78
- nokogiri (1.18.8-x86_64-linux-musl)
80
+ nokogiri (1.18.10-x86_64-linux-musl)
79
81
  racc (~> 1.4)
80
82
  notiffany (0.1.3)
81
83
  nenv (~> 0.1)
82
84
  shellany (~> 0.0)
83
85
  observer (0.1.2)
84
- ostruct (0.6.1)
86
+ ostruct (0.6.3)
85
87
  parallel (1.27.0)
86
- parser (3.3.8.0)
88
+ parser (3.3.9.0)
87
89
  ast (~> 2.4.1)
88
90
  racc
89
- prism (1.4.0)
91
+ prism (1.6.0)
90
92
  pry (0.15.2)
91
93
  coderay (~> 1.1)
92
94
  method_source (~> 1.0)
@@ -96,13 +98,15 @@ GEM
96
98
  rb-fsevent (0.11.2)
97
99
  rb-inotify (0.11.1)
98
100
  ffi (~> 1.0)
99
- rbs (3.9.4)
101
+ rbs (3.9.5)
100
102
  logger
101
- regexp_parser (2.10.0)
103
+ regexp_parser (2.11.3)
104
+ reline (0.6.2)
105
+ io-console (~> 0.5)
102
106
  reverse_markdown (3.0.0)
103
107
  nokogiri
104
- rexml (3.4.1)
105
- rubocop (1.75.8)
108
+ rexml (3.4.4)
109
+ rubocop (1.80.2)
106
110
  json (~> 2.3)
107
111
  language_server-protocol (~> 3.17.0.2)
108
112
  lint_roller (~> 1.1.0)
@@ -110,10 +114,10 @@ GEM
110
114
  parser (>= 3.3.0.2)
111
115
  rainbow (>= 2.2.2, < 4.0)
112
116
  regexp_parser (>= 2.9.3, < 3.0)
113
- rubocop-ast (>= 1.44.0, < 2.0)
117
+ rubocop-ast (>= 1.46.0, < 2.0)
114
118
  ruby-progressbar (~> 1.7)
115
119
  unicode-display_width (>= 2.4.0, < 4.0)
116
- rubocop-ast (1.44.1)
120
+ rubocop-ast (1.47.1)
117
121
  parser (>= 3.3.7.2)
118
122
  prism (~> 1.4)
119
123
  rubocop-performance (1.25.0)
@@ -126,9 +130,9 @@ GEM
126
130
  docile (~> 1.1)
127
131
  simplecov-html (~> 0.11)
128
132
  simplecov_json_formatter (~> 0.1)
129
- simplecov-html (0.13.1)
133
+ simplecov-html (0.13.2)
130
134
  simplecov_json_formatter (0.1.4)
131
- solargraph (0.54.5)
135
+ solargraph (0.57.0)
132
136
  backport (~> 1.2)
133
137
  benchmark (~> 0.4)
134
138
  bundler (~> 2.0)
@@ -140,17 +144,19 @@ GEM
140
144
  observer (~> 0.1)
141
145
  ostruct (~> 0.6)
142
146
  parser (~> 3.0)
143
- rbs (~> 3.3)
147
+ prism (~> 1.4)
148
+ rbs (>= 3.6.1, <= 4.0.0.dev.4)
144
149
  reverse_markdown (~> 3.0)
145
- rubocop (~> 1.38)
150
+ rubocop (~> 1.76)
146
151
  thor (~> 1.0)
147
152
  tilt (~> 2.0)
148
153
  yard (~> 0.9, >= 0.9.24)
154
+ yard-activesupport-concern (~> 0.0)
149
155
  yard-solargraph (~> 0.1)
150
- standard (1.50.0)
156
+ standard (1.51.1)
151
157
  language_server-protocol (~> 3.17.0.2)
152
158
  lint_roller (~> 1.0)
153
- rubocop (~> 1.75.5)
159
+ rubocop (~> 1.80.2)
154
160
  standard-custom (~> 1.0.0)
155
161
  standard-performance (~> 1.8)
156
162
  standard-custom (1.0.2)
@@ -161,12 +167,14 @@ GEM
161
167
  rubocop-performance (~> 1.25.0)
162
168
  standardrb (1.0.1)
163
169
  standard
164
- thor (1.3.2)
165
- tilt (2.6.0)
166
- unicode-display_width (3.1.4)
167
- unicode-emoji (~> 4.0, >= 4.0.4)
168
- unicode-emoji (4.0.4)
170
+ thor (1.4.0)
171
+ tilt (2.6.1)
172
+ unicode-display_width (3.2.0)
173
+ unicode-emoji (~> 4.1)
174
+ unicode-emoji (4.1.0)
169
175
  yard (0.9.37)
176
+ yard-activesupport-concern (0.0.1)
177
+ yard (>= 0.8)
170
178
  yard-solargraph (0.1.0)
171
179
  yard (~> 0.9)
172
180
 
@@ -191,6 +199,7 @@ DEPENDENCIES
191
199
  simplecov
192
200
  solargraph
193
201
  standardrb
202
+ yard
194
203
 
195
204
  BUNDLED WITH
196
205
  2.6.8
data/README.md CHANGED
@@ -1,40 +1,341 @@
1
1
  # RichEngine
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/rich_engine`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ RichEngine is a tiny terminal game engine for Ruby. It gives you a simple game
4
+ loop, a 2D character canvas with colors, non-blocking keyboard input, and a
5
+ handful of helpers (timers, cooldowns, RNG, enums, matrices) so you can ship
6
+ playful ASCII games quickly.
4
7
 
5
- TODO: Delete this and the text above, and describe your gem
8
+ At its core, you subclass `RichEngine::Game`, implement a few lifecycle hooks,
9
+ and draw to a `Canvas` each frame.
6
10
 
7
- ## Installation
11
+ This README is a tour. For method-by-method reference, see the
12
+ [API docs](https://rubydoc.info/gems/rich_engine) (or run
13
+ `bundle exec yard server` locally).
8
14
 
9
- Add this line to your application's Gemfile:
15
+ ## Quick start: build a simple game
16
+
17
+ Below is a minimal, complete example showing how to:
18
+ - create a game by subclassing `RichEngine::Game`
19
+ - quit on a key press
20
+ - draw text and shapes to the screen
21
+ - use canvas slots to keep a bottom HUD separate from the playfield
22
+
23
+ ```ruby
24
+ require "rich_engine"
25
+
26
+ class MyGame < RichEngine::Game
27
+ using RichEngine::StringColors
28
+
29
+ TITLE = "Catch the Star"
30
+ PLAYER_CHAR = "@"
31
+ PLAYER_COLOR = :yellow
32
+ ITEM_COLORS = [:green, :magenta, :cyan]
33
+ ITEM_CHAR = "*"
34
+ HUD_HEIGHT = 3
35
+
36
+ def on_create
37
+ @score = 0
38
+ @player_x = 2
39
+ @player_y = field_height / 2
40
+ @timer = RichEngine::Cooldown.new(5.0)
41
+ @field = @canvas.slot(x: 0, y: 0, width: @width, height: field_height, bg: RichEngine::UI::Textures.solid.white)
42
+ @hud = @canvas.slot(x: 0, y: field_height, width: @width, height: HUD_HEIGHT)
43
+ spawn_item
44
+ end
45
+
46
+ # elapsed_time: seconds since last frame (Float)
47
+ # key: last key pressed (Symbol) or nil
48
+ def on_update(elapsed_time, key)
49
+ quit! if key == :q || key == :esc
50
+
51
+ # Move player with arrow keys
52
+ case key
53
+ when :left then @player_x -= 1
54
+ when :right then @player_x += 1
55
+ when :up then @player_y -= 1
56
+ when :down then @player_y += 1
57
+ end
58
+
59
+ # Keep player inside the game field (above the HUD)
60
+ @player_x = @player_x.clamp(0, @width - 1)
61
+ @player_y = @player_y.clamp(0, field_height - 1)
62
+
63
+ # Game over if time runs out
64
+ @timer.update(elapsed_time)
65
+ if @timer.finished?
66
+ @game_over = true
67
+ quit!
68
+ end
69
+
70
+ # Pick up item
71
+ if @player_x == @item_x && @player_y == @item_y
72
+ @score += 1
73
+ spawn_item
74
+ @timer.reset!
75
+ end
76
+
77
+ # rendering the frame
78
+ @canvas.clear
79
+
80
+ @field.write_string(ITEM_CHAR, x: @item_x, y: @item_y, fg: @item_color)
81
+ @field.write_string(PLAYER_CHAR, x: @player_x, y: @player_y, fg: PLAYER_COLOR)
82
+
83
+ @hud.write_string(TITLE, x: 0, y: 0, fg: :bright_cyan)
84
+ @hud.write_string("Score: #{@score}", x: 0, y: 1, fg: :bright_yellow)
85
+ @hud.write_string("Time: #{format('%.1f', @timer.get)}s", x: 0, y: 2, fg: :bright_green)
86
+ end
87
+
88
+ def on_destroy
89
+ puts(@game_over ? "Game over! Final score: #{@score}" : "Thanks for playing! Score: #{@score}")
90
+ end
91
+
92
+ private
93
+
94
+ def field_height
95
+ @height - HUD_HEIGHT
96
+ end
97
+
98
+ def spawn_item
99
+ @item_x = rand(@width)
100
+ @item_y = rand(field_height)
101
+ @item_color = ITEM_COLORS.sample
102
+ end
103
+ end
104
+
105
+ MyGame.play(width: 50, height: 12)
106
+ ```
107
+
108
+ Notes
109
+ - Hooks:
110
+ - `on_create` runs once at start
111
+ - `on_update(elapsed_time, key)` runs every frame
112
+ - `on_destroy` runs when the game exits.
113
+ - Keys: letters are symbols (e.g., `:q`), plus arrows (`:up`, `:down`, `:left`, `:right`), `:space`, `:enter`, `:esc`, `:pg_up`, `:pg_down`, `:home`, `:end`.
114
+ - Drawing: all drawing happens on `@canvas`, via `write_string`, `draw_rect`,
115
+ `draw_circle`, and `draw_sprite`. Call `@canvas.clear` each frame if you want
116
+ to redraw from scratch.
117
+ - Rendering and frame pacing are handled for you:
118
+ - `Game` flushes the canvas after each frame
119
+ - `Game` auto-sleeps to hit your target FPS (60 by default, but configurable via `target_fps:` on `Game.play`)
120
+
121
+ ## Canvas slots (sub-canvases)
122
+
123
+ Slots are sub-regions of a canvas that translate local coordinates and clip drawing automatically. Great for HUDs and side panels.
124
+
125
+ ```ruby
126
+ canvas = RichEngine::Canvas.new(100, 40)
127
+ hud = canvas.slot(x: 0, y: 35, width: 100, height: 5, bg: " ")
128
+ hud.clear
129
+ hud.write_string("Score: 10", x: 2, y: 1, fg: :bright_yellow)
130
+
131
+ log = canvas.slot(x: 80, y: 0, width: 20, height: 35)
132
+ log.write_string("Hello", x: 1, y: 1) # writes to (81, 1) on the parent canvas
133
+ ```
134
+
135
+ ## Colors
136
+
137
+ Colors are emitted as 256-color escape sequences using only the theme-independent
138
+ regions of the palette, so they look the same in every terminal regardless of the
139
+ user's color scheme. Anywhere a color is accepted (`fg:`, `bg:`, `color:`), you
140
+ can pass:
141
+
142
+ - a named color: `:red`, `:bright_cyan`, etc. (see `RichEngine::StringColors::PALETTE`)
143
+ - a hex string: `"#ff8800"` (also `"ff8800"` and shorthand `"#f80"`)
144
+ - an RGB array: `[255, 136, 0]`
145
+ - a raw 256-color index: `208`
146
+
147
+ Hex and RGB values snap to the nearest color in the fixed 256-color palette.
148
+ Note: `write_string` treats arrays as per-character color cycles, so use hex
149
+ strings for custom colors there.
150
+
151
+ `RichEngine::StringColors.contrast_color(color)` returns `:black` or `:white`,
152
+ whichever reads better on top of the given color (like CSS's `contrast-color()`
153
+ function). Handy for labels on dynamic backgrounds.
154
+
155
+ To color strings directly (outside of canvas methods), add
156
+ `using RichEngine::StringColors` to your class and chain away:
157
+ `"hello".fg(:red).bg("#222222").bold`.
158
+
159
+ ## Animations
160
+
161
+ `RichEngine::Animation` plays a sequence of string frames (sprites) at a fixed
162
+ frames-per-second. Each frame is a multi-line string; spaces are treated as
163
+ transparency by `Canvas#draw_sprite`.
164
+
165
+ ```ruby
166
+ # frozen_string_literal: true
167
+
168
+ require "rich_engine"
169
+
170
+ class AnimationExample < RichEngine::Game
171
+ def on_create
172
+ sprites = ["(•‿•)", "(•‿-)", "(-‿-)", "(-‿•)"]
173
+
174
+ @animation = RichEngine::Animation.new(
175
+ frames: sprites,
176
+ fps: 4,
177
+ loop: true,
178
+ fg: :bright_yellow
179
+ )
180
+ end
181
+
182
+ def on_update(elapsed_time, key)
183
+ quit! if key == :q
184
+
185
+ @animation.update(elapsed_time)
186
+
187
+ @canvas.clear
188
+ @animation.draw(@canvas, x: 0, y: 0)
189
+ @canvas.write_string("q: quit", x: 0, y: @config[:screen_height] - 1, fg: :black)
190
+ end
191
+ end
192
+
193
+ AnimationExample.play(width: 10, height: 3, target_fps: 30)
194
+ ```
195
+
196
+ Playback is controlled with `play!`, `pause!`, `stop!`, `reset!`, and `fps=`.
197
+
198
+ ## Helpers you can use
199
+
200
+ All helpers live under `RichEngine::...` and are independent utilities you can
201
+ use inside your game code.
202
+
203
+ ### Timer
204
+
205
+ Accumulates elapsed time; you drive it by calling `update(dt)` with the
206
+ `elapsed_time` from `on_update`. `Timer.every(seconds:)` returns a small
207
+ scheduler that fires a block at a fixed interval.
208
+
209
+ ```ruby
210
+ tick = RichEngine::Timer.new
211
+
212
+ def on_update(dt, _key)
213
+ tick.update(dt)
214
+ if tick.get > 2
215
+ # do something every ~2 seconds
216
+ tick.reset!
217
+ end
218
+ end
219
+
220
+ # Fixed interval
221
+ spawn = RichEngine::Timer.every(seconds: 0.5)
222
+ def on_update(dt, _key)
223
+ spawn.update(dt)
224
+ spawn.when_ready { spawn_enemy! }
225
+ end
226
+ ```
227
+
228
+ ### Cooldown
229
+
230
+ Track a fixed delay and check if it’s ready.
10
231
 
11
232
  ```ruby
12
- gem 'rich_engine'
233
+ shoot_cd = RichEngine::Cooldown.new(0.25) # seconds
234
+
235
+ def on_update(dt, key)
236
+ shoot_cd.update(dt)
237
+ if key == :space && shoot_cd.ready?
238
+ shoot!
239
+ shoot_cd.reset!
240
+ end
241
+ end
13
242
  ```
14
243
 
15
- And then execute:
244
+ ### Chance (random helpers)
16
245
 
17
- $ bundle install
246
+ ```ruby
247
+ RichEngine::Chance.of(0.2) # 20% chance
248
+ RichEngine::Chance.of(20) # also 20% (percent form)
249
+ RichEngine::Chance.of_one_in(10) # 1 in 10 chance
250
+ ```
18
251
 
19
- Or install it yourself as:
252
+ ### Enum and Enum::Mixin
20
253
 
21
- $ gem install rich_engine
254
+ Create ergonomic, comparable enums with query methods.
22
255
 
23
- ## Usage
256
+ ```ruby
257
+ # Standalone enum
258
+ STATE = RichEngine::Enum.new(:state, {idle: 0, running: 1, paused: 2})
259
+ STATE.idle.value #=> 0
260
+ STATE.running > STATE.idle #=> true
261
+
262
+ # In a class via Mixin
263
+ class Player
264
+ include RichEngine::Enum::Mixin
265
+ enum :state, {idle: 0, running: 1, paused: 2}
24
266
 
25
- TODO: Write usage instructions here
267
+ def initialize
268
+ @state = :idle
269
+ end
26
270
 
27
- ## Development
271
+ def update
272
+ if state.running?
273
+ # ...
274
+ end
275
+ end
276
+ end
277
+ ```
28
278
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
279
+ ### Matrix (2D grid)
30
280
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
281
+ A simple 2D matrix utility with convenience methods.
282
+
283
+ ```ruby
284
+ grid = RichEngine::Matrix.new(width: 10, height: 5, fill_with: 0)
285
+ grid[2, 3] = 1
32
286
 
33
- ## Contributing
287
+ grid.each { |cell| puts cell }
34
288
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rich_engine.
289
+ # Fill regions
290
+ grid.fill(x: 0..2, y: 0..1, with: 9)
36
291
 
292
+ # Zip two matrices into pairs
293
+ other = RichEngine::Matrix.new(width: 10, height: 5, fill_with: :a)
294
+ pairs = grid.zip(other) # => matrix of [left, right]
295
+ ```
296
+
297
+ ### UI::Textures
298
+
299
+ Convenience glyphs for shading and blocky fills: `solid` (█), the shades
300
+ (▓ ▒ ░), half blocks, and friends.
301
+
302
+ ```ruby
303
+ @canvas.draw_rect(x: 10, y: 6, width: 8, height: 2, char: RichEngine::UI::Textures.solid, color: :magenta)
304
+ ```
305
+
306
+ ## Examples
307
+
308
+ See the `examples/` folder for more complete samples:
309
+ - `timer.rb` — using timers and intervals
310
+ - `noise.rb` — colorful random output
311
+ - `background.rb` — background fill and drawing
312
+ - `grains_of_sand.rb` — simple cellular-like simulation
313
+ - `command_line_fps.rb` — a raycasting FPS with a radar and target practice
314
+
315
+ ## Install and run locally (optional)
316
+
317
+ Add to a Gemfile, then bundle:
318
+
319
+ ```ruby
320
+ gem "rich_engine"
321
+ ```
322
+
323
+ ```sh
324
+ bundle install
325
+ ```
326
+
327
+ Or install directly:
328
+
329
+ ```sh
330
+ gem install rich_engine
331
+ ```
332
+
333
+ Then run one of the examples:
334
+
335
+ ```sh
336
+ ruby examples/timer.rb
337
+ ```
37
338
 
38
339
  ## License
39
340
 
40
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
341
+ MIT
@@ -73,7 +73,7 @@ class Cloud
73
73
  def initialize(x: -rand(5..300))
74
74
  @x = x
75
75
  @y = rand(0..4)
76
- @color = [:white, :bright_white].sample
76
+ @color = [:light_gray, :white].sample
77
77
  @sprite = cloud_sprites.sample
78
78
  @speed = rand(1..10)
79
79
  end