Commit Graph
116 Commits
Author SHA1 Message Date
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
dietrich e6bc79ea7b now svg lines, circles and fills are exported 2025-10-23 16:15:02 +02:00
dietrich 6e6aa8b27e initial svg support 2025-10-23 09:40:08 +02:00
dietrich 88d188a794 small fixes for clippy compliance 2025-10-20 14:46:04 +02:00
dietrich 0e191c617c fix doc tests 2025-10-20 11:51:05 +02:00
dietrich 728549253d some more examples 2025-10-19 16:39:42 +02:00