From c4558db289bfccd88ac9b9d95eea8bd3c0c53334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Pham?= Date: Sun, 21 Sep 2025 20:14:17 +0200 Subject: [PATCH] feat: space invaders! --- README.md | 36 +++++++- img/space-invaders-demo.png | Bin 0 -> 46947 bytes lib/mural/invader/board.rb | 112 +++++++++++++++++++++++ lib/mural/invader/crab.rb | 30 ++++++ lib/mural/invader/draw_invader_params.rb | 25 +++++ lib/mural/invader/octopus.rb | 30 ++++++ lib/mural/invader/squid.rb | 30 ++++++ 7 files changed, 261 insertions(+), 2 deletions(-) create mode 100644 img/space-invaders-demo.png create mode 100644 lib/mural/invader/board.rb create mode 100644 lib/mural/invader/crab.rb create mode 100644 lib/mural/invader/draw_invader_params.rb create mode 100644 lib/mural/invader/octopus.rb create mode 100644 lib/mural/invader/squid.rb diff --git a/README.md b/README.md index 70ac817..3868248 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ irb(main):002> mural.users.current_user ### Upload a file to a mural -To upload a `my.pdf` file that's located in the same directory as where you are +To upload a `my.pdf` file that’s located in the same directory as where you are running the script: ```rb @@ -161,9 +161,41 @@ an email notification. ![mind map example](./img/mind-map.png) -- Likewise, smart planners are collection of widgets, and the API doesn't +- Likewise, smart planners are collection of widgets, and the API doesn’t specify anything about them. ![smart planner example](./img/smart-planner.png) [register-app]: https://developers.mural.co/public/docs/register-your-app + +## Invaders module! + +How about some good ol’ nostalgia? Let’s bring in the +[space invaders](https://en.wikipedia.org/wiki/Space_Invaders) in a mural! + +![space invaders demo](./img/space-invaders-demo.png) + +To accomplish this, simply create a script with the following code: + +```rb +require 'mural' + +MURAL_ID = 'mural-1' # some mural you have write access to + +client = Mural::Client.from_env + +begin + board = Mural::Invader::Board.new(client, MURAL_ID) + + draw_invader_params = Mural::Invader::DrawInvaderParams.new.tap do |params| + params.origin = [0, 0] + params.pixel_width = 10 # default, and the minimum size for the square shape + params.variant = 0 + end + + board.draw_invader_grid(draw_invader_params) +rescue Mural::Error => e + puts "\n--- ☠️☠️☠️ MURAL ERROR ☠️☠️☠️ ---" + puts e.inspect +end +``` diff --git a/img/space-invaders-demo.png b/img/space-invaders-demo.png new file mode 100644 index 0000000000000000000000000000000000000000..146fc2e599aa31594fb893f2d0473c53e48aeca3 GIT binary patch literal 46947 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 literal 0 HcmV?d00001 diff --git a/lib/mural/invader/board.rb b/lib/mural/invader/board.rb new file mode 100644 index 0000000..5694e00 --- /dev/null +++ b/lib/mural/invader/board.rb @@ -0,0 +1,112 @@ +# frozen_string_literal: true + +module Mural + module Invader + class Board + INVADER = { + 'crab' => 'Mural::Invader::Crab::SPRITE', + 'octopus' => 'Mural::Invader::Octopus::SPRITE', + 'squid' => 'Mural::Invader::Squid::SPRITE' + }.freeze + + ROWS = [ + ['squid', '#69ED36FF'], + ['crab', '#69ED36FF'], + ['crab', '#68F1F4FF'], + ['octopus', '#68F1F4FF'], + ['octopus', '#D937EEFF'] + ].freeze + COLS = 11 + + # the widest invader (octopus) is 12 "pixels" wide + MAX_INVADER_WIDTH = 12 + + # they are all the same height + MAX_INVADER_HEIGHT = 8 + + # the gitter scale with the size of the "pixel" + GUTTER_SIZE = 3 + + # how many shapes can we send in a single request + MAX_SHAPES_IN_PAYLOAD = 1_000 + + attr_reader :client, :mural_id + + def initialize(client, mural_id) + @client = client + @mural_id = mural_id + end + + def draw_invader_grid(draw_invader_params) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength + draw_invader_params.to_h => { origin:, pixel_width:, variant: } + origin_x, origin_y = origin + + cell_width = (MAX_INVADER_WIDTH + GUTTER_SIZE) * pixel_width + cell_height = (MAX_INVADER_HEIGHT + GUTTER_SIZE) * pixel_width + + payload = ROWS.flat_map.with_index do |invader, row| + invader_kind, invader_color = invader + + (0...COLS).flat_map do |col| + cell_origin = [ + origin_x + (cell_width * col), + origin_y + (cell_height * row) + ] + + cell_invader_params = + Mural::Invader::DrawInvaderParams.new.tap do |params| + params.color = invader_color + params.origin = cell_origin + params.variant = variant + params.pixel_width = pixel_width + end + + invader_shape(invader_kind, cell_invader_params) + end + end + + payload.each_slice(MAX_SHAPES_IN_PAYLOAD) do |shapes| + client.mural_content.create_shapes(mural_id, shapes) + end + end + + def draw_invader(kind, draw_invader_params) + client + .mural_content + .create_shapes(mural_id, invader_shape(kind, draw_invader_params)) + end + + def invader_shape( # rubocop:disable Metrics/AbcSize,Metrics/MethodLength + kind, + draw_invader_params + ) + draw_invader_params.to_h => { color:, origin:, pixel_width:, variant: } + sprite = Object.const_get(INVADER[kind])[variant] + origin_x, origin_y = origin + + sprite.flat_map.with_index do |row_content, row| + row_content.map.with_index do |cell, col| + next unless cell == 1 + + Mural::Widget::CreateShapeParams.new.tap do |params| + params.x = origin_x + (col * pixel_width) + params.y = origin_y + (row * pixel_width) + params.width = pixel_width + params.height = pixel_width + params.shape = 'square' + + params.style = + Mural::Widget::CreateShapeParams::Style.new.tap do |style| + style.background_color = color + + # We want a transparent border, else the "pixel" is wider than + # the desired dimension + style.border_color = '#00000000' + end + end + end + end.compact + end + end + end +end diff --git a/lib/mural/invader/crab.rb b/lib/mural/invader/crab.rb new file mode 100644 index 0000000..17b5a68 --- /dev/null +++ b/lib/mural/invader/crab.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Mural + module Invader + class Crab + SPRITE = [ + [ + [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1], + [1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1], + [0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0] + ], + [ + [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0], + [1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1], + [1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1], + [1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0] + ] + ].freeze + end + end +end diff --git a/lib/mural/invader/draw_invader_params.rb b/lib/mural/invader/draw_invader_params.rb new file mode 100644 index 0000000..ec62bfd --- /dev/null +++ b/lib/mural/invader/draw_invader_params.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Mural + module Invader + class DrawInvaderParams + attr_accessor :pixel_width, :color, :origin, :variant + + def initialize + @pixel_width = 10 + @color = '#000000FF' + @origin = [0, 0] + @variant = 0 + end + + def to_h + { + pixel_width: pixel_width, + color: color, + origin: origin, + variant: variant + } + end + end + end +end diff --git a/lib/mural/invader/octopus.rb b/lib/mural/invader/octopus.rb new file mode 100644 index 0000000..e289e2b --- /dev/null +++ b/lib/mural/invader/octopus.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Mural + module Invader + class Octopus + SPRITE = [ + [ + [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0], + [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0], + [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1] + ], + [ + [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0], + [0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0], + [0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0] + ] + ].freeze + end + end +end diff --git a/lib/mural/invader/squid.rb b/lib/mural/invader/squid.rb new file mode 100644 index 0000000..ff4dd74 --- /dev/null +++ b/lib/mural/invader/squid.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Mural + module Invader + class Squid + SPRITE = [ + [ + [0, 0, 0, 1, 1, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 0], + [1, 1, 0, 1, 1, 0, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1], + [0, 1, 0, 1, 1, 0, 1, 0], + [1, 0, 0, 0, 0, 0, 0, 1], + [0, 1, 0, 0, 0, 0, 1, 0] + ], + [ + [0, 0, 0, 1, 1, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 0], + [1, 1, 0, 1, 1, 0, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1], + [0, 0, 1, 0, 0, 1, 0, 0], + [0, 1, 0, 1, 1, 0, 1, 0], + [1, 0, 1, 0, 0, 1, 0, 1] + ] + ].freeze + end + end +end