diff --git a/deploy/img/dev/img-buf1.png b/deploy/img/dev/img-buf1.png
new file mode 100644
index 0000000..324c4b4
Binary files /dev/null and b/deploy/img/dev/img-buf1.png differ
diff --git a/deploy/img/dev/img-buf2.png b/deploy/img/dev/img-buf2.png
new file mode 100644
index 0000000..5ff99e2
Binary files /dev/null and b/deploy/img/dev/img-buf2.png differ
diff --git a/deploy/img/dev/img-buf3.png b/deploy/img/dev/img-buf3.png
new file mode 100644
index 0000000..ef9d33f
Binary files /dev/null and b/deploy/img/dev/img-buf3.png differ
diff --git a/deploy/img/dev/img-buf4.png b/deploy/img/dev/img-buf4.png
new file mode 100644
index 0000000..82a7a43
Binary files /dev/null and b/deploy/img/dev/img-buf4.png differ
diff --git a/src/dev.md b/src/dev.md
new file mode 100644
index 0000000..d548c96
--- /dev/null
+++ b/src/dev.md
@@ -0,0 +1,58 @@
+# Developer Section
+
+1. [Image Buffers](#img-buf)
+
+# 1. Image Buffers {#img-buf}
+
+Ref: [#2489](https://github.com/labwc/labwc/pull/2489)
+
+This relates to the structs `lab_img`, `lab_image_cache` and
+`scaled_img_buffer`.
+
+- When creating a `scaled_img_buffer`, `lab_img` is replicated via
+ `lab_img_copy()`
+- When destroying a `scaled_img_buffer`, `lab_img` is destroyed via
+ `lab_img_destroy()`
+
+## The lifetime of `lab_img` and `lab_img_cache`
+
+After startup, theme struct references `lab_img`, which references
+`lab_img_cache` with refcount=1. Here, `lab_img_cache` is the wrapper for
+`lab_data_buffer` or `RsvgHandle` and represents the actual content of the
+loaded image file.
+
+
+
+When a window is opened and its decoration is created, the `lab_img` is copied
+via `lab_img_copy()` and a new `scaled_img_buffer` references it. Note that the
+image content is not copied here; instead, the refcount of `lab_img_cache` is
+incremented.
+
+
+
+When the theme is de-initialized in `theme_finish()` and the `lab_img`
+referenced by theme is destroyed, the `lab_img` referenced by the
+`scaled_img_buffer` and `lab_img_cache` outlive. Therefore, it's safe for
+`_update_buffer()` in `scaled-img-buffer.c` to be called.
+
+
+
+And when the decoration is destroyed via undecorate(), the `scaled_img_buffer`,
+`lab_img` and `lab_img_cache` are finally destroyed.
+
+## Motivation for `lab_img_copy()` and `lab_img_cache`
+
+For better understanding of `lab_img` API in general, let me explain the initial
+motivation of `lab_img_copy()` and `lab_img_cache`. `lab_img_copy()` was
+introduced to share the image content with different variants of buttons
+including normal, hovered, rounded, rounded-hovered buttons:
+
+
+
+For example, when `close_hover-active.png` is not found, the `lab_img` for
+`close-active.png` is copied via `lab_img_copy()` and a "modifier" function
+that draws a hover overlay on it is added to the copied `lab_img` via
+`lab_img_add_modifier()`. And if the close button is placed at the corner of
+the titlebar, the `lab_img` is further copied and the modifier function that
+cuts its corner is applied.
+
diff --git a/src/more.md b/src/more.md
index df134fc..4b09e49 100644
--- a/src/more.md
+++ b/src/more.md
@@ -1,4 +1,5 @@
- [configuration](configuration.html)
+- [dev](dev.html)
- [faq](faq.html)
- [hidpi scaling](hidpi-scaling.html)
- [links](links.html)