rubysketch 0.7.19 → 0.8.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: b251469c4df4dae76cf96474b13d46c7e321b3f84702c0b4cb36a2724665f4d9
4
- data.tar.gz: 48ee21b1e75820ebfff7345687fad5c835335fbb9771b571c640b6b8f4ad1fcc
3
+ metadata.gz: c2d5ce7e554264c501763b490d4ecec02cc7be17509bf44c4821c5b0d4083788
4
+ data.tar.gz: 8c1d4352f30dd6e5b7455f4d67892952f43594e02f35fc7a5a3e3832ecc77aa4
5
5
  SHA512:
6
- metadata.gz: 30c4a2f0a8a8463df2bd403d9f7ad42fe1cc37cd1fb81c06b19a5d5d6cf3ebe1b445aa06e62af84097ab68e74c5d9fcafef122db07d0ce3bb47e447fb7815e62
7
- data.tar.gz: 871090464a099b23a9aa1477acd5efe66c5e9739a2864749da2b4a469a58a0474ce8bbf71c7e17921e878ce850d4c027a275a20fcb55fd69a45bf43d88556ea3
6
+ metadata.gz: 9ecd190e2f06b9321e76cb74c2d8ffdbe42142430095f80837df1731fbf6c0539d3c89855e9b69e09d94d730d69379ebe8a3968916a55a5b4cafbaaa9b885697
7
+ data.tar.gz: 28a1bc912004c769b691804768c203a2cb98454d3f96accd63b536687797eba08432ec4bb2cfe2a27f7411b97a85317e6bfe959e7e389dde13331b2915f38034
@@ -36,23 +36,9 @@ jobs:
36
36
  echo path=$(ruby -e 'print Dir.glob("*.gem").first') >> $GITHUB_OUTPUT
37
37
 
38
38
  - name: create github release
39
- id: release
40
- uses: actions/create-release@v1
41
39
  env:
42
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
43
- with:
44
- tag_name: ${{ github.ref }}
45
- release_name: ${{ github.ref }}
46
-
47
- - name: upload to github release
48
- uses: actions/upload-release-asset@v1
49
- env:
50
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51
- with:
52
- upload_url: ${{ steps.release.outputs.upload_url }}
53
- asset_path: ./${{ steps.gem.outputs.path }}
54
- asset_name: ${{ steps.gem.outputs.path }}
55
- asset_content_type: application/zip
40
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
41
+ run: ruby -I.github/workflows -rutils -e 'release(*ARGV)' ./${{ steps.gem.outputs.path }}
56
42
 
57
43
  - name: upload to rubygems
58
44
  env:
data/ChangeLog.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # rubysketch ChangeLog
2
2
 
3
3
 
4
+ ## [v0.8.0] - 2026-05-17
5
+
6
+ - [BREAKING] Wheel Y delta now follows top-left origin convention (from reflex)
7
+
8
+ - Expose MML class at top level and add example
9
+ - Add RDoc to MML class
10
+ - Rewrite README.md
11
+ - CI: Migrate release-gem.yml from actions/create-release to gh release create
12
+
13
+
4
14
  ## [v0.7.19] - 2026-05-10
5
15
 
6
16
  - Support WebAssembly
data/README.md CHANGED
@@ -21,20 +21,24 @@ Thanks for your support! 🙌
21
21
 
22
22
  ## 🚀 About
23
23
 
24
- **RubySketch** is a game engine based on the Processing API, designed for use with Ruby.
24
+ **RubySketch** is a 2D game engine for Ruby. It takes the [Processing for CRuby](https://github.com/xord/processing) sketch loop — `setup` / `draw` / `mousePressed` / ... — and layers a game-oriented vocabulary on top of it: `Sprite`, world-based 2D physics (via Box2D), `Sound` and `MML` (Music Macro Language) for audio, animation timers (`animate`, `setInterval`, `setTimeout`), and a small library of easing curves.
25
25
 
26
- It provides a familiar environment for developers who are accustomed to Processing, enabling them to create games and interactive graphics with ease.
26
+ ## 📋 Requirements
27
27
 
28
- **RubySketch** combines the simplicity of the Processing API with the power of Ruby, making it a versatile tool for creative coding.
28
+ - Ruby **3.0.0** or later
29
+ - All the runtime requirements of [Reflex](https://github.com/xord/reflex) (Rays, Rucy, Xot, plus the platform GUI backend — AppKit / UIKit / Win32 / SDL2 — and OpenGL)
30
+ - The dependent gems are installed automatically: `xot`, `rucy`, `beeps`, `rays`, `reflexion`, `processing`
31
+
32
+ There is no native C/C++ extension in this gem; the heavy lifting is done by the underlying gems' extensions.
29
33
 
30
34
  ## 📦 Installation
31
35
 
32
36
  Add this line to your Gemfile:
33
37
  ```ruby
34
- $ gem 'rubysketch'
38
+ gem 'rubysketch'
35
39
  ```
36
40
 
37
- Then, install gem:
41
+ Then install:
38
42
  ```bash
39
43
  $ bundle install
40
44
  ```
@@ -44,6 +48,183 @@ Or install it directly:
44
48
  $ gem install rubysketch
45
49
  ```
46
50
 
51
+ ## 📚 What's Provided
52
+
53
+ `require 'rubysketch'` and `using RubySketch` make the whole **Processing API** ([camelCase](https://github.com/xord/processing#-whats-provided)) plus the RubySketch additions available as top-level methods in your file. As with Processing, a window opens and the sketch runs automatically on file exit; you do not need an explicit `start` call.
54
+
55
+ `using RubySketch(snake_case: true)` adds snake_case aliases (`create_sprite`, `set_interval`, ...) alongside the camelCase originals.
56
+
57
+ ### On top of Processing, RubySketch adds:
58
+
59
+ #### Sprites — `RubySketch::Sprite`
60
+
61
+ `createSprite` returns a `Sprite` whose position, size, angle, velocity, image, offset, pivot, shape, draw block, and per-sprite mouse events you can drive directly.
62
+
63
+ | Capability | API |
64
+ | ------------------------- | ---------------------------------------------------------------------------------- |
65
+ | Position / size | `pos`, `x`, `y`, `z`, `left`, `top`, `right`, `bottom`, `center`, `size`, `width`, `height` |
66
+ | Motion | `velocity`, `vx`, `vy`, `angle`, `fixAngle`, `pivot` |
67
+ | Appearance | `image`, `offset` (texture offset), draw block |
68
+ | Physics | `dynamic = true`, `static = true`, `restitution`, `density`, `friction`, `shape` |
69
+ | Interaction | `mousePressed`, `mouseReleased`, `mouseMoved`, `mouseDragged`, `mouseClicked` (per-sprite) |
70
+ | Lifecycle | `update { ... }`, `draw { ... }`, `show`, `hide`, `capture = true/false` |
71
+
72
+ Sprites can be sorted by `z` and drawn in bulk via the top-level `sprite(*sprites)` call.
73
+
74
+ #### 2D physics
75
+
76
+ | API | Purpose |
77
+ | -------------------------------- | ---------------------------------------------------- |
78
+ | `gravity(x, y)` / `gravity(vec)` | Set the gravity of the active world |
79
+ | `Sprite#shape =` | Box2D fixture shape (rect, ellipse, polygon) |
80
+
81
+ #### Sound
82
+
83
+ | API | Purpose |
84
+ | -------------------------------- | ---------------------------------------------------- |
85
+ | `loadSound(path)` | Load a sample (WAV / AIFF / ...) into a `RubySketch::Sound` |
86
+ | `Sound#play(gain:)` | Play; returns a handle exposing `stop`, `playing?`, `seconds` |
87
+ | `Sound#stop` | Stop all instances |
88
+
89
+ #### Music Macro Language (MML)
90
+
91
+ A tiny MML compiler (`RubySketch::MML`) that turns a string like `"t120 l4 cdefgab>c"` into a `RubySketch::Sound`.
92
+
93
+ - `MML.compile(str, streaming = false)` — compile and return a `Sound` you can play later.
94
+ - `MML.play(str)` — shortcut for `compile(str).play`.
95
+
96
+ #### Animation and timers
97
+
98
+ | API | Purpose |
99
+ | ------------------------------------- | -------------------------------------------------------------------------------- |
100
+ | `setTimeout(seconds) { ... }` | Run a block once after a delay; returns an id usable with `clearTimer` |
101
+ | `setInterval(seconds, now:) { ... }` | Run a block every N seconds |
102
+ | `clearTimer(id)` | Cancel a timer |
103
+ | `animate(seconds, easing:) { ... }` | Drive a block from 0.0 to 1.0 over time, optionally with an easing curve |
104
+ | `animateValue(seconds, from:, to:, easing:) { ... }` | Same but yields the interpolated value |
105
+
106
+ Easing names: `linear`, `sineIn` / `sineOut` / `sineInOut`, `quadIn` / ... / `cubicIn` / ..., `expoIn` / `expoOut` / `expoInOut`, `circIn` / ..., `backIn` / `backOut` / `backInOut`, `elasticIn` / `elasticOut` / `elasticInOut`, `bounceIn` / `bounceOut` / `bounceInOut`. See `lib/rubysketch/easings.rb`.
107
+
108
+ #### MIDI input (forwarded from Reflex)
109
+
110
+ `notePressed`, `noteReleased`, `controlChange` blocks; `noteNumber`, `noteFrequency`, `noteVelocity`, `controllerIndex`, `controllerValue` accessors during a callback.
111
+
112
+ #### Miscellaneous
113
+
114
+ - `vibrate` (mobile)
115
+ - `Vector`, `Image`, `WheelEvent` — re-exported from Processing for convenience
116
+
117
+ ## 💡 Usage
118
+
119
+ ### Hello, RubySketch
120
+
121
+ ```ruby
122
+ require 'rubysketch'
123
+ using RubySketch
124
+
125
+ draw do
126
+ background 0
127
+ textSize 30
128
+ text 'hello, rubysketch!', 10, 100
129
+ end
130
+ ```
131
+
132
+ ### Sprites and per-sprite input
133
+
134
+ ```ruby
135
+ require 'rubysketch'
136
+ using RubySketch
137
+
138
+ player = createSprite 200, 200, 40, 40
139
+ player.image = loadImage 'player.png'
140
+
141
+ player.update do
142
+ player.x += 2 if keyIsDown(RIGHT)
143
+ player.x -= 2 if keyIsDown(LEFT)
144
+ end
145
+
146
+ player.mouseClicked do
147
+ player.z += 10 # bring forward on click
148
+ end
149
+
150
+ draw do
151
+ background 30
152
+ sprite player
153
+ end
154
+ ```
155
+
156
+ ### 2D physics
157
+
158
+ ```ruby
159
+ require 'rubysketch'
160
+ using RubySketch
161
+
162
+ noStroke
163
+ gravity 0, 1000 # pixels / s^2 downward
164
+
165
+ ground = createSprite 0, height - 10, width, 10 # static by default
166
+ sprites = []
167
+
168
+ draw do
169
+ background 100
170
+ sprite ground, *sprites
171
+ end
172
+
173
+ mousePressed do
174
+ sp = createSprite mouseX + rand, mouseY + rand,
175
+ shape: Circle.new(0, 0, 20)
176
+ sp.dynamic = true
177
+ sp.restitution = 0.5
178
+ sprites << sp
179
+ end
180
+ ```
181
+
182
+ ### Sound and MML
183
+
184
+ ```ruby
185
+ require 'rubysketch'
186
+ using RubySketch
187
+
188
+ bgm = loadSound 'bgm.wav'
189
+
190
+ setup do
191
+ bgm.play(gain: 0.6)
192
+ end
193
+
194
+ # play an MML phrase on every click
195
+ mousePressed do
196
+ RubySketch::MML.play 't140 l8 ccggaag4 ffeeddc4'
197
+ end
198
+ ```
199
+
200
+ ### Animation with easing
201
+
202
+ ```ruby
203
+ require 'rubysketch'
204
+ using RubySketch
205
+
206
+ x = 0
207
+ animateValue(2.0, from: 0, to: width, easing: :elasticOut) {|v| x = v }
208
+
209
+ draw do
210
+ background 0
211
+ fill 1
212
+ ellipse x, height / 2, 40, 40
213
+ end
214
+ ```
215
+
216
+ See [`examples/`](./examples) for `hello.rb`, `sprite.rb`, `physics.rb`, and `toon.rb`.
217
+
218
+ ## 🛠️ Development
219
+
220
+ ```bash
221
+ $ rake test # run the test suite
222
+ $ rake doc # generate YARD docs
223
+ $ rake # default tasks
224
+ ```
225
+
226
+ In the [`xord/all`](https://github.com/xord/all) monorepo you can scope by module, e.g. `rake rubysketch test`.
227
+
47
228
  ## 📜 License
48
229
 
49
230
  **RubySketch** is licensed under the MIT License.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.19
1
+ 0.8.0
data/examples/mml.rb ADDED
@@ -0,0 +1,10 @@
1
+ %w[xot rucy beeps rays reflex processing rubysketch]
2
+ .map {|s| File.expand_path "../../#{s}/lib", __dir__}
3
+ .each {|s| $:.unshift s if !$:.include?(s) && File.directory?(s)}
4
+
5
+ require 'rubysketch'
6
+ using RubySketch
7
+
8
+ mouseClicked do
9
+ MML.play('cdefgab>c')
10
+ end
@@ -18,8 +18,7 @@ require 'rubysketch/helper'
18
18
  require 'rubysketch/sprite'
19
19
  require 'rubysketch/shape'
20
20
  require 'rubysketch/sound'
21
+ require 'rubysketch/mml'
21
22
  require 'rubysketch/easings'
22
23
  require 'rubysketch/graphics_context'
23
24
  require 'rubysketch/context'
24
-
25
- require 'rubysketch/mml'
@@ -9,6 +9,7 @@ module RubySketch
9
9
  SpriteWorld = RubySketch::SpriteWorld
10
10
  Circle = RubySketch::Circle
11
11
  Sound = RubySketch::Sound
12
+ MML = RubySketch::MML
12
13
 
13
14
  # @private
14
15
  def initialize(window)
@@ -1,20 +1,32 @@
1
1
  module RubySketch
2
2
 
3
3
 
4
+ # MML (Music Macro Language) compiler.
5
+ #
4
6
  class MML
5
7
 
8
+ # Oscillator tone types selectable with the `@N` command.
9
+ #
6
10
  TONES = %i[
7
11
  sine triangle square sawtooth pulse12_5 pulse25 noise
8
12
  ].freeze
9
13
 
10
14
  class << self
11
15
 
16
+ # Compile MML string into a sound.
17
+ #
18
+ # @param [String] str MML string
19
+ # @param [Boolean] streaming if true, creates a streaming sound
20
+ #
21
+ # @return [Sound] sound object
22
+ #
12
23
  def compile(str, streaming = false)
13
- seq, duration = compile! str
24
+ seq, duration = compile__! str
14
25
  Sound.new Beeps::Sound.new(seq, streaming ? 0 : duration)
15
26
  end
16
27
 
17
- def compile!(str)
28
+ # @private
29
+ def compile__!(str)
18
30
  scanner = StringScanner.new expandLoops__ str.gsub(/[;%].*(?:\n|$)/, '')
19
31
  seq = Beeps::Sequencer.new
20
32
  note = Note__.new
@@ -87,6 +99,12 @@ module RubySketch
87
99
  return seq, note.time
88
100
  end
89
101
 
102
+ # Compile and play MML string.
103
+ #
104
+ # @param [String] str MML string
105
+ #
106
+ # @return [nil] nil
107
+ #
90
108
  def play(str)
91
109
  compile(str).play
92
110
  end
data/rubysketch.gemspec CHANGED
@@ -25,12 +25,12 @@ Gem::Specification.new do |s|
25
25
  s.platform = Gem::Platform::RUBY
26
26
  s.required_ruby_version = '>= 3.0.0'
27
27
 
28
- s.add_dependency 'xot', '~> 0.3.12'
29
- s.add_dependency 'rucy', '~> 0.3.12'
30
- s.add_dependency 'beeps', '~> 0.3.12'
31
- s.add_dependency 'rays', '~> 0.3.12'
32
- s.add_dependency 'reflexion', '~> 0.3.15'
33
- s.add_dependency 'processing', '~> 1.1.18'
28
+ s.add_dependency 'xot', '~> 0.3.13'
29
+ s.add_dependency 'rucy', '~> 0.3.13'
30
+ s.add_dependency 'beeps', '~> 0.3.13'
31
+ s.add_dependency 'rays', '~> 0.3.13'
32
+ s.add_dependency 'reflexion', '~> 0.4.0'
33
+ s.add_dependency 'processing', '~> 1.2.0'
34
34
 
35
35
  s.files = `git ls-files`.split $/
36
36
  s.test_files = s.files.grep %r{^(test|spec|features)/}
data/test/test_mml.rb CHANGED
@@ -4,7 +4,7 @@ require_relative 'helper'
4
4
  class TestMML < Test::Unit::TestCase
5
5
 
6
6
  def compile(str)
7
- RubySketch::MML.compile! str
7
+ RubySketch::MML.compile__! str
8
8
  end
9
9
 
10
10
  def procs(str, klass = nil)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubysketch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.19
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - xordog
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-05-09 00:00:00.000000000 Z
11
+ date: 2026-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xot
@@ -16,84 +16,84 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.3.12
19
+ version: 0.3.13
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.3.12
26
+ version: 0.3.13
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rucy
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.3.12
33
+ version: 0.3.13
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.3.12
40
+ version: 0.3.13
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: beeps
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.3.12
47
+ version: 0.3.13
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.3.12
54
+ version: 0.3.13
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rays
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.3.12
61
+ version: 0.3.13
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.3.12
68
+ version: 0.3.13
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: reflexion
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 0.3.15
75
+ version: 0.4.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 0.3.15
82
+ version: 0.4.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: processing
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 1.1.18
89
+ version: 1.2.0
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 1.1.18
96
+ version: 1.2.0
97
97
  description: A game engine based on the Processing API.
98
98
  email: xordog@gmail.com
99
99
  executables: []
@@ -117,6 +117,7 @@ files:
117
117
  - RubySketch.podspec
118
118
  - VERSION
119
119
  - examples/hello.rb
120
+ - examples/mml.rb
120
121
  - examples/physics.rb
121
122
  - examples/sprite.rb
122
123
  - examples/toon.rb