Skip to main content
  1. Posts/

New Day 1 - Beholder on Your Phone pt6

NewDays sms-beholder blog hugo ruby GitLab

Hello Hugo
Hello, Hugo.

A new/old look, and some other stuff.

Everything old is new again
#

Thanks to Hugo and the Hugo-Octopress theme, this blog now looks a lot like it originally did. Of course, I found it necessary to fork and expand on Octopress, so I’ve had to do that again to fully support my old blog posts. Luckily Hugo shortcodes are pretty easy and convenient.

codeblock
#

The codecaption shortcode from the Hugo Octopress theme gives a nice Octopress look, but I really like to specify a starting line number with a link to that line in the source repository. So along with a title, I need a URL, the link text, and optionally a line number on which to start.

shortcodes/codeblock.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<!-- Based on the codecaption shortcode by
   Parsia Hakimian https://github.com/parsiya/Hugo-Shortcodes -->

   <figure class="code">
    <figcaption>
      <span>{{ .Get "title" }} <a href="{{ .Get "url" }}">{{ .Get "linktext" }}</a></span>
    </figcaption>
    <div class="codewrapper">
      {{ $options := printf "linenos=true,linenostart=%d" (.Get "linenostart" | default 1) }}
      {{ highlight (trim .Inner "\n\r") (.Get "lang") $options }}
    </div>
    </figure>

rawhtml
#

I also tripped over how to handle the HTML I’d embedded directly in a couple of blog posts. Those sections would simply not show up at all, unless I opted for “unsafe” rendering in the markdown settings. Instead of doing that, I found someone’s trivial shortcode to wrap around them:

shortcodes/rawhtml.html
1
2
3
{{/*  Thanks to Ana Ulin https://anaulin.org/blog/hugo-raw-html-shortcode/  */}}
<!-- raw html -->
{{.Inner}}

Close enough
#

I’m sure I’ll tweak more in future (maybe even fork the theme), but so far I’m satisfied.


Beholder on Your Phone pt6
#

Beholder emerges from AT&amp;T logo
Beholder emerges from AT&T logo

At some point during my hiatus, I resumed work on the SMS port of Beholder High. I was close to a textual MVP, but the art was one of the best parts of the game. The web-based version of the game was free to composite the images in real time, and do some idle animations; but for the sake of bandwidth and simplicity, I decided it was better to pre-process the images for the SMS (technically SMS and MMS, now) version.

A Little Image Magick
#

I had some history with ImageMagick, so was glad to find a handy Ruby gem: rmagick. With some trial and error, I started putting together images in MMS-friendly resolution:

image_comp.rb
 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
require 'json'
require 'rmagick'
include Magick

def beholder_compose_image(image_spec, filename=nil, dir="composite")
  if image_spec[:bg]
  bg_image_name = "images/bg/#{image_spec[:bg]}.jpg"
  return unless File.file?(bg_image_name)
  bg_image = ImageList.new(bg_image_name).resize(600, 400)
  new_image = bg_image
  if image_spec[:beholder]
    beholder_image_name = "images/char/#{image_spec[:beholder]}/#{image_spec[:beholder]}-" \
    "#{image_spec[:beholderExp]}.png"
    return unless File.file?(beholder_image_name)
    beholder_image = ImageList.new(beholder_image_name)
    new_image = bg_image.composite(beholder_image, CenterGravity, SrcOverCompositeOp)
    debug_text(image_spec, new_image) if image_spec[:debug]
  end
  if filename
    new_image.write("#{dir}/#{filename}")
  else
    new_image.write("#{dir}/#{image_spec[:bg]}_#{image_spec[:beholder]}_" \
            "#{image_spec[:beholderExp]}#{image_spec[:debug] ? '_debug' : ''}.png")
  end
  else
  print("Bad image_spec: #{image_spec}")
  end
end

Happy beholder Moxanimous on the sports field.
Happy beholder Moxanimous on the sports field.

I wasn’t going to spend much time putting together tests for this run-once code, so the ability to superimpose debug info on the image was useful for human verification.

image_comp.rb
30
31
32
33
34
35
36
37
38
39
40
41
42
43
def debug_text(image_spec, image)
  text = Magick::Draw.new
  text.font = "Helvetica"
  text.pointsize = 30
  text.gravity = Magick::SouthGravity
  new_text = "#{image_spec[:beholder]} is #{image_spec[:beholderExp]}" \
  " at #{image_spec[:bg]}"
  text.fill = 'gray83'
  text.annotate(image, 0, 0, 2, 2, new_text)
  text.fill = 'gray40'
  text.annotate(image, 0, 0, -1.5, -1.5, new_text)
  text.fill = 'darkred'
  text.annotate(image, 0, 0, 0, 0, new_text)
end

Angry beholder Siriak the Rapid in the lunchroom with debug text.
Angry beholder Siriak the Rapid in the lunchroom with debug text.

Continuous (Visual) Integration
#

Of course I wanted to generate the images as part of a CI workflow, which seemed straightforward:

.gitlab-ci.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
image: ruby:2.7

before_script:
  - apt-get update -qq
  - ruby -v
  - which ruby
  - gem install bundler
  - bundle install --jobs $(nproc)  "${FLAGS[@]}"
  - mkdir composite
  - bundle exec ruby image_comp.rb
  - ls composite

…but had issues with my debug text.

$ bundle exec ruby image_comp.rb
/usr/local/bundle/gems/json-2.1.0/lib/json/common.rb:156: warning: Using the last argument as keyword parameters is deprecated
image_comp.rb:38:in `annotate': unable to read font `Helvetica' @ error/annotate.c/RenderFreetype/1396 (Magick::ImageMagickError)
  from image_comp.rb:38:in `debug_text'
  from image_comp.rb:17:in `beholder_compose_image'
  from image_comp.rb:56:in `block in <main>'
  from image_comp.rb:47:in `each'
  from image_comp.rb:47:in `<main>'

After a little research, it seemed like maybe installing Ghostscript would give me the fonts I needed, so I added that.

.gitlab-ci.yml
3
4
5
6
7
8
9
before_script:
  - apt-get update -qq
  - apt-get install ghostscript -q -y
  - ruby -v
  - which ruby
  - gem install bundler
  - bundle install --jobs $(nproc)  "${FLAGS[@]}"

I ran the image compositing at part of the rspec test pipeline, and archived the results.

.gitlab-ci.yml
16
17
18
19
20
21
22
23
24
25
26
27
28
rspec:
  script:
  - mkdir composite
  - bundle exec ruby image_comp.rb
  - ls composite
  - bundle exec rspec --format progress --format RspecJunitFormatter --out rspec.xml
  artifacts:
  when: always
  paths:
    - composite/
    - rspec.xml
  reports:
    junit: rspec.xml
On GitLab, the pipeline successfully ran and created artifacts
On GitLab, the pipeline successfully ran and created artifacts

Download and unzip, and…

I have all of my composited images.
I have all of my composited images.

Now to put them somewhere public so they can be attached to messages.


More to come
More to come

sms-beholder New Day 001 code