Specifying Colors & Gradients

Colors

by hex-string

You can specify a color via the standard hexadecimal string for RGB (as in HTML and CSS). You also have a few other options as well. You can use:

  • 12-bit (3 hex numbers), RGB. e.g. '#f08'
  • 24-bit (6 hex numbers), RRGGBB. e.g. '#ff0088'
  • 48-bit (9 hex numbers), RRRGGGBBB. e.g. '#fff000888'

Additionally, you can specify the alpha (i.e. transparency) of the color as RGBA. An alpha of 0 is full transparent, and f is fully opaque. Thus, you can also use:

  • 12-bit (4 hex numbers), RGBA. e.g. '#f085'
  • 24-bit (8 hex numbers), RRGGBBAA. e.g. '#ff008855'
  • 48-bit (12 hex numbers), RRRGGGBBBAAA. e.g. '#fff000888555'

The # at the beginning is optional, but encouraged for readability. In layout files (described in Layouts are Squib’s Best Feature), the # character will initiate a comment in Yaml. So to specify a color in a layout file, just quote it:

# this is a comment in yaml
attack:
  fill_color: '#fff'

by name

Under the hood, Squib uses the rcairo color parser to accept around 300 named colors. The full list can be found here.

Names of colors can be either strings or symbols, and case does not matter. Multiple words are separated by underscores. For example, 'white', :burnt_orange, or 'ALIZARIN_CRIMSON' are all acceptable names.

by custom name

In your config.yml, as described in Configuration Options, you can specify custom names of colors. For example, 'foreground'.

Gradients

In most places where colors are allowed, you may also supply a string that defines a gradient. Squib supports two flavors of gradients: linear and radial. Gradients are specified by supplying some xy coordinates, which are relative to the card (not the command). Each stop must be between 0.0 and 1.0, and you can supply as many as you like. Colors can be specified as above (in any of the hex notations or built-in constant). If you add two or more colors at the same stop, then the gradient keeps the colors in the in order specified and treats it like sharp transition.

The format for linear gradient strings look like this:

'(x1,y1)(x2,y2) color1@stop1 color2@stop2'

The xy coordinates define the angle of the gradient.

The format for radial gradients look like this:

'(x1,y1,radius1)(x2,y2,radius2) color1@stop1 color2@stop2'

The coordinates specify an inner circle first, then an outer circle.

In both of these formats, whitespace is ignored between tokens so as to make complex gradients more readable.

If you need something more powerful than these two types of gradients (e.g. mesh gradients), then we suggest encapsulating your logic within an SVG and using the svg method to render it.

Samples

Code is maintained in the repository here in case you need some of the assets referenced.

Sample: colors and color constants

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
require 'squib'

Squib::Deck.new(width: 825, height: 1125, cards: 1) do
  background color: :white

  y = 0
  text color: '#f00', str: '3-hex', x: 50, y: y += 50
  text color: '#f00', str: '3-hex (alpha)', x: 50, y: y += 50
  text color: '#ff0000', str: '6-hex', x: 50, y: y += 50
  text color: '#ff000099', str: '8-hex(alpha)', x: 50, y: y += 50
  text color: '#ffff00000000', str: '12-hex', x: 50, y: y += 50
  text color: '#ffff000000009999', str: '12-hex (alpha)', x: 50, y: y += 50
  text color: :burnt_orange, str: 'Symbols of constants too', x: 50, y: y += 50
  text color: '(0,0)(400,0) blue@0.0 red@1.0', str: 'Linear gradients!', x: 50, y: y += 50
  text color: '(200,500,10)(200,500,100) blue@0.0 red@1.0', str: 'Radial gradients!', x: 50, y: y += 50
  # see gradients.rb sample for more on gradients

  save_png prefix: 'colors_'
end

# This script generates a table of the built-in constants
colors = (Cairo::Color.constants - %i(HEX_RE Base RGB CMYK HSV X11))
colors.sort_by! do |c|
  hsv = Cairo::Color.parse(c).to_hsv
  [(hsv.hue / 16.0).to_i, hsv.value, hsv.saturation]
end
w, h = 300, 50
deck_height = 4000
deck_width = (colors.size / ((deck_height / h) + 1)) * w
Squib::Deck.new(width: deck_width, height: deck_height) do
  background color: :white
  x, y = 0, 0
  colors.each_with_index do |color, i|
    rect x: x, y: y, width: w, height: h, fill_color: color
    text str: color.to_s, x: x + 5, y: y + 13, font: 'Sans Bold 5',
         color: (Cairo::Color.parse(color).to_hsv.v > 0.9) ? '#000' : '#fff'
    y += h
    if y > deck_height
      x += w
      y = 0
    end
  end
  save_png prefix: 'color_constants_'
end

Sample: gradients

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
require 'squib'

Squib::Deck.new do
  # Just about anywhere Squib takes in a color it can also take in a gradient too
  # The x-y coordinates on the card itself,
  # and then color stops are defined between 0 and 1
  background color: '(0,0)(0,1125) #ccc@0.0 #111@1.0'
  line stroke_color: '(0,0)(825,0) #111@1.0 #ccc@0.0',
      x1: 0, y1: 600, x2: 825, y2: 600,
       stroke_width: 15

  # Radial gradients look like this
  circle fill_color: '(425,400,2)(425,400,120) #ccc@0.0 #111@1.0',
         x: 415, y: 415, radius: 100, stroke_color: '#0000'
  triangle fill_color: '(650,400,2)(650,400,120) #ccc@0.0 #111@1.0',
           stroke_color: '#0000',
           x1: 650, y1: 360,
           x2: 550, y2: 500,
           x3: 750, y3: 500

  # Gradients are also good for beveling effects:
  rect fill_color: '(0,200)(0,600) #111@0.0 #ccc@1.0',
       x: 30, y: 350, width: 150, height: 150,
       radius: 15, stroke_color: '#0000'
  rect fill_color: '(0,200)(0,600) #111@1.0 #ccc@0.0',
       x: 40, y: 360, width: 130, height: 130,
       radius: 15, stroke_color: '#0000'

  # Alpha transparency can be used too
  text str: 'Hello, world!', x: 75, y: 700, font: 'Sans Bold 24',
       color: '(0,0)(825,0) #000f@0.0 #0000@1.0'

  save_png prefix: 'gradient_'
end

Sample: Switch color based on variable

Say you have different card types with different colors or themes but you would like to change the theme quickly without changing all parameters for each method inside Squib::Deck.new().

You could use something like the following snippet to have one place to define the color/theme and use that in all map functions. The example inverts the color from white to black for one card type. Use a switch-statement inside the map function to differentiate multiple types.

It’s possible to use that for e.g. background color, text color or to choose the correct SVG for that color scheme (e.g. use the white or the black version of an image). The sample shows how to define the color at one place, e.g. choose between white and black, to quickly change the color scheme for the cards:

Here’s the data or see the tab-separated file in the sample directory:

Type Text
Snake This is a snake.
Lion This is a lion.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
require_relative '../../lib/squib'

# Choose between black and white color theme for type snake
#   * Allow using white snake cards with black text or
#     black snake cards with white text
color = 'white'

cards = Squib.csv file: '_switch_color_data.csv'

Squib::Deck.new cards: cards['Type'].size do

    background_color = cards['Type'].map do |t|
        if color == 'black' && t == "Snake" then
            "black"
        else
            "white"
        end
    end
    background color: background_color

    text_color = cards['Type'].map do |t|
        if color == 'black' && t == "Snake" then
            "white"
        else
            "black"
        end
    end

    text str: cards['Text'], color: text_color

    save_png prefix: '_switch_color_sample_'

end