asciinema_win 0.2.1 → 0.3.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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +96 -41
  3. data/LICENSE +21 -21
  4. data/README.md +645 -655
  5. data/docs/architecture.md +113 -105
  6. data/docs/cheat-sheet.md +80 -80
  7. data/docs/customization.md +141 -141
  8. data/docs/example.md +350 -350
  9. data/docs/how-to-use.md +153 -153
  10. data/docs/test-report.md +165 -165
  11. data/docs/troubleshooting.md +94 -94
  12. data/docs/windows-notes.md +87 -87
  13. data/exe/asciinema_win +18 -17
  14. data/lib/asciinema_win/ansi_parser.rb +437 -437
  15. data/lib/asciinema_win/asciicast.rb +567 -537
  16. data/lib/asciinema_win/cli.rb +604 -604
  17. data/lib/asciinema_win/export.rb +1412 -1410
  18. data/lib/asciinema_win/output_organizer.rb +276 -276
  19. data/lib/asciinema_win/player.rb +348 -348
  20. data/lib/asciinema_win/recorder.rb +519 -480
  21. data/lib/asciinema_win/screen_buffer.rb +371 -375
  22. data/lib/asciinema_win/themes.rb +334 -334
  23. data/lib/asciinema_win/version.rb +6 -6
  24. data/lib/asciinema_win/win32_screen.rb +119 -0
  25. data/lib/asciinema_win.rb +156 -153
  26. data/lib/rich/_palettes.rb +148 -148
  27. data/lib/rich/box.rb +342 -342
  28. data/lib/rich/cells.rb +524 -512
  29. data/lib/rich/color.rb +631 -628
  30. data/lib/rich/color_triplet.rb +227 -220
  31. data/lib/rich/console.rb +604 -549
  32. data/lib/rich/control.rb +332 -332
  33. data/lib/rich/json.rb +260 -254
  34. data/lib/rich/layout.rb +314 -314
  35. data/lib/rich/markdown.rb +531 -509
  36. data/lib/rich/markup.rb +186 -175
  37. data/lib/rich/panel.rb +318 -311
  38. data/lib/rich/progress.rb +430 -430
  39. data/lib/rich/segment.rb +387 -387
  40. data/lib/rich/style.rb +464 -433
  41. data/lib/rich/syntax.rb +1220 -1145
  42. data/lib/rich/table.rb +547 -525
  43. data/lib/rich/terminal_theme.rb +126 -126
  44. data/lib/rich/text.rb +460 -433
  45. data/lib/rich/tree.rb +232 -238
  46. data/lib/rich/version.rb +5 -5
  47. data/lib/rich/win32_console.rb +620 -859
  48. data/lib/rich.rb +108 -108
  49. metadata +2 -4
data/README.md CHANGED
@@ -1,655 +1,645 @@
1
- # asciinema-win + Rich-Ruby
2
-
3
- [![Ruby Version](https://img.shields.io/badge/ruby-3.4%2B-cc342d?style=flat-square&logo=ruby&logoColor=white)](https://www.ruby-lang.org/)
4
- [![Platform](https://img.shields.io/badge/platform-Windows-0078d4?style=flat-square&logo=windows&logoColor=white)](https://github.com/tigel-agm/asciinema-windows)
5
- [![License](https://img.shields.io/badge/license-MIT-0078d4?style=flat-square)](LICENSE)
6
- [![Pure Ruby](https://img.shields.io/badge/dependencies-zero-0078d4?style=flat-square)](https://github.com/tigel-agm/asciinema-windows)
7
- [![RubyGems](https://img.shields.io/gem/v/asciinema_win?style=flat-square&logo=rubygems)](https://rubygems.org/gems/asciinema_win)
8
-
9
- > **Native Windows Terminal Recorder and Rich Text Library in Pure Ruby**
10
-
11
- Record terminal sessions, export to GIF/MP4/WebM video, and render beautiful formatted outputall with zero external dependencies (except FFmpeg for video export).
12
-
13
- ---
14
-
15
- ## Demo
16
-
17
- **Rich-Ruby Terminal Recording exported to GIF:**
18
-
19
- ![Rich-Ruby Demo](rich_demo.gif)
20
-
21
- The GIF above shows Rich-Ruby components (Panel, Table, Tree, Syntax Highlighting, Progress Bar) rendered correctly with ANSI colors. Created with `examples/rich_ruby_demo.rb` and exported using the pure Ruby PPM frame renderer.
22
-
23
- <details>
24
- <summary><strong>Common rendering issues and solutions</strong></summary>
25
-
26
- **Issue 1: Literal markup tags instead of colors**
27
-
28
- If you see `[blue]text[/]` instead of colored text, the Rich-Ruby markup wasn't parsed:
29
-
30
- ![Missing Color Parsing](rich_demo_missing_color.gif)
31
-
32
- **Solution:** Use `Rich::Text.from_markup()` or `Rich::Console.print()` to properly parse markup before recording.
33
-
34
- ---
35
-
36
- **Issue 2: Missing progress bar blocks**
37
-
38
- If percentage increases but the bar is empty, Unicode block characters weren't in the font:
39
-
40
- ![Missing Progress Bar](rich_demo_missing_bar.gif)
41
-
42
- **Solution:** This was fixed in v0.2.0. The embedded font now includes block elements (█ ░ ▒ ▓) and box-drawing characters.
43
-
44
- </details>
45
-
46
- ---
47
-
48
- ## Table of Contents
49
-
50
- - [asciinema-win](#asciinema-win)
51
- - [Features](#asciinema-features)
52
- - [Quick Start](#asciinema-quick-start)
53
- - [CLI Reference](#cli-reference)
54
- - [Ruby API](#ruby-api)
55
- - [Export Formats](#export-formats)
56
- - [Rich-Ruby](#rich-ruby)
57
- - [Features](#rich-ruby-features)
58
- - [Quick Start](#rich-ruby-quick-start)
59
- - [Usage Guide](#usage-guide)
60
- - [Requirements](#requirements)
61
- - [Installation](#installation)
62
- - [Documentation](#documentation)
63
- - [License](#license)
64
-
65
- ---
66
-
67
- # asciinema-win
68
-
69
- Record and playback terminal sessions on native Windows with accurate timing and full color support. Export to video formats (GIF, MP4, WebM) using a pure Ruby frame renderer.
70
-
71
- <a name="asciinema-features"></a>
72
- ## Features
73
-
74
- **Core**
75
- - Zero external dependencies (pure Ruby + Fiddle for Win32 API)
76
- - Native Windows Console API access
77
- - asciicast v2 format (compatible with asciinema.org)
78
-
79
- **Recording**
80
- - Screen buffer capture with colors and attributes
81
- - Microsecond-accurate timing
82
- - Idle time limiting
83
- - Command recording mode
84
-
85
- **Export**
86
- - Native: HTML, SVG, Text, JSON (no dependencies)
87
- - Video: GIF, MP4, WebM (requires FFmpeg)
88
- - 9 terminal color themes
89
- - Pure Ruby PPM frame renderer with embedded VGA font
90
-
91
- **Playback**
92
- - Accurate timing reproduction
93
- - Adjustable speed (0.5x to 4x)
94
-
95
- <a name="asciinema-quick-start"></a>
96
- ## Quick Start
97
-
98
- > **Note:** Use the full Ruby path: `C:\RubyMSVC34\bin\ruby.exe`
99
-
100
- ### Record a Terminal Session
101
-
102
- ```powershell
103
- C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win rec session.cast
104
- # Press Ctrl+D to stop recording
105
- ```
106
-
107
- ### Record a Specific Command
108
-
109
- ```powershell
110
- C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win rec -c "dir /s" output.cast
111
- ```
112
-
113
- ### Play Back a Recording
114
-
115
- ```powershell
116
- C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win play session.cast
117
- ```
118
-
119
- ### Play at 2x Speed
120
-
121
- ```powershell
122
- C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win play -s 2 session.cast
123
- ```
124
-
125
- ### Get Recording Info
126
-
127
- ```powershell
128
- C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win info session.cast
129
- ```
130
-
131
- ### Export to HTML
132
-
133
- ```powershell
134
- C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win export session.cast -o session.html
135
- ```
136
-
137
- <a name="cli-reference"></a>
138
- ## CLI Reference
139
-
140
- ### `asciinema_win rec`
141
-
142
- Record a terminal session.
143
-
144
- ```
145
- Usage: asciinema_win rec [options] <filename>
146
-
147
- Options:
148
- -t, --title <title> Recording title
149
- -c, --command <cmd> Record specific command
150
- -i, --idle-time-limit <s> Max idle time (default: 2.0)
151
- -y, --overwrite Overwrite existing file
152
- ```
153
-
154
- ### `asciinema_win play`
155
-
156
- Play back a recording.
157
-
158
- ```
159
- Usage: asciinema_win play [options] <filename>
160
-
161
- Options:
162
- -s, --speed <factor> Playback speed (default: 1.0)
163
- -i, --idle-time-limit <s> Max idle time between frames
164
- -m, --pause-on-markers Pause at marker events
165
- ```
166
-
167
- ### `asciinema_win export`
168
-
169
- Export to other formats.
170
-
171
- ```
172
- Usage: asciinema_win export [options] <filename>
173
-
174
- Formats:
175
- html Standalone HTML with embedded player
176
- svg SVG image snapshot
177
- txt Plain text (ANSI stripped)
178
- json Normalized JSON
179
- gif Animated GIF (requires FFmpeg)
180
- mp4 MP4 video (requires FFmpeg)
181
- webm WebM video (requires FFmpeg)
182
-
183
- Options:
184
- -f, --format <fmt> Output format
185
- -o, --output <file> Output file path
186
- -t, --title <title> Title for HTML export
187
- --fps <n> Frames per second for video (default: 10)
188
- --theme <name> Color theme for video export
189
- --scale <n> Scale factor for video output
190
- ```
191
-
192
- ### `asciinema_win cat`
193
-
194
- Output to stdout without timing.
195
-
196
- ```
197
- Usage: asciinema_win cat <filename>
198
- ```
199
-
200
- ### `asciinema_win info`
201
-
202
- Show recording metadata.
203
-
204
- ```
205
- Usage: asciinema_win info <filename>
206
- ```
207
-
208
- <a name="ruby-api"></a>
209
- ## Ruby API
210
-
211
- ### Recording
212
-
213
- ```ruby
214
- require 'asciinema_win'
215
-
216
- # Record an interactive session
217
- AsciinemaWin.record("session.cast", title: "My Demo")
218
-
219
- # Record a command
220
- AsciinemaWin.record("command.cast", command: "dir /s")
221
- ```
222
-
223
- ### Playback
224
-
225
- ```ruby
226
- require 'asciinema_win'
227
-
228
- # Simple playback
229
- AsciinemaWin.play("session.cast")
230
-
231
- # With options
232
- AsciinemaWin.play("session.cast", speed: 2.0)
233
- ```
234
-
235
- ### Export
236
-
237
- ```ruby
238
- require 'asciinema_win'
239
-
240
- # Export to HTML
241
- AsciinemaWin::Export.export("session.cast", "output.html", format: :html)
242
-
243
- # Export to SVG with theme
244
- AsciinemaWin::Export.export("session.cast", "output.svg", format: :svg, theme: "dracula")
245
- ```
246
-
247
- ### Creating Recordings Programmatically
248
-
249
- ```ruby
250
- require 'asciinema_win'
251
-
252
- AsciinemaWin::Asciicast.create("demo.cast", width: 80, height: 24) do |writer|
253
- writer.write_output(0.0, "Hello ")
254
- writer.write_output(0.5, "\e[32mWorld!\e[0m\r\n")
255
- writer.write_marker(1.0, "greeting done")
256
- end
257
- ```
258
-
259
- <a name="export-formats"></a>
260
- ## Export Formats
261
-
262
- | Format | Extension | Dependencies | Description |
263
- |--------|-----------|--------------|-------------|
264
- | Cast | `.cast` | None | Asciicast v2 (with speed/trim options) |
265
- | HTML | `.html` | None | Standalone page with asciinema-player |
266
- | SVG | `.svg` | None | Colored terminal snapshot with themes |
267
- | Text | `.txt` | None | Plain text with ANSI stripped |
268
- | JSON | `.json` | None | Normalized event data |
269
- | GIF | `.gif` | FFmpeg | Animated GIF (2-pass palette) |
270
- | MP4 | `.mp4` | FFmpeg | H.264 video (yuv420p) |
271
- | WebM | `.webm` | FFmpeg | VP9 video |
272
-
273
- ### Video Export (GIF/MP4/WebM)
274
-
275
- Export recordings to video formats using FFmpeg. Uses a pure Ruby PPM frame
276
- renderer with an embedded 8x16 VGA bitmap font—no external libraries needed
277
- except FFmpeg itself.
278
-
279
- **CLI Examples:**
280
-
281
- ```powershell
282
- # Export to GIF (default 10 FPS)
283
- C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win export demo.cast -o demo.gif
284
-
285
- # Export to GIF with custom FPS and theme
286
- C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win export demo.cast -o demo.gif --fps 15 --theme dracula
287
-
288
- # Export to MP4
289
- C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win export demo.cast -o demo.mp4 --fps 30
290
-
291
- # Export to WebM
292
- C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win export demo.cast -o demo.webm
293
- ```
294
-
295
- **Ruby API:**
296
-
297
- ```ruby
298
- require 'asciinema_win'
299
-
300
- # Export to GIF with options
301
- AsciinemaWin::Export.export("demo.cast", "demo.gif",
302
- format: :gif,
303
- fps: 15,
304
- theme: "dracula"
305
- )
306
-
307
- # Export to MP4
308
- AsciinemaWin::Export.export("demo.cast", "demo.mp4", format: :mp4, fps: 30)
309
-
310
- # Export to WebM
311
- AsciinemaWin::Export.export("demo.cast", "demo.webm", format: :webm)
312
- ```
313
-
314
- > **Note:** GIF export uses 2-pass palette optimization (`palettegen` + `paletteuse`)
315
- > for high-quality output with proper dithering.
316
-
317
- ### Terminal Themes
318
-
319
- SVG exports support multiple color themes:
320
-
321
- - `asciinema` (default)
322
- - `dracula`
323
- - `monokai`
324
- - `solarized-dark`
325
- - `solarized-light`
326
- - `nord`
327
- - `one-dark`
328
- - `github-dark`
329
- - `tokyo-night`
330
-
331
- ```ruby
332
- # Export with Dracula theme
333
- AsciinemaWin::Export.export("demo.cast", "demo.svg", format: :svg, theme: "dracula")
334
-
335
- # List available themes
336
- AsciinemaWin::Themes.names # => ["asciinema", "dracula", "monokai", ...]
337
- ```
338
-
339
- ### Speed Adjustment & Idle Compression
340
-
341
- ```ruby
342
- # Speed up playback 2x
343
- AsciinemaWin::Export.adjust_speed("input.cast", "output.cast", speed: 2.0)
344
-
345
- # Compress idle time to max 0.5s
346
- AsciinemaWin::Export.adjust_speed("input.cast", "output.cast", max_idle: 0.5)
347
-
348
- # Both
349
- AsciinemaWin::Export.adjust_speed("input.cast", "output.cast", speed: 1.5, max_idle: 0.5)
350
- ```
351
-
352
- ### Recording Concatenation
353
-
354
- ```ruby
355
- # Combine multiple recordings
356
- AsciinemaWin::Export.concatenate(
357
- ["part1.cast", "part2.cast", "part3.cast"],
358
- "combined.cast",
359
- title: "Full Demo",
360
- gap: 1.0 # seconds between recordings
361
- )
362
- ```
363
-
364
- ### Thumbnail Generation
365
-
366
- ```ruby
367
- # Generate thumbnail from last frame
368
- AsciinemaWin::Export.thumbnail("demo.cast", "thumb.svg", frame: :last, theme: "dracula")
369
-
370
- # Other frame options: :first, :middle, or specific time in seconds
371
- AsciinemaWin::Export.thumbnail("demo.cast", "thumb.svg", frame: :middle)
372
- AsciinemaWin::Export.thumbnail("demo.cast", "thumb.svg", frame: 5.0) # at 5s
373
- ```
374
-
375
- ### Organized Output
376
-
377
- Use `OutputOrganizer` for structured output directories:
378
-
379
- ```ruby
380
- # Create a session
381
- session = AsciinemaWin::OutputOrganizer.create_session("my_demo")
382
-
383
- # Get paths for various outputs
384
- recording = session.recording_path("demo") # asciinema_output/recordings/my_demo_YYYYMMDD_HHMMSS/demo.cast
385
- svg_path = session.export_path("demo", format: :svg) # asciinema_output/svg/my_demo_YYYYMMDD_HHMMSS/demo.svg
386
- thumb = session.thumbnail_path("demo", frame: :last) # asciinema_output/thumbnails/svg/.../demo_last.svg
387
-
388
- # View session summary
389
- puts session.summary
390
- ```
391
-
392
- Output directory structure:
393
- ```
394
- asciinema_output/
395
- ├── recordings/
396
- │ └── my_demo_20251224_120000/
397
- │ └── demo.cast
398
- ├── svg/
399
- │ └── my_demo_20251224_120000/
400
- ├── demo_asciinema.svg
401
- ├── demo_dracula.svg
402
- └── ...
403
- ├── html/
404
- └── my_demo_20251224_120000/
405
- │ └── demo.html
406
- ├── json/
407
- ├── text/
408
- ├── thumbnails/
409
- │ └── svg/
410
- │ └── my_demo_20251224_120000/
411
- │ ├── demo_first.svg
412
- │ ├── demo_middle.svg
413
- │ └── demo_last.svg
414
- └── video/
415
- ```
416
-
417
- ---
418
-
419
- # Rich-Ruby
420
-
421
- A Pure Ruby library for rich text and beautiful formatting in the terminal.
422
-
423
- <a name="rich-ruby-features"></a>
424
- ## Features
425
-
426
- - **Colors**: 16-color, 256-color, and TrueColor (24-bit)
427
- - **Styles**: Bold, italic, underline, strikethrough, blink, reverse
428
- - **Markup**: `[bold red]text[/]` syntax for inline styling
429
- - **Panels**: Bordered boxes with titles
430
- - **Tables**: Data tables with alignment and styling
431
- - **Trees**: Hierarchical tree views
432
- - **Progress**: Animated progress bars and spinners
433
- - **Syntax**: Code highlighting for Ruby, Python, JavaScript, SQL
434
- - **Markdown**: Render Markdown in the terminal
435
- - **Windows**: Full Windows Console API support
436
-
437
- <a name="rich-ruby-quick-start"></a>
438
- ## Quick Start
439
-
440
- ```ruby
441
- require 'rich'
442
-
443
- # Simple styled output
444
- Rich.print("[bold cyan]Hello[/] [yellow]World![/]")
445
-
446
- # Create a console for more control
447
- console = Rich::Console.new
448
- console.print("Welcome!", style: "bold green")
449
-
450
- # Display a panel
451
- panel = Rich::Panel.new(
452
- "This is important information.",
453
- title: "Notice",
454
- border_style: "cyan"
455
- )
456
- puts panel.render(max_width: 50)
457
-
458
- # Display a table
459
- table = Rich::Table.new(title: "Users")
460
- table.add_column("Name", header_style: "bold")
461
- table.add_column("Role")
462
- table.add_row("Alice", "Admin")
463
- table.add_row("Bob", "User")
464
- puts table.render(max_width: 40)
465
- ```
466
-
467
- <a name="usage-guide"></a>
468
- ## Usage Guide
469
-
470
- ### Colors and Styles
471
-
472
- ```ruby
473
- # Named colors
474
- Rich.print("[red]Error[/] [green]Success[/] [blue]Info[/]")
475
-
476
- # 256 colors
477
- Rich.print("[color(208)]Orange[/]")
478
-
479
- # RGB colors
480
- Rich.print("[rgb(255,100,50)]Custom[/]")
481
-
482
- # Background colors
483
- Rich.print("[white on blue]Highlighted[/]")
484
-
485
- # Styles
486
- Rich.print("[bold]Bold[/] [italic]Italic[/] [underline]Underline[/]")
487
- ```
488
-
489
- ### Panels
490
-
491
- ```ruby
492
- panel = Rich::Panel.new(
493
- "Content here",
494
- title: "Title",
495
- subtitle: "Subtitle",
496
- border_style: "green",
497
- padding: [1, 2]
498
- )
499
- puts panel.render(max_width: 60)
500
- ```
501
-
502
- ### Tables
503
-
504
- ```ruby
505
- table = Rich::Table.new(title: "Data", show_header: true)
506
- table.add_column("ID", justify: :right)
507
- table.add_column("Name", justify: :left)
508
- table.add_column("Value", justify: :center)
509
- table.add_row("1", "Item A", "100")
510
- table.add_row("2", "Item B", "200")
511
- puts table.render
512
- ```
513
-
514
- ### Trees
515
-
516
- ```ruby
517
- tree = Rich::Tree.new("Root")
518
- child1 = tree.add("Child 1")
519
- child1.add("Grandchild 1")
520
- child1.add("Grandchild 2")
521
- tree.add("Child 2")
522
- puts tree.render
523
- ```
524
-
525
- ### Progress Bars
526
-
527
- ```ruby
528
- progress = Rich::Progress.new("Processing", total: 100)
529
- 100.times do |i|
530
- progress.update(i + 1)
531
- sleep(0.05)
532
- end
533
- progress.complete!
534
- ```
535
-
536
- ### Syntax Highlighting
537
-
538
- ```ruby
539
- code = 'def hello; puts "Hello"; end'
540
- syntax = Rich::Syntax.new(code, "ruby", theme: "monokai")
541
- puts syntax.render
542
- ```
543
-
544
- ---
545
-
546
- # Requirements
547
-
548
- - **Ruby**: 3.0+ (tested on 3.4.8 MSVC)
549
- - **Platform**: Windows 10/11 (asciinema-win requires Windows)
550
- - **Dependencies**: None (zero external gems)
551
-
552
- ### Development Environment
553
-
554
- ```
555
- C:\RubyMSVC34 # Ruby installation
556
- C:\Users\#yourusername\vcpkg # Dependencies
557
- C:\Program Files\Microsoft Visual Studio\18\Community # VS 2026
558
- ```
559
-
560
- ---
561
-
562
- # Installation
563
-
564
- ### From Source
565
-
566
- ```powershell
567
- git clone https://github.com/tigel-agm/asciinema-win.git
568
- cd asciinema-win
569
- ```
570
-
571
- ### Build and Install Gem
572
-
573
- ```powershell
574
- C:\RubyMSVC34\bin\gem.cmd build asciinema_win.gemspec
575
- C:\RubyMSVC34\bin\gem.cmd install asciinema_win-0.2.0.gem
576
- ```
577
-
578
- ---
579
-
580
- # Documentation
581
-
582
- - [docs/how-to-use.md](docs/how-to-use.md) - Rich-Ruby usage guide
583
- - [docs/troubleshooting.md](docs/troubleshooting.md) - Solutions for common issues
584
- - [docs/windows-notes.md](docs/windows-notes.md) - Windows-specific details
585
- - [docs/cheat-sheet.md](docs/cheat-sheet.md) - Quick reference
586
-
587
- ---
588
-
589
- # Project Structure
590
-
591
- ```
592
- asciinema-win/
593
- ├── asciinema_win.gemspec # Gem specification
594
- ├── exe/
595
- │ └── asciinema_win # CLI executable
596
- ├── lib/
597
- ├── asciinema_win.rb # asciinema-win entry point
598
- ├── asciinema_win/
599
- ├── version.rb
600
- ├── screen_buffer.rb # Screen capture
601
- ├── asciicast.rb # File format
602
- ├── recorder.rb # Recording engine
603
- ├── player.rb # Playback engine
604
- ├── export.rb # Export formats
605
- └── cli.rb # CLI
606
- │ └── rich/ # Rich-Ruby library
607
- ├── console.rb
608
- ├── text.rb
609
- ├── panel.rb
610
- │ ├── table.rb
611
- │ ├── tree.rb
612
- │ ├── progress.rb
613
- │ ├── syntax.rb
614
- │ ├── markdown.rb
615
- │ └── win32_console.rb # Windows API
616
- ├── examples/
617
- │ ├── test_capture.rb
618
- │ ├── rich_ruby_recording_demo.rb
619
- │ └── create_sample_recording.rb
620
- └── docs/
621
- └── ...
622
- ```
623
-
624
- ---
625
-
626
- # File Format
627
-
628
- asciinema-win uses **asciicast v2** format (newline-delimited JSON):
629
-
630
- ```json
631
- {"version":2,"width":80,"height":24,"timestamp":1735052000,"title":"Demo"}
632
- [0.0,"o","Hello "]
633
- [0.5,"o","\u001b[32mWorld!\u001b[0m\r\n"]
634
- [1.0,"m","marker label"]
635
- ```
636
-
637
- Event types:
638
- - `"o"` - Output (terminal data)
639
- - `"i"` - Input (keyboard)
640
- - `"r"` - Resize (`"80x24"`)
641
- - `"m"` - Marker (bookmark)
642
-
643
- ---
644
-
645
- # License
646
-
647
- MIT License - See [LICENSE](LICENSE)
648
-
649
- ---
650
-
651
- # Credits
652
-
653
- - Inspired by [asciinema](https://asciinema.org)
654
- - Rich-Ruby inspired by Python's [Rich](https://github.com/Textualize/rich)
655
- - Developed on Ruby 3.4.8 (MSVC) on Windows
1
+ # asciinema-win + Rich-Ruby
2
+
3
+ [![Ruby Version](https://img.shields.io/badge/ruby-3.4%2B-cc342d?style=flat-square&logo=ruby&logoColor=white)](https://www.ruby-lang.org/)
4
+ [![Platform](https://img.shields.io/badge/platform-Windows-0078d4?style=flat-square&logo=windows&logoColor=white)](https://github.com/tigel-agm/asciinema-windows)
5
+ [![License](https://img.shields.io/badge/license-MIT-0078d4?style=flat-square)](LICENSE)
6
+ [![Pure Ruby](https://img.shields.io/badge/dependencies-zero-0078d4?style=flat-square)](https://github.com/tigel-agm/asciinema-windows)
7
+ [![RubyGems](https://img.shields.io/gem/v/asciinema_win?style=flat-square&logo=rubygems)](https://rubygems.org/gems/asciinema_win)
8
+
9
+ > **Native Windows Terminal Recorder and Rich Text Library in Pure Ruby**
10
+
11
+ Record terminal sessions, export to GIF/MP4/WebM video, and render beautiful formatted output, all with zero external dependencies (except FFmpeg for video export).
12
+
13
+ ---
14
+
15
+ ## Demo
16
+
17
+ **Rich-Ruby Terminal Recording exported to GIF:**
18
+
19
+ ![Rich-Ruby Demo](rich_demo.gif)
20
+
21
+ The GIF above shows Rich-Ruby components (Panel, Table, Tree, Syntax Highlighting, Progress Bar) rendered correctly with ANSI colors. Created with `examples/rich_ruby_demo.rb` and exported using the pure Ruby PPM frame renderer.
22
+
23
+ <details>
24
+ <summary><strong>Common rendering issues</strong></summary>
25
+
26
+ - **Literal markup tags** if you see `[blue]text[/]` instead of colored text,
27
+ the markup wasn't parsed. Render through `Rich::Console#print` or
28
+ `Rich::Text.from_markup`. All built-in components (Panel, Table, Tree, Syntax)
29
+ parse markup in their content automatically.
30
+ - **Empty progress bar / missing block glyphs** the embedded video-export font
31
+ includes block elements (█ ░ ▒ ▓) and box-drawing characters (since v0.2.0),
32
+ so bars in exported GIF/MP4/WebM render correctly.
33
+
34
+ </details>
35
+
36
+ ---
37
+
38
+ ## Table of Contents
39
+
40
+ - [asciinema-win](#asciinema-win)
41
+ - [Features](#asciinema-features)
42
+ - [Quick Start](#asciinema-quick-start)
43
+ - [CLI Reference](#cli-reference)
44
+ - [Ruby API](#ruby-api)
45
+ - [Export Formats](#export-formats)
46
+ - [Rich-Ruby](#rich-ruby)
47
+ - [Features](#rich-ruby-features)
48
+ - [Quick Start](#rich-ruby-quick-start)
49
+ - [Usage Guide](#usage-guide)
50
+ - [Requirements](#requirements)
51
+ - [Installation](#installation)
52
+ - [Documentation](#documentation)
53
+ - [License](#license)
54
+
55
+ ---
56
+
57
+ # asciinema-win
58
+
59
+ Record and playback terminal sessions on native Windows with accurate timing and full color support. Export to video formats (GIF, MP4, WebM) using a pure Ruby frame renderer.
60
+
61
+ <a name="asciinema-features"></a>
62
+ ## Features
63
+
64
+ **Core**
65
+ - Zero external dependencies (pure Ruby + Fiddle for Win32 API)
66
+ - Native Windows Console API access
67
+ - asciicast v2 format (compatible with asciinema.org)
68
+
69
+ **Recording**
70
+ - Screen buffer capture with colors and attributes
71
+ - Microsecond-accurate timing
72
+ - Idle time limiting
73
+ - Command recording mode
74
+
75
+ **Export**
76
+ - Native: HTML, SVG, Text, JSON (no dependencies)
77
+ - Video: GIF, MP4, WebM (requires FFmpeg)
78
+ - 9 terminal color themes
79
+ - Pure Ruby PPM frame renderer with embedded VGA font
80
+
81
+ **Playback**
82
+ - Accurate timing reproduction
83
+ - Adjustable speed (0.5x to 4x)
84
+
85
+ <a name="asciinema-quick-start"></a>
86
+ ## Quick Start
87
+
88
+ > **Note:** Use the full Ruby path: `C:\RubyMSVC34\bin\ruby.exe`
89
+
90
+ ### Record a Terminal Session
91
+
92
+ ```powershell
93
+ C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win rec session.cast
94
+ # Press Ctrl+D to stop recording
95
+ ```
96
+
97
+ ### Record a Specific Command
98
+
99
+ ```powershell
100
+ C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win rec -c "dir /s" output.cast
101
+ ```
102
+
103
+ ### Play Back a Recording
104
+
105
+ ```powershell
106
+ C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win play session.cast
107
+ ```
108
+
109
+ ### Play at 2x Speed
110
+
111
+ ```powershell
112
+ C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win play -s 2 session.cast
113
+ ```
114
+
115
+ ### Get Recording Info
116
+
117
+ ```powershell
118
+ C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win info session.cast
119
+ ```
120
+
121
+ ### Export to HTML
122
+
123
+ ```powershell
124
+ C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win export session.cast -o session.html
125
+ ```
126
+
127
+ <a name="cli-reference"></a>
128
+ ## CLI Reference
129
+
130
+ ### `asciinema_win rec`
131
+
132
+ Record a terminal session.
133
+
134
+ ```
135
+ Usage: asciinema_win rec [options] <filename>
136
+
137
+ Options:
138
+ -t, --title <title> Recording title
139
+ -c, --command <cmd> Record specific command
140
+ -i, --idle-time-limit <s> Max idle time (default: 2.0)
141
+ -y, --overwrite Overwrite existing file
142
+ ```
143
+
144
+ ### `asciinema_win play`
145
+
146
+ Play back a recording.
147
+
148
+ ```
149
+ Usage: asciinema_win play [options] <filename>
150
+
151
+ Options:
152
+ -s, --speed <factor> Playback speed (default: 1.0)
153
+ -i, --idle-time-limit <s> Max idle time between frames
154
+ -m, --pause-on-markers Pause at marker events
155
+ ```
156
+
157
+ ### `asciinema_win export`
158
+
159
+ Export to other formats.
160
+
161
+ ```
162
+ Usage: asciinema_win export [options] <filename>
163
+
164
+ Formats:
165
+ html Standalone HTML with embedded player
166
+ svg SVG image snapshot
167
+ txt Plain text (ANSI stripped)
168
+ json Normalized JSON
169
+ gif Animated GIF (requires FFmpeg)
170
+ mp4 MP4 video (requires FFmpeg)
171
+ webm WebM video (requires FFmpeg)
172
+
173
+ Options:
174
+ -f, --format <fmt> Output format
175
+ -o, --output <file> Output file path
176
+ -t, --title <title> Title for HTML export
177
+ --fps <n> Frames per second for video (default: 10)
178
+ --theme <name> Color theme for video export
179
+ --scale <n> Scale factor for video output
180
+ ```
181
+
182
+ ### `asciinema_win cat`
183
+
184
+ Output to stdout without timing.
185
+
186
+ ```
187
+ Usage: asciinema_win cat <filename>
188
+ ```
189
+
190
+ ### `asciinema_win info`
191
+
192
+ Show recording metadata.
193
+
194
+ ```
195
+ Usage: asciinema_win info <filename>
196
+ ```
197
+
198
+ <a name="ruby-api"></a>
199
+ ## Ruby API
200
+
201
+ ### Recording
202
+
203
+ ```ruby
204
+ require 'asciinema_win'
205
+
206
+ # Record an interactive session
207
+ AsciinemaWin.record("session.cast", title: "My Demo")
208
+
209
+ # Record a command
210
+ AsciinemaWin.record("command.cast", command: "dir /s")
211
+ ```
212
+
213
+ ### Playback
214
+
215
+ ```ruby
216
+ require 'asciinema_win'
217
+
218
+ # Simple playback
219
+ AsciinemaWin.play("session.cast")
220
+
221
+ # With options
222
+ AsciinemaWin.play("session.cast", speed: 2.0)
223
+ ```
224
+
225
+ ### Export
226
+
227
+ ```ruby
228
+ require 'asciinema_win'
229
+
230
+ # Export to HTML
231
+ AsciinemaWin::Export.export("session.cast", "output.html", format: :html)
232
+
233
+ # Export to SVG with theme
234
+ AsciinemaWin::Export.export("session.cast", "output.svg", format: :svg, theme: "dracula")
235
+ ```
236
+
237
+ ### Creating Recordings Programmatically
238
+
239
+ ```ruby
240
+ require 'asciinema_win'
241
+
242
+ AsciinemaWin::Asciicast.create("demo.cast", width: 80, height: 24) do |writer|
243
+ writer.write_output(0.0, "Hello ")
244
+ writer.write_output(0.5, "\e[32mWorld!\e[0m\r\n")
245
+ writer.write_marker(1.0, "greeting done")
246
+ end
247
+ ```
248
+
249
+ <a name="export-formats"></a>
250
+ ## Export Formats
251
+
252
+ | Format | Extension | Dependencies | Description |
253
+ |--------|-----------|--------------|-------------|
254
+ | Cast | `.cast` | None | Asciicast v2 (with speed/trim options) |
255
+ | HTML | `.html` | None | Standalone page with asciinema-player |
256
+ | SVG | `.svg` | None | Colored terminal snapshot with themes |
257
+ | Text | `.txt` | None | Plain text with ANSI stripped |
258
+ | JSON | `.json` | None | Normalized event data |
259
+ | GIF | `.gif` | FFmpeg | Animated GIF (2-pass palette) |
260
+ | MP4 | `.mp4` | FFmpeg | H.264 video (yuv420p) |
261
+ | WebM | `.webm` | FFmpeg | VP9 video |
262
+
263
+ ### Video Export (GIF/MP4/WebM)
264
+
265
+ Export recordings to video formats using FFmpeg. Uses a pure Ruby PPM frame
266
+ renderer with an embedded 8x16 VGA bitmap font, no external libraries needed
267
+ except FFmpeg itself.
268
+
269
+ **CLI Examples:**
270
+
271
+ ```powershell
272
+ # Export to GIF (default 10 FPS)
273
+ C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win export demo.cast -o demo.gif
274
+
275
+ # Export to GIF with custom FPS and theme
276
+ C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win export demo.cast -o demo.gif --fps 15 --theme dracula
277
+
278
+ # Export to MP4
279
+ C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win export demo.cast -o demo.mp4 --fps 30
280
+
281
+ # Export to WebM
282
+ C:\RubyMSVC34\bin\ruby.exe -Ilib exe\asciinema_win export demo.cast -o demo.webm
283
+ ```
284
+
285
+ **Ruby API:**
286
+
287
+ ```ruby
288
+ require 'asciinema_win'
289
+
290
+ # Export to GIF with options
291
+ AsciinemaWin::Export.export("demo.cast", "demo.gif",
292
+ format: :gif,
293
+ fps: 15,
294
+ theme: "dracula"
295
+ )
296
+
297
+ # Export to MP4
298
+ AsciinemaWin::Export.export("demo.cast", "demo.mp4", format: :mp4, fps: 30)
299
+
300
+ # Export to WebM
301
+ AsciinemaWin::Export.export("demo.cast", "demo.webm", format: :webm)
302
+ ```
303
+
304
+ > **Note:** GIF export uses 2-pass palette optimization (`palettegen` + `paletteuse`)
305
+ > for high-quality output with proper dithering.
306
+
307
+ ### Terminal Themes
308
+
309
+ SVG exports support multiple color themes:
310
+
311
+ - `asciinema` (default)
312
+ - `dracula`
313
+ - `monokai`
314
+ - `solarized-dark`
315
+ - `solarized-light`
316
+ - `nord`
317
+ - `one-dark`
318
+ - `github-dark`
319
+ - `tokyo-night`
320
+
321
+ ```ruby
322
+ # Export with Dracula theme
323
+ AsciinemaWin::Export.export("demo.cast", "demo.svg", format: :svg, theme: "dracula")
324
+
325
+ # List available themes
326
+ AsciinemaWin::Themes.names # => ["asciinema", "dracula", "monokai", ...]
327
+ ```
328
+
329
+ ### Speed Adjustment & Idle Compression
330
+
331
+ ```ruby
332
+ # Speed up playback 2x
333
+ AsciinemaWin::Export.adjust_speed("input.cast", "output.cast", speed: 2.0)
334
+
335
+ # Compress idle time to max 0.5s
336
+ AsciinemaWin::Export.adjust_speed("input.cast", "output.cast", max_idle: 0.5)
337
+
338
+ # Both
339
+ AsciinemaWin::Export.adjust_speed("input.cast", "output.cast", speed: 1.5, max_idle: 0.5)
340
+ ```
341
+
342
+ ### Recording Concatenation
343
+
344
+ ```ruby
345
+ # Combine multiple recordings
346
+ AsciinemaWin::Export.concatenate(
347
+ ["part1.cast", "part2.cast", "part3.cast"],
348
+ "combined.cast",
349
+ title: "Full Demo",
350
+ gap: 1.0 # seconds between recordings
351
+ )
352
+ ```
353
+
354
+ ### Thumbnail Generation
355
+
356
+ ```ruby
357
+ # Generate thumbnail from last frame
358
+ AsciinemaWin::Export.thumbnail("demo.cast", "thumb.svg", frame: :last, theme: "dracula")
359
+
360
+ # Other frame options: :first, :middle, or specific time in seconds
361
+ AsciinemaWin::Export.thumbnail("demo.cast", "thumb.svg", frame: :middle)
362
+ AsciinemaWin::Export.thumbnail("demo.cast", "thumb.svg", frame: 5.0) # at 5s
363
+ ```
364
+
365
+ ### Organized Output
366
+
367
+ Use `OutputOrganizer` for structured output directories:
368
+
369
+ ```ruby
370
+ # Create a session
371
+ session = AsciinemaWin::OutputOrganizer.create_session("my_demo")
372
+
373
+ # Get paths for various outputs
374
+ recording = session.recording_path("demo") # asciinema_output/recordings/my_demo_YYYYMMDD_HHMMSS/demo.cast
375
+ svg_path = session.export_path("demo", format: :svg) # asciinema_output/svg/my_demo_YYYYMMDD_HHMMSS/demo.svg
376
+ thumb = session.thumbnail_path("demo", frame: :last) # asciinema_output/thumbnails/svg/.../demo_last.svg
377
+
378
+ # View session summary
379
+ puts session.summary
380
+ ```
381
+
382
+ Output directory structure:
383
+ ```
384
+ asciinema_output/
385
+ ├── recordings/
386
+ │ └── my_demo_20251224_120000/
387
+ │ └── demo.cast
388
+ ├── svg/
389
+ │ └── my_demo_20251224_120000/
390
+ │ ├── demo_asciinema.svg
391
+ │ ├── demo_dracula.svg
392
+ │ └── ...
393
+ ├── html/
394
+ │ └── my_demo_20251224_120000/
395
+ │ └── demo.html
396
+ ├── json/
397
+ ├── text/
398
+ ├── thumbnails/
399
+ │ └── svg/
400
+ └── my_demo_20251224_120000/
401
+ ├── demo_first.svg
402
+ ├── demo_middle.svg
403
+ │ └── demo_last.svg
404
+ └── video/
405
+ ```
406
+
407
+ ---
408
+
409
+ # Rich-Ruby
410
+
411
+ A Pure Ruby library for rich text and beautiful formatting in the terminal.
412
+
413
+ <a name="rich-ruby-features"></a>
414
+ ## Features
415
+
416
+ - **Colors**: 16-color, 256-color, and TrueColor (24-bit)
417
+ - **Styles**: Bold, italic, underline, strikethrough, blink, reverse
418
+ - **Markup**: `[bold red]text[/]` syntax for inline styling
419
+ - **Panels**: Bordered boxes with titles
420
+ - **Tables**: Data tables with alignment and styling
421
+ - **Trees**: Hierarchical tree views
422
+ - **Progress**: Animated progress bars and spinners
423
+ - **Syntax**: Code highlighting for Ruby, Python, JavaScript, SQL
424
+ - **Markdown**: Render Markdown in the terminal
425
+ - **Windows**: Full Windows Console API support
426
+
427
+ <a name="rich-ruby-quick-start"></a>
428
+ ## Quick Start
429
+
430
+ ```ruby
431
+ require 'rich'
432
+
433
+ # Simple styled output
434
+ Rich.print("[bold cyan]Hello[/] [yellow]World![/]")
435
+
436
+ # Create a console for more control
437
+ console = Rich::Console.new
438
+ console.print("Welcome!", style: "bold green")
439
+
440
+ # Display a panel
441
+ panel = Rich::Panel.new(
442
+ "This is important information.",
443
+ title: "Notice",
444
+ border_style: "cyan"
445
+ )
446
+ puts panel.render(max_width: 50)
447
+
448
+ # Display a table
449
+ table = Rich::Table.new(title: "Users")
450
+ table.add_column("Name", header_style: "bold")
451
+ table.add_column("Role")
452
+ table.add_row("Alice", "Admin")
453
+ table.add_row("Bob", "User")
454
+ puts table.render(max_width: 40)
455
+ ```
456
+
457
+ <a name="usage-guide"></a>
458
+ ## Usage Guide
459
+
460
+ ### Colors and Styles
461
+
462
+ ```ruby
463
+ # Named colors
464
+ Rich.print("[red]Error[/] [green]Success[/] [blue]Info[/]")
465
+
466
+ # 256 colors
467
+ Rich.print("[color(208)]Orange[/]")
468
+
469
+ # RGB colors
470
+ Rich.print("[rgb(255,100,50)]Custom[/]")
471
+
472
+ # Background colors
473
+ Rich.print("[white on blue]Highlighted[/]")
474
+
475
+ # Styles
476
+ Rich.print("[bold]Bold[/] [italic]Italic[/] [underline]Underline[/]")
477
+ ```
478
+
479
+ ### Panels
480
+
481
+ ```ruby
482
+ panel = Rich::Panel.new(
483
+ "Content here",
484
+ title: "Title",
485
+ subtitle: "Subtitle",
486
+ border_style: "green",
487
+ padding: [1, 2]
488
+ )
489
+ puts panel.render(max_width: 60)
490
+ ```
491
+
492
+ ### Tables
493
+
494
+ ```ruby
495
+ table = Rich::Table.new(title: "Data", show_header: true)
496
+ table.add_column("ID", justify: :right)
497
+ table.add_column("Name", justify: :left)
498
+ table.add_column("Value", justify: :center)
499
+ table.add_row("1", "Item A", "100")
500
+ table.add_row("2", "Item B", "200")
501
+ puts table.render
502
+ ```
503
+
504
+ ### Trees
505
+
506
+ ```ruby
507
+ tree = Rich::Tree.new("Root")
508
+ child1 = tree.add("Child 1")
509
+ child1.add("Grandchild 1")
510
+ child1.add("Grandchild 2")
511
+ tree.add("Child 2")
512
+ puts tree.render
513
+ ```
514
+
515
+ ### Progress Bars
516
+
517
+ ```ruby
518
+ progress = Rich::Progress.new("Processing", total: 100)
519
+ 100.times do |i|
520
+ progress.update(i + 1)
521
+ sleep(0.05)
522
+ end
523
+ progress.complete!
524
+ ```
525
+
526
+ ### Syntax Highlighting
527
+
528
+ ```ruby
529
+ code = 'def hello; puts "Hello"; end'
530
+ syntax = Rich::Syntax.new(code, "ruby", theme: "monokai")
531
+ puts syntax.render
532
+ ```
533
+
534
+ ---
535
+
536
+ # Requirements
537
+
538
+ - **Ruby**: 3.0+ (tested on 3.4.8 MSVC)
539
+ - **Platform**: Windows 10/11 (asciinema-win requires Windows)
540
+ - **Dependencies**: None (zero external gems)
541
+
542
+ ### Development Environment
543
+
544
+ ```
545
+ C:\RubyMSVC34 # Ruby installation
546
+ C:\Users\#yourusername\vcpkg # Dependencies
547
+ C:\Program Files\Microsoft Visual Studio\18\Community # VS 2026
548
+ ```
549
+
550
+ ---
551
+
552
+ # Installation
553
+
554
+ ### From Source
555
+
556
+ ```powershell
557
+ git clone https://github.com/tigel-agm/asciinema-win.git
558
+ cd asciinema-win
559
+ ```
560
+
561
+ ### Build and Install Gem
562
+
563
+ ```powershell
564
+ C:\RubyMSVC34\bin\gem.cmd build asciinema_win.gemspec
565
+ C:\RubyMSVC34\bin\gem.cmd install asciinema_win-0.2.0.gem
566
+ ```
567
+
568
+ ---
569
+
570
+ # Documentation
571
+
572
+ - [docs/how-to-use.md](docs/how-to-use.md) - Rich-Ruby usage guide
573
+ - [docs/troubleshooting.md](docs/troubleshooting.md) - Solutions for common issues
574
+ - [docs/windows-notes.md](docs/windows-notes.md) - Windows-specific details
575
+ - [docs/cheat-sheet.md](docs/cheat-sheet.md) - Quick reference
576
+
577
+ ---
578
+
579
+ # Project Structure
580
+
581
+ ```
582
+ asciinema-win/
583
+ ├── asciinema_win.gemspec # Gem specification
584
+ ├── exe/
585
+ │ └── asciinema_win # CLI executable
586
+ ├── lib/
587
+ │ ├── asciinema_win.rb # asciinema-win entry point
588
+ │ ├── asciinema_win/
589
+ │ │ ├── version.rb
590
+ │ │ ├── screen_buffer.rb # Screen capture
591
+ │ │ ├── asciicast.rb # File format
592
+ │ │ ├── recorder.rb # Recording engine
593
+ │ │ ├── player.rb # Playback engine
594
+ │ │ ├── export.rb # Export formats
595
+ └── cli.rb # CLI
596
+ │ └── rich/ # Rich-Ruby library
597
+ ├── console.rb
598
+ ├── text.rb
599
+ ├── panel.rb
600
+ ├── table.rb
601
+ ├── tree.rb
602
+ ├── progress.rb
603
+ ├── syntax.rb
604
+ ├── markdown.rb
605
+ └── win32_console.rb # Windows API
606
+ ├── examples/
607
+ ├── test_capture.rb
608
+ ├── rich_ruby_recording_demo.rb
609
+ └── create_sample_recording.rb
610
+ └── docs/
611
+ └── ...
612
+ ```
613
+
614
+ ---
615
+
616
+ # File Format
617
+
618
+ asciinema-win uses **asciicast v2** format (newline-delimited JSON):
619
+
620
+ ```json
621
+ {"version":2,"width":80,"height":24,"timestamp":1735052000,"title":"Demo"}
622
+ [0.0,"o","Hello "]
623
+ [0.5,"o","\u001b[32mWorld!\u001b[0m\r\n"]
624
+ [1.0,"m","marker label"]
625
+ ```
626
+
627
+ Event types:
628
+ - `"o"` - Output (terminal data)
629
+ - `"i"` - Input (keyboard)
630
+ - `"r"` - Resize (`"80x24"`)
631
+ - `"m"` - Marker (bookmark)
632
+
633
+ ---
634
+
635
+ # License
636
+
637
+ MIT License - See [LICENSE](LICENSE)
638
+
639
+ ---
640
+
641
+ # Credits
642
+
643
+ - Inspired by [asciinema](https://asciinema.org)
644
+ - Rich-Ruby inspired by Python's [Rich](https://github.com/Textualize/rich)
645
+ - Developed on Ruby 3.4.8 (MSVC) on Windows