Skip to content

Releases: Stuyk/meshcoat

v2.4.0

Choose a tag to compare

@github-actions github-actions released this 19 Sep 23:47
Immutable release. Only release title and notes can be modified.
2b34b04

Added

  • Text Tool (Y): Select faces, type, and apply. Text renders to a transparent decal placed by the Face UV Projector. Font, alignment, bold/italic, spacing, fill, and outline, with a live preview. Baked into the layer, not re-editable.
  • Font Picker: Modal listing the system's installed fonts, each previewed in its own face, with search.

Fixed

  • Tool Panel Focus: Panels no longer rebuild their DOM on every state change, which stole focus from fields while typing.
  • Brush Texture Memory: The previous GPU texture is released on every texture swap.

v2.3.0

Choose a tag to compare

@github-actions github-actions released this 19 Sep 05:04
Immutable release. Only release title and notes can be modified.
7b5b016

Added

  • Selection Groups: Save face selections by name and reselect them from the new Selections tab. Stored in the project file.
  • Reload Model from Disk: File menu option to re-import an edited model while keeping layers.
  • Texture Subfolders: Texture folders load their subfolders, with a dropdown to filter by folder.
  • Nav Cube Snap: Click a face of the top-right cube to snap the camera to that view.
  • Texture Region Angle Input: Type an exact rotation or snap to 0°/90°/180°/-90°.

Changed

  • Distinct Icons: Material Channels, Edge Wear, and Brush Library each have their own icon.

v2.2.4

Choose a tag to compare

@github-actions github-actions released this 18 Sep 04:21
Immutable release. Only release title and notes can be modified.
a57550c

Fixed

Exported Textures Mirrored on glTF Models: glTF puts the UV origin at the top-left, and a .blend inherits that through the Blender bridge, so a map painted on one exported vertically flipped against the source asset's own UVs. UVs are now normalized to a bottom-left origin at import, matching the space the app paints and exports in. Projects saved before this are migrated on load.

v2.2.3

Choose a tag to compare

@github-actions github-actions released this 18 Sep 03:32
Immutable release. Only release title and notes can be modified.
e4ccca0

What's Changed

  • fix: layer opacity contrast, recent textures cap, .blend reopen, .abr… by @Stuyk in #16

v2.2.2

Choose a tag to compare

@github-actions github-actions released this 15 Sep 03:22
Immutable release. Only release title and notes can be modified.
fba5d12

Added

  • Brush Tip Support for Eraser, Stamp, and Effects Brushes: Custom .abr and preset brush tips can now be selected and applied to the Eraser, Stamp, and Effects (Blur, Sharpen, Smudge, Pixelate) tools.
  • Unified 3D Reticle Silhouettes: The 3D cursor reticle and mirror symmetry gizmo now display active brush tip outlines across all brush, stamp, eraser, and effects tools.
  • Docked Tool Panel Brush Access: Added direct brush tip preview, reset, and library access buttons to the Effects Brush HUD and Material Texture / Stamp panels.
  • Expanded Bottom Dock Indicators: Added hardness and rotation indicators to the bottom dock for Eraser and Effects tools.
  • Rotation Gizmo: In the top right, introduced a 3D gizmo to grab and rotate. Handy for pen users.

Fixed

  • Stamp Tool Falloff: Fixed stamp mode falloff calculation to prevent untextured stamp dabs from flooding the mesh with flat color.
  • Stamp Reticle Orientation: The stamp reticle now rotates in sync with brush angle adjustments.

v2.2.0

Choose a tag to compare

@github-actions github-actions released this 13 Sep 18:41
Immutable release. Only release title and notes can be modified.
fdb37a2

Added

  • Face UV Projector (P / 8): Dedicated tool for TrenchBroom/PSX-style workflows. Select faces, adjust offset, scale, and rotation independently of base UVs, and bake directly to the active layer with Apply to Selection. Fully supports Texture Region and Material Texture controls.
  • Live 3D Preview: View lit, tone-mapped projections directly on selected faces before baking, flagged by an unbaked status badge.
  • Fit to Selection Mode: Default placement mode that stretches a single texture copy across the selection's UV bounds. Inverts scale/offset controls to behave like decal sizing rather than UV repeat.
  • Clipboard Texture Pasting: New Pasted shelf tab lets you import images directly via Ctrl+V or the paste button. Stores up to 24 in-memory textures per session for immediate use across all painting tools.

Changed

  • Contextual Tool Dock: Inactive panels are now completely hidden instead of displayed as dimmed text.
  • Projector Face Selection: Face selection controls now match the Face Select tool (drag-select, Shift-click extend, Alt-orbit).
  • Codebase Typing: Removed any casts, typed UI icon maps and window globals, and added explicit error logging to previously swallowed catch blocks.

Fixed

  • Dark Projection Previews: Resolved preview shading issues caused by depth-test fighting, incorrect unlit tone mapping, aggressive mipmapping, and improper blending. The preview now uses a full PBR material matching the mesh surface without depth-testing.
  • LocalStorage Quota Crashes: Prevented large base64/blob URLs from being saved to the persistent Used shelf, eliminating storage exhaustion errors.

v2.1.0

Choose a tag to compare

@github-actions github-actions released this 13 Sep 05:40
Immutable release. Only release title and notes can be modified.
c2efcbb

Added

  • Tool Dock: Consolidated floating panels into a toggleable (C) accordion dock with inactive state indicators.
  • Texture Region Picker: Live crop, rotate, and grid-slice (2×2–4×4) source textures in-shader across all tools.
  • Placement & Repeat Modes: Replaced UV/Triplanar/Tip with Placement (Surface, World, Cursor) and Repeat (Tile, Mirror, Once).
  • Clipboard Stencil: Load system clipboard images straight into the stencil panel with Ctrl+V.
  • Selection Framing: F focuses the camera on selected faces instead of the whole model.
  • Drag-to-Fill: Sweep across faces in Fill Face mode to paint multiple triangles in one undo step.
  • Relative Brush Scaling: Brush slider ranges and presets scale to the loaded model's bounds.
  • Selection Visibility: Added a translucent wash and depth-independent outlines to selected/hovered faces.

Changed

  • Import Wizard: PBR slots and shelf settings moved into an "Advanced" drawer; main flow requires only model and resolution.
  • Bucket Tool: Stripped brush dynamics, 3D reticles, and large icons in favor of a clean dot cursor.
  • Shared UI: Unified all side panels onto the PanelSection accordion component.
  • Tiling Units: Surface and World placements store independent scale values and unit labels.
  • Filename Display: Stripped full directory paths from texture labels on Windows.

Fixed

  • Cursor Preview: Brush-tip and stamp previews now match the cropped texture region.
  • Region Y-Inversion: Fixed UV vertical flip causing crops to sample upside down.
  • Layer Duplication: Buffer clears to transparent before copying to prevent solid background fills.
  • Layer ID Conflicts: Stack-derived IDs replace the global counter, preventing duplicate active states after hot reloads.
  • Ghost Gizmos: Previews reset globally on tool switch so inactive reticles no longer linger.
  • Scale Slider Freeze: Removed circular reactive triggers in setTextureScale.
  • Menu Stacking: Resolved z-index conflicts causing dropdowns to render beneath panels.

v2.0.0

Choose a tag to compare

@github-actions github-actions released this 13 Sep 01:23
Immutable release. Only release title and notes can be modified.
1667990

Added

  • PBR material painting, alongside — not instead of — the existing flat-texture workflow. The brush is a material brush in the Substance sense: one stroke writes every enabled channel at once and in perfect register, so gold is a single brush (yellow base color + 0.1 roughness + 1.0 metalness), not three passes to line up by hand.

    • Four channels — Base Color, Roughness, Metalness, and a tangent-space Normal map — each toggled independently in a new Material Channels panel, with value sliders and eight ready-made material presets (Polished Gold, Brushed Steel, Rusted Iron, Copper, Glossy Plastic, Matte Rubber, Rough Wood, Wet Clay).
    • Relief from the dab itself. The normal channel takes its slope from whatever shapes the stroke — a custom tip's alpha, a stamped image's alpha, or the round falloff when neither is set. The gradient is measured in the brush's own plane (which follows the cursor and rotates with the stroke) and then re-expressed in the mesh's UV tangent frame, which is the frame a tangent-space normal map is actually read in; without that conversion the relief would light as though pointing somewhere else entirely. Negative strength engraves instead of embossing.
    • Lazy per-channel allocation. A layer allocates a channel's ping-pong pair only when a stroke actually writes to it, and its undo snapshots carry only the channels it has. A flat-color project therefore costs exactly what it always did in both VRAM and undo depth, instead of paying four times over for channels nobody painted.
    • Every existing tool is channel-aware: brush, line, stamp, bucket fill (whole model and per-face), symmetry, face restriction, screen stencils, and the effects brush (which filters every channel a layer has, so a blurred stroke doesn't leave razor-sharp roughness underneath it). The eraser takes coverage back out of the PBR channels rather than stamping zeros over them. Mask layers stay grayscale coverage only, as before.
  • Image-based lighting. A prefiltered RoomEnvironment is now the scene's environment map. Roughness and metalness are only legible against a varied environment — a metal surface renders as whatever it reflects, and under directional lights alone a painted metalness map would read as dark grey paint. Each lighting preset weights the environment differently; Flat mode keeps it low so raw texture color stays judgeable.

  • Showcase lighting mode, a fourth preset for judging material response rather than form. Roughness and metalness are read off reflections — a metal shows whatever surrounds it, and gloss reads as how sharply those surroundings appear in the surface — so direct lights, which give a surface nothing to reflect but a few hot spots, are exactly the wrong rig for checking a PBR material. Showcase hands the lighting to the environment (2.4x) and drops the direct rig to a single raking key, kept only because a grazing angle is what makes normal-map relief legible; a darker ground keeps highlights from competing with the backdrop.

  • Channel view modes in the top bar: the full shaded material, or one isolated map (Color / Rough / Metal / Normal) shown unlit and untone-mapped, so values can be read straight off the surface.

  • PBR texture set export (File menu): one PNG per painted channel — _BaseColor, _Roughness, _Metallic, _Normal — plus the packed ORM map (R = ambient occlusion, G = roughness, B = metalness) that Unreal, Unity and glTF expect. Channels nobody painted are skipped rather than written out as flat defaults.

  • Painting with PBR texture sets. A folder of loose files — rock_BaseColor.png, rock_Roughness.png, rock_Normal.png — is grouped back into the material it came from by filename convention, and shows in the shelf as one card badged with the channels it covers. Pick it and paint: every channel the set ships is written in one stroke, through the same projection, in register. There is nothing to configure — selecting a set switches its channels on, resets the value sliders to neutral, and sizes tiling to the model (the 8x pattern-stamp default packs a material into unreadable moiré on anything small). The sliders remain live as multipliers over the maps, and the channel switches now sit behind an Advanced disclosure rather than in the way. Suffix spellings from Substance, Quixel, Poliigon, ambientCG and Blender are all recognised; a lone suffixed file with no siblings stays the plain stamp image it is.

  • .tga texture support. Chromium can't decode TGA in an <img>, so the shelf used to filter it out — which silently dropped the colour channel of any pack shipping a .tga albedo beside .png data maps. TGAs now load through three's TGALoader for painting, with the thumbnail borrowing a sibling map.

  • Direct Blender (.blend) File Import:

    • Direct import of native .blend files through both the Welcome / Import Wizard and standard Open Model dialog (Ctrl+O).
    • Headless Blender CLI Bridge: runs background conversion via detected Blender binary (--background --python-expr) exporting evaluated geometries (including modifiers and tangent frames) to glTF 2.0 with Draco/MeshOptimizer compression support, importing directly into MeshCoat's multi-component PBR pipeline in milliseconds.
    • Smart Blender Detection: automatically detects Blender across standard installation paths, custom Linux programs folders (~/programs/blender*), PATH, macOS App bundles, and Windows Program Files.
    • Blender 3D Bridge Settings: user-configurable Blender executable path with instant version testing, auto-detect button, file system browser, and persistent storage in user preferences. Startup prompt alerts the user if Blender is not yet found, with a dismissible option.
  • Multi-piece model support: models containing multiple distinct meshes/objects (characters with clothes/accessories, weapons, modular vehicles) are now partitioned into separate paintable pieces, each maintaining its own independent layer stack, resolution, and undo history:

    • Quick Piece Switching: toggle active pieces via Tab / Shift+Tab, through the dropdown in the top header or layer panel, or by double-clicking meshes directly in the 3D viewport.
    • Isolate Active Piece (EyeOff button): hide unselected pieces to easily paint inside tight crevices or interior geometry without visual obstruction. Switching pieces while isolation is active automatically isolates the new selection.
  • Unified Texture Export Wizard (Ctrl+Shift+E / Ctrl+E):

    • Replaced fragmented File menu export options with a single, comprehensive export modal.
    • Piece Export Modes: supports exporting Individual Pieces ([Model]_[Piece]_[Channel].png) or a Single Image (Shared UV / Atlas) composite ([Model]_[Channel].png) across all pieces.
    • Channel Selection & Presets: individual toggles for Base Color, Packed ORM, Roughness, Metalness, and Normal maps, with one-click presets for PBR + ORM, Color Only, and All Unpacked.
    • Resolution Overrides: export at native resolution or rescale to 1024px, 2048px, or 4096px.
    • Live Preview & Safety Tooltip: live badge and filename list showing exact files to be written, paired with an engine workflow disclaimer.
  • Modernized Welcome & Import Wizard:

    • Replaced legacy modal with a cohesive 3-tab layout: Import 3D Model & PBR, Quick Start Primitives, and Recent Projects.
    • Multi-Component 3D Model Support:
      • Automatically inspects model meshes upon file selection to detect single vs multi-piece models.
      • Mode Switcher: easily toggle between Shared Texture Map (Single Atlas) (maps one texture set across all model pieces) and Per-Component Maps (dedicated channel slots per mesh piece).
      • Component Selector Pills: fast navigation across model pieces ([Body (3 maps)], [Armor (2 maps)], [Helmet]) with quick "Copy to all components" action.
      • Smart Component Auto-Discovery: matches sibling texture filenames containing component names (e.g. Character_Body_BaseColor.png matches Body) and auto-assigns channels per piece.
    • Full PBR Texture Ingestion: dedicated channel slots for Base Color, Roughness, Metalness, Tangent Normal, and Packed ORM (Occlusion/Roughness/Metallic).
    • Automatic Sibling Map Detection: automatically inspects model directories on pick and auto-populates matching channel textures based on standard naming conventions (_BaseColor, _Roughness, _Normal, _ORM, etc.).
    • Packed ORM Auto-Unpacking: splits green (Roughness) and blue (Metalness) channels automatically from ORM maps upon model load.
    • Interactive Previews: live thumbnail previews for assigned texture slots with quick swap and remove controls.
    • Quick Start Primitives: one-click creation with resolution selectors for UV Sphere (equirectangular) and UV Unwrapped Cube (custom 6-face non-overlapping 3×2 island layout).
    • Preload Texture Library Folder: optional directory picker to populate the Texture Shelf with brush stamps and materials on project startup.
    • Auto-Recovery Banner & Recents: persistent autosave restoration with relative timestamps, layer count summaries, and clearable recent history.
  • Direct 3D Model Open (Ctrl+O): open 3D model files (.glb, .gltf, .obj) directly via shortcut or the File menu without needing to go through the Welcome Wizard.

  • Multi-tab Help & Documentation Modal (?):

    • Keyboard Shortcuts: categorized table with real-time search, badge filters, and updated hotkey listings.
    • Documentation & Workflows: comprehensive guides covering PBR Material Painting, Multi-Piece Meshes & Isolation, Procedural Edge Wear & Crevice Grime, Screen Stencil Projection, Effects Brush, and Texture Exporting.
  • Cast shadows in Showcase lighting. The key light casts a sof...

Read more

v1.2.0

Choose a tag to compare

@github-actions github-actions released this 12 Sep 20:00
Immutable release. Only release title and notes can be modified.
2aa4f56

v1.2.0

Added

  • Effects brush (U) — one tool with four modes, since they share a dab footprint and differ only in the filter applied under it:

    • Blur — box filter over the texels beneath the dab.
    • Sharpen — unsharp mask, pushing each texel away from its blurred neighbourhood.
    • Smudge — drags color along the stroke. The pull direction comes from consecutive hit UVs (valid because the UV map is locally affine across a single dab), so it follows the hand rather than a fixed axis. A large UV jump means the stroke crossed an island seam, where dragging would smear two unrelated parts of the model together, so that step is dropped.
    • Pixelate — snaps to a block grid, sampling each block's center so the result stays stable as the brush passes over it instead of shimmering.

    It reworks paint already on the active layer rather than adding color, so the color and texture settings don't apply; radius, hardness, opacity, spacing, face selection and pen pressure all work as they do for the paint brush. Per-mode controls (strength, kernel radius, block size, drag length) appear in Brush Settings when the tool is active. Filtering happens in premultiplied alpha — the only space where averaging neighbouring texels is correct, since filtering straight-alpha color drags the meaningless RGB of fully transparent texels into the result and produces dark halos at every stroke and island edge.

  • Crevice / Cavity Dirt generator: the Edge Wear Wizard gained a Generator switch — "Edge Wear" chips convex ridges and exposed corners as before, "Crevice Dirt" targets the concave edge population instead, settling grime and ambient shadow into interior folds and valleys. Convex and concave edges are disjoint sets of the same mesh edges, so computeEdgeCurvature now emits both a convex curvature and a concave one per edge and the shader picks between them. Four cavity presets ship with it: Ambient Occlusion, Crevice Dirt, Heavy Grime, and Cel Crease Shade. Open borders count as exposed ridges and are never treated as crevices.

  • Smoothness (AO Look) control for both generators: at 100% the procedural noise drops out entirely and the falloff ramp squares, leaving a clean curvature gradient — an ambient-occlusion pass rather than grunge. Cavity presets lean smooth, wear presets stay noisy.

  • Screen-space stencil (the Mari / Mudbox workflow), opened from the left toolbar: load an image that pins to the viewport rather than the surface, orbit the model underneath it, then either Stamp Onto Model to project it on in one shot or paint through it with the brush. Because the projection is fixed to the screen, photos and patterns land undistorted on curved geometry — the thing the tangent-space Stamp tool can't do. Brightness drives where paint lands (a cut-out PNG's alpha multiplies in), with an Invert toggle to paint through the dark areas instead. The stamp is a true decal pass: every visible texel inside the stencil rect takes the image at once, gated by the camera-visibility test so the projection can't wrap through the model and reprint itself mirrored on the far side, and confined by any active face selection. It can stamp the image's own colors and alpha (a photo or logo) or use its brightness as a mask and stamp the current paint color through it (plain black-and-white stencil artwork, which is opaque everywhere and would otherwise stamp as a solid rectangle). The panel carries size, rotation, overlay opacity, and a Transform Stencil mode in which dragging positions the sheet, the wheel scales it, and Shift+wheel rotates it. The DOM overlay and the paint shader are driven from the same rect, so what you line up is what paints.

  • Stylus / pen pressure sensitivity: PointerEvent.pressure now maps to brush radius and opacity, each independently toggleable, with a Min Pressure Floor so a light touch still marks. Dab spacing follows the pressure-adjusted radius, so the thin part of a tapered stroke doesn't leave gaps sized for the full-pressure brush. Whether pressure applies is decided by pointerType, not by the pressure value — a mouse never scales, a pen always does. Tablets that report pressure 0 on the contact event itself have that sample skipped, so a stroke starts from the first reading that reflects what the artist actually pressed rather than opening with a full-strength dab.

  • Shift+click straight-line snapping on the Brush, Eraser, and Stamp: connects the previous dab to the new click with an interpolated straight line, without switching to the Line tool. The interpolation walks screen space and raycasts each step back onto the mesh rather than lerping world positions — a world-space line would tunnel through curved geometry and paint the far side — so the line follows the surface being looked at and stops cleanly at silhouettes.

Fixed

  • Undo/redo turned the whole model opaque black. Three.js defines OPAQUE for any material with transparent === false and blending === NormalBlending — exactly MeshBasicMaterial's defaults — and its opaque_fragment shader chunk then hard-sets diffuseColor.a = 1.0. Every layer copy went through such a material, so restoring a snapshot destroyed its alpha channel: transparent texels, stored premultiplied as (0,0,0,0), came back as (0,0,0,1) — opaque black — turning each restored layer into a solid black sheet over everything beneath it. Layer copies now use a passthrough shader with NoBlending, which writes RGBA verbatim. The same corruption applied to the Edge Wear preview snapshot/revert path, which shared those helpers.

Changed

  • The brush's projector footprint and camera-visibility test now live in one shared GLSL module (brushMask.ts) used by both the paint shader and the new effects shader. These are the two pieces of this app that have been got wrong the most times; a second copy in a second shader would have drifted from the first the next time either was tuned. Behaviour is unchanged — same math, same uniform names.
  • Layer copy/snapshot/restore now reuse persistent GPU objects instead of allocating a Scene, Mesh, and PlaneGeometry per call — undo and redo run one of these per layer, which adds up on a deep history at large canvas sizes.

v1.1.1

Choose a tag to compare

@github-actions github-actions released this 12 Sep 16:34
Immutable release. Only release title and notes can be modified.
4dfddeb

v1.1.1

Added

  • Brush projector depth ("Depth (Bleed Through)" slider): controls how far a dab reaches along the surface normal, as a percentage of the brush radius (default 35%, presets Thin / Default / Wrap). Lower it when paint reaches the far side of a thin wall or the opposite fold of a crease; raise it to wrap further over sharp edges and tight curvature.
  • Brush "Max Angle" slider: widest angle between the surface normal and the brush normal that still takes paint (default 85°), replacing the previous fixed facing cutoff. The contribution ramps to zero approaching the cutoff, so a stroke across curvature no longer shows a hard ring where it ends.
  • Fill tool "Fill Face" mode: fill only the single clicked face instead of the whole model / active face selection, switchable from the floating HUD (which now also appears for the Fill tool with no texture selected). The status bar hint reflects the active mode.
  • Edge Wear "bake to new layer" live preview: previewing in new-layer mode now composites a transient ghost layer on top rather than mutating the active layer, so what you see during preview is what gets committed.
  • Edge Wear new-layer background choice: the baked layer can start transparent (default) or opaque black. Switching the target mode or background retriggers the live preview immediately.
  • Paint diagnostics on the DevTools console: slipDebug.uvOverlap() reports what fraction of covered texels carry two or more triangles (overlapping/mirrored UVs mean two faces physically share texels — painting one necessarily paints the other, which looks like bleed-through but is a model problem), and slipDebug.occlusion() reports whether the occlusion depth pass is producing data.

Changed

  • The brush is now modeled as a projector rather than a sphere. Each texel is transformed into the brush's local frame (tangent/bitangent spanning the tangent plane, normal as the third axis); the round dab comes from the radial distance in that plane, and penetration is bounded separately along the normal. Radius and depth are now independent, which is what lets a wide brush paint a thin wall.
  • The brush tangent basis is now computed on every dab, not only for stamps, tips, and rotated brushes — the projector bounds are evaluated in that frame, so a stale basis left from an earlier dab would misshape the dab and mis-measure its penetration.
  • The occlusion depth pass was rebuilt (see Fixed) and is now the secondary visibility test, covering the case the projector bounds can't: a front-facing surface hidden behind another part of the model.
  • Segmented control options now flex to fill their track and no longer wrap their labels.

Fixed

  • Paint bleeding through to geometry behind the brushed face (v1.1.0's fix was incomplete — it addressed visibility while leaving the underlying cause in place). The shader masked strokes by length(worldPos - brushPos), a sphere: a sphere of radius r paints everything within r in every direction, so it unavoidably caught the far side of any shell thinner than r, the inside of any tube narrower than r, and the neighbouring fold of any crease. No visibility test can undo that, because from the brush's point of view those texels genuinely are in range. Bounding penetration along the surface normal separately from the dab radius removes the cause.
  • Occlusion depth pass rendered the entire scene, including the brush cursor ring and tip quad (which sit exactly on the hit point), the face-highlight and wireframe overlays (children of the model mesh itself), the symmetry guide plane, and the grid. All of them wrote depth in front of the surface being painted, so the test rejected the very texels it was meant to allow. The pass now renders only the model meshes, hiding and restoring everything else.
  • Occlusion depth comparison was unreliable at any camera distance: it reconstructed view-space Z from a non-linear 24-bit depth buffer spanning near 0.01 to far 1000, where a fixed bias is worth millimetres at one distance and metres at another. The pass now writes linear camera-space distance into a half-float target, so the comparison and its bias are both in world units. Unwritten texels clear to the far plane, so background can no longer read as an occluder, and the map matches the canvas aspect ratio so its texels line up with what the camera rasterized.
  • Symmetry strokes were rejected wholesale once occlusion testing was active: the mirrored dab lands on the far side of the model, which is by definition not visible from the paint camera. Mirrored dabs now skip the camera visibility test.
  • Models with inverted normals would take no paint at all under the camera-facing test. The sign is now derived per dab from the face actually under the cursor, which is demonstrably one the user can see.
  • Empty layers rendered opaque thumbnails: the thumbnail pass inherited the renderer's ambient clear color (typically opaque black) instead of clearing transparent, so a layer with no content showed a solid filled square that implied it had some.
  • Edge Wear texture scale defaulted to 1.0, which read as an extreme zoom against the rest of the app's tiling convention; it now defaults to 8.0.