loomy 0.0.1
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 +7 -0
- data/.gitignore +2 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +74 -0
- data/README.md +160 -0
- data/Rakefile +10 -0
- data/assets/logo.png +0 -0
- data/bench.rb +76 -0
- data/lib/loomy/ast/canvas.rb +19 -0
- data/lib/loomy/ast/effect.rb +15 -0
- data/lib/loomy/ast/effects/blur.rb +17 -0
- data/lib/loomy/ast/effects/color_adjustment.rb +21 -0
- data/lib/loomy/ast/effects/displacement.rb +17 -0
- data/lib/loomy/ast/effects/grayscale.rb +13 -0
- data/lib/loomy/ast/effects/lighting.rb +21 -0
- data/lib/loomy/ast/group.rb +39 -0
- data/lib/loomy/ast/layer.rb +55 -0
- data/lib/loomy/ast/node.rb +21 -0
- data/lib/loomy/ast/optimizer.rb +115 -0
- data/lib/loomy/ast/visitor.rb +38 -0
- data/lib/loomy/dsl/layer_builder.rb +94 -0
- data/lib/loomy/dsl/pipeline_builder.rb +69 -0
- data/lib/loomy/effects_registration.rb +48 -0
- data/lib/loomy/engine/vips_backend.rb +19 -0
- data/lib/loomy/ops/base.rb +15 -0
- data/lib/loomy/ops/effect_op.rb +25 -0
- data/lib/loomy/ops/load.rb +81 -0
- data/lib/loomy/ops/pipeline.rb +53 -0
- data/lib/loomy/ops/resize.rb +36 -0
- data/lib/loomy/ops/trim.rb +27 -0
- data/lib/loomy/planner/builder.rb +135 -0
- data/lib/loomy/planner/optimizer.rb +89 -0
- data/lib/loomy/version.rb +3 -0
- data/lib/loomy.rb +45 -0
- data/loomy.gemspec +29 -0
- metadata +131 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: e58a5dd9cc41368d235d075797fed3c422b7abb9db8c38372f382c53ebe0a4a5
|
|
4
|
+
data.tar.gz: 8ea209c82cf8442a48408c9a607bdf5f967fe70262b74660bb427a3d8b28e193
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c32b8633ff0d8160e342470f6214b6813cb01618b699be83c6b4acf10039a7e57785f70805973b2751f46776cfd0ec2ef67124f670a49ddd6e54b9721c31ce33
|
|
7
|
+
data.tar.gz: bd6720746b685ca99ed7eefa3d6fab6f6815f7de54d5a3b2d53fed406abfc76b24698c8cae736e56eb4e660b48257712f99897f1d0cfcee98e4047bdd74976dc
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
loomy (0.1.0)
|
|
5
|
+
ruby-vips (~> 2.3)
|
|
6
|
+
zeitwerk (~> 2.7)
|
|
7
|
+
|
|
8
|
+
GEM
|
|
9
|
+
remote: https://rubygems.org/
|
|
10
|
+
specs:
|
|
11
|
+
benchmark-ips (2.14.0)
|
|
12
|
+
ffi (1.17.3)
|
|
13
|
+
ffi (1.17.3-aarch64-linux-gnu)
|
|
14
|
+
ffi (1.17.3-aarch64-linux-musl)
|
|
15
|
+
ffi (1.17.3-arm-linux-gnu)
|
|
16
|
+
ffi (1.17.3-arm-linux-musl)
|
|
17
|
+
ffi (1.17.3-arm64-darwin)
|
|
18
|
+
ffi (1.17.3-x86-linux-gnu)
|
|
19
|
+
ffi (1.17.3-x86-linux-musl)
|
|
20
|
+
ffi (1.17.3-x86_64-darwin)
|
|
21
|
+
ffi (1.17.3-x86_64-linux-gnu)
|
|
22
|
+
ffi (1.17.3-x86_64-linux-musl)
|
|
23
|
+
logger (1.7.0)
|
|
24
|
+
minitest (6.0.1)
|
|
25
|
+
prism (~> 1.5)
|
|
26
|
+
prism (1.9.0)
|
|
27
|
+
rake (13.3.1)
|
|
28
|
+
ruby-vips (2.3.0)
|
|
29
|
+
ffi (~> 1.12)
|
|
30
|
+
logger
|
|
31
|
+
zeitwerk (2.7.4)
|
|
32
|
+
|
|
33
|
+
PLATFORMS
|
|
34
|
+
aarch64-linux-gnu
|
|
35
|
+
aarch64-linux-musl
|
|
36
|
+
arm-linux-gnu
|
|
37
|
+
arm-linux-musl
|
|
38
|
+
arm64-darwin
|
|
39
|
+
ruby
|
|
40
|
+
x86-linux-gnu
|
|
41
|
+
x86-linux-musl
|
|
42
|
+
x86_64-darwin
|
|
43
|
+
x86_64-linux-gnu
|
|
44
|
+
x86_64-linux-musl
|
|
45
|
+
|
|
46
|
+
DEPENDENCIES
|
|
47
|
+
benchmark-ips
|
|
48
|
+
loomy!
|
|
49
|
+
minitest (~> 6.0)
|
|
50
|
+
rake (~> 13.0)
|
|
51
|
+
|
|
52
|
+
CHECKSUMS
|
|
53
|
+
benchmark-ips (2.14.0) sha256=b72bc8a65d525d5906f8cd94270dccf73452ee3257a32b89fbd6684d3e8a9b1d
|
|
54
|
+
ffi (1.17.3) sha256=0e9f39f7bb3934f77ad6feab49662be77e87eedcdeb2a3f5c0234c2938563d4c
|
|
55
|
+
ffi (1.17.3-aarch64-linux-gnu) sha256=28ad573df26560f0aedd8a90c3371279a0b2bd0b4e834b16a2baa10bd7a97068
|
|
56
|
+
ffi (1.17.3-aarch64-linux-musl) sha256=020b33b76775b1abacc3b7d86b287cef3251f66d747092deec592c7f5df764b2
|
|
57
|
+
ffi (1.17.3-arm-linux-gnu) sha256=5bd4cea83b68b5ec0037f99c57d5ce2dd5aa438f35decc5ef68a7d085c785668
|
|
58
|
+
ffi (1.17.3-arm-linux-musl) sha256=0d7626bb96265f9af78afa33e267d71cfef9d9a8eb8f5525344f8da6c7d76053
|
|
59
|
+
ffi (1.17.3-arm64-darwin) sha256=0c690555d4cee17a7f07c04d59df39b2fba74ec440b19da1f685c6579bb0717f
|
|
60
|
+
ffi (1.17.3-x86-linux-gnu) sha256=868a88fcaf5186c3a46b7c7c2b2c34550e1e61a405670ab23f5b6c9971529089
|
|
61
|
+
ffi (1.17.3-x86-linux-musl) sha256=f0286aa6ef40605cf586e61406c446de34397b85dbb08cc99fdaddaef8343945
|
|
62
|
+
ffi (1.17.3-x86_64-darwin) sha256=1f211811eb5cfaa25998322cdd92ab104bfbd26d1c4c08471599c511f2c00bb5
|
|
63
|
+
ffi (1.17.3-x86_64-linux-gnu) sha256=3746b01f677aae7b16dc1acb7cb3cc17b3e35bdae7676a3f568153fb0e2c887f
|
|
64
|
+
ffi (1.17.3-x86_64-linux-musl) sha256=086b221c3a68320b7564066f46fed23449a44f7a1935f1fe5a245bd89d9aea56
|
|
65
|
+
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
|
66
|
+
loomy (0.1.0)
|
|
67
|
+
minitest (6.0.1) sha256=7854c74f48e2e975969062833adc4013f249a4b212f5e7b9d5c040bf838d54bb
|
|
68
|
+
prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
|
|
69
|
+
rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c
|
|
70
|
+
ruby-vips (2.3.0) sha256=e685ec02c13969912debbd98019e50492e12989282da5f37d05f5471442f5374
|
|
71
|
+
zeitwerk (2.7.4) sha256=2bef90f356bdafe9a6c2bd32bcd804f83a4f9b8bc27f3600fff051eb3edcec8b
|
|
72
|
+
|
|
73
|
+
BUNDLED WITH
|
|
74
|
+
4.0.3
|
data/README.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/logo.png" width="240" alt="Loomy Logo">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Loomy 🧶</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>The friendly pixel-weaver for Ruby.</strong>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://rubygems.org/gems/loomy"><img src="https://img.shields.io/gem/v/loomy.svg" alt="Gem Version"></a>
|
|
13
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License"></a>
|
|
14
|
+
<a href="https://github.com/JohnAnon9771/loomy/actions"><img src="https://img.shields.io/badge/tests-passing-success.svg" alt="Tests Status"></a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
**Loomy** is a modern, high-performance image processing engine for Ruby. Think of it as a master weaver for your images: it takes raw layers (the threads) and weaves them into complex compositions using a smart, declarative DSL.
|
|
20
|
+
|
|
21
|
+
Built on top of `libvips`, Loomy doesn't just process images; it optimizes the entire "weaving" process (AST) to ensure your pipelines are as light and fast as silk.
|
|
22
|
+
|
|
23
|
+
## 🚀 Key Features
|
|
24
|
+
|
|
25
|
+
- **High Performance**: Built on `libvips` with a custom Batch Composition engine that flattens operations into a single efficient pipeline.
|
|
26
|
+
- **Hierarchical Groups**: Nest layers and groups to create complex layouts with shared effects.
|
|
27
|
+
- **Intelligent DSL**: Declarative, block-based syntax. Define properties naturally without complex argument lists.
|
|
28
|
+
- **AST Optimizer**: A smart "pre-weaving" layer that prunes invisible layers and pre-calculates geometry before rendering.
|
|
29
|
+
- **Extensible Effects**: Dynamic registry to add your own image processing strategies.
|
|
30
|
+
|
|
31
|
+
## 📦 Installation
|
|
32
|
+
|
|
33
|
+
Add this line to your application's Gemfile:
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
gem 'loomy'
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
And then execute:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bundle install
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 🛠 Usage
|
|
46
|
+
|
|
47
|
+
### 1. Generating Images
|
|
48
|
+
|
|
49
|
+
Loomy offers two ways to get your results: `render` (write to file) and `generate` (get a `Vips::Image` object).
|
|
50
|
+
|
|
51
|
+
#### Render to file
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
Loomy.render("output.png", size: [1200, 630]) do
|
|
55
|
+
layer "background.jpg"
|
|
56
|
+
end
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### Generate in-memory (Web Servers / Testing)
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
# Returns a Vips::Image object
|
|
63
|
+
image = Loomy.generate(size: [1200, 630]) do
|
|
64
|
+
layer "background.jpg"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Get binary buffer for HTTP response or S3
|
|
68
|
+
buffer = image.write_to_buffer(".png")
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 2. Hierarchical Groups
|
|
72
|
+
|
|
73
|
+
Group layers to apply effects or positioning to a set of nodes collectively.
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
Loomy.render("banner.png", size: [800, 400]) do
|
|
77
|
+
group x: 50, y: 50 do
|
|
78
|
+
layer "icon.png", width: 50
|
|
79
|
+
layer "text.png", x: 60
|
|
80
|
+
|
|
81
|
+
# Apply blur to the entire group
|
|
82
|
+
blur radius: 2
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 3. The Smart DSL
|
|
88
|
+
|
|
89
|
+
Forget about complex argument lists. Describe your image layout naturally:
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
require 'loomy'
|
|
93
|
+
|
|
94
|
+
Loomy.render("output.png", size: [1200, 630]) do
|
|
95
|
+
# Background
|
|
96
|
+
layer "background.jpg" do
|
|
97
|
+
fit :cover
|
|
98
|
+
blur radius: 10
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Overlay
|
|
102
|
+
layer "avatar.png" do
|
|
103
|
+
x :center
|
|
104
|
+
y :center
|
|
105
|
+
width "20%"
|
|
106
|
+
trim true # Auto-crop transparent borders
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 4. Reusable Styles
|
|
112
|
+
|
|
113
|
+
Define common looks and apply them anywhere.
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
# Define a style
|
|
117
|
+
Loomy.define_style :hero_layer do
|
|
118
|
+
x 50
|
|
119
|
+
y 100
|
|
120
|
+
blend :overlay
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
Loomy.render("post.png", size: [1000, 1000]) do
|
|
124
|
+
layer "texture.png" do
|
|
125
|
+
use :hero_layer # Apply the style
|
|
126
|
+
width 500 # Override or extend
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 5. Custom Effects & Registry
|
|
132
|
+
|
|
133
|
+
Loomy is extensible. You can register your own `libvips` processors:
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
# Register a custom effect
|
|
137
|
+
Loomy.register_effect(MyCustomEffectClass, ->(img, effect_node) {
|
|
138
|
+
img.my_vips_operation(effect_node.param)
|
|
139
|
+
})
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## ⚡ Performance
|
|
143
|
+
|
|
144
|
+
Loomy is designed for scale. Leveraging `libvips`' streaming architecture and our proprietary AST optimization, Loomy delivers exceptional throughput:
|
|
145
|
+
|
|
146
|
+
| Complexity | Throughput (M1) |
|
|
147
|
+
| :---------------------------- | :-------------- |
|
|
148
|
+
| Simple Composites | ~70 images/sec |
|
|
149
|
+
| Complex (5+ layers + effects) | ~60 images/sec |
|
|
150
|
+
|
|
151
|
+
## 🗺 Roadmap
|
|
152
|
+
|
|
153
|
+
- [ ] Full support for relative geometry (`%`, `vh`, `vw`)
|
|
154
|
+
- [ ] Rounded corners and masking
|
|
155
|
+
- [ ] SVG support as layers
|
|
156
|
+
- [ ] Smart Saliency Masking (Background Removal)
|
|
157
|
+
|
|
158
|
+
## 📄 License
|
|
159
|
+
|
|
160
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/assets/logo.png
ADDED
|
Binary file
|
data/bench.rb
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require "benchmark/ips"
|
|
2
|
+
$LOAD_PATH.unshift File.expand_path("lib", __dir__)
|
|
3
|
+
require "loomy"
|
|
4
|
+
|
|
5
|
+
# Ensure assets are generated
|
|
6
|
+
unless File.exist?("test/assets/base.png")
|
|
7
|
+
Vips::Image.black(1024, 1024, bands: 3).linear([1], [128,128,128]).bandjoin(255).cast(:uchar).write_to_file("test/assets/base.png")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
unless File.exist?("test/assets/overlay.png")
|
|
11
|
+
Vips::Image.black(500, 500, bands: 3).linear([1], [255,0,0]).bandjoin(255).cast(:uchar).write_to_file("test/assets/overlay.png")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Large assets (4200x4800)
|
|
15
|
+
unless File.exist?("test/assets/base_large.png")
|
|
16
|
+
puts "Generating large base asset (4200x4800)..."
|
|
17
|
+
Vips::Image.black(4200, 4800, bands: 3).linear([1], [50,50,50]).bandjoin(255).cast(:uchar).write_to_file("test/assets/base_large.png")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
unless File.exist?("test/assets/overlay_large.png")
|
|
21
|
+
puts "Generating large overlay asset (2000x2000)..."
|
|
22
|
+
Vips::Image.black(2000, 2000, bands: 3).linear([1], [0,255,0]).bandjoin(255).cast(:uchar).write_to_file("test/assets/overlay_large.png")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
unless File.exist?("test/assets/trim_source_large.png")
|
|
26
|
+
puts "Generating large trim asset..."
|
|
27
|
+
# 2000x2000 image with 500x500 content in middle, rest transparent
|
|
28
|
+
content = Vips::Image.black(500, 500, bands: 3).linear([1], [0,0,255]).bandjoin(255)
|
|
29
|
+
padded = content.embed(750, 750, 2000, 2000, extend: :background, background: [0,0,0,0])
|
|
30
|
+
padded.cast(:uchar).write_to_file("test/assets/trim_source_large.png")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Benchmark.ips do |x|
|
|
34
|
+
x.config(time: 5, warmup: 2)
|
|
35
|
+
|
|
36
|
+
x.report("simple_composite") do
|
|
37
|
+
Loomy.render("bench_output_simple.png", size: [1024, 1024]) do
|
|
38
|
+
layer "test/assets/base.png"
|
|
39
|
+
layer "test/assets/overlay.png", x: 200, y: 200
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
x.report("complex_composite") do
|
|
44
|
+
Loomy.render("bench_output_complex.png", size: [1024, 1024]) do
|
|
45
|
+
layer "test/assets/base.png"
|
|
46
|
+
layer "test/assets/overlay.png", x: 50, y: 50, blend: :multiply
|
|
47
|
+
layer "test/assets/overlay.png", x: 400, y: 400, width: 200, height: 200, fit: :cover
|
|
48
|
+
layer "test/assets/overlay.png", x: 600, y: 100, blur: 5
|
|
49
|
+
layer "test/assets/overlay.png", x: 100, y: 600, grayscale: true
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
x.report("large_composite_4k") do
|
|
54
|
+
Loomy.render("bench_output_large.png", size: [4200, 4800]) do
|
|
55
|
+
layer "test/assets/base_large.png"
|
|
56
|
+
layer "test/assets/overlay_large.png", x: 500, y: 500
|
|
57
|
+
layer "test/assets/overlay.png", x: 100, y: 100 # Mixing sizes
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
x.report("trim_composite") do
|
|
62
|
+
Loomy.render("bench_output_trim.png", size: [4200, 4800]) do
|
|
63
|
+
layer "test/assets/base_large.png"
|
|
64
|
+
# This image is 2000x2000 but only has 500x500 content.
|
|
65
|
+
# With trim: true, it should act like 500x500 image.
|
|
66
|
+
layer "test/assets/trim_source_large.png", trim: true, x: 1000, y: 1000
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
x.compare!
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Cleanup outputs (keep inputs for re-runs)
|
|
74
|
+
["bench_output_simple.png", "bench_output_complex.png", "bench_output_large.png", "bench_output_trim.png"].each do |f|
|
|
75
|
+
File.delete(f) if File.exist?(f)
|
|
76
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require_relative 'node'
|
|
2
|
+
|
|
3
|
+
module Loomy
|
|
4
|
+
module AST
|
|
5
|
+
class Canvas < Node
|
|
6
|
+
def width
|
|
7
|
+
properties[:size][0]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def height
|
|
11
|
+
properties[:size][1]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def accept(visitor)
|
|
15
|
+
visitor.visit_canvas(self)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require_relative '../effect'
|
|
2
|
+
|
|
3
|
+
module Loomy
|
|
4
|
+
module AST
|
|
5
|
+
module Effects
|
|
6
|
+
class ColorAdjustment < Effect
|
|
7
|
+
def brightness
|
|
8
|
+
properties[:brightness] || 1.0
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def contrast
|
|
12
|
+
properties[:contrast] || 1.0
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def accept(visitor)
|
|
16
|
+
visitor.visit_color_adjustment_effect(self)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require_relative '../effect'
|
|
2
|
+
|
|
3
|
+
module Loomy
|
|
4
|
+
module AST
|
|
5
|
+
module Effects
|
|
6
|
+
class Displacement < Effect
|
|
7
|
+
def scale
|
|
8
|
+
properties[:scale] || 20
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def accept(visitor)
|
|
12
|
+
visitor.visit_displacement_effect(self)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require_relative '../effect'
|
|
2
|
+
|
|
3
|
+
module Loomy
|
|
4
|
+
module AST
|
|
5
|
+
module Effects
|
|
6
|
+
class Lighting < Effect
|
|
7
|
+
def type
|
|
8
|
+
properties[:type] || :ambient
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def strength
|
|
12
|
+
properties[:strength] || 1.0
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def accept(visitor)
|
|
16
|
+
visitor.visit_lighting_effect(self)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require_relative 'node'
|
|
2
|
+
|
|
3
|
+
module Loomy
|
|
4
|
+
module AST
|
|
5
|
+
class Group < Node
|
|
6
|
+
def x
|
|
7
|
+
properties[:x] || 0
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def y
|
|
11
|
+
properties[:y] || 0
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def width
|
|
15
|
+
properties[:width]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def height
|
|
19
|
+
properties[:height]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def blend_mode
|
|
23
|
+
properties[:blend] || :over
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def effects
|
|
27
|
+
@effects ||= []
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def add_effect(effect)
|
|
31
|
+
effects << effect
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def accept(visitor)
|
|
35
|
+
visitor.visit_group(self)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require_relative 'node'
|
|
2
|
+
|
|
3
|
+
module Loomy
|
|
4
|
+
module AST
|
|
5
|
+
class Layer < Node
|
|
6
|
+
def source
|
|
7
|
+
properties[:source]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def blend_mode
|
|
11
|
+
properties[:blend] || :over
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def x
|
|
15
|
+
properties[:x] || 0
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def y
|
|
19
|
+
properties[:y] || 0
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def width
|
|
23
|
+
properties[:width]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def height
|
|
27
|
+
properties[:height]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def fit
|
|
31
|
+
properties[:fit]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def gravity
|
|
35
|
+
properties[:gravity] || :centre
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def trim
|
|
39
|
+
properties[:trim]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def effects
|
|
43
|
+
@effects ||= []
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def add_effect(effect)
|
|
47
|
+
effects << effect
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def accept(visitor)
|
|
51
|
+
visitor.visit_layer(self)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Loomy
|
|
2
|
+
module AST
|
|
3
|
+
class Node
|
|
4
|
+
attr_reader :children, :properties
|
|
5
|
+
|
|
6
|
+
def initialize(properties = {})
|
|
7
|
+
@properties = properties
|
|
8
|
+
@children = []
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def add_child(node)
|
|
12
|
+
@children << node
|
|
13
|
+
node
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def accept(visitor)
|
|
17
|
+
visitor.visit_node(self)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|