{"id":51272892,"url":"https://github.com/arcsymer/fractal-paint","last_synced_at":"2026-06-29T19:30:35.200Z","repository":{"id":366662963,"uuid":"1277106590","full_name":"arcsymer/fractal-paint","owner":"arcsymer","description":"Fractal drawing app (Java 17, Swing) — Mandelbrot, Julia, Sierpinski, Koch snowflake, fractal tree; pure deterministic core with JUnit 5 tests","archived":false,"fork":false,"pushed_at":"2026-06-22T19:07:54.000Z","size":579,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-22T21:08:35.859Z","etag":null,"topics":["fractals","java","julia-set","junit5","mandelbrot","maven","portfolio","swing"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arcsymer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-22T15:31:21.000Z","updated_at":"2026-06-22T19:07:59.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/arcsymer/fractal-paint","commit_stats":null,"previous_names":["arcsymer/fractal-paint"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/arcsymer/fractal-paint","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arcsymer%2Ffractal-paint","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arcsymer%2Ffractal-paint/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arcsymer%2Ffractal-paint/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arcsymer%2Ffractal-paint/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arcsymer","download_url":"https://codeload.github.com/arcsymer/fractal-paint/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arcsymer%2Ffractal-paint/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34941025,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-29T02:00:05.398Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fractals","java","julia-set","junit5","mandelbrot","maven","portfolio","swing"],"created_at":"2026-06-29T19:30:31.276Z","updated_at":"2026-06-29T19:30:35.191Z","avatar_url":"https://github.com/arcsymer.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fractal Paint\n\n[![CI](https://github.com/arcsymer/fractal-paint/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/arcsymer/fractal-paint/actions/workflows/ci.yml)\n![tests](https://img.shields.io/badge/tests-174%20passing-brightgreen)\n![java](https://img.shields.io/badge/Java-17-blue)\n![maven](https://img.shields.io/badge/build-Maven-orange)\n\nAn interactive drawing app for classic geometric fractals, built in Java 17 with Swing.\nThe computation core is a pure-function library with no GUI dependency, so it's testable headless.\nTen fractals are implemented across three algorithmic families: escape-time sets, geometric\nsubdivision, and stochastic/L-system iteration.\n\n---\n\n## Problem / Solution\n\n**Problem:** Fractal geometry looks great but is easy to get wrong in code. Common pitfalls\nare mixing rendering with the math, non-deterministic output, and coordinate systems that\nbreak at higher zoom levels.\n\n**Solution:** A layered architecture separates the pure math (`core`) from rendering (`render`)\nand interaction (`app`). The core layer is covered by property-based unit tests that check\nmathematical invariants (exact triangle counts, segment counts) before any pixel is drawn.\n\n---\n\n## Fractals implemented\n\n| Fractal | Family | Description | Count property |\n|---|---|---|---|\n| **Mandelbrot set** | Escape-time | z → z² + c from z₀ = 0; smooth (normalized) colouring | — (pixel-wise) |\n| **Julia set** | Escape-time | z → z² + c from varying z₀; fixed c parameter; smooth colouring | — (pixel-wise) |\n| **Burning Ship** | Escape-time | z → (\\|Re z\\| + i\\|Im z\\|)² + c; smooth colouring | — (pixel-wise) |\n| **Newton fractal** | Escape-time | Newton's method on z³ − 1; coloured by basin of attraction | — (pixel-wise) |\n| **Sierpinski triangle** | Geometric subdivision | Recursive midpoint subdivision; centre removed | triangles = **3ⁿ** |\n| **Koch snowflake** | Geometric subdivision | Each edge replaced by 4 Koch-rule segments | segments = **3 · 4ⁿ** |\n| **Fractal tree** | Geometric recursive | Symmetric binary branching | segments = **2^(d+1) − 1** |\n| **Barnsley fern** | IFS (random) | 4-rule affine IFS; fixed PRNG seed → deterministic | points = **n** (exact) |\n| **Dragon curve** | L-system | Axiom F; rules F→F+H, H→F-H; 90° turns | segments = **2ⁿ** |\n| **Pythagoras tree** | Geometric recursive | Symmetric 45-45-90 square tree | segments = **4 × (2^(n+1) − 1)** |\n\n---\n\n## Architecture\n\n```\nfractal-paint/\n├── src/\n│   ├── main/java/com/arcsymer/fractalpaint/\n│   │   ├── core/          # Pure math — no GUI, fully headless-testable\n│   │   │   ├── Mandelbrot.java\n│   │   │   ├── Julia.java\n│   │   │   ├── BurningShip.java\n│   │   │   ├── Newton.java\n│   │   │   ├── SmoothColor.java                    (normalized iteration count)\n│   │   │   ├── Sierpinski.java  + Triangle.java\n│   │   │   ├── KochSnowflake.java  + Segment.java\n│   │   │   ├── FractalTree.java\n│   │   │   ├── BarnsleyFern.java  + Point2D.java   (IFS)\n│   │   │   ├── DragonCurve.java                    (L-system)\n│   │   │   └── PythagorasTree.java                 (geometric recursive)\n│   │   ├── app/           # Swing GUI (JFrame + canvas + controls)\n│   │   │   ├── Main.java\n│   │   │   ├── FractalCanvas.java\n│   │   │   ├── ControlPanel.java\n│   │   │   └── FractalType.java\n│   │   └── render/        # Headless PNG renderer (used by CI)\n│   │       └── Renderer.java\n│   └── test/java/com/arcsymer/fractalpaint/\n│       ├── core/   (MandelbrotTest, JuliaTest, BurningShipTest, NewtonTest,\n│       │            SmoothColorTest, SierpinskiTest, KochSnowflakeTest,\n│       │            FractalTreeTest, BarnsleyFernTest, DragonCurveTest,\n│       │            PythagorasTreeTest)\n│       └── render/  (RendererTest)\n├── docs/screenshots/      # PNGs generated by the CI render step\n├── pom.xml\n└── .github/workflows/ci.yml\n```\n\n**Layer rules:**\n- `core` has no dependencies (no Swing, no ImageIO), only `java.lang` and `java.util`.\n- `render` depends on `core` plus `javax.imageio` (stdlib).\n- `app` depends on `core` plus Swing (stdlib).\n- Tests depend only on `core` plus JUnit 5.\n\n---\n\n## Build \u0026 Run\n\n**Requirements:** JDK 17+, Maven 3.8+\n\n### Build (produces a runnable fat-JAR)\n```bash\nmvn -B verify\n```\nThis runs all tests and packages a self-contained executable JAR at\n`target/fractal-paint.jar`.\n\n### Run the interactive GUI\nDouble-click `target/fractal-paint.jar`, or:\n```bash\njava -jar target/fractal-paint.jar\n```\n\n### Render all fractals to PNG (headless, no display needed)\n```bash\njava -jar target/fractal-paint.jar --render docs/screenshots\n```\n`java -jar target/fractal-paint.jar --help` prints usage. The renderer can also\nbe invoked directly:\n```bash\njava -Djava.awt.headless=true \\\n     -cp target/classes \\\n     com.arcsymer.fractalpaint.render.Renderer docs/screenshots\n```\nProduces all 10 PNGs: `mandelbrot.png`, `julia.png`, `burning_ship.png`,\n`newton.png`, `sierpinski.png`, `koch.png`, `tree.png`, `barnsley_fern.png`,\n`dragon_curve.png`, `pythagoras_tree.png`\n\n---\n\n## Tests\n\nAll core tests verify deterministic mathematical properties, not pixel output:\n\n| Test class | Property verified |\n|---|---|\n| `MandelbrotTest` | Origin `(0,0)` → `maxIter`; point `(2,2)` → escapes at iteration 1; result ≤ maxIter always; `maxIter\u003c1` throws |\n| `JuliaTest` | Origin inside the basilica set c=(-1,0) stays bounded (periodic 0→-1→0); `(2,0)` escapes at iteration 1; unit-circle boundary for c=0; `maxIter\u003c1` throws |\n| `BurningShipTest` | Interior/exterior escape behaviour; differs from Mandelbrot; `maxIter\u003c1` throws; smooth-count consistency |\n| `NewtonTest` | Convergence to the three cube-roots of unity; three-fold basin symmetry; `maxIter\u003c1` throws |\n| `SmoothColorTest` | Interior → 0.0; exterior smooth count in (0, maxIter); monotonic in escape time |\n| `SierpinskiTest` | `triangles(n) == 3ⁿ` for n=0..5; all vertices in bounding box |\n| `KochSnowflakeTest` | `segments(n) == 3·4ⁿ` for n=0..5; level-0 is closed triangle; no degenerate segments |\n| `FractalTreeTest` | `segments(d) == 2^(d+1)−1` for d=0..5; trunk geometry; branch symmetry; error on invalid input |\n| `BarnsleyFernTest` | `points(n) == n` exactly; bounding box [−2.182,2.658]×[0,10]; fully deterministic (fixed seed); all finite |\n| `DragonCurveTest` | `segments(n) == 2ⁿ` for n=0..5; level-0 is a single horizontal segment; all segments connected; equal length at any level |\n| `PythagorasTreeTest` | `segments(n) == 4×(2^(n+1)−1)` for n=0..5; root square exact geometry; all coordinates finite; no degenerate segments |\n\nRun with: `mvn test`\n\n---\n\n## Screenshots\n\n\u003c!-- PNGs generated by the CI render step --\u003e\n\n| Mandelbrot | Julia |\n|---|---|\n| ![Mandelbrot](docs/screenshots/mandelbrot.png) | ![Julia](docs/screenshots/julia.png) |\n\n| Burning Ship | Newton |\n|---|---|\n| ![Burning Ship](docs/screenshots/burning_ship.png) | ![Newton](docs/screenshots/newton.png) |\n\n| Sierpinski | Koch Snowflake | Fractal Tree |\n|---|---|---|\n| ![Sierpinski](docs/screenshots/sierpinski.png) | ![Koch](docs/screenshots/koch.png) | ![Tree](docs/screenshots/tree.png) |\n\n| Barnsley Fern | Dragon Curve | Pythagoras Tree |\n|---|---|---|\n| ![Barnsley Fern](docs/screenshots/barnsley_fern.png) | ![Dragon Curve](docs/screenshots/dragon_curve.png) | ![Pythagoras Tree](docs/screenshots/pythagoras_tree.png) |\n\n---\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farcsymer%2Ffractal-paint","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farcsymer%2Ffractal-paint","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farcsymer%2Ffractal-paint/lists"}