diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..87237d1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+# Gladiator (Glimmer Editor)
+.gladiator
+.DS_Store
diff --git a/pixelart/.gitignore b/pixelart/.gitignore
index 38b7fd8..0d3f038 100644
--- a/pixelart/.gitignore
+++ b/pixelart/.gitignore
@@ -28,9 +28,12 @@ build/
# for a library or gem, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# Gemfile.lock
-# .ruby-version
-# .ruby-gemset
+.ruby-version
+.ruby-gemset
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc
+# Gladiator (Glimmer Editor)
+.gladiator
+.DS_Store
diff --git a/pixelart/README.md b/pixelart/README.md
index 96fb4d0..4c4c092 100644
--- a/pixelart/README.md
+++ b/pixelart/README.md
@@ -277,6 +277,148 @@ require 'pixelart/base'
+## Canvas Vector Graphics
+
+You may utilize inline-DSL (Domain Specific Language) syntax for building vector graphics via a canvas `PixelArt::Vector` object:
+
+```ruby
+require 'pixelart/base'
+
+
+canvas = PixelArt::Vector.new( 24, 24 )
+
+## face
+canvas.path( stroke: 'black', fill: '#c8fbfb' ).line(
+ 6, 23, 6, 14,
+ 5, 14, 5, 13, 4, 12,
+ 5, 11, 6, 11, 6, 7, 7, 6, 8, 5,
+ 14, 5, 15, 6,
+ 16, 7, 16, 19, 15, 20, 14, 21, 10, 21, 10, 23 )
+
+## mouth
+canvas.path( stroke: 'black' ).line( 10, 18, 14, 18 )
+## nose
+canvas.path( stroke: '#9be0e0' ).line( 12, 16, 12, 14 )
+
+
+## eyes
+canvas.path( stroke: 'black' ).line( 9, 13, 9, 12 )
+ .line( 10, 12, 10, 11 )
+ .line( 14, 13, 14, 12 )
+ .line( 15, 12, 15, 11 )
+canvas.path( stroke: '#9be0e0' ).line( 10, 13, 10, 12 )
+ .line( 15, 13, 15, 12 )
+canvas.path( stroke: '#75bdbd' ).line( 9, 12, 9, 11 )
+ .line( 14, 12, 14, 11 )
+
+## headband
+canvas.path( stroke: '#1a6ed5' ).line( 7, 8, 15, 8 )
+canvas.path( stroke: 'white' ).line( 7, 7, 15, 7 )
+
+
+canvas.save( "./tmp/punk3100.svg" )
+```
+
+Voila!
+
+
+
+## Modular "Glimmer" Version
+
+You may utilize a [Glimmer](https://github.com/AndyObtiva/glimmer) DSL for Pixelart vector graphics by requiring `'pixelart/glimmer'` and including `Glimmer` module:
+
+```ruby
+require 'pixelart/glimmer'
+include Glimmer # activates Glimmer DSL for Pixelart (in real apps, mix into a class instead)
+```
+
+Afterwards, you may build canvas vector graphics declaratively and hierarchically:
+
+```ruby
+def face
+ line {
+ coordinates 6, 23, 6, 14,
+ 5, 14, 5, 13, 4, 12,
+ 5, 11, 6, 11, 6, 7, 7, 6, 8, 5,
+ 14, 5, 15, 6,
+ 16, 7, 16, 19, 15, 20, 14, 21, 10, 21, 10, 23
+ fill '#c8fbfb'
+ stroke 'black'
+ }
+end
+
+def mouth
+ line( 10, 18, 14, 18 ) {
+ stroke 'black'
+ }
+end
+
+def nose
+ line( 12, 16, 12, 14 ) {
+ stroke '#9be0e0'
+ }
+end
+
+def eyes
+ path {
+ line( 9, 13, 9, 12 )
+ line( 10, 12, 10, 11 )
+ line( 14, 13, 14, 12 )
+ line( 15, 12, 15, 11 )
+
+ stroke 'black'
+ }
+
+ path {
+ line( 10, 13, 10, 12 )
+ line( 15, 13, 15, 12 )
+
+ stroke '#9be0e0'
+ }
+
+ path {
+ line( 9, 12, 9, 11 )
+ line( 14, 12, 14, 11 )
+
+ stroke '#75bdbd'
+ }
+end
+
+def headband
+ line( 7, 8, 15, 8 ) {
+ stroke '#1a6ed5'
+ }
+
+ line( 7, 7, 15, 7 ) {
+ stroke 'white'
+ }
+end
+
+image = canvas(24, 24) {
+ file './tmp/punk3100.svg' # auto-saves file when canvas expression closes
+
+ face
+ mouth
+ nose
+ eyes
+ headband
+}
+
+# Re-open content to modify attributes and add more shapes
+image.content {
+ file './tmp/punk3100-round-nose.svg' # auto-saves file when content closes
+
+ ## Round Nose
+ circle( 12, 15, 1 ) {
+ fill '#9be0e0'
+ }
+}
+```
+
+Voila!
+
+
+
## Install
Just install the gem:
@@ -288,4 +430,3 @@ Just install the gem:
The scripts are dedicated to the public domain.
Use it as you please with no restrictions whatsoever.
-
diff --git a/pixelart/i/punk3100-round-nose.svg b/pixelart/i/punk3100-round-nose.svg
new file mode 100644
index 0000000..f1db205
--- /dev/null
+++ b/pixelart/i/punk3100-round-nose.svg
@@ -0,0 +1,16 @@
+
\ No newline at end of file
diff --git a/pixelart/i/punk3100.svg b/pixelart/i/punk3100.svg
new file mode 100644
index 0000000..6356c83
--- /dev/null
+++ b/pixelart/i/punk3100.svg
@@ -0,0 +1,15 @@
+
\ No newline at end of file
diff --git a/pixelart/lib/glimmer/dsl/pixelart/attribute_expression.rb b/pixelart/lib/glimmer/dsl/pixelart/attribute_expression.rb
new file mode 100644
index 0000000..6674b55
--- /dev/null
+++ b/pixelart/lib/glimmer/dsl/pixelart/attribute_expression.rb
@@ -0,0 +1,17 @@
+require 'glimmer/dsl/expression'
+
+module Glimmer
+ module DSL
+ module Pixelart
+ class AttributeExpression < Expression
+ def can_interpret?(parent, keyword, *args, &block)
+ parent.respond_to?("#{keyword}=") && !args.empty? && block.nil?
+ end
+
+ def interpret(parent, keyword, *args, &block)
+ parent.send("#{keyword}=", *args)
+ end
+ end
+ end
+ end
+end
diff --git a/pixelart/lib/glimmer/dsl/pixelart/dsl.rb b/pixelart/lib/glimmer/dsl/pixelart/dsl.rb
new file mode 100644
index 0000000..22817d1
--- /dev/null
+++ b/pixelart/lib/glimmer/dsl/pixelart/dsl.rb
@@ -0,0 +1,16 @@
+require 'glimmer/dsl/engine'
+Dir[File.expand_path('*_expression.rb', __dir__)].each {|f| require f}
+
+module Glimmer
+ module DSL
+ module Pixelart
+ Engine.add_dynamic_expressions(
+ Pixelart,
+ %w[
+ attribute
+ element
+ ]
+ )
+ end
+ end
+end
diff --git a/pixelart/lib/glimmer/dsl/pixelart/element_expression.rb b/pixelart/lib/glimmer/dsl/pixelart/element_expression.rb
new file mode 100644
index 0000000..99cc3a1
--- /dev/null
+++ b/pixelart/lib/glimmer/dsl/pixelart/element_expression.rb
@@ -0,0 +1,28 @@
+require 'glimmer/dsl/expression'
+require 'glimmer/dsl/parent_expression'
+require 'glimmer/dsl/top_level_expression'
+require_relative '../../pixelart/element'
+
+module Glimmer
+ module DSL
+ module Pixelart
+ class ElementExpression < Expression
+ include ParentExpression
+ include TopLevelExpression
+
+ def can_interpret?(parent, keyword, *args, &block)
+ Glimmer::Pixelart::Element.element_exist?(keyword)
+ end
+
+ def interpret(parent, keyword, *args, &block)
+ Glimmer::Pixelart::Element.element_class(keyword).new(parent, keyword, *args, &block)
+ end
+
+ def add_content(element, keyword, *args, &block)
+ super
+ element.post_add_content
+ end
+ end
+ end
+ end
+end
diff --git a/pixelart/lib/glimmer/pixelart/element.rb b/pixelart/lib/glimmer/pixelart/element.rb
new file mode 100644
index 0000000..50c1645
--- /dev/null
+++ b/pixelart/lib/glimmer/pixelart/element.rb
@@ -0,0 +1,53 @@
+require 'facets/string/camelcase'
+
+module Glimmer
+ module Pixelart
+ class Element
+ class << self
+ def element_exist?(keyword)
+ constants.include?(element_class_name(keyword)) && element_class(keyword).respond_to?(:new)
+ end
+
+ def element_class(keyword)
+ const_get(element_class_name(keyword))
+ end
+
+ def element_class_name(keyword)
+ keyword.to_s.camelcase(:upper).to_sym
+ end
+ end
+
+ attr_reader :parent, :keyword, :args, :block
+
+ def initialize(parent, keyword, *args, &block)
+ @parent = parent
+ @keyword = keyword
+ @args = args
+ @block = block
+ @children = []
+ @parent&.post_initialize_child(self)
+ post_add_content if @block.nil?
+ end
+
+ # Subclasses may optionally override and call super to have children built
+ def build
+ @children&.each(&:build)
+ end
+
+ def post_initialize_child(child)
+ @children << child
+ end
+
+ def post_add_content
+ # No Op (subclasses may override to do something at the closing of the element)
+ end
+
+ # Enables re-opening content and adding new shapes
+ def content(&block)
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Pixelart::ElementExpression.new, @keyword, &block)
+ end
+ end
+ end
+end
+
+Dir[File.expand_path('./element/*.rb', __dir__)].each {|f| require f}
diff --git a/pixelart/lib/glimmer/pixelart/element/canvas.rb b/pixelart/lib/glimmer/pixelart/element/canvas.rb
new file mode 100644
index 0000000..e45e027
--- /dev/null
+++ b/pixelart/lib/glimmer/pixelart/element/canvas.rb
@@ -0,0 +1,50 @@
+require 'pixelart/base'
+
+module Glimmer
+ module Pixelart
+ class Element
+ class Canvas < Element
+ attr_reader :vector
+ attr_accessor :file
+
+ def width
+ @args[0]
+ end
+
+ def height
+ @args[1]
+ end
+
+ def width=(new_width)
+ @args[0] = new_width
+ end
+
+ def height=(new_height)
+ @args[1] = new_height
+ end
+
+ def post_add_content
+ build
+ end
+
+ def build
+ @vector = ::PixelArt::Vector.new(*@args)
+ super
+ @vector.save(@file) if @file
+ end
+
+ def respond_to?(method_name, include_private = true)
+ super || @vector.respond_to?(method_name, include_private)
+ end
+
+ def method_missing(method_name, *args, **kwargs, &block)
+ if @vector.respond_to?(method_name, true)
+ @vector.send(method_name, *args, **kwargs, &block)
+ else
+ super
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/pixelart/lib/glimmer/pixelart/element/circle.rb b/pixelart/lib/glimmer/pixelart/element/circle.rb
new file mode 100644
index 0000000..5d383f6
--- /dev/null
+++ b/pixelart/lib/glimmer/pixelart/element/circle.rb
@@ -0,0 +1,43 @@
+module Glimmer
+ module Pixelart
+ class Element
+ class Circle < Element
+ attr_accessor :fill
+
+ def cx
+ @args[0]
+ end
+ alias center_x cx
+
+ def cy
+ @args[1]
+ end
+ alias center_y cy
+
+ def r
+ @args[2]
+ end
+ alias radius r
+
+ def cx=(new_cx)
+ @args[0] = new_cx
+ end
+ alias center_x cx
+
+ def cy=(new_cy)
+ @args[1] = new_cy
+ end
+ alias center_y cy
+
+ def r=(new_r)
+ @args[2] = new_r
+ end
+ alias radius r
+
+ def build
+ @parent.circle(cx: cx, cy: cy, r: r, fill: @fill)
+ end
+ end
+ end
+ end
+end
diff --git a/pixelart/lib/glimmer/pixelart/element/line.rb b/pixelart/lib/glimmer/pixelart/element/line.rb
new file mode 100644
index 0000000..e6aa734
--- /dev/null
+++ b/pixelart/lib/glimmer/pixelart/element/line.rb
@@ -0,0 +1,27 @@
+module Glimmer
+ module Pixelart
+ class Element
+ class Line < Element
+ attr_accessor :fill, :stroke
+
+ def coordinates
+ @args
+ end
+
+ def coordinates=(*new_coordinates)
+ new_coordinates = new_coordinates.first if new_coordinates.size == 1 && new_coordinates.first.is_a?(Array)
+ @args = *new_coordinates
+ end
+
+ def build
+ case @parent
+ when Glimmer::Pixelart::Element::Canvas
+ @parent.path(stroke: @stroke, fill: @fill).line(*coordinates)
+ when Glimmer::Pixelart::Element::Path
+ @parent.parent.path(stroke: @parent.stroke, fill: @parent.fill).line(*coordinates)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/pixelart/lib/glimmer/pixelart/element/path.rb b/pixelart/lib/glimmer/pixelart/element/path.rb
new file mode 100644
index 0000000..f90d99b
--- /dev/null
+++ b/pixelart/lib/glimmer/pixelart/element/path.rb
@@ -0,0 +1,9 @@
+module Glimmer
+ module Pixelart
+ class Element
+ class Path < Element
+ attr_accessor :fill, :stroke
+ end
+ end
+ end
+end
diff --git a/pixelart/lib/pixelart/glimmer.rb b/pixelart/lib/pixelart/glimmer.rb
new file mode 100644
index 0000000..66e7335
--- /dev/null
+++ b/pixelart/lib/pixelart/glimmer.rb
@@ -0,0 +1,3 @@
+require 'glimmer'
+
+require_relative '../glimmer/dsl/pixelart/dsl'
diff --git a/pixelart/sandbox/test_glimmer.rb b/pixelart/sandbox/test_glimmer.rb
new file mode 100644
index 0000000..bd545fb
--- /dev/null
+++ b/pixelart/sandbox/test_glimmer.rb
@@ -0,0 +1,88 @@
+###
+# to run use
+# ruby -I ./lib sandbox/test_vector.rb
+
+
+require 'pixelart/glimmer'
+
+
+include Glimmer # activates Glimmer DSL for Pixelart (in real apps, mix into a class instead)
+
+def face
+ line {
+ coordinates 6, 23, 6, 14,
+ 5, 14, 5, 13, 4, 12,
+ 5, 11, 6, 11, 6, 7, 7, 6, 8, 5,
+ 14, 5, 15, 6,
+ 16, 7, 16, 19, 15, 20, 14, 21, 10, 21, 10, 23
+ fill '#c8fbfb'
+ stroke 'black'
+ }
+end
+
+def mouth
+ line( 10, 18, 14, 18 ) {
+ stroke 'black'
+ }
+end
+
+def nose
+ line( 12, 16, 12, 14 ) {
+ stroke '#9be0e0'
+ }
+end
+
+def eyes
+ path {
+ line( 9, 13, 9, 12 )
+ line( 10, 12, 10, 11 )
+ line( 14, 13, 14, 12 )
+ line( 15, 12, 15, 11 )
+
+ stroke 'black'
+ }
+
+ path {
+ line( 10, 13, 10, 12 )
+ line( 15, 13, 15, 12 )
+
+ stroke '#9be0e0'
+ }
+
+ path {
+ line( 9, 12, 9, 11 )
+ line( 14, 12, 14, 11 )
+
+ stroke '#75bdbd'
+ }
+end
+
+def headband
+ line( 7, 8, 15, 8 ) {
+ stroke '#1a6ed5'
+ }
+
+ line( 7, 7, 15, 7 ) {
+ stroke 'white'
+ }
+end
+
+image = canvas(24, 24) {
+ file './tmp/punk3100.svg' # auto-saves file when canvas expression closes
+
+ face
+ mouth
+ nose
+ eyes
+ headband
+}
+
+# Re-open content to modify attributes and add more shapes
+image.content {
+ file './tmp/punk3100-round-nose.svg' # auto-saves file when content closes
+
+ ## Round Nose
+ circle( 12, 15, 1 ) {
+ fill '#9be0e0'
+ }
+}
diff --git a/pixelart/sandbox/test_vector.rb b/pixelart/sandbox/test_vector.rb
index 5e56b59..88cbae6 100644
--- a/pixelart/sandbox/test_vector.rb
+++ b/pixelart/sandbox/test_vector.rb
@@ -38,5 +38,3 @@
canvas.save( "./tmp/punk3100.svg" )
-
-