colorset_generator 0.1.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.
- checksums.yaml +7 -0
- data/bin/colorset_generator +34 -0
- data/lib/colorset_generator.rb +140 -0
- metadata +63 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: f2a65e2140c63b80c428875344ccfffc9095a7f7d99131d91d71f81178d6a1cf
|
|
4
|
+
data.tar.gz: 123f72d2300ad118a0d2b6384cbaf7a59f20a9f896e17680fa78ba9755f94fdd
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 00c4f31625cfcb5a3825578da439cce326697335e7f60e3853fc1eaa83ad02ca170c64d039194747e01755e886b8d895b8e42ff5e3476f30b622e63f20f5cd6a
|
|
7
|
+
data.tar.gz: 4ae500fa55c996ec19988d69e984099582a2e5e52011738e73f05000313ceca1b14215615ebd52e90486d6ebbdddf8f88f994960b2a6901e99a311ee3e464100
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
$LOAD_PATH.unshift File.join(__dir__, '..', 'lib')
|
|
5
|
+
require 'colorset_generator'
|
|
6
|
+
|
|
7
|
+
if ARGV.empty?
|
|
8
|
+
puts <<~USAGE
|
|
9
|
+
Usage: colorset_generator <URL> [options]
|
|
10
|
+
|
|
11
|
+
Options:
|
|
12
|
+
--dark Generate Light/Dark variant ColorSets (default: on)
|
|
13
|
+
--no-dark Generate Light-only ColorSets
|
|
14
|
+
--output DIR Output directory (default: Colors.xcassets)
|
|
15
|
+
|
|
16
|
+
Supported sites:
|
|
17
|
+
Huemint https://huemint.com/brand-2/#palette=2a3031-fafdfc-a19985
|
|
18
|
+
RealtimeColors https://www.realtimecolors.com/?colors=14140f-f8f8f6-9a9e79-aec4bd-8ea7ad&fonts=Inter-Inter
|
|
19
|
+
Coolors https://coolors.co/c4f1be-a2c3a4-869d96-525b76-201e50
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
colorset_generator "https://huemint.com/brand-2/#palette=2a3031-fafdfc-a19985"
|
|
23
|
+
colorset_generator "https://coolors.co/c4f1be-a2c3a4-869d96-525b76-201e50" --output MyPalette.xcassets
|
|
24
|
+
USAGE
|
|
25
|
+
exit 1
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
url = ARGV[0]
|
|
29
|
+
dark_mode = !ARGV.include?('--no-dark')
|
|
30
|
+
output_idx = ARGV.index('--output')
|
|
31
|
+
output_dir = output_idx ? ARGV[output_idx + 1] : 'Colors.xcassets'
|
|
32
|
+
|
|
33
|
+
success = ColorsetGenerator.generate(url, output_dir: output_dir, dark_mode: dark_mode)
|
|
34
|
+
exit(success ? 0 : 1)
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'uri'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
module ColorsetGenerator
|
|
7
|
+
VERSION = '0.1.0'
|
|
8
|
+
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def hex_to_rgb_int(hex_color)
|
|
12
|
+
hex = hex_color.delete_prefix('#')
|
|
13
|
+
[hex[0..1].to_i(16), hex[2..3].to_i(16), hex[4..5].to_i(16)]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def hex_to_rgb_float(hex_color)
|
|
17
|
+
hex_to_rgb_int(hex_color).map { |v| v / 255.0 }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def rgb_to_hsl(r, g, b)
|
|
21
|
+
max = [r, g, b].max
|
|
22
|
+
min = [r, g, b].min
|
|
23
|
+
delta = max - min
|
|
24
|
+
l = (max + min) / 2.0
|
|
25
|
+
|
|
26
|
+
if delta.zero?
|
|
27
|
+
[0, 0, l * 100]
|
|
28
|
+
else
|
|
29
|
+
s = l > 0.5 ? delta / (2.0 - max - min) : delta / (max + min)
|
|
30
|
+
h = case max
|
|
31
|
+
when r then ((g - b) / delta + (g < b ? 6 : 0)) / 6.0
|
|
32
|
+
when g then ((b - r) / delta + 2) / 6.0
|
|
33
|
+
when b then ((r - g) / delta + 4) / 6.0
|
|
34
|
+
end
|
|
35
|
+
[h * 360, s * 100, l * 100]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def hsl_to_rgb(h, s, l)
|
|
40
|
+
h /= 360.0; s /= 100.0; l /= 100.0
|
|
41
|
+
return [l, l, l] if s.zero?
|
|
42
|
+
|
|
43
|
+
q = l < 0.5 ? l * (1 + s) : l + s - l * s
|
|
44
|
+
p = 2 * l - q
|
|
45
|
+
[hue_to_rgb(p, q, h + 1.0 / 3.0), hue_to_rgb(p, q, h), hue_to_rgb(p, q, h - 1.0 / 3.0)]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def hue_to_rgb(p, q, t)
|
|
49
|
+
t += 1 if t < 0
|
|
50
|
+
t -= 1 if t > 1
|
|
51
|
+
return p + (q - p) * 6 * t if t < 1.0 / 6.0
|
|
52
|
+
return q if t < 1.0 / 2.0
|
|
53
|
+
return p + (q - p) * (2.0 / 3.0 - t) * 6 if t < 2.0 / 3.0
|
|
54
|
+
p
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def rgb_to_hex(r, g, b)
|
|
58
|
+
format('#%02x%02x%02x', (r * 255).round, (g * 255).round, (b * 255).round)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Generate dark variant by inverting HSL lightness
|
|
62
|
+
def invert_color(hex_color)
|
|
63
|
+
r, g, b = hex_to_rgb_float(hex_color)
|
|
64
|
+
h, s, l = rgb_to_hsl(r, g, b)
|
|
65
|
+
r2, g2, b2 = hsl_to_rgb(h, s, 100 - l)
|
|
66
|
+
rgb_to_hex(r2, g2, b2)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def create_colorset_json(light_hex, dark_hex = nil)
|
|
70
|
+
lr, lg, lb = hex_to_rgb_int(light_hex)
|
|
71
|
+
|
|
72
|
+
colors = [
|
|
73
|
+
{ color: { 'color-space': 'srgb', components: { alpha: '1.000', blue: lb.to_s, green: lg.to_s, red: lr.to_s } }, idiom: 'universal' },
|
|
74
|
+
{ appearances: [{ appearance: 'luminosity', value: 'light' }],
|
|
75
|
+
color: { 'color-space': 'srgb', components: { alpha: '1.000', blue: lb.to_s, green: lg.to_s, red: lr.to_s } }, idiom: 'universal' }
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
if dark_hex
|
|
79
|
+
dr, dg, db = hex_to_rgb_int(dark_hex)
|
|
80
|
+
colors << {
|
|
81
|
+
appearances: [{ appearance: 'luminosity', value: 'dark' }],
|
|
82
|
+
color: { 'color-space': 'srgb', components: { alpha: '1.000', blue: db.to_s, green: dg.to_s, red: dr.to_s } },
|
|
83
|
+
idiom: 'universal'
|
|
84
|
+
}
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
{ colors: colors, info: { author: 'xcode', version: 1 } }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def extract_palette_from_url(url)
|
|
91
|
+
if url.include?('huemint.com')
|
|
92
|
+
fragment = URI.parse(url).fragment || ''
|
|
93
|
+
match = fragment.match(/palette=([0-9a-fA-F-]+)/)
|
|
94
|
+
match ? match[1].split('-').map { |c| "##{c}" } : []
|
|
95
|
+
else
|
|
96
|
+
query = URI.parse(url).query || ''
|
|
97
|
+
match = query.match(/colors=([0-9a-fA-F-]+)/)
|
|
98
|
+
match ? match[1].split('-').map { |c| "##{c}" } : []
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
COLOR_LABELS = %w[Text Background Primary Secondary Accent].freeze
|
|
103
|
+
|
|
104
|
+
def generate(url, output_dir: 'Colors.xcassets', dark_mode: true)
|
|
105
|
+
colors = extract_palette_from_url(url)
|
|
106
|
+
|
|
107
|
+
if colors.empty?
|
|
108
|
+
warn 'Error: Could not extract color palette from URL.'
|
|
109
|
+
return false
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
puts "Light colors: #{colors.join(', ')}"
|
|
113
|
+
|
|
114
|
+
dark_colors = dark_mode ? colors.map { |c| invert_color(c) } : nil
|
|
115
|
+
puts "Dark colors: #{dark_colors.join(', ')}" if dark_colors
|
|
116
|
+
|
|
117
|
+
FileUtils.mkdir_p(output_dir)
|
|
118
|
+
File.write(File.join(output_dir, 'Contents.json'), JSON.pretty_generate({ info: { author: 'xcode', version: 1 } }))
|
|
119
|
+
|
|
120
|
+
colors.each_with_index do |light_hex, i|
|
|
121
|
+
name = (colors.length == 5 && COLOR_LABELS[i]) ? "#{COLOR_LABELS[i]}Color" : "Color#{i + 1}"
|
|
122
|
+
colorset_dir = File.join(output_dir, "#{name}.colorset")
|
|
123
|
+
FileUtils.mkdir_p(colorset_dir)
|
|
124
|
+
|
|
125
|
+
dark_hex = dark_colors ? dark_colors[i] : nil
|
|
126
|
+
File.write(File.join(colorset_dir, 'Contents.json'), JSON.pretty_generate(create_colorset_json(light_hex, dark_hex)))
|
|
127
|
+
|
|
128
|
+
if dark_hex
|
|
129
|
+
puts "✓ #{name}.colorset (Light: #{light_hex}, Dark: #{dark_hex})"
|
|
130
|
+
else
|
|
131
|
+
puts "✓ #{name}.colorset (#{light_hex})"
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
mode_text = dark_mode ? ' (Light/Dark)' : ''
|
|
136
|
+
puts "\nDone! ColorSets#{mode_text} generated in #{output_dir}/"
|
|
137
|
+
puts 'Drag and drop into your Xcode project Assets to use.'
|
|
138
|
+
true
|
|
139
|
+
end
|
|
140
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: colorset_generator
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- tsu-na-gu
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-04-10 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: |
|
|
14
|
+
Generates Xcode .xcassets ColorSet JSON files from color palette URLs.
|
|
15
|
+
|
|
16
|
+
Extracts hex color codes embedded in URLs from palette tools such as:
|
|
17
|
+
- Huemint (https://huemint.com)
|
|
18
|
+
- RealtimeColors (https://realtimecolors.com)
|
|
19
|
+
- Coolors (https://coolors.co)
|
|
20
|
+
|
|
21
|
+
Any URL that encodes hex codes in its path or query string is supported.
|
|
22
|
+
Dark mode variants are automatically calculated by inverting the HSL
|
|
23
|
+
lightness of each light color — no manual dark palette needed.
|
|
24
|
+
|
|
25
|
+
The generated Colors.xcassets folder can be dragged and dropped directly
|
|
26
|
+
into Xcode's Assets catalog to use the colors in Swift/SwiftUI projects.
|
|
27
|
+
|
|
28
|
+
Usage:
|
|
29
|
+
colorset_generator "https://huemint.com/brand-2/#palette=2a3031-fafdfc-a19985"
|
|
30
|
+
colorset_generator "https://coolors.co/c4f1be-a2c3a4-869d96-525b76-201e50" --output MyPalette.xcassets
|
|
31
|
+
colorset_generator "https://www.realtimecolors.com/?colors=14140f-f8f8f6-9a9e79-aec4bd-8ea7ad" --no-dark
|
|
32
|
+
email:
|
|
33
|
+
executables:
|
|
34
|
+
- colorset_generator
|
|
35
|
+
extensions: []
|
|
36
|
+
extra_rdoc_files: []
|
|
37
|
+
files:
|
|
38
|
+
- bin/colorset_generator
|
|
39
|
+
- lib/colorset_generator.rb
|
|
40
|
+
homepage:
|
|
41
|
+
licenses:
|
|
42
|
+
- MIT
|
|
43
|
+
metadata: {}
|
|
44
|
+
post_install_message:
|
|
45
|
+
rdoc_options: []
|
|
46
|
+
require_paths:
|
|
47
|
+
- lib
|
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: 2.7.0
|
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
|
+
requirements:
|
|
55
|
+
- - ">="
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: '0'
|
|
58
|
+
requirements: []
|
|
59
|
+
rubygems_version: 3.0.3.1
|
|
60
|
+
signing_key:
|
|
61
|
+
specification_version: 4
|
|
62
|
+
summary: Generate Xcode ColorSet assets from palette URLs
|
|
63
|
+
test_files: []
|