meshlite 0.2.0__tar.gz

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.
Files changed (109) hide show
  1. meshlite-0.2.0/.gitignore +32 -0
  2. meshlite-0.2.0/CHANGELOG.md +70 -0
  3. meshlite-0.2.0/CONTRIBUTING.md +81 -0
  4. meshlite-0.2.0/LICENSE +33 -0
  5. meshlite-0.2.0/PKG-INFO +173 -0
  6. meshlite-0.2.0/README.md +135 -0
  7. meshlite-0.2.0/assets/fonts/codicon.ttf +0 -0
  8. meshlite-0.2.0/assets/shaders/mesh.frag +43 -0
  9. meshlite-0.2.0/assets/shaders/mesh.vert +18 -0
  10. meshlite-0.2.0/main.py +27 -0
  11. meshlite-0.2.0/pyproject.toml +92 -0
  12. meshlite-0.2.0/src/meshlite/__init__.py +3 -0
  13. meshlite-0.2.0/src/meshlite/app.py +123 -0
  14. meshlite-0.2.0/src/meshlite/app_state/__init__.py +58 -0
  15. meshlite-0.2.0/src/meshlite/app_state/command_bus.py +285 -0
  16. meshlite-0.2.0/src/meshlite/app_state/document.py +114 -0
  17. meshlite-0.2.0/src/meshlite/app_state/events.py +137 -0
  18. meshlite-0.2.0/src/meshlite/app_state/history.py +161 -0
  19. meshlite-0.2.0/src/meshlite/app_state/node.py +58 -0
  20. meshlite-0.2.0/src/meshlite/app_state/preferences.py +127 -0
  21. meshlite-0.2.0/src/meshlite/app_state/selection_model.py +93 -0
  22. meshlite-0.2.0/src/meshlite/app_state/task_runner.py +164 -0
  23. meshlite-0.2.0/src/meshlite/app_state/transform.py +43 -0
  24. meshlite-0.2.0/src/meshlite/config/__init__.py +0 -0
  25. meshlite-0.2.0/src/meshlite/domain/__init__.py +24 -0
  26. meshlite-0.2.0/src/meshlite/domain/mesh_data.py +88 -0
  27. meshlite-0.2.0/src/meshlite/domain/mesh_info.py +81 -0
  28. meshlite-0.2.0/src/meshlite/domain/mesh_io.py +92 -0
  29. meshlite-0.2.0/src/meshlite/domain/mrm_shim.py +214 -0
  30. meshlite-0.2.0/src/meshlite/ops/__init__.py +44 -0
  31. meshlite-0.2.0/src/meshlite/ops/_dev/__init__.py +0 -0
  32. meshlite-0.2.0/src/meshlite/ops/_dev/counter_op.py +64 -0
  33. meshlite-0.2.0/src/meshlite/ops/_manifest.py +25 -0
  34. meshlite-0.2.0/src/meshlite/ops/base.py +269 -0
  35. meshlite-0.2.0/src/meshlite/ops/boolean/__init__.py +0 -0
  36. meshlite-0.2.0/src/meshlite/ops/boolean/boolean_op.py +138 -0
  37. meshlite-0.2.0/src/meshlite/ops/inspect/__init__.py +0 -0
  38. meshlite-0.2.0/src/meshlite/ops/inspect/find_self_intersections.py +109 -0
  39. meshlite-0.2.0/src/meshlite/ops/io/__init__.py +0 -0
  40. meshlite-0.2.0/src/meshlite/ops/io/load_mesh.py +97 -0
  41. meshlite-0.2.0/src/meshlite/ops/io/save_mesh.py +83 -0
  42. meshlite-0.2.0/src/meshlite/ops/registry.py +230 -0
  43. meshlite-0.2.0/src/meshlite/ops/repair/__init__.py +0 -0
  44. meshlite-0.2.0/src/meshlite/ops/repair/auto_repair.py +188 -0
  45. meshlite-0.2.0/src/meshlite/ops/repair/fill_holes.py +135 -0
  46. meshlite-0.2.0/src/meshlite/ops/repair/remove_duplicates.py +84 -0
  47. meshlite-0.2.0/src/meshlite/ops/simplify/__init__.py +0 -0
  48. meshlite-0.2.0/src/meshlite/ops/simplify/decimate.py +189 -0
  49. meshlite-0.2.0/src/meshlite/ops/simplify/remesh.py +121 -0
  50. meshlite-0.2.0/src/meshlite/ops/simplify/subdivide.py +130 -0
  51. meshlite-0.2.0/src/meshlite/ops/smooth/__init__.py +0 -0
  52. meshlite-0.2.0/src/meshlite/ops/smooth/laplacian.py +83 -0
  53. meshlite-0.2.0/src/meshlite/ops/transform/__init__.py +0 -0
  54. meshlite-0.2.0/src/meshlite/ops/transform/mirror.py +91 -0
  55. meshlite-0.2.0/src/meshlite/ops/transform/rotate.py +114 -0
  56. meshlite-0.2.0/src/meshlite/ops/transform/scale.py +106 -0
  57. meshlite-0.2.0/src/meshlite/ops/transform/translate.py +52 -0
  58. meshlite-0.2.0/src/meshlite/render/__init__.py +21 -0
  59. meshlite-0.2.0/src/meshlite/render/axes.py +71 -0
  60. meshlite-0.2.0/src/meshlite/render/camera.py +186 -0
  61. meshlite-0.2.0/src/meshlite/render/gpu_mesh.py +88 -0
  62. meshlite-0.2.0/src/meshlite/render/gpu_upload.py +65 -0
  63. meshlite-0.2.0/src/meshlite/render/renderer.py +202 -0
  64. meshlite-0.2.0/src/meshlite/render/shader_loader.py +83 -0
  65. meshlite-0.2.0/src/meshlite/ui/__init__.py +0 -0
  66. meshlite-0.2.0/src/meshlite/ui/fonts.py +63 -0
  67. meshlite-0.2.0/src/meshlite/ui/icons.py +209 -0
  68. meshlite-0.2.0/src/meshlite/ui/panels/__init__.py +0 -0
  69. meshlite-0.2.0/src/meshlite/ui/panels/activity_bar.py +76 -0
  70. meshlite-0.2.0/src/meshlite/ui/panels/base_panel.py +93 -0
  71. meshlite-0.2.0/src/meshlite/ui/panels/bottom/__init__.py +0 -0
  72. meshlite-0.2.0/src/meshlite/ui/panels/bottom/console.py +20 -0
  73. meshlite-0.2.0/src/meshlite/ui/panels/bottom/mesh_info.py +106 -0
  74. meshlite-0.2.0/src/meshlite/ui/panels/properties.py +216 -0
  75. meshlite-0.2.0/src/meshlite/ui/panels/sidebar.py +66 -0
  76. meshlite-0.2.0/src/meshlite/ui/panels/sidebar_operations.py +62 -0
  77. meshlite-0.2.0/src/meshlite/ui/panels/sidebar_outliner.py +94 -0
  78. meshlite-0.2.0/src/meshlite/ui/panels/sidebar_search.py +96 -0
  79. meshlite-0.2.0/src/meshlite/ui/panels/sidebar_settings.py +149 -0
  80. meshlite-0.2.0/src/meshlite/ui/panels/status_bar.py +71 -0
  81. meshlite-0.2.0/src/meshlite/ui/panels/top_toolbar.py +335 -0
  82. meshlite-0.2.0/src/meshlite/ui/panels/viewport.py +156 -0
  83. meshlite-0.2.0/src/meshlite/ui/runner.py +704 -0
  84. meshlite-0.2.0/src/meshlite/ui/theme.py +180 -0
  85. meshlite-0.2.0/src/meshlite/ui/widgets/__init__.py +0 -0
  86. meshlite-0.2.0/src/meshlite/ui/widgets/command_palette.py +268 -0
  87. meshlite-0.2.0/src/meshlite/ui/widgets/info_cache.py +38 -0
  88. meshlite-0.2.0/src/meshlite/ui/widgets/param_widgets.py +144 -0
  89. meshlite-0.2.0/src/meshlite/utils/__init__.py +0 -0
  90. meshlite-0.2.0/src/meshlite/utils/async_task.py +240 -0
  91. meshlite-0.2.0/src/meshlite/utils/file_dialog.py +79 -0
  92. meshlite-0.2.0/src/meshlite/utils/fuzzy.py +108 -0
  93. meshlite-0.2.0/src/meshlite/utils/paths.py +36 -0
  94. meshlite-0.2.0/tests/__init__.py +0 -0
  95. meshlite-0.2.0/tests/conftest.py +29 -0
  96. meshlite-0.2.0/tests/fixtures/cube.stl +0 -0
  97. meshlite-0.2.0/tests/fixtures/open_cylinder.stl +0 -0
  98. meshlite-0.2.0/tests/test_architecture.py +85 -0
  99. meshlite-0.2.0/tests/test_command_bus.py +230 -0
  100. meshlite-0.2.0/tests/test_fill_holes.py +194 -0
  101. meshlite-0.2.0/tests/test_load_save_ops.py +200 -0
  102. meshlite-0.2.0/tests/test_mesh_info.py +98 -0
  103. meshlite-0.2.0/tests/test_mesh_io.py +151 -0
  104. meshlite-0.2.0/tests/test_ops_repair.py +101 -0
  105. meshlite-0.2.0/tests/test_ops_simplify.py +92 -0
  106. meshlite-0.2.0/tests/test_ops_transform.py +102 -0
  107. meshlite-0.2.0/tests/test_preferences.py +82 -0
  108. meshlite-0.2.0/tests/test_registry.py +189 -0
  109. meshlite-0.2.0/tests/test_undo.py +265 -0
@@ -0,0 +1,32 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ .eggs/
7
+ build/
8
+ dist/
9
+ .pytest_cache/
10
+ .mypy_cache/
11
+ .ruff_cache/
12
+ .coverage
13
+ htmlcov/
14
+
15
+ # Virtual environments
16
+ .venv/
17
+ venv/
18
+ env/
19
+
20
+ # IDE
21
+ .vscode/
22
+ .idea/
23
+ *.swp
24
+ *.swo
25
+
26
+ # hello_imgui — runtime layout/window state, not source
27
+ *.ini
28
+ !assets/layouts/*.ini
29
+
30
+ # OS
31
+ .DS_Store
32
+ Thumbs.db
@@ -0,0 +1,70 @@
1
+ # Changelog
2
+
3
+ ## v0.2.0 (2026-04-12)
4
+
5
+ Production readiness release.
6
+
7
+ ### New Features
8
+
9
+ - **User preferences** — all settings (viewport sensitivity, colors, lighting, camera FOV, undo limits) are persisted between sessions via hello_imgui's user pref API
10
+ - **Settings panel** — live sliders and color pickers in the sidebar for viewport, rendering, camera, and history settings with "Reset to Defaults"
11
+ - **Search panel** — fuzzy search across document nodes and operations in the sidebar
12
+ - **Recent files** — tracked automatically on mesh load; accessible from File > Open Recent and the command palette
13
+ - **Drag-and-drop** — drop mesh files onto the window to load them (GLFW backend, Linux)
14
+ - **Cross-platform CI** — GitHub Actions matrix now covers Linux, Windows, and macOS with Python 3.11/3.12/3.13
15
+
16
+ ### Bug Fixes
17
+
18
+ - **active_task_count leak** — counter was never decremented after task completion
19
+ - **GPU upload retry spam** — failed uploads no longer retry every frame at 60fps flooding the log
20
+ - **Unnecessary mesh clone** — removed a redundant `.clone()` in CommandBus finalize, saving memory per undoable operation
21
+ - **Falsy zero check in Decimate** — setting max_deleted_vertices to 0 no longer silently defaults to unlimited
22
+ - **BasePanel error dedup** — distinct panel errors are now logged instead of silencing everything after the first
23
+ - **Auto repair partial failure** — result message now clearly says "PARTIAL" when self-intersection fix fails
24
+ - **Debug button in production** — removed the CounterOp debug button and `_dev` import from the viewport
25
+
26
+ ### Improvements
27
+
28
+ - Extracted `FLT_MAX` constant — replaced 5 duplicated 19-digit float literals across decimate/remesh/subdivide
29
+ - Named byte estimation constants in undo history with derivation comments
30
+ - Asset path resolver (`utils/paths.py`) — works in dev, pip-installed, and frozen bundle contexts
31
+ - Operation manifest (`ops/_manifest.py`) — explicit module list for frozen-bundle discovery
32
+ - Shader loader and font loader now use the centralized path resolver
33
+
34
+ ### Technical
35
+
36
+ - 85 automated tests (77 original + 8 new preferences tests)
37
+ - Cross-platform CI: ubuntu-latest, windows-latest, macos-latest
38
+ - `selected_color` field on `RenderItem` — selection color now driven by preferences
39
+
40
+ ## v0.1.0 (2026-04-12)
41
+
42
+ Initial public release.
43
+
44
+ ### Features
45
+
46
+ - **15 mesh operations** with full MeshLib parameter exposure:
47
+ - File: Open Mesh, Save Mesh As
48
+ - Repair: Fill Holes, Auto Repair, Remove Duplicates
49
+ - Inspect: Fix Self-Intersections (Local + Voxel-based)
50
+ - Mesh Edit: Decimate, Remesh, Subdivide, Laplacian Smooth
51
+ - Boolean: Union / Intersection / Difference (with node picker)
52
+ - Transform: Translate, Rotate, Scale, Mirror
53
+ - **VSCode-style UI** with activity bar, dockable panels, dark theme, codicons
54
+ - **MeshInspector-style top toolbar** with 26 tools across 7 groups
55
+ - **Command palette** (Ctrl+Shift+P) with fuzzy search
56
+ - **Snapshot-based undo/redo** (Ctrl+Z / Ctrl+Shift+Z)
57
+ - **Mesh Info panel** with comprehensive statistics
58
+ - **Properties panel** with auto-rendered parameter widgets
59
+ - **Outliner** with visibility toggles and right-click context menus
60
+ - **Status bar** with mesh count, selection, FPS
61
+ - **Async worker dispatch** — operations run on background threads
62
+ - **One-file operation pattern** — adding a new op requires zero edits elsewhere
63
+
64
+ ### Technical
65
+
66
+ - 5-layer architecture: domain / ops / render / app_state / ui
67
+ - MeshLib 3.1.1.211 backend
68
+ - imgui_bundle 1.92.601 UI
69
+ - moderngl 5.12.0 renderer
70
+ - Python 3.11+ required
@@ -0,0 +1,81 @@
1
+ # Contributing to meshlite
2
+
3
+ Thanks for your interest in contributing! meshlite is an open-source 3D mesh processing desktop app.
4
+
5
+ ## Development Setup
6
+
7
+ ```bash
8
+ git clone https://github.com/syedjameel/meshlite.git
9
+ cd meshlite
10
+ uv venv --python 3.13 .venv
11
+ source .venv/bin/activate
12
+ uv pip install -e ".[dev]"
13
+ ```
14
+
15
+ ## Running Tests
16
+
17
+ ```bash
18
+ PYTHONPATH= pytest
19
+ ```
20
+
21
+ > **Note:** If your shell exports `PYTHONPATH` (e.g. for ROS or FreeCAD), clear it before running pytest to avoid plugin conflicts.
22
+
23
+ ## Running the App
24
+
25
+ ```bash
26
+ python main.py
27
+ ```
28
+
29
+ ## Adding a New Operation
30
+
31
+ Adding an operation to meshlite is a **one-file change**. Here's the pattern:
32
+
33
+ 1. Create a file under `src/meshlite/ops/<category>/your_op.py`
34
+ 2. Subclass `Operation`, decorate with `@register_operation`
35
+ 3. Define `id`, `label`, `category`, `schema` (params), and `run()`
36
+ 4. That's it — the op auto-discovers and appears in the command palette, sidebar, properties panel, and toolbar
37
+
38
+ See `src/meshlite/ops/smooth/laplacian.py` for a clean example.
39
+
40
+ If you plan to build a standalone bundle (PyInstaller etc.), also add the module path to `src/meshlite/ops/_manifest.py` so it's discovered in frozen mode.
41
+
42
+ ## Architecture Rules
43
+
44
+ meshlite has 5 layers with strict dependency rules:
45
+
46
+ ```
47
+ ui ───> app_state ──> ops ──> domain
48
+ | | |
49
+ └─> render ─┘ └──> domain
50
+ ```
51
+
52
+ - **domain/** — pure MeshLib wrapper. Only place `meshlib.*` is imported (via `mrm_shim.py`)
53
+ - **ops/** — operations. May import `meshlib` directly for Settings struct construction
54
+ - **render/** — moderngl only. No meshlib, no ImGui
55
+ - **app_state/** — Document, CommandBus, events, preferences. No meshlib, no GL, no ImGui
56
+ - **ui/** — ImGui panels. Imports from `app_state` (not `domain` directly)
57
+
58
+ Run `pytest tests/test_architecture.py` to verify these rules.
59
+
60
+ ## User Preferences
61
+
62
+ User-configurable settings live in `app_state/preferences.py` (a plain dataclass with JSON serialization). To make a new value configurable:
63
+
64
+ 1. Add the field to `Preferences` with a sensible default
65
+ 2. Read from `self._app.preferences.<field>` in the consumer code
66
+ 3. Add a widget in `ui/panels/sidebar_settings.py` if it should be user-facing
67
+ 4. Preferences are auto-saved on exit and auto-loaded on startup
68
+
69
+ ## Code Style
70
+
71
+ - We use `ruff` for linting
72
+ - Type hints on all public functions
73
+ - Docstrings on all public classes and functions
74
+
75
+ ## Pull Request Process
76
+
77
+ 1. Fork + branch from `main`
78
+ 2. Make your changes
79
+ 3. Run `PYTHONPATH= pytest` — all tests must pass
80
+ 4. Run `ruff check src/ tests/` — no errors
81
+ 5. Open a PR with a clear description
meshlite-0.2.0/LICENSE ADDED
@@ -0,0 +1,33 @@
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+ Preamble
9
+
10
+ The GNU General Public License is a free, copyleft license for
11
+ software and other kinds of works.
12
+
13
+ The licenses for most software and other practical works are designed
14
+ to take away your freedom to share and change the works. By contrast,
15
+ the GNU General Public License is intended to guarantee your freedom to
16
+ share and change all versions of a program--to make sure it remains free
17
+ software for all its users. We, the Free Software Foundation, use the
18
+ GNU General Public License for most of our software; it applies also to
19
+ any other work released this way by its authors. You can apply it to
20
+ your programs, too.
21
+
22
+ For the complete license text, see <https://www.gnu.org/licenses/gpl-3.0.txt>
23
+
24
+ meshforge — Copyright (C) 2026 Syed Jameel
25
+ This program is free software: you can redistribute it and/or modify
26
+ it under the terms of the GNU General Public License as published by
27
+ the Free Software Foundation, either version 3 of the License, or
28
+ (at your option) any later version.
29
+
30
+ This program is distributed in the hope that it will be useful,
31
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
32
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33
+ GNU General Public License for more details.
@@ -0,0 +1,173 @@
1
+ Metadata-Version: 2.4
2
+ Name: meshlite
3
+ Version: 0.2.0
4
+ Summary: VSCode-style 3D mesh processing desktop app, powered by MeshLib + ImGui.
5
+ Project-URL: Homepage, https://github.com/syedjameel/meshlite
6
+ Project-URL: Repository, https://github.com/syedjameel/meshlite
7
+ Project-URL: Issues, https://github.com/syedjameel/meshlite/issues
8
+ Project-URL: Changelog, https://github.com/syedjameel/meshlite/blob/main/CHANGELOG.md
9
+ Author: Syed Jameel
10
+ License: GPL-3.0-or-later
11
+ License-File: LICENSE
12
+ Keywords: 3d,imgui,mesh,mesh-processing,meshlib,moderngl,obj,ply,stl,viewer
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: X11 Applications
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
18
+ Classifier: Operating System :: MacOS
19
+ Classifier: Operating System :: Microsoft :: Windows
20
+ Classifier: Operating System :: POSIX :: Linux
21
+ Classifier: Programming Language :: Python :: 3 :: Only
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
26
+ Classifier: Topic :: Scientific/Engineering :: Visualization
27
+ Requires-Python: >=3.11
28
+ Requires-Dist: imgui-bundle<2.0.0,>=1.6.3
29
+ Requires-Dist: meshlib>=3.0.0
30
+ Requires-Dist: moderngl<6.0.0,>=5.12.0
31
+ Requires-Dist: numpy<3.0.0,>=2.0.0
32
+ Requires-Dist: pyglm<3.0.0,>=2.8.2
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
35
+ Requires-Dist: pytest>=8.0; extra == 'dev'
36
+ Requires-Dist: ruff>=0.4.0; extra == 'dev'
37
+ Description-Content-Type: text/markdown
38
+
39
+ # meshlite
40
+
41
+ A desktop 3D mesh processing application with a VSCode-inspired interface, powered by [MeshLib](https://meshlib.io/), [moderngl](https://github.com/moderngl/moderngl), and [Dear ImGui](https://github.com/pthom/imgui_bundle).
42
+
43
+ ## Features
44
+
45
+ **15 mesh operations** with full parameter control:
46
+
47
+ | Category | Operations |
48
+ |---|---|
49
+ | **File** | Open (STL / OBJ / PLY / GLB / OFF / 3MF), Save As |
50
+ | **Repair** | Fill Holes, Auto Repair, Remove Duplicates |
51
+ | **Inspect** | Mesh Info, Find Self-Intersections (Local + Voxel) |
52
+ | **Mesh Edit** | Decimate, Remesh, Subdivide, Laplacian Smooth |
53
+ | **Boolean** | Union, Intersection, Difference |
54
+ | **Transform** | Translate, Rotate, Scale, Mirror |
55
+
56
+ **Professional UI:**
57
+
58
+ - MeshInspector-style top toolbar with grouped icon buttons
59
+ - Activity bar + collapsible sidebar (Outliner, Operations, Search, Settings)
60
+ - Properties panel with auto-rendered parameter widgets
61
+ - Command palette with fuzzy search (`Ctrl+Shift+P`)
62
+ - Mesh Info panel with topology, geometry, and bounding box statistics
63
+ - Snapshot-based undo/redo (`Ctrl+Z` / `Ctrl+Shift+Z`)
64
+ - VSCode "Dark+" theme with codicon glyphs
65
+ - Drag-and-drop file loading (GLFW backend)
66
+ - Recent files list (File menu + command palette)
67
+ - Persistent user preferences (viewport, rendering, camera, history)
68
+
69
+ **Architecture:**
70
+
71
+ - Adding a new operation is a **single-file change** — zero edits to UI, toolbar, or registry
72
+ - 5-layer separation: `domain` / `ops` / `render` / `app_state` / `ui`
73
+ - Async worker dispatch — operations run on background threads
74
+ - 85 automated tests with architecture rule enforcement
75
+ - Cross-platform CI (Linux, Windows, macOS)
76
+
77
+ ## Install
78
+
79
+ ### From PyPI
80
+
81
+ ```bash
82
+ pip install meshlite
83
+ meshlite
84
+ ```
85
+
86
+ ### From source
87
+
88
+ ```bash
89
+ git clone https://github.com/syedjameel/meshlite.git
90
+ cd meshlite
91
+ uv venv --python 3.13 .venv && source .venv/bin/activate
92
+ uv pip install -e ".[dev]"
93
+ python main.py
94
+ ```
95
+
96
+ ## Keyboard Shortcuts
97
+
98
+ | Shortcut | Action |
99
+ |---|---|
100
+ | `Ctrl+Shift+P` | Command palette |
101
+ | `Ctrl+O` | Open mesh |
102
+ | `Ctrl+S` | Save mesh as |
103
+ | `Ctrl+Z` | Undo |
104
+ | `Ctrl+Shift+Z` | Redo |
105
+ | `F` | Frame all (fit viewport) |
106
+ | Drag file onto window | Load mesh |
107
+
108
+ ## User Preferences
109
+
110
+ All settings are persisted automatically between sessions:
111
+
112
+ - **Viewport:** Rotate / zoom / pan sensitivity
113
+ - **Rendering:** Background color, mesh color, selected color, lighting (ambient, specular)
114
+ - **Camera:** Field of view
115
+ - **History:** Undo depth, memory cap
116
+
117
+ Access via the **Settings** panel in the sidebar (gear icon in the activity bar).
118
+
119
+ ## Adding a New Operation
120
+
121
+ meshlite's architecture makes it trivial to add operations. Create one file:
122
+
123
+ ```python
124
+ # src/meshlite/ops/smooth/laplacian.py
125
+
126
+ @register_operation
127
+ class LaplacianSmoothOperation(Operation):
128
+ id = "smooth.laplacian"
129
+ label = "Laplacian Smooth"
130
+ category = "Mesh Edit"
131
+ schema = ParamSchema((
132
+ Param("iterations", "int", "Iterations", default=3, min=1, max=100),
133
+ Param("force", "float", "Force", default=0.5, min=0.01, max=1.0),
134
+ ))
135
+
136
+ def run(self, mesh, params, ctx):
137
+ # ... meshlib calls ...
138
+ return OperationResult(mesh=mesh, message="Smoothed")
139
+ ```
140
+
141
+ The operation automatically appears in the command palette, sidebar, properties panel, and toolbar — with zero edits to any other file.
142
+
143
+ ## Architecture
144
+
145
+ ```
146
+ ui ───> app_state ──> ops ──> domain
147
+ | | |
148
+ └─> render ─┘ └──> domain
149
+ ```
150
+
151
+ | Layer | Responsibility | Dependencies |
152
+ |---|---|---|
153
+ | `domain/` | MeshLib wrapper (`mrm_shim.py`), mesh data, I/O | meshlib, numpy |
154
+ | `ops/` | Operations framework, registry, auto-discovery | domain |
155
+ | `render/` | moderngl renderer, GPU mesh, camera, shaders | domain (read-only) |
156
+ | `app_state/` | Document, CommandBus, undo, events, preferences | domain, ops |
157
+ | `ui/` | ImGui panels, theme, toolbar, command palette | all layers (except domain directly) |
158
+
159
+ ## Tech Stack
160
+
161
+ - **Python 3.11+**
162
+ - [MeshLib](https://meshlib.io/) — mesh processing engine (GPL-3)
163
+ - [imgui_bundle](https://github.com/pthom/imgui_bundle) — Dear ImGui + hello_imgui
164
+ - [moderngl](https://github.com/moderngl/moderngl) — OpenGL rendering
165
+ - [numpy](https://numpy.org/) + [PyGLM](https://github.com/Zuzu-Typ/PyGLM)
166
+
167
+ ## Contributing
168
+
169
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup, code style, and how to add operations.
170
+
171
+ ## License
172
+
173
+ [GPL-3.0-or-later](./LICENSE) — matches MeshLib's license.
@@ -0,0 +1,135 @@
1
+ # meshlite
2
+
3
+ A desktop 3D mesh processing application with a VSCode-inspired interface, powered by [MeshLib](https://meshlib.io/), [moderngl](https://github.com/moderngl/moderngl), and [Dear ImGui](https://github.com/pthom/imgui_bundle).
4
+
5
+ ## Features
6
+
7
+ **15 mesh operations** with full parameter control:
8
+
9
+ | Category | Operations |
10
+ |---|---|
11
+ | **File** | Open (STL / OBJ / PLY / GLB / OFF / 3MF), Save As |
12
+ | **Repair** | Fill Holes, Auto Repair, Remove Duplicates |
13
+ | **Inspect** | Mesh Info, Find Self-Intersections (Local + Voxel) |
14
+ | **Mesh Edit** | Decimate, Remesh, Subdivide, Laplacian Smooth |
15
+ | **Boolean** | Union, Intersection, Difference |
16
+ | **Transform** | Translate, Rotate, Scale, Mirror |
17
+
18
+ **Professional UI:**
19
+
20
+ - MeshInspector-style top toolbar with grouped icon buttons
21
+ - Activity bar + collapsible sidebar (Outliner, Operations, Search, Settings)
22
+ - Properties panel with auto-rendered parameter widgets
23
+ - Command palette with fuzzy search (`Ctrl+Shift+P`)
24
+ - Mesh Info panel with topology, geometry, and bounding box statistics
25
+ - Snapshot-based undo/redo (`Ctrl+Z` / `Ctrl+Shift+Z`)
26
+ - VSCode "Dark+" theme with codicon glyphs
27
+ - Drag-and-drop file loading (GLFW backend)
28
+ - Recent files list (File menu + command palette)
29
+ - Persistent user preferences (viewport, rendering, camera, history)
30
+
31
+ **Architecture:**
32
+
33
+ - Adding a new operation is a **single-file change** — zero edits to UI, toolbar, or registry
34
+ - 5-layer separation: `domain` / `ops` / `render` / `app_state` / `ui`
35
+ - Async worker dispatch — operations run on background threads
36
+ - 85 automated tests with architecture rule enforcement
37
+ - Cross-platform CI (Linux, Windows, macOS)
38
+
39
+ ## Install
40
+
41
+ ### From PyPI
42
+
43
+ ```bash
44
+ pip install meshlite
45
+ meshlite
46
+ ```
47
+
48
+ ### From source
49
+
50
+ ```bash
51
+ git clone https://github.com/syedjameel/meshlite.git
52
+ cd meshlite
53
+ uv venv --python 3.13 .venv && source .venv/bin/activate
54
+ uv pip install -e ".[dev]"
55
+ python main.py
56
+ ```
57
+
58
+ ## Keyboard Shortcuts
59
+
60
+ | Shortcut | Action |
61
+ |---|---|
62
+ | `Ctrl+Shift+P` | Command palette |
63
+ | `Ctrl+O` | Open mesh |
64
+ | `Ctrl+S` | Save mesh as |
65
+ | `Ctrl+Z` | Undo |
66
+ | `Ctrl+Shift+Z` | Redo |
67
+ | `F` | Frame all (fit viewport) |
68
+ | Drag file onto window | Load mesh |
69
+
70
+ ## User Preferences
71
+
72
+ All settings are persisted automatically between sessions:
73
+
74
+ - **Viewport:** Rotate / zoom / pan sensitivity
75
+ - **Rendering:** Background color, mesh color, selected color, lighting (ambient, specular)
76
+ - **Camera:** Field of view
77
+ - **History:** Undo depth, memory cap
78
+
79
+ Access via the **Settings** panel in the sidebar (gear icon in the activity bar).
80
+
81
+ ## Adding a New Operation
82
+
83
+ meshlite's architecture makes it trivial to add operations. Create one file:
84
+
85
+ ```python
86
+ # src/meshlite/ops/smooth/laplacian.py
87
+
88
+ @register_operation
89
+ class LaplacianSmoothOperation(Operation):
90
+ id = "smooth.laplacian"
91
+ label = "Laplacian Smooth"
92
+ category = "Mesh Edit"
93
+ schema = ParamSchema((
94
+ Param("iterations", "int", "Iterations", default=3, min=1, max=100),
95
+ Param("force", "float", "Force", default=0.5, min=0.01, max=1.0),
96
+ ))
97
+
98
+ def run(self, mesh, params, ctx):
99
+ # ... meshlib calls ...
100
+ return OperationResult(mesh=mesh, message="Smoothed")
101
+ ```
102
+
103
+ The operation automatically appears in the command palette, sidebar, properties panel, and toolbar — with zero edits to any other file.
104
+
105
+ ## Architecture
106
+
107
+ ```
108
+ ui ───> app_state ──> ops ──> domain
109
+ | | |
110
+ └─> render ─┘ └──> domain
111
+ ```
112
+
113
+ | Layer | Responsibility | Dependencies |
114
+ |---|---|---|
115
+ | `domain/` | MeshLib wrapper (`mrm_shim.py`), mesh data, I/O | meshlib, numpy |
116
+ | `ops/` | Operations framework, registry, auto-discovery | domain |
117
+ | `render/` | moderngl renderer, GPU mesh, camera, shaders | domain (read-only) |
118
+ | `app_state/` | Document, CommandBus, undo, events, preferences | domain, ops |
119
+ | `ui/` | ImGui panels, theme, toolbar, command palette | all layers (except domain directly) |
120
+
121
+ ## Tech Stack
122
+
123
+ - **Python 3.11+**
124
+ - [MeshLib](https://meshlib.io/) — mesh processing engine (GPL-3)
125
+ - [imgui_bundle](https://github.com/pthom/imgui_bundle) — Dear ImGui + hello_imgui
126
+ - [moderngl](https://github.com/moderngl/moderngl) — OpenGL rendering
127
+ - [numpy](https://numpy.org/) + [PyGLM](https://github.com/Zuzu-Typ/PyGLM)
128
+
129
+ ## Contributing
130
+
131
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup, code style, and how to add operations.
132
+
133
+ ## License
134
+
135
+ [GPL-3.0-or-later](./LICENSE) — matches MeshLib's license.
Binary file
@@ -0,0 +1,43 @@
1
+ #version 330
2
+
3
+ // Lighting model aligned with MeshInspector/MeshLib's approach:
4
+ // simple Phong (ambient + diffuse + specular) with configurable strengths.
5
+ // No fill light, no rim light — clean and predictable.
6
+
7
+ in vec3 v_normal;
8
+ in vec3 v_position;
9
+
10
+ out vec4 f_color;
11
+
12
+ uniform vec3 light_pos;
13
+ uniform vec3 view_pos;
14
+ uniform vec3 object_color;
15
+
16
+ // Configurable lighting params - sent from the renderer each frame.
17
+ // Defaults match MeshInspector's typical look.
18
+ uniform float ambient_strength; // default 0.2
19
+ uniform float specular_strength; // default 0.4
20
+ uniform float specular_exponent; // default 35.0
21
+
22
+ void main() {
23
+ vec3 N = normalize(v_normal);
24
+ vec3 L = normalize(light_pos - v_position);
25
+ vec3 V = normalize(view_pos - v_position);
26
+
27
+ // Diffuse (Lambertian)
28
+ float NdotL = max(dot(N, L), 0.0);
29
+
30
+ // Specular (Phong reflection)
31
+ vec3 R = reflect(-L, N);
32
+ float spec = pow(max(dot(R, V), 0.0), specular_exponent);
33
+
34
+ // Combine
35
+ vec3 ambient = ambient_strength * vec3(1.0);
36
+ vec3 diffuse = NdotL * vec3(1.0);
37
+ vec3 specular = specular_strength * spec * vec3(1.0);
38
+
39
+ vec3 result = (ambient + diffuse + specular) * object_color;
40
+ result = clamp(result, 0.0, 1.0);
41
+
42
+ f_color = vec4(result, 1.0);
43
+ }
@@ -0,0 +1,18 @@
1
+ #version 330
2
+
3
+ in vec3 in_position;
4
+ in vec3 in_normal;
5
+
6
+ out vec3 v_normal;
7
+ out vec3 v_position;
8
+
9
+ uniform mat4 model;
10
+ uniform mat4 view;
11
+ uniform mat4 projection;
12
+ uniform mat3 normal_matrix;
13
+
14
+ void main() {
15
+ v_normal = normal_matrix * in_normal;
16
+ v_position = vec3(model * vec4(in_position, 1.0));
17
+ gl_Position = projection * view * model * vec4(in_position, 1.0);
18
+ }
meshlite-0.2.0/main.py ADDED
@@ -0,0 +1,27 @@
1
+ """meshlite entry point.
2
+
3
+ Run with:
4
+
5
+ python main.py
6
+
7
+ or, after ``pip install -e .``:
8
+
9
+ meshlite
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import sys
15
+ from pathlib import Path
16
+
17
+ # Allow ``python main.py`` from the project root without installing the package.
18
+ # When installed via ``pip install -e .`` the package is on sys.path already and
19
+ # this insert is harmless.
20
+ _SRC = Path(__file__).resolve().parent / "src"
21
+ if _SRC.is_dir() and str(_SRC) not in sys.path:
22
+ sys.path.insert(0, str(_SRC))
23
+
24
+ from meshlite.app import main # noqa: E402
25
+
26
+ if __name__ == "__main__":
27
+ main()