rubysketch 0.7.18 → 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 +4 -4
- data/.github/workflows/release-gem.yml +5 -16
- data/.github/workflows/utils.rb +88 -17
- data/ChangeLog.md +16 -0
- data/README.md +186 -5
- data/RubySketch.podspec +3 -3
- data/VERSION +1 -1
- data/examples/mml.rb +10 -0
- data/lib/rubysketch/all.rb +1 -2
- data/lib/rubysketch/context.rb +1 -0
- data/lib/rubysketch/extension.rb +4 -2
- data/lib/rubysketch/mml.rb +20 -2
- data/rubysketch.gemspec +7 -7
- data/src/RubySketch.mm +6 -6
- data/test/test_mml.rb +1 -1
- metadata +15 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c2d5ce7e554264c501763b490d4ecec02cc7be17509bf44c4821c5b0d4083788
|
|
4
|
+
data.tar.gz: 8c1d4352f30dd6e5b7455f4d67892952f43594e02f35fc7a5a3e3832ecc77aa4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9ecd190e2f06b9321e76cb74c2d8ffdbe42142430095f80837df1731fbf6c0539d3c89855e9b69e09d94d730d69379ebe8a3968916a55a5b4cafbaaa9b885697
|
|
7
|
+
data.tar.gz: 28a1bc912004c769b691804768c203a2cb98454d3f96accd63b536687797eba08432ec4bb2cfe2a27f7411b97a85317e6bfe959e7e389dde13331b2915f38034
|
|
@@ -4,6 +4,9 @@ on:
|
|
|
4
4
|
push:
|
|
5
5
|
tags: ['v[0-9]*']
|
|
6
6
|
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
|
|
7
10
|
jobs:
|
|
8
11
|
release:
|
|
9
12
|
runs-on: macos-latest
|
|
@@ -33,23 +36,9 @@ jobs:
|
|
|
33
36
|
echo path=$(ruby -e 'print Dir.glob("*.gem").first') >> $GITHUB_OUTPUT
|
|
34
37
|
|
|
35
38
|
- name: create github release
|
|
36
|
-
id: release
|
|
37
|
-
uses: actions/create-release@v1
|
|
38
39
|
env:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
tag_name: ${{ github.ref }}
|
|
42
|
-
release_name: ${{ github.ref }}
|
|
43
|
-
|
|
44
|
-
- name: upload to github release
|
|
45
|
-
uses: actions/upload-release-asset@v1
|
|
46
|
-
env:
|
|
47
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
48
|
-
with:
|
|
49
|
-
upload_url: ${{ steps.release.outputs.upload_url }}
|
|
50
|
-
asset_path: ./${{ steps.gem.outputs.path }}
|
|
51
|
-
asset_name: ${{ steps.gem.outputs.path }}
|
|
52
|
-
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 }}
|
|
53
42
|
|
|
54
43
|
- name: upload to rubygems
|
|
55
44
|
env:
|
data/.github/workflows/utils.rb
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
require 'shellwords'
|
|
2
|
+
|
|
3
|
+
ALL_REPO = 'xord/all'
|
|
4
|
+
ALL_DIR = '../all'
|
|
5
|
+
ALL_FETCH_DEPTH = 100
|
|
6
|
+
|
|
1
7
|
RENAMES = {reflex: 'reflexion'}
|
|
2
8
|
|
|
3
9
|
def sh(cmd)
|
|
@@ -5,7 +11,7 @@ def sh(cmd)
|
|
|
5
11
|
system cmd
|
|
6
12
|
end
|
|
7
13
|
|
|
8
|
-
def setup_dependencies(
|
|
14
|
+
def setup_dependencies(only: nil)
|
|
9
15
|
gemspec_path = `git ls-files`.lines(chomp: true).find {|l| l =~ /\.gemspec$/}
|
|
10
16
|
return unless gemspec_path
|
|
11
17
|
|
|
@@ -13,44 +19,109 @@ def setup_dependencies(build: true, only: nil)
|
|
|
13
19
|
name = File.basename gemspec_path, '.gemspec'
|
|
14
20
|
|
|
15
21
|
exts = File.readlines('Rakefile')
|
|
16
|
-
.map {|l| l[%r|^\s*require\W+(\w+)/extension\W+$|, 1]}
|
|
22
|
+
.map {|l| l[%r|^\s*require\W+([\w\-\_]+)/extension\W+$|, 1]}
|
|
17
23
|
.compact
|
|
18
24
|
.reject {|ext| ext == name}
|
|
19
25
|
exts = exts & [only].flatten.map(&:to_s) if only
|
|
26
|
+
return if exts.empty?
|
|
27
|
+
|
|
28
|
+
unless setup_dependencies_via_monorepo(exts)
|
|
29
|
+
setup_dependencies_via_each_repo_by_version(gemspec, exts)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
exts.each {|ext| sh %( cd ../#{ext} && rake ext )}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def setup_dependencies_via_monorepo(exts)
|
|
36
|
+
return false unless checkout_monorepo
|
|
37
|
+
exts.each {|ext| sh %( ln -snf all/#{ext} ../#{ext} )}
|
|
38
|
+
true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def checkout_monorepo()
|
|
42
|
+
uuid = `git log -1 --format=%B`[/^\[\[([0-9a-fA-F-]+)\]\]$/, 1]
|
|
43
|
+
return false unless uuid
|
|
44
|
+
|
|
45
|
+
commit = setup_monorepo uuid
|
|
46
|
+
return false unless commit
|
|
47
|
+
|
|
48
|
+
Dir.chdir(ALL_DIR) {sh %( git checkout -q #{commit} )}
|
|
49
|
+
true
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def setup_monorepo(uuid)
|
|
53
|
+
unless File.directory? ALL_DIR
|
|
54
|
+
url = "https://github.com/#{ALL_REPO}.git"
|
|
55
|
+
sh %( git clone --no-tags --depth #{ALL_FETCH_DEPTH} #{url} #{ALL_DIR} )
|
|
56
|
+
end
|
|
57
|
+
loop do
|
|
58
|
+
commit = find_monorepo_commit uuid
|
|
59
|
+
return commit if commit
|
|
60
|
+
|
|
61
|
+
deepened = Dir.chdir ALL_DIR do
|
|
62
|
+
before = `git rev-list --count HEAD`.to_i
|
|
63
|
+
sh %( git fetch --deepen #{ALL_FETCH_DEPTH} )
|
|
64
|
+
`git rev-list --count HEAD`.to_i > before
|
|
65
|
+
end
|
|
66
|
+
return nil unless deepened
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def find_monorepo_commit(uuid)
|
|
71
|
+
Dir.chdir ALL_DIR do
|
|
72
|
+
out = `git log origin/HEAD -F --grep="[[#{uuid}]]" --format=%H -1`.strip
|
|
73
|
+
out.empty? ? nil : out
|
|
74
|
+
end
|
|
75
|
+
end
|
|
20
76
|
|
|
77
|
+
def setup_dependencies_via_each_repo_by_version(gemspec, exts)
|
|
21
78
|
exts.each do |ext|
|
|
22
79
|
gem = RENAMES[ext.to_sym].then {|s| s || ext}
|
|
23
|
-
ver = gemspec[/add_dependency.*['"]#{gem}['"].*['"]\s
|
|
80
|
+
ver = gemspec[/add_dependency.*['"]#{gem}['"].*['"]\s*~>\s*([\d\.]+)\s*['"]/, 1]
|
|
24
81
|
opts = '-c advice.detachedHead=false --depth 1'
|
|
25
82
|
clone = "git clone #{opts} https://github.com/xord/#{ext}.git ../#{ext}"
|
|
26
83
|
|
|
27
84
|
# 'rake subtree:push' pushes all subrepos, so cloning by new tag
|
|
28
85
|
# often fails before tagging each new tag
|
|
29
86
|
sh %( #{clone} --branch v#{ver} || #{clone} )
|
|
30
|
-
sh %( cd ../#{ext} && rake ext )
|
|
31
87
|
end
|
|
32
88
|
end
|
|
33
89
|
|
|
34
90
|
def tag_versions()
|
|
35
|
-
|
|
36
|
-
|
|
91
|
+
changes = changelogs
|
|
92
|
+
tags = `git tag`.lines chomp: true
|
|
93
|
+
vers = `git log --oneline ./VERSION`
|
|
37
94
|
.lines(chomp: true)
|
|
38
95
|
.map {|line| line.split.first[/^\w+$/]}
|
|
39
|
-
.map {|
|
|
40
|
-
.select {|ver,
|
|
96
|
+
.map {|sha| [`git cat-file -p #{sha}:./VERSION 2>/dev/null`[/[\d\.]+/], sha]}
|
|
97
|
+
.select {|ver, sha| ver && sha}
|
|
41
98
|
.reverse
|
|
42
99
|
.to_h
|
|
43
100
|
|
|
44
|
-
|
|
45
|
-
.split(/^\s*##\s*\[\s*v([\d\.]+)\s*\].*$/)
|
|
46
|
-
.slice(1..-1)
|
|
47
|
-
.each_slice(2)
|
|
48
|
-
.to_h
|
|
49
|
-
.transform_values(&:strip!)
|
|
50
|
-
|
|
51
|
-
vers.to_a.reverse.each do |ver, hash|
|
|
101
|
+
vers.to_a.reverse.each do |ver, sha|
|
|
52
102
|
tag = "v#{ver}"
|
|
53
103
|
break if tags.include?(tag)
|
|
54
|
-
sh %( git tag -a -m \"#{changes[
|
|
104
|
+
sh %( git tag -a -m \"#{changes[tag]&.gsub '"', '\\"'}\" #{tag} #{sha} )
|
|
55
105
|
end
|
|
56
106
|
end
|
|
107
|
+
|
|
108
|
+
def release(*paths)
|
|
109
|
+
tag = ENV['GITHUB_REF']&.sub(%r|^refs/tags/|, '') || raise('GITHUB_REF tag not set')
|
|
110
|
+
notes = (changelogs[tag] || '').shellescape
|
|
111
|
+
paths = paths.flatten.join ' '
|
|
112
|
+
|
|
113
|
+
sh(%( gh release create #{tag} #{paths} --notes #{notes} )) ||
|
|
114
|
+
sh(%( gh release upload #{tag} #{paths} --clobber )) ||
|
|
115
|
+
raise('failed to upload to releases')
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def changelogs()
|
|
119
|
+
File.read('ChangeLog.md')
|
|
120
|
+
.split(/^\s*##\s*\[\s*(v[\d\.]+)\s*\].*$/)
|
|
121
|
+
.slice(1..)
|
|
122
|
+
.each_slice(2)
|
|
123
|
+
.to_h
|
|
124
|
+
.transform_values(&:strip!)
|
|
125
|
+
rescue Errno::ENOENT
|
|
126
|
+
raise 'failed to get changelogs'
|
|
127
|
+
end
|
data/ChangeLog.md
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
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
|
+
|
|
14
|
+
## [v0.7.19] - 2026-05-10
|
|
15
|
+
|
|
16
|
+
- Support WebAssembly
|
|
17
|
+
- Sync podspec and extension init symbols with new module layout
|
|
18
|
+
|
|
19
|
+
|
|
4
20
|
## [v0.7.18] - 2026-04-17
|
|
5
21
|
|
|
6
22
|
- Update dependencies
|
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
|
|
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
|
-
|
|
26
|
+
## 📋 Requirements
|
|
27
27
|
|
|
28
|
-
|
|
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
|
-
|
|
38
|
+
gem 'rubysketch'
|
|
35
39
|
```
|
|
36
40
|
|
|
37
|
-
Then
|
|
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/RubySketch.podspec
CHANGED
|
@@ -93,9 +93,9 @@ Pod::Spec.new do |s|
|
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
s.subspec "Rays" do |spec|
|
|
96
|
-
spec .source_files = "rays/src/*.cpp"
|
|
97
|
-
spec.osx.source_files = "rays/src
|
|
98
|
-
spec.ios.source_files = "rays/src
|
|
96
|
+
spec .source_files = "rays/src/*.cpp", "rays/src/opengl/*.cpp"
|
|
97
|
+
spec.osx.source_files = "rays/src/**/osx/*.{cpp,mm}"
|
|
98
|
+
spec.ios.source_files = "rays/src/**/ios/*.{cpp,mm}"
|
|
99
99
|
spec.ios.frameworks = %w[GLKit MobileCoreServices AVFoundation]# ImageIO
|
|
100
100
|
|
|
101
101
|
spec.subspec "Clipper" do |sub|
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
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
|
data/lib/rubysketch/all.rb
CHANGED
|
@@ -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'
|
data/lib/rubysketch/context.rb
CHANGED
data/lib/rubysketch/extension.rb
CHANGED
data/lib/rubysketch/mml.rb
CHANGED
|
@@ -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 =
|
|
24
|
+
seq, duration = compile__! str
|
|
14
25
|
Sound.new Beeps::Sound.new(seq, streaming ? 0 : duration)
|
|
15
26
|
end
|
|
16
27
|
|
|
17
|
-
|
|
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
|
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
ext = RubySketch::Extension
|
|
13
|
-
name = ext.name
|
|
13
|
+
name = ext.name true
|
|
14
14
|
rdocs = glob.call *%w[README]
|
|
15
15
|
|
|
16
16
|
s.name = name
|
|
@@ -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.
|
|
29
|
-
s.add_dependency 'rucy', '~> 0.3.
|
|
30
|
-
s.add_dependency 'beeps', '~> 0.3.
|
|
31
|
-
s.add_dependency 'rays', '~> 0.3.
|
|
32
|
-
s.add_dependency 'reflexion', '~> 0.
|
|
33
|
-
s.add_dependency 'processing', '~> 1.
|
|
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/src/RubySketch.mm
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
extern "C"
|
|
8
8
|
{
|
|
9
|
-
void
|
|
10
|
-
void
|
|
11
|
-
void
|
|
9
|
+
void Init_beeps_ext ();
|
|
10
|
+
void Init_rays_ext ();
|
|
11
|
+
void Init_reflex_ext ();
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
|
|
@@ -34,9 +34,9 @@ ReflexViewController_show (UIViewController*, ReflexViewController*)
|
|
|
34
34
|
if (done) return;
|
|
35
35
|
done = YES;
|
|
36
36
|
|
|
37
|
-
[CRuby addExtension:@"
|
|
38
|
-
[CRuby addExtension:@"
|
|
39
|
-
[CRuby addExtension:@"
|
|
37
|
+
[CRuby addExtension:@"beeps_ext" init:^{Init_beeps_ext();}];
|
|
38
|
+
[CRuby addExtension:@"rays_ext" init:^{Init_rays_ext();}];
|
|
39
|
+
[CRuby addExtension:@"reflex_ext" init:^{Init_reflex_ext();}];
|
|
40
40
|
|
|
41
41
|
for (NSString *ext in @[
|
|
42
42
|
@"Xot",
|
data/test/test_mml.rb
CHANGED
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.
|
|
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-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|