# Render Nine Patch Bug Fix

**URL:** <https://forum.babylonjs.com/t/render-nine-patch-bug-fix/60043>\
**Category:** Bugs\
**Created:** [August 13, 2025, 11:00am UTC](https://forum.babylonjs.com/t/render-nine-patch-bug-fix/60043 "2025-08-13T11:00:35Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![MackeyK24](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/mackeyk24/32/3741_2.png) [@MackeyK24](https://forum.babylonjs.com/u/MackeyK24)\
**Post date:** [August 13, 2025, 11:00am UTC](https://forum.babylonjs.com/t/render-nine-patch-bug-fix/60043/1 "2025-08-13T11:00:36Z")

</div>

So there is a bug with the Image.\_renderNinePatch when:

There is an ADT idealWidth/Height and you use Image.width/Height percentages:

First playground shows WITHOUT ADT idealWidth/Height and borders look great, properly stretched:

> **[Babylon.js Playground](https://playground.babylonjs.com/#O5AWUX)**
>
> Babylon.js playground is a live editor for Babylon.js WebGL and WebGPU 3D scenes

Second playground shows WITH ADT idealWidth/Height and BORDERS ARE CROPPED OUT:

> **[Babylon.js Playground](https://playground.babylonjs.com/#O5AWUX%231)**
>
> Babylon.js playground is a live editor for Babylon.js WebGL and WebGPU 3D scenes

So I had devin.ai track down and fix the issue. And it fixed it perfectly.

> <https://github.com/BabylonJS/Babylon.js/pull/17018>
>
> Fix nine-patch rendering for BABYLON.GUI.Image when width/height are percentages… and ADT has idealWidth/idealHeight. The old code used ValueAndUnit.getValue(this.host) (raw %) for idealRatio; the fix uses resolved pixels from \_currentMeasure.
> 
> Root cause
> 
> \_renderNinePatch used this.\_width.getValue(this.host)/idealWidth (and height variant). For percentage sizes, getValue(host) is normalized, not pixels, collapsing slice scaling when ideal\* is set.
> Fix (2 lines)
> 
> Compute idealRatio from resolved measure:
> 
> const idealRatio = this.host.idealWidth
> 
> ? this.\_currentMeasure.width / this.host.idealWidth
> 
> : this.host.idealHeight ? this.\_currentMeasure.height / this.host.idealHeight : 1;
> 
> Safety
> 
> \_currentMeasure is the resolved pixel size post-layout, so pixel-sized images are unchanged; nine-patch math/draw remains identical otherwise.
> Repro (before fix)
> 
> ADT with idealWidth or idealHeight
> 
> Image: stretch = Image.STRETCH\_NINE\_PATCH, width = "100%", height = "100%", slice props or populateNinePatchSlicesFromImage = true
> 
> Borders disappear/crop with % sizing; OK with px.
> 
> After fix
> 
> Borders render correctly with % sizing and ADT ideal\*.

We need a fix for nine-patch rendering for BABYLON.GUI.Image when width/height are percentages and ADT has idealWidth/idealHeight.

The current code uses ValueAndUnit.getValue(this.host) (raw %) for idealRatio; the fix is to use resolved pixels from \_currentMeasure.

Root cause

- \_renderNinePatch used this.\_width.getValue(this.host)/idealWidth (and height variant). For percentage sizes, getValue(host) is normalized, not pixels, collapsing slice scaling when ideal\* is set.

Fix (2 lines)

- Compute idealRatio from resolved measure:

Safety

- \_currentMeasure is the resolved pixel size post-layout, so pixel-sized images are unchanged; nine-patch math/draw remains identical otherwise.

Repro (before fix)

- ADT with idealWidth or idealHeight

- Image: stretch = Image.STRETCH\_NINE\_PATCH, width = “100%”, height = “100%”, slice props or populateNinePatchSlicesFromImage = true

- Borders disappear/crop with % sizing; OK with px.

After fix

- Borders render correctly with % sizing and ADT ideal\*.

---

<div class="post-metadata">

**Author:** ![Deltakosh](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/deltakosh/32/26635_2.png) [@Deltakosh](https://forum.babylonjs.com/u/Deltakosh)\
**Post date:** [August 13, 2025, 4:10pm UTC](https://forum.babylonjs.com/t/render-nine-patch-bug-fix/60043/2 "2025-08-13T16:10:04Z")

</div>

cc @georgie

---

<div class="post-metadata">

**Author:** ![georgie](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/georgie/32/46049_2.png) [@georgie](https://forum.babylonjs.com/u/georgie)\
**Post date:** [August 13, 2025, 7:59pm UTC](https://forum.babylonjs.com/t/render-nine-patch-bug-fix/60043/4 "2025-08-13T19:59:56Z")

</div>

thank you for the fix @MackeyK24 ! Approved 🙂

---

<div class="post-metadata">

**Author:** ![MackeyK24](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/mackeyk24/32/3741_2.png) [@MackeyK24](https://forum.babylonjs.com/u/MackeyK24)\
**Post date:** [August 14, 2025, 7:25am UTC](https://forum.babylonjs.com/t/render-nine-patch-bug-fix/60043/5 "2025-08-14T07:25:00Z")

</div>

I think the calculation for idealRatio is not quite right, it should be more like the ADT.idealRatio or better yet , just use the `this.host.idealRatio` instead of recalculating that when the adt already has it calculated correctly:

 ![Screenshot 2025-08-13 at 9.25.31 PM](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/b/3/b326d476940040bd085dad27103cda918aa18fd8.png)

Or maybe not, what do you think @georgie ?

---

<div class="post-metadata">

**Author:** ![georgie](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/georgie/32/46049_2.png) [@georgie](https://forum.babylonjs.com/u/georgie)\
**Post date:** [August 14, 2025, 2:10pm UTC](https://forum.babylonjs.com/t/render-nine-patch-bug-fix/60043/6 "2025-08-14T14:10:47Z")

</div>

Doing some debugging I see that from within image class if i set idealWidth then this.host.idealRatio matches the calc in image because image.currentMeasure.width === adt.getSize().width (1713)

 ![image](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/0/8/08ac3dc8e7c9455660f4290597ff5ddfae4d96fc.png)

However if i set idealHeight instead, I’m seeing different results , where the idealRatios dont match because image.\_currentMeasure.height != adt.getSize().height

 ![image](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/0/6/06177899be979de84c1e9a7d90be7ea8a8c8908d.png)

I also see that when calculating currentMeasure, the ‘cx’ control has width/height ispixel true, while the ‘but’ has them as false

 ![image](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/4/7/4715af5e46a8a1d920a9042e912fa6b9ba499072.png)

Honestly I’m not 100% sure whether we should be using the currentMeasure height or the ADT height – but they do produce slightly different visual results  
currentMeasure

 ![image](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/4/4/444890ccea02a80292db979d5ad96648f1b19c52.png)

 ![host](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/a/d/adb73e07775ccd5a8d83740cb4357ab54406cdb2.png)

If i compare to the asset itself,it does seem like the bottom image (using host idealRatio) is more true to what we’d want  
[panel.9.png (446×446)](https://www.babylontoolkit.com/images/panel.9.png)

If you agree, please submit a PR that updates the image to use ADT’s idealRatio if it exists!

---

<div class="post-metadata">

**Author:** ![MackeyK24](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/mackeyk24/32/3741_2.png) [@MackeyK24](https://forum.babylonjs.com/u/MackeyK24)\
**Post date:** [August 14, 2025, 5:08pm UTC](https://forum.babylonjs.com/t/render-nine-patch-bug-fix/60043/7 "2025-08-14T17:08:33Z")

</div>

Hey @georgie

I am not a big fan of the syntax, but i am just following the existing pattern.

So how does this look to you:

 ![Screenshot 2025-08-14 at 7.07.41 AM](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/4/5/4575a990c600f1cfba0bc48c578daace7090e70a.png)

> <https://github.com/BabylonJS/Babylon.js/pull/17028>
>
> This address the ideal ratio calculation for nine sliced image support.
> 
> https…://forum.babylonjs.com/t/render-nine-patch-bug-fix/60043/6
> 
> Summary
> 
> Fix nine-patch rendering for BABYLON.GUI.Image when width/height are percentages and ADT has idealWidth/idealHeight. The old code used ValueAndUnit.getValue(this.host) (raw %) for idealRatio; the fix uses resolved pixels from \_currentMeasure.
> 
> Root cause
> 
> \_renderNinePatch used this.\_width.getValue(this.host)/idealWidth (and height variant). For percentage sizes, getValue(host) is normalized, not pixels, collapsing slice scaling when ideal\* is set.
> Fix (2 lines)
> 
> Compute idealRatio from resolved measure:
> 
> const idealRatio = this.host.idealRatio
> ? this.host.idealRatio
> : this.host.idealWidth
> ? this.\_currentMeasure.width / this.host.idealWidth
> : this.host.idealHeight
> ? this.\_currentMeasure.height / this.host.idealHeight
> : 1;
> Safety
> 
> Try ADT idealRatio first, then \_currentMeasure is the resolved pixel size post-layout, so pixel-sized images are unchanged; nine-patch math/draw remains identical otherwise.
> Repro (before fix)
> 
> ADT with idealWidth or idealHeight
> 
> Image: stretch = Image.STRETCH\_NINE\_PATCH, width = "100%", height = "100%", slice props or populateNinePatchSlicesFromImage = true
> 
> Borders disappear/crop with % sizing; OK with px.
> 
> After fix
> 
> Borders render correctly with % sizing and ADT idealRatio

---

<div class="post-metadata">

**Author:** ![georgie](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/georgie/32/46049_2.png) [@georgie](https://forum.babylonjs.com/u/georgie)\
**Post date:** [August 14, 2025, 8:26pm UTC](https://forum.babylonjs.com/t/render-nine-patch-bug-fix/60043/8 "2025-08-14T20:26:08Z")

</div>

Lots of back and forth on these PRs, sorry about that! Here is the fix, thank you for raising it / solving 🙂

[Fix RenderNinePatch bug in GUI image by georginahalpern · Pull Request #17030 · BabylonJS/Babylon.js](https://github.com/BabylonJS/Babylon.js/pull/17030)

---

<div class="post-metadata">

**Author:** ![MackeyK24](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/mackeyk24/32/3741_2.png) [@MackeyK24](https://forum.babylonjs.com/u/MackeyK24)\
**Post date:** [August 14, 2025, 8:36pm UTC](https://forum.babylonjs.com/t/render-nine-patch-bug-fix/60043/9 "2025-08-14T20:36:03Z")

</div>

Thank you @georgie
