@womp/mesh-editor 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,6 +23,10 @@ await open_edit_session({
23
23
  });
24
24
  ```
25
25
 
26
+ Return `false` from `on_commit` when the host cancels its import dialog. The session
27
+ stays open with its edits and undo history. Rejected promises display an error
28
+ and also keep the session open for retry.
29
+
26
30
  `root_class` scopes the semantic `--womp-mesh-editor-*` theme tokens documented
27
31
  in `docs/ui-theming.md`. Omit it to retain the default appearance.
28
32
 
@@ -65,7 +65,7 @@ interface OrbitState {
65
65
  pointerId: number | null;
66
66
  lastX: number;
67
67
  lastY: number;
68
- mode: "orbit" | "pan";
68
+ mode: "orbit" | "pan" | "zoom";
69
69
  }
70
70
  interface DragState {
71
71
  pointerId: number;
@@ -587,6 +587,7 @@ export declare class PortableMeshEditor {
587
587
  update_brush_stroke_surface_hit(hit: any): void;
588
588
  apply_brush_hit(hit: any, pathRatio?: number): void;
589
589
  handle_wheel(event: WheelEvent): void;
590
+ zoom_camera(factor: number): void;
590
591
  pan_camera(dx: number, dy: number): void;
591
592
  pick_mesh(event: PointerEvent): any;
592
593
  pick_mesh_at(clientX: number, clientY: number): any;
@@ -6404,7 +6404,7 @@ export class PortableMeshEditor {
6404
6404
  event.preventDefault();
6405
6405
  return;
6406
6406
  }
6407
- if (event.button === 2) {
6407
+ if (event.button === 2 || event.button === 1 || event.altKey || event.metaKey) {
6408
6408
  event.preventDefault();
6409
6409
  this.canvas.setPointerCapture(event.pointerId);
6410
6410
  this.hide_brush_cursor();
@@ -6412,18 +6412,7 @@ export class PortableMeshEditor {
6412
6412
  this.orbit.pointerId = event.pointerId;
6413
6413
  this.orbit.lastX = event.clientX;
6414
6414
  this.orbit.lastY = event.clientY;
6415
- this.orbit.mode = "pan";
6416
- return;
6417
- }
6418
- if (event.button === 1 || event.altKey || event.metaKey) {
6419
- event.preventDefault();
6420
- this.canvas.setPointerCapture(event.pointerId);
6421
- this.hide_brush_cursor();
6422
- this.orbit.active = true;
6423
- this.orbit.pointerId = event.pointerId;
6424
- this.orbit.lastX = event.clientX;
6425
- this.orbit.lastY = event.clientY;
6426
- this.orbit.mode = "orbit";
6415
+ this.orbit.mode = event.button === 2 ? "pan" : event.button === 1 ? "zoom" : "orbit";
6427
6416
  return;
6428
6417
  }
6429
6418
  if (event.button !== 0) {
@@ -6435,7 +6424,12 @@ export class PortableMeshEditor {
6435
6424
  if (this.meshObject === null) {
6436
6425
  return;
6437
6426
  }
6438
- if (this.tool === "view") {
6427
+ const hit = this.tool === "view" ? null : this.pick_mesh(event);
6428
+ const vertexPick = this.tool === "drag" ? this.pick_vertex(event, hit) : null;
6429
+ if (this.tool === "view" || (hit === null && vertexPick === null)) {
6430
+ if (hit === null && this.tool !== "view") {
6431
+ this.clear_selection();
6432
+ }
6439
6433
  this.hide_brush_cursor();
6440
6434
  this.orbit.active = true;
6441
6435
  this.orbit.pointerId = event.pointerId;
@@ -6444,9 +6438,7 @@ export class PortableMeshEditor {
6444
6438
  this.orbit.mode = "orbit";
6445
6439
  return;
6446
6440
  }
6447
- const hit = this.pick_mesh(event);
6448
6441
  if (this.tool === "drag") {
6449
- const vertexPick = this.pick_vertex(event, hit);
6450
6442
  if (vertexPick === null) {
6451
6443
  this.clear_selection();
6452
6444
  this.set_status("No vertex selected.");
@@ -6469,12 +6461,6 @@ export class PortableMeshEditor {
6469
6461
  this.set_status(`Dragging vertex ${vertexIndex}`);
6470
6462
  return;
6471
6463
  }
6472
- if (hit === null) {
6473
- this.hide_brush_cursor();
6474
- this.clear_selection();
6475
- this.release_pointer_capture(event.pointerId);
6476
- return;
6477
- }
6478
6464
  this.show_brush_cursor([hit.point.x, hit.point.y, hit.point.z], [hit.face.normal.x, hit.face.normal.y, hit.face.normal.z]);
6479
6465
  this.brushStrokeState = {
6480
6466
  pointerId: event.pointerId,
@@ -6513,6 +6499,10 @@ export class PortableMeshEditor {
6513
6499
  this.pan_camera(dx, dy);
6514
6500
  return;
6515
6501
  }
6502
+ if (this.orbit.mode === "zoom") {
6503
+ this.zoom_camera(Math.exp(dy * 0.01));
6504
+ return;
6505
+ }
6516
6506
  this.orbit.theta -= dx * 0.01;
6517
6507
  this.orbit.phi = Math.min(Math.PI - 0.02, Math.max(0.02, this.orbit.phi - (dy * 0.01)));
6518
6508
  this.apply_orbit_camera();
@@ -7174,7 +7164,9 @@ export class PortableMeshEditor {
7174
7164
  handle_wheel(event) {
7175
7165
  event.preventDefault();
7176
7166
  this.hide_brush_cursor();
7177
- const factor = Math.exp(event.deltaY * 0.001);
7167
+ this.zoom_camera(Math.exp(event.deltaY * 0.001));
7168
+ }
7169
+ zoom_camera(factor) {
7178
7170
  const referenceRadius = Math.max(this.sessionBoundsRadius, Number.MIN_VALUE);
7179
7171
  this.orbit.radius = Math.min(referenceRadius * 1000, Math.max(referenceRadius * 0.02, this.orbit.radius * factor));
7180
7172
  this.apply_orbit_camera();
@@ -10,7 +10,7 @@ export interface OpenEditSessionOptions {
10
10
  symmetry_enabled?: boolean;
11
11
  symmetry_vertical?: boolean;
12
12
  symmetry_horizontal?: boolean;
13
- on_commit?: (result: EditSessionCommitResult) => void | Promise<void>;
13
+ on_commit?: (result: EditSessionCommitResult) => void | boolean | Promise<void | boolean>;
14
14
  }
15
15
  export type EditSessionCommitResult = {
16
16
  action: "commit";
@@ -765,7 +765,7 @@ export async function open_edit_session(options) {
765
765
  viewport.className = "womp-mesh-editor-viewport";
766
766
  const canvas = document.createElement("canvas");
767
767
  canvas.className = "womp-mesh-editor-canvas";
768
- canvas.title = "Mesh editor viewport. Primary drag in View orbits; secondary drag pans; Alt-drag or middle mouse orbits; brush tools edit on drag.";
768
+ canvas.title = "Mesh editor viewport. Left drag on empty space rotates; right drag pans; middle drag zooms; left drag on the mesh sculpts. Alt-drag or View also rotates.";
769
769
  canvas.setAttribute("aria-label", "Mesh editor viewport");
770
770
  viewport.appendChild(canvas);
771
771
  const header = document.createElement("div");
@@ -1111,7 +1111,7 @@ export async function open_edit_session(options) {
1111
1111
  const cancelButton = button("Cancel", "Close the mesh editor without applying changes.", "womp-mesh-editor-button is-secondary");
1112
1112
  const footerHint = document.createElement("div");
1113
1113
  footerHint.className = "womp-mesh-editor-footer-hint";
1114
- footerHint.textContent = "Orbit: Alt or middle drag · Pan: right drag · Zoom: wheel";
1114
+ footerHint.textContent = "Rotate: left drag on empty space · Pan: right drag · Zoom: middle drag or wheel";
1115
1115
  const footerActions = document.createElement("div");
1116
1116
  footerActions.className = "womp-mesh-editor-footer-actions";
1117
1117
  footerActions.appendChild(cancelButton);
@@ -1440,7 +1440,13 @@ export async function open_edit_session(options) {
1440
1440
  mode: "edit",
1441
1441
  mesh: await editor.prepare_commit_async(),
1442
1442
  };
1443
- await options.on_commit?.(result);
1443
+ const accepted = await options.on_commit?.(result);
1444
+ if (accepted === false) {
1445
+ set_status("Mesh editing", "Mesh tools are ready.", "idle");
1446
+ set_busy(false);
1447
+ commitButton.focus();
1448
+ return;
1449
+ }
1444
1450
  editor.accept_commit();
1445
1451
  close(result);
1446
1452
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@womp/mesh-editor",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Browser mesh editing engine and edit-session UI for Womp products.",
5
5
  "private": false,
6
6
  "type": "module",