diff --git a/README.md b/README.md
index 28b35e6fc6..328e2f69d6 100644
--- a/README.md
+++ b/README.md
@@ -208,7 +208,7 @@ single-purpose layout types like sequence diagrams. You can choose whichever lay
you like and works best for the diagram you're making.
Sketch-mode rendering uses [rough-go](https://github.com/d2lang/rough-go), a native Go
-port of Rough.js 4.0.4.
+compatibility port of the Rough.js 4.6.6 rendering surface used by D2.
LaTeX labels use [mathjax-go](https://github.com/d2lang/mathjax-go), a native Go port of
the MathJax 3.2.2 TeX-to-SVG pipeline.
diff --git a/THIRD_PARTY_NOTICES.txt b/THIRD_PARTY_NOTICES.txt
index c650257cbb..897338c6e3 100644
--- a/THIRD_PARTY_NOTICES.txt
+++ b/THIRD_PARTY_NOTICES.txt
@@ -41,15 +41,26 @@ SOFTWARE.
Rough-go
https://github.com/d2lang/rough-go
-Rough-go is a native Go port of Rough.js 4.0.4. The port is based on:
+Rough-go is a native Go compatibility port of the Rough.js 4.6.6 rendering
+surface used by D2. The port is based on:
- Rough.js 4.0.4
+ Rough.js 4.6.6
https://github.com/rough-stuff/rough
- commit 35302b8f1119ad004b4550f9a4d4162d3d845b0a
+ commit 56a2762171b1294d643501e8d14f120db6b27bd7
+
+It also derives implementation details from:
+
+ hachure-fill 0.5.2, Copyright (c) 2023 Preet Shihn
+ path-data-parser 0.1.0, Copyright (c) 2020 Preet Shihn
+
+All three upstream projects are licensed under the MIT License reproduced
+below.
MIT License
Copyright (c) 2019 Preet Shihn
+Copyright (c) 2020 Preet Shihn
+Copyright (c) 2023 Preet Shihn
Copyright (c) 2026 rough-go contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md
index cb2380f1ef..8be4b7d323 100644
--- a/ci/release/changelogs/next.md
+++ b/ci/release/changelogs/next.md
@@ -9,7 +9,7 @@
- maintenance: update the Go toolchain to 1.26.5 and refresh Go, d2.js, CI, and release dependencies
- renders: update syntax highlighting and migrate archived font and PDF dependencies to maintained replacements
- d2dagre: replace the embedded JavaScript runtime with native Go Dagro and update its D2-used layout surface from Dagre 0.8.5 to Dagre 3.1.1 behavior. This intentionally changes node ordering and coordinates, edge routes, self-loops, and compound sizing in some diagrams; regenerate and review stored SVG or board-JSON snapshots
-- d2sketch: replace the embedded Rough.js runtime with the native Go rough-go port without changing sketch output
+- d2sketch: update the native rough-go renderer from Rough.js 4.0.4 to 4.6.6 behavior. Seeded sketch strokes, fills, arrowheads, and SVG paths may change; regenerate and review stored sketch SVG snapshots
- d2elk: replace the embedded ELK.js 0.8.2 runtime with native Go elk-go and update D2's ELK layout profile to ELK.js 0.12.0 behavior. This is a layout-behavior update, not an output-compatible runtime swap:
- existing ELK diagrams may receive different node coordinates and ordering, edge and label routes, and component packing; regenerate and review stored SVG or board-JSON snapshots
- children of nested compound graphs may be reordered because ELK 0.12 cannot safely apply D2's previous nested model-order profile
diff --git a/d2js/js/THIRD_PARTY_NOTICES.txt b/d2js/js/THIRD_PARTY_NOTICES.txt
index c650257cbb..897338c6e3 100644
--- a/d2js/js/THIRD_PARTY_NOTICES.txt
+++ b/d2js/js/THIRD_PARTY_NOTICES.txt
@@ -41,15 +41,26 @@ SOFTWARE.
Rough-go
https://github.com/d2lang/rough-go
-Rough-go is a native Go port of Rough.js 4.0.4. The port is based on:
+Rough-go is a native Go compatibility port of the Rough.js 4.6.6 rendering
+surface used by D2. The port is based on:
- Rough.js 4.0.4
+ Rough.js 4.6.6
https://github.com/rough-stuff/rough
- commit 35302b8f1119ad004b4550f9a4d4162d3d845b0a
+ commit 56a2762171b1294d643501e8d14f120db6b27bd7
+
+It also derives implementation details from:
+
+ hachure-fill 0.5.2, Copyright (c) 2023 Preet Shihn
+ path-data-parser 0.1.0, Copyright (c) 2020 Preet Shihn
+
+All three upstream projects are licensed under the MIT License reproduced
+below.
MIT License
Copyright (c) 2019 Preet Shihn
+Copyright (c) 2020 Preet Shihn
+Copyright (c) 2023 Preet Shihn
Copyright (c) 2026 rough-go contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/d2renderers/d2sketch/NOTICE.txt b/d2renderers/d2sketch/NOTICE.txt
index 5ceedefc35..e9591c9c51 100644
--- a/d2renderers/d2sketch/NOTICE.txt
+++ b/d2renderers/d2sketch/NOTICE.txt
@@ -1,4 +1,5 @@
-The native sketch renderer uses rough-go, a Go port of Rough.js 4.0.4.
+The native sketch renderer uses rough-go, a Go compatibility port of the
+Rough.js 4.6.6 rendering surface used by D2.
Source and license details are included in the repository-root
THIRD_PARTY_NOTICES.txt and in https://github.com/d2lang/rough-go.
diff --git a/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg b/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg
index bef2bae33e..e82556df55 100644
--- a/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg
@@ -101,7 +101,7 @@
-rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud
+rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/all_shapes_dark/sketch.exp.svg b/d2renderers/d2sketch/testdata/all_shapes_dark/sketch.exp.svg
index 3074d375d0..d8d670f068 100644
--- a/d2renderers/d2sketch/testdata/all_shapes_dark/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/all_shapes_dark/sketch.exp.svg
@@ -98,7 +98,7 @@
-rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud
+rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/arrowheads/sketch.exp.svg b/d2renderers/d2sketch/testdata/arrowheads/sketch.exp.svg
index 7107387fbc..506291ee05 100644
--- a/d2renderers/d2sketch/testdata/arrowheads/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/arrowheads/sketch.exp.svg
@@ -108,7 +108,7 @@
-11223344556677889910101111nonearrowtrianglediamonddiamond filledcf-manycf-many-requiredcf-onecf-one-requiredboxbox-filled
+11223344556677889910101111nonearrowtrianglediamonddiamond filledcf-manycf-many-requiredcf-onecf-one-requiredboxbox-filled
diff --git a/d2renderers/d2sketch/testdata/arrowheads_dark/sketch.exp.svg b/d2renderers/d2sketch/testdata/arrowheads_dark/sketch.exp.svg
index fe8bb4c517..e627dd033f 100644
--- a/d2renderers/d2sketch/testdata/arrowheads_dark/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/arrowheads_dark/sketch.exp.svg
@@ -105,7 +105,7 @@
-112233445566778899nonearrowtrianglediamonddiamond filledcf-manycf-many-requiredcf-onecf-one-required
+112233445566778899nonearrowtrianglediamonddiamond filledcf-manycf-many-requiredcf-onecf-one-required
diff --git a/d2renderers/d2sketch/testdata/basic/sketch.exp.svg b/d2renderers/d2sketch/testdata/basic/sketch.exp.svg
index 05dcc94b16..cca09f1e44 100644
--- a/d2renderers/d2sketch/testdata/basic/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/basic/sketch.exp.svg
@@ -101,7 +101,7 @@
-ab
+ab
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/basic_dark/sketch.exp.svg b/d2renderers/d2sketch/testdata/basic_dark/sketch.exp.svg
index eeb1e09a1f..6ce1ff79cf 100644
--- a/d2renderers/d2sketch/testdata/basic_dark/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/basic_dark/sketch.exp.svg
@@ -98,7 +98,7 @@
-ab
+ab
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/border-container/sketch.exp.svg b/d2renderers/d2sketch/testdata/border-container/sketch.exp.svg
index c479d85343..84432694f8 100644
--- a/d2renderers/d2sketch/testdata/border-container/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/border-container/sketch.exp.svg
@@ -156,7 +156,7 @@
-YOUR ENVIRONMENTYOUR APPLICATONWORKFLOWSDKWORKERSHELLO
+YOUR ENVIRONMENTYOUR APPLICATONWORKFLOWSDKWORKERSHELLO
diff --git a/d2renderers/d2sketch/testdata/child_to_child/sketch.exp.svg b/d2renderers/d2sketch/testdata/child_to_child/sketch.exp.svg
index 339cd631cf..63ba148066 100644
--- a/d2renderers/d2sketch/testdata/child_to_child/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/child_to_child/sketch.exp.svg
@@ -108,7 +108,7 @@
-wintersummersnowsun
+wintersummersnowsun
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/child_to_child_dark/sketch.exp.svg b/d2renderers/d2sketch/testdata/child_to_child_dark/sketch.exp.svg
index 6dd44a6cea..bc6cb03be1 100644
--- a/d2renderers/d2sketch/testdata/child_to_child_dark/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/child_to_child_dark/sketch.exp.svg
@@ -105,7 +105,7 @@
-wintersummersnowsun
+wintersummersnowsun
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/class/sketch.exp.svg b/d2renderers/d2sketch/testdata/class/sketch.exp.svg
index 19274028b3..54957dee90 100644
--- a/d2renderers/d2sketch/testdata/class/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/class/sketch.exp.svg
@@ -101,7 +101,7 @@
-BatchManager-numint-timeoutint-pid+getStatus()Enum+getJobs()Job[]+setTimeout(seconds int)void
+BatchManager-numint-timeoutint-pid+getStatus()Enum+getJobs()Job[]+setTimeout(seconds int)void
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/class_dark/sketch.exp.svg b/d2renderers/d2sketch/testdata/class_dark/sketch.exp.svg
index 4fc3075e47..5f0d7bd980 100644
--- a/d2renderers/d2sketch/testdata/class_dark/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/class_dark/sketch.exp.svg
@@ -98,7 +98,7 @@
-BatchManager-numint-timeoutint-pid+getStatus()Enum+getJobs()Job[]+setTimeout(seconds int)void
+BatchManager-numint-timeoutint-pid+getStatus()Enum+getJobs()Job[]+setTimeout(seconds int)void
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/connection-style-fill/sketch.exp.svg b/d2renderers/d2sketch/testdata/connection-style-fill/sketch.exp.svg
index a474363db0..4fcc43f6f0 100644
--- a/d2renderers/d2sketch/testdata/connection-style-fill/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/connection-style-fill/sketch.exp.svg
@@ -108,7 +108,7 @@
-customeremployeerentalitemrent(this, i, p)new(this, i, p)isValid()isRentable(c)is(Adult)true
+customeremployeerentalitemrent(this, i, p)new(this, i, p)isValid()isRentable(c)is(Adult)true
diff --git a/d2renderers/d2sketch/testdata/connection_label/sketch.exp.svg b/d2renderers/d2sketch/testdata/connection_label/sketch.exp.svg
index 94df53c967..da5ca87d9f 100644
--- a/d2renderers/d2sketch/testdata/connection_label/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/connection_label/sketch.exp.svg
@@ -108,7 +108,7 @@
-abhello
+abhello
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/connection_label_dark/sketch.exp.svg b/d2renderers/d2sketch/testdata/connection_label_dark/sketch.exp.svg
index 014edd5426..b58b86f63b 100644
--- a/d2renderers/d2sketch/testdata/connection_label_dark/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/connection_label_dark/sketch.exp.svg
@@ -105,7 +105,7 @@
-abhello
+abhello
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/crows_feet/sketch.exp.svg b/d2renderers/d2sketch/testdata/crows_feet/sketch.exp.svg
index bdb88bf16c..2abf224fe0 100644
--- a/d2renderers/d2sketch/testdata/crows_feet/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/crows_feet/sketch.exp.svg
@@ -101,7 +101,7 @@
-a1b1a2b2a3b3c1d1c2d2c3d3e1f1e2f2e3f3g1h1g2h2g3h3cdf
+a1b1a2b2a3b3c1d1c2d2c3d3e1f1e2f2e3f3g1h1g2h2g3h3cdf
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/crows_feet_dark/sketch.exp.svg b/d2renderers/d2sketch/testdata/crows_feet_dark/sketch.exp.svg
index edab52eaa2..0314c4d3bf 100644
--- a/d2renderers/d2sketch/testdata/crows_feet_dark/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/crows_feet_dark/sketch.exp.svg
@@ -98,7 +98,7 @@
-a1b1a2b2a3b3c1d1c2d2c3d3e1f1e2f2e3f3g1h1g2h2g3h3cdf
+a1b1a2b2a3b3c1d1c2d2c3d3e1f1e2f2e3f3g1h1g2h2g3h3cdf
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/dots-all/sketch.exp.svg b/d2renderers/d2sketch/testdata/dots-all/sketch.exp.svg
index 3216883fc9..ecfad51822 100644
--- a/d2renderers/d2sketch/testdata/dots-all/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/dots-all/sketch.exp.svg
@@ -134,7 +134,7 @@
-rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud
+rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/dots-multiple/sketch.exp.svg b/d2renderers/d2sketch/testdata/dots-multiple/sketch.exp.svg
index ed5a8515e7..156af5161d 100644
--- a/d2renderers/d2sketch/testdata/dots-multiple/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/dots-multiple/sketch.exp.svg
@@ -134,7 +134,7 @@
-rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud
+rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/dots-real/sketch.exp.svg b/d2renderers/d2sketch/testdata/dots-real/sketch.exp.svg
index f0fbf6fad3..9c73c48fe9 100644
--- a/d2renderers/d2sketch/testdata/dots-real/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/dots-real/sketch.exp.svg
@@ -170,7 +170,7 @@
-NETWORKD2 Parser+readerio.RuneReader+readerPosd2ast.Position-lookahead[]rune#peekn(n int)(s string, eof bool)+peek()(r rune, eof bool)+rewind()void+commit()voidCELL TOWERSATELLITESTRANSMITTERSENDSENDSEND
+NETWORKD2 Parser+readerio.RuneReader+readerPosd2ast.Position-lookahead[]rune#peekn(n int)(s string, eof bool)+peek()(r rune, eof bool)+rewind()void+commit()voidCELL TOWERSATELLITESTRANSMITTERSENDSENDSEND
diff --git a/d2renderers/d2sketch/testdata/double-border/sketch.exp.svg b/d2renderers/d2sketch/testdata/double-border/sketch.exp.svg
index 59ab52a549..f1a0fc3265 100644
--- a/d2renderers/d2sketch/testdata/double-border/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/double-border/sketch.exp.svg
@@ -108,7 +108,7 @@
-acnormalsomethingbdnested normal
+acnormalsomethingbdnested normal
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/elk_corners/sketch.exp.svg b/d2renderers/d2sketch/testdata/elk_corners/sketch.exp.svg
index 0b6f38ada4..71bc1cea39 100644
--- a/d2renderers/d2sketch/testdata/elk_corners/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/elk_corners/sketch.exp.svg
@@ -101,7 +101,7 @@
-abc
+abc
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/long_arrowhead_label/sketch.exp.svg b/d2renderers/d2sketch/testdata/long_arrowhead_label/sketch.exp.svg
index 5b49110baf..99321372ac 100644
--- a/d2renderers/d2sketch/testdata/long_arrowhead_label/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/long_arrowhead_label/sketch.exp.svg
@@ -108,7 +108,7 @@
-aba to b with unexpectedly long target arrowhead label
+aba to b with unexpectedly long target arrowhead label
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/opacity/sketch.exp.svg b/d2renderers/d2sketch/testdata/opacity/sketch.exp.svg
index 1b7ad74ec3..9886668769 100644
--- a/d2renderers/d2sketch/testdata/opacity/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/opacity/sketch.exp.svg
@@ -855,7 +855,7 @@
x
linux: because a PC is a terrible thing to waste
-
auserslast_logindatetimeYou don't have to know how the computer works,just how to work the computer.
+auserslast_logindatetimeYou don't have to know how the computer works,just how to work the computer.
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/opacity_dark/sketch.exp.svg b/d2renderers/d2sketch/testdata/opacity_dark/sketch.exp.svg
index 22e2fb86e6..ece5ebb2a1 100644
--- a/d2renderers/d2sketch/testdata/opacity_dark/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/opacity_dark/sketch.exp.svg
@@ -852,7 +852,7 @@
x
linux: because a PC is a terrible thing to waste
-
auserslast_logindatetimeYou don't have to know how the computer works,just how to work the computer.
+auserslast_logindatetimeYou don't have to know how the computer works,just how to work the computer.
\ No newline at end of file
diff --git a/d2renderers/d2sketch/testdata/paper-real/sketch.exp.svg b/d2renderers/d2sketch/testdata/paper-real/sketch.exp.svg
index dac9f44347..9397141647 100644
--- a/d2renderers/d2sketch/testdata/paper-real/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/paper-real/sketch.exp.svg
@@ -1216,7 +1216,7 @@
-NETWORKCELL TOWERSATELLITESTRANSMITTERSENDSENDSEND
+NETWORKCELL TOWERSATELLITESTRANSMITTERSENDSENDSEND
diff --git a/d2renderers/d2sketch/testdata/root-fill/sketch.exp.svg b/d2renderers/d2sketch/testdata/root-fill/sketch.exp.svg
index f94b3b2653..5d6928a20f 100644
--- a/d2renderers/d2sketch/testdata/root-fill/sketch.exp.svg
+++ b/d2renderers/d2sketch/testdata/root-fill/sketch.exp.svg
@@ -847,14 +847,14 @@
-Flow-I (Warehousing, Installation)OEM FactoryOEM WarehouseDistributor Warehousecompany WarehouseMasterRegional-1Regional-2Regional-N