diff --git a/content/memex/art-design/colour.md b/content/memex/art-design/colour.md
new file mode 100644
index 00000000..0dfe1757
--- /dev/null
+++ b/content/memex/art-design/colour.md
@@ -0,0 +1,20 @@
+---
+title: Colour
+emoji: π
+summary: The different frequencies in the human visible spectrum used for fun, communication, art and more.
+draft: false
+tags:
+- css
+- lch
+- vision
+- deliveroo
+- colour
+---
+
+## Spelling
+
+I spell colour with a U (as I'm British) while I'm writing text for humans, but without when I'm writing text for computers (as software languages like #css were created or standardised for American English spelling, `color: red`). This can get confusing when I'm talking about writing code about colours. Weird eh? This was a decision made in the early days of #Deliveroo, and it's kinda stuck with me.
+
+## LCH colours
+
+I'm a big fan of the [LCH colour space](https://css.land/lch/), which is designed to allow for consistent human-perceived luminescence as the hue and chroma change. [Read more here](https://lea.verou.me/blog/2020/04/lch-colors-in-css-what-why-and-how/).
diff --git a/content/memex/art-design/fonts.md b/content/memex/art-design/fonts.md
index 53adbb51..62e65931 100644
--- a/content/memex/art-design/fonts.md
+++ b/content/memex/art-design/fonts.md
@@ -3,6 +3,11 @@ title: Fonts
emoji: π‘
summary: Instructions for how to turn streams of data into legible writing.
draft: false
+tags:
+- ttf
+- zwj
+- emoji
+- fonts
---
## TTF Fonts
diff --git a/content/memex/art-design/pottery.md b/content/memex/art-design/pottery.md
index b84fdcbd..b9d2fdbc 100644
--- a/content/memex/art-design/pottery.md
+++ b/content/memex/art-design/pottery.md
@@ -2,6 +2,10 @@
title: Pottery
emoji: πΊ
summary: Making objects out of clay.
+tags:
+- clay
+- course
+- pottery
---
## Turning clay
diff --git a/content/memex/art-design/spectre.svg b/content/memex/art-design/spectre.svg
new file mode 100644
index 00000000..4cf2f807
--- /dev/null
+++ b/content/memex/art-design/spectre.svg
@@ -0,0 +1,355 @@
+
+
\ No newline at end of file
diff --git a/content/memex/art-design/tiles.md b/content/memex/art-design/tiles.md
index 1220be08..342fb86a 100644
--- a/content/memex/art-design/tiles.md
+++ b/content/memex/art-design/tiles.md
@@ -2,6 +2,11 @@
title: Tiles
emoji: π²
summary: Shapes that fit together to create an infinite pattern.
+tags:
+- monotile
+- shapes
+- tiling
+- colour
---
## Aperiodic monotiles
@@ -12,6 +17,192 @@ summary: Shapes that fit together to create an infinite pattern.
I've designed 3D-printed cookie cutters that could make ceramic tiles with these, but I've not reached out to my local potters to ask for some time to make them β and I haven't figured out the 'rules' for placing a tile next to others, some placings definitely end up making tilings that can't be completed.
+## Spectre + Tantrix
+
+I wrote a little code a few weekends ago to try and figure out if I could make a Spectre tiling that also had lines that travelled across the tiles β something like a tiling game I used to play called [Tantrix](http://www.tantrix.com/).
+
+Though there are some lines that close (you can see some here) I have a _hunch_ that there may be provably non-zero many that never close. I have no idea how to go about proving that though!
+
+{{< figure src="../spectre.svg" title="My spectre & tantrix crossover tiling, each one with a #colour chosen for its angle of rotation." alt="A computer-generated tiling of 20 identical 14-sided irregular shapes. They vary in light pastel colours. Each of the 14 sides inside each shape is connected with a different side by a white line, making a big but pretty knot of white lines connected through each of the shapes.">}}
+
+The code for making this is below; but it's definitely not polished!
+
+Code for creating Spectre + Tantrix crossover
+
+```ruby
+require 'victor'
+include Victor
+
+class Spectre
+ attr_reader :points
+
+ # Angle 1 is the angle between side 1 and side 2 etc.
+ ANGLES = [90, 60, -90, 60, 0, 60, 90, -60, 90, -60, 90, 60, -90, 60].freeze
+ SIDE_LENGTH = 25
+ LINE_WIDTH = 2.5
+ CONTROL_LEN_MULT = 0.4
+
+ SHOW_NAME = false
+
+ ARCS = [
+ [7, 9],
+ [3, 11],
+ [0, 13],
+ [2, 8],
+ [5, 10],
+ [4, 6],
+ [1, 12],
+ ]
+
+ def initialize(origin, corner_index, rotation, name: nil, show_corner_indeces: false)
+ @show_corner_indeces = show_corner_indeces
+ @hue = ANGLES[corner_index..].sum(-rotation) % 360
+ @indexes = (0...ANGLES.length).cycle.take(corner_index + ANGLES.length)[corner_index..]
+ @name = name || (@@i ||= 1).to_s
+
+ previous_angle = -rotation
+ @points = @indexes.each_with_object([[origin[0], origin[1]]]) do |idx, acc|
+ previous_angle += ANGLES[idx]
+ ang = previous_angle / 180.0 * Math::PI
+ acc.push([
+ acc.last[0] + SIDE_LENGTH*Math.sin(ang),
+ acc.last[1] + SIDE_LENGTH*Math.cos(ang)
+ ])
+ end
+
+ @background = "hsl(#{@hue}, 100%, 85%)"
+ # @background = "hsl(#{(@hue / 90).floor * 90}, 100%, 85%)"
+ # @background = "hsl(23, 100%, 72%)"
+
+ @@i += 1
+ end
+
+ def point(idx) = @points[@indexes.index(idx)]
+
+ def between(idx1, idx2) = [
+ point(idx1)[0] + (point(idx2)[0] - point(idx1)[0])/2,
+ point(idx1)[1] + (point(idx2)[1] - point(idx1)[1])/2
+ ]
+
+ def normal_point(idx1, idx2, n_dist)
+ b = between(idx1, idx2)
+ p1 = point(idx1)
+ p2 = point(idx2)
+ dx = p2[0] - p1[0]
+ dy = p2[1] - p1[1]
+ b_ang = Math.atan2(dy, dx)
+ b_dist = Math.sqrt(dx*dx + dy*dy) / 2
+
+ n_ang = Math.atan2(n_dist, b_dist)
+
+ t_ang = b_ang - n_ang
+ t_dist = Math.sqrt(n_dist*n_dist + b_dist*b_dist)
+ n_x = Math.cos(t_ang) * t_dist
+ n_y = Math.sin(t_ang) * t_dist
+ [p1[0] + n_x, p1[1] + n_y]
+ end
+
+
+ def svg
+ SVG.new.tap do |svg|
+ svg.polygon points: @points, stroke: 'none', fill: @background
+
+ ARCS.each do |(i1, i2)|
+ i1next = (i1 + 1) % ANGLES.length
+ i2next = (i2 + 1) % ANGLES.length
+ p1 = between(i1, i1next)
+ p2 = between(i2, i2next)
+ dx = (p2[0] - p1[0])
+ dy = (p2[1] - p1[1])
+ mid_dist = Math.sqrt(dx*dx + dy*dy)
+ c1 = normal_point(i1, i1next, mid_dist*CONTROL_LEN_MULT)
+ c2 = normal_point(i2, i2next, mid_dist*CONTROL_LEN_MULT)
+
+ show_control_points = false
+ if show_control_points
+ svg.circle cx: p1[0], cy: p1[1], r: 2, fill: 'green'
+ svg.line x1: p1[0], y1: p1[1], x2: c1[0], y2: c1[1], stroke: 'green'
+ svg.circle cx: c1[0], cy: c1[1], r: 2, fill: 'green'
+ svg.circle cx: c2[0], cy: c2[1], r: 2, fill: 'green'
+ svg.line x1: p2[0], y1: p2[1], x2: c2[0], y2: c2[1], stroke: 'green'
+ svg.circle cx: p2[0], cy: p2[1], r: 2, fill: 'green'
+ end
+
+ svg.path d: "M#{p1[0]},#{p1[1]}C#{c1[0]} #{c1[1]},#{c2[0]} #{c2[1]},#{p2[0]} #{p2[1]}", stroke: @background, stroke_width: LINE_WIDTH*2, fill: 'none'
+ svg.path d: "M#{p1[0]},#{p1[1]}C#{c1[0]} #{c1[1]},#{c2[0]} #{c2[1]},#{p2[0]} #{p2[1]}", stroke: 'white', stroke_width: LINE_WIDTH, fill: 'none'
+ end
+
+ centre = between(2, 7)
+
+ if SHOW_NAME
+ svg.text(
+ @name,
+ x: centre[0],
+ y: centre[1],
+ font_family: 'arial',
+ font_size: 16,
+ text_anchor: "middle",
+ dominant_baseline: "middle"
+ )
+ end
+
+ svg.polygon points: @points, stroke: 'black', fill: 'none'
+
+ if @show_corner_indeces
+ @points[0..-2].each.with_index do |p, idx|
+ svg.circle cx: p[0], cy:p[1], r: 5, fill: "hsla(#{@hue}, 100%, 95%, 85%)"
+ svg.text(
+ @indexes[idx],
+ x: p[0],
+ y: p[1],
+ font_family: 'arial',
+ font_size: 6,
+ text_anchor: "middle",
+ dominant_baseline: "middle"
+ )
+ end
+ end
+ end
+ end
+
+ def into(svg)
+ svg << self.svg
+ self
+ end
+end
+
+
+svg = Victor::SVG.new width: 475, height: 400
+
+s1 = Spectre.new([100, 100], 0, 0).into(svg)
+s2 = Spectre.new(s1.point(2), 8, 120).into(svg)
+s3 = Spectre.new(s1.point(4), 8, 60).into(svg)
+s4 = Spectre.new(s3.point(2), 10, 30).into(svg)
+s5 = Spectre.new(s3.point(10), 8, 120).into(svg)
+s6 = Spectre.new(s3.point(0), 2, 0).into(svg)
+s7 = Spectre.new(s5.point(2), 0, 90).into(svg)
+s8 = Spectre.new(s7.point(2), 10, 210).into(svg)
+s9 = Spectre.new(s5.point(12), 0, -150).into(svg)
+s10 = Spectre.new(s2.point(12), 6, -150).into(svg)
+s11 = Spectre.new(s6.point(9), 3, 90).into(svg)
+s12 = Spectre.new(s6.point(12), 0, 30).into(svg)
+s13 = Spectre.new(s11.point(7), 3, 120).into(svg)
+s14 = Spectre.new(s11.point(12), 6, 30).into(svg)
+s15 = Spectre.new(s13.point(0), 6, 90).into(svg)
+s16 = Spectre.new(s8.point(2), 0, 210).into(svg)
+s17 = Spectre.new(s16.point(12), 6, 90).into(svg)
+s18 = Spectre.new(s17.point(2), 0, 30).into(svg)
+s19 = Spectre.new(s7.point(6), 0, 90).into(svg)
+s20 = Spectre.new(s13.point(10), 10, 120).into(svg)
+s21 = Spectre.new(s4.point(2), 10, 30).into(svg)
+s22 = Spectre.new(s15.point(4), 8, 60).into(svg)
+
+svg.save 'spectre'
+```
+
+