Skip to content

Conversation

@mateuszJS
Copy link
Owner

@mateuszJS mateuszJS commented Aug 26, 2025

Summary by CodeRabbit

  • New Features

    • Distance scale control for shape computation; per-shape preview state.
    • New picking support for shapes and triangles.
  • Performance

    • Per-shape SDF caching with selective recompute; automatic SDF texture sizing that respects device limits.
  • Visual

    • Skeleton points scale with render scale; consistent skeleton stroke width.
  • Bug Fixes

    • Avoids unintended pointer release when no shape is selected.
  • Refactor

    • Compute pass renamed to "computeShape" and initialization now includes device buffer size.

Copilot AI review requested due to automatic review settings August 26, 2025 13:45
@coderabbitai
Copy link

coderabbitai bot commented Aug 26, 2025

Walkthrough

Renames computeSDF→computeShape across WebGPU and runtime, adds a distance_scale uniform and bind-group binding to the compute shader, threads buffer/size and distance-scale parameters through Zig/WebGPU APIs, introduces SDF texture sizing and per-shape SDF caching/preview state, and expands initialization to accept max buffer size.

Changes

Cohort / File(s) Summary
WebGPU computeShape pipeline
src/WebGPU/programs/computeShape/getProgram.ts, src/WebGPU/programs/computeShape/shader.wgsl, src/WebGPU/programs/initPrograms.ts
Rename API to computeShape; update labels; add uniform struct Uniforms { distance_scale } and @binding(2) uniform; create/destroy uniform buffer and include it in bind group (binding 2); shader multiplies signed distance by distance_scale.
Runtime wiring
src/run.ts, src/index.ts
Replace computeSDF with computeShape; thread distanceScaleFactor into compute_shape call; pass device.limits.maxBufferSize into initState; remove timing/logging instrumentation.
Logic core API & sizing
src/logic/index.zig, src/logic/index.d.ts, src/logic/get_sdf_texture_size.zig, src/logic/shared.zig, src/logic/types.zig, src/logic/utils.zig
initState gains max_buffer_size; add TextureSize type; add get_sdf_texture_size(bounds) that clamps to texture_max_size and max_buffer_size; add shared.{texture_max_size,max_buffer_size}; rename cmpF32equalF32; expand compute_shape signature to include width/height as u32 and a distance_scale f32; add picking function pointers.
Shapes and rendering adjustments
src/logic/shapes/shapes.zig, src/logic/shapes/paths.zig
Move preview state into Shape (preview_point, sdf_size); add getNewSdfPoint and update_preview_point; updatePointPreview now accepts Point; getSkeletonDrawVertexData signature drops is_active; bounds/padding and skeleton sizing now respect render_scale; onReleasePointer becomes a Shape method.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant App as App/UI
  participant Logic as Logic (Zig)
  participant Size as get_sdf_texture_size
  participant WG as WebGPU computeShape
  participant Shader as WGSL Shader
  participant Tex as Storage Texture

  App->>Logic: initState(width,height,maxTex,maxBuf)
  App->>Logic: request SDF for shape
  Logic->>Size: compute(bounds) -> TextureSize {w,h}
  Size-->>Logic: {w,h}
  Logic->>WG: compute_shape(points, w, h, distance_scale, texture_id)
  WG->>Shader: dispatch (bindings: texture(0), curves(1), uniform(distance_scale@2))
  Shader->>Tex: write sdf_value * distance_scale
  WG-->>Logic: done
  Logic-->>App: render uses updated texture
  note over WG,Shader: New uniform @group(0) @binding(2): distance_scale
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

released on @next

Poem

"I hop through bytes and shader light,
I scale the distance, snug and right.
Buffers bounded, textures trim—
Shapes cache secrets, edges brim.
A rabbit cheers: computeShape, delight! 🐇"

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9407da9 and cd7f41e.

📒 Files selected for processing (3)
  • src/WebGPU/programs/computeShape/getProgram.ts (1 hunks)
  • src/logic/get_sdf_texture_size.zig (1 hunks)
  • src/logic/shared.zig (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/logic/get_sdf_texture_size.zig
  • src/logic/shared.zig
  • src/WebGPU/programs/computeShape/getProgram.ts
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch recompute-sdf

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Refactors the SDF (Signed Distance Field) computation system by renaming functions and improving texture size management for better performance and scalability.

  • Renames computeSDF to computeShape for clearer function naming
  • Improves texture size calculation with dynamic scaling based on device limits
  • Optimizes SDF regeneration to only occur when necessary

Reviewed Changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/run.ts Updates function call from computeSDF to computeShape and adds distance scale parameter
src/logic/utils.zig Renames cmpF32 to equalF32 for clarity
src/logic/types.zig Adds TextureSize struct for texture dimension management
src/logic/shared.zig Adds global variables for buffer and texture size limits
src/logic/shapes/shapes.zig Major refactor to improve SDF computation with better state management and scaling
src/logic/shapes/paths.zig Fixes skeleton point size calculation
src/logic/index.zig Updates initialization and shape cache management with new texture sizing
src/logic/get_sdf_texture_size.zig New utility for calculating optimal SDF texture dimensions
src/index.ts Passes device buffer limits to initialization
src/WebGPU/programs/initPrograms.ts Renames computeSDF to computeShape
src/WebGPU/programs/computeShape/shader.wgsl Adds distance scale uniform to shader
src/WebGPU/programs/computeShape/getProgram.ts Updates program with distance scale parameter

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/logic/shapes/shapes.zig (1)

277-308: Only clear outdated_sdf when bounds update succeeds; avoid premature “cache valid”.
Ties into the earlier degenerate-bounds issue. With the update_bounds change, guard the reset:

 // function has side effect, marks texture as generated
 pub fn getNewSdfPoint(self: *Shape, allocator: std.mem.Allocator) !?[]Point {
-    if (self.outdated_sdf) {
-        try self.update_bounds(allocator, self.preview_point);
-    }
+    if (self.outdated_sdf) {
+        const updated = try self.update_bounds(allocator, self.preview_point);
+        if (!updated) {
+            // Keep outdated_sdf = true; wait for more input before emitting points
+            return null;
+        }
+    }

     const points = try self.getAllPoints(
       allocator,
       self.preview_point,
       active_path_index,
     );

     if (points.len == 0) {
         return null;
     }

     const scale = Matrix3x3.scaling(
         self.bounds[0].distance(self.bounds[1]) / shared.render_scale,
         self.bounds[0].distance(self.bounds[3]) / shared.render_scale,
     );

     const padding = (self.props.stroke_width / 2.0) / shared.render_scale;
     for (points) |*point| {
         const scaled = scale.get(point);
         point.x = padding + scaled.x;
         point.y = padding + scaled.y;
     }

-    self.outdated_sdf = false;
+    self.outdated_sdf = false;

     return points;
 }
src/logic/index.zig (1)

712-751: Unit test broken by API changes (initState and callback types).
The test currently won’t compile:

  • initState now needs (width, height, texture_max_size, max_buffer_size)
  • connectOnAssetUpdateCallback expects ([]const AssetSerialized) → void
  • resetAssets now takes []const AssetSerialized

Update the test as follows:

 test "reset_assets does not call the real update callback" {
   // Setup initial state
-  initState(100, 100);
+  initState(100, 100, 8192, 16_777_216);
   // Ensure state is cleaned up after the test
   defer destroyState();

   // Define a mock callback function locally, with its own static state.
   const MockCallback = struct {
     // This static variable will hold the state for our mock.
     // It's reset to false before each test run.
     var was_called: bool = false;

-    fn assets_update(_: []const images.Serialized) void {
+    fn assets_update(_: []const AssetSerialized) void {
       // Modify the static variable within the struct.
       was_called = true;
     }

     fn assets_selection(_: u32) void {}
   };

   // Connect our mock callback. This is the "real" callback for this test.
   connectOnAssetUpdateCallback(MockCallback.assets_update);
   connectOnAssetSelectionCallback(MockCallback.assets_selection);

   // Call the function we are testing
-  const initial_assets = [_]images.Serialized{.{
-      .points = [_]types.PointUV{
-          types.PointUV{ .x = 0.0, .y = 0.0, .u = 0.0, .v = 0.0 },
-          types.PointUV{ .x = 1.0, .y = 0.0, .u = 1.0, .v = 0.0 },
-          types.PointUV{ .x = 1.0, .y = 1.0, .u = 1.0, .v = 1.0 },
-          types.PointUV{ .x = 0.0, .y = 1.0, .u = 0.0, .v = 1.0 },
-      },
-      .texture_id = 1,
-      .id = 123,
-  }};
-  resetAssets(&initial_assets, false);
+  const initial_assets = [_]AssetSerialized{ .{
+      .img = .{
+          .points = [_]types.PointUV{
+              .{ .x = 0.0, .y = 0.0, .u = 0.0, .v = 0.0 },
+              .{ .x = 1.0, .y = 0.0, .u = 1.0, .v = 0.0 },
+              .{ .x = 1.0, .y = 1.0, .u = 1.0, .v = 1.0 },
+              .{ .x = 0.0, .y = 1.0, .u = 0.0, .v = 1.0 },
+          },
+          .texture_id = 1,
+          .id = 123,
+      },
+  }};
+  resetAssets(&initial_assets, false);

   // for the duration of resetAssets, the update callback should NOT be called
   try std.testing.expect(!MockCallback.was_called);
 }

If you’d like, I can open a follow-up PR to update any other tests and callsites similarly.

🧹 Nitpick comments (9)
src/logic/utils.zig (1)

18-21: Consider tolerance parameter or relative tolerance to avoid false negatives

Using floatEps(f32) as an absolute threshold is often too tight for world-space values far from 1.0. Optional: add a variant that accepts tolerance, or compute a mixed tolerance.

Option A (drop-in tweak):

-const EPSILON = math.floatEps(f32);
+const EPSILON = math.floatEps(f32); // base epsilon

 pub fn equalF32(a: f32, b: f32) bool {
-    return @abs(a - b) < EPSILON;
+    const scale = @max(@abs(a), @abs(b));
+    const tol = @max(EPSILON * scale, 1e-6); // floor tolerance at 1e-6 world units
+    return @abs(a - b) <= tol;
 }

Option B (non-breaking API addition elsewhere in this file):

pub fn equalF32Tol(a: f32, b: f32, tol: f32) bool {
    return @abs(a - b) <= tol;
}
src/logic/shapes/paths.zig (1)

115-124: Correct fix: corner radius scales with render_scale now

Passing size / 2.0 makes the vertex marker consistently round at all zooms. This aligns with the control-point sizing and removes the non-scaled constant.

Minor: size is computed twice (Lines 104 and 115). You can compute once above the branch for clarity.

Example outside this hunk:

const size = SKELETON_POINT_SIZE * shared.render_scale;
if (is_control_point) { ... } else { ... }
src/WebGPU/programs/computeShape/shader.wgsl (1)

26-26: Semantics: negative distance_scale flips inside/outside; clamp or document

If callers pass a negative value, the sign of signed_distance is inverted in the texture. Either document that distance_scale must be > 0, or clamp/abs it here.

Option (shader-side guard):

-    shape_info.signed_distance * u.distance_scale,
+    shape_info.signed_distance * abs(u.distance_scale),

Alternatively, validate on the host and default to 1.0 when unset.

src/index.ts (1)

88-93: Use a safe fallback for device.limits.maxBufferSize in Logic.initState

Passing an undefined maxBufferSize into the Zig sizing logic will yield NaN. It’s safest to prefer the explicit maxBufferSize when available, and otherwise fall back to maxStorageBufferBindingSize.

Locations to update:

  • src/index.ts, around lines 88–93 (the Logic.initState call)
  • Insert the fallback locals immediately after obtaining device (just before the call to Logic.initState)

Suggested diff in src/index.ts:

--- a/src/index.ts
+++ b/src/index.ts
@@ -87,6 +87,10 @@ async function main() {
   const device = await getDevice()
+  // Texture and buffer size limits (fallbacks for runtimes that omit maxBufferSize)
+  const maxTextureSize = device.limits.maxTextureDimension2D
+  const maxBufferSize =
+    (device.limits as any).maxBufferSize ?? device.limits.maxStorageBufferBindingSize

   Logic.initState(
-    projectWidth,
-    projectHeight,
-    device.limits.maxTextureDimension2D,
-    device.limits.maxBufferSize
+    projectWidth,
+    projectHeight,
+    maxTextureSize,
+    maxBufferSize
   )
src/WebGPU/programs/initPrograms.ts (1)

61-64: Clear the per-frame buffer trash list to prevent unbounded growth

cleanup() destroys buffers but does not clear buffersToDestroy, causing repeated iteration over already-destroyed entries and steady growth if cleanup is called per frame.

   return function cleanup() {
-    buffersToDestroy.forEach((buffer) => buffer.destroy())
+    buffersToDestroy.forEach((buffer) => buffer.destroy())
+    // Reset the list to avoid re-destroying and unbounded growth across frames.
+    buffersToDestroy.length = 0
   }
src/WebGPU/programs/computeShape/getProgram.ts (1)

17-21: Nit: rename the returned function for consistency

The returned function is still named computeSDF. Rename to computeShape to match file/module naming and reduce confusion.

-  return function computeSDF(
+  return function computeShape(
     passEncoder: GPUComputePassEncoder,
     curvesDataView: DataView,
     distanceScaleFactor: number,
     texture: GPUTexture
   ) {
src/logic/index.d.ts (1)

63-69: Ensure TS definitions and call sites align with latest Zig API changes

  • initState signature now includes max_buffer_size (4th parameter) — verified call site in src/index.ts:88 uses five arguments matching the updated signature.
  • compute_shape signature should include a new distance_scale parameter before texture_id — please confirm the definition in src/logic/index.d.ts (lines ~95–101) and update any TypeScript call sites (none were found via grep).
  • start_cache callback signature has been standardized to texture_id as the first parameter — verify the definition in src/logic/index.d.ts (lines ~116–119) and ensure any JS/TS callback implementations match.

Nit: In TS ambient types, consider using camelCase (distanceScale) for the new parameter to stay idiomatic, provided it doesn’t diverge from the Zig ABI/contracts.

src/run.ts (1)

59-63: Threaded distanceScaleFactor looks correct; add basic guards for width/height.
The argument order matches the Zig side (points, w, h, distance_scale, texture). Consider fast‑failing on zero dimensions to avoid creating 0×0 textures or dispatching empty workgroups.

Apply this minimal guard:

-    compute_shape: (curves_data, width, height, distanceScaleFactor, textureId) => {
+    compute_shape: (curves_data, width, height, distanceScaleFactor, textureId) => {
       const curvesDataView = curves_data['*'].dataView
-      Textures.updateSDF(textureId, width, height)
-      computeShape(computePass, curvesDataView, distanceScaleFactor, Textures.getTexture(textureId))
+      if (width === 0 || height === 0) return
+      Textures.updateSDF(textureId, width, height)
+      computeShape(
+        computePass,
+        curvesDataView,
+        distanceScaleFactor,
+        Textures.getTexture(textureId)
+      )
     },
src/logic/shapes/shapes.zig (1)

209-219: onReleasePointer clears active_path_index when closed — OK; consider clearing preview_point.
Stale preview_point may persist visually after release. Optional QoL: reset preview_point here.

 pub fn onReleasePointer(self: Shape) void {
   if (active_path_index) |i| {
     const active_path = self.paths.items[i];
     if (active_path.closed) {
       active_path_index = null;
     }
   }

   is_handle_preview = false;
+  // Optional: avoid stale preview dot after release
+  // (safe no-op when editor will call update_preview_point(null) on commit)
+  // self.preview_point = null;
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 36d4467 and 9407da9.

📒 Files selected for processing (13)
  • src/WebGPU/programs/computeShape/getProgram.ts (1 hunks)
  • src/WebGPU/programs/computeShape/shader.wgsl (2 hunks)
  • src/WebGPU/programs/initPrograms.ts (3 hunks)
  • src/index.ts (1 hunks)
  • src/logic/get_sdf_texture_size.zig (1 hunks)
  • src/logic/index.d.ts (3 hunks)
  • src/logic/index.zig (7 hunks)
  • src/logic/shapes/paths.zig (1 hunks)
  • src/logic/shapes/shapes.zig (14 hunks)
  • src/logic/shared.zig (1 hunks)
  • src/logic/types.zig (1 hunks)
  • src/logic/utils.zig (1 hunks)
  • src/run.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
src/logic/types.zig (1)
src/textures.ts (3)
  • TextureSource (23-28)
  • add (30-79)
  • img (49-76)
src/logic/get_sdf_texture_size.zig (2)
src/utils/getDefaultPoints.ts (2)
  • getDefaultTextureScale (26-42)
  • getDefaultPoints (3-21)
src/textures.ts (2)
  • updateSDF (115-126)
  • createSDF (101-113)
src/WebGPU/programs/computeShape/getProgram.ts (2)
src/WebGPU/programs/computeSDF/getProgram.ts (2)
  • getComputeSDF (3-43)
  • drawShape (17-42)
src/WebGPU/programs/drawShape/getProgram.ts (2)
  • getDrawShape (3-98)
  • drawShape (60-97)
src/WebGPU/programs/initPrograms.ts (2)
src/WebGPU/programs/computeShape/getProgram.ts (1)
  • getComputeShape (3-53)
src/WebGPU/programs/computeSDF/getProgram.ts (2)
  • drawShape (17-42)
  • getComputeSDF (3-43)
src/WebGPU/programs/computeShape/shader.wgsl (1)
src/WebGPU/programs/computeSDF/getProgram.ts (2)
  • drawShape (17-42)
  • getComputeSDF (3-43)
src/logic/index.d.ts (2)
src/WebGPU/textureCache.ts (1)
  • startCache (15-85)
src/WebGPU/programs/computeSDF/getProgram.ts (1)
  • drawShape (17-42)
src/run.ts (2)
src/WebGPU/programs/initPrograms.ts (1)
  • computeShape (27-27)
src/WebGPU/programs/computeSDF/getProgram.ts (2)
  • drawShape (17-42)
  • getComputeSDF (3-43)
src/logic/index.zig (3)
src/WebGPU/programs/pickShape/getProgram.ts (2)
  • pickShape (45-82)
  • getDrawShape (3-83)
src/WebGPU/programs/drawShape/getProgram.ts (2)
  • drawShape (60-97)
  • getDrawShape (3-98)
src/WebGPU/programs/computeSDF/getProgram.ts (2)
  • drawShape (17-42)
  • getComputeSDF (3-43)
🔇 Additional comments (26)
src/logic/utils.zig (1)

18-21: No remaining cmpF32 references—rename verified

Searches for cmpF32 across the repository returned no matches, confirming all call sites have been updated to equalF32.

src/WebGPU/programs/computeShape/shader.wgsl (2)

17-17: Bind group entries are consistent
The WGSL shader (@group(0) @binding(2) var<uniform> u: Uniforms;) expects bindings in the order 0: texture, 1: curves, 2: uniforms. In src/WebGPU/programs/computeShape/getProgram.ts (lines 44–48), the host code creates the bind group with:

  • binding 0 → texture.createView()
  • binding 1 → { buffer: curvesBuffer }
  • binding 2 → { buffer: uniformBuffer }

This matches the shader’s binding indices exactly. No changes are needed.


11-14: Uniform buffer layout matches host-side usage—no changes required

The WGSL Uniforms struct is 4 bytes (one f32), and in getComputeShape you create the GPUBuffer with size: 4, so the shader layout and host-side buffer size align perfectly. Per the WGSL spec, a single f32 struct has 4 byte size and 4 byte alignment, so no implicit padding is needed. If you do encounter platform-specific junk or zero values in distance_scale, you can revisit padding then, but for now the current setup is correct and consistent.

src/logic/shapes/shapes.zig (14)

4-4: New TextureSize import — OK.
Used for sdf_size; keeps type coupling explicit.


18-20: Clarifying comment about non‑struct state — OK.
Localizing “active” state outside Shape struct is an acceptable tradeoff here.


42-45: Skeleton uniform uses constant stroke width 2.0.
Intentional for editor overlay; just confirm it’s independent from render_scale by design.

Would you like this to scale with render_scale for high‑DPI consistency?


64-68: Per‑shape preview_point and sdf_size fields — good additions.

  • preview_point scoped to the shape eliminates global coupling.
  • sdf_size caches the last texture size for smarter invalidation.

89-96: Shape.new: Initialize outdated_sdf = true — correct.
Ensures first SDF is computed without relying on external triggers.


108-114: Initial bounds offset by first absolute point.
This establishes local coordinates early. One caveat: until update_bounds runs, DEFAULT_BOUNDS may overestimate the SDF region.

Confirm DEFAULT_BOUNDS is reasonably small to avoid oversized initial textures when only a point/segment exists.


128-134: Start new path vs. extend active path — OK.
Snap threshold is computed from current bounds; matches earlier logic.


137-144: updatePointPreview signature shift (Point instead of x,y) — good.
Cleaner callsites and less param churn; also marks outdated_sdf only when needed.


146-161: update_preview_point avoids redundant invalidation — good.
Comparison via Utils.equalF32 on x/y keeps noise down. Nice use of inf sentinel.


197-207: updateLastHandle — OK.
Converts to local path space correctly and marks outdated_sdf.


232-236: Preview point skeleton rendering — OK.
Appends only when not handling; keeps overlay clean.


271-275: Uniform scaling: stroke_width divided by render_scale — good.
Matches how bounds and SDF are scaled elsewhere.


310-327: getBoundsWithPadding(scale) — OK.
Padding is applied in world units, then scaled; that’s consistent with render_scale handling elsewhere.


333-334: getDrawBounds delegates to getBoundsWithPadding(1) — OK.
Keeps a single source of truth for padding logic.

src/logic/index.zig (9)

2-4: Import updates — OK.
New modules (types, images, Msdf, shared, Utils, get_sdf_texture_size) are consistent with the refactor.

Also applies to: 6-6, 8-8, 12-15


135-141: Smart SDF invalidation on render_scale changes — good.
Only marks outdated when texture size would grow; avoids churn.


327-330: onPointerUp: release shape pointers only when drawing — good.
Prevents unintended state resets in other tools.


336-337: onPointerMove: pass Point object to shape.updatePointPreview — good.
Matches new API; no issues.


393-394: commitChanges uses update_preview_point(null) — good.
Explicitly clears preview state on commit; pairs with shapes.resetState().


526-529: calculateShapesSDF: short‑circuit when !outdated_sdf — good.
Prevents unnecessary compute submissions.


531-541: SDF size/scale computation pipeline — looks correct.

  • bounds = getBoundsWithPadding(1 / render_scale)
  • init_width from bounds
  • sdf_size via get_sdf_texture_size
  • points scaled to texture size
  • distance_scale = 1/scale
    This is coherent with run.ts and WGSL uniform.

590-592: Editor overlay draw path updated — OK.
Uses new getSkeletonDrawVertexData API; no issues.


19-25: compute_shape signature verified across Zig and TypeScript
All callsites consistently use the five-parameter signature—no stragglers found.
• src/logic/index.zig
– Declaration (lines 19–25) and call (around line 541) both pass 5 arguments
• src/run.ts (lines 59–61)
• src/logic/index.d.ts (lines 95–100)
No further action required.

@mateuszJS mateuszJS merged commit f5b1529 into next Aug 26, 2025
6 checks passed
@github-actions
Copy link

github-actions bot commented Oct 6, 2025

🎉 This PR is included in version 0.1.0-next.22 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants