I like sending New Year's cards. Each year I prepare the design, buy these blank cards, and print them at home. This year I thought I'd try quil, basically Processing in clojure, to draw some fancy patterns for it. Because I can't draw at all...
Edit: syngrato adapted this code into ClojureScript (Thanks!). You can have some fun here. The license is MIT.
Design
Motif
What kind of pattern is suitable for New Year's cards? In Japan (I'm a Japanese, by the way), things which we can wish each other's health and prosperity with have been popular --- pine trees, cranes, and turtles to name some. They are symbols of health & long lives because they live long (always green for pines). Another popular symbol is the ume 梅, Japanese apricot, because they bloom the earliest in spiring and celebrating the New Year is all about celebrating the coming spring.
Ume flowers are traditionally abstracted into design (for lack of my vocab) like this:
(Image taken from this site, which allows replication). Five circles with stamen nicely signifies the ume flowers. I like them and its simplicity will go well with quil.
I talked with Mom and she suggested a traditional design called 利休梅 (do check out the link which is google image search), where the flower is symbolised with 5+1 circles + lines connecting the centre and the petals.
The flowers are, she says, usually scattered to form a design. Maybe I can tile them to make a pattern?
Pattern
Tessellation is always an interesting topic. For pentagons, I found the Cairo pentagonal tiling quite beautiful and symmetric (remember we'll be putting flowers to the pentagons)
(Image by TED-43, licensed under the CC-BY License.)
So let's assign a flower to each of the pentagon there. From now on, I'll call the hexagon formed by 4 pentagons Hexa. Let the length of the squares and regular triangles r, which I set to 50px in the code.
Coding
Let's look at a Hexa and name some lengths. The structure is so elegant that every length I'll need can be calculated nicely. Here's a doodle I drew while coding, which shows how the lengths r1
- r3
is defined.
After these simple math, coding itself is quite straightforward. To make things easier, a Hexa is drawn in an angle where it stands straight. I defined draw-flower
to draw a single flower; draw-hex-pattern
for a Hexa, in which 4 draw-flower
is called with appropriate translation and rotation; then draw-hex-at
, which accepts the location in the form of (structure hexa x y)
, where x
and y
are the hexagonal coordinates. Full code (which is probably not ideal) follows..
; licensed under the MIT license
(ns nen.core
(:require [quil.core :as q]
[quil.middleware :as m]))
(defstruct hexa :x :y)
(def r 50)
(def r1 (/ r (Math/sqrt 3)))
(def r2 (* r (+ 1 (/ 1 (Math/sqrt 3)))))
(def r3 (/ (* r (+ 1 (Math/sqrt 3))) 2))
(def corolla-size 15)
(def centre-size 12)
(def str-w 3)
(defn draw-corolla [x y] (q/ellipse x y corolla-size corolla-size))
(defn draw-corolla-r [x y]
(let [dx (* 0.1 corolla-size (- (Math/random) 0.5))
dy (* 0.1 corolla-size (- (Math/random) 0.5)) ]
(draw-corolla (+ x 0) (+ y 0))
)
)
(defn draw-flower []
(q/fill 223 130 138)
(doseq
; every corolla is located half-way for aesthetics
[ [x y]
[[0 0]
[(/ r2 8) (/ r3 4)]
[(/ r2 8) (- (/ r3 4))]
[(/ (+ r1 r2) 4) (/ r1 4)]
[(/ (+ r1 r2) 4) ( - (/ r1 4))] ]]
(do
(q/stroke 223 130 138)
(q/stroke-weight str-w)
(q/line (/ r1 2) 0 x y)
(q/no-stroke)
(draw-corolla-r x y)))
(q/fill 248 181 0)
(q/ellipse (/ r1 2) 0 centre-size centre-size)
)
(defn draw-hex-pattern []
(q/fill 223 130 138)
(draw-flower)
(q/with-translation
[ (/ (+ r1 r2) 2) (- (/ r1 2)) ]
(q/with-rotation
[(/ Math/PI -2)]
(draw-flower)))
(q/with-translation
[ (/ (+ r1 r2) 2) (/ r1 2) ]
(q/with-rotation
[(/ Math/PI 2)]
(draw-flower)))
(q/with-translation
[ (+ r1 r2) 0 ]
(q/with-rotation
[Math/PI]
(draw-flower)))
)
(defn draw-hex-at [h]
(q/with-translation
[
(* (:x h) (+ r1 (/ r2 2)) )
(+
(* 2 r3 (:y h))
(if (even? (:x h))
0
r3))]
(draw-hex-pattern)))
(defn setup []
(q/frame-rate 30)
(q/color-mode :rgb)
(for [x (range 10) y (range 5)]
(struct hexa x y)))
(defn update-state [s] s)
(defn draw-state [state]
(q/background 255)
(q/no-loop)
(q/with-translation [50 100]
(doseq [h state]
(draw-hex-at h)))
(q/save "out.png")
)
(q/defsketch nen
:title "super-omedetai"
:size [800 800]
; setup function called only once, during sketch initialization.
:setup setup
; update-state is called on each iteration before draw-state.
:update update-state
:draw draw-state
:features [:keep-on-top]
:middleware [m/fun-mode])
which results in something like this:
That looks beautiful. I love it.
After adding some texts and my hand-written messages (which is blurred in this post) and my name, here's my new year's card. I'd use the spaces in top-left to add some personal messages to each person.
I wish you all a happy new year, and hope that 2018 will be a wonderful year for all of us.
Top comments (2)
Here is lightly modified ClojureScript version running in the online Quil playground quil.info/sketches/show/-L2Fznrshf...
Hi, thank you! I was thinking of doing it myself :) One thing I love about quil is that I can make it run on browsers pretty easily (and it runs smooth). I have added the link to my post.