fun_ci 1.0.0 → 1.2.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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/README.md +3 -1
  4. data/exe/fun-ci-trigger +6 -6
  5. data/exe/fun-ci-tui +9 -4
  6. data/lib/fun_ci/animations/celebrate.rb +210 -0
  7. data/lib/fun_ci/animations/explosion.rb +138 -0
  8. data/lib/fun_ci/animations/flash.rb +205 -0
  9. data/lib/fun_ci/animations/idle.rb +127 -0
  10. data/lib/fun_ci/animations/leprechauns.rb +240 -0
  11. data/lib/fun_ci/animations/running.rb +129 -0
  12. data/lib/fun_ci/animations/success.rb +281 -0
  13. data/lib/fun_ci/animations/yay.rb +169 -0
  14. data/lib/fun_ci/cli.rb +20 -14
  15. data/lib/fun_ci/persistence/database.rb +52 -0
  16. data/lib/fun_ci/persistence/pipeline_recorder.rb +74 -0
  17. data/lib/fun_ci/persistence/pipeline_run.rb +59 -0
  18. data/lib/fun_ci/persistence/stage_job.rb +46 -0
  19. data/lib/fun_ci/{state_machine.rb → persistence/state_machine.rb} +3 -12
  20. data/lib/fun_ci/pipeline/background_wrapper.rb +27 -0
  21. data/lib/fun_ci/pipeline/pipeline_forker.rb +38 -0
  22. data/lib/fun_ci/pipeline/process_runner.rb +28 -0
  23. data/lib/fun_ci/pipeline/progress_reporter.rb +31 -0
  24. data/lib/fun_ci/pipeline/stage_runner.rb +85 -0
  25. data/lib/fun_ci/pipeline/stale_pipeline_canceller.rb +53 -0
  26. data/lib/fun_ci/pipeline/trigger.rb +153 -0
  27. data/lib/fun_ci/setup/hook_writer.rb +75 -0
  28. data/lib/fun_ci/setup/installer.rb +55 -0
  29. data/lib/fun_ci/setup/maven_linter_detector.rb +26 -0
  30. data/lib/fun_ci/setup/project_config.rb +42 -0
  31. data/lib/fun_ci/setup/project_detector.rb +22 -0
  32. data/lib/fun_ci/setup/setup_checker.rb +30 -0
  33. data/lib/fun_ci/setup/template_writer.rb +53 -0
  34. data/lib/fun_ci/tui/admin_tui.rb +90 -0
  35. data/lib/fun_ci/tui/animation.rb +49 -0
  36. data/lib/fun_ci/tui/animation_compositor.rb +107 -0
  37. data/lib/fun_ci/tui/animation_frames.rb +112 -0
  38. data/lib/fun_ci/tui/animation_library.rb +46 -0
  39. data/lib/fun_ci/tui/animation_renderer.rb +144 -0
  40. data/lib/fun_ci/tui/ansi.rb +34 -0
  41. data/lib/fun_ci/tui/board_data.rb +53 -0
  42. data/lib/fun_ci/tui/board_renderer.rb +105 -0
  43. data/lib/fun_ci/tui/duration_formatter.rb +24 -0
  44. data/lib/fun_ci/tui/header_animation_manager.rb +71 -0
  45. data/lib/fun_ci/tui/header_animation_player.rb +45 -0
  46. data/lib/fun_ci/tui/key_handler.rb +86 -0
  47. data/lib/fun_ci/tui/looping_animation_player.rb +45 -0
  48. data/lib/fun_ci/tui/relative_time.rb +22 -0
  49. data/lib/fun_ci/tui/row_formatter.rb +108 -0
  50. data/lib/fun_ci/tui/screen.rb +103 -0
  51. data/lib/fun_ci/tui/spinner.rb +24 -0
  52. data/lib/fun_ci/tui/stage_change_detector.rb +58 -0
  53. data/lib/fun_ci/tui/streak_counter.rb +29 -0
  54. data/lib/fun_ci/tui/terminal_input.rb +69 -0
  55. data/lib/fun_ci.rb +6 -6
  56. metadata +49 -28
  57. data/lib/fun_ci/admin_tui.rb +0 -226
  58. data/lib/fun_ci/ansi.rb +0 -21
  59. data/lib/fun_ci/background_wrapper.rb +0 -27
  60. data/lib/fun_ci/board_data.rb +0 -51
  61. data/lib/fun_ci/database.rb +0 -50
  62. data/lib/fun_ci/duration_formatter.rb +0 -23
  63. data/lib/fun_ci/hook_writer.rb +0 -73
  64. data/lib/fun_ci/installer.rb +0 -53
  65. data/lib/fun_ci/maven_linter_detector.rb +0 -24
  66. data/lib/fun_ci/pipeline_forker.rb +0 -36
  67. data/lib/fun_ci/pipeline_recorder.rb +0 -72
  68. data/lib/fun_ci/pipeline_run.rb +0 -57
  69. data/lib/fun_ci/progress_reporter.rb +0 -29
  70. data/lib/fun_ci/project_config.rb +0 -40
  71. data/lib/fun_ci/project_detector.rb +0 -18
  72. data/lib/fun_ci/relative_time.rb +0 -20
  73. data/lib/fun_ci/row_formatter.rb +0 -106
  74. data/lib/fun_ci/screen.rb +0 -81
  75. data/lib/fun_ci/setup_checker.rb +0 -28
  76. data/lib/fun_ci/spinner.rb +0 -22
  77. data/lib/fun_ci/stage_job.rb +0 -44
  78. data/lib/fun_ci/stage_runner.rb +0 -108
  79. data/lib/fun_ci/stale_pipeline_canceller.rb +0 -51
  80. data/lib/fun_ci/streak_counter.rb +0 -30
  81. data/lib/fun_ci/template_writer.rb +0 -51
  82. data/lib/fun_ci/trigger.rb +0 -150
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FunCi
4
+ module Animations
5
+ module Running
6
+ # Rocket cruising through a starfield — exhaust cycles short/medium/long
7
+ # Body pipes fixed at cols 20 & 25, nose/tail at 21-24/22-23
8
+
9
+ w = "\e[1;37m" # bold white (hull)
10
+ c = "\e[1;36m" # bold cyan (window, bright stars)
11
+ dc = "\e[36m" # cyan (mid stars)
12
+ dm = "\e[2;36m" # dim cyan (far stars)
13
+ y = "\e[1;33m" # bold yellow (flame core)
14
+ o = "\e[38;5;208m" # orange (flame edge)
15
+ r = "\e[2;33m" # dim yellow (flame trail)
16
+ x = "\e[0m" # reset
17
+
18
+ raw_frames = [
19
+ [ # frame 1 — short exhaust
20
+ " #{dm}.#{x} #{c}*#{x} #{dm}.#{x}",
21
+ " #{c}.#{x} #{dm}.#{x}",
22
+ " #{dc}.#{x} #{dm}.#{x}",
23
+ "#{dm}.#{x} #{dc}.#{x}",
24
+ " #{w}/\\#{x}",
25
+ " #{w}/ \\#{x}",
26
+ " #{o}~#{x} #{w}| #{c}oo#{w} |#{x} #{c}*#{x}",
27
+ " #{y}=#{o}=#{r}=~#{x} #{w}| |====>#{x}",
28
+ " #{o}~#{x} #{w}|#{c}FUN!#{w}|#{x}",
29
+ " #{w}\\ /#{x}",
30
+ " #{w}\\/#{x} #{dm}.#{x}",
31
+ " #{dc}.#{x} #{c}.#{x}",
32
+ " #{dm}.#{x} #{dc}.#{x}",
33
+ " #{dm}.#{x}",
34
+ ],
35
+ [ # frame 2 — medium exhaust
36
+ " #{dm}.#{x} #{c}*#{x} #{dm}.#{x}",
37
+ " #{dm}.#{x} #{c}.#{x}",
38
+ " #{dc}.#{x} #{dm}.#{x}",
39
+ " #{dc}.#{x}",
40
+ " #{w}/\\#{x}",
41
+ " #{w}/ \\#{x}",
42
+ " #{o}~~~#{x} #{w}| #{c}oo#{w} |#{x} #{c}*#{x}",
43
+ " #{y}=#{o}==#{r}==~#{x} #{w}| |====>#{x}",
44
+ " #{o}~~~#{x} #{w}|#{c}FUN!#{w}|#{x}",
45
+ " #{w}\\ /#{x}",
46
+ " #{w}\\/#{x} #{dm}.#{x}",
47
+ " #{c}.#{x}",
48
+ " #{dm}.#{x} #{dc}.#{x}",
49
+ "#{dc}.#{x} #{dm}.#{x}",
50
+ ],
51
+ [ # frame 3 — long exhaust
52
+ " #{dm}.#{x} #{c}*#{x} #{dm}.#{x}",
53
+ " #{dm}.#{x} #{c}.#{x}",
54
+ " #{dc}.#{x} #{dm}.#{x}",
55
+ " #{dm}.#{x} #{dc}.#{x}",
56
+ " #{w}/\\#{x}",
57
+ " #{w}/ \\#{x}",
58
+ " #{o}~~~~~#{x} #{w}| #{c}oo#{w} |#{x} #{c}*#{x}",
59
+ " #{y}===#{o}==#{r}==~#{x} #{w}| |====>#{x}",
60
+ " #{o}~~~~~#{x} #{w}|#{c}FUN!#{w}|#{x}",
61
+ " #{w}\\ /#{x}",
62
+ " #{w}\\/#{x} #{dm}.#{x}",
63
+ " #{c}.#{x}",
64
+ " #{dm}.#{x} #{dc}.#{x}",
65
+ " #{dm}.#{x}",
66
+ ],
67
+ [ # frame 4 — short exhaust
68
+ "#{dm}.#{x} #{c}*#{x} #{dm}.#{x}",
69
+ " #{dm}.#{x} #{c}.#{x}",
70
+ " #{dc}.#{x} #{dm}.#{x}",
71
+ " #{dm}.#{x} #{dc}.#{x}",
72
+ " #{w}/\\#{x}",
73
+ " #{w}/ \\#{x}",
74
+ " #{o}~#{x} #{w}| #{c}oo#{w} |#{x} #{c}*#{x}",
75
+ " #{y}=#{o}=#{r}=~#{x} #{w}| |====>#{x}",
76
+ " #{o}~#{x} #{w}|#{c}FUN!#{w}|#{x}",
77
+ " #{w}\\ /#{x}",
78
+ " #{w}\\/#{x} #{dm}.#{x}",
79
+ " #{dm}.#{x} #{c}.#{x}",
80
+ "#{dm}.#{x} #{dc}.#{x}",
81
+ " #{dm}.#{x}",
82
+ ],
83
+ [ # frame 5 — medium exhaust
84
+ " #{c}*#{x} #{dm}.#{x} #{c}.#{x}",
85
+ " #{dm}.#{x} #{dm}.#{x}",
86
+ " #{dc}.#{x} #{dm}.#{x}",
87
+ " #{dm}.#{x} #{dc}.#{x}",
88
+ " #{w}/\\#{x}",
89
+ " #{w}/ \\#{x}",
90
+ " #{o}~~~#{x} #{w}| #{c}oo#{w} |#{x} #{c}*#{x}",
91
+ " #{y}=#{o}==#{r}==~#{x} #{w}| |====>#{x}",
92
+ " #{o}~~~#{x} #{w}|#{c}FUN!#{w}|#{x}",
93
+ " #{w}\\ /#{x}",
94
+ " #{w}\\/#{x} #{dm}.#{x}",
95
+ " #{c}.#{x}",
96
+ " #{dm}.#{x} #{dc}.#{x}",
97
+ " #{dm}.#{x}",
98
+ ],
99
+ [ # frame 6 — long exhaust
100
+ " #{c}*#{x} #{dm}.#{x} #{c}.#{x}",
101
+ " #{dm}.#{x} #{dm}.#{x}",
102
+ " #{dc}.#{x} #{dm}.#{x}",
103
+ " #{dm}.#{x} #{dc}.#{x}",
104
+ " #{w}/\\#{x}",
105
+ " #{w}/ \\#{x}",
106
+ " #{o}~~~~~#{x} #{w}| #{c}oo#{w} |#{x} #{c}*#{x}",
107
+ " #{y}===#{o}==#{r}==~#{x} #{w}| |====>#{x}",
108
+ " #{o}~~~~~#{x} #{w}|#{c}FUN!#{w}|#{x}",
109
+ " #{w}\\ /#{x}",
110
+ " #{w}\\/#{x} #{dm}.#{x}",
111
+ " #{c}.#{x}",
112
+ " #{dm}.#{x} #{dc}.#{x}",
113
+ " #{dm}.#{x}",
114
+ ],
115
+ ]
116
+
117
+ max = raw_frames.flatten.map { |l| l.gsub(/\e\[[0-9;]*m/, "").length }.max
118
+ raw_frames.each do |frame|
119
+ frame.map! { |l| l + " " * (max - l.gsub(/\e\[[0-9;]*m/, "").length) }
120
+ end
121
+
122
+ DATA = {
123
+ name: "Running",
124
+ fps: 4,
125
+ frames: raw_frames
126
+ }.freeze
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,281 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FunCi
4
+ module Animations
5
+ module Success
6
+ # Success celebration animation — fireworks bursting with sparkles
7
+ # Run: ruby exe/animation-player animations/success.rb
8
+
9
+ g = "\e[1;32m" # bold green
10
+ G = "\e[32m" # green
11
+ y = "\e[1;33m" # bold yellow
12
+ Y = "\e[33m" # yellow
13
+ w = "\e[1;37m" # bold white
14
+ c = "\e[1;36m" # bold cyan
15
+ d = "\e[2;32m" # dim green
16
+ x = "\e[0m" # reset
17
+
18
+ raw_frames = [
19
+ # Frame 1 — launch
20
+ [
21
+ "",
22
+ "",
23
+ "",
24
+ "",
25
+ "",
26
+ "",
27
+ "",
28
+ "",
29
+ " #{w}|#{x}",
30
+ " #{y}*#{x}",
31
+ "",
32
+ ],
33
+ # Frame 2 — rising
34
+ [
35
+ "",
36
+ "",
37
+ "",
38
+ "",
39
+ "",
40
+ "",
41
+ " #{w}|#{x}",
42
+ " #{y}*#{x}",
43
+ " #{d}:#{x}",
44
+ " #{d}.#{x}",
45
+ "",
46
+ ],
47
+ # Frame 3 — ascending
48
+ [
49
+ "",
50
+ "",
51
+ "",
52
+ "",
53
+ " #{w}|#{x}",
54
+ " #{y}*#{x}",
55
+ " #{d}:#{x}",
56
+ " #{d}.#{x}",
57
+ "",
58
+ "",
59
+ "",
60
+ ],
61
+ # Frame 4 — about to burst
62
+ [
63
+ "",
64
+ "",
65
+ " #{w}*#{x}",
66
+ " #{y}|#{x}",
67
+ " #{d}:#{x}",
68
+ "",
69
+ "",
70
+ "",
71
+ "",
72
+ "",
73
+ "",
74
+ ],
75
+ # Frame 5 — small burst
76
+ [
77
+ "",
78
+ " #{y}\\#{x} #{w}|#{x} #{y}/#{x}",
79
+ " #{g}*#{y}*#{g}*#{x}",
80
+ " #{y}/ #{w}|#{x} #{y}\\#{x}",
81
+ "",
82
+ "",
83
+ "",
84
+ "",
85
+ "",
86
+ "",
87
+ "",
88
+ ],
89
+ # Frame 6 — full firework (hold 2x)
90
+ [
91
+ " #{c}*#{x} #{y}\\#{x} #{w}|#{x} #{y}/#{x} #{c}*#{x}",
92
+ " #{g}*#{x} #{y}*#{x} #{w}*#{x} #{y}*#{x} #{g}*#{x}",
93
+ " #{y}--#{x} #{g}*#{y}*#{w}*#{g}*#{y}*#{w} #{g}*#{y}*#{w}*#{g}*#{y}*#{x} #{y}--#{x}",
94
+ " #{g}*#{x} #{y}*#{x} #{w}*#{x} #{y}*#{x} #{g}*#{x}",
95
+ " #{c}*#{x} #{y}/#{x} #{w}|#{x} #{y}\\#{x} #{c}*#{x}",
96
+ "",
97
+ "",
98
+ "",
99
+ "",
100
+ "",
101
+ "",
102
+ ],
103
+ [
104
+ " #{c}*#{x} #{y}\\#{x} #{w}|#{x} #{y}/#{x} #{c}*#{x}",
105
+ " #{g}*#{x} #{y}*#{x} #{w}*#{x} #{y}*#{x} #{g}*#{x}",
106
+ " #{y}--#{x} #{g}*#{y}*#{w}*#{g}*#{y}*#{w} #{g}*#{y}*#{w}*#{g}*#{y}*#{x} #{y}--#{x}",
107
+ " #{g}*#{x} #{y}*#{x} #{w}*#{x} #{y}*#{x} #{g}*#{x}",
108
+ " #{c}*#{x} #{y}/#{x} #{w}|#{x} #{y}\\#{x} #{c}*#{x}",
109
+ "",
110
+ "",
111
+ "",
112
+ "",
113
+ "",
114
+ "",
115
+ ],
116
+ # Frame 7 — big celebration with sparkles (hold 3x)
117
+ [
118
+ " #{c}+#{x} #{y}.#{x} #{g}*#{x} #{y}.#{x} #{c}+#{x}",
119
+ " #{g}*#{x} #{y}*#{x} #{y}*#{x} #{g}*#{x}",
120
+ " #{y}*#{x} #{g}.#{x} #{w}* #{g}P#{w}A#{g}S#{w}S #{g}*#{x} #{g}.#{x} #{y}*#{x}",
121
+ " #{g}*#{x} #{y}*#{x} #{y}*#{x} #{g}*#{x}",
122
+ " #{c}+#{x} #{y}'#{x} #{g}*#{x} #{y}'#{x} #{c}+#{x}",
123
+ " #{d}.#{x} #{d}.#{x}",
124
+ " #{d}*#{x} #{d}*#{x}",
125
+ "",
126
+ "",
127
+ "",
128
+ "",
129
+ ],
130
+ [
131
+ " #{c}+#{x} #{y}.#{x} #{g}*#{x} #{y}.#{x} #{c}+#{x}",
132
+ " #{g}*#{x} #{y}*#{x} #{y}*#{x} #{g}*#{x}",
133
+ " #{y}*#{x} #{g}.#{x} #{w}* #{g}P#{w}A#{g}S#{w}S #{g}*#{x} #{g}.#{x} #{y}*#{x}",
134
+ " #{g}*#{x} #{y}*#{x} #{y}*#{x} #{g}*#{x}",
135
+ " #{c}+#{x} #{y}'#{x} #{g}*#{x} #{y}'#{x} #{c}+#{x}",
136
+ " #{d}.#{x} #{d}.#{x}",
137
+ " #{d}*#{x} #{d}*#{x}",
138
+ "",
139
+ "",
140
+ "",
141
+ "",
142
+ ],
143
+ [
144
+ " #{c}+#{x} #{y}.#{x} #{g}*#{x} #{y}.#{x} #{c}+#{x}",
145
+ " #{g}*#{x} #{y}*#{x} #{y}*#{x} #{g}*#{x}",
146
+ " #{y}*#{x} #{g}.#{x} #{w}* #{g}P#{w}A#{g}S#{w}S #{g}*#{x} #{g}.#{x} #{y}*#{x}",
147
+ " #{g}*#{x} #{y}*#{x} #{y}*#{x} #{g}*#{x}",
148
+ " #{c}+#{x} #{y}'#{x} #{g}*#{x} #{y}'#{x} #{c}+#{x}",
149
+ " #{d}.#{x} #{d}.#{x}",
150
+ " #{d}*#{x} #{d}*#{x}",
151
+ "",
152
+ "",
153
+ "",
154
+ "",
155
+ ],
156
+ # Frame 8 — sparkles raining + second launch
157
+ [
158
+ " #{d}.#{x} #{c}+#{x} #{g}.#{x} #{y}*#{x} #{g}.#{x} #{c}+#{x} #{d}.#{x}",
159
+ " #{y}.#{x} #{d}*#{x} #{y}.#{x}",
160
+ " #{g}*#{x} #{d}.#{x} #{g}.#{x} #{d}.#{x} #{g}*#{x}",
161
+ " #{d}'#{x} #{d}.#{x} #{d}'#{x}",
162
+ " #{c}+#{x} #{d}. .#{x} #{c}+#{x}",
163
+ " #{d}. .#{x}",
164
+ " #{w}|#{x}",
165
+ " #{y}*#{x}",
166
+ " #{d}:#{x}",
167
+ "",
168
+ "",
169
+ ],
170
+ # Frame 9 — second firework rising + rain
171
+ [
172
+ " #{d}.#{x} #{d}.#{x}",
173
+ " #{d}.#{x} #{d}'#{x} #{d}'#{x} #{d}.#{x}",
174
+ " #{d}. . .#{x}",
175
+ " #{w}*#{x}",
176
+ " #{y}|#{x}",
177
+ " #{d}:#{x}",
178
+ "",
179
+ "",
180
+ "",
181
+ "",
182
+ "",
183
+ ],
184
+ # Frame 10 — second burst
185
+ [
186
+ "",
187
+ " #{d}.#{x} #{d}.#{x}",
188
+ " #{y}\\#{x} #{w}|#{x} #{y}/#{x}",
189
+ " #{g}*#{y}*#{g}*#{x}",
190
+ " #{y}/ #{w}|#{x} #{y}\\#{x}",
191
+ "",
192
+ "",
193
+ "",
194
+ "",
195
+ "",
196
+ "",
197
+ ],
198
+ # Frame 11 — second full firework (hold 2x)
199
+ [
200
+ "",
201
+ " #{c}*#{x} #{y}\\#{x} #{w}|#{x} #{y}/#{x} #{c}*#{x}",
202
+ " #{g}*#{y}*#{w}*#{y}*#{g}*#{x}",
203
+ " #{y}--#{x} #{g}*#{w}*#{g}*#{w}*#{g}*#{x} #{y}--#{x}",
204
+ " #{g}*#{y}*#{w}*#{y}*#{g}*#{x}",
205
+ " #{c}*#{x} #{y}/#{x} #{w}|#{x} #{y}\\#{x} #{c}*#{x}",
206
+ "",
207
+ "",
208
+ "",
209
+ "",
210
+ "",
211
+ ],
212
+ [
213
+ "",
214
+ " #{c}*#{x} #{y}\\#{x} #{w}|#{x} #{y}/#{x} #{c}*#{x}",
215
+ " #{g}*#{y}*#{w}*#{y}*#{g}*#{x}",
216
+ " #{y}--#{x} #{g}*#{w}*#{g}*#{w}*#{g}*#{x} #{y}--#{x}",
217
+ " #{g}*#{y}*#{w}*#{y}*#{g}*#{x}",
218
+ " #{c}*#{x} #{y}/#{x} #{w}|#{x} #{y}\\#{x} #{c}*#{x}",
219
+ "",
220
+ "",
221
+ "",
222
+ "",
223
+ "",
224
+ ],
225
+ # Frame 12 — grand finale, both sparkle (hold 3x)
226
+ [
227
+ " #{c}+#{x} #{y}*#{x} #{g}.#{x} #{g}.#{x} #{y}*#{x} #{c}+#{x} #{g}.#{x}",
228
+ " #{g}*#{x} #{y}.#{x} #{d}*#{x} #{d}*#{x} #{y}.#{x} #{g}*#{x} #{y}.#{x}",
229
+ " #{y}.#{x} #{w}*#{x} #{g}YES#{x} #{w}*#{x} #{w}*#{x} #{g}YES#{x} #{w}*#{x} #{y}.#{x}",
230
+ " #{g}*#{x} #{y}'#{x} #{d}*#{x} #{d}*#{x} #{y}'#{x} #{g}*#{x} #{y}'#{x}",
231
+ " #{c}+#{x} #{y}*#{x} #{g}'#{x} #{g}'#{x} #{y}*#{x} #{c}+#{x} #{g}'#{x}",
232
+ "#{d}.#{x} #{d}.#{x} #{d}.#{x} #{d}.#{x} #{d}.#{x} #{d}.#{x}",
233
+ " #{d}*#{x} #{d}*#{x} #{d}*#{x} #{d}*#{x} #{d}*#{x}",
234
+ " #{d}.#{x} #{d}.#{x} #{d}.#{x} #{d}.#{x}",
235
+ "",
236
+ "",
237
+ "",
238
+ ],
239
+ [
240
+ " #{c}+#{x} #{y}*#{x} #{g}.#{x} #{g}.#{x} #{y}*#{x} #{c}+#{x} #{g}.#{x}",
241
+ " #{g}*#{x} #{y}.#{x} #{d}*#{x} #{d}*#{x} #{y}.#{x} #{g}*#{x} #{y}.#{x}",
242
+ " #{y}.#{x} #{w}*#{x} #{g}YES#{x} #{w}*#{x} #{w}*#{x} #{g}YES#{x} #{w}*#{x} #{y}.#{x}",
243
+ " #{g}*#{x} #{y}'#{x} #{d}*#{x} #{d}*#{x} #{y}'#{x} #{g}*#{x} #{y}'#{x}",
244
+ " #{c}+#{x} #{y}*#{x} #{g}'#{x} #{g}'#{x} #{y}*#{x} #{c}+#{x} #{g}'#{x}",
245
+ "#{d}.#{x} #{d}.#{x} #{d}.#{x} #{d}.#{x} #{d}.#{x} #{d}.#{x}",
246
+ " #{d}*#{x} #{d}*#{x} #{d}*#{x} #{d}*#{x} #{d}*#{x}",
247
+ " #{d}.#{x} #{d}.#{x} #{d}.#{x} #{d}.#{x}",
248
+ "",
249
+ "",
250
+ "",
251
+ ],
252
+ [
253
+ " #{c}+#{x} #{y}*#{x} #{g}.#{x} #{g}.#{x} #{y}*#{x} #{c}+#{x} #{g}.#{x}",
254
+ " #{g}*#{x} #{y}.#{x} #{d}*#{x} #{d}*#{x} #{y}.#{x} #{g}*#{x} #{y}.#{x}",
255
+ " #{y}.#{x} #{w}*#{x} #{g}YES#{x} #{w}*#{x} #{w}*#{x} #{g}YES#{x} #{w}*#{x} #{y}.#{x}",
256
+ " #{g}*#{x} #{y}'#{x} #{d}*#{x} #{d}*#{x} #{y}'#{x} #{g}*#{x} #{y}'#{x}",
257
+ " #{c}+#{x} #{y}*#{x} #{g}'#{x} #{g}'#{x} #{y}*#{x} #{c}+#{x} #{g}'#{x}",
258
+ "#{d}.#{x} #{d}.#{x} #{d}.#{x} #{d}.#{x} #{d}.#{x} #{d}.#{x}",
259
+ " #{d}*#{x} #{d}*#{x} #{d}*#{x} #{d}*#{x} #{d}*#{x}",
260
+ " #{d}.#{x} #{d}.#{x} #{d}.#{x} #{d}.#{x}",
261
+ "",
262
+ "",
263
+ "",
264
+ ],
265
+ ]
266
+
267
+ # Pad lines so all rows in each frame have equal stripped length —
268
+ # prevents the player's per-line centering from misaligning the art.
269
+ max = raw_frames.flatten.map { |l| l.gsub(/\e\[[0-9;]*m/, "").length }.max
270
+ raw_frames.each do |frame|
271
+ frame.map! { |l| l + " " * (max - l.gsub(/\e\[[0-9;]*m/, "").length) }
272
+ end
273
+
274
+ DATA = {
275
+ name: "Success",
276
+ fps: 8,
277
+ frames: raw_frames
278
+ }.freeze
279
+ end
280
+ end
281
+ end
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FunCi
4
+ module Animations
5
+ module Yay
6
+ # YAY! wide banner — white letters, green and blue celebration
7
+ # Run: ruby exe/animation-player animations/yay.rb
8
+
9
+ w = "\e[1;37m" # bold white (letters only)
10
+ g = "\e[1;32m" # bold green
11
+ G = "\e[32m" # green
12
+ d = "\e[2;32m" # dim green
13
+ c = "\e[1;36m" # bold cyan
14
+ C = "\e[36m" # cyan
15
+ b = "\e[1;34m" # bold blue
16
+ B = "\e[34m" # blue
17
+ D = "\e[2;37m" # dim white (fading letters)
18
+ x = "\e[0m" # reset
19
+
20
+ raw_frames = [
21
+ # Frame 1 — dark field, spark
22
+ [
23
+ " #{d}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .#{x}",
24
+ " #{d}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .#{x}",
25
+ " #{d}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .#{x}",
26
+ " #{d}. . . . . . . . . . . . . . . . . #{w}*#{d} . . . . . . . . . . . . . . .#{x}",
27
+ " #{d}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .#{x}",
28
+ " #{d}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .#{x}",
29
+ " #{d}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .#{x}",
30
+ " #{d}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .#{x}",
31
+ ],
32
+ # Frame 2 — middle rows of letters flash in
33
+ [
34
+ " #{d}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .#{x}",
35
+ " #{d}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .#{x}",
36
+ " #{d}. . #{G}. . . . .#{d} . #{G}. . . . . . . . . .#{d} . #{G}. . . . .#{d} . . . . . . . .#{x}",
37
+ " #{d}. . . #{G}---#{w}#####{G}---#{d} . #{G}--#{w}#########{G}--#{d} . #{G}---#{w}#####{G}---#{d} . . . . . . . .#{x}",
38
+ " #{d}. . . . #{G}--#{w}###{G}--#{d} . . #{G}-#{w}#########{G}-#{d} . . #{G}--#{w}###{G}--#{d} . . . . . . . . .#{x}",
39
+ " #{d}. . #{G}' ' ' ' '#{d} . #{G}' ' ' ' ' ' ' ' '#{d} . #{G}' ' ' ' '#{d} . . . . . . . .#{x}",
40
+ " #{d}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .#{x}",
41
+ " #{d}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .#{x}",
42
+ ],
43
+ # Frame 3 — letters expand vertically
44
+ [
45
+ " #{d}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .#{x}",
46
+ " #{d}. #{G}*#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{d} . . . .#{x}",
47
+ " #{d}. . #{w}\\###{d} . #{w}/\\###{d} . #{w}#####{d} . #{w}#####{d} . #{w}\\###{d} . #{w}/\\###{d} . #{w}#####{d} . . . . .#{x}",
48
+ " #{d}. . #{G}*#{g} *#{w}#####{g} *#{G} *#{g} *#{w}#########{g} *#{G} *#{g} *#{w}#####{g} *#{G} *#{w}#####{d} . . . .#{x}",
49
+ " #{d}. . . . #{G}*#{g} #{w}###{g} *#{G} *#{d} . #{w}###{d} . . . . #{w}###{d} . . #{G}*#{g} #{w}###{g} *#{G} *#{d} . . . . . . .#{x}",
50
+ " #{d}. . #{w}/###{d} . . #{w}\\###{d} . #{w}###{d} . . . . #{w}###{d} . #{w}/###{d} . . #{w}\\###{d} . #{w}#####{d} . . . .#{x}",
51
+ " #{d}. #{G}'#{g} '#{G} '#{g} '#{G} '#{g} '#{G} '#{g} '#{G} '#{g} '#{G} '#{g} '#{G} '#{g} '#{G} '#{g} '#{G} '#{g} '#{G} '#{d} . . . .#{x}",
52
+ " #{d}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .#{x}",
53
+ ],
54
+ # Frame 4 — full letters revealed, green/cyan border
55
+ [
56
+ " #{g}*#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{x}",
57
+ " #{c}*#{G} . #{w}###{G} . . . . #{w}###{G} . . . #{w}#####{G} . . . #{w}###{G} . . . . #{w}###{G} . #{w}#####{G} . #{c}*#{x}",
58
+ " #{c}*#{G} . . #{w}###{G} . . #{w}/\\###{G} . #{w}###{G} . . #{w}###{G} . . #{w}###{G} . . #{w}/\\###{G} . #{w}#####{G} . #{c}*#{x}",
59
+ " #{c}*#{G} . . . #{w}#####{G} . . #{w}###{G} . . . . #{w}###{G} . . . #{w}#####{G} . . . #{w}#####{G} . #{c}*#{x}",
60
+ " #{c}*#{G} . . . . #{w}###{G} . . #{w}#########{G} . . . . #{w}###{G} . . . . . . . . . #{c}*#{x}",
61
+ " #{c}*#{G} . . . . #{w}###{G} . . #{w}###{G} . . . . #{w}###{G} . . . . #{w}###{G} . . . #{w}#####{G} . #{c}*#{x}",
62
+ " #{c}*#{G} . . . . #{w}###{G} . . #{w}###{G} . . . . #{w}###{G} . . . . #{w}###{G} . . . #{w}#####{G} . #{c}*#{x}",
63
+ " #{g}'#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{x}",
64
+ ],
65
+ # (hold with colour shift)
66
+ [
67
+ " #{c}*#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{x}",
68
+ " #{g}*#{G} . #{w}###{G} . . . . #{w}###{G} . . . #{w}#####{G} . . . #{w}###{G} . . . . #{w}###{G} . #{w}#####{G} . #{g}*#{x}",
69
+ " #{g}*#{G} . . #{w}###{G} . . #{w}/\\###{G} . #{w}###{G} . . #{w}###{G} . . #{w}###{G} . . #{w}/\\###{G} . #{w}#####{G} . #{g}*#{x}",
70
+ " #{g}*#{G} . . . #{w}#####{G} . . #{w}###{G} . . . . #{w}###{G} . . . #{w}#####{G} . . . #{w}#####{G} . #{g}*#{x}",
71
+ " #{g}*#{G} . . . . #{w}###{G} . . #{w}#########{G} . . . . #{w}###{G} . . . . . . . . . #{g}*#{x}",
72
+ " #{g}*#{G} . . . . #{w}###{G} . . #{w}###{G} . . . . #{w}###{G} . . . . #{w}###{G} . . . #{w}#####{G} . #{g}*#{x}",
73
+ " #{g}*#{G} . . . . #{w}###{G} . . #{w}###{G} . . . . #{w}###{G} . . . . #{w}###{G} . . . #{w}#####{G} . #{g}*#{x}",
74
+ " #{c}'#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{c} '#{g} '#{x}",
75
+ ],
76
+ # Frame 5 — colour explosion, green/blue/cyan ring
77
+ [
78
+ " #{b}*#{B} *#{b} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{b} *#{B} *#{b} *#{B} *#{x}",
79
+ " #{B}*#{g} *#{c} #{w}###{c} *#{g} *#{c} *#{w}###{c} *#{g} *#{c} #{w}#####{c} *#{g} *#{c} #{w}###{c} *#{g} *#{c} *#{w}###{c} * #{w}#####{c} *#{B} *#{x}",
80
+ " #{b}*#{c} *#{C} *#{w}###{C} *#{c} #{w}/\\###{c} *#{w}###{C} *#{c} #{w}###{C} *#{c} #{w}###{C} *#{c} #{w}/\\###{C} * #{w}#####{C} *#{b} *#{x}",
81
+ " #{g}*#{c} *#{G} *#{g} #{w}#####{g} *#{G} #{w}###{G} *#{g} *#{G} *#{w}###{G} *#{g} *#{w}#####{g} *#{G} *#{w}#####{g} *#{c} *#{x}",
82
+ " #{c}*#{g} *#{c} *#{g} *#{w}###{g} *#{c} #{w}#########{c} *#{g} *#{c} #{w}###{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{x}",
83
+ " #{b}*#{c} *#{C} *#{g} #{w}###{C} *#{c} *#{w}###{C} *#{c} *#{C} *#{w}###{C} *#{c} *#{C} *#{w}###{C} *#{c} * #{w}#####{C} *#{b} *#{x}",
84
+ " #{B}*#{g} *#{c} *#{C} *#{w}###{c} *#{g} *#{w}###{c} *#{g} *#{c} *#{w}###{c} *#{g} *#{c} *#{w}###{c} *#{g} * #{w}#####{c} *#{B} *#{x}",
85
+ " #{b}*#{B} *#{b} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{b} *#{B} *#{b} *#{B} *#{x}",
86
+ ],
87
+ # Frame 6 — FULL CELEBRATION, dense green/blue, white letters
88
+ [
89
+ " #{b}*#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{b} *#{B} *#{x}",
90
+ " #{g}*#{c} *#{g} #{w}###{g} *#{c} *#{g} *#{w}###{g} *#{c} *#{g} #{w}#####{g} *#{c} *#{g} #{w}###{g} *#{c} *#{g} *#{w}###{g} * #{w}#####{g} *#{c} *#{x}",
91
+ " #{c}*#{g} *#{c} *#{w}###{c} *#{g} #{w}/\\###{c} *#{w}###{g} *#{c} #{w}###{g} *#{c} #{w}###{c} *#{g} #{w}/\\###{g} * #{w}#####{c} *#{g} *#{x}",
92
+ " #{g}*#{c} *#{g} *#{c} #{w}#####{c} *#{g} #{w}###{g} *#{c} *#{g} *#{w}###{g} *#{c} *#{w}#####{c} *#{g} *#{w}#####{c} *#{c} *#{x}",
93
+ " #{c}*#{g} *#{c} *#{g} *#{w}###{g} *#{c} #{w}#########{c} *#{g} *#{c} #{w}###{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{x}",
94
+ " #{g}*#{c} *#{g} *#{c} #{w}###{c} *#{g} *#{w}###{g} *#{c} *#{g} *#{w}###{g} *#{c} *#{g} *#{w}###{g} *#{c} * #{w}#####{c} *#{c} *#{x}",
95
+ " #{c}*#{g} *#{c} *#{g} #{w}###{g} *#{c} *#{w}###{c} *#{g} *#{c} *#{w}###{c} *#{g} *#{c} *#{w}###{g} *#{c} * #{w}#####{g} *#{g} *#{x}",
96
+ " #{b}*#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{b} *#{B} *#{x}",
97
+ ],
98
+ # (hold — green/cyan shimmer)
99
+ [
100
+ " #{c}*#{g} *#{c} *#{g} *#{b} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{b} *#{g} *#{c} *#{g} *#{c} *#{b} *#{x}",
101
+ " #{g}*#{G} *#{c} #{w}###{G} *#{g} *#{G} *#{w}###{g} *#{G} *#{g} #{w}#####{G} *#{g} *#{G} #{w}###{g} *#{G} *#{g} *#{w}###{G} * #{w}#####{g} *#{g} *#{x}",
102
+ " #{c}*#{C} *#{g} *#{w}###{g} *#{C} #{w}/\\###{g} *#{w}###{C} *#{g} #{w}###{C} *#{g} #{w}###{g} *#{C} #{w}/\\###{C} * #{w}#####{g} *#{c} *#{x}",
103
+ " #{g}*#{G} *#{c} *#{g} #{w}#####{g} *#{G} #{w}###{G} *#{g} *#{G} *#{w}###{G} *#{g} *#{w}#####{g} *#{G} *#{w}#####{g} *#{g} *#{x}",
104
+ " #{c}*#{C} *#{g} *#{c} *#{w}###{c} *#{C} #{w}#########{C} *#{c} *#{C} #{w}###{c} *#{C} *#{c} *#{C} *#{c} *#{C} *#{c} *#{x}",
105
+ " #{g}*#{G} *#{c} *#{g} #{w}###{g} *#{G} *#{w}###{G} *#{g} *#{G} *#{w}###{G} *#{g} *#{G} *#{w}###{G} *#{g} * #{w}#####{g} *#{g} *#{x}",
106
+ " #{c}*#{C} *#{g} *#{c} #{w}###{c} *#{C} *#{w}###{C} *#{c} *#{C} *#{w}###{C} *#{c} *#{C} *#{w}###{c} *#{C} * #{w}#####{c} *#{c} *#{x}",
107
+ " #{c}*#{g} *#{c} *#{g} *#{b} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{b} *#{g} *#{c} *#{g} *#{c} *#{b} *#{x}",
108
+ ],
109
+ # (hold — blue accent shift)
110
+ [
111
+ " #{B}*#{b} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{b} *#{B} *#{b} *#{B} *#{x}",
112
+ " #{b}*#{c} *#{g} #{w}###{c} *#{g} *#{c} *#{w}###{g} *#{c} *#{g} #{w}#####{c} *#{g} *#{c} #{w}###{g} *#{c} *#{g} *#{w}###{c} * #{w}#####{g} *#{b} *#{x}",
113
+ " #{g}*#{c} *#{c} *#{w}###{g} *#{c} #{w}/\\###{g} *#{w}###{c} *#{g} #{w}###{c} *#{g} #{w}###{g} *#{c} #{w}/\\###{c} * #{w}#####{g} *#{g} *#{x}",
114
+ " #{c}*#{g} *#{g} *#{c} #{w}#####{c} *#{g} #{w}###{g} *#{c} *#{g} *#{w}###{g} *#{c} *#{w}#####{c} *#{g} *#{w}#####{c} *#{c} *#{x}",
115
+ " #{g}*#{c} *#{c} *#{g} *#{w}###{g} *#{c} #{w}#########{c} *#{g} *#{c} #{w}###{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{x}",
116
+ " #{c}*#{g} *#{g} *#{c} #{w}###{c} *#{g} *#{w}###{g} *#{c} *#{g} *#{w}###{g} *#{c} *#{g} *#{w}###{g} *#{c} * #{w}#####{c} *#{c} *#{x}",
117
+ " #{b}*#{c} *#{c} *#{g} #{w}###{g} *#{c} *#{w}###{c} *#{g} *#{c} *#{w}###{c} *#{g} *#{c} *#{w}###{c} *#{g} * #{w}#####{g} *#{b} *#{x}",
118
+ " #{B}*#{b} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{b} *#{B} *#{b} *#{B} *#{x}",
119
+ ],
120
+ # Frame 7 — settling, letters still bright
121
+ [
122
+ " #{d}. #{b}*#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{b} *#{d} . . .#{x}",
123
+ " #{b}*#{c} *#{C} #{w}###{C} *#{c} *#{C} *#{w}###{C} *#{c} *#{C} #{w}#####{C} *#{c} *#{C} #{w}###{c} *#{C} *#{c} *#{w}###{C} * #{w}#####{c} *#{b} *#{x}",
124
+ " #{g}*#{G} *#{g} *#{w}###{g} *#{G} #{w}/\\###{g} *#{w}###{G} *#{g} #{w}###{G} *#{g} #{w}###{g} *#{G} #{w}/\\###{G} * #{w}#####{g} *#{g} *#{x}",
125
+ " #{c}*#{C} *#{g} *#{c} #{w}#####{c} *#{C} #{w}###{C} *#{c} *#{C} *#{w}###{C} *#{c} *#{w}#####{c} *#{C} *#{w}#####{c} *#{c} *#{x}",
126
+ " #{g}*#{G} *#{c} *#{g} *#{w}###{g} *#{G} #{w}#########{G} *#{g} *#{G} #{w}###{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{x}",
127
+ " #{c}*#{C} *#{g} *#{c} #{w}###{C} *#{c} *#{w}###{C} *#{c} *#{C} *#{w}###{C} *#{c} *#{C} *#{w}###{C} *#{c} * #{w}#####{C} *#{c} *#{x}",
128
+ " #{b}*#{c} *#{C} *#{g} #{w}###{C} *#{c} *#{w}###{C} *#{c} *#{C} *#{w}###{C} *#{c} *#{C} *#{w}###{c} *#{C} * #{w}#####{C} *#{b} *#{x}",
129
+ " #{d}. #{b}*#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{g} *#{c} *#{b} *#{d} . . .#{x}",
130
+ ],
131
+ # Frame 8 — fading, letters on green field
132
+ [
133
+ " #{d}. . #{g}*#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{d} . . .#{x}",
134
+ " #{d}. #{g}*#{G} . #{w}###{G} . . . . #{w}###{G} . . . #{w}#####{G} . . . #{w}###{G} . . . . #{w}###{G} . #{w}#####{G} .#{g} *#{d} .#{x}",
135
+ " #{d}. #{g}*#{G} . . #{w}###{G} . . #{w}/\\###{G} . #{w}###{G} . . #{w}###{G} . . #{w}###{G} . . #{w}/\\###{G} . #{w}#####{G} .#{g} *#{d} .#{x}",
136
+ " #{d}. . #{g}*#{G} . . #{w}#####{G} . . #{w}###{G} . . . . #{w}###{G} . . . #{w}#####{G} . . . #{w}#####{G} .#{g} *#{d} .#{x}",
137
+ " #{d}. . #{g}*#{G} . . . #{w}###{G} . . #{w}#########{G} . . . . #{w}###{G} . . . . . . . . . .#{g} *#{d} .#{x}",
138
+ " #{d}. #{g}*#{G} . . . #{w}###{G} . . #{w}###{G} . . . . #{w}###{G} . . . . #{w}###{G} . . . #{w}#####{G} .#{g} *#{d} .#{x}",
139
+ " #{d}. #{g}*#{G} . . . #{w}###{G} . . #{w}###{G} . . . . #{w}###{G} . . . . #{w}###{G} . . . #{w}#####{G} .#{g} *#{d} .#{x}",
140
+ " #{d}. . #{g}*#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{d} . . .#{x}",
141
+ ],
142
+ # Frame 9 — almost gone, dim letters
143
+ [
144
+ " #{d}. . . . #{G}*#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{G} *#{g} *#{d} . . . . .#{x}",
145
+ " #{d}. . . #{G}. #{D}###{G} . . . . #{D}###{G} . . . #{D}#####{G} . . . #{D}###{G} . . . . #{D}###{G} . #{D}#####{G} . . .#{x}",
146
+ " #{d}. . . . #{D}\\###{d} . . #{D}/\\###{d} . #{D}###{d} . . #{D}###{d} . . #{D}\\###{d} . . #{D}/\\###{d} . #{D}#####{d} . . .#{x}",
147
+ " #{d}. . . . . #{D}#####{d} . . #{D}###{d} . . . . #{D}###{d} . . . #{D}#####{d} . . . #{D}#####{d} . . .#{x}",
148
+ " #{d}. . . . . . #{D}###{d} . . #{D}#########{d} . . . . #{D}###{d} . . . . . . . . . . . .#{x}",
149
+ " #{d}. . . . . #{D}###{d} . . #{D}###{d} . . . . #{D}###{d} . . . . #{D}###{d} . . . #{D}#####{d} . . . .#{x}",
150
+ " #{d}. . . #{G}. #{D}\\###{G} . . #{D}\\###{G} . #{D}###{G} . . #{D}###{G} . #{D}\\###{G} . . #{D}\\###{G} . #{D}#####{G} . . .#{x}",
151
+ " #{d}. . . . #{G}'#{g} '#{G} '#{g} '#{G} '#{g} '#{G} '#{g} '#{G} '#{g} '#{G} '#{g} '#{G} '#{g} '#{G} '#{g} '#{d} . . . . .#{x}",
152
+ ],
153
+ ]
154
+
155
+ # Pad lines so all rows in each frame have equal stripped length —
156
+ # prevents the player's per-line centering from misaligning the art.
157
+ max = raw_frames.flatten.map { |l| l.gsub(/\e\[[0-9;]*m/, "").length }.max
158
+ raw_frames.each do |frame|
159
+ frame.map! { |l| l + " " * (max - l.gsub(/\e\[[0-9;]*m/, "").length) }
160
+ end
161
+
162
+ DATA = {
163
+ name: "YAY!",
164
+ fps: 8,
165
+ frames: raw_frames
166
+ }.freeze
167
+ end
168
+ end
169
+ end
data/lib/fun_ci/cli.rb CHANGED
@@ -42,25 +42,31 @@ module FunCi
42
42
  end
43
43
 
44
44
  def run_trigger(args)
45
- require_relative "trigger"
46
- require_relative "pipeline_recorder"
45
+ require_relative "pipeline/trigger"
46
+ require_relative "persistence/pipeline_recorder"
47
47
  db = setup_db
48
- recorder = DbRecorder.new(db)
49
- Trigger.run_from_args(args, stdout: @stdout, stderr: @stderr, recorder: recorder)
48
+ recorder = Persistence::DbRecorder.new(db)
49
+ Pipeline::Trigger.run_from_args(args, stdout: @stdout, stderr: @stderr, recorder: recorder)
50
50
  end
51
51
 
52
52
  def run_console(_args)
53
- require_relative "admin_tui"
53
+ require_relative "tui/admin_tui"
54
+ require_relative "tui/animation_renderer"
54
55
  require "io/console"
55
56
  db = setup_db
56
- tui = AdminTui.new(db: db, width_provider: -> { IO.console&.winsize&.dig(1) || 80 })
57
+ tui = Tui::AdminTui.new(
58
+ db: db,
59
+ width_provider: -> { IO.console&.winsize&.dig(1) || 80 },
60
+ height_provider: -> { IO.console&.winsize&.dig(0) },
61
+ animation_renderer: Tui::AnimationRenderer.new
62
+ )
57
63
  tui.run
58
64
  0
59
65
  end
60
66
 
61
67
  def run_init(args)
62
- require_relative "installer"
63
- code = Installer.run(project_root: Dir.pwd, stdout: @stdout)
68
+ require_relative "setup/installer"
69
+ code = Setup::Installer.run(project_root: Dir.pwd, stdout: @stdout)
64
70
  return code if code != 0 || !args.include?("--everything")
65
71
  code = run_install_hooks([])
66
72
  return code unless code == 0
@@ -68,26 +74,26 @@ module FunCi
68
74
  end
69
75
 
70
76
  def run_install_hooks(args)
71
- require_relative "hook_writer"
77
+ require_relative "setup/hook_writer"
72
78
  types = args.any? ? [args.first] : %w[pre-commit pre-push]
73
79
  types.each do |type|
74
- code = HookWriter.run(project_root: Dir.pwd, hook_type: type, stdout: @stdout)
80
+ code = Setup::HookWriter.run(project_root: Dir.pwd, hook_type: type, stdout: @stdout)
75
81
  return code unless code == 0
76
82
  end
77
83
  0
78
84
  end
79
85
 
80
86
  def run_check(_args)
81
- require_relative "setup_checker"
82
- SetupChecker.run(project_root: Dir.pwd, stdout: @stdout, stderr: @stderr)
87
+ require_relative "setup/setup_checker"
88
+ Setup::SetupChecker.run(project_root: Dir.pwd, stdout: @stdout, stderr: @stderr)
83
89
  end
84
90
 
85
91
  def setup_db
86
92
  db_dir = File.join(Dir.tmpdir, "fun-ci")
87
93
  Dir.mkdir(db_dir) unless Dir.exist?(db_dir)
88
94
  db_path = File.join(db_dir, "db.sqlite3")
89
- db = Database.connection(db_path)
90
- Database.migrate!(db)
95
+ db = Persistence::Database.connection(db_path)
96
+ Persistence::Database.migrate!(db)
91
97
  db
92
98
  end
93
99