Releases: alfu32/k3d
5.1.1: feat(ui): exports
Highlights
- Added selection-aware model export.
- Added unit-scaled exports with suffix-based unit metadata.
- Added .octd voxel import with staged placement and wireframe preview.
- Added xref/external-object storage support.
- Improved object placement preview.
- Improved in-tool operator/context menu behavior.
- Fixed polyline arc/circle segment input behavior.
Export Improvements
- Model export now exports the full model only when nothing is selected.
- When there is any selection, export is restricted to selected elements.
- Line-only selections no longer accidentally trigger full-model export.
- Exported coordinates are multiplied by the configured model unit size.
- Unit-aware formats now infer units from filename suffixes when possible:
- Examples: model_mm.3mf, model_cm.dae, model_m.dxf.
- If no known unit suffix is detected, exports use unitless units.
- DXF export now includes unit metadata through $INSUNITS.
- Collada/DAE, 3MF, AMF, and IFC unit handling was improved where supported.
- IFC export now handles selected line geometry as well as mesh geometry.
.octd Import
- .octd files can now be imported through the import flow.
- Imported voxel cubes are converted into a voxel object prototype.
- After import, the user is prompted to place the object interactively.
- Placement shows a wireframe preview before the insertion point is picked.
XRef / External Objects
- Object prototypes can now be stored externally as xrefs.
- Objects panel now includes:
- Store externally
- Pick XRef File
- Internal/external status in the object list
- Xref objects remain normal editable object prototypes in memory.
- Actionable hotspots remain visible/actionable through the existing object/hotspot system.
- Saves write external object data to its .octd xref file.
- Main model saves keep xref metadata and avoid embedding external object geometry.
- Desktop xrefs use normal filesystem .octd files.
- Android xrefs use SAF document URIs.
- Web runtime reports xrefs unavailable.
Object Placement
- Object placement now renders the selected prototype as a wireframe at the cursor.
- Double-clicking an object prototype in the object list stages it for placement as before, now with visible preview support.
Contextual Tool Operators
- The in-tool operators panel now exposes common contextual operations:
- Esc/cancel/return to select where relevant.
- Close Object while editing an object.
- Polyline-style segment buttons for line, arc, and circle segments.
- Polyline-style tools now expose clearer segment actions:
- Line Seg
- Arc Seg
- Circle Seg
Polyline Fixes
- Arc segment input behavior was corrected:
- Previous endpoint is point 1.
- Next click is point 2 on the arc.
- Next click is point 3/end of the arc.
- Circle segment input behavior was corrected:
- Previous endpoint is the arc start.
- Next click is the circle center.
- Next click is the arc end.
Assets / Examples
- App icons were refreshed.
- New export/example assets were added, including carcass exports and xref example .octd files.
external refs/ impoert-export improvements
- Export now uses selection when anything is selected, otherwise full model export. Line-only selections no longer accidentally export the full model for mesh-only formats.
- Export coordinates are scaled by modelUnit.size, and unit suffixes like model_mm.3mf, model_cm.dae, model_m.dxf, etc. now drive unit metadata where supported.
- .octd import is available through the import flow and imports voxel cubes into a new voxel prototype, then switches to object placement with a wireframe preview before insertion.
- Object placement now renders the selected prototype wireframe at the cursor.
- Objects can now be marked as xrefs via the Objects panel: Store externally, Pick XRef File, and the object list shows internal / external.
- Xref object geometry/hotspots remain normal object prototype data in memory, so editing and actionable hotspots continue through the existing object path. Saves write external xref .octd data and strip
that geometry from the main model snapshot when external storage is enabled. - Xref picking supports desktop files and Android SAF document URIs. Web reports xrefs unavailable.
4.9.8: feat(ui): grid toggle, thin line setting fix
UI improvements:
- thin and thick line width settings
- base grid can be turned off
- base grid can be rotated to xoz,yoz or back to xoy planes
-
the grid should always be thin ... should sit on its own batch together with all the helpers.
- the meaning behind swapping the grid normal was to swap also the snap plane, if the grid normal is pointing left then we should provide snap points in that vertical plane ....
- it would be great that every 5th grid line to be green and every 10th to be red coloured. the grid lines that pass through 0,0,0 should be black the rest should be gray
Applied the three corrections. The permanent grid now renders in the thin helper-line batch instead of the normal-width line batch, while selection/draft/dimension lines stay on the configurable batch in
core/src/main/kotlin/com/github/alfu32/sketch/Main.kt:2861 and core/src/main/kotlin/com/github/alfu32/sketch/Main.kt:2889. The grid itself is now basis-driven from the selected normal, with coloring rules
in core/src/main/kotlin/com/github/alfu32/sketch/Main.kt:3076: origin lines are black, every 10th line red, every 5th green, all others gray.The snap fallback plane now uses that same permanent-grid basis instead of a hardcoded y=0 plane, so switching the grid normal also switches empty-space grid snapping onto the corresponding vertical or
horizontal plane in core/src/main/kotlin/com/github/alfu32/sketch/input/Snapper.kt:15, core/src/main/kotlin/com/github/alfu32/sketch/input/Snapper.kt:128, and core/src/main/kotlin/com/github/alfu32/
sketch/input/Snapper.kt:170. I also updated the adaptive helper cloud so its “base grid” logic follows the selected permanent grid plane in core/src/main/kotlin/com/github/alfu32/sketch/Main.kt:3295.
4.9.6: feat(dist): snap
fix snap
promoted to stable strict
4.9.4: feat(dist): snap
-
fix snap build crashing
-
The AppImage wrapper ends up running octodraw-jre from the mounted AppImage payload.
-
That launcher defaulted PLUGINS_DIR to "$INSTALL_PATH/plugins".
-
In an AppImage that path is read-only, so plugins.json creation failed.
I fixed the Unix launchers in lwjgl3/build.gradle.
What changed
- octodraw-editor and octodraw-jre now compute a writable app home:
- OCTODRAW_HOME
- fallback K3D_HOME
- fallback XDG_DATA_HOME/octodraw
- fallback ~/.local/share/octodraw
- They export that as OCTODRAW_HOME
- Plugin dir now falls back to:
- "$APP_HOME/plugins"
- whenever the packaged plugins dir is not writable
- They also mkdir -p the chosen plugin dir before launch
Effect
- AppImage now writes plugin state to a writable user location
- extracted Linux bundles still use packaged plugins/ when that directory is writable
- if a portable bundle is installed read-only, it also falls back cleanly to user data
android, object picking and DXF fixes
Patched the three regressions.
- Android Ctrl/copy mode
- core/src/main/kotlin/com/github/alfu32/sketch/ui/ToolController.kt
- Android now syncs copyMode from the live Ctrl modifier every frame for tools that support copy mode.
- This avoids relying on libGDX receiving raw Ctrl key events, which Android was intercepting.
- Android render save
- core/src/main/kotlin/com/github/alfu32/sketch/Main.kt
- core/src/main/kotlin/com/github/alfu32/sketch/render/RenderController.kt
- Save on Android now opens the system ACTION_CREATE_DOCUMENT picker and writes the rendered PNG through SAF.
- It no longer silently saves to app-local storage instead of showing the dialog.
- Object picking inside larger object bounds
- core/src/main/kotlin/com/github/alfu32/sketch/tools/SelectTool.kt
- Removed the coarse AABB fallback from click-picking.
- Object click-pick now requires an actual face or line hit, so an outer object no longer wins just because the ray passes through its bounds.
DXF import/export is fixed at the core path.
-
core/src/main/kotlin/com/github/alfu32/sketch/export/MeshIo.kt
- DXF import now parses:
- LINE
- LWPOLYLINE
- POLYLINE / VERTEX / SEQEND
- 3DFACE
- SOLID
- TRACE
- DXF export now writes both:
- LINE
- 3DFACE
- added DXF-specific geometry APIs so lines are no longer lost on import/export- core/src/main/kotlin/com/github/alfu32/sketch/model/GroupScene.kt
- added MeshSegment
- added createImportedPrototype(...) so imported objects can contain both faces and explicit linework
- existing createMeshPrototype(...) now delegates to it
- core/src/main/kotlin/com/github/alfu32/sketch/Main.kt
- DXF import now places both imported faces and imported lines into the created prototype
- DXF export now exports both world triangles and world segments
- selected export works for line segments too
- export label changed from DXF 3DFACE (.dxf) to DXF LINE + 3DFACE (.dxf)
- export status text is now generic enough for non-triangle DXF entities
Checked:
- GRADLE_USER_HOME=.gradle-user ./gradlew :core:compileKotlin -q
Current behavior:
- DXF import still follows the existing mesh-import flow:
- create prototype
- click to place object
- DXF export emits explicit lines plus triangle faces
- if a DXF has faces but no explicit lines, triangle edges are generated only when no DXF line entities were imported
Remaining limitation:
- exporter writes LINE + 3DFACE only; it does not try to recreate original DXF higher-level entities like LWPOLYLINE on export.
- core/src/main/kotlin/com/github/alfu32/sketch/model/GroupScene.kt
Global Illumination/Raytracing
changelog from 4.8.9 to 4.9.1:
- Improved the new offline renderer preview and output stability.
- Fixed saved render images being vertically flipped.
- Fixed render framing/camera mapping so the offline render matches the current view much more closely.
- Fixed directional/sun light contribution in offline rendering.
- Fixed path-tracing striping/banding artefacts.
- Fixed stale previous-pass/block artefacts in progressive rendering.
- Fixed render-window preview sizing so the preview no longer grows to the full internal buffer size.
- Added render size presets while keeping the preview window at a manageable fixed display size.
- Added a global render light level control for both raytrace and GI/path-trace.
- Added camera light intensity control.
- Added an option to disable tile pruning, with pruning now off by default.
- Improved transparent-material rendering so transmitted rays:
- pass through transparent surfaces,
- are tinted by material color,
- and are dimmed according to alpha.
- Added a new Rendering toolbar and render window.
- Added two offline rendering modes:
- Raytrace
- GI / Pathtrace
- Added progressive rendering passes from coarse to fine, ordered from image center toward the borders.
- Added Stop and Save controls for offline rendering.
- Added live compositing of the offline render over the captured GPU framebuffer.
- Added blur and blend controls for the render overlay.
- Added simple glass transmission/refraction support.
- Added desktop/Android parallel tile rendering with worker pool support.
- Kept web rendering on the single-threaded fallback path.
- Added worker-count control in the render window.
- Added resolution display in the render window.
Shorter store/update-note version:

- Introduced a new offline rendering window with Raytrace and GI/Pathtrace modes.
- Added progressive center-out rendering, save/stop controls, worker-count control, size presets, blur/blend controls, and adjustable lighting.
- Improved transparency handling for glass-like materials.
- Fixed multiple offline renderer issues including framing, lighting, vertical save flip, striping, and progressive pass artefacts.

UX/jar plugins/dimension bounds
4.8.9
In Short:
- Hotspot dragging now previews the resulting geometry in wireframe and shows live movement measurements.
- Array tool previews now show far more copies.
- Desktop now supports precompiled jar plugins.
- Plugin loading is disabled on unsupported Web/Android runtimes.
- Dimension selection bounds are now tight and correct.
TLDR
- Added live hotspot drag feedback:
- shows the hotspot movement line
- shows measurement feedback while dragging
- shows a wireframe preview of the future geometry driven by the hotspot
- Increased array/multiplier preview capacity:
- ghost/wireframe preview limit raised from 32 to 10000
- Added desktop support for precompiled plugin jars:
- plugin manager can now load .jar plugins in addition to Groovy script plugins
- jar plugins can expose their entry point through:
- META-INF/services/com.github.alfu32.sketch.plugin.Plugin
- or manifest Plugin-Class / K3D-Plugin-Class / Octodraw-Plugin-Class
- Restricted plugins to supported runtimes:
- plugin loading is now disabled on Web and Android
- avoids unsupported runtime/classloading paths on those targets
- Fixed dimension bounding boxes:
- selection/frame bounds now use the actual rendered dimension geometry
- extension lines, dimension line, and slash markers are all accounted for
- bounds are now tight instead of oversized/wrong
staged loading/fixes/maintenance
- Added staged model loading with visible progress instead of a long blind startup stall.
- File loading now initializes the app scene first, then loads the model in steps.
- Added a modal load dialog with progress feedback and an Abort button.
- Scene application during load is now chunked across frames, so the UI stays responsive while loading.
- Opening a file now creates a .bak copy as part of the staged load flow.
- Aborting a load no longer overwrites the target file or the previously opened file.
- Camera is reset to a valid default position immediately when a load starts.
- Added Edit Selected Object action for entering object edit mode more directly.
- Fixed object click-picking regression where objects were not selected correctly by direct click.
- Fixed orbit camera target auto-glue on faces, including root faces and object faces.
- Fixed hotspot-driven object geometry refresh so stale face shells are no longer left visible after deformation.
4.8.7
- Added a numeric Circle segments setting to Model Settings.
- Circle preview and generated geometry now use the configured segment count.
- Default circle segment count is now 24.
- Added internal optimizations for model delete/change handling.
- Added asynchronous/background spatial indexing work for model/query structures.
- Reduced excessive render/status feedback caused by indexing progress spam.
- Fixed linear/multiple translate array multiplication spacing faults.
- Disabled Snap bundle generation from the default desktop bundle pipeline to stop unrelated desktop builds from failing on Snap packaging.
4.8.6 -> 4.8.8 overall
- Major work on model loading, scene application, and persistence safety.
- Better responsiveness and feedback when opening large files.
- Safer cancel behavior during load.
- Better object editing workflow.
- Fixes for object picking, camera face snapping, and hotspot-driven geometry updates.

array tools
feat(tools): arrays and array hotspots

implemented the array tools and fixed the existing translate-multiple behavior.
What changed
- core/src/main/kotlin/com/github/alfu32/sketch/tools/MultipleCopyTools.kt
- fixed CopyMultipleTool
- step direction now comes from a - o
- copy count now comes from the span of b - o projected onto that step direction
- the old tool was using the final span direction and projecting the measure onto it, which was the wrong geometry
- added PlanarTranslateMultipleTool
- repeats in the xoz plane
- offsets are built from the measured step components on x and z
- added VolumetricTranslateMultipleTool
- repeats in x, y, and z
- offsets are built from the measured step components on all three axes
- added proper preview rendering for planar/volumetric translated arrays
- fixed CopyMultipleTool
- core/src/main/kotlin/com/github/alfu32/sketch/model/GroupScene.kt
- fixed hotspot multiplier behavior to match the same semantics
- for hotspots:
- o = referencePosition
- a = hotspot definition position
- b = runtime target / instance value
- MULTIPLY_LINEAR now uses the measured step vector from o -> a
- MULTIPLY_VOLUMETRIC now uses per-axis step ratios from o -> a and o -> b
- I did not invent a new planar hotspot operation; planar hotspot behavior is the ny = 0 case of volumetric multiplication
- core/src/main/kotlin/com/github/alfu32/sketch/ui/ToolId.kt
- added:
- PLANAR_TRANSLATE_MULTIPLE
- VOLUMETRIC_TRANSLATE_MULTIPLE
- added:
- core/src/main/kotlin/com/github/alfu32/sketch/Main.kt
- registered both new tools
- added them to the built-in tool command palette list
- core/src/main/kotlin/com/github/alfu32/sketch/ui/SketchUiOverlay.kt
- added both tools to the modification toolbar
- added icon-name/color mapping fallbacks
- core/src/main/kotlin/com/github/alfu32/sketch/ui/ToolInputProcessor.kt
- added both tools to the M-cycle with the other transform tools
feat(tools): arrays and array hotspots
implemented the array tools and fixed the existing translate-multiple behavior.
What changed
- core/src/main/kotlin/com/github/alfu32/sketch/tools/MultipleCopyTools.kt
- fixed CopyMultipleTool
- step direction now comes from a - o
- copy count now comes from the span of b - o projected onto that step direction
- the old tool was using the final span direction and projecting the measure onto it, which was the wrong geometry
- added PlanarTranslateMultipleTool
- repeats in the xoz plane
- offsets are built from the measured step components on x and z
- added VolumetricTranslateMultipleTool
- repeats in x, y, and z
- offsets are built from the measured step components on all three axes
- added proper preview rendering for planar/volumetric translated arrays
- fixed CopyMultipleTool
- core/src/main/kotlin/com/github/alfu32/sketch/model/GroupScene.kt
- fixed hotspot multiplier behavior to match the same semantics
- for hotspots:
- o = referencePosition
- a = hotspot definition position
- b = runtime target / instance value
- MULTIPLY_LINEAR now uses the measured step vector from o -> a
- MULTIPLY_VOLUMETRIC now uses per-axis step ratios from o -> a and o -> b
- I did not invent a new planar hotspot operation; planar hotspot behavior is the ny = 0 case of volumetric multiplication
- core/src/main/kotlin/com/github/alfu32/sketch/ui/ToolId.kt
- added:
- PLANAR_TRANSLATE_MULTIPLE
- VOLUMETRIC_TRANSLATE_MULTIPLE
- added:
- core/src/main/kotlin/com/github/alfu32/sketch/Main.kt
- registered both new tools
- added them to the built-in tool command palette list
- core/src/main/kotlin/com/github/alfu32/sketch/ui/SketchUiOverlay.kt
- added both tools to the modification toolbar
- added icon-name/color mapping fallbacks
- core/src/main/kotlin/com/github/alfu32/sketch/ui/ToolInputProcessor.kt
- added both tools to the M-cycle with the other transform tools
fix(tools): arrays and array hotspots
- core/src/main/kotlin/com/github/alfu32/sketch/ui/SketchUiOverlay.kt:5987
- PLANAR_TRANSLATE_MULTIPLE now maps to multiple-copy-translate-planar
- VOLUMETRIC_TRANSLATE_MULTIPLE now maps to multiple-copy-translate-volumetric
fix(snapcraft): release
-
Moved the Snapcraft project file to the repo root:
- snapcraft.yaml- Removed the old nested config:
- snap/snapcraft.yaml
- Kept the GUI assets under:
- snap/gui/octodraw.desktop
- snap/gui/icon.png
Gradle change
- lwjgl3/build.gradle
- bundleLinuxSnap now copies:
- root snapcraft.yaml into the Snapcraft project root
- snap/ into the staged snap/ directory
- local Snap build still uses Snapcraft, not mksquashfs
- bundleLinuxSnap now copies:
CI change
- .github/workflows/release.yml
- Linux CI no longer installs Snapcraft
- Linux CI no longer runs :lwjgl3:bundleLinuxSnap
- Linux CI no longer uploads *.snap
- Removed the old nested config:


