Commit Graph
2847 Commits
Author SHA1 Message Date
Felix RiestraandClaude Sonnet 5 44deee2ac9 Port 6 audit-found bugs from the upstream OSNAP fix branch
Ports the fixes from fix/osnap-circle-arc-ellipse-intersection (and
this session's audit follow-up) onto this branch. All are independent
correctness/reliability fixes, unrelated to the parametric-constraint-
system work also in progress here.

1. OSNAP Intersection snap used a tessellated approximation instead of
   exact geometry (GitHub discussion #1052): a circle/arc always
   tessellates at a fixed 48 segments in the resident wire set
   regardless of radius or zoom, so every circle/arc intersection snap
   was off by construction. Added exact_circle_intersections, a
   closed-form, frame-independent circle/arc-vs-circle/arc solver,
   wired into both Intersection-snap code paths ahead of the
   tessellated sweep. This branch's TangentGeom predates the
   PlanarEllipse variant added upstream, so the ellipse/line
   generalization from the upstream fix isn't ported here — this
   covers the literal reported bug (a circle-circle case) using only
   variants this branch already has.

2. Unbounded MINSERT allocation: array_offsets() reserved one Vec
   element per array instance with row/column counts parsed as
   unchecked u16s — a corrupt 65535x65535 pair requests ~96 GiB.
   Fixed with a documented instance budget (20,000), enforced at both
   the load-time corrupt-entity filter and a render-graph failsafe.

3. MINSERT spacing was scaled by the block's own scale:
   insert_instance_transform composed the offset translation before
   the instance transform, so x/y block scale multiplied the row/
   column spacing too. Fixed by orienting the offset with rotation +
   OCS only, then translating the already-scaled instance transform.

4. Automation "open" skipped the finalization (block-origin
   normalization, raster-path resolution, source_path) and corrupt-
   entity purge a UI open always runs. Added
   io::load_bytes_finalized(path, bytes), used by automation's "open"
   handler, which now also reports the purge count.

5. Material maps were uploaded without checking
   device.limits().max_texture_dimension_2d, unlike raster-image
   rendering (which already tiles to that limit). A mesh material is
   sampled by UV, so it can't use the same tiling trick — instead,
   upload_rgba_texture now downscales an oversized image before
   upload, falling back to the 1x1 material color if malformed.

6. Sketch-constraint persistence/undo, audit-found while reviewing
   this branch's own constraint system:
   - Clearing every constraint in a scope after a prior non-empty save
     left the stale XRecord in place, resurrecting the deleted
     constraints on the next load. materialize_sketch_constraints_for_
     save now actively removes the XRecord when a scope goes back to
     empty.
   - ERASE removing an entity took its constraints with it (design
     doc's deletion policy), but sketch_constraints lives on Scene,
     outside document/document.objects, so nothing captured that
     mutation for undo — the erased geometry came back on undo, but
     its constraints didn't. refresh_sketch_constraints's deletion
     pass now records the touched scope's before-image into the same
     UndoRecording the entity removal rides in, threaded through a new
     sketch_constraints channel on DeltaSnapshot, so one undo restores
     both together. HistorySnapshot::Delta is now boxed (clippy
     flagged the resulting size skew across undo/redo stack variants).

31 new/adapted tests across all six fixes. Full workspace suite passes
except the one pre-existing, unrelated font-test failure also present
on main.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 10:46:28 +02:00
Felix RiestraandClaude Sonnet 5 63a74b19a9 Add persistent sketch-constraint system (ocs_gcs port) and named-parameters handoff docs
Ports FreeCAD's planegcs 2D geometric constraint solver to Rust as a new
crates/ocs_gcs workspace member, and wires it into the document/scene model
as a persistent SketchConstraintSet: Coincident, Horizontal/Vertical,
Parallel/Perpendicular, Equal, Tangent, Distance, Angle and Radius
constraints that re-solve live (including mid-drag, not just on release),
render glyphs and a DOF badge, flag conflicts with a one-click resolver
pill, and round-trip through save/load via an XRecord blob.

Also includes docs/command_reference.md (a statically generated reference
of every registered command and its prompt sequence) and
docs/named_parameters_design.md + docs/backlog.md, which hand off the next
queued feature (a named-parameter/expression table) and consolidate every
deliberate scope-down and open gap found along the way, so a fresh session
has a complete starting point.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 22:19:23 +02:00
Felix RiestraandClaude Sonnet 5 a39c7b8f71 macOS launcher: re-assert Accessory policy after handling an event
Handling a document-open Apple Event (a warm "Open With" while the app
is already running) silently promotes this process from
NSApplicationActivationPolicyAccessory to a normal foreground app —
confirmed with lsappinfo, not assumed: its own entry flips from
type="UIElement" to type="Foreground" the instant it handles a second
Apple Event (a cold launch's own first event doesn't trigger this).
That gave the launcher its own, contentless Dock icon sitting next to
the real editor's, both apparently "the same app" to the user but
actually two separate Dock entries.

Re-set Accessory explicitly right after relaying, in the one place
every open (cold fallback, document open, and reopen-while-running)
already funnels through.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 17:51:23 +02:00
Felix RiestraandClaude Sonnet 5 24e9a7663d macOS launcher: handle reopen while already running with no window
Quitting the real GUI binary (Cmd+Q) leaves the launcher itself still
running — that's by design, so it can keep relaying opens for the
session. But reopening the app afterward (Dock icon, double-clicking
it in Finder again) reactivates that same long-lived launcher process
rather than triggering a fresh cold launch, since Launch Services
still considers the bundle running. Neither of the delegate methods
already handled covered that: applicationDidFinishLaunching: only
fires once, at the launcher's own original cold start, and
application:openURLs: only fires when a document was named. The net
effect: the Dock icon would appear, but no window ever showed.

applicationShouldHandleReopen:hasVisibleWindows: is exactly the
callback AppKit fires for this reactivation case. Reproduced and
verified the fix against the real sequence (cold launch, kill only the
GUI process to simulate Cmd+Q, reopen) rather than assuming it from
the delegate method's docs alone.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 17:34:57 +02:00
Felix RiestraandClaude Sonnet 5 e767507850 macOS: add a launcher shim so a cold Finder open also works (#1039)
The previous commit's Apple Event handler only ever catches an open
sent to an already-running process. A cold double-click (app not
running yet) still failed: every registration point tried inside the
real binary — before app::run(), on the Subscription's first poll,
even the literal first statement of main() — reliably caught a warm
open but never the original cold-launch event. A raw
AEInstallEventHandler in a separate, minimal, non-AppKit process (no
winit/iced, just a manual CFRunLoopRunInMode pump) still missed it
too, ruling out "the real binary's heavy dependency graph loading
before main() wins the race" as the explanation.

What does reliably catch a cold launch, verified against real
Finder-equivalent opens: a from-scratch NSApplication with its own
delegate implementing application:openURLs: — in a process where we
own setDelegate: from the start, with no contention over the single
delegate slot winit already claims. That has to be a separate process
from the real GUI binary (only one -[NSApplication run] call can own a
process), so src/bin/ocs_launcher.rs is now the .app's actual
CFBundleExecutable: a small, dependency-light binary (no iced, wgpu,
or cadkernel) whose only job is to catch the open and relay it.

Relaying by replacing this process's image (exec, same PID) or by
spawning a child and exiting turned out to both be dead ends: Launch
Services tracks "the running instance of this bundle" by the
Application Serial Number it handed out to whichever process it
actually launched — this launcher, not whatever it execs into or
spawns. Once the launcher's own ASN stopped pointing at a live,
listening process, every later open Finder tried to deliver silently
went nowhere (measured with lsappinfo against a real second "Open
With", not assumed). So the launcher now stays running for the app's
session — invisible, via NSApplicationActivationPolicyAccessory, since
it owns no window — and relays every open (cold or warm) over the same
channel a second CLI invocation already uses: io::single_instance.

That relay only worked once single_instance's rendezvous key stopped
being computed from the running executable's own path. That was fine
when one binary always did the job, but the launcher and the real
binary are different executables and independently computed different
ports, so they could never find each other. Anchor the key on the
enclosing .app bundle instead, shared by both.

packaging/build_macos_signed.sh and .github/workflows/release.yml now
build ocs_launcher and place it at Contents/MacOS/OpenCADStudio (the
CFBundleExecutable Info.plist already names), with the real GUI binary
renamed to Contents/MacOS/OpenCADStudio-App alongside it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 16:45:02 +02:00
Felix RiestraandClaude Sonnet 5 b617734d5c macOS: catch a Finder open aimed at the already-running app (#1039)
Double-click / "Open With" never puts the file on argv — Finder always
delivers it as a kAEOpenDocuments Apple Event instead, which nothing in
this app listened for, so it just showed "cannot open files in this
format" even though the file association itself was registered
correctly.

The standard fix, implementing application:openURLs: on this app's own
NSApplicationDelegate, isn't available here: winit already installs
its own delegate to own window/lifecycle events, NSApplication has
exactly one delegate slot, and winit's class doesn't implement the
open-document method.

This bypasses the delegate protocol and registers directly with the
lower-level Apple Event Manager (AEInstallEventHandler) instead — the
same mechanism AppKit's delegate forwarding is itself built on, and
independent of who owns the delegate. Registration happens on the
iced Subscription's first poll rather than in main() before app::run()
— registering earlier gets silently overwritten by winit's own
NSApplication startup, confirmed by testing against a real `open -a`
rather than assumed from Apple's docs.

This handles a file opened while the app is already running. A cold
launch (app not running yet) needs a different mechanism, in the
following commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 16:44:44 +02:00
Hakan Seven 143703d809 Improve website translations and favicons; disable push workflows 2026-09-07 01:19:39 +03:00
Hakan Seven d66e89ca19 Complete application localization across all supported languages 2026-09-07 01:05:02 +03:00
Hakan Seven 96c794c072 Remove .claude configuration directory 2026-09-06 21:52:03 +03:00
Hakan Seven 3385160493 Merge PR #1028: add document API with atomic edits
Add the typed document facade and plugin IPC adapter. Prepare bulk edits
before mutation, preserve undo and dirty state, keep profile elevations,
validate numeric inputs and session bindings, and generate Python constructors
with typed results.

Reuse existing entity transforms and profile conversion. Compute mass
properties and closed-surface bounds in cadkernel; pin its main revision
6a5e6fc2822f6af6b2611cd605b44437b35158f0. Keep plugin API metadata at version 6.

Validation: 646 native application tests, 597 kernel tests, 12 document API
tests, 91 plugin API tests, 3 Python tests, default/IPC feature builds and
wasm32 check passed.
2026-09-06 21:43:02 +03:00
Hakan Seven bf4614856c Merge PR #1023: preserve minified text strokes
Keep adaptive sampling in both text shaders with compact sampling loops. Validate shader derivatives and existing text rendering, including GPU pipeline creation.

Closes #964
2026-09-06 21:04:14 +03:00
Sebastian f79c8c59bb ocs_doc_api: dissolve src/app/doc_api_convert.rs shim into direct crate usage
Delete the thin re-export file; src/app/doc_api.rs now uses ocs_doc_api::convert
directly (use ocs_doc_api::convert + convert::* call sites). Remove the
mod doc_api_convert registration from src/app/mod.rs.

The conversion logic already lives in the crate (src/convert.rs) from the prior
move; the shim was redundant. 623 host lib + 38 doc_api tests green.
2026-09-06 17:14:48 +02:00
Sebastian d746d635fb ocs_doc_api: move doc_api_convert.rs into the crate (src/convert.rs)
Move the 503-line host-independent entity-conversion module (acadrust EntityType
<-> DTO conversions, transform_entity_geometry, entity_to_profile_curves,
bulge_arc_segment, entity_bounds, entity_kind_name, points_aabb) from
src/app/doc_api_convert.rs into crates/ocs_doc_api/src/convert.rs (host feature).

The host file is now a thin re-export (pub use ocs_doc_api::convert::*) so all
existing crate::app::doc_api_convert::* paths keep working unchanged. Zero
coupling risk (the module only touches acadrust + crate DTOs).

623 host lib + 8 crate + 3 consistency green.
2026-09-06 17:00:04 +02:00
Sebastian d1b8fc93f5 ocs_doc_api: convert architecture flow diagram to readable text format
Replace the mermaid flowchart (hard to read raw) with a clean ASCII/text diagram
tracing the same flow from the single source of truth (spec/entities.toml +
layouts.json) through codegen, facade, wire, transport, executor, and the host
backend/Scene, plus a layer-by-layer legend.
2026-09-06 16:34:39 +02:00
Sebastian 0965e188c9 ocs_doc_api: enrich + update all documentation (architecture flow diagram, guarantees, counts)
- ARCHITECTURE.md: add 'Flow: from the single source of truth to a committed
  change' mermaid diagram (spec/entities.toml + layouts.json -> codegen -> facade
  -> wire -> transport -> executor -> host backend/Scene); fix stale claims
  (hand-maintained enums not 'GENERATED'; accuracy-first mass properties + Scene
  cold-tess budget; with_body borrow; tab auth); add Review round 3 change-log;
  update Known deviations.
- README.md: Core guarantees now include Loft/query caps, accurate mass properties
  (Scene budget persists + graceful fallback), and tab authorization.
- IMPLEMENTATION.md: accuracy paragraph (Scene budget + fallback) + current test
  counts (623 host lib + 8 crate + 3 consistency + 34 plugin_api).
- Regenerate api_reference.md (26 sections) + binding_schema.json (28 ops / 12
  queries / 14 handles / 19 families).
- 623 host lib + 8 crate + 3 consistency + 34 plugin_api green.
2026-09-06 16:23:33 +02:00
Sebastian 919128e087 ocs_doc_api: fix branch-review findings (tab auth, bulge center, budget, caps, dead code)
CRITICAL:
- execute_doc_api: reject tab_id != bound tab (confused deputy); test
  doc_api_tab_mismatch_is_rejected.
- bulge_arc_segment: fix negative/CW bulge center (apothem magnitude + sign picks
  side; was double-sign-mirrored); test CW-vs-CCW center offset.
- cold-tess budget: move mass_cache/cold_tess_used to per-tab Scene so the budget
  persists across DocApi dispatches (was reset per request); budget-exhausted ->
  approximate meshes.metrics fallback instead of error.

WARNING:
- Loft: add BULK_ITEM_CAP (was uncapped -> unbounded kernel call from one request).
- CreateMany: pre-validate EntitySpec::Curve (ellipse ratio) in prepare phase ->
  all-or-nothing restored; regression test.
- Partial Ellipse: offset start/end_parameter by rot_z on rotation; regression test.
- resolve_body: add with_body borrow accessor (host overrides to borrow cache in
  place, O(1)); bounds() uses it instead of deep-cloning the B-rep per query.
- add_raster_image: validate file path (non-empty, image extension, reject
  UNC/traversal); regression test.

SUGGESTION:
- deploy: bump API_VERSION 5 -> 6 so DocApi plugins are gated at handshake on old
  hosts (append-only wire + defaulted method keep old V2-V5 plugins loading).
- dead code: wire query_name into apply_queries error labels; host uses crate's
  ObjectId::from_handle/to_handle (drop local duplicates); delete is_null/backend_mut.
- mock drift: test mock now stores curve specs + computes curve bounds (aligns with
  example mock); Spline/Dimension bounds delegate to points_aabb.

623 host lib + 8 crate + 3 consistency + 34 plugin_api green.
2026-09-06 16:03:34 +02:00
github-actions[bot] ddbbdd27ba Release v2026.36 v2026.36 2026-09-06 12:27:42 +00:00
Sebastian ac54d6079b ocs_doc_api: fix review findings (layouts, Helix bounds, points_aabb, mass-properties budget, docs)
- layouts.json: append the 6 missing ops (CreateDimensionRadius/Diameter/Angular,
  CreateAttributeDefinition, CreateTable, CreateDimensionAngular2Ln); regenerate
  binding_schema.json + api_reference.md wire vocabulary (all 28 ops).
- Helix bounds: bound the evaluated spline control polygon (was a degenerate
  single-start-point AABB).
- points_aabb: empty -> Geometry::Empty('entity has no points to bound'), not
  UnknownId (the entity exists; don't misclassify as stale/deleted).
- mass_properties: accuracy-first fine tessellation + graceful degradation to the
  approximate meshes.metrics value when the cold-tess budget is exhausted (large
  distinct-solid batches no longer hard-fail).
- IMPLEMENTATION.md: Volume/Centroid rows + accuracy paragraph + test count (618)
  consistent with the final design.
- 618 host lib + 8 crate + 3 consistency green.
2026-09-06 14:23:00 +02:00
Sebastian 28c8e0ef1a ocs_doc_api: read-mostly family bounds (Leader/Mesh/Face3D/MLine/Helix)
- entity_bounds: vertex/point-carrying read-mostly families (Leader.vertices,
  Mesh.vertices, Face3D 4 corners, MLine vertex positions, Helix start point)
  via a points-to-AABB helper. Region/Body/Surface/MultiLeader stay Unsupported.
- IMPLEMENTATION.md: read-mostly bounds done.
- Test read_mostly_family_bounds_leader_and_mesh -> 618 host lib green.
2026-09-06 13:46:41 +02:00
Hakan Seven 8eafbc6899 Refresh shared website and README screenshots 2026-09-06 14:40:42 +03:00
Sebastian 6997dfe618 ocs_doc_api: accurate GetVolume/GetCentroid via fine tessellation
- mass_properties: query path now uses fine mesh_body(0.1, 1e-4) for near-analytic
  volume/centroid; the render-mesh metrics cache (coarse display LOD) no longer
  shadows query accuracy. Memoized per (handle, epoch); cold-tess budget kept.
- IMPLEMENTATION.md: accuracy item done.
- Test accurate_volume_centroid_sphere_and_cube (sphere within 0.5% of 4/3*pi*r^3,
  centroid at centre, cube exact) -> 617 host lib green.
2026-09-06 13:40:07 +02:00
Sebastian 612e8e13e0 ocs_doc_api: Phase 2c-iii — 2-line angular dimension (all dimension sub-types done)
- CreateDimensionAngular2Ln(DimensionAngularSpec) op (append-only).
- backend add_dimension_angular2ln (DimensionAngular2Ln::new computes angle).
- facade create_dimension_angular2ln; spec constructor; api_reference + binding_schema
  regenerated; mocks + baseline.
- IMPLEMENTATION.md: fix stale Status line (all 5 phases complete, current test
  counts); mark all dimension sub-types done.
- Test phase2ciii_dimension_angular2ln (90-degree 2-line angle) -> 616 host lib +
  3 consistency green.
2026-09-06 13:24:25 +02:00
Sebastian 240831edcd ocs_doc_api: Phase 5-ii — typed Table create
- CreateTable(TableSpec{insertion_point, data[row][col]}) op (append-only).
- backend add_table via Table::new(insertion_point, rows, cols) + set_cell_text
  (Table::default() pre-creates 3x3, so use Table::new for exact dims).
- executor validates non-empty rectangular grid; facade create_table.
- spec Table constructor; api_reference + binding_schema regenerated; mocks + baseline.
- Test phase5ii_create_table_from_grid (3x2 grid, non-rectangular rejected)
  -> 615 host lib + 3 consistency green. Phase 5 complete.
2026-09-06 13:02:21 +02:00
Hakan Seven bf2e89ce0c Point the star chart to the publicly accessible project page 2026-09-06 14:01:04 +03:00
Hakan Seven 2d06004c1f Balance all website sections and improve mobile navigation 2026-09-06 13:58:32 +03:00
Hakan Seven a86f46375d Center the website hero and balance translated headings 2026-09-06 13:49:34 +03:00
Sebastian f8ae54a351 ocs_doc_api: Phase 3-ii — typed AttributeDefinition create (Phase 3 complete)
- CreateAttributeDefinition(AttributeDefinitionSpec) op (append-only).
- backend add_attribute_definition (ATTDEF tag/prompt/default/insertion/height/rotation).
- facade create_attribute_definition; entity_kind_name AttributeDefinition/AttributeEntity.
- spec AttributeDefinition family; api_reference + binding_schema regenerated; mocks + baseline.
- Test phase3ii_create_attribute_definition -> 614 host lib + 3 consistency green.
2026-09-06 12:43:34 +02:00
Hakan Seven 4a5adf90a5 Localize website in all supported languages and refresh site icons 2026-09-06 13:32:37 +03:00
Sebastian 8d8c120880 ocs_doc_api: Phase 2c-ii — dimension sub-types (radius/diameter/angular)
- CreateDimensionRadius/CreateDimensionDiameter (DimensionRadialSpec) +
  CreateDimensionAngular (DimensionAngularSpec) ops (append-only).
- backend add_dimension_radius/diameter (DimensionRadius/DimensionDiameter::new)
  + add_dimension_angular (DimensionAngular3Pt::new computes angle);
  dimension_measurement returns degrees for angular sub-types.
- facade create_dimension_radius/diameter/angular; spec constructors; api_reference
  + binding_schema regenerated; mocks + baseline.
- Test phase2cii_dimension_radius_diameter_angular -> 613 host lib + 3 consistency green.
2026-09-06 12:31:23 +02:00
Hakan Seven 2ebad14586 fix(web): capture save previews from the browser canvas
Capture the rendered canvas during the clean frame instead of requesting synchronous GPU buffer readback. Preserve embedded previews and allow saving when canvas readback is denied. Add a browser save and reopen regression check.

Fixes #1021
2026-09-06 13:14:56 +03:00
Sebastian 2522979285 ocs_doc_api: enrich API reference generator
api_reference.md now includes (regenerated from spec + layouts.json):
- Wire vocabulary section: every Operation (22) + Query (12) variant with payloads.
- Errors section: ApiError variant table.
- Envelope & transport section: DocApiEnvelope framing, Receipt, transports.
- Method/constructor lines now show fixed fields (e.g. SolidBoolean erase_sources
  + op value) and clean zero-arg () rendering.

Generator: fmt_fixed/fmt_call_args helpers; reads layouts.json for the wire vocab.
612 host lib + 8 crate + 3 consistency green.
2026-09-06 11:35:23 +02:00
Hakan Seven a16e0f4163 Remove theme-changing test cases 2026-09-06 12:26:10 +03:00
Sebastian a9c278e32a ocs_doc_api: update docs + fix review-drift findings
- lib.rs: export all 14 facade handles (add ArcCurve/Ellipse/Spline/Ray/XLine/Text/
  MText/Dimension + Circle) — public surface matches collection return types.
- build.rs: fix step-1 comment (enums are hand-maintained, not 'regenerated');
  generic_reference_md: Clone (not Copy) + full 14-handle list (was stale 6).
- ops.rs/query.rs: correct 'hand-maintained' module doc comments (were 'GENERATED').
- layouts.json: extend to all 22 Operation + 12 Query variants (was stale phase-1).
- binding_schema.json regenerated (complete layouts + derived handles).
- generate.py: inject 'id': self.id for SetTextContent/SetAttribute/SetViewportView/
  Transform/Delete/AddVertex (was malformed id-less payloads); _apply_op/_apply_query
  accept want=None; extend PY_TYPES (String/&str/Vec returns/new handles).
- README.md: Clone (not Copy) + full scope (2D curves, annotations, containers,
  viewports, media) replacing stale 'Not yet' list.
- Plan (.kilo): mark implemented & published; pointer to live crate docs.
2026-09-06 11:22:01 +02:00
Sebastian 8417375e5a ocs_doc_api: fix stray impl-closing brace in both mock backends
The loft/attributes/viewport mock methods were appended after the impl block's
closing brace, orphaning add_vertex..finalize_op and leaving a duplicate brace.
Move the impl close to the true end in both tests/mock_backend.rs and
examples/common/mod.rs. Crate tests (8) + examples compile green again.
2026-09-06 10:55:36 +02:00
Hakan Seven 2c83ae2736 Show donation request once per app version 2026-09-06 11:44:38 +03:00
Sebastian e216a7bf94 ocs_doc_api: outstanding methods — loft + bulge-arc polyline profiles
- Loft{profiles} op (append-only); executor resolves each profile to curve sets
  all-or-nothing; backend loft() -> brep::loft on XY plane; facade solids().loft.
- entity_to_profile_curves: convert LwVertex.bulge to geom2d::Curve::Arc via
  bulge_arc_segment (theta = 4*atan(bulge)), so bulged polyline profiles sweep
  correctly instead of erroring Unsupported.
- spec loft; api_reference + binding_schema regenerated; mocks + baseline.
- Tests: loft_two_profiles_produces_solid, bulge_arc_polyline_profile_converts_to_arc
  (semicircle radius=5 for bulge=1) -> 612 host lib + 3 consistency green.
2026-09-06 10:44:37 +02:00
Sebastian 46a5922520 ocs_doc_api: Phase 5 typed raster image create
- CreateRasterImage(RasterImageSpec) op (append-only).
- backend add_raster_image (RasterImage with file_path/insertion/u/v/size; the
  scene auto-registers the ImageDefinition on add_entity).
- facade create_raster_image; spec RasterImage constructor; api_reference +
  binding_schema regenerated; mocks + baseline.
- Test phase5_create_raster_image_registers_definition (asserts definition_handle
  auto-registered + 4-corner bounds) -> 610 host lib + 3 consistency green.
- Phase 5 complete.
2026-09-06 10:28:51 +02:00
Sebastian e6c132e0eb ocs_doc_api: Phase 4 set_view + viewport-view query
- SetViewportView op + GetViewportView query (append-only).
- backend set_viewport_view (update Viewport.view_target/view_height) + viewport_view.
- facade Entity::set_view/viewport_view (Viewport returns Entity).
- spec Viewport methods; api_reference + binding_schema regenerated; mocks + baseline.
- Test phase4_set_view_and_view_query -> 609 host lib + 3 consistency green.
- Phase 4 complete.
2026-09-06 10:16:27 +02:00
Sebastian 67655add72 ocs_doc_api: Phase 3 attributes + nested block traversal
- SetAttribute op + GetAttributes/GetBlockEntities queries (append-only).
- backend set_attribute (add/update Insert attribute), attributes (tag,value pairs),
  block_entities (read-only traversal via BlockRecord.entity_handles -> id+kind+bounds).
- facade Entity::set_attribute/attributes, Document::block_entities.
- spec Insert methods; api_reference + binding_schema regenerated; mocks + baseline.
- Query enum: drop Copy (GetBlockEntities carries String).
- Test phase3_attributes_and_block_traversal -> 608 host lib + 3 consistency green.
2026-09-06 10:02:23 +02:00
Sebastian 2dba0158ca ocs_doc_api: Phase 2b-c (linear Dimension) — Phase 2 complete
- CreateDimensionLinear(DimensionSpec) op + GetDimensionMeasurement query (append-only).
- backend add_dimension_linear (Dimension::Linear via DimensionLinear::new) +
  dimension_measurement (linear/radius/diameter distance).
- Dimension bounds from measured + definition points; Dimension handle + measurement().
- spec Dimension family; api_reference + binding_schema regenerated; mocks + baseline.
- Test phase2c_dimension_linear_create_measurement_bounds -> 607 host lib + 8 crate
  + 3 consistency green. Phase 2 (full 2D + annotations) is now complete.
2026-09-06 09:43:37 +02:00
Sebastian ba8e5ed0cd ocs_doc_api: Phase 2b-b (Hatch)
- CreateHatch(HatchSpec) op + GetHatchBoundary query (append-only).
- HatchSpec{boundary: Vec<[f64;2]>, solid}; executor validates >= 3 boundary points.
- backend add_hatch (Line-edge BoundaryPath, solid/pattern) + hatch_boundary
  (reconstruct loops from Line edges; non-line edges -> Unsupported).
- Hatch bounds from boundary edges; facade create_hatch + Entity handle.
- spec Hatch family; api_reference + binding_schema regenerated; mocks + baseline.
- Test phase2b_hatch_create_boundary_bounds_delete -> 606 host lib + 8 crate + 3 consistency green.
2026-09-06 09:24:11 +02:00
Sebastian fc0e2c2c9d ocs_doc_api: Phase 2b-a (Text/MText annotations)
- CreateText/CreateMText/SetTextContent ops + GetTextContent query (append-only).
- backend add_text/add_mtext/set_text_content/text_content (Text.value/MText.value).
- facade create_text/create_mtext + Text/MText handles with content()/set_content().
- Text/MText coarse bounds + transform (insertion point); ensure_transformable.
- spec Text/MText families; api_reference + binding_schema regenerated; mocks.
- can_modify backend hook (exists + not-locked) for SetTextContent validation.
- consistency baseline extended with the appended variants.
- Test phase2b_text_mtext_create_content_transform -> 605 host lib + 3 consistency green.
2026-09-06 09:07:41 +02:00
Sebastian 1925a83a25 ocs_doc_api: spec<->wire consistency + append-only baseline tests
Add tests/spec_wire_consistency.rs: (a) every op/query name in spec/entities.toml
maps to an existing Operation/Query variant; (b) both enums are append-only
relative to a recorded variant-order baseline (bincode discriminant stability).
Adds toml to dev-dependencies. 3 tests green.
2026-09-06 08:44:53 +02:00
Sebastian c74504f30c ocs_doc_api: fix review findings (scale/rotation/all-or-nothing/DoS/bounds/codegen)
CRITICAL:
- transform_entity_geometry: fix s^2 double-scale (axes already carry scale; drop
  the *s pre-multiply so 2D entities scale by s like solids), and handle rotation
  for direction/angle fields (apply_dir for Ray/XLine direction + Ellipse
  major_axis; offset Arc angles; compose Insert rotation).
- ensure_transformable: check layer-lock + resolve solid bodies (not just type),
  restoring TransformMany all-or-nothing; regression test with a locked layer.

WARNING:
- volume/centroid: memoize per (handle, geometry_epoch) + cap cold-cache
  tessellation budget (query-batch DoS).
- entity_to_profile_curves: fail Unsupported on polyline bulge (no silent
  chord-substituted sweep profile).
- Ellipse: validate minor_axis_ratio in (0,1] so bounds never under-bound.
- RasterImage bounds: bracket all four corners (rotated/flipped images).

SUGGESTION:
- binding_schema.json handles derived from spec families (includes ArcCurve/
  Ellipse/Spline/Ray/XLine).
- build.rs header: enums are hand-maintained (not 'GENERATED'); ops_gen/query_gen
  headers corrected to match.
- Dedupe divergence mesh_volume_centroid into the crate's geom module; host +
  both mocks delegate.

Tests: +3 regression tests (scale-once, rotation, locked-layer all-or-nothing)
-> 604 host lib green; 8 crate unit tests green.
2026-09-06 08:36:06 +02:00
codallos 995b25ae51 Fix SDF text minification artifacts 2026-09-05 22:30:16 -06:00
gianlucafiore 1b0a42a35c Merge pull request #1022 from gianlucafiore/feat/drawing-cursor-dot
feat(cursor): add point cursor for active commands
2026-09-05 22:52:00 -03:00
gianlucafiore 5bca05d913 feat(cursor): add point cursor for active commands 2026-09-05 22:39:34 -03:00
Karim Jerbi 0dab3ec54a feat: add COMMANDLINEFADETIME sysvar for overlay history fade
Controls how long command-line history lines stay visible, in ms (0-60000, default 3000). Bare form stays active until a value or Esc.
2026-09-06 02:13:09 +01:00
Sebastian fabdeae8bf ocs_doc_api: make mock backends exhaustive over new Curve2Spec variants
Add Arc/Ellipse/Spline/Ray/XLine arms to the test + example mock add_curve
kind matching and the example curve_bounds, so the crate's unit tests and
examples compile against the Phase 2 curve families.
2026-09-06 01:29:51 +02:00
Sebastian 0e18867915 IMPLEMENTATION.md: roadmap status — all 5 phases done (with noted remaining sub-items) 2026-09-06 01:23:25 +02:00