|
249 | 249 | (fn [t] |
250 | 250 | (let [angle (* t 2 Math/PI) |
251 | 251 | proj (s3d/perspective |
252 | | - {:scale 120 :origin [200 200] |
253 | | - :yaw angle :pitch -0.4 :distance 4.5}) |
| 252 | + {:scale 110 :origin [200 200] |
| 253 | + :yaw angle :pitch -0.35 :distance 5}) |
254 | 254 | light {:light/direction [0.8 1.0 0.5] |
255 | 255 | :light/ambient 0.15 |
256 | 256 | :light/intensity 0.85} |
257 | | - ;; Build a gem shape from two cones meeting at the middle |
258 | | - top (-> (s3d/cone-mesh 1.2 1.8 8) |
259 | | - (s3d/rotate-mesh :x Math/PI) |
260 | | - (s3d/translate-mesh [0 0.9 0])) |
261 | | - bottom (-> (s3d/cone-mesh 1.2 1.2 8) |
262 | | - (s3d/translate-mesh [0 -0.6 0])) |
263 | | - gem (s3d/merge-meshes top bottom)] |
| 257 | + ;; Torus knot — visually interesting rotating shape |
| 258 | + torus (-> (s3d/torus-mesh 1.0 0.4 24 12) |
| 259 | + (s3d/rotate-mesh :x (* 0.3 (Math/sin (* t Math/PI)))))] |
264 | 260 | {:image/size [400 400] |
265 | 261 | :image/background [:color/rgb 8 8 18] |
266 | 262 | :image/nodes |
267 | | - [(s3d/render-mesh proj gem |
| 263 | + [(s3d/render-mesh proj torus |
268 | 264 | {:style {:style/fill [:color/rgb 80 180 220] |
269 | | - :style/stroke {:color [:color/rgb 120 220 255] |
270 | | - :width 0.4}} |
| 265 | + :style/stroke {:color [:color/rgb 140 230 255] |
| 266 | + :width 0.3}} |
271 | 267 | :light light})]}))) |
272 | 268 | :fps 30}) |
273 | 269 |
|
|
635 | 631 | (anim/frames 60 |
636 | 632 | (fn [t] |
637 | 633 | (let [proj (s3d/perspective |
638 | | - {:scale 80 :origin [250 250] |
639 | | - :yaw 0.3 :pitch -0.5 :distance 7}) |
| 634 | + {:scale 90 :origin [250 250] |
| 635 | + :yaw 0.3 :pitch -0.45 :distance 6}) |
640 | 636 | light {:light/direction [0.7 1.0 0.4] |
641 | | - :light/ambient 0.2 :light/intensity 0.8} |
| 637 | + :light/ambient 0.25 :light/intensity 0.75} |
642 | 638 | angle (* t 2 Math/PI) |
| 639 | + ;; Orbit trails — fading dots behind each sphere |
| 640 | + trails |
| 641 | + (vec |
| 642 | + (for [i (range 5) |
| 643 | + trail (range 8)] |
| 644 | + (let [orbit-r (+ 1.8 (* i 0.7)) |
| 645 | + speed (/ 1.0 (+ 1.0 (* i 0.3))) |
| 646 | + a (- (+ (* angle speed) (* i (/ (* 2 Math/PI) 5))) |
| 647 | + (* trail 0.08)) |
| 648 | + x (* orbit-r (Math/cos a)) |
| 649 | + z (* orbit-r (Math/sin a)) |
| 650 | + ;; Project to 2D for trail dots |
| 651 | + hue (* i 72) |
| 652 | + fade (/ 1.0 (+ 1.0 trail))] |
| 653 | + {:node/type :shape/circle |
| 654 | + :circle/center [(+ 250 (* 90 x 0.15)) (+ 250 (* 90 z 0.08))] |
| 655 | + :circle/radius (* 3 fade) |
| 656 | + :node/opacity (* 0.3 fade) |
| 657 | + :style/fill [:color/hsl hue 0.8 0.6]}))) |
643 | 658 | spheres |
644 | 659 | (for [i (range 5)] |
645 | | - (let [orbit-r (+ 1.5 (* i 0.6)) |
646 | | - speed (/ 1.0 (+ 1.0 (* i 0.4))) |
| 660 | + (let [orbit-r (+ 1.8 (* i 0.7)) |
| 661 | + speed (/ 1.0 (+ 1.0 (* i 0.3))) |
647 | 662 | a (+ (* angle speed) (* i (/ (* 2 Math/PI) 5))) |
648 | 663 | x (* orbit-r (Math/cos a)) |
649 | 664 | z (* orbit-r (Math/sin a)) |
650 | 665 | hue (* i 72) |
651 | | - mesh (s3d/sphere-mesh 0.35 12 8)] |
| 666 | + mesh (s3d/sphere-mesh 0.4 12 8)] |
652 | 667 | (s3d/render-mesh proj |
653 | 668 | (s3d/translate-mesh mesh [x 0 z]) |
654 | | - {:style {:style/fill [:color/hsl hue 0.7 0.5]} |
| 669 | + {:style {:style/fill [:color/hsl hue 0.8 0.55]} |
655 | 670 | :light light}))) |
656 | | - ;; Central sphere |
657 | 671 | center (s3d/render-mesh proj |
658 | | - (s3d/sphere-mesh 0.5 16 10) |
659 | | - {:style {:style/fill [:color/rgb 240 230 200]} |
| 672 | + (s3d/sphere-mesh 0.6 16 10) |
| 673 | + {:style {:style/fill [:color/rgb 255 240 200]} |
660 | 674 | :light light})] |
661 | 675 | {:image/size [500 500] |
662 | | - :image/background [:color/rgb 8 8 15] |
663 | | - :image/nodes (into [center] spheres)}))) |
| 676 | + :image/background [:color/rgb 5 5 12] |
| 677 | + :image/nodes (into (into trails [center]) spheres)}))) |
664 | 678 | :fps 24}) |
665 | 679 |
|
666 | 680 | ;; --- 15. Pixel Dissolve --- |
|
756 | 770 | (< phase 0.25) (* -20 (/ (- phase 0.2) 0.05)) |
757 | 771 | (< phase 0.35) (* 5 (Math/sin (* (/ (- phase 0.25) 0.1) Math/PI))) |
758 | 772 | :else 0))) |
759 | | - pts (for [i (range 200)] |
760 | | - (let [x-norm (/ (double i) 200) |
| 773 | + ;; Scroll exactly 1 full ECG cycle per loop |
| 774 | + pts (for [i (range 300)] |
| 775 | + (let [x-norm (/ (double i) 300) |
761 | 776 | x (* x-norm w) |
762 | | - wave-x (+ (* x-norm 2.0) (* t 2.0)) |
763 | | - y (+ (/ h 2.0) (ecg (mod wave-x 1.0)))] |
| 777 | + wave-x (+ (* x-norm 3.0) (* t 3.0)) |
| 778 | + y (+ (/ h 2.0) (ecg wave-x))] |
764 | 779 | [x y])) |
765 | 780 | ;; Trail — fading line |
766 | 781 | trail {:node/type :shape/path |
|
844 | 859 | (let [n-petals (+ 6 (* layer 2)) |
845 | 860 | base-r (+ 30 (* layer 45)) |
846 | 861 | r (* base-r (+ 0.7 (* 0.3 eased))) |
| 862 | + petal-w (* r 0.15) |
| 863 | + hue (mod (+ (* layer 60) (* t 120)) 360) |
847 | 864 | rotation (+ (* layer 0.2) (* t Math/PI 0.5))] |
848 | 865 | {:node/type :symmetry |
849 | 866 | :symmetry/type :radial |
850 | 867 | :symmetry/n n-petals |
851 | 868 | :symmetry/center [cx cy] |
852 | 869 | :group/children |
853 | | - [(let [petal-len (* r 0.6) |
854 | | - petal-w (* r 0.2) |
855 | | - hue (mod (+ (* layer 60) (* t 120)) 360)] |
856 | | - {:node/type :shape/path |
857 | | - :path/commands [[:move-to [cx (- cy (* r 0.3))]] |
858 | | - [:curve-to [(+ cx petal-w) (- cy (* r 0.5))] |
859 | | - [(+ cx petal-w) (- cy r)] |
860 | | - [cx (- cy r petal-len)]] |
861 | | - [:curve-to [(- cx petal-w) (- cy r)] |
862 | | - [(- cx petal-w) (- cy (* r 0.5))] |
863 | | - [cx (- cy (* r 0.3))]]] |
864 | | - :node/opacity (- 0.6 (* layer 0.1)) |
865 | | - :style/fill [:color/hsl hue 0.7 0.5] |
866 | | - :style/stroke {:color [:color/hsl hue 0.5 0.35] :width 0.5}})] |
| 870 | + [{:node/type :shape/ellipse |
| 871 | + :ellipse/center [cx (- cy (* r 0.6))] |
| 872 | + :ellipse/rx petal-w |
| 873 | + :ellipse/ry (* r 0.45) |
| 874 | + :node/opacity (- 0.6 (* layer 0.1)) |
| 875 | + :style/fill [:color/hsl hue 0.7 0.5] |
| 876 | + :style/stroke {:color [:color/hsl hue 0.5 0.35] :width 0.5}}] |
867 | 877 | :node/transform [[:transform/rotate rotation]]}))) |
868 | 878 | ;; Center dot |
869 | 879 | center {:node/type :shape/circle |
|
890 | 900 | drops |
891 | 901 | (vec |
892 | 902 | (for [col (range cols) |
893 | | - row (range 30)] |
894 | | - (let [;; Each column falls at a different speed |
895 | | - rng (java.util.Random. (long col)) |
896 | | - speed (+ 0.5 (* (.nextDouble rng) 1.5)) |
897 | | - head-y (mod (* (+ t (* col 0.03)) speed h) (* h 1.3)) |
| 903 | + row (range 25)] |
| 904 | + (let [rng (java.util.Random. (long col)) |
| 905 | + ;; Speed is integer multiple so it loops at t=1 |
| 906 | + speed (+ 1 (.nextInt rng 3)) |
| 907 | + offset (* (.nextDouble rng) h) |
| 908 | + head-y (mod (+ (* t speed h) offset) h) |
898 | 909 | y (- head-y (* row 16)) |
899 | 910 | x (+ 2 (* col col-w)) |
900 | | - ;; Fade based on distance from head |
901 | | - fade (max 0 (- 1.0 (* row 0.06))) |
| 911 | + fade (max 0 (- 1.0 (* row 0.05))) |
902 | 912 | brightness (if (zero? row) 1.0 (* 0.7 fade))] |
903 | 913 | (when (and (> y -10) (< y (+ h 10)) (> fade 0.05)) |
904 | 914 | {:node/type :shape/rect |
|
0 commit comments