animate_it 0.3.2 → 0.4.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/CHANGELOG.md +35 -1
- data/README.md +131 -19
- data/app/controllers/animate_it/frames_controller.rb +7 -0
- data/app/controllers/animate_it/public_players_controller.rb +69 -0
- data/app/controllers/animate_it/renders_controller.rb +3 -17
- data/app/controllers/animate_it/studio_controller.rb +1 -0
- data/app/jobs/animate_it/render_job.rb +2 -0
- data/app/views/animate_it/frames/filmstrip.html.haml +37 -6
- data/app/views/animate_it/frames/player.html.haml +81 -0
- data/app/views/animate_it/studio/_preview_pane.html.haml +1 -1
- data/app/views/animate_it/studio/_props_pane.html.haml +3 -2
- data/app/views/animate_it/studio/_studio_script.html.haml +71 -48
- data/app/views/animate_it/studio/show.html.haml +10 -3
- data/config/routes.rb +5 -0
- data/lib/animate_it/asset_manifest.rb +92 -0
- data/lib/animate_it/asset_renderer.rb +39 -7
- data/lib/animate_it/composition.rb +100 -9
- data/lib/animate_it/embed_helper.rb +22 -0
- data/lib/animate_it/engine.rb +4 -0
- data/lib/animate_it/runtime/runtime.js +385 -0
- data/lib/animate_it/runtime.rb +11 -0
- data/lib/animate_it/scene.rb +57 -3
- data/lib/animate_it/text_effects.rb +104 -0
- data/lib/animate_it/track_document_schema.rb +71 -0
- data/lib/animate_it/tracks/document.rb +100 -0
- data/lib/animate_it/tracks/layer.rb +13 -0
- data/lib/animate_it/tracks/recorder.rb +149 -0
- data/lib/animate_it/verification.rb +187 -0
- data/lib/animate_it/version.rb +1 -1
- data/lib/animate_it/video_renderer.rb +89 -26
- data/lib/animate_it/view_helpers.rb +11 -1
- data/lib/animate_it.rb +9 -0
- data/lib/tasks/animate_it_tasks.rake +133 -0
- metadata +13 -1
data/lib/animate_it.rb
CHANGED
|
@@ -14,12 +14,21 @@ require_relative "animate_it/registry"
|
|
|
14
14
|
require_relative "animate_it/render_store"
|
|
15
15
|
require_relative "animate_it/beats"
|
|
16
16
|
require_relative "animate_it/animation"
|
|
17
|
+
require_relative "animate_it/text_effects"
|
|
17
18
|
require_relative "animate_it/scene"
|
|
18
19
|
require_relative "animate_it/configuration"
|
|
19
20
|
require_relative "animate_it/composition"
|
|
21
|
+
require_relative "animate_it/tracks/layer"
|
|
22
|
+
require_relative "animate_it/tracks/document"
|
|
23
|
+
require_relative "animate_it/tracks/recorder"
|
|
24
|
+
require_relative "animate_it/track_document_schema"
|
|
25
|
+
require_relative "animate_it/runtime"
|
|
26
|
+
require_relative "animate_it/embed_helper"
|
|
20
27
|
require_relative "animate_it/output"
|
|
21
28
|
require_relative "animate_it/video_renderer"
|
|
29
|
+
require_relative "animate_it/verification"
|
|
22
30
|
require_relative "animate_it/asset_renderer"
|
|
31
|
+
require_relative "animate_it/asset_manifest"
|
|
23
32
|
# Controllers (app/controllers/animate_it/*) and AnimateIt::RenderJob
|
|
24
33
|
# (app/jobs/animate_it/render_job.rb) autoload via Rails — the engine's
|
|
25
34
|
# `isolate_namespace AnimateIt` wires `app/` paths into the autoloader.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
1
3
|
def animate_it_render_host
|
|
2
4
|
# Prefer ANIMATE_IT_HOST; fall back to the legacy RAILS_MOTION_HOST, then
|
|
3
5
|
# RAILS_HOST, then localhost.
|
|
@@ -8,6 +10,12 @@ def animate_it_render_host
|
|
|
8
10
|
end
|
|
9
11
|
|
|
10
12
|
namespace :animate_it do
|
|
13
|
+
desc "Validate source assets and provenance required by AnimateIt compositions"
|
|
14
|
+
task preflight: :environment do
|
|
15
|
+
result = AnimateIt::AssetManifest.new.validate!
|
|
16
|
+
puts "AnimateIt asset preflight passed (#{result.checked} assets)."
|
|
17
|
+
end
|
|
18
|
+
|
|
11
19
|
desc <<~DESC
|
|
12
20
|
Render a single composition's declared outputs to their asset paths.
|
|
13
21
|
|
|
@@ -52,6 +60,61 @@ namespace :animate_it do
|
|
|
52
60
|
end
|
|
53
61
|
end
|
|
54
62
|
|
|
63
|
+
desc <<~DESC
|
|
64
|
+
Pixel-diff a composition's client-driven /player page against the legacy
|
|
65
|
+
/filmstrip. Samples every <step>-th frame (default 10; use 1 for the full
|
|
66
|
+
gate) plus structural layer boundaries and adjacent frames.
|
|
67
|
+
|
|
68
|
+
Requires a running Rails server.
|
|
69
|
+
|
|
70
|
+
Usage:
|
|
71
|
+
bin/rails 'animate_it:verify[<composition-id>]'
|
|
72
|
+
bin/rails 'animate_it:verify[<composition-id>,1]'
|
|
73
|
+
ANIMATE_IT_PROPS_JSON='{"title":"Variant"}' bin/rails 'animate_it:verify[<composition-id>,1]'
|
|
74
|
+
ANIMATE_IT_PROPS_MATRIX_JSON='[{}, {"title":"Variant"}]' bin/rails 'animate_it:verify[<composition-id>,1]'
|
|
75
|
+
|
|
76
|
+
Set ANIMATE_IT_READY_TIMEOUT_MS to override the 30000ms readiness timeout.
|
|
77
|
+
DESC
|
|
78
|
+
task :verify, %i[id step] => :environment do |_task, args|
|
|
79
|
+
raise "Usage: bin/rails 'animate_it:verify[<composition-id>,(<step>)?]'" if args[:id].blank?
|
|
80
|
+
|
|
81
|
+
AnimateIt.load_compositions!
|
|
82
|
+
composition = AnimateIt.registry.fetch(args[:id])
|
|
83
|
+
verify_composition!(
|
|
84
|
+
composition,
|
|
85
|
+
host: animate_it_render_host,
|
|
86
|
+
step: (args[:step] || 10).to_i,
|
|
87
|
+
props_variants: verification_props_variants(composition)
|
|
88
|
+
)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
desc <<~DESC
|
|
92
|
+
Every-frame verification gate for every client-driven composition and each
|
|
93
|
+
composition's declared `verification_props` variant.
|
|
94
|
+
|
|
95
|
+
Requires a running Rails server.
|
|
96
|
+
|
|
97
|
+
Usage:
|
|
98
|
+
bin/rails animate_it:verify_all
|
|
99
|
+
ANIMATE_IT_PROPS_MATRIX_JSON='[{}, {"title":"Variant"}]' bin/rails animate_it:verify_all
|
|
100
|
+
DESC
|
|
101
|
+
task verify_all: :environment do
|
|
102
|
+
AnimateIt.load_compositions!
|
|
103
|
+
compositions = AnimateIt.compositions.select(&:client_driven?)
|
|
104
|
+
raise "No client-driven AnimateIt compositions are registered" if compositions.empty?
|
|
105
|
+
|
|
106
|
+
compositions.each do |composition|
|
|
107
|
+
verify_composition!(
|
|
108
|
+
composition,
|
|
109
|
+
host: animate_it_render_host,
|
|
110
|
+
step: 1,
|
|
111
|
+
props_variants: verification_props_variants(composition)
|
|
112
|
+
)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
puts "Verified #{compositions.size} client-driven compositions at every frame."
|
|
116
|
+
end
|
|
117
|
+
|
|
55
118
|
# Parse `30..120` / `30-120` / `30` (single frame) into a Range. Returns
|
|
56
119
|
# nil for blank input, meaning "use the whole composition".
|
|
57
120
|
def parse_frame_range(raw, composition)
|
|
@@ -80,4 +143,74 @@ namespace :animate_it do
|
|
|
80
143
|
$stdout.flush
|
|
81
144
|
end
|
|
82
145
|
end
|
|
146
|
+
|
|
147
|
+
def verification_props_variants(composition)
|
|
148
|
+
matrix_json = ENV.fetch("ANIMATE_IT_PROPS_MATRIX_JSON", nil)
|
|
149
|
+
single_json = ENV.fetch("ANIMATE_IT_PROPS_JSON", nil)
|
|
150
|
+
return parse_props_matrix(matrix_json) if matrix_json.present?
|
|
151
|
+
return [parse_props(single_json, "ANIMATE_IT_PROPS_JSON")] if single_json.present?
|
|
152
|
+
|
|
153
|
+
composition.verification_props
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def parse_props_matrix(raw)
|
|
157
|
+
variants = JSON.parse(raw)
|
|
158
|
+
valid_matrix = variants.is_a?(Array) && variants.present? && variants.all?(Hash)
|
|
159
|
+
raise "ANIMATE_IT_PROPS_MATRIX_JSON must contain a non-empty JSON array of objects" unless valid_matrix
|
|
160
|
+
|
|
161
|
+
variants.map(&:deep_symbolize_keys)
|
|
162
|
+
rescue JSON::ParserError => e
|
|
163
|
+
raise "ANIMATE_IT_PROPS_MATRIX_JSON must contain a JSON array of objects: #{e.message}"
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def parse_props(raw, name)
|
|
167
|
+
props = JSON.parse(raw)
|
|
168
|
+
raise "#{name} must contain a JSON object" unless props.is_a?(Hash)
|
|
169
|
+
|
|
170
|
+
props.deep_symbolize_keys
|
|
171
|
+
rescue JSON::ParserError => e
|
|
172
|
+
raise "#{name} must contain a JSON object: #{e.message}"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def verify_composition!(composition, host:, step:, props_variants:)
|
|
176
|
+
props_variants.each_with_index do |props, variant_index|
|
|
177
|
+
output_dir = Rails.root.join("tmp/animate_it/verify/#{composition.id}/variant-#{variant_index + 1}")
|
|
178
|
+
verification = AnimateIt::Verification.new(
|
|
179
|
+
composition:,
|
|
180
|
+
host:,
|
|
181
|
+
step:,
|
|
182
|
+
props:,
|
|
183
|
+
output_dir:,
|
|
184
|
+
ready_timeout: ENV.fetch("ANIMATE_IT_READY_TIMEOUT_MS", 30_000).to_i
|
|
185
|
+
)
|
|
186
|
+
puts "Verifying #{composition.id} variant #{variant_index + 1}/#{props_variants.size}: " \
|
|
187
|
+
"#{verification.sample_frames.size} frames (step #{verification.step}, " \
|
|
188
|
+
"RGB threshold #{verification.threshold}dB, alpha threshold #{verification.alpha_threshold}dB)"
|
|
189
|
+
|
|
190
|
+
results = verification.call
|
|
191
|
+
failures = results.reject(&:passed)
|
|
192
|
+
print_verification_results(results)
|
|
193
|
+
if failures.any?
|
|
194
|
+
raise "#{failures.size}/#{results.size} frames below threshold. " \
|
|
195
|
+
"Screenshots in #{verification.output_dir}"
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
puts "All #{results.size} frames match " \
|
|
199
|
+
"(RGB >= #{verification.threshold}dB, alpha >= #{verification.alpha_threshold}dB)."
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def print_verification_results(results)
|
|
204
|
+
results.each do |result|
|
|
205
|
+
rgb = result.rgb_psnr.infinite? ? "identical" : format("%.2fdB", result.rgb_psnr)
|
|
206
|
+
alpha = result.alpha_psnr.infinite? ? "identical" : format("%.2fdB", result.alpha_psnr)
|
|
207
|
+
puts format(
|
|
208
|
+
" frame %<frame>5d RGB %<rgb>s alpha %<alpha>s%<flag>s",
|
|
209
|
+
frame: result.frame,
|
|
210
|
+
rgb:,
|
|
211
|
+
alpha:,
|
|
212
|
+
flag: result.passed ? "" : " ← FAIL"
|
|
213
|
+
)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
83
216
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: animate_it
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- growth-constant
|
|
@@ -60,12 +60,14 @@ files:
|
|
|
60
60
|
- app/controllers/animate_it/audio_controller.rb
|
|
61
61
|
- app/controllers/animate_it/frames_controller.rb
|
|
62
62
|
- app/controllers/animate_it/props_controller.rb
|
|
63
|
+
- app/controllers/animate_it/public_players_controller.rb
|
|
63
64
|
- app/controllers/animate_it/renders_controller.rb
|
|
64
65
|
- app/controllers/animate_it/studio_controller.rb
|
|
65
66
|
- app/jobs/animate_it/application_job.rb
|
|
66
67
|
- app/jobs/animate_it/render_job.rb
|
|
67
68
|
- app/views/animate_it/frames/filmstrip.html.haml
|
|
68
69
|
- app/views/animate_it/frames/fragment.html.haml
|
|
70
|
+
- app/views/animate_it/frames/player.html.haml
|
|
69
71
|
- app/views/animate_it/frames/show.html.haml
|
|
70
72
|
- app/views/animate_it/props/_form.html.haml
|
|
71
73
|
- app/views/animate_it/props/update.html.haml
|
|
@@ -85,11 +87,13 @@ files:
|
|
|
85
87
|
- lib/animate_it.rb
|
|
86
88
|
- lib/animate_it/animation.rb
|
|
87
89
|
- lib/animate_it/animation_helpers.rb
|
|
90
|
+
- lib/animate_it/asset_manifest.rb
|
|
88
91
|
- lib/animate_it/asset_renderer.rb
|
|
89
92
|
- lib/animate_it/beats.rb
|
|
90
93
|
- lib/animate_it/composition.rb
|
|
91
94
|
- lib/animate_it/configuration.rb
|
|
92
95
|
- lib/animate_it/easing.rb
|
|
96
|
+
- lib/animate_it/embed_helper.rb
|
|
93
97
|
- lib/animate_it/engine.rb
|
|
94
98
|
- lib/animate_it/errors.rb
|
|
95
99
|
- lib/animate_it/frame_context.rb
|
|
@@ -98,11 +102,19 @@ files:
|
|
|
98
102
|
- lib/animate_it/props_schema.rb
|
|
99
103
|
- lib/animate_it/registry.rb
|
|
100
104
|
- lib/animate_it/render_store.rb
|
|
105
|
+
- lib/animate_it/runtime.rb
|
|
106
|
+
- lib/animate_it/runtime/runtime.js
|
|
101
107
|
- lib/animate_it/scene.rb
|
|
102
108
|
- lib/animate_it/style.rb
|
|
109
|
+
- lib/animate_it/text_effects.rb
|
|
103
110
|
- lib/animate_it/timeline.rb
|
|
104
111
|
- lib/animate_it/timing.rb
|
|
112
|
+
- lib/animate_it/track_document_schema.rb
|
|
113
|
+
- lib/animate_it/tracks/document.rb
|
|
114
|
+
- lib/animate_it/tracks/layer.rb
|
|
115
|
+
- lib/animate_it/tracks/recorder.rb
|
|
105
116
|
- lib/animate_it/units.rb
|
|
117
|
+
- lib/animate_it/verification.rb
|
|
106
118
|
- lib/animate_it/version.rb
|
|
107
119
|
- lib/animate_it/video_renderer.rb
|
|
108
120
|
- lib/animate_it/view_helpers.rb
|