diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Revision history for granite
 
+## 0.7.1.0 -- 2026-05-25
+
+* Numeric `aesAlpha` mappings are now honoured for points (per-point opacity); previously only the per-layer `defAlpha` was applied.
+
 ## 0.7.0.0 -- 2026-05-24
 
 * `Color` is now a 24-bit RGB value, and categorical colour mappings are honoured for points.
diff --git a/granite.cabal b/granite.cabal
--- a/granite.cabal
+++ b/granite.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               granite
-version:            0.7.0.0
+version:            0.7.1.0
 synopsis:           Easy terminal plotting.
 description:        A terminal plotting library for quick and easy visualisation.
 license:            MIT
diff --git a/src/Granite/Render/Pipeline.hs b/src/Granite/Render/Pipeline.hs
--- a/src/Granite/Render/Pipeline.hs
+++ b/src/Granite/Render/Pipeline.hs
@@ -440,8 +440,16 @@
                 | Just cats <- categoricalColorColumn frame m ->
                     map (\cat -> specToColor (fromMaybe colorSpec (lookup cat levelColors))) cats
             _ -> repeat col
+        pointAlphas = case resolveNumColumn frame (aesAlpha m) of
+            Just vs@(_ : _) ->
+                let lo = minimum vs
+                    hi = maximum vs
+                 in if hi <= lo
+                        then repeat alpha
+                        else map (\v -> 0.15 + 0.85 * (v - lo) / (hi - lo)) vs
+            _ -> repeat alpha
      in case layerGeom layer of
-            GeomPoint -> drawPoints proj frame m pointColors radius alpha
+            GeomPoint -> drawPoints proj frame m pointColors radius pointAlphas
             GeomLine -> drawLine proj frame m colorSpec lineW
             GeomBar -> drawBars proj frame m col
             GeomCol -> drawBars proj frame m col
@@ -460,9 +468,9 @@
     Mapping ->
     [Color] ->
     Double ->
-    Double ->
+    [Double] ->
     [Mark]
-drawPoints proj frame m cols r alpha =
+drawPoints proj frame m cols r alphas =
     case (resolveNumColumn frame (aesX m), resolveNumColumn frame (aesY m)) of
         (Just xv, Just yv) ->
             [ MCircle
@@ -470,9 +478,9 @@
                 r
                 defaultStyle
                     { styleFill = Just c
-                    , styleFillOpacity = alpha
+                    , styleFillOpacity = a
                     }
-            | ((x, y), c) <- zip (zip xv yv) cols
+            | ((x, y), c, a) <- zip3 (zip xv yv) cols alphas
             ]
         _ -> []
 
diff --git a/test/GoldenSpec.hs b/test/GoldenSpec.hs
--- a/test/GoldenSpec.hs
+++ b/test/GoldenSpec.hs
@@ -63,6 +63,32 @@
         ]
         (Just "Random points")
 
+-- A scatter whose point opacity is driven by a numeric column via 'aesAlpha':
+-- low weight -> faint, high weight -> opaque. Locks in per-point alpha.
+alphaScatter :: Chart
+alphaScatter =
+    let df =
+            fromColumns
+                [ ("x", ColNum [0, 1, 2, 3, 4])
+                , ("y", ColNum [0, 1, 2, 3, 4])
+                , ("w", ColNum [1, 2, 3, 4, 5])
+                ]
+        layer =
+            (defLayer GeomPoint)
+                { layerMapping =
+                    emptyMapping
+                        { aesX = Just (ColumnRef "x")
+                        , aesY = Just (ColumnRef "y")
+                        , aesAlpha = Just (ColumnRef "w")
+                        }
+                }
+     in emptyChart
+            { chartData = df
+            , chartLayers = [layer]
+            , chartTitle = Just "Alpha by weight"
+            , chartSize = SizeChars 40 14
+            }
+
 singleSeriesLine :: Chart
 singleSeriesLine =
     lineChart
@@ -295,6 +321,9 @@
 
         it "no-title scatter renders to expected SVG output" $
             goldenText "scatter-no-title.svg" (renderChartSvg noTitleScatter)
+
+        it "alpha-mapped scatter renders to expected SVG output" $
+            goldenText "scatter-alpha.svg" (renderChartSvg alphaScatter)
 
     describe "Line chart" $ do
         it "single-series line renders to expected terminal output" $
diff --git a/test/golden/scatter-alpha.svg b/test/golden/scatter-alpha.svg
new file mode 100644
--- /dev/null
+++ b/test/golden/scatter-alpha.svg
@@ -0,0 +1,23 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 224" width="400" height="224" font-family="system-ui, -apple-system, sans-serif">
+<rect width="100%" height="100%" fill="white"/>
+<line x1="55" y1="196.20" x2="280" y2="196.20" stroke="#ecf0f1" stroke-width="1"/>
+<line x1="55" y1="34" x2="55" y2="196.20" stroke="#ecf0f1" stroke-width="1"/>
+<text x="65.23" y="211.20" text-anchor="middle" fill="#7f8c8d" font-size="11">0.0</text>
+<text x="116.36" y="211.20" text-anchor="middle" fill="#7f8c8d" font-size="11">1.0</text>
+<text x="167.50" y="211.20" text-anchor="middle" fill="#7f8c8d" font-size="11">2.0</text>
+<text x="218.64" y="211.20" text-anchor="middle" fill="#7f8c8d" font-size="11">3.0</text>
+<text x="269.77" y="211.20" text-anchor="middle" fill="#7f8c8d" font-size="11">4.0</text>
+<text x="49" y="192.49" text-anchor="end" fill="#7f8c8d" font-size="11">0.0</text>
+<text x="49" y="155.63" text-anchor="end" fill="#7f8c8d" font-size="11">1.0</text>
+<text x="49" y="118.77" text-anchor="end" fill="#7f8c8d" font-size="11">2.0</text>
+<text x="49" y="81.90" text-anchor="end" fill="#7f8c8d" font-size="11">3.0</text>
+<text x="49" y="45.04" text-anchor="end" fill="#7f8c8d" font-size="11">4.0</text>
+<circle cx="65.23" cy="188.83" r="3" fill="#3498db" fill-opacity="0.15"/>
+<circle cx="116.36" cy="151.96" r="3" fill="#3498db" fill-opacity="0.36"/>
+<circle cx="167.50" cy="115.10" r="3" fill="#3498db" fill-opacity="0.58"/>
+<circle cx="218.64" cy="78.24" r="3" fill="#3498db" fill-opacity="0.79"/>
+<circle cx="269.77" cy="41.37" r="3" fill="#3498db"/>
+<text x="167.50" y="26" text-anchor="middle" fill="#7f8c8d" font-size="14">Alpha by weight</text>
+<rect x="295" y="39" width="12" height="12" fill="#3498db"/>
+<text x="311" y="49" text-anchor="start" fill="#7f8c8d" font-size="11">series 0</text>
+</svg>
