There is a sketch on OpenProcessing which seems to have much more detail with OpenSimplexNoise:-

```
attr_reader :img, :colors, :theta, :phi, :remap1, :remap2
R = 5
RR = 1
def setup
sketch_title 'PNoise Pattern'
color_mode(RGB, 1.0)
@theta = 0
@phi = 0
# the dimensions of the image are twice the dimentions of
# the canvas to add antialiasing when the image is reduced
@img = create_image(2 * width, 2 * height, RGB)
@colors = (0..255).map { color(rand, rand, rand) }
@remap1 = ->(a, b, c) { ((SmoothNoise.noise(a, b, c) + 1) * 128).floor }
@remap2 = ->(a, b) { ((SmoothNoise.noise(a, b) + 1) * 128).floor }
end
def noisef(a, b, c, t)
remap2.call(remap1.call(a, b, c), t)
end
def draw
# fill the array with rand colors
# create pattern
img.load_pixels
grid(img.width, img.height) do |x, y|
# map x and y to angles between 0 and TWO_PI
@theta = map1d(x, 0..img.width, 0..TWO_PI)
@phi = map1d(y, 0..img.height, 0..TWO_PI)
# calculate the parameters of noise with the equation of a torus
# this is used to make the pattern seamless
nx = (R + RR * cos(phi)) * cos(theta)
ny = (R + RR * cos(phi)) * sin(theta)
nz = RR * sin(phi)
# normalize noise parameters so that the de pattern has homogeneous dimensions
nx = norm(nx, 0, R + RR)
ny = norm(ny, 0, R + RR)
nz = norm(nz, 0, RR)
# apply noise twice and use the equivalent color on the pallete
img.pixels[x + y * img.width] = colors[noisef(nx, ny, nz, frame_count / 5)]
end
img.update_pixels
# display pattern
image(img, 0, 0, width, height) # the image is reduce to the size of the canvas to make it smooth
end
def key_pressed
save(data_path('image.png'))
end
def settings
size(500, 500)
end
```

An interesting thing that came out of this experiment is you have to be careful where you declare your lambda functions (in this case within setup made most sense). I made virtue out of necessity when I created my `remap`

lambdas necessary because of SimplexNoise `range (-1.0..1.0)`

*cf* processing (and Perlin) noise `range(0..1.0`

).