{"version":"https://jsonfeed.org/version/1.1","title":"Polygonjs releases","description":"What changed in each release of the Polygonjs engine and editor.","home_page_url":"https://polygonjs.com/changelog","feed_url":"https://polygonjs.com/changelog.json","language":"en","items":[{"id":"https://polygonjs.com/changelog/2.0.60","url":"https://polygonjs.com/changelog/2.0.60","title":"2.0.60: Control panels, reference links, transform nodes","summary":"Control panels, reference links, transform nodes","content_html":"<div class=\"markdown\">\n<ul class=\"my-6 space-y-3\">\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span><code>geo/TransformOrigin</code> and <code>geo/TransformFit</code> are removed, to be replaced by 3 new nodes. <code>geo/TransformPivot</code> to move a pivot. <code>geo/TransformAlign</code> to translate/rotate/scale relative to dimensions of another object. <code>geo/BoundsCheck</code> to ensure an object fits given bounds.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span>The <code>direction</code> is removed from 2D primitive nodes: <code>geo/Circle</code>, <code>geo/M2DCircle</code> and <code>geo/M2DPlane</code>. <code>center</code> and <code>twist</code> are now baked into the points and the object matrix stays identity. This ensures <code>geo/Mirror</code> or <code>geo/Clip</code> reads the geometry where it is. To aim the plane somewhere other than XY, put a <code>geo/Transform</code> in OBJECT mode after the primitive. <code>geo/Line</code> with no input went the same way: its <code>origin</code> and <code>direction</code> are two numbers each now, and the straight line it draws lives in XY.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/ControlPanel</code> draws a panel of controls over the viewer, in the editor and in a runtime build, with no UI code. See example <a href=\"https://polygonjs.com/examples/control-panel\">control-panel</a>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>The network panel draws reference links: a faded arrow between two nodes when a parameter on one refers to the other.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/TransformAlign</code> translates/rotates/scales input objects relative to given dimensions of another object.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/TransformLayout</code> arranges the input’s objects side by side.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/TransformPivot</code> moves an object’s pivot without moving the object.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/BoundsCheck</code> measures the input against a target box.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>mat/MeshSDF</code> allows fine-tuning how SDF objects are rendered.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/Mirror</code> reflects an SDF field, across the same plane. <code>geo/SDFMirror</code> is still the other operation on a field: it folds the field across the origin planes and costs no duplicated subtree.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/SDFTriangulate</code> runs in the browser on the GPU, and samples the field in slices so a large grid does not have to fit in one dispatch.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>A web build carries less code: a scene with no light drops the lighting models, a scene whose lights cast no shadow drops the shadow functions, and the area light tables load only when an area light is registered.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>Ctrl+Enter submits a multi-line text field, so an expression typed over several lines is applied without reaching for the mouse.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>A spare parameter can be renamed, and the expressions that read it are rewritten to the new name instead of breaking.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/Delete</code>, <code>geo/Clean</code> and <code>geo/Clip</code> gained <code>keepUnreferencedPoints</code>, which keeps the points the surviving primitives no longer use instead of dropping them with the primitives that owned them. <code>geo/Clip</code> also cuts 2D geometry now.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/Connectivity</code> splits segments, triangles, quads, hexagons and tetrahedra, refuses a point cloud instead of answering with one object per point, and says what to convert first when it is handed a NURBS or a CAD shape. <code>geo/ManifoldDisplay</code> reports the same facts from the other side.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>The geometry spreadsheet shows each object’s translate, rotate and scale.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/DimensionDisplay</code> scales its ticks with its text, so a dimension stays readable at any size.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/DXFExporter</code> defaults to the XY plane, which is the plane a DXF is read in.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>The quad nodes preserve primitive attributes through <code>geo/QuadSubdivide</code> and <code>geo/Quadrangulate</code>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Scene time ran slow in a browser, at 96% of wall time at 60 Hz and 86% at 144 Hz, because every frame’s delta was floored to a whole millisecond. The clock now carries the remainder and an animation runs at 100% of wall time. The time that expressions and shaders read now wraps every 2048 seconds, so it keeps its precision however long a session runs.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>A bypassed <code>geo/Output</code> no longer commits its inputs to the scene graph, so bypassing it really does hide what it was showing.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>A <code>geo/Subnet</code> whose output node is added after the subnet was created now cooks.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>The network panel’s “Display Help” toggle was not saved with the scene.</span>\n      </li>\n</ul>\n\n</div>\n","date_published":"2026-09-11T00:00:00+00:00","tags":["breaking","new","improved","fixed"]},{"id":"https://polygonjs.com/changelog/2.0.59","url":"https://polygonjs.com/changelog/2.0.59","title":"2.0.59: SDF deformers, screw threads, GPU meshing","summary":"SDF deformers, screw threads, GPU meshing","content_html":"<div class=\"markdown\">\n<ul class=\"my-6 space-y-3\">\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span><code>geo/SDFRound</code> is now <code>geo/SDFOffset</code>, and <code>code/SDFRound</code> is <code>code/SDFOffset</code>. I had chosen the previous name poorly, this one fits what the node does.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/SDFTwist</code> turns a Field about an axis, <code>geo/SDFBend</code> wraps it around one, and <code>geo/SDFPolarRepeat</code> copies it around one. It’s very useful to bend text on a cylinder for instance: <a href=\"https://polygonjs.com/examples/sdf-bend-text-on-cylinder\">sdf-bend-text-on-cylinder</a>, to build a <a href=\"https://polygonjs.com/examples/sdf-twist-pillar\">twisted pillar</a>, or a <a href=\"https://polygonjs.com/examples/sdf-polar-repeat\">gear</a>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/SDFThread</code> is a polynode (a node made of node), showing a receipe to make a thread. <a href=\"https://polygonjs.com/examples/sdf-thread-bolt-and-nut\">sdf-thread-bolt-and-nut</a>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>The <code>code/SDF*</code> set now mirrors <code>geo/SDF*</code> one for one, with <code>code/SDFTube</code>, <code>SDFHexPrism</code>, <code>SDFTriPrism</code>, <code>SDFSolidAngle</code>, <code>SDFElongate</code>, <code>SDFImprint</code>, <code>SDFSeam</code>, <code>SDFExtrude</code> and <code>SDFRevolve</code> added. Anything you can build with the <code>geo/SDF*</code> nodes you can now build inside a <code>geo/SDFBuilder</code>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/SDFBuilder</code> can now modify an input field, not just generate one. <a href=\"https://polygonjs.com/examples/sdf-builder-rock\">sdf-builder-rock</a>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/SDFCreate</code> can save the generated grid to disk and reload it. This is useful when building it from a high resolution geometry takes time: <a href=\"https://polygonjs.com/examples/sdf-grid-cache\">sdf-grid-cache</a>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/SDFCreate</code> accepts curves. <a href=\"https://polygonjs.com/examples/sdf-curve-tube\">sdf-curve-tube</a>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/CurveProperties</code> allows you to open or close an input curve.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/M2DStroke</code> gives an open curve a width, so a polyline becomes a 2D region the rest of the M2D family can extrude, offset or triangulate.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/SDFTriangulate</code> can sample the field on the graphics card.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/SDFRevolve</code> gains <code>helical</code> and <code>pitch</code>, so the revolve climbs as it turns instead of closing on itself. That is what <code>geo/SDFThread</code> is built on.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/Line</code> takes an input and joins its points into a polyline, one per object, in the order they arrive and with nothing else done to them. A 2D input gives a 2D polyline. <code>geo/Add</code> into <code>geo/Line</code> is the shortest route from a few hand-placed positions to something drawable.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/Curve</code> builds a curve from positions typed into the node, with no input at all.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>Seven <code>code/SDF*</code> nodes gained the viewport handle their <code>geo/SDF*</code> twin already had: the 2D family (<code>SDFBox2D</code>, <code>SDFCircle2D</code>, <code>SDFEllipse2D</code>, <code>SDFEquilateralTriangle2D</code>, <code>SDFHexagon2D</code>), <code>SDFSegment2D</code> and <code>SDFTransform</code>. A field built inside a <code>geo/SDFBuilder</code> is now dragged the same way as one built from the geo nodes.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>The editor’s Memory panel reports what each node holds, broken down by category and sortable by column, so the node behind a large scene is findable.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Importing a binary STL built every triangle from the first three points, so a file came in as a single sliver and nothing else. Only the first face was ever right.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>a crash when extracting a subnet from the network panel’s context menu. Typing into an integer parameter read the text as a float.</span>\n      </li>\n</ul>\n\n</div>\n","date_published":"2026-09-04T00:00:00+00:00","tags":["breaking","new","improved","fixed"]},{"id":"https://polygonjs.com/changelog/2.0.58","url":"https://polygonjs.com/changelog/2.0.58","title":"2.0.58: SDF modeling, exporters, environment lighting","summary":"SDF modeling, exporters, environment lighting","content_html":"<div class=\"markdown\">\n<ul class=\"my-6 space-y-3\">\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span>The primitives take their sweep angles in DEGREES. <code>geo/Sphere</code> (<code>phiStart</code>, <code>phiLength</code>, <code>thetaStart</code>, <code>thetaLength</code>), <code>geo/Tube</code> and <code>geo/Capsule</code> (<code>thetaStart</code>, <code>thetaLength</code>) and <code>geo/Torus</code> (<code>arc</code>) all used radians. A saved scene keeps the number it stored, so a half sweep that read 3.14 now reads as 3.14 degrees. Retype the angle you want: a full turn is 360.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span>A partial sweep needs the new <code>open</code> toggle. <code>geo/Sphere</code>, <code>geo/Tube</code>, <code>geo/Capsule</code> and <code>geo/Torus</code> only cut their sweep when <code>open</code> is on, so a scene that cut it with the angle alone comes back whole. Turn <code>open</code> on.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span><code>geo/Tube</code>’s <code>openEnded</code> is now <code>caps</code>, which means the opposite and is on by default. A scene that had <code>openEnded</code> on loses that setting and gets its caps back, so turn <code>caps</code> off.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span>The manifold primitives are always built about their own middle. <code>geo/M3DBox</code> and <code>geo/M3DTube</code> lose <code>centered</code>, and <code>geo/M2DPlane</code>’s <code>center</code> changes from a toggle to an in-plane offset. Offset them with <code>center</code>, which a translate manipulator now drags in the viewer. <code>geo/Circle</code>’s <code>center</code> is a 2D offset in the circle’s own plane rather than a 3D position.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span>A light’s <code>lightSize</code> is merged into <code>softness</code>. One number now sizes the PCF blur, the PCSS penumbra and the shadow an SDF object marches for itself, and it is a fraction of the light’s frustum rather than a count of shadow-map texels. Raising the shadow resolution no longer narrows the soft edge. Retune <code>softness</code> on lights that had it set.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span><code>geo/ManifoldDebug</code> is now <code>geo/ManifoldDisplay</code>, and it reports an error rather than only drawing. A scene saved with the old node drops it on load, so rebuild it.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>Model with signed distance fields. The <code>geo/SDF*</code> nodes are out: primitives (<code>SDFSphere</code>, <code>SDFBox</code>, <code>SDFBoxFrame</code>, <code>SDFCapsule</code>, <code>SDFTorus</code>, <code>SDFTube</code>, <code>SDFRoundCone</code>, <code>SDFEllipsoid</code>, <code>SDFOctahedron</code>, <code>SDFPyramid</code>, <code>SDFTriPrism</code>, <code>SDFHexPrism</code>, <code>SDFPlane</code>, <code>SDFSolidAngle</code>), their 2D counterparts (<code>SDFCircle</code>, <code>SDFBox2D</code>, <code>SDFEllipse2D</code>, <code>SDFHexagon2D</code>, <code>SDFEquilateralTriangle2D</code>, <code>SDFSegment2D</code>), <code>geo/SDFBoolean</code> for union, subtraction and intersection with a hard, rounded or chamfered seam, and the shaping nodes <code>SDFRound</code>, <code>SDFOnion</code>, <code>SDFElongate</code>, <code>SDFMirror</code>, <code>SDFRepeat</code>, <code>SDFExtrude</code>, <code>SDFRevolve</code> and <code>SDFSlice</code>. An SDF object is raymarched in the viewer, so you shape the field itself and only turn it into a mesh when you want one. Start from <a href=\"https://polygonjs.com/examples/sdf-boolean-basic\">SDF Boolean Basic</a>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/SDFImprint</code> marks one SDF object with another: a raised pad, a recess, a groove or an engraving. <code>geo/SDFSeam</code> builds the joint between two of them as a solid rod, for a weld bead, a piping or a trim line. Each SDF primitive carries its own colour, roughness and metalness, so a boolean keeps every part looking like itself: <a href=\"https://polygonjs.com/examples/sdf-boolean-with-different-colors\">SDF Boolean with different colors</a>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/SDFTriangulate</code> converts an SDF back to a mesh, to a closed solid, or, from a 2D field, to its outline. It marches on a cell count or a cell size, takes an <code>isoValue</code> to grow or shrink the surface, and its solid output goes straight into the exporters: <a href=\"https://polygonjs.com/examples/sdf-3d-printing-vase-basic\">SDF for 3D printing</a>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/SDFCreate</code> turns real geometry into a field, so a mesh can be blended, hollowed or imprinted like a primitive. <code>geo/SDFBuilder</code> defines a field from the <code>code/SDF*</code> nodes inside it, for a shape none of the primitives cover.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>Four exporters. <code>geo/GLTFExporter</code> writes binary glTF (.glb) with per-object transforms and material colours, <a href=\"https://polygonjs.com/examples/export-gltf\">export-gltf</a>. <code>geo/ThreeMFExporter</code> writes 3MF with units, several objects and colour, <a href=\"https://polygonjs.com/examples/export-3mf\">export-3mf</a>. <code>geo/OBJExporter</code> writes Wavefront OBJ with one named block per object, <a href=\"https://polygonjs.com/examples/export-obj\">export-obj</a>. <code>geo/DXFExporter</code> writes DXF R12 for laser cutters and CNC, with cut and engrave lines on separate layers, <a href=\"https://polygonjs.com/examples/export-dxf\">export-dxf</a>. PLY and STL merge their input objects so nothing is silently left out: <a href=\"https://polygonjs.com/examples/export-ply\">export-ply</a>, <a href=\"https://polygonjs.com/examples/export-stl\">export-stl</a>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>The <code>geo/PrinterPrepare</code> polynode puts a model in the state a printer expects, in one node: it checks the model is a closed solid, turns the scene’s Y-up into the Z-up every slicer reads, scales the scene unit into millimetres, and measures the result against the build volume. It errors before an exporter writes a file that cannot be printed.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/Environment</code> lights the whole scene from one environment map, with a background mode to show it or hide it. The <code>geo/EnvironmentHelper</code> polynode puts a mirror ball and a matte grey ball in the scene so you can read what the map is doing. <code>tex/FileHDR</code> loads Radiance .hdr files, and the editor gets an HDRI and EXR picker with real image previews.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/MaterialAttributes</code> sets colour, roughness, metallic and emission on geometry in one node, and those attributes survive a manifold boolean.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>The <code>geo/DimensionDisplay</code> polynode writes a part’s size beside it, per axis, in millimetres and inches, which is the readout someone wants before downloading a file: <a href=\"https://polygonjs.com/examples/dimension-display\">showing a part’s size</a>. <code>geo/DimensionPromote</code> converts geometry between 2D and 3D.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/FileOBJ</code> imports Wavefront .obj geometry, with presets. <code>tex/Color</code> fills a texture with a flat colour, for any input that wants a texture but only needs a constant. <code>geo/VolumeSmooth</code> smooths a volume’s voxel values.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>render/Taa</code> is available, to allow temporal antialiasing. It’s currently useful to have smooth edges when modeling with SDF nodes.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>A glTF compressed with Draco or meshopt now imports. 2.0.57 refused those files with an error naming the extension, which is still what happens for an extension Polygon does not support.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>A node can WARN as well as error. A warning marks the node and reaches the logger without stopping the graph, and <code>geo/AttributeDisplay</code> is the first to use it. A polynode also surfaces the error of the node inside it rather than failing silently.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>Expressions do more. <code>bbox()</code> and <code>centroid()</code> take a node path, so <code>bbox(\"/geo1/box1\").size.x</code> reads another node’s bounds. <code>format(value, decimals)</code> turns a number into a string, which is what lets a <code>StringParam</code> read <code>\"X \" + format(bbox(\"/box1\").size.x, 1) + \" mm\"</code>. A cycle between expressions is detected and reported instead of looping.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/GroupCreate</code> gains <code>byPattern</code>: build a group from the members of groups that already exist, or by entity index, using the same syntax as any other group field.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>Manipulators translate on the XY plane, and the manifold primitives carry one for <code>center</code>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/Text</code> gains vertical alignment, handles line breaks properly, and describes itself in the help panel.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/Merge</code> preserves the object groups of its inputs. <code>geo/Delete</code> no longer clones its input, so it is faster on large scenes. <code>geo/Wireframe</code> emits one segment per edge rather than one per half edge. <code>geo/Clip</code> interpolates attributes across the cut.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/SceneGLTF</code> references nodes by relative path, names and lays out the generated sub-graph better, and gets a flight helmet preset.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>The 3MF export carries colour, writes the tags Bambu Studio reads, and drops its pretty printing to keep files small.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>code/TextureSample2D</code> gains <code>mipMapBias</code>, and the <code>code</code> context gets divide and invert through MathBinary and MathUnary.</span>\n      </li>\n</ul>\n\n  <details class=\"my-6 text-base\">\n    <summary class=\"cursor-pointer text-fg-muted\">Also in this release</summary>\n    <ul class=\"mt-3 ml-5 list-disc space-y-2\">\n        <li>The wireframe hotkey is G, and Shift+G walks the cycle backwards. It was Ctrl+W, which browsers take to close the tab, so it never worked on the web.</li>\n        <li>Fixed: a crash when creating a node with Enter from the tab menu, a crash when dropping a polynode with no inputs onto a connection, a crash when clicking a read-only panel in the LLM tab, and a crash on resize in the web build, which the blog embeds were hitting.</li>\n        <li>Fixed: the colour picker did not match the colour it was editing when used for the renderer background. A node context menu could be opened from outside the network panel. Renderer leaks and a double free on the GPU side.</li>\n    </ul>\n  </details>\n</div>\n","date_published":"2026-08-28T00:00:00+00:00","tags":["breaking","new","improved"]},{"id":"https://polygonjs.com/changelog/2.0.57","url":"https://polygonjs.com/changelog/2.0.57","title":"2.0.57: Extrude inset, polyWire follows edges, glTF fixes","summary":"Extrude inset, polyWire follows edges, glTF fixes","content_html":"<div class=\"markdown\">\n<ul class=\"my-6 space-y-3\">\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span><code>geo/PolyWire</code> follows the edges of its input instead of sweeping through the points in order. Separate curves inside one object are no longer stitched end to start, and separate input objects come out as separate meshes. A point cloud with no edges still sweeps through its points in order, so that case is unchanged.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span><code>geo/MergeCompact</code> is gone. It is now a <code>compact</code> toggle on <code>geo/Merge</code>, off by default, with <code>computeNormals</code> beside it. Existing Merge nodes behave exactly as before. A scene saved with a MergeCompact drops that node on load, so rebuild it as a Merge with <code>compact</code> on. The compact path gains what Merge already had: the per-input toggles apply, stage attributes carry through, and lights, cameras and controls pass through instead of being swallowed.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/Extrude</code> gets an <code>inset</code> param. It tapers the extrusion inwards by a distance measured perpendicular to each edge, so the inset edges stay parallel to the ones they came from. Negative values widen it instead. Feed the mesh through <code>geo/Facet</code> with <code>splitAllFaces</code> first and every face becomes its own panel with a tapered rim.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>Ctrl+Down sends the playhead back to the start of the play range. If the scene is playing, it pauses instead.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/PolyWire</code> tubes a mesh or a grid wireframe correctly: mitered rings through bends, a ball at every junction where three or more edges meet, flat caps at loose ends, and a frame that no longer rolls along a long curve.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/Extrude</code> handles quad meshes, and a quad mesh stays a quad mesh. A new <code>computeNormals</code> toggle, on by default, recomputes the normals from the extruded result rather than keeping the input’s, which described the input and not the extrusion.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/Extrude</code> keeps primitive attributes. The bottom, the top and every side wall inherit the attributes of the face they came from.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/Facet</code> works on quad and hexa meshes. Both <code>splitAllFaces</code> and the angle threshold apply, and the node never triangulates: a quad mesh stays quads and a hexa mesh stays hexa.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>A glTF that requires an extension Polygon does not support is refused with an error naming it, instead of reading compressed bytes as geometry. Draco and meshopt exports are the common case. Re-export without compression.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/SceneGLTF</code> maps glTF’s <code>doubleSided</code> onto the generated <code>mat/MeshPBR</code>’s <code>sides</code> param, so imported foliage, cloth and thin panels are no longer invisible from the back.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/SceneGLTF</code> builds a remote asset on a single press of Build. The node reports that it is fetching while the download runs, then generates the sub-graph on its own as one undoable step, and clears its error once the build succeeds.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>Framing the camera skips lights and helpers, so it frames your geometry instead of pulling back to include a distant light. The <code>frameObjects</code> default on the camera control nodes is now <code>* ^grid* ^*Camera* ^*Light* ^*Helper*</code>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>The material nodes carry help. <code>mat/MeshPBR</code>, <code>MeshPhong</code>, <code>MeshLambert</code>, <code>MeshNormal</code>, <code>MeshGrid</code>, <code>MeshBasicTexture</code>, <code>MeshBasicDepthTexture</code>, <code>Sky</code>, <code>Volume</code>, <code>Voxel</code> and <code>RaymarchingBuilder</code> all describe themselves and their params in the panel.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Soft shadows no longer show acne as <code>softness</code> goes up on a spotlight or a directional light. Two related artifacts go with it: a dark band at the edge of a light’s shadow map, and shadow bleeding in from a light packed beside it in the atlas.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>The <code>geo/SpotLight</code> helper draws the cone at the angle the light actually covers. It used to draw it about half as wide.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Deleting a node no longer crashes the editor when work was already queued for it that frame, such as a dirty node inside an open <code>MAT</code> network, or a node that had just errored.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span><code>geo/HexaPlane</code> outputs a normal attribute. It carried none.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Triangulating a hexa or a quad mesh gives the added centre points their own attributes, the average of the corners they sit between. They used to carry an unrelated source point’s uv and colour, and a hexa mesh could read past the end of its attribute buffers.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Normals computed on a quad or a hexa mesh point outwards. They came out inverted relative to the triangles on screen.</span>\n      </li>\n</ul>\n\n  <details class=\"my-6 text-base\">\n    <summary class=\"cursor-pointer text-fg-muted\">Also in this release</summary>\n    <ul class=\"mt-3 ml-5 list-disc space-y-2\">\n        <li>Transform gizmos from nodes selected inside a subnet no longer stay on screen after you leave it, when the selection was larger than the number of gizmos the editor displays at once.</li>\n        <li><code>mat/MeshBasicTexture</code> and <code>mat/MeshBasicDepthTexture</code> use the alpha of their <code>color</code> param as an overall opacity, on top of the texture’s own alpha.</li>\n        <li><code>geo/Copy</code>, <code>geo/ObjectProperties</code> and <code>geo/PhysicsRBDAttributes</code> show their key values under the node in the network panel.</li>\n        <li><code>geo/PolyWire</code>’s <code>radius</code> goes past 1, up to 10 and beyond.</li>\n    </ul>\n  </details>\n</div>\n","date_published":"2026-08-13T00:00:00+00:00","tags":["breaking","new","improved","fixed"]},{"id":"https://polygonjs.com/changelog/2.0.56","url":"https://polygonjs.com/changelog/2.0.56","title":"2.0.56: Transparency modes, colour palettes, cursor-driven compute","summary":"Transparency modes, colour palettes, cursor-driven compute","content_html":"<div class=\"markdown\">\n<ul class=\"my-6 space-y-3\">\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span>The <code>advanced</code> toggle and the depth params behind it are gone from the <code>mat/*</code> nodes. Use the new <code>transparencyMode</code> instead: <code>OPAQUE</code> keeps a material out of the transparent pass, <code>BLEND</code> puts it in. <code>AUTO</code> will infer what is needed on most cases.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span>The <code>USE_OIT</code> object attribute is now <code>TRANSPARENCY_MODE</code>, and it holds a mode rather than a flag. Rename it in your scenes and set it to <code>BLEND</code> where it used to be true. Similar to the material, <code>AUTO</code> will infer what is needed on most cases.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span>Type-specific params on the <code>code/*</code> nodes now carry an underscore. <code>code/Clamp.inputFloat</code> is <code>input_Float</code>, and <code>geo/AttributeCreate.valueFloat</code> is <code>value_Float</code>. Saved scenes need those names updated by hand, there is no migration yet.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>Every material has a <code>transparencyMode</code>: <code>AUTO</code>, <code>OPAQUE</code>, <code>MASK</code> or <code>BLEND</code>. An alpha below 1 now does something on every material, not only on the few that happened to implement it. The names match glTF <code>alphaMode</code>, and <code>geo/SceneGLTF</code> maps an imported one straight onto it.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>MASK</code> mode and the new <code>alphaCutoff</code> param give hard-edged cutouts that still write depth, so cutouts occlude each other correctly. <code>mat/MeshBuilder</code> carries it today.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/ObjectProperties</code> sets <code>transparencyMode</code> per object, so one material can serve both opaque and transparent objects.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>Materials have a <code>sides</code> param: front, back or both.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>tex/Palette</code> generates a colour palette and bakes it into a 1D texture. Hue travels an eased cycle while saturation and lightness sweep eased ranges, in OKLCH for perceptually even steps or in plain HSL. The result comes out as hard blocks or as a gradient blended in OKLab.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>The cursor and its ray are available inside compute and GPU shaders, alongside a new <code>code/RayClosestPoint</code>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>One wasm build can drive several scenes on the same page, each with its own canvas, camera and pointer input. The editor stays single-scene and switches itself off when a page holds more than one.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/M2DBoolean</code> and <code>geo/M3DBoolean</code> get a mode. Either pair each shape from input 0 with its counterpart in input 1, or batch every shape from both inputs into a single result.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/AttributeCreate</code> and the <code>code/*</code> nodes handle <code>S8</code>, <code>S32</code> and <code>U8</code> attributes.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>The alpha of a <code>mat/MeshBuilder</code> can drive its shadow, so a faded or cut-out surface casts a matching one.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>tex/Image</code> comes with presets.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>Hovering a param in the params panel shows its help as a tooltip. Polynodes carry help of their own now, so the panel is no longer blank on them.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>Hovering a connector in the network panel raises its label, so it is readable over the nodes behind it.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>The <code>group</code> param sits nearer the top of <code>geo/Transform</code>, <code>geo/Material</code>, <code>geo/CADExtrude</code> and <code>geo/CADRevolve</code>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>Errors coming out of a wasm build report a usable stack trace.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>Crash logs can be uploaded from canvas and SDK builds, not only from the editor.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>code/Compare</code> and <code>code/TwoWaySwitch</code> start on more useful default values.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Textures fed to <code>mat/MeshBuilder</code> have their colour space managed, so an sRGB image no longer renders with the wrong colours.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Deleting a node inside a <code>code</code> network no longer crashes the editor.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Custom attribute names, defined in the SDK, appear in the attribute name menus again, and they serialize correctly from the nodes that create them.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>File &gt; Save As was missing from SDK builds.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Images loaded in wasm keep their alpha channel.</span>\n      </li>\n</ul>\n\n</div>\n","date_published":"2026-08-12T00:00:00+00:00","tags":["breaking","new","improved","fixed"]},{"id":"https://polygonjs.com/changelog/2.0.55","url":"https://polygonjs.com/changelog/2.0.55","title":"2.0.55: minor fixes","summary":"minor fixes","content_html":"<div class=\"markdown\">\n<ul class=\"my-6 space-y-3\">\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>When opening the examples panel on windows, there are no more spawned extra windows (which happened due to child processes downloading the thumbnails).</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>When using the cursor to drive an object, the cursor would be clamped to the viewer bounds. This is not the case anymore.</span>\n      </li>\n</ul>\n\n</div>\n","date_published":"2026-08-08T00:00:00+00:00","tags":["fixed"]},{"id":"https://polygonjs.com/changelog/2.0.54","url":"https://polygonjs.com/changelog/2.0.54","title":"2.0.54: autoplay for embedded scenes","summary":"autoplay for embedded scenes","content_html":"<div class=\"markdown\">\n<ul class=\"my-6 space-y-3\">\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>An embedded scene can start playing as soon as it loads: pass <code>autoplay: true</code> to <code>polygonAppInit</code> next to the scene data. Without it the scene sits on frame 0, which makes a solver or an <code>OnTick</code> actor look like a still image on a page with no transport controls.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>The example pages on polygonjs.com no longer show the default scene’s box sitting in the middle of the example. The box is bypassed, not deleted, so un-bypassing it brings it back.</span>\n      </li>\n</ul>\n\n</div>\n","date_published":"2026-08-08T00:00:00+00:00","tags":["new","fixed"]},{"id":"https://polygonjs.com/changelog/2.0.53","url":"https://polygonjs.com/changelog/2.0.53","title":"2.0.53: Cursor-driven physics, render/Combine, shadow fixes","summary":"Cursor-driven physics, render/Combine, shadow fixes","content_html":"<div class=\"markdown\">\n<ul class=\"my-6 space-y-3\">\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span><code>render/Add</code>, <code>render/Multiply</code> and <code>render/Composite</code> are replaced by one <code>render/Combine</code>, whose <code>operation</code> param is ADD, MULTIPLY or OVER. Scenes using the old nodes need the node swapped by hand.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span><code>mat/MeshInstance</code> is gone. Instances are drawn by <code>mat/MeshBuilder</code> with a <code>code/Instance</code> node inside, which is the graph <code>geo/Instance</code> now builds for you.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>A rigid body can be kinematic, driven from an actor with <code>code/SetObjectPosition</code> or <code>code/SetObjectAttribute</code>. It pushes the dynamic bodies around, so you can shove a simulation with the cursor.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>Cursor nodes: <code>code/Cursor</code>, <code>code/CursorRay</code>, <code>code/Ray</code>, <code>code/Plane</code> and <code>code/RayPlaneIntersect</code>, to turn a pointer into a position in the scene.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>compute/Subnet</code> and <code>compute/PolyNode</code>: group compute nodes together, and save the group as a node you can reuse.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>render/Combine</code> works on WebGL2. Where there are no compute shaders it runs the same operation as a fullscreen pass, and the image is the same.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>An embedded scene can be unmounted and remounted from JavaScript, so a page can put a scene away and bring it back.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>New example: many rigid bodies you can push around with the cursor.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>The command line downloads the SDK without a login.</span>\n      </li>\n</ul>\n\n</div>\n","date_published":"2026-08-08T00:00:00+00:00","tags":["breaking","new"]},{"id":"https://polygonjs.com/changelog/2.0.49","url":"https://polygonjs.com/changelog/2.0.49","title":"2.0.49: Decimate, embedded text fonts, error propagation","summary":"Decimate, embedded text fonts, error propagation","content_html":"<div class=\"markdown\">\n<ul class=\"my-6 space-y-3\">\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-red-400 dark:bg-red-700\">Breaking</span>\n        <span><code>code/Negate</code>, <code>code/Complement</code>, <code>code/Pow</code> and <code>code/Normalize</code> are merged into the node <code>code/MathUnary</code>. Typing the old name in the tab menu still creates it, but scenes saved with the old node types will not load. We don’t have a migration system yet, so this may require manual update in the scene file for now.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>geo/Decimate</code>: reduce a mesh’s triangle count, either as a fraction of the input or to an absolute triangle count, with boundary locking, small-component pruning and a maximum-error budget.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>Chrome-less fullscreen viewer. Toggle it in the viewer and save the scene, and it reopens with no editor UI around it.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/Text</code> embeds its font, so text renders with no external font file to ship or find.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>Errors travel through the graph: a node whose input is errored reports it, referencing an errored node is itself an error, and the network panel tells you when you are inside one.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>The web editor reports its loading progress and fetches a gzipped payload, so the first frame arrives sooner.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>Network panel: improve snapping.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>Normals are computed whenever a material needs them, including through <code>geo/CageDeform</code>. No more black shading on deformed geometry.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/HexaPlane</code> now faces +Y by default.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Nodes inside a bypassed subnet no longer cook.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span><code>geo/PLYExporter</code> and <code>geo/VolumeExporter</code> preserve the object’s transform.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Object transforms are no longer read before they are up to date, which could place geometry a frame behind.</span>\n      </li>\n</ul>\n\n  <details class=\"my-6 text-base\">\n    <summary class=\"cursor-pointer text-fg-muted\">Also in this release</summary>\n    <ul class=\"mt-3 ml-5 list-disc space-y-2\">\n        <li><code>geo/Text</code>’s secondary parameters are simplified.</li>\n        <li>Dropdown styling and window corners are consistent across the editor.</li>\n    </ul>\n  </details>\n</div>\n","date_published":"2026-08-01T00:00:00+00:00","tags":["breaking","new","improved","fixed"]},{"id":"https://polygonjs.com/changelog/2.0.46","url":"https://polygonjs.com/changelog/2.0.46","title":"2.0.46: Drag-to-connect network panel, voxel surface offsets","summary":"Drag-to-connect network panel, voxel surface offsets","content_html":"<div class=\"markdown\">\n<ul class=\"my-6 space-y-3\">\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>Drag a node over another and hold for a moment, they connect, with no aiming at a connector.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>Shake a node (or a whole selection) mid-drag to pull it out of the graph: the boundary edges drop and the chain heals behind it, so <code>a → x → c</code> becomes <code>a → c</code>.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span><code>surfaceOffset</code> on <code>geo/MeshToVoxel</code> and <code>geo/VoxelCreate</code>: shift the iso-surface the voxels are built from: negative erodes so the voxels sit inside the real surface, positive dilates for a thicker shell or to close thin features.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>Connecting nodes no longer needs a precise cursor: connectors snap from a distance, the wire you are dragging previews the connector the drop will actually use, and the snap still works when zoomed out.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span>A whole node drag is a single undo step, however many connect, disconnect and splice actions it fired along the way.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-sky-400 dark:bg-sky-700\">Improved</span>\n        <span><code>geo/MeshToVoxel</code> voxelizes box-shaped meshes far more faithfully.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Undoing while dragging a node no longer crashes the editor.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Setting a node path, asset path or string parameter to an empty string resets it to its default, instead of leaving an empty reference that could not resolve and broke code export.</span>\n      </li>\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-emerald-400 dark:bg-emerald-700\">Fixed</span>\n        <span>Node paths and asset paths are trimmed, so a path pasted with a stray leading or trailing space still resolves.</span>\n      </li>\n</ul>\n\n  <details class=\"my-6 text-base\">\n    <summary class=\"cursor-pointer text-fg-muted\">Also in this release</summary>\n    <ul class=\"mt-3 ml-5 list-disc space-y-2\">\n        <li>PolyNode spare parameters and the parameters declared by a PolyNode definition now stay in step with each other, including through save, reload and regeneration.</li>\n    </ul>\n  </details>\n</div>\n","date_published":"2026-07-29T00:00:00+00:00","tags":["new","improved","fixed"]},{"id":"https://polygonjs.com/changelog/2.0.45","url":"https://polygonjs.com/changelog/2.0.45","title":"2.0.45: First public version of Polygon V2","summary":"First public version of Polygon V2","content_html":"<div class=\"markdown\">\n<ul class=\"my-6 space-y-3\">\n      <li class=\"flex gap-3 items-baseline\">\n        <span class=\"inline-block shrink-0 w-24 text-center text-xs uppercase tracking-wide rounded-full px-2 py-0.5 bg-green-40 dark:bg-green-700\">New</span>\n        <span>Polygon V2 is a complete rewrite of v1, that can run and build for native &amp; web.</span>\n      </li>\n</ul>\n\n</div>\n","date_published":"2026-07-28T00:00:00+00:00","tags":["new"]}]}