Last active
February 3, 2026 20:18
-
-
Save dacr/c0eeb3adcd7181d2eab8e97e273c8713 to your computer and use it in GitHub Desktop.
Trying to animate vector graphics using doodle library. / published by https://github.com/dacr/code-examples-manager #b6b3e414-1fea-47a1-8948-98fadb10b257/819b27a6167e31e3e547d0ef28a44a309640f187
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // summary : Trying to animate vector graphics using doodle library. | |
| // keywords : scala, vector-graphics, doodle, examples, @testable | |
| // publish : gist | |
| // authors : Noel Welsh, David Crosson | |
| // license : Apache License Version 2.0 (https://www.apache.org/licenses/LICENSE-2.0.txt) | |
| // id : b6b3e414-1fea-47a1-8948-98fadb10b257 | |
| // created-on : 2019-06-25T21:04:29Z | |
| // managed-by : https://github.com/dacr/code-examples-manager | |
| // run-with : scala-cli $file | |
| // --------------------- | |
| //> using scala "3.4.2" | |
| //> using dep "org.creativescala::doodle:0.10.1" | |
| // --------------------- | |
| // Example coming from doodle examples code (PulsingCircle.scala), author is Noel Welsh | |
| // https://github.com/creativescala/doodle/blob/master/java2d/src/main/scala/doodle/java2d/examples/PulsingCircle.scala | |
| object TryIt { | |
| import cats.instances.all._ | |
| import doodle.core._ | |
| import doodle.effect.Writer.Gif | |
| import doodle.syntax.all._ | |
| import doodle.java2d.effect._ | |
| import doodle.interact.syntax._ | |
| import fs2.Stream | |
| import cats.effect.IO | |
| import doodle.java2d._ | |
| import cats.effect.unsafe.implicits.global | |
| val frame = Frame.size(600, 600).background(Color.darkMagenta) | |
| val strokeWidth = 9.0 | |
| val gapWidth = 6.0 | |
| val minimumDiameter = gapWidth + strokeWidth | |
| val maxNumberOfDisks = 15 | |
| def disk(count: Int): Picture[Unit] = | |
| count match { | |
| case 0 => | |
| circle[Algebra, Drawing](minimumDiameter.toDouble).noFill | |
| .strokeWidth(strokeWidth) | |
| case n => | |
| circle[Algebra, Drawing]( | |
| (n * 2 * (strokeWidth + gapWidth) + minimumDiameter) | |
| ).noFill | |
| .strokeWidth(strokeWidth) | |
| } | |
| def background(count: Int): Picture[Unit] = { | |
| def iter(count: Int): Picture[Unit] = | |
| count match { | |
| case 0 => | |
| disk(count) | |
| case n => | |
| disk(count).on(iter(n - 1)) | |
| } | |
| iter(count).strokeWidth(strokeWidth.toDouble).strokeColor(Color.darkGray) | |
| } | |
| def pulse(count: Int): Picture[Unit] = | |
| count match { | |
| case 0 => disk(0).strokeColor(Color.crimson) | |
| case 1 => | |
| disk(1) | |
| .strokeColor(Color.crimson) | |
| .on(disk(0).strokeColor(Color.crimson.spin(30.degrees))) | |
| case n => | |
| disk(n) | |
| .strokeColor(Color.crimson) | |
| .on( | |
| disk(n - 1) | |
| .strokeColor(Color.crimson.spin(30.degrees)) | |
| ) | |
| .on( | |
| disk(n - 2) | |
| .strokeColor(Color.crimson.spin(60.degrees)) | |
| ) | |
| } | |
| val animation: Stream[IO, Picture[Unit]] = | |
| Stream(1).repeat | |
| .scan((1, 0)) { (state, _) => | |
| val (inc, count) = state | |
| if (count >= maxNumberOfDisks) (-1, maxNumberOfDisks - 1) | |
| else if (count <= 0) (1, 1) | |
| else (inc, count + inc) | |
| } | |
| .map { case (_, c) => pulse(c).on(background(maxNumberOfDisks)) } | |
| def go() = | |
| animation.animate(frame) | |
| def write() = | |
| animation.take(maxNumberOfDisks * 2).write[Gif]("bouncy-circles.gif", frame) | |
| } | |
| //TryIt.go() | |
| //scala.io.StdIn.readLine("Enter to exit...") // required when run as a script | |
| TryIt.write() | |
| //scala.io.StdIn.readLine("Enter to exit...") // required when run as a script | |
| //System.exit(0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment