Skip to content

Commit e8567c0

Browse files
vipenzoclaude
andcommitted
Manual: gallery Hamiltonian cycle, voronoi hi-res, fix reduce example, IT titles
- Add Hamiltonian Cycle gallery page (contributed by u/Eternally_Monika) - Bump shell-voronoi examples to 256 resolution with performance note - Fix reduce example: wrap mesh-union macro in fn for reduce - IT titles: "Usare Attach con una Mesh" / "con le Facce" Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9942168 commit e8567c0

File tree

2 files changed

+64
-9
lines changed

2 files changed

+64
-9
lines changed

dev-docs/Examples.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,8 @@ Shell wraps a shape into a hollow wall with variable thickness. Where the thickn
341341
(register checkerboard (loft-n 64 (shell-checkerboard (circle 20 64) :thickness 2 :cols 8 :rows 8) (f 60)))
342342
(register lattice2 (loft-n 64 (shell-lattice (circle 20 64) :thickness 2 :openings 8 :rows 12) (f 60)))
343343
(register weave (loft-n 64 (shell-weave (circle 20 64) :thickness 2 :strands 6 :frequency 8) (f 60)))
344-
(register voronoi (loft-n 64 (shell-voronoi (circle 20 64) :thickness 2 :cells 8 :rows 8) (f 60)))
344+
;; Note: Voronoi needs high resolution (256+) for best results — may take a few seconds
345+
(register voronoi (loft-n 256 (shell-voronoi (circle 20 256) :thickness 2 :cells 8 :rows 8) (f 60)))
345346

346347
;; Tapered lattice cone
347348
(register tapered-lattice

src/ridley/manual/content.cljs

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@
131131
{:id :shell-lattice
132132
:code "(register bricks\n (loft-n 64\n (shell-lattice (circle 20 64)\n :thickness 2 :openings 8 :rows 12 :shift 0.5)\n (f 60)))"}
133133
{:id :shell-voronoi
134-
:code "(register organic\n (loft-n 64\n (shell-voronoi (circle 20 64)\n :thickness 2 :cells 8 :rows 8 :seed 42)\n (f 60)))"}
134+
:code "(register organic\n (loft-n 256\n (shell-voronoi (circle 20 256)\n :thickness 2 :cells 8 :rows 8 :seed 42)\n (f 60)))"}
135135
{:id :shell-tapered
136136
:code "(register tapered-lattice\n (loft-n 64\n (-> (circle 20 64)\n (shell :thickness 2\n :fn (fn [a t]\n (max 0 (sin (+ (* a 8) (* t PI 4))))))\n (tapered :to 0.5))\n (f 60)))"}
137137
{:id :woven-diagonal
@@ -351,7 +351,7 @@
351351
[{:id :map-basic
352352
:code "(register sizes\n (for [r (map #(* % 5) [1 2 3 4])]\n (attach (sphere r) (f (* r 3)))))"}
353353
{:id :reduce-union
354-
:code "(register merged\n (reduce mesh-union\n (for [i (range 5)]\n (attach (box 10) (f (* i 15))))))"}
354+
:code "(register merged\n (reduce (fn [a b] (mesh-union a b))\n (for [i (range 5)]\n (attach (box 10) (f (* i 15))))))"}
355355
{:id :map-indexed
356356
:code "(register staircase\n (for [[i size] (map-indexed vector [8 12 16 20])]\n (attach (extrude (circle size) (f 5))\n (f (* i 8)))))"}]}
357357
{:id :repl-usage
@@ -380,6 +380,10 @@
380380
:examples
381381
[{:id :embossed-column-code
382382
:code "(def col-radius 15)\n(def col-height 80)\n(def n-flutes 16)\n(def flute-depth 0.12)\n\n(def letters (text-shape \"RIDLEY\" :size 20))\n(def text-mesh (turtle (tv 90) (concat-meshes (extrude letters (f 3)))))\n(def text-bounds (bounds text-mesh))\n(def text-hm\n (mesh-to-heightmap text-mesh\n :resolution 128\n :offset-x (get-in text-bounds [:min 0])\n :offset-y (get-in text-bounds [:min 1])\n :length-x (- (get-in text-bounds [:max 0]) (get-in text-bounds [:min 0]))\n :length-y (- (get-in text-bounds [:max 1]) (get-in text-bounds [:min 1]))))\n\n(def shaft\n (loft-n 96\n (-> (circle col-radius 64)\n (fluted :flutes n-flutes :depth flute-depth)\n (heightmap text-hm :amplitude 1.5 :center true :tile-x 2 :tile-y 1))\n (f col-height)))\n\n(def base\n (attach\n (loft-n 8\n (tapered (circle (* col-radius 1.4) 64) :to (/ 1 1.4))\n (f 6))\n (tv 180)))\n\n(def capital\n (attach\n (loft-n 8\n (tapered (circle col-radius 64) :to 1.3)\n (f 5))\n (f col-height)))\n\n(def column (concat-meshes [base shaft capital]))\n(register column column)"}]}
383+
{:id :gallery-hamiltonian-cycle
384+
:examples
385+
[{:id :hamiltonian-cycle-code
386+
:code ";; Hamiltonian Cycle on a Grid — by u/Eternally_Monika\n;; Config\n(def cols 10)\n(def rows 10)\n(def cell-size 10)\n(def path-width 4)\n(def path-thickness 1)\n(def mixing-steps 1000)\n(def max-search-steps (* rows cols rows cols))\n\n(assert (even? (* cols rows))\n \"Hamiltonian cycles are impossible on odd-sized grids.\")\n\n;; Logic\n(defn make-snake [c r]\n (vec (for [y (range r)\n x (if (even? y) (range c) (reverse (range c)))]\n [x y])))\n\n(defn in-bounds? [[x y]]\n (and (>= x 0) (< x cols) (>= y 0) (< y rows)))\n\n(defn on-boundary? [[x y]]\n (or (= x 0) (= x (dec cols)) (= y 0) (= y (dec rows))))\n\n(defn abs [n] (max n (- n)))\n\n(defn manhattan-dist [p1 p2]\n (+ (abs (- (first p1) (first p2)))\n (abs (- (second p1) (second p2)))))\n\n(defn reverse-prefix [path idx]\n (vec (concat (reverse (take idx path)) (drop idx path))))\n\n(defn find-index [coll target]\n (first (keep-indexed #(when (= %2 target) %1) coll)))\n\n(defn backbite-step [path]\n (let [work-path (if (> (rand) 0.5) (vec (reverse path)) path)\n head (first work-path)\n neck (second work-path)\n [hx hy] head\n candidates [[(inc hx) hy] [(dec hx) hy]\n [hx (inc hy)] [hx (dec hy)]]\n valid-neighbors (filter #(and (in-bounds? %)\n (not= % neck))\n candidates)]\n (if (empty? valid-neighbors)\n work-path\n (let [chosen (rand-nth valid-neighbors)\n cut-idx (find-index work-path chosen)]\n (reverse-prefix work-path cut-idx)))))\n\n(defn find-cycle [path step limit]\n (let [head (first path)\n tail (last path)\n is-cycle (and (= 1 (manhattan-dist head tail))\n (on-boundary? head)\n (on-boundary? tail))]\n (if (or is-cycle (>= step limit))\n path\n (recur (backbite-step path) (inc step) limit))))\n\n(defn roll-to-zero [path]\n (let [idx (find-index path [0 0])]\n (vec (concat (drop idx path) (take idx path)))))\n\n;; Execution\n(def initial-snake (make-snake cols rows))\n\n(def mixed-path\n (loop [p initial-snake i 0]\n (if (< i mixing-steps)\n (recur (backbite-step p) (inc i))\n p)))\n\n(def raw-cycle (find-cycle mixed-path 0 max-search-steps))\n(def path-points (roll-to-zero raw-cycle))\n\n;; Rendering\n(def cycle-path\n (path\n (loop [pts (conj (vec path-points) (first path-points))\n curr-heading 0]\n (when (> (count pts) 1)\n (let [[[x1 y1] [x2 y2]] pts\n dx (- x2 x1)\n dy (- y2 y1)\n target-heading (cond\n (> dx 0) 0 (> dy 0) 90\n (< dx 0) 180 (< dy 0) -90\n :else curr-heading)\n diff (mod (- target-heading curr-heading) 360)\n turn (if (> diff 180) (- diff 360) diff)]\n (when-not (zero? turn) (th turn))\n (f cell-size)\n (recur (rest pts) target-heading))))))\n\n(register cycle-mesh\n (extrude (rect path-width path-thickness) cycle-path))"}]}
383387
{:id :gallery-canvas-weave
384388
:examples
385389
[{:id :canvas-weave-code
@@ -751,7 +755,7 @@ Both `shell` and `woven-shell` compose with other shape-fns via `->` threading:
751755
:shell-lattice {:caption "Brick lattice"
752756
:description "`shell-lattice` creates a grid of openings. `:shift 0.5` offsets alternate rows for a brick pattern."}
753757
:shell-voronoi {:caption "Voronoi openings"
754-
:description "`shell-voronoi` creates organic, irregular cell-shaped openings using Voronoi distance."}
758+
:description "`shell-voronoi` creates organic, irregular cell-shaped openings using Voronoi distance. Best at high resolution (256+) — rendering may take a few seconds."}
755759
:shell-tapered {:caption "Tapered lattice"
756760
:description "Shell composes with `tapered` — the lattice narrows toward the end."}
757761
:woven-diagonal {:caption "Woven diagonal"
@@ -867,7 +871,7 @@ These compose naturally: `(map f (filter pred coll))`. Combined with `for`, they
867871
{:map-basic {:caption "Map"
868872
:description "`map` applies a function to each element. Here we scale a list of values to get radii, then create spheres."}
869873
:reduce-union {:caption "Reduce"
870-
:description "`reduce` combines elements pairwise. Here we merge multiple boxes into a single mesh with `mesh-union`."}
874+
:description "`reduce` combines elements pairwise. Here we merge multiple boxes into a single mesh with `mesh-union`. Note: `mesh-union` is a macro, so it must be wrapped in `(fn [a b] ...)` to pass it to `reduce`."}
871875
:map-indexed {:caption "Map-indexed"
872876
:description "`map-indexed` pairs each element with its index. Useful for positioning objects along a sequence."}}}
873877

@@ -1504,6 +1508,31 @@ The text is converted to a 2D shape with `text-shape`, extruded into a thin 3D m
15041508
:examples
15051509
{:embossed-column-code {:caption "Embossed Column"}}}
15061510

1511+
:gallery-hamiltonian-cycle
1512+
{:title "Hamiltonian Cycle"
1513+
:content "A **random Hamiltonian cycle** on a grid, rendered as a 3D path. Contributed by **u/Eternally_Monika** on Reddit.
1514+
1515+
A Hamiltonian cycle visits every node in a grid exactly once, returning to the start. This script generates one algorithmically using the **backbite algorithm**: start with a snake path, then randomly perturb it thousands of times until a valid cycle emerges.
1516+
1517+
The result is converted to turtle movements and extruded with a flat rectangle cross-section.
1518+
1519+
This example showcases why having a **real programming language** as a modeling base matters: graph theory algorithms, `loop`/`recur`, `assert`, random number generation — all natively available.
1520+
1521+
**Features demonstrated:**
1522+
- Algorithmic geometry — path generated by backbite random walk
1523+
- `loop`/`recur` for iterative algorithms
1524+
- `assert` for input validation
1525+
- `path` with dynamic turtle commands from computed data
1526+
- `extrude` along a programmatically generated path
1527+
1528+
**Try changing:**
1529+
- `cols` / `rows` for different grid sizes (product must be even)
1530+
- `cell-size` for spacing
1531+
- `path-width` / `path-thickness` for the ribbon dimensions
1532+
- `mixing-steps` for more randomization (higher = more shuffled)"
1533+
:examples
1534+
{:hamiltonian-cycle-code {:caption "Hamiltonian Cycle"}}}
1535+
15071536
:gallery-canvas-weave
15081537
{:title "Canvas Weave Cup"
15091538
:content "A cup with **woven canvas texture** on the outside. This is the most complex example in the gallery.
@@ -1891,7 +1920,7 @@ Sia `shell` che `woven-shell` si compongono con altre shape-fn tramite `->`:
18911920
:shell-lattice {:caption "Reticolo a mattone"
18921921
:description "`shell-lattice` crea una griglia di aperture. `:shift 0.5` sfasa le righe alternate per un effetto mattone."}
18931922
:shell-voronoi {:caption "Aperture Voronoi"
1894-
:description "`shell-voronoi` crea aperture organiche e irregolari a forma di cella usando la distanza di Voronoi."}
1923+
:description "`shell-voronoi` crea aperture organiche e irregolari a forma di cella usando la distanza di Voronoi. Rende meglio ad alta risoluzione (256+) — il rendering potrebbe richiedere qualche secondo."}
18951924
:shell-tapered {:caption "Reticolo rastremato"
18961925
:description "Shell si compone con `tapered` — il reticolo si restringe verso la fine."}
18971926
:woven-diagonal {:caption "Tessuto diagonale"
@@ -2007,7 +2036,7 @@ Si compongono naturalmente: `(map f (filter pred coll))`. Combinati con `for`, o
20072036
{:map-basic {:caption "Map"
20082037
:description "`map` applica una funzione a ogni elemento. Qui scaliamo una lista di valori per ottenere raggi, poi creiamo sfere."}
20092038
:reduce-union {:caption "Reduce"
2010-
:description "`reduce` combina elementi a coppie. Qui uniamo più box in una singola mesh con `mesh-union`."}
2039+
:description "`reduce` combina elementi a coppie. Qui uniamo più box in una singola mesh con `mesh-union`. Nota: `mesh-union` è una macro, quindi va wrappata in `(fn [a b] ...)` per passarla a `reduce`."}
20112040
:map-indexed {:caption "Map-indexed"
20122041
:description "`map-indexed` accoppia ogni elemento con il suo indice. Utile per posizionare oggetti lungo una sequenza."}}}
20132042

@@ -2112,7 +2141,7 @@ Il piano di taglio è orizzontale all'altezza Y corrente della tartaruga (o a un
21122141
:description "Lo stesso toroide tagliato su due piani diversi. Il piano di taglio è perpendicolare alla direzione della tartaruga nella sua posizione corrente."}}}
21132142

21142143
:attach-meshes
2115-
{:title "Attaccare Mesh"
2144+
{:title "Usare Attach con una Mesh"
21162145
:content "La funzione `attach` trasforma una mesh con movimenti turtle, restituendo una nuova mesh. Usa `attach!` per trasformare una mesh registrata in-place per nome.
21172146
21182147
```
@@ -2132,7 +2161,7 @@ Il piano di taglio è orizzontale all'altezza Y corrente della tartaruga (o a un
21322161
:description "Le copie possono includere rotazioni. Qui `tv` inclina e `tr` ruota la tartaruga prima di posizionare la copia."}}}
21332162

21342163
:attach-faces
2135-
{:title "Attaccare alle Facce"
2164+
{:title "Usare Attach con le Facce"
21362165
:content "La funzione `attach-face` attacca geometria a una faccia specifica di una mesh. Usa keyword (`:top`, `:bottom`, `:front`, `:back`, `:left`, `:right`) o indici 0-5.
21372166
21382167
```
@@ -2644,6 +2673,31 @@ Il testo viene convertito in forma 2D con `text-shape`, estruso in una mesh 3D s
26442673
:examples
26452674
{:embossed-column-code {:caption "Colonna con Testo in Rilievo"}}}
26462675

2676+
:gallery-hamiltonian-cycle
2677+
{:title "Ciclo Hamiltoniano"
2678+
:content "Un **ciclo Hamiltoniano casuale** su una griglia, renderizzato come percorso 3D. Contributo di **u/Eternally_Monika** su Reddit.
2679+
2680+
Un ciclo Hamiltoniano visita ogni nodo della griglia esattamente una volta, tornando al punto di partenza. Questo script ne genera uno algoritmicamente usando l'**algoritmo backbite**: si parte da un percorso a serpentina, poi lo si perturba casualmente migliaia di volte fino a ottenere un ciclo valido.
2681+
2682+
Il risultato viene convertito in movimenti turtle ed estruso con una sezione rettangolare piatta.
2683+
2684+
Questo esempio dimostra perché avere un **vero linguaggio di programmazione** come base di modellazione fa la differenza: algoritmi di teoria dei grafi, `loop`/`recur`, `assert`, generazione di numeri casuali — tutto disponibile nativamente.
2685+
2686+
**Funzionalità dimostrate:**
2687+
- Geometria algoritmica — percorso generato da random walk backbite
2688+
- `loop`/`recur` per algoritmi iterativi
2689+
- `assert` per validazione degli input
2690+
- `path` con comandi turtle dinamici da dati calcolati
2691+
- `extrude` lungo un percorso generato programmaticamente
2692+
2693+
**Prova a cambiare:**
2694+
- `cols` / `rows` per griglie di dimensioni diverse (il prodotto deve essere pari)
2695+
- `cell-size` per la spaziatura
2696+
- `path-width` / `path-thickness` per le dimensioni del nastro
2697+
- `mixing-steps` per più randomizzazione (più alto = più mescolato)"
2698+
:examples
2699+
{:hamiltonian-cycle-code {:caption "Ciclo Hamiltoniano"}}}
2700+
26472701
:gallery-canvas-weave
26482702
{:title "Tazza con Trama a Intreccio"
26492703
:content "Una tazza con **texture a intreccio** sulla superficie esterna. Questo è l'esempio più complesso della galleria.

0 commit comments

Comments
 (0)