https://github.com/kperreau/wordsubgen
A Go library and CLI tool for generating ASS (Advanced SubStation Alpha) subtitle files with word-by-word fade-in effects. Perfect for creating dynamic subtitles where words appear sequentially with smooth fade transitions.
https://github.com/kperreau/wordsubgen
advanced-substation-alpha ass cli fade-in go golang karaoke ssa subtitles text-animation word-by-word
Last synced: 14 days ago
JSON representation
A Go library and CLI tool for generating ASS (Advanced SubStation Alpha) subtitle files with word-by-word fade-in effects. Perfect for creating dynamic subtitles where words appear sequentially with smooth fade transitions.
- Host: GitHub
- URL: https://github.com/kperreau/wordsubgen
- Owner: kperreau
- License: mit
- Created: 2025-09-17T15:15:39.000Z (21 days ago)
- Default Branch: main
- Last Pushed: 2025-09-18T11:19:55.000Z (20 days ago)
- Last Synced: 2025-09-21T03:57:16.679Z (18 days ago)
- Topics: advanced-substation-alpha, ass, cli, fade-in, go, golang, karaoke, ssa, subtitles, text-animation, word-by-word
- Language: Go
- Homepage:
- Size: 6 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# wordsubgen
A Go library and CLI tool for generating ASS (Advanced SubStation Alpha) subtitle files with word-by-word fade-in effects. Perfect for creating dynamic subtitles where words appear sequentially with smooth fade transitions.
## Features
- **Word-by-word fade effects**: Each word fades in sequentially using ASS `\alpha` tags
- **Karaoke support**: Optional karaoke mode with `\k` tags for word highlighting
- **Shadow effects**: Customizable shadow with directional control using `\xshad` and `\yshad` tags
- **Flexible configuration**: Customizable fonts, colors, timing, alignment, and styling
- **Library API**: Use as a Go library in your own projects
- **CLI tool**: Easy-to-use command-line interface with structured logging## Demo
Here's a visual example of the word-by-word fade effect generated by wordsubgen:

This demo was generated using the following command:
```bash
wordsubgen --lines "This is a super test|Hello world \!" --font "Outfit" --fontsize 85 --shadow-enabled --shadow-x 3 --shadow-y 8 --width 1080 --height 734 --out subtitle.ass
```## Installation
### CLI Tool Installation
To install the command-line tool:
```bash
go install github.com/kperreau/wordsubgen/cmd/wordsubgen@latest
```### Package Installation (for Go projects)
To use wordsubgen as a library in your Go project:
```bash
go get github.com/kperreau/wordsubgen@latest
```Then import it in your Go code:
```go
import "github.com/kperreau/wordsubgen"
```### Development Installation
For development work on the wordsubgen project itself:
```bash
git clone https://github.com/kperreau/wordsubgen.git
cd wordsubgen
make deps
make build
```Or install the CLI to your GOPATH/bin:
```bash
make install # Installs to GOPATH/bin
```### Requirements
- **Go 1.25.0+**: Required for building from source
- **Make**: Required for using the Makefile (optional, you can use `go build` directly)## Quick Start
### CLI Usage
Generate subtitles from command line:
```bash
# Basic usage
wordsubgen --lines "Hello world|This is a test" --out subtitle.ass# Custom styling
wordsubgen --lines "Hello world" --color "#FF0000" --fontsize 72 --delay 500# Karaoke mode
wordsubgen --lines "Hello world" --karaoke --delay 400# From file
wordsubgen --file input.txt --out subtitle.ass# Show help with current default values
wordsubgen --help
```### Library Usage
```go
package mainimport (
"log"
"github.com/kperreau/wordsubgen"
)func main() {
// Create configuration
cfg := wordsubgen.DefaultConfig()
cfg.FontSize = 48
cfg.PrimaryColor = wordsubgen.ColorToASS("#FF0000")
cfg.PerWordDelay = 500// Enable shadow with diagonal direction (more downward than sideways)
cfg.ShadowEnabled = true
cfg.ShadowX = 3 // Horizontal offset
cfg.ShadowY = 8 // Vertical offset (more downward)// Generate ASS content
lines := []string{"Hello world", "This is a test"}
content, err := wordsubgen.GenerateASS(cfg, lines)
if err != nil {
log.Fatal(err)
}// Write to file
err = wordsubgen.WriteASS("output.ass", content, cfg.Logger)
if err != nil {
log.Fatal(err)
}
}
```## Flexible Logging Interface
wordsubgen features a flexible logging interface that allows you to inject your own logger implementation. The library comes with several built-in loggers and supports popular logging libraries like zerolog (recommended), logrus, and others.
### Built-in Loggers
```go
// Default logger (uses Go's standard log package)
cfg.Logger = wordsubgen.NewDefaultLogger()// No-operation logger (silent, useful for tests)
cfg.Logger = wordsubgen.NewNoOpLogger()
```### Custom Logger Implementation
```go
type MyCustomLogger struct{}func (l *MyCustomLogger) Debug(msg string, fields ...wordsubgen.Field) {
// Your debug implementation
}func (l *MyCustomLogger) Info(msg string, fields ...wordsubgen.Field) {
// Your info implementation
}func (l *MyCustomLogger) Error(msg string, fields ...wordsubgen.Field) {
// Your error implementation
}func (l *MyCustomLogger) Warn(msg string, fields ...wordsubgen.Field) {
// Your warning implementation
}// Use your custom logger
cfg.Logger = &MyCustomLogger{}
```### Logging Features
- **Structured logging**: Support for key-value fields
- **Multiple log levels**: Debug, Info, Error, Warn
- **Zero dependencies**: No forced logging library dependencies
- **Flexible**: Easy to integrate with any logging system
- **zerolog support**: Recommended for high-performance structured logging## Configuration Reference
### Video Settings
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `Width` | int | 1080 | Video width in pixels |
| `Height` | int | 1920 | Video height in pixels |### Font Settings
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `FontName` | string | "Arial" | Font family name |
| `FontSize` | int | 64 | Font size in points |### Colors (ASS format: &H00BBGGRR)
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `PrimaryColor` | string | "&H00FFFFFF" | Text color (white) |
| `SecondaryColor` | string | "&H0000FFFF" | Karaoke highlight color (yellow) |
| `OutlineColor` | string | "&H00000000" | Outline color (black) |
| `BackColor` | string | "&H64000000" | Background color (semi-transparent) |> **Color Conversion**: Use `ColorToASS()` to convert hex colors (#RRGGBB) to ASS format, and `ColorToHex()` to convert ASS colors back to hex format.
### Style Settings
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `Bold` | bool | true | Bold text |
| `Italic` | bool | false | Italic text |
| `Underline` | bool | false | Underlined text |
| `StrikeOut` | bool | false | Strikethrough text |### Scaling and Spacing
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `ScaleX` | int | 100 | Horizontal scale (%) |
| `ScaleY` | int | 100 | Vertical scale (%) |
| `Spacing` | int | 0 | Character spacing |
| `Angle` | int | 0 | Text rotation angle |### Border and Shadow
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `BorderStyle` | int | 1 | Border style (1=outline, 3=box) |
| `Outline` | int | 4 | Outline width |
| `Shadow` | int | 0 | Shadow width |### Shadow Effects
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `ShadowEnabled` | bool | false | Enable/disable shadow effect |
| `ShadowX` | int | 3 | Horizontal shadow offset (-50 to 50) |
| `ShadowY` | int | 8 | Vertical shadow offset (-50 to 50) |> **Shadow Direction**: Positive values move the shadow right (X) and down (Y). Negative values move left and up. The default values (X=3, Y=8) create a diagonal shadow that's more downward than sideways.
### Alignment
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `Alignment` | int | 2 | Text alignment (1=bottom-left, 2=bottom-center, 3=bottom-right, etc.) |### Margins
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `MarginL` | int | 40 | Left margin |
| `MarginR` | int | 40 | Right margin |
| `MarginV` | int | 120 | Vertical margin |### Timing Settings
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `PerWordDelay` | int | 300 | Delay between words (milliseconds) |
| `FadeDuration` | int | 140 | Fade duration (milliseconds) |
| `LineHold` | int | 2000 | Line hold duration (milliseconds) |
| `LineGap` | int | 0 | Gap between lines (milliseconds) |### Features
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `Karaoke` | bool | false | Enable karaoke mode |### Encoding
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `Encoding` | int | 1 | Text encoding (1=ANSI, 0=Unicode) |## CLI Reference
> **Note**: All default values are dynamically generated from the `DefaultConfig()` function. Use `--help` to see the current default values.
### Input Options
- `--lines string`: Input lines separated by `|` (e.g., 'Hello world|Second line')
- `--file string`: Input file with lines (one per line)### Output Options
- `--out string`: Output ASS file path (default: output.ass)
### Video Settings
- `--width int`: Video width (default: 1080)
- `--height int`: Video height (default: 1920)### Font Settings
- `--font string`: Font name (default: Arial)
- `--fontsize int`: Font size (default: 64)### Colors (hex format)
- `--color string`: Primary text color (default: #FFFFFF)
- `--secondary string`: Secondary color for karaoke (default: #FFFF00)
- `--outline string`: Outline color (default: #000000)
- `--background string`: Background color in ASS format (default: #64000000)### Style Settings
- `--bold`: Bold text (default: true)
- `--italic`: Italic text (default: false)
- `--underline`: Underline text (default: false)
- `--strikeout`: Strikeout text (default: false)### Scaling
- `--scalex int`: Horizontal scale % (default: 100)
- `--scaley int`: Vertical scale % (default: 100)
- `--spacing int`: Character spacing (default: 0)
- `--angle int`: Text angle (default: 0)### Border and Shadow
- `--borderstyle int`: Border style (default: 1)
- `--outlinewidth int`: Outline width (default: 4)
- `--shadow int`: Shadow width (default: 0)### Shadow Effects
- `--shadow-enabled`: Enable shadow effect (default: false)
- `--shadow-x int`: Horizontal shadow offset (default: 3)
- `--shadow-y int`: Vertical shadow offset (default: 8)### Alignment
- `--alignment int`: Text alignment (1=bottom-left, 2=bottom-center, 3=bottom-right, etc.) (default: 2)
### Margins
- `--marginl int`: Left margin (default: 40)
- `--marginr int`: Right margin (default: 40)
- `--marginv int`: Vertical margin (default: 120)### Timing
- `--delay int`: Delay between words in ms (default: 300)
- `--fade int`: Fade duration in ms (default: 140)
- `--hold int`: Line hold duration in ms (default: 2000)
- `--gap int`: Gap between lines in ms (default: 0)### Features
- `--karaoke`: Enable karaoke mode (default: false)
### Other
- `--help`: Show help with current default values
## Examples
### Basic Example
```bash
wordsubgen --lines "Hello world|This is a test" --out subtitle.ass
```### Custom Styling
```bash
wordsubgen --lines "Hello world" --fontsize 48 --color "#FF0000" --bold
```### Karaoke Mode
```bash
wordsubgen --lines "Hello world" --karaoke --delay 500
```### From File
```bash
echo -e "First line\nSecond line\nThird line" > input.txt
wordsubgen --file input.txt --out subtitle.ass
```### Shadow Effects
```bash
# Diagonal shadow (more downward than sideways)
wordsubgen --lines "Hello world" --shadow-enabled --shadow-x 3 --shadow-y 8# Horizontal shadow (more sideways)
wordsubgen --lines "Hello world" --shadow-enabled --shadow-x 8 --shadow-y 3# No shadow (explicitly disabled)
wordsubgen --lines "Hello world" --shadow-enabled=false
```### Quick Demo with Makefile
```bash
# Generate sample files
make run-cli # Basic sample
make run-cli-custom # Custom styling
make run-cli-karaoke # Karaoke mode
```## Development
### Project Structure
```
wordsubgen/
├── cmd/wordsubgen/
│ ├── main.go # CLI application entry point
│ └── wordsubgen # Built binary (after make build)
├── assets/ # Assets
│ └── example.gif # Demo animation
├── config.go # Configuration and validation
├── config_test.go # Configuration tests
├── generator.go # ASS generation logic
├── generator_test.go # Generator tests
├── integration_test.go # Integration tests
├── logger.go # Flexible logging interface
├── logger_test.go # Logger tests
├── writer.go # File I/O operations
├── writer_test.go # Writer tests
├── go.mod # Go module definition
├── go.sum # Go module checksums
├── Makefile # Build automation
├── README.md # Documentation
├── LICENSE # MIT License
├── input.txt # Sample input file
├── subs.exemple.ass # Example subtitle file
└── subtitle.ass # Generated subtitle file
```### Building
```bash
make build # Build CLI binary
make install # Install CLI to GOPATH/bin
make clean # Clean build artifacts
```### Testing
```bash
make test # Run all tests
make test-coverage # Run tests with coverage report
make check # Run fmt, lint, and test
```### Running Examples
```bash
make run-cli # Run CLI with sample input
make run-cli-custom # Run CLI with custom styling
make run-cli-karaoke # Run CLI with karaoke mode
```### Code Quality
```bash
make fmt # Format code
make lint # Lint code
make deps # Install dependencies
```### Development Workflow
```bash
make dev # Complete dev workflow: deps, fmt, lint, test, build
make release # Build release binaries for multiple platforms
```### Available Make Targets
```bash
make help # Show all available targets
```### Testing
The project includes test coverage:
- **Unit tests**: Individual component testing (`*_test.go` files)
Run tests with:
```bash
make test # Run all tests
make test-coverage # Generate coverage report
make ci-test # Run all tests for ci
```## Usage Examples
### Basic Library Usage with Custom Logger
```go
package mainimport (
"log"
"github.com/kperreau/wordsubgen"
)func main() {
// Create configuration with custom logger
cfg := wordsubgen.DefaultConfig()
cfg.Logger = wordsubgen.NewDefaultLogger() // or your custom logger
// Generate subtitles
lines := []string{"Hello world", "This is a test"}
content, err := wordsubgen.GenerateASS(cfg, lines)
if err != nil {
log.Fatal(err)
}
// Write to file
err = wordsubgen.WriteASS("output.ass", content, cfg.Logger)
if err != nil {
log.Fatal(err)
}
}
```### CLI with Help
```bash
# Show help with current default values
wordsubgen --help
```This will display all available options with their current default values, which are dynamically generated from the `DefaultConfig()` function.
## ASS Format Details
The generated ASS files follow the Advanced SubStation Alpha v4.00+ format with:
- **Script Info**: Basic metadata and video resolution
- **V4+ Styles**: Font, color, and styling definitions
- **Events**: Dialogue lines with timing and effects### Word Fade Effect
Each word uses the `\alpha` tag for fade effects:
```
{\alpha&HFF&\t(start,end,\alpha&H00&)}word
```Where:
- `\alpha&HFF&`: Start invisible (fully transparent)
- `\t(start,end,\alpha&H00&)`: Transition to visible over time
- `start,end`: Timing in milliseconds### Karaoke Effect
When karaoke mode is enabled, words also include `\k` tags:
```
{\k100}word
```Where `100` is the duration in centiseconds.
### Shadow Effect
When shadow is enabled, text includes `\xshad` and `\yshad` tags:
```
{\xshad3\yshad8}word
```Where:
- `\xshad3`: Horizontal shadow offset of 3 pixels
- `\yshad8`: Vertical shadow offset of 8 pixelsThis creates a diagonal shadow that's more downward than sideways, as requested in the original specification.
## Key Benefits
- **🎯 Simple Structure**: Clean, flat project structure with all source files at the root
- **🔌 Flexible Logging**: Injectable logger interface supporting multiple logging libraries
- **⚡ Zero Dependencies**: Core library has no forced external dependencies
- **📝 Structured Logging**: Built-in support for structured logging with key-value fields
- **🛠️ Easy Integration**: Simple API that works with any Go project
- **🎨 Rich Configuration**: Extensive customization options for fonts, colors, timing, and styling
- **📊 Performance**: Optimized for performance with zero-allocation logging options
- **🔧 Developer Friendly**: Comprehensive CLI with verbose logging and helpful error messages
- **🔄 Consistent Defaults**: CLI flags automatically use configuration defaults, ensuring consistency
- **🎨 Color Conversion**: Built-in functions to convert between hex and ASS color formats
- **🌍 Encoding Support**: Built-in support for different text encodings (ANSI/Unicode)## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Contributing
We welcome contributions! Please follow these steps:
1. Fork the repository
2. Create a feature branch (`git checkout -b feat/amazing-feature`)
3. Make your changes
4. Add tests if applicable
5. Run the test suite (`make test`)
6. Commit your changes (`git commit -m 'feat: add some amazing feature'`)
7. Push to the branch (`git push origin feat/amazing-feature`)
8. Open a Pull Request### Development Guidelines
- Follow Go best practices and conventions
- Add tests for new functionality
- Update documentation as needed
- Use the provided Makefile targets for consistency
- Ensure all tests pass before submitting