# Box shadow in Makie

**URL:** <https://discourse.julialang.org/t/box-shadow-in-makie/136064>\
**Category:** Visualization\
**Tags:** makie\
**Created:** [March 6, 2026, 10:57am UTC](https://discourse.julialang.org/t/box-shadow-in-makie/136064 "2026-03-06T10:57:36Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![klafyvel](https://avatars.discourse-cdn.com/v4/letter/k/a587f6/32.png) [@klafyvel](https://discourse.julialang.org/u/klafyvel)\
**Post date:** [March 6, 2026, 10:57am UTC](https://discourse.julialang.org/t/box-shadow-in-makie/136064/1 "2026-03-06T10:57:36Z")

</div>

Hi!  
I am a big fan of de-marking boxes from their background using box shadows. Is there a way to do that in Makie?  
Thanks for the help!

---

<div class="post-metadata">

**Author:** ![klafyvel](https://avatars.discourse-cdn.com/v4/letter/k/a587f6/32.png) [@klafyvel](https://discourse.julialang.org/u/klafyvel)\
**Post date:** [March 20, 2026, 10:52am UTC](https://discourse.julialang.org/t/box-shadow-in-makie/136064/2 "2026-03-20T10:52:29Z")

</div>

After studying a bit how to use `mesh` and thanks to the help of @asinghvi17 on slack, I manage to get a solution that works!

 ![image](https://global.discourse-cdn.com/julialang/original/3X/7/f/7f14506a55a6dde99efa5c6c69f51093dc90e698.png)

This was generated using the following code:

> **Summary**
>
> ```julia
> using CairoMakie, Colors
> 
> function generate_arc(radius, θ₀, θ₁, n_points=50)
> @assert n_points ≥ 2 "n_points must be ≥ 2"
> θs = range(start=θ₀, stop=θ₁, length=n_points)
> vertices = [[0.0; cos.(θs)...] [0.0;sin.(θs)]]
> faces = [ones(Int, n_points-1) 2:(n_points) 3:(n_points+1)]
> return vertices .* radius, faces
> end
> 
> function generate_box_shadow(width, height, extent=0.1*(width+height)/2; n_points=5, dark=RGBA(0.0, 0.0, 0.0, 0.5), light=RGBA(0.0, 0.0, 0.0, 0.0))
> bottom_left_vertices, bottom_left_faces = generate_arc(extent, π, 3π/2, n_points)
> bottom_right_vertices, bottom_right_faces = generate_arc(extent, -π/2, 0.0, n_points)
> top_right_vertices, top_right_faces = generate_arc(extent, 0.0, π/2, n_points)
> top_left_vertices, top_left_faces = generate_arc(extent, π/2, π, n_points)
> bottom_right_vertices = bottom_right_vertices + repeat([width 0], n_points+1)
> top_right_vertices = top_right_vertices + repeat([width height], n_points+1)
> top_left_vertices = top_left_vertices + repeat([0 height], n_points+1)
> vertices = [bottom_left_vertices; bottom_right_vertices; top_right_vertices; top_left_vertices]
> face1 = [1 n_points+1 n_points+3]
> face2 = [1 n_points+3 n_points+2]
> faces = [
> bottom_left_faces; 
> face1;
> face2;
> bottom_right_faces .+ (n_points+1);
> face1 .+ (n_points+1);
> face2 .+ (n_points+1);
> top_right_faces .+ 2(n_points+1);
> face1 .+ 2(n_points+1);
> face2 .+ 2(n_points+1);
> top_left_faces .+ 3(n_points+1);
> [3(n_points+1)+1 4(n_points+1) 2];
> [3(n_points+1)+1 2 1];
> ]
> colors = repeat([dark; fill(light, n_points);], 4)
> return vertices, faces, colors
> end
> 
> function shadow(obj; extent=5, dark=RGBA(0.0, 0.0, 0.0, 0.5), padding=(5,5,5,5), meshkw=(;))
> padding_left, padding_right, padding_bottom, padding_top = padding
> inner_box = map(viewport(obj), obj.layoutobservables.protrusions) do v, protrusions
> x,y = v.origin
> w,h = v.widths
> left = protrusions.left
> right = protrusions.right
> top = protrusions.top
> bottom = protrusions.bottom
> Rect2{Int}(
> (x - left - padding_left, y - bottom - padding_bottom), 
> (
> w + left + right + padding_left + padding_right , 
> h + bottom + top + padding_bottom + padding_top
> )
> )
> end
> outer_box = map(inner_box) do v
> x,y = v.origin
> w,h = v.widths
> Rect2{Int}(
> (x - extent, y - extent), 
> ( w + 2extent, h + 2extent)
> )
> end
> mesh = map(inner_box) do v
> widths = v.widths
> vertices, faces, colors = generate_box_shadow(widths[1], widths[2], extent; n_points=5, dark)
> vertices = vertices .+ repeat([extent extent], size(vertices, 1))
> (;vertices, faces, colors)
> end
> vertices = map(mesh) do m
> m.vertices
> end
> faces = map(mesh) do m
> m.faces
> end
> colors = map(mesh) do m
> m.colors
> end
> t = obj.scene
> while !isnothing(t.parent)
> t = t.parent
> end
> Box(t, color=:white, bbox=inner_box, strokevisible=false)
> inset = LScene(t,
> scenekw = (camera = campixel!,),
> bbox=outer_box,
> )
> mesh!(inset, vertices, faces; color = colors, meshkw...)
> translate!(inset.scene, 0, 0, 100)
> inset
> end
> 
> let
> fig, ax, p = lines(-3π..3π, sin)
> ax_inset = Axis(fig[1, 1],
> width=Relative(0.2),
> height=Relative(0.2),
> halign=0.15,
> valign=0.9,
> spinewidth=0.2,
> )
> translate!(ax_inset.blockscene, 0, 0, 150)
> lines!(ax_inset, -3π..3π, cos)
> s = shadow(ax_inset, extent=5, padding=(5, 10, 5, 5), meshkw=(rasterize=4,), dark=RGBA(0.1, 0.1, 0.1, 0.25))
> display(fig)
> end
> 
> ```

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [March 20, 2026, 11:14am UTC](https://discourse.julialang.org/t/box-shadow-in-makie/136064/3 "2026-03-20T11:14:14Z")

</div>

The problem is that meshes in CairoMakie are drawn triangle after triangle so you get ugly seams when you have transparency involved, as the pixels get more saturated there.

---

<div class="post-metadata">

**Author:** ![klafyvel](https://avatars.discourse-cdn.com/v4/letter/k/a587f6/32.png) [@klafyvel](https://discourse.julialang.org/u/klafyvel)\
**Post date:** [March 20, 2026, 11:35am UTC](https://discourse.julialang.org/t/box-shadow-in-makie/136064/4 "2026-03-20T11:35:39Z")

</div>

Yep, I noticed… I guess I could render the shadow in GLMakie then display it as an image, or use GLMakie for this specific figure.

Edit: or by accepting to become a criminal and offsetting the position of the nodes by \varepsilon to avoid seams

---

<div class="post-metadata">

**Author:** ![tp2750](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tp2750/32/207806_2.png) [@tp2750](https://discourse.julialang.org/u/tp2750)\
**Post date:** [March 21, 2026, 4:00am UTC](https://discourse.julialang.org/t/box-shadow-in-makie/136064/5 "2026-03-21T04:00:23Z")

</div>

This looks awesome.  
Are you planning to package this up to make it more accessible?

---

<div class="post-metadata">

**Author:** ![klafyvel](https://avatars.discourse-cdn.com/v4/letter/k/a587f6/32.png) [@klafyvel](https://discourse.julialang.org/u/klafyvel)\
**Post date:** [March 23, 2026, 12:01pm UTC](https://discourse.julialang.org/t/box-shadow-in-makie/136064/6 "2026-03-23T12:01:53Z")

</div>

I can make PR to Makie’s repo, but would it be accepted despite the mesh artifact in CairoMakie? Which parameters would be interesting to keep / to add?
