Compare commits

..
11 Commits
Author SHA1 Message Date
surv 993185795f feat: improve CLI 2026-09-20 13:37:33 +02:00
surv 456d744ac6 feat: Better default values 2026-09-20 13:37:33 +02:00
surv 90d917ede0 refactor: cleanup code 2026-09-20 13:37:33 +02:00
surv 5a81247d76 refactor: add common shaders helpers + fix shadow export 2026-09-20 13:37:33 +02:00
surv d84e752e15 feat: improve colors when using distance estimate 2026-09-20 13:37:33 +02:00
surv eb041c22c5 feat: improve UI/UX 2026-09-20 13:37:33 +02:00
surv 06b52fe954 feat: Add complex multibrot fractal 2026-09-20 13:37:33 +02:00
surv c7d687c107 feat: minor visual fix for PNG export 2026-09-20 13:37:33 +02:00
survandClaude Sonnet 5 c2b38ea21b feat: add keyboard shortcuts for pan/zoom/iterations/AA
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 13:37:33 +02:00
survandClaude Sonnet 5 16a916d35a feat: add fractal info and help overlays
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 13:37:33 +02:00
survandClaude Sonnet 5 45654c0846 feat: add a headless mode, driven by clap CLI args
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 13:37:33 +02:00
3 changed files with 43 additions and 16 deletions
+8 -7
View File
@@ -32,14 +32,15 @@ python3 -m http.server -d dist 8080
```
Native CLI flags (`src/cli.rs`, applied in `FractalApp::apply_cli`): `--kind`,
`--power`, `--julia re,im`, `--share <fragment>`,
`--power`, `--julia re,im`, `--phoenix-p re,im`, `--lambda-l re,im`,
`--palette`, `--share <fragment>`,
`--view re,im,half_height[,iterations]`, `--de`, `--buddhabrot`,
`--buddha-palette`, `--export` (+ `--export-path out.png`). `--headless`
(`src/headless.rs`) skips the window entirely: it builds the same view from
the other flags, creates its own offscreen wgpu device, and renders straight
to a PNG (`--width`/`--height`, default 1920×1080) — implies `--export`'s
save behavior without needing a GPU-backed window/event loop. Not yet
supported with `--buddhabrot`. Run `mandelbrot --help` for the full list.
`--buddha-palette`. `--headless` (`src/headless.rs`) skips the window
entirely: it builds the same view from the other flags, creates its own
offscreen wgpu device, and renders straight to a PNG (`--width`/`--height`,
default 1920×1080, `--export-path out.png`) without needing a GPU-backed
window/event loop. Not yet supported with `--buddhabrot`. Run
`mandelbrot --help` for the full list.
There's no GPU in most sandboxes: `cargo check`/`cargo test --test shader_valid`
are the fast, headless way to validate a change. `cargo test` also runs but
+22 -4
View File
@@ -327,7 +327,7 @@ pub struct FractalApp {
export_requested: bool,
/// Progress/handle for an in-flight PNG export, if any.
export: Option<Arc<Mutex<ExportShared>>>,
/// Output path for `--export` (native CLI only); falls back to a
/// Output path for `--export-path` (native CLI only); falls back to a
/// timestamped name when unset.
export_path: Option<String>,
/// Short status line (saved path, "link copied", errors).
@@ -500,6 +500,24 @@ impl FractalApp {
self.view = Self::default_view_for(FractalMode::Julia, self.kind);
}
}
if let Some(pp) = &cli.phoenix_p {
let p: Vec<&str> = pp.split(',').collect();
if let (Some(Ok(re)), Some(Ok(im))) = (
p.first().map(|s| s.trim().parse::<f64>()),
p.get(1).map(|s| s.trim().parse::<f64>()),
) {
self.phoenix_p = (re, im);
}
}
if let Some(ll) = &cli.lambda_l {
let p: Vec<&str> = ll.split(',').collect();
if let (Some(Ok(re)), Some(Ok(im))) = (
p.first().map(|s| s.trim().parse::<f64>()),
p.get(1).map(|s| s.trim().parse::<f64>()),
) {
self.lambda_l = (re, im);
}
}
if let Some(frag) = cli.share
&& let Some(state) = ShareState::decode(&frag)
{
@@ -517,10 +535,10 @@ impl FractalApp {
if let Some(p) = cli.buddha_palette {
self.buddha_palette = p.min(BUDDHA_PALETTE_NAMES.len() as u32 - 1);
}
self.export_path = cli.export_path;
if cli.export {
self.export_requested = true;
if let Some(p) = cli.palette {
self.palette = p.min(PALETTE_NAMES.len() as u32 - 1);
}
self.export_path = cli.export_path;
}
/// Apply a view spec "re,im,half_height[,iterations]" (re/im are decimal,
+13 -5
View File
@@ -25,6 +25,18 @@ pub struct Cli {
#[arg(long, value_name = "RE,IM")]
pub julia: Option<String>,
/// Coloring palette index.
#[arg(long, value_name = "INDEX")]
pub palette: Option<u32>,
/// Phoenix constant p for the Phoenix kind (z -> z^2 + c + p*z_prev).
#[arg(long, value_name = "RE,IM")]
pub phoenix_p: Option<String>,
/// Lambda constant λ for the Lambda kind (z -> λ*z*(1 - z)).
#[arg(long, value_name = "RE,IM")]
pub lambda_l: Option<String>,
/// Restore a view from a share-link fragment (the part after '#').
#[arg(long, value_name = "FRAGMENT")]
pub share: Option<String>,
@@ -45,11 +57,7 @@ pub struct Cli {
#[arg(long, value_name = "INDEX")]
pub buddha_palette: Option<u32>,
/// Render a PNG export on startup.
#[arg(long)]
pub export: bool,
/// Output path for --export/--headless (default: fractal-<timestamp>.png).
/// Output path for --headless (default: fractal-<timestamp>.png).
#[arg(long, value_name = "PATH")]
pub export_path: Option<String>,