Commit Graph
121 Commits
Author SHA1 Message Date
dietrich d855750970 Headless SVG Export Macroquad Panic Clarification
Clarified and improved error reporting when drawing routines invoke
Macroquad window or rendering functions (such as `screen_width()` or
`screen_height()`) during headless SVG export (`--export-svg`).

[export.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/export.rs)
- Added `ExportError::Execution(String)` variant to represent drawing
  execution failures and panics.
- Implemented `std::fmt::Display` and `std::error::Error` for
  `ExportError`.
- Created `PanicHookGuard` RAII struct ensuring any installed panic
  hooks are automatically restored after execution.
- In `run_headless_svg_export`:
  - Chains onto the existing panic hook to preserve standard panic
    backtrace and line number information.
  - Detects if the panic originated from uninitialized Macroquad context
    (`THREAD_ID.is_some()`).
  - Emits a clear, prominent diagnostic banner explaining that
    window/GUI functions are unavailable in headless mode.
  - Catches the panic via `std::panic::catch_unwind` and returns
    `Err(ExportError::Execution(...))`.
  - In `handle_svg_export`, uses `{e}` (Display) rather than `{e:?}`
    (Debug) for cleaner error reporting.

[lib.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib-macros/src/lib.rs)
- Updated the expanded `main` function generated by `#[turtle_main]` to
  format errors with `{}` (Display) instead of `{:?}` (Debug).

[sierpinski_triangle.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/sierpinski_triangle.rs)
- Added documentation notes to the module header and
  `sierpinski_triangle_auto` noting that the example requires an active
  graphics window and cannot be exported to SVG headlessly because it
  queries window dimensions.

---

Executed:
```bash
RUST_BACKTRACE=1 cargo run --example sierpinski_triangle --features svg
-- --export-svg sier.svg
```

Output:
```
thread 'main' (49702) panicked at
/home/dietrich/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/macroquad-0.4.16/src/lib.rs:172:13:
assertion failed: THREAD_ID.is_some()
stack backtrace:
0: __rustc::rust_begin_unwind
...
5: macroquad::window::screen_width
6: sierpinski_triangle::sierpinski_triangle_auto
at ./turtle-lib/examples/sierpinski_triangle.rs:100:20
7: sierpinski_triangle::draw_sierpinski
at ./turtle-lib/examples/sierpinski_triangle.rs:39:5
...
================================================================================
Headless SVG Export Note:
A Macroquad window/rendering function (e.g. `screen_width()`,
`screen_height()`,
or input check) was called while running in headless export mode.
Headless export does not initialize a graphics window. To resolve this:
  - Use relative turtle commands or fixed coordinates instead of window
    queries, or
  - Run the program in windowed GUI mode without the `--export-svg`
    flag.
    ================================================================================

Error exporting SVG: execution error: Drawing function called Macroquad
window/GUI functions (e.g. `screen_width()`, `screen_height()`) which
are unavailable in headless SVG export mode.
```
- Process exited cleanly with exit code 1.

Executed:
```bash
cargo run --example koch --features svg -- --export-svg /tmp/koch.svg
```
Output:
```
SVG exported successfully to: /tmp/koch.svg
```
Exit code 0.

```bash
cargo test --package turtle-lib
cargo clippy --package turtle-lib --features svg -- -Wclippy::pedantic
-Aclippy::cast_precision_loss -Aclippy::cast_sign_loss
-Aclippy::cast_possible_truncation
```
- 17 unit tests + 34 doctests passed (1 ignored doctest).
- Clippy completed with zero warnings.
2026-09-20 11:11:59 +02:00
dietrich 05c2654005 Fix: Svg export of arcs with negative angle were wrong
In `flower.rs`, several arc commands are drawn with negative angles (or
negative extents), for example:
- Right leaves: [`circle_right(RIGHT_LEAF_TOP_RADIUS,
  -RIGHT_LEAF_TOP_EXTENT,
  75)`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/flower.rs#L94)
- Petals: [`circle_right(PETALS_SPACE_RADIUS, -PETALS_SPACE_EXTENT,
  30)`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/flower.rs#L116)
- Petal finish: [`circle_left(PETALS_SIDE_RADIUS + 1.0, 3.0 -
  PETALS_SIDE_EXTENT,
  87)`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/flower.rs#L124)

In SVG path arc syntax (`A rx ry x-axis-rotation large-arc-flag
sweep-flag x y`):
- `sweep-flag`: `1` specifies clockwise motion along the circle; `0`
  specifies counter-clockwise motion.
- `large-arc-flag`: `1` specifies an arc sweep $> 180^\circ$; `0`
  specifies $\le 180^\circ$.

In
[`turtle-lib/src/export_svg.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/export_svg.rs):
1. **Sweep direction**: `sweep` was mapped purely based on
   [`CircleDirection`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/circle_geometry.rs#L43)
   (`Right => 1`, `Left => 0`), without taking the sign of `angle` into
   account. Traveling a negative angle reverses the angular motion along
   the circle (e.g. `Right` with a negative angle moves
   counter-clockwise, needing `sweep = 0`). Because `sweep` was not
   flipped for negative angles, SVG drew the arc on the opposite side of
   the circle/chord, resulting in arcs bulging in the wrong direction
   across the leaves and flower petals.
2. **Large arc flag**: `large_arc` was computed using `angle.value() >
   180.0` rather than checking absolute magnitude `angle.value().abs() >
   180.0`.
   3. **Full circle check**: Full circle check compared `angle.value() -
   360.0` instead of `angle.value().abs() - 360.0`.

In
[`turtle-lib/src/export_svg.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/export_svg.rs#L116-L135):
- Determined `sweep` from both `direction` and `angle.value() >= 0.0`:
  ```rust
  let sweep = match (direction, angle.value() >= 0.0) {
  (CircleDirection::Right, true) | (CircleDirection::Left, false) => 1,
  (CircleDirection::Left, true) | (CircleDirection::Right, false) => 0,
  };
  ```
- Evaluated `large_arc` and full-circle checks using
  `angle.value().abs()`.
- Added a unit test
  [`test_svg_export_arc_negative_angle_sweep`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/export_svg.rs#L302-L340)
  to verify SVG arc sweep flags for negative angles.
2026-09-20 11:02:29 +02:00
dietrich 368497f97a Line caps on exported SVG lines and arcs are now configured to be round
(stroke-linecap="round"), matching the on-screen Lyon tessellation.

Summary of Changes
turtle-lib/src/export_svg.rs:
Added .set("stroke-linecap", "round") to SVG <line> elements.
Added .set("stroke-linecap", "round") to partial arc <path> elements.
Extracted SvgExporter::to_svg_document(&TurtleWorld) -> Document to
allow in-memory SVG inspection and testing.
Added unit tests verifying that both lines and arcs export with
stroke-linecap="round".

turtle-lib/src/state.rs:
Added #[allow(clippy::unused_self)] to SvgLog::clear for clean clippy
passes when compiling without the svg feature.
2026-09-20 10:33:38 +02:00
dietrich c4831967be Parameter Type Validation Helper: Added
validate_parameter_type(&syn::Type):

Verifies the type is a reference (syn::Type::Reference).
Ensures the reference is mutable (type_ref.mutability.is_some()),
reporting: #[turtle_main] parameter must be a mutable reference: '&mut
TurtlePlan'.
Checks that the target type (type_ref.elem) is a path whose trailing
identifier is TurtlePlan, allowing both &mut TurtlePlan and qualified
paths like &mut turtle_lib::TurtlePlan.
Rejects other types (like value: i32 or owned t: TurtlePlan), reporting:
Integration into validate_input: Called
validate_parameter_type(&pat_type.ty)?; directly within
syn::FnArg::Typed(pat_type).

Unit Tests Added:

test_valid_qualified_type: verifies &mut turtle_lib::TurtlePlan is
accepted.
test_rejects_wrong_type: verifies value: i32 is rejected with an
informative error.
test_rejects_immutable_reference: verifies t: &TurtlePlan is rejected.
test_rejects_owned_type: verifies t: TurtlePlan is rejected.
test_rejects_wrong_reference_type: verifies t: &mut i32 is rejected.
2026-09-19 20:55:00 +02:00
dietrich 99a51ef40e Fix Greptile review comment regarding parameter name preservation in
turtle-lib-macros

Summary of Changes
Preserve Parameter Pattern in Macro Expansion:

In
turtle-lib-macros/src/lib.rs
, updated the helper function generation when has_turtle_param is true:
rust

let param = &input_fn.sig.inputs[0];
quote! {
}
This retains the exact parameter pattern and identifier (e.g. t: &mut
TurtlePlan, mut t: &mut TurtlePlan, etc.) rather than replacing it with
turtle: &mut turtle_lib::TurtlePlan.
Preserves user function visibility (#fn_vis) for named non-main helper
functions.
Validation of Parameters:

In validate_input, explicitly reject self receivers (FnArg::Receiver)
with an informative error message.
Reject unsupported patterns (e.g., tuple destructuring or struct
patterns) during validation, only accepting identifier patterns
(syn::Pat::Ident) and wildcards (syn::Pat::Wild).
Macro Expansion Testing:

Factored macro expansion logic into turtle_main_impl(&args, input) ->
Result<proc_macro2::TokenStream, syn::Error> so macro expansions can be
parsed into syn::File and verified directly in unit tests.
Added unit tests verifying:
Expansion with custom parameter names like t: &mut TurtlePlan preserves
t
Expansion with mutable parameters like mut t: &mut TurtlePlan
Expansion when the function name is main renames to __turtle_main_draw
while preserving parameter t
Expansion for zero-argument functions generates parameter turtle
Rejection of &mut self
Rejection of unsupported destructuring patterns like (a, b)
Verification
cargo test --package turtle-lib-macros: All 13 tests passed.
cargo clippy --package turtle-lib-macros -- -Wclippy::pedantic: Passed
with 0 warnings.
cargo test --all-targets --all-features: All unit and doc tests across
the workspace passed.
cargo check --package turtle-lib --examples: All 30 examples compiled
cleanly.
2026-09-19 12:34:33 +02:00
dietrichandgreptile-apps[bot] a5261feca3 Update turtle-lib/src/general/fontsize.rs
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-09-19 11:58:17 +02:00
dietrich 68593ba64d Builder Pattern Trait Hierarchy Refactoring
We refactored the builder pattern in
[`turtle-lib`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib)
to eliminate inherent method asymmetry and organize all turtle
capabilities into six cohesive traits.

[`builders.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs)

The legacy traits (`DirectionalMovement`, `Turnable`, `CurvedMovement`)
and orphaned inherent methods have been reorganized into six
domain-focused traits:

-
  **[`Movement`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs#L14)**:
  - `forward()`
  - `backward()`
  - `go_to()`
  - `circle_left()`
  - `circle_right()`
-
  **[`Rotation`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs#L191)**:
  - `left()`
  - `right()`
  - `set_heading()`
-
  **[`Pen`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs#L279)**:
  - `pen_up()`
  - `pen_down()`
  - `set_pen_color()`
  - `set_pen_width()`
-
  **[`Fill`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs#L393)**:
  - `begin_fill()`
  - `end_fill()`
  - `set_fill_color()`
-
  **[`Cursor`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs#L481)**:
  - `hide()`
  - `show()`
  - `shape()`
  - `set_shape()`
  - `set_speed()`
  - `reset()`
-
  **[`Text`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs#L646)**:
  - `write_text()`

[`TurtlePlan`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs#L688)

`TurtlePlan`'s inherent methods are now strictly builder lifecycle
controls:
- `new() -> Self`
- `build(self) -> CommandQueue`

`TurtlePlan` implements `WithCommands`, `Movement`, `Rotation`, `Pen`,
`Fill`, `Cursor`, and `Text`.

-
  **[`lib.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/lib.rs#L62-L65)**:
  Re-exports `Cursor`, `Fill`, `Movement`, `Pen`, `Rotation`, `Text`,
  `TurtlePlan`, `WithCommands`.
- **Examples**: Updated
  [`clock.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/clock.rs#L8),
  [`clock_threaded.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/clock_threaded.rs#L9),
  [`dashed_circle.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/dashed_circle.rs#L4),
  and
  [`bezier.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/bezier.rs#L4)
  to use `use turtle_lib::*;`.
-
  **[`README.md`](file:///home/dietrich/Projekte/Source/turtlers/README.md#L344)**:
  Updated trait references in the architecture outline.

---

- **Unit & Doc Tests**:
  ```bash
  cargo test --package turtle-lib
  ```
  Result: 17 unit tests passed; 34 doc-tests passed (0 failed).
- **All Examples**:
  ```bash
  cargo check --package turtle-lib --examples
  ```
  Result: Successfully compiled all 30 examples.
- **Clippy**:
  ```bash
  cargo clippy --package turtle-lib -- -Wclippy::pedantic \
  -Aclippy::cast_precision_loss -Aclippy::cast_sign_loss
  -Aclippy::cast_possible_truncation
  ```
  Result: 0 warnings in `builders.rs`.
2026-09-19 11:45:57 +02:00
dietrich f117361950 Fix Timing Clocks Divergence
Fixed the timing clock divergence between
[tweening.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tweening.rs)
and
[drawing.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/drawing.rs)
by delegating animation progress evaluation exclusively to
`TweenController`.

`current_time()` in `tweening.rs` was using a monotonic `Instant` epoch
(to support headless execution and unit tests without panicking on
missing Macroquad context), while `drawing.rs` was measuring progress
via `macroquad::time::get_time() - tween.start_time`. Because these two
clocks operate on completely different epochs, subtracting them caused
negative elapsed times, premature clamping, jitter, or animation lockup.

In
[`turtle-lib/src/tweening.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tweening.rs):
- Added `pub(crate) progress: f32` to
  [`CommandTween`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tweening.rs#L55-L68)
  to track the current evaluated, eased progress in `[0.0, 1.0]`.
- Made `start_time: f64` and `duration: f64` private to `tweening.rs` so
  outside modules cannot accidentally perform desynchronized clock
  arithmetic.
- Initialized `progress: 0.0` when constructing a new `CommandTween`.
- In `TweenController::update`, evaluated and clamped `tween.progress =
  tween.heading_tweener.move_to(elapsed).clamp(0.0, 1.0)`.

In
[`turtle-lib/src/drawing.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/drawing.rs):
- Removed `use tween::CubicInOut;` and duplicate easing calculations.
- Replaced `get_time() - tween.start_time` and `CubicInOut.tween(...)`
  in in-flight fill preview with `tween.progress`.
- Replaced `get_time() - tween.start_time` and `CubicInOut.tween(...)`
  in `draw_tween_arc` with `tween.progress`.
- Ensured `drawing.rs` has zero clock queries and strictly renders the
  state provided by `TweenController`.

In
[`turtle-lib/src/tweening.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tweening.rs#L540-L579):
- Updated `test_animated_mode_pops_to_current_tween` to assert that
  `progress` initializes to `0.0`.
- Added `test_animated_mode_progress_advances_and_clamps` to verify that
  `progress` advances monotonically across frames and stays within
  `[0.0, 1.0]`.

---

```bash
cargo test --package turtle-lib --features svg
```
Output:
```text
running 17 tests
test circle_geometry::tests::test_circle_left_geometry ... ok
test circle_geometry::tests::test_circle_right_geometry ... ok
test command_behavior::tests::test_goto_duration_cartesian_inversion ...
ok
test
command_behavior::tests::test_set_heading_degrees_and_instant_duration
... ok
test execution::tests::test_forward_left_forward ... ok
test general::angle::tests::degrees_to_radians_roundtrip ... ok
test general::angle::tests::from_f64 ... ok
test general::angle::tests::from_integer ... ok
test general::angle::tests::negation ... ok
test general::fontsize::tests::font_size_conversions ... ok
test general::length::tests::test_length_conversions_and_negation ... ok
test general::tests::animation_speed_conversions ... ok
test tweening::tests::test_animated_mode_pops_to_current_tween ... ok
test tweening::tests::test_instant_mode_drains_queue ... ok
test
tweening::tests::test_instant_mode_respects_batch_limit_and_retains_pending
... ok
test tweening::tests::test_streaming_append_commands_does_not_accumulate
... ok
test tweening::tests::test_animated_mode_progress_advances_and_clamps
... ok

test result: ok. 17 passed; 0 failed; 0 ignored; 0 measured; 0 filtered
out; finished in 0.02s

Doc-tests turtle_lib: 34 passed; 0 failed; 1 ignored; 0 measured; 0
filtered out; finished in 0.26s
```

```bash
cargo clippy --package turtle-lib --features svg -- -Wclippy::pedantic \
-Aclippy::cast_precision_loss -Aclippy::cast_sign_loss
-Aclippy::cast_possible_truncation
```
Output:
```text
Finished `dev` profile [optimized + debuginfo] target(s) in 0.82s
```
**0 warnings.**

```bash
cargo run --example yinyang --features svg -- --export-svg
/tmp/yinyang_test.svg
```
Output:
```text
SVG exported successfully to: /tmp/yinyang_test.svg
```

```bash
cargo build --package turtle-lib --examples
```
Output:
```text
Finished `dev` profile [optimized + debuginfo] target(s) in 6.74s
```
**All 30 examples compiled cleanly with 0 errors and 0 warnings.**
2026-09-19 10:52:00 +02:00
dietrich f4357cb73d When running:
```bash
cargo run --example yinyang --features svg -- --export-svg yinyang.svg
```
the application crashed with:
```text
thread 'main' panicked at macroquad-0.4.16/src/lib.rs:172:13:
assertion failed: THREAD_ID.is_some()
```
along with 10 compiler dead-code warnings in `turtle-lib`.

1. **Headless Execution Path**: When `--export-svg` is provided,
   `turtle_main` runs `run_headless_svg_export` headlessly without
   creating a graphics window (`macroquad::Window::new` is bypassed).
2. **Speed Overwrite in Headless Mode**: `run_headless_svg_export`
   originally called `app.set_all_turtles_speed(Instant(1000))` and
   stepped animations with `while !app.is_complete() {
   app.step_animations(); }`. However, `yinyang.rs` contains
   `turtle.set_speed(100)` in its plan. When `TweenController` processed
   `SetSpeed(100)`, it switched to animated mode.
3. **Macroquad Context Assertion**: In animated mode,
   `TweenController::update` creates a `CommandTween` and called
   `current_time()`. In `turtle-lib/src/tweening.rs`, `current_time()`
   called `macroquad::time::get_time()`, which queried Macroquad's
   context (`get_context()`). Because no window was created, Macroquad
   asserted `THREAD_ID.is_some()` and panicked.
4. **Dead Code Warnings**: Types previously made `pub(crate)` had dead
   fields and obsolete helper methods that were never called internally
   or were superseded by `execution.rs`.

---

-
  **[`turtle-lib/src/export.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/export.rs)**:
  - Updated `run_headless_svg_export` to use `app.execute_immediate(0,
    turtle)` instead of queuing commands and stepping animations in a
    loop.
  - Headless SVG export now executes all commands synchronously in under
    0.1s regardless of any `set_speed` in the drawing plan.
-
  **[`turtle-lib/src/lib.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/lib.rs)**:
  - In `TurtleApp::execute_immediate`: ensured the turtle exists in
    `self.world` before executing.
  - Removed unused `pub(crate) fn world` and `pub(crate) fn world_mut`.
-
  **[`turtle-lib/src/tweening.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tweening.rs)**:
  - Updated `current_time()` to use monotonic `std::time::Instant` on
    non-WASM targets (`#[cfg(not(target_arch = "wasm32"))]`) and
    `macroquad::time::get_time()` on WASM (`#[cfg(target_arch =
    "wasm32")]`).
  - Removed unused `turtle_id` field on `CommandTween`.

-
  **[`turtle-lib/src/circle_geometry.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/circle_geometry.rs)**:
  - Removed obsolete unused methods: `position_at_progress`,
    `angle_to_position`, `draw_arc_params`, and
    `draw_arc_params_partial`.
-
  **[`turtle-lib/src/commands_channel.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/commands_channel.rs)**:
  - Removed unused `turtle_id` field from `TurtleCommandReceiver`.
  - Removed unused methods `turtle_id`, `try_recv`, `is_empty`, and
    `len` from `TurtleCommandReceiver`.
-
  **[`turtle-lib/src/general.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/general.rs)**:
  - Removed unused `Visibility` type alias.
-
  **[`turtle-lib/src/state.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/state.rs)**
  &
  **[`turtle-lib/src/execution.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/execution.rs)**:
  - Removed unused `start_position` field on `FillState`.
  - Removed unused superseded methods on `Turtle`: `heading_angle`,
    `reset`, `begin_fill`, `record_fill_vertex`, `close_fill_contour`,
    `start_fill_contour`, `record_fill_vertices_for_arc`, `reset_fill`.
  - Removed unused `background_color` field and unused methods
    `get_turtle`, `reset_turtle`, `clear` from `TurtleWorld`.
  - Added `#[allow(clippy::struct_field_names)]` on `Turtle::turtle_id`.
-
  **[`turtle-lib/src/export_svg.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/export_svg.rs)**:
  - Moved `update_bounds` outside `export`.
  - Replaced `if angle.value() > 180.0 { 1 } else { 0 }` with
    `i32::from(angle.value() > 180.0)`.
  - Replaced `d.push_str(&format!(...))` with `write!(d, ...)`.
  - Inlined format arguments in `color_to_svg`.

---

```bash
cargo run --example yinyang --features svg -- --export-svg yinyang.svg
```
Output:
```text
Finished `dev` profile [optimized + debuginfo] target(s) in 0.07s
Running `target/debug/examples/yinyang --export-svg yinyang.svg`
SVG exported successfully to: yinyang.svg
```
Completed cleanly in **0.07s** with **0 compiler warnings** and **0
errors**.

Inspected `yinyang.svg`: contains all expected paths, outer arcs, inner
S-curve, and EvenOdd fill contours.

```bash
cargo test --package turtle-lib --features svg
```
Output:
```text
test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered
out; finished in 0.00s
test result: ok. 34 passed; 0 failed; 1 ignored; 0 measured; 0 filtered
out; finished in 0.25s
```

```bash
cargo clippy --package turtle-lib --features svg -- -Wclippy::pedantic \
-Aclippy::cast_precision_loss -Aclippy::cast_sign_loss
-Aclippy::cast_possible_truncation
```
Output:
```text
Checking turtle-lib v0.2.0
(/home/dietrich/Projekte/Source/turtlers/turtle-lib)
Finished `dev` profile [optimized + debuginfo] target(s) in 0.51s
```
**0 warnings.**
2026-09-19 09:24:10 +02:00
dietrich 823bf13c24 Usability & Ergonomics Improvements
All issues identified across Sections 3.1, 3.2, and 3.3 have been
resolved, verified with unit tests, automated compilation checks under
`-D float_literal_f32_fallback`, and headless SVG export runs.

-
  **[angle.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/general/angle.rs)**:
  - Implemented `From<f64>` and `From<usize>` for `Degrees`.
  - Added unit tests `from_integer` and `from_f64` to verify conversion
    accuracy.
-
  **[fontsize.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/general/fontsize.rs)**:
  - Implemented `From<f64>` for `FontSize`.
  - Refactored `FontSize::value(self)` to pass Copy type by value.
  - Added unit test `font_size_conversions`.
-
  **[general.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/general.rs)**:
  - Implemented `From<f64>`, `From<i32>`, and `From<usize>` for
    `AnimationSpeed`.
  - Added unit test `animation_speed_conversions`.
  - Re-exported `macroquad` crate (`pub use macroquad;`) so downstream
    code and macro expansions have reliable direct access.

-
  **[export.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/export.rs)**:
  - Made `parse_svg_export_arg()` public.
  - Implemented `run_headless_svg_export<F>(mut build_commands: F,
    filename: &str) -> Result<(), ExportError>` that executes commands
    using `app.step_animations()`, avoiding all window/GUI dependencies
    and never calling `std::process::exit`.
  - Updated `handle_svg_export` to delegate to
    `run_headless_svg_export`.
-
  **[lib.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/lib.rs)**:
  - Extracted `pub fn step_animations(&mut self)` from `update(&mut
    self)`, allowing command queue draining and tween stepping
    headlessly without querying window mouse position or events.
-
  **[state.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/state.rs)**:
  - Changed `TurtleWorld::new()` to initialize camera with
    `Camera2D::default()` instead of querying `screen_width()` /
    `screen_height()`, eliminating panics when running without a
    Macroquad window.
-
  **[turtle-lib-macros/src/lib.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib-macros/src/lib.rs)**:
  - Added `validate_input` helper providing clean compile diagnostics
    with spans for:
    - Multiple arguments: `#[turtle_main] functions must take either 0
      arguments or a single &mut TurtlePlan`
    - Non-unit return types: `#[turtle_main] functions cannot have a
      return type`
    - Async functions: `#[turtle_main] functions cannot be async`
  - Replaced `#[macroquad::main]` wrapper expansion with a native `fn
    main()` that inspects CLI arguments first. If `--export-svg` is
    present, it runs `run_headless_svg_export` directly and returns
    cleanly without opening a window. Otherwise, it launches
    `macroquad::Window::new(#window_title, async { ... })`.
  - Added 5 unit tests in `turtle-lib-macros` testing signature
    validation.

-
  **[.vscode/launch.json](file:///home/dietrich/Projekte/Source/turtlers/.vscode/launch.json)**:
  - Removed stale references to nonexistent `turtle-example` and
    `turtle-ui`.
  - Added debug configurations for `turtle-lib` tests,
    `turtle-lib-macros` tests, `hello_turtle`, and `breadboard`.
-
  **[breadboard.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/breadboard.rs)**:
  - Refactored example to use `#[turtle_main("Breadboard")]`.
  - Removed `#[cfg(feature = "svg")]` and the early-exit message; the
    example now renders directly on screen by default and supports
    `--features svg -- --export-svg breadboard.svg`.
-
  **[README.md](file:///home/dietrich/Projekte/Source/turtlers/README.md)**:
  - Documented optional user-level `~/.cargo/config.toml` mold/lld
    fast-linking configuration under "Building and Running".

---

```bash
cargo test --workspace
```
- **Result**: 21 passed (16 in `turtle-lib`, 5 in `turtle-lib-macros`),
  34 doctests passed, 0 failed.

```bash
RUSTFLAGS="-D float_literal_f32_fallback" cargo check --workspace
--all-targets --all-features
RUSTFLAGS="-D float_literal_f32_fallback" cargo check --package
turtle-lib --examples --all-features
```
- **Result**: Passed with 0 errors and 0 fallback warnings across all
  workspace crates and all 30 examples.

```bash
cargo run --package turtle-lib --example hello_turtle --features svg --
--export-svg hello.svg
cargo run --package turtle-lib --example breadboard --features svg --
--export-svg breadboard.svg
```
- **Result**: Both exported SVG files successfully and exited with code
  0 without creating or flashing a graphical window.

```bash
cargo check --package turtle-lib --example breadboard
```
- **Result**: Compiled cleanly with 0 errors when SVG feature is
  disabled.
2026-09-19 08:19:11 +02:00
dietrich 76d07ab009 Consistency Refactoring
All 6 consistency review items have been resolved, verified with new
unit tests, automated test suites, and clean example builds.

- **Fixed `Goto` Duration Bug**: In
  [`turtle-lib/src/command_behavior.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/command_behavior.rs),
  mapped Cartesian target coordinates to screen space (`vec2(target.x,
  -target.y)`) before calculating $\Delta x$ and $\Delta y$ in
  `animation_duration`.
- **Unit Test**: Added `test_goto_duration_cartesian_inversion` testing
  that moving from screen $(0, 100)$ (Cartesian $(0, -100)$) to
  Cartesian $(0, 100)$ computes duration based on the actual 200px
  Euclidean distance ($2.0\text{s}$ at $100\text{ px/s}$).

- **Stored `Degrees`**: Updated `TurtleCommand::SetHeading(Degrees)` in
  [`turtle-lib/src/commands.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/commands.rs)
  to store user degrees directly ($0^\circ = \text{East}$, $90^\circ =
  \text{North}$), matching `Turn(Degrees)` and `Circle { angle: Degrees
  }`.
- **Deferred Screen-Space Conversion**: Converted to internal screen
  radians (`normalize_angle(-heading.as_radians().value())`) inside
  `apply_to_params` in
  [`turtle-lib/src/command_behavior.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/command_behavior.rs).
- **Instant Duration**: Maintained instant transition ($0.01\text{s}$
  minimum) in `animation_duration`.
- **Unit Test**: Added `test_set_heading_degrees_and_instant_duration`
  verifying $90^\circ$ maps to North ($-\frac{\pi}{2}$ in screen space),
  $0^\circ$ to East ($0$), $270^\circ$ to South ($+\frac{\pi}{2}$), and
  duration is $0.01\text{s}$.

- **Enhanced `Length` Type**: Expanded
  [`turtle-lib/src/general/length.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/general/length.rs)
  with `new()`, `value()`, `Neg`, `PartialOrd`, and conversion
  implementations (`From<f32>`, `From<f64>`, `From<i32>`, `From<i16>`,
  `From<usize>`).
- **Adopted Across API**:
  - `TurtleCommand::Move(Length)` in `commands.rs`.
  - `TurtleCommand::Circle { radius: Length, ... }` in `commands.rs`.
  - `forward<T: Into<Length>>` and `backward<T: Into<Length>>` in
    [`turtle-lib/src/builders.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs).
  - `circle_left`, `circle_right` accept `radius: impl Into<Length>`.
  - Kept stroke attribute `pen_width` as `Precision` (`f32`).
- **Unit Test**: Added `test_length_conversions_and_negation` in
  `general::length`.

- **Removed Duplicate Alias**: Removed `all_animations_complete(&self)`
  from `TurtleApp` in
  [`turtle-lib/src/lib.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/lib.rs);
  updated call in
  [`turtle-lib/src/export.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/export.rs)
  to use canonical `is_complete(&self)`.
- **Corrected
  [`README.md`](file:///home/dietrich/Projekte/Source/turtlers/README.md)**:
  - `plan.goto(...)` $\rightarrow$ `plan.go_to(...)`
  - `plan.set_color(...)` $\rightarrow$ `plan.set_pen_color(...)`
  - `create_turtle()` $\rightarrow$ `create_turtle_plan()`
- **Corrected
  [`AGENTS.md`](file:///home/dietrich/Projekte/Source/turtlers/AGENTS.md)**:
  - `create_turtle()` $\rightarrow$ `create_turtle_plan()` in Threading
    Pattern.

- **Unified on `1000.0`**:
  - Updated
    [`README.md`](file:///home/dietrich/Projekte/Source/turtlers/README.md)
    lines 9, 108, 109 to state `speed >= 1000` is Instant and `speed <
    1000` is Animated.
  - Updated
    [`turtle-lib/examples/circle_test.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/circle_test.rs)
    to use `turtle.set_speed(1000)`.

- **Renamed Examples**:
  - `turtle-lib/examples/stern.rs` $\rightarrow$
    [`turtle-lib/examples/star.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/star.rs)
  - `turtle-lib/examples/nikolaus.rs` $\rightarrow$
    [`turtle-lib/examples/house_of_nikolaus.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/house_of_nikolaus.rs)
- **Translated Functions & Parameters**:
  - `house_of_nikolaus.rs`: Translated `nikolausquadrat` $\rightarrow$
    `house_square`, `nikolausdiag` $\rightarrow$ `house_diagonal`,
    `nikolausdach2` $\rightarrow$ `house_roof`, parameter `groesse`
    $\rightarrow$ `size`. Added doc comment explaining the Eulerian path
    puzzle.
  - `breadboard.rs`: Translated `pin_reihe` $\rightarrow$ `pin_row`,
    `pin_spalte` $\rightarrow$ `pin_column`, `pin_seite` $\rightarrow$
    `pin_side`, parameter `anzahl` $\rightarrow$ `count`,
    `anzahl_reihen` $\rightarrow$ `row_count`. Added `#[cfg(feature =
    "svg")]` to helper functions to eliminate dead-code warnings when
    SVG feature is not enabled.
- **Translated UI Text & Print Messages**:
  - `"Drücke E für SVG-Export"` $\rightarrow$ `"Press E for SVG export"`
  - `"SVG exportiert nach test.svg"` $\rightarrow$ `"SVG exported to
    test.svg"`
  - `"Fehler beim Export: {:?}"` $\rightarrow$ `"Export error: {:?}"`
  - `"SVG-Export ist nicht aktiviert..."` $\rightarrow$ `"SVG export is
    not enabled..."`
  - Translated module doc in `export_svg.rs`.
- **Updated
  [`README.md`](file:///home/dietrich/Projekte/Source/turtlers/README.md)**
  example lists and CLI commands to reference `star` and
  `house_of_nikolaus`.

---

- `cargo test --package turtle-lib`:
  - 13 unit tests passed (including 3 new targeted unit tests)
  - 34 doctests passed (1 ignored internal helper)
- `cargo check --workspace --all-targets --all-features`: Passed with 0
  errors.
- `cargo check --examples --package turtle-lib --all-features`: All 30
  examples compiled cleanly with 0 errors.
- `cargo clippy --package turtle-lib -- -Wclippy::pedantic
  -Aclippy::cast_precision_loss -Aclippy::cast_sign_loss
  -Aclippy::cast_possible_truncation`: Passed with 0 errors.
2026-09-19 07:51:55 +02:00
dietrich c12cb7c3ee update agents.md 2026-09-18 21:50:09 +02:00
dietrich ea9a8839c4 Eliminate Per-Frame Allocation in Rendering Loop
We resolved **Issue 4.3 (Severe Per-Frame Allocation in Rendering
Loop)** by removing the intermediate `MeshData` structure and storing
`macroquad::prelude::Mesh` directly in
[`DrawCommand::Mesh`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/state.rs).

[`DrawCommand`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/state.rs)
- Dropped `Clone` and `Debug` derives from
  [`Turtle`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/state.rs#L58)
  and
  [`DrawCommand`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/state.rs#L351),
  accommodating Macroquad's `Mesh` which does not implement these
  traits.
- Changed
  [`DrawCommand::Mesh`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/state.rs#L353)
  to the tuple variant `DrawCommand::Mesh(macroquad::prelude::Mesh)`.
- Deleted `struct MeshData` and its `to_mesh` method.

[`tessellation.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tessellation.rs)
- Renamed `build_mesh_data` to
  [`build_mesh`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tessellation.rs#L35)
  returning `macroquad::prelude::Mesh { vertices, indices, texture: None
  }` directly.
- Updated
  [`tessellate_polygon`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tessellation.rs#L71),
  [`tessellate_multi_contour`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tessellation.rs#L116),
  [`tessellate_stroke`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tessellation.rs#L214),
  [`tessellate_circle`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tessellation.rs#L259),
  and
  [`tessellate_arc`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tessellation.rs#L308)
  to return `Result<Mesh, Box<dyn std::error::Error>>`.

[`drawing.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/drawing.rs)
- In the main drawing loop
  ([`drawing.rs:36-38`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/drawing.rs#L36-L38)):
  ```rust
  DrawCommand::Mesh(mesh) => {
  draw_mesh(mesh);
  }
  ```
  Now borrows `&Mesh` directly from the command vector with **0 heap
  allocations and 0 vector clones per frame**.
- Updated fill preview ([line
  228](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/drawing.rs#L228)),
  tween arc/center indicators ([lines 309,
  329](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/drawing.rs#L309)),
  and turtle shape drawing ([line
  349](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/drawing.rs#L349))
  to pass `&mesh` directly to `draw_mesh(&mesh)` without vector cloning.

[`execution.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/execution.rs)
- Updated
  [`commands.push(DrawCommand::Mesh(mesh))`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/execution.rs#L135)
  and
  [`tessellate_command`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/execution.rs#L337).
- Updated
  [`test_forward_left_forward`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/execution.rs#L487)
  to instantiate `mut state` directly without dummy cloning.

---

```bash
cargo test --lib
```
Output:
```
running 10 tests
test circle_geometry::tests::test_circle_left_geometry ... ok
test circle_geometry::tests::test_circle_right_geometry ... ok
test general::angle::tests::degrees_to_radians_roundtrip ... ok
test general::angle::tests::from_integer ... ok
test execution::tests::test_forward_left_forward ... ok
test general::angle::tests::negation ... ok
test tweening::tests::test_animated_mode_pops_to_current_tween ... ok
test tweening::tests::test_instant_mode_drains_queue ... ok
test
tweening::tests::test_instant_mode_respects_batch_limit_and_retains_pending
... ok
test tweening::tests::test_streaming_append_commands_does_not_accumulate
... ok

test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered
out; finished in 0.00s
```

All targets verified with `cargo check --all-targets` and `cargo clippy
--lib`.
2026-09-18 21:34:07 +02:00
dietrich 1d0e149d22 Fix Unbounded Memory Growth (Memory Leak) in TweenController
In
[`TweenController`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tweening.rs),
commands are currently accumulated in `queue: CommandQueue` (which wraps
a `Vec<TurtleCommand>`). When commands execute in `update()`, an
internal `cursor: usize` increments, but executed commands are never
removed. In streaming and threaded applications (such as
[`examples/clock_threaded.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/clock_threaded.rs)),
new commands are appended continuously, causing `queue` to grow
unboundedly over time and exhaust memory.

We will replace `queue: CommandQueue` and `cursor: usize` with `queue:
std::collections::VecDeque<TurtleCommand>` inside `TweenController`.
Consumed commands will be removed immediately using `pop_front()`,
completely freeing memory as commands complete.

> [!NOTE]
> All design decisions were aligned during the `/grill-me` session:
  > - `TweenController` will internally store
  `std::collections::VecDeque<TurtleCommand>` and consume items via
  `pop_front()`.
  > - `self.cursor` is eliminated entirely.
  > - `CommandQueue` remains the public API container for passing
  batches of commands into `TweenController::new` and
  `TweenController::append_commands`.
  > - `TurtleCommand::Reset` retains its normal semantics (clearing
  drawings and parameters without clearing future queued commands), as
  continuous `pop_front()` already discards consumed commands.
  > - Standard `VecDeque` capacity behavior is maintained (no
  auto-shrinking) to prevent reallocation jitter in streaming scenarios.

[tweening.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tweening.rs)
- Import `std::collections::VecDeque`.
- Update `TweenController` struct definition:
  - Replace `queue: CommandQueue` and `cursor: usize` with `queue:
    VecDeque<TurtleCommand>`.
- In `TweenController::new`:
  - Initialize `queue` using `queue.into_iter().collect()`.
  - Remove `cursor` initialization.
- In `TweenController::append_commands`:
  - Extend `self.queue` directly from `new_queue: CommandQueue`.
- In `TweenController::update`:
  - **Instant mode**: Replace `while let Some(command) =
    self.queue.get(self.cursor).cloned()` with `while let Some(command)
    = self.queue.pop_front()`, removing `self.cursor += 1` and
    unnecessary command cloning.
  - **Animated mode**: Replace `if let Some(command) =
    self.queue.get(self.cursor).cloned()` with `if let Some(command) =
    self.queue.pop_front()`, removing `self.cursor += 1` and unnecessary
    command cloning.
- In `TweenController::is_complete`:
  - Update check to `self.current_tween.is_none() &&
    self.queue.is_empty()`.
- Add unit tests in `#[cfg(test)] mod tests`:
  - Verify queue drains to 0 length in Instant mode.
  - Verify queue drains in Animated mode with multiple frames.
  - Verify streaming `append_commands` calls continuously drain and do
    not accumulate.
  - Verify `is_complete()` transitions correctly.

---

[commands.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/commands.rs)
- Update doc comments referencing `TweenController`'s cursor to reflect
  the queue consumption model.

- Run `cargo test -p turtle-lib --lib tweening` to execute the new unit
  tests.
- Run `cargo test -p turtle-lib` to ensure all existing tests in
  `turtle-lib` continue to pass.
- Run `cargo check --examples` to ensure all examples (including
  `clock_threaded.rs`) compile cleanly.

- Review memory behavior or run `examples/clock_threaded.rs` in debug to
  confirm streaming updates run smoothly.
2026-09-18 21:13:46 +02:00
dietrich 4752075d08 remove custom linker 2026-09-18 20:57:00 +02:00
Dietrich bc925ffe26 svg text size and orientation 2026-07-20 13:39:42 +02:00
dietrich 5e0e0e5be3 update the dependencies 2026-05-22 15:13:22 +02:00
dietrich 106dd79677 improve README 2026-05-21 22:51:19 +02:00
dietrich 89c778289c Merge pull request #5 from enaut/copilot/research-turtle-lib-architecture
Align turtle-lib API docs with actual speed/reset/coordinate/heading semantics
2026-05-21 22:17:42 +02:00
copilot-swe-agent[bot]andenaut 77ca219621 Refine SetHeading conversion wording
Agent-Logs-Url: https://github.com/enaut/turtlers/sessions/5fb2f5ed-163f-4c2d-8180-1e96150e7e46

Co-authored-by: enaut <290005+enaut@users.noreply.github.com>
2026-05-21 20:09:15 +00:00
copilot-swe-agent[bot]andenaut 2ac52ecc92 Fix turtle-lib API docs and invariant wording
Agent-Logs-Url: https://github.com/enaut/turtlers/sessions/5fb2f5ed-163f-4c2d-8180-1e96150e7e46

Co-authored-by: enaut <290005+enaut@users.noreply.github.com>
2026-05-21 20:08:40 +00:00
dietrich 59d6bc164e improve examples 2026-05-21 21:50:13 +02:00
dietrich ece26bfe04 create a svg log instead of caching the commands where they do not
belong...
2026-05-21 21:28:14 +02:00
dietrich 156301f272 remove dead code and translate german comments to english 2026-05-21 17:35:59 +02:00
dietrich 96b02f61be improve circle construction and rendering 2026-05-21 17:29:27 +02:00
dietrich 998cffdcbf make the drwing of the center of the circle a regular feature. 2026-05-21 15:05:23 +02:00
dietrich 6b558ca8a0 more consistent use of angle types 2026-05-21 15:02:57 +02:00
dietrich 3c076fdd03 improve command handling 2026-05-17 07:23:13 +02:00
dietrich 44046abe12 improve command handling 2026-05-16 16:03:09 +02:00
dietrich a7570911d8 reduce exposed internal functions and fields 2026-05-16 15:31:10 +02:00
dietrich cd589b2513 Merge pull request #4 from enaut/copilot/change-license-to-mit-or-apache2
Add dual MIT/Apache-2.0 license files
2026-01-16 19:43:28 +01:00
copilot-swe-agent[bot]andenaut 4ce176f44d Add LICENSE-MIT and LICENSE-APACHE files for dual licensing
Co-authored-by: enaut <290005+enaut@users.noreply.github.com>
2026-01-16 18:34:55 +00:00
copilot-swe-agent[bot] ef6e8e4c76 Initial plan 2026-01-16 18:31:28 +00:00
dietrich 8a4ed0bf32 avoid cfg svg in public macro 2026-01-02 14:47:21 +01:00
dietrich 402a8be205 additional feature flag to suppress a warning 2026-01-02 13:50:13 +01:00
dietrich 3820f20048 Merge pull request #2 from enaut/copilot/add-cmdline-parameters-svg-export
Add --export-svg CLI parameter to turtle_main macro
2026-01-02 12:09:03 +01:00
dietrich 6f29d97bb6 unify comandline parsing into function 2026-01-02 11:53:18 +01:00
dietrich cadc5a6798 fix cartesian axes example 2026-01-02 11:45:20 +01:00
copilot-swe-agent[bot]andenaut 9568bc10d9 Add comment explaining intentional code duplication in proc macro
Co-authored-by: enaut <290005+enaut@users.noreply.github.com>
2026-01-01 20:44:27 +00:00
copilot-swe-agent[bot]andenaut cbe249b9b7 Update README with CLI SVG export documentation and examples
Co-authored-by: enaut <290005+enaut@users.noreply.github.com>
2026-01-01 20:42:53 +00:00
copilot-swe-agent[bot]andenaut f5140361d5 Add documentation comment explaining magic number in instant speed
Co-authored-by: enaut <290005+enaut@users.noreply.github.com>
2026-01-01 20:41:52 +00:00
copilot-swe-agent[bot]andenaut c806570156 Implement CLI --export-svg parameter for instant SVG export
Co-authored-by: enaut <290005+enaut@users.noreply.github.com>
2026-01-01 20:40:06 +00:00
copilot-swe-agent[bot]andenaut d85a9c7d26 Add --export-svg CLI parameter support to turtle_main macro
Co-authored-by: enaut <290005+enaut@users.noreply.github.com>
2026-01-01 20:31:58 +00:00
copilot-swe-agent[bot] 2b64be29a8 Initial plan 2026-01-01 20:27:41 +00:00
dietrich 9831008b9f fix clippy lints 2025-10-24 17:35:23 +02:00
dietrich a3cad7d1bc update the README.md 2025-10-24 17:29:40 +02:00
dietrich 8128c212ae fix unused variable warning 2025-10-24 17:29:06 +02:00
dietrich 78ecc84493 use the builder syntax for yinyang 2025-10-24 16:35:27 +02:00
dietrich 73d0ef4881 make speed increas exponentially 2025-10-24 16:31:43 +02:00
dietrich ea5bb85e88 add a viewbox to the svg that has the whole drawing in frame 2025-10-24 16:31:25 +02:00