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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7fa254f0344ffc52479fb2be5aae9a6f0486b9ebff42b684156260bfe4814879
4
- data.tar.gz: 34cdc3ed5192c5e89e7a4e0d58260f5276fbfa920a48e286c9638757e301342c
3
+ metadata.gz: da380956bcd066726ee25156f61eda1ea82071f07a5fa18a10b6eaaf00802351
4
+ data.tar.gz: 3f246516bc68c71485d7edcec625391329a2445b9219f7b79d1e5d28824bb57d
5
5
  SHA512:
6
- metadata.gz: cf7b3b64a9c76fcb695571a3320cc5fdf9746c7719f411eb3ebaaa9d64573aec3862990f99b0818b754ed6b62191ff40b73d7997536328fc85e35f2b9a286626
7
- data.tar.gz: ebc7ed18847e53e800e9fe2b7156e82ad470ac22984c2f418a8e662680f63a1bd46693808f804295408c185014760e05a3a0e7898517ae7fa07dbd29777591a7
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
- - Hybrid and Phyrexian mana symbol support, with a new `IconFilenameService` for symbol mapping
16
- - SVG to WebP conversion script (experimental)
17
- - Italicized flavor text
18
- - Improved SVG initialization and viewBox scaling in card rendering
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 new symbols and Markdown docs support; YARD documentation refreshed
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
- Optionals without a default hide when omitted.
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" # Required
87
- type_line: "Creature - Dragon" # Required
88
- rules_text: "Card rules text" # Required
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 gem includes experimental support for converting SVG cards to WebP format using Chrome's headless mode. This feature is currently **Mac-only** and requires specific dependencies.
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
- validate_required_fields
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 validate_required_fields
191
- required_fields = %i[name type_line rules_text]
192
- missing_fields = required_fields.select { |field| send(field).nil? || send(field).to_s.strip.empty? }
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
- return if missing_fields.empty?
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
@@ -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, required: true, desc: 'Card name' },
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, required: true, aliases: ['type'],
45
- desc: 'Card type & subtype (e.g., "Creature - Dragon", "Instant")' },
46
- rules_text: { type: :string, required: true, aliases: ['rules'], desc: 'Card rules text' },
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 (required)
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 (required)
64
- # @option options [String] :rules_text the card rules (required)
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 = build_required_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 build_required_config
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
- # Handle flavor_text separately to process newlines
181
- return unless options[:flavor_text]
179
+ add_text_fields(config)
180
+ end
182
181
 
183
- config['flavor_text'] = process_newlines(options[:flavor_text])
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
- if config.key?(base_key)
216
- counter = 1
217
- counter += 1 while config.key?("#{base_key}_#{counter}")
218
- "#{base_key}_#{counter}"
219
- else
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
@@ -3,6 +3,6 @@
3
3
  module MtgCardMaker
4
4
  MAJOR = 0
5
5
  MINOR = 2
6
- PATCH = 0
6
+ PATCH = 1
7
7
  VERSION = [MAJOR, MINOR, PATCH].join('.')
8
8
  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.0
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.0
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'