mtg_card_maker 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -5
- data/README.md +8 -6
- data/lib/mtg_card_maker/base_card.rb +7 -9
- data/lib/mtg_card_maker/cli.rb +28 -28
- data/lib/mtg_card_maker/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: da380956bcd066726ee25156f61eda1ea82071f07a5fa18a10b6eaaf00802351
|
|
4
|
+
data.tar.gz: 3f246516bc68c71485d7edcec625391329a2445b9219f7b79d1e5d28824bb57d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fe45049d937ba11f0f33c5dc37c663107f50df23a68602ceaa22c1a830a2c151ecda86a272e0bfa32b3f4940332eb1add45a0338f37548d28a4ab13835eea668
|
|
7
|
+
data.tar.gz: f006407754e7a65a85aa6d1eecf52c45e1739174ae95f999d9c3f6d7e9d8b8d5389d628b44a4712df5ba1843dd329e9f5b04cb16fdd8f96c4fa695cef642f4b4
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.2.1] - 2026-10-11
|
|
4
|
+
|
|
5
|
+
### 🔄 Changed
|
|
6
|
+
- **All card text fields are optional again.** `name`, `type_line`, and `rules_text` may be omitted or blank in the Ruby API, YAML configuration, and CLI, so vanilla creatures, tokens, and blank frames can be generated. 0.2.0 required all three. When `name` or `type_line` is missing, a warning is printed ("Card has no name or type line") and the card is still generated.
|
|
7
|
+
- **The CLI rejects unknown options.** A misspelled option such as `--nmae` now fails with `Unknown switches "--nmae"` and a suggestion, instead of being ignored and producing a blank card.
|
|
8
|
+
- `add_card` uses the key `card` (then `card_1`, `card_2`, ...) when no name is given.
|
|
9
|
+
|
|
10
|
+
### 🐛 Fixed
|
|
11
|
+
- `generate_sprite` reports `YAML file not found: <path>` for a missing YAML file again, instead of the generic "Failed to generate sprite sheet" error.
|
|
12
|
+
|
|
3
13
|
## [0.2.0] - 2026-10-11
|
|
4
14
|
|
|
5
15
|
### 📜 License
|
|
@@ -9,16 +19,34 @@
|
|
|
9
19
|
- Replaced the bundled Goudy Mediaeval DemiBold font, which is licensed for personal use only, with Goudy Bookletter 1911. Embedded card text renders slightly differently, and SVGs with embedded fonts are about 38 KB larger.
|
|
10
20
|
|
|
11
21
|
### ⚠️ Breaking Changes
|
|
22
|
+
- **Card validation.** The Ruby API and YAML configuration now raise `ArgumentError: Missing required fields` when `name`, `type_line`, or `rules_text` is missing or blank. In 0.1.0 these cards rendered without the missing text. These requirements were removed again in 0.2.1.
|
|
12
23
|
- **Dropped support for Ruby 3.2.** Ruby 3.3 or higher is now required (Ruby 3.2 reached end of life in March 2026).
|
|
13
24
|
|
|
14
25
|
### ✨ Features
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
26
|
+
- **Symbols:** hybrid mana (`{W/U}`, `{2/W}`, `{C/W}`), Phyrexian mana (`{R/P}`, `{W/B/P}`), snow (`{S}`), energy (`{E}`), tap and untap (`{T}`, `{Q}`), `{X}`, and numeric symbols `{0}` through `{99}`, in mana costs and in rules text. Symbols in rules text are rendered inline.
|
|
27
|
+
- **Font embedding option:** `--embed-font` / `--no-embed-font` on the CLI and `embed_font:` in the Ruby API and YAML configuration.
|
|
28
|
+
- **Italic flavor text.**
|
|
29
|
+
- **Quieter, consistent CLI output:** messages go through a new `MtgCardMaker::Logger` (success and info to stdout, warnings and errors to stderr).
|
|
30
|
+
- **viewBox on generated SVGs**, so cards scale correctly when embedded or resized.
|
|
31
|
+
- SVG to WebP conversion script (`bin/svg_to_webp`, experimental, in the source repository only).
|
|
32
|
+
|
|
33
|
+
### 🔄 Changed
|
|
34
|
+
- **Fonts are embedded by default.** Generated cards now embed the card font as base64 (`embed_font` defaults to `true`; pass `--no-embed-font` or `embed_font: false` to opt out). Single-card SVGs are about 95 KB larger. Sprite sheets embed the font once, and only when a card sets `embed_font: true`.
|
|
35
|
+
- **Generated SVG markup:** the rules text CSS class `card-description` is now `card-rules-text`, and the text box gradient ids `<scheme>_description_gradient` are now `<scheme>_text_box_gradient`. Stylesheets that target the old names need updating.
|
|
36
|
+
- **Public Ruby API renames (affects direct users of these classes):**
|
|
37
|
+
- `ColorScheme#description_gradient_*` → `#text_box_gradient_*`
|
|
38
|
+
- `SvgGradientService.description_gradient_id` / `.define_description_gradient` → `.text_box_gradient_id` / `.define_text_box_gradient`
|
|
39
|
+
- `IconService#available_colors` and `#icon_svg` → `#available_icon_types` and `#symbol_svg`; `IconService::ICON_SETS` → `IconService.icon_sets`
|
|
40
|
+
- `LayerConfig#text_positioning_config` → `#text_box_config`; `#mana_cost_font_size`, `#mana_cost_icon_opacity`, `#mana_cost_text_y_offset`, and `#icon_opacity_config` were removed
|
|
41
|
+
- `ColorScheme.silver` and `ManaCost::COLOR_MAP` were removed
|
|
42
|
+
|
|
43
|
+
### 🐛 Fixed
|
|
44
|
+
- Snow and energy symbols no longer corrupt the SVG output.
|
|
45
|
+
- Mana costs combining `X` and a number (for example `X3R`) render correctly.
|
|
46
|
+
- An empty YAML file passed to `generate_sprite` now exits with "Failed to generate sprite sheet" instead of `undefined method 'empty?' for nil`.
|
|
19
47
|
|
|
20
48
|
### 📚 Documentation
|
|
21
|
-
- README updated with
|
|
49
|
+
- README updated with hybrid, Phyrexian, snow, energy, tap, and numeric symbol references, and Markdown docs support; YARD documentation refreshed.
|
|
22
50
|
|
|
23
51
|
## [0.1.0] - 2025-07-12
|
|
24
52
|
|
data/README.md
CHANGED
|
@@ -81,11 +81,11 @@ gem install mtg_card_maker
|
|
|
81
81
|
|
|
82
82
|
**Card Properties:**
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
Every property is optional and hides when omitted. A warning is shown if `name` or `type_line` is missing.
|
|
85
85
|
```yaml
|
|
86
|
-
name: "Card Name" #
|
|
87
|
-
type_line: "Creature - Dragon" #
|
|
88
|
-
rules_text: "Card rules text" #
|
|
86
|
+
name: "Card Name" # Optional (warns when omitted)
|
|
87
|
+
type_line: "Creature - Dragon" # Optional (warns when omitted)
|
|
88
|
+
rules_text: "Card rules text" # Optional
|
|
89
89
|
mana_cost: 2RR # Optional
|
|
90
90
|
flavor_text: "Flavor text" # Optional
|
|
91
91
|
power: 4 # Optional
|
|
@@ -244,6 +244,8 @@ mtg_card_maker add_card deck.yml \
|
|
|
244
244
|
- `g` or `gc` for `generate_card`
|
|
245
245
|
- `a` or `ac` for `add_card`
|
|
246
246
|
|
|
247
|
+
*Misspelled options are rejected* (for example `--nmae` fails with `Unknown switches "--nmae"` and suggests `--name`) rather than silently producing a blank card.
|
|
248
|
+
|
|
247
249
|
### Generate a Sprite Sheet
|
|
248
250
|
|
|
249
251
|
For printing or displaying multiple cards on a webpage, using a sprite sheet is recommended. This approach embeds fonts and gradients once per sheet instead of repeating them for each individual card, improving file size and loading efficiency.
|
|
@@ -269,7 +271,7 @@ mtg_card_maker generate_sprite deck.yml sprite_sheet.svg \
|
|
|
269
271
|
|
|
270
272
|
**⚠️ Experimental Feature - Mac Only**
|
|
271
273
|
|
|
272
|
-
The
|
|
274
|
+
The source repository includes an experimental script, `bin/svg_to_webp`, for converting SVG cards to WebP format using Chrome's headless mode. It is a development script and is **not** part of the published gem, so clone the repository to use it. This feature is currently **Mac-only** and requires specific dependencies.
|
|
273
275
|
|
|
274
276
|
**Why?:**
|
|
275
277
|
It seems a lot more user-friendly for use in things like this README.md file. The file size is bigger and it can't scale so I wouldn't use this option unless something in the SVG isn't working with whatever you are trying to do. You should also report that at https://github.com/joe-sharp/mtg_card_maker/issues . Thanks in advance!
|
|
@@ -278,7 +280,7 @@ It seems a lot more user-friendly for use in things like this README.md file. Th
|
|
|
278
280
|
- **macOS**: Chrome must be installed at `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`
|
|
279
281
|
- **cwebp**: Google's WebP encoder must be installed (install via Homebrew: `brew install webp`)
|
|
280
282
|
|
|
281
|
-
**Usage
|
|
283
|
+
**Usage** (from a clone of the repository):
|
|
282
284
|
```bash
|
|
283
285
|
# Convert a single SVG card to WebP
|
|
284
286
|
bin/svg_to_webp output_card.svg
|
|
@@ -111,10 +111,10 @@ module MtgCardMaker
|
|
|
111
111
|
# Initialize a new card with the given configuration
|
|
112
112
|
#
|
|
113
113
|
# @param config [Hash] the card configuration
|
|
114
|
-
# @option config [String] :name the card name
|
|
114
|
+
# @option config [String] :name the card name (optional, warns when omitted)
|
|
115
115
|
# @option config [String] :mana_cost the mana cost in MTG notation
|
|
116
116
|
# @option config [String] :type_line the card type
|
|
117
|
-
# @option config [String] :rules_text the card rules text
|
|
117
|
+
# @option config [String] :rules_text the card rules text (optional)
|
|
118
118
|
# @option config [String] :flavor_text the flavor text
|
|
119
119
|
# @option config [String] :power the power value for creatures
|
|
120
120
|
# @option config [String] :toughness the toughness value for creatures
|
|
@@ -124,7 +124,7 @@ module MtgCardMaker
|
|
|
124
124
|
# @option config [Boolean] :embed_font whether to embed the font as base64 (default: true)
|
|
125
125
|
def initialize(config)
|
|
126
126
|
assign_attributes(config)
|
|
127
|
-
|
|
127
|
+
warn_about_missing_fields
|
|
128
128
|
@template = Template.new(embed_font: config.fetch(:embed_font, true))
|
|
129
129
|
add_layers
|
|
130
130
|
end
|
|
@@ -187,13 +187,11 @@ module MtgCardMaker
|
|
|
187
187
|
@art = config[:art]
|
|
188
188
|
end
|
|
189
189
|
|
|
190
|
-
def
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
def warn_about_missing_fields
|
|
191
|
+
missing = { name: 'name', type_line: 'type line' }.select { |field, _label| public_send(field).to_s.strip.empty? }
|
|
192
|
+
return if missing.empty?
|
|
193
193
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
raise ArgumentError, "Missing required fields: #{missing_fields.join(', ')}"
|
|
194
|
+
Logger.new.warn("Card has no #{missing.values.join(' or ')}")
|
|
197
195
|
end
|
|
198
196
|
|
|
199
197
|
def define_art_window_mask
|
data/lib/mtg_card_maker/cli.rb
CHANGED
|
@@ -30,6 +30,9 @@ module MtgCardMaker
|
|
|
30
30
|
map 'gcs'=> :generate_sprite
|
|
31
31
|
map 'gs' => :generate_sprite
|
|
32
32
|
|
|
33
|
+
# Fail on misspelled options (for example --nmae) instead of ignoring them
|
|
34
|
+
check_unknown_options!
|
|
35
|
+
|
|
33
36
|
def self.exit_on_failure?
|
|
34
37
|
true
|
|
35
38
|
end
|
|
@@ -39,11 +42,11 @@ module MtgCardMaker
|
|
|
39
42
|
# @return [Hash] the card option definitions for Thor
|
|
40
43
|
def self.card_options
|
|
41
44
|
{
|
|
42
|
-
name: { type: :string,
|
|
45
|
+
name: { type: :string, desc: 'Card name (warns when omitted)' },
|
|
43
46
|
mana_cost: { type: :string, aliases: ['mana', 'cost'], desc: 'Mana cost (e.g., "2RR", "XG")' },
|
|
44
|
-
type_line: { type: :string,
|
|
45
|
-
desc: 'Card type & subtype (e.g., "Creature - Dragon", "Instant")' },
|
|
46
|
-
rules_text: { type: :string,
|
|
47
|
+
type_line: { type: :string, aliases: ['type'],
|
|
48
|
+
desc: 'Card type & subtype (e.g., "Creature - Dragon", "Instant"; warns when omitted)' },
|
|
49
|
+
rules_text: { type: :string, aliases: ['rules'], desc: 'Card rules text (optional)' },
|
|
47
50
|
flavor_text: { type: :string, aliases: ['flavor'], desc: 'Flavor text (optional)' },
|
|
48
51
|
power: { type: :string, desc: 'Power (for creatures)' },
|
|
49
52
|
toughness: { type: :string, desc: 'Toughness (for creatures)' },
|
|
@@ -58,10 +61,10 @@ module MtgCardMaker
|
|
|
58
61
|
|
|
59
62
|
# Generate a single MTG card with specified parameters
|
|
60
63
|
#
|
|
61
|
-
# @option options [String] :name the card name (
|
|
64
|
+
# @option options [String] :name the card name (optional, warns when omitted)
|
|
62
65
|
# @option options [String] :mana_cost the mana cost in MTG notation
|
|
63
|
-
# @option options [String] :type_line the card type (
|
|
64
|
-
# @option options [String] :rules_text the card rules (
|
|
66
|
+
# @option options [String] :type_line the card type (optional, warns when omitted)
|
|
67
|
+
# @option options [String] :rules_text the card rules text (optional)
|
|
65
68
|
# @option options [String] :flavor_text the flavor text
|
|
66
69
|
# @option options [String] :power the power value for creatures
|
|
67
70
|
# @option options [String] :toughness the toughness value for creatures
|
|
@@ -90,6 +93,8 @@ module MtgCardMaker
|
|
|
90
93
|
option :cards_per_row, type: :numeric, default: 4, desc: 'Number of cards per row in sprite'
|
|
91
94
|
option :spacing, type: :numeric, default: 30, desc: 'Spacing between cards in pixels'
|
|
92
95
|
def generate_sprite(yaml_file, output_file)
|
|
96
|
+
abort "❌ YAML file not found: #{yaml_file}" unless File.exist?(yaml_file)
|
|
97
|
+
|
|
93
98
|
config = validate_yaml(yaml_file)
|
|
94
99
|
sprite_service = create_sprite_service
|
|
95
100
|
process_sprite_generation(config, sprite_service, output_file)
|
|
@@ -114,7 +119,7 @@ module MtgCardMaker
|
|
|
114
119
|
|
|
115
120
|
# Save back to file
|
|
116
121
|
File.write(yaml_file, config.to_yaml)
|
|
117
|
-
logger.success("Added card '#{options[:name]}' to #{yaml_file}!")
|
|
122
|
+
logger.success("Added card '#{options[:name] || card_key}' to #{yaml_file}!")
|
|
118
123
|
logger.info("🎴 Key: #{card_key}")
|
|
119
124
|
end
|
|
120
125
|
|
|
@@ -158,17 +163,11 @@ module MtgCardMaker
|
|
|
158
163
|
end
|
|
159
164
|
|
|
160
165
|
def build_card_config_from_options
|
|
161
|
-
config
|
|
162
|
-
add_optional_fields(config)
|
|
163
|
-
config
|
|
166
|
+
build_base_config.tap { |config| add_optional_fields(config) }
|
|
164
167
|
end
|
|
165
168
|
|
|
166
|
-
def
|
|
167
|
-
{
|
|
168
|
-
'name' => options[:name],
|
|
169
|
-
'type_line' => options[:type_line],
|
|
170
|
-
'rules_text' => process_newlines(options[:rules_text])
|
|
171
|
-
}
|
|
169
|
+
def build_base_config
|
|
170
|
+
{ 'name' => options[:name], 'type_line' => options[:type_line] }.compact
|
|
172
171
|
end
|
|
173
172
|
|
|
174
173
|
def add_optional_fields(config)
|
|
@@ -177,10 +176,12 @@ module MtgCardMaker
|
|
|
177
176
|
config[field] = options[field.to_sym] if options.key?(field.to_sym)
|
|
178
177
|
end
|
|
179
178
|
|
|
180
|
-
|
|
181
|
-
|
|
179
|
+
add_text_fields(config)
|
|
180
|
+
end
|
|
182
181
|
|
|
183
|
-
|
|
182
|
+
# Text fields are handled separately to process newlines
|
|
183
|
+
def add_text_fields(config)
|
|
184
|
+
%i[rules_text flavor_text].each { |f| config[f.to_s] = process_newlines(options[f]) if options[f] }
|
|
184
185
|
end
|
|
185
186
|
|
|
186
187
|
def process_newlines(text)
|
|
@@ -209,16 +210,15 @@ module MtgCardMaker
|
|
|
209
210
|
end
|
|
210
211
|
|
|
211
212
|
def generate_card_key(name, config)
|
|
212
|
-
base_key = name.downcase.gsub(/[^a-z0-9]/, '_').squeeze('_').chomp('_')
|
|
213
|
+
base_key = name.to_s.downcase.gsub(/[^a-z0-9]/, '_').squeeze('_').chomp('_')
|
|
214
|
+
base_key = 'card' if base_key.empty?
|
|
213
215
|
|
|
214
216
|
# If key already exists, append a number
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
base_key
|
|
221
|
-
end
|
|
217
|
+
return base_key unless config.key?(base_key)
|
|
218
|
+
|
|
219
|
+
counter = 1
|
|
220
|
+
counter += 1 while config.key?("#{base_key}_#{counter}")
|
|
221
|
+
"#{base_key}_#{counter}"
|
|
222
222
|
end
|
|
223
223
|
end
|
|
224
224
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mtg_card_maker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- joe-sharp
|
|
@@ -192,7 +192,7 @@ licenses:
|
|
|
192
192
|
metadata:
|
|
193
193
|
license: MIT
|
|
194
194
|
homepage_uri: https://github.com/joe-sharp/mtg_card_maker
|
|
195
|
-
source_code_uri: https://github.com/joe-sharp/mtg_card_maker/tree/v0.2.
|
|
195
|
+
source_code_uri: https://github.com/joe-sharp/mtg_card_maker/tree/v0.2.1
|
|
196
196
|
bug_tracker_uri: https://github.com/joe-sharp/mtg_card_maker/issues
|
|
197
197
|
changelog_uri: https://github.com/joe-sharp/mtg_card_maker/blob/main/CHANGELOG.md
|
|
198
198
|
rubygems_mfa_required: 'true'
|