diff --git a/.all-contributorsrc b/.all-contributorsrc
index 79df1a226c..0c3e715f9f 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -277,6 +277,26 @@
"contributions": [
"bug"
]
+ },
+ {
+ "login": "JamieSlome",
+ "name": "Jamie Slome",
+ "avatar_url": "https://avatars.githubusercontent.com/u/55323451?v=4",
+ "profile": "https://418sec.com",
+ "contributions": [
+ "bug",
+ "security"
+ ]
+ },
+ {
+ "login": "d3v53c",
+ "name": "d3v53c",
+ "avatar_url": "https://avatars.githubusercontent.com/u/64132745?v=4",
+ "profile": "https://github.com/d3v53c",
+ "contributions": [
+ "bug",
+ "security"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 524260ef41..daf9432fe7 100644
--- a/README.md
+++ b/README.md
@@ -101,7 +101,7 @@ packages) in the [**examples**](./examples/README.md) directory.
- [Part 3 - Convolution, 1D/2D Cellular automata](https://medium.com/@thi.ng/of-umbrellas-transducers-reactive-streams-mushrooms-pt-3-a1c4e621db9b)
- [Part 4 - Disjoint Sets, Graph analysis, Signed Distance Fields](https://medium.com/@thi.ng/of-umbrellas-transducers-reactive-streams-mushrooms-pt-4-62d8e71e5603)
-## Community & contributing
+## Community, contributing, getting help
Join our little community on our [Discord
server](https://discord.gg/JhYcmBw) or get in touch via
@@ -120,12 +120,18 @@ local clones, please follow the [advice & short instructions in this
article](https://www.hanselman.com/blog/easily-rename-your-git-default-branch-from-master-to-main)
to update your local version.
+Also please be sure to check the [wiki](https://github.com/thi-ng/umbrella/wiki)
+for other project-wide information, tidbits, useful snippets etc.
+
## Projects
-
+feature or `develop` branches)
+
+- [`@thi.ng/color`](./packages/color) - Complete refactor/overhaul/extension of color package
+- [`@thi.ng/pixel-io-netpbm`](./packages/pixel-io-netpbm) - 1/8/16/24bit NetPBM image format reader/writer
### Latest additions (2021-01-21)
@@ -414,44 +420,49 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
-
+
+
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
diff --git a/assets/color/blackbody.svg b/assets/color/blackbody.svg
new file mode 100644
index 0000000000..e4588a6fe7
--- /dev/null
+++ b/assets/color/blackbody.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/lch-gradient.svg b/assets/color/lch-gradient.svg
new file mode 100644
index 0000000000..dfd0775c87
--- /dev/null
+++ b/assets/color/lch-gradient.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/mapped-colors-01.png b/assets/color/mapped-colors-01.png
new file mode 100644
index 0000000000..a83061141f
Binary files /dev/null and b/assets/color/mapped-colors-01.png differ
diff --git a/assets/color/mapped-colors-02.png b/assets/color/mapped-colors-02.png
new file mode 100644
index 0000000000..a3f192ec4f
Binary files /dev/null and b/assets/color/mapped-colors-02.png differ
diff --git a/assets/color/mapped-colors.drawio b/assets/color/mapped-colors.drawio
new file mode 100644
index 0000000000..4ed4b57fd1
--- /dev/null
+++ b/assets/color/mapped-colors.drawio
@@ -0,0 +1 @@
+7ZtLc5swEMc/jY/JGDCOfYxpSC7pZJqmbXLDIAMTgVwQsdNPX/EQTzlxnbVRmfhiWPRifwu78wdGmhFsryNr7d0SB+GROna2I+3LSFUVZTZlf6nlNbfMtHFucCPfKRpVhnv/DyqMvFniOyhuNKSEYOqvm0abhCGyacNmRRHZNJutCG7OurZc1DHc2xbuWn/6DvWKs1AvKvsN8l2Pz6xM5/mRwOKNizOJPcshm5pJuxppRkQIzbeCrYFw6jzul7yfueNoubAIhXSfDsubB/z17vmnep2sXDV5cu4S5awY5cXCSXHCI3WK2XiLFWHDModZdn5g+jtJV7q4RSEm1S7bctP/b7xfnCy5TeE2tqiauWbNJ+HmzEv0lbs+IknooHT1Y3Z44/kU3a/z5WxYsDGbRwPM9pR0uT7GBsEkyvpqpmmwXznqC4oo2u50nFLiYHGMSIBo9MqaFB0mBUAewcXupgoH3sKrRQK3WUUAuuW4FSO2UWD6B2QqFLJruZAZRgoNBtlMLmQaFLKFbMiudNOEQaaocjGbQDG77JkZBJupXGz0Y2Yttb/rCTJrqWO5mE2PmbZ6ZAaZtmQrNS6Ombd6ZQaXt2SrNWbHzFunZAbARpOsppgfM29pw8hbmmS1BhcijpO4eoQGmbgmkhUbCpiuIcpcvUKDy1wTyaoNBUzZEKWuU0KDgCNZWaGAaRii3DUZRu7SJas3FDARQ5S7eoQGmbt02QoOMHVDlLt6hQaXu6ayFRxg8oYod50SGgQc2QoLMB1DlLsG8pSrrT2V+mFv1MCUjAE/6GqrT/1TA9M4RNlrIM+62rpU79T4ej6fdo26ClT/dMDUjF9yXVOmCSlBSQYNTM14HC402bKXCqZyPA0XWvtNjf6pgckcD7JRM4z5HIiadFkNTOf4MVxq7bc4+qcGJnRUtcjaChve5y3TAc/i7JVgVlaOlfF62x1GwF59l30+5f95+20/a+s/JMDklcfPkDgsJKQrfsG0m6fPkDgsJKQrrbvC0Pn5ecd/7Ixp00kxjcgz4m4KSYhanitMFvbdkO3azEOI2Rep/3zbwpfFgcB3nHQaIZUmNwAAOlfCSgD6XgDUYwHgH9585Jrc4/JTd1x+VpC6OVzG6R9zzRhhFDBfxu1j+15pKHQu0w982N4SE/v5u+eHWbhYERUdqIUU62r6uAow1qO2n8+EnM6HQe+ir6HVBWi5LULYov5Lc3gR72KGO+JnfMRKhzJrRUxMkshGRacqaATjvDMQ84uLaGegLPrKs/5AQIpkrf0g72R5OLtdj0H07n3zLbb7Y+zMND+Q484ln4ojmNKVXYmsPVmtYpRuZJ3SG+d+t4TBJI8S4RtRWMowH8webLf6CDGPiepTTu3qLw==
\ No newline at end of file
diff --git a/assets/color/swatches-duo-bright.svg b/assets/color/swatches-duo-bright.svg
deleted file mode 100644
index 95b7941eb6..0000000000
--- a/assets/color/swatches-duo-bright.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-duo-cool.svg b/assets/color/swatches-duo-cool.svg
deleted file mode 100644
index 6ae5224e1d..0000000000
--- a/assets/color/swatches-duo-cool.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-duo-dark.svg b/assets/color/swatches-duo-dark.svg
deleted file mode 100644
index 93597469f5..0000000000
--- a/assets/color/swatches-duo-dark.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-duo-fresh.svg b/assets/color/swatches-duo-fresh.svg
deleted file mode 100644
index 5f4258d571..0000000000
--- a/assets/color/swatches-duo-fresh.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-duo-hard.svg b/assets/color/swatches-duo-hard.svg
deleted file mode 100644
index 5349176d8b..0000000000
--- a/assets/color/swatches-duo-hard.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-duo-intense.svg b/assets/color/swatches-duo-intense.svg
deleted file mode 100644
index bad59f11e4..0000000000
--- a/assets/color/swatches-duo-intense.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-duo-light.svg b/assets/color/swatches-duo-light.svg
deleted file mode 100644
index 68afcebdc2..0000000000
--- a/assets/color/swatches-duo-light.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-duo-neutral.svg b/assets/color/swatches-duo-neutral.svg
deleted file mode 100644
index 49823eea30..0000000000
--- a/assets/color/swatches-duo-neutral.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-duo-soft.svg b/assets/color/swatches-duo-soft.svg
deleted file mode 100644
index c9af2f227d..0000000000
--- a/assets/color/swatches-duo-soft.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-duo-warm.svg b/assets/color/swatches-duo-warm.svg
deleted file mode 100644
index e2c3beadc1..0000000000
--- a/assets/color/swatches-duo-warm.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-duo-weak.svg b/assets/color/swatches-duo-weak.svg
deleted file mode 100644
index b362ede965..0000000000
--- a/assets/color/swatches-duo-weak.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-ex01.svg b/assets/color/swatches-ex01.svg
index 34806a10d1..d374671918 100644
--- a/assets/color/swatches-ex01.svg
+++ b/assets/color/swatches-ex01.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/assets/color/swatches-ex02.svg b/assets/color/swatches-ex02.svg
index 08b60fa026..af7662e79d 100644
--- a/assets/color/swatches-ex02.svg
+++ b/assets/color/swatches-ex02.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/assets/color/swatches-green-bright.svg b/assets/color/swatches-green-bright.svg
deleted file mode 100644
index 51ba0c13fd..0000000000
--- a/assets/color/swatches-green-bright.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-green-cool.svg b/assets/color/swatches-green-cool.svg
deleted file mode 100644
index 9f9a4d2d47..0000000000
--- a/assets/color/swatches-green-cool.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-green-dark.svg b/assets/color/swatches-green-dark.svg
deleted file mode 100644
index f85860c8c2..0000000000
--- a/assets/color/swatches-green-dark.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-green-fresh.svg b/assets/color/swatches-green-fresh.svg
deleted file mode 100644
index f03297c295..0000000000
--- a/assets/color/swatches-green-fresh.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-green-hard.svg b/assets/color/swatches-green-hard.svg
deleted file mode 100644
index 0f4d5c6edc..0000000000
--- a/assets/color/swatches-green-hard.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-green-intense.svg b/assets/color/swatches-green-intense.svg
deleted file mode 100644
index c2245a98b2..0000000000
--- a/assets/color/swatches-green-intense.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-green-light.svg b/assets/color/swatches-green-light.svg
deleted file mode 100644
index 16b37436c3..0000000000
--- a/assets/color/swatches-green-light.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-green-neutral.svg b/assets/color/swatches-green-neutral.svg
deleted file mode 100644
index 18f1c9d374..0000000000
--- a/assets/color/swatches-green-neutral.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-green-soft.svg b/assets/color/swatches-green-soft.svg
deleted file mode 100644
index a6c63fa449..0000000000
--- a/assets/color/swatches-green-soft.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-green-warm.svg b/assets/color/swatches-green-warm.svg
deleted file mode 100644
index 3eed818084..0000000000
--- a/assets/color/swatches-green-warm.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-green-weak.svg b/assets/color/swatches-green-weak.svg
deleted file mode 100644
index afdbecf083..0000000000
--- a/assets/color/swatches-green-weak.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-range-bright-chunks.svg b/assets/color/swatches-range-bright-chunks.svg
new file mode 100644
index 0000000000..f6ae8d0953
--- /dev/null
+++ b/assets/color/swatches-range-bright-chunks.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-bright-hue.svg b/assets/color/swatches-range-bright-hue.svg
new file mode 100644
index 0000000000..58dcd6dc1f
--- /dev/null
+++ b/assets/color/swatches-range-bright-hue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-bright-mixed.svg b/assets/color/swatches-range-bright-mixed.svg
new file mode 100644
index 0000000000..0456b42826
--- /dev/null
+++ b/assets/color/swatches-range-bright-mixed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-bright.svg b/assets/color/swatches-range-bright.svg
deleted file mode 100644
index b9ad885d8b..0000000000
--- a/assets/color/swatches-range-bright.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-range-cool-chunks.svg b/assets/color/swatches-range-cool-chunks.svg
new file mode 100644
index 0000000000..23b4bf981c
--- /dev/null
+++ b/assets/color/swatches-range-cool-chunks.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-cool-hue.svg b/assets/color/swatches-range-cool-hue.svg
new file mode 100644
index 0000000000..c9e14e32f3
--- /dev/null
+++ b/assets/color/swatches-range-cool-hue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-cool-mixed.svg b/assets/color/swatches-range-cool-mixed.svg
new file mode 100644
index 0000000000..95d3d631c6
--- /dev/null
+++ b/assets/color/swatches-range-cool-mixed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-cool.svg b/assets/color/swatches-range-cool.svg
deleted file mode 100644
index 6daa81828a..0000000000
--- a/assets/color/swatches-range-cool.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-range-dark-chunks.svg b/assets/color/swatches-range-dark-chunks.svg
new file mode 100644
index 0000000000..af46b75ef1
--- /dev/null
+++ b/assets/color/swatches-range-dark-chunks.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-dark-hue.svg b/assets/color/swatches-range-dark-hue.svg
new file mode 100644
index 0000000000..dd05314c72
--- /dev/null
+++ b/assets/color/swatches-range-dark-hue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-dark-mixed.svg b/assets/color/swatches-range-dark-mixed.svg
new file mode 100644
index 0000000000..9e32bcc7e1
--- /dev/null
+++ b/assets/color/swatches-range-dark-mixed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-dark.svg b/assets/color/swatches-range-dark.svg
deleted file mode 100644
index 027c891b59..0000000000
--- a/assets/color/swatches-range-dark.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-range-fresh-chunks.svg b/assets/color/swatches-range-fresh-chunks.svg
new file mode 100644
index 0000000000..a11b403bd4
--- /dev/null
+++ b/assets/color/swatches-range-fresh-chunks.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-fresh-hue.svg b/assets/color/swatches-range-fresh-hue.svg
new file mode 100644
index 0000000000..0601dd189d
--- /dev/null
+++ b/assets/color/swatches-range-fresh-hue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-fresh-mixed.svg b/assets/color/swatches-range-fresh-mixed.svg
new file mode 100644
index 0000000000..b6395a90b3
--- /dev/null
+++ b/assets/color/swatches-range-fresh-mixed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-fresh.svg b/assets/color/swatches-range-fresh.svg
deleted file mode 100644
index 4953ef9ba5..0000000000
--- a/assets/color/swatches-range-fresh.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-range-hard-chunks.svg b/assets/color/swatches-range-hard-chunks.svg
new file mode 100644
index 0000000000..54d5be6e00
--- /dev/null
+++ b/assets/color/swatches-range-hard-chunks.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-hard-hue.svg b/assets/color/swatches-range-hard-hue.svg
new file mode 100644
index 0000000000..94ab718c11
--- /dev/null
+++ b/assets/color/swatches-range-hard-hue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-hard-mixed.svg b/assets/color/swatches-range-hard-mixed.svg
new file mode 100644
index 0000000000..7bf82d83ac
--- /dev/null
+++ b/assets/color/swatches-range-hard-mixed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-hard.svg b/assets/color/swatches-range-hard.svg
deleted file mode 100644
index c620dab789..0000000000
--- a/assets/color/swatches-range-hard.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-range-intense-chunks.svg b/assets/color/swatches-range-intense-chunks.svg
new file mode 100644
index 0000000000..757484ec82
--- /dev/null
+++ b/assets/color/swatches-range-intense-chunks.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-intense-hue.svg b/assets/color/swatches-range-intense-hue.svg
new file mode 100644
index 0000000000..61b04dcd6f
--- /dev/null
+++ b/assets/color/swatches-range-intense-hue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-intense-mixed.svg b/assets/color/swatches-range-intense-mixed.svg
new file mode 100644
index 0000000000..31bd6001db
--- /dev/null
+++ b/assets/color/swatches-range-intense-mixed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-intense.svg b/assets/color/swatches-range-intense.svg
deleted file mode 100644
index 89f3aad1b3..0000000000
--- a/assets/color/swatches-range-intense.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-range-light-chunks.svg b/assets/color/swatches-range-light-chunks.svg
new file mode 100644
index 0000000000..ed315f3a7b
--- /dev/null
+++ b/assets/color/swatches-range-light-chunks.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-light-hue.svg b/assets/color/swatches-range-light-hue.svg
new file mode 100644
index 0000000000..43ab1207ad
--- /dev/null
+++ b/assets/color/swatches-range-light-hue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-light-mixed.svg b/assets/color/swatches-range-light-mixed.svg
new file mode 100644
index 0000000000..b52c00b79b
--- /dev/null
+++ b/assets/color/swatches-range-light-mixed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-light.svg b/assets/color/swatches-range-light.svg
deleted file mode 100644
index 6593ca7542..0000000000
--- a/assets/color/swatches-range-light.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-range-neutral-chunks.svg b/assets/color/swatches-range-neutral-chunks.svg
new file mode 100644
index 0000000000..3cb7ea5b47
--- /dev/null
+++ b/assets/color/swatches-range-neutral-chunks.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-neutral-hue.svg b/assets/color/swatches-range-neutral-hue.svg
new file mode 100644
index 0000000000..6846369438
--- /dev/null
+++ b/assets/color/swatches-range-neutral-hue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-neutral-mixed.svg b/assets/color/swatches-range-neutral-mixed.svg
new file mode 100644
index 0000000000..6fe3ce919f
--- /dev/null
+++ b/assets/color/swatches-range-neutral-mixed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-neutral.svg b/assets/color/swatches-range-neutral.svg
deleted file mode 100644
index 0bf115f90f..0000000000
--- a/assets/color/swatches-range-neutral.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-range-soft-chunks.svg b/assets/color/swatches-range-soft-chunks.svg
new file mode 100644
index 0000000000..6e6b3c45b5
--- /dev/null
+++ b/assets/color/swatches-range-soft-chunks.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-soft-hue.svg b/assets/color/swatches-range-soft-hue.svg
new file mode 100644
index 0000000000..74aebc0ac1
--- /dev/null
+++ b/assets/color/swatches-range-soft-hue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-soft-mixed.svg b/assets/color/swatches-range-soft-mixed.svg
new file mode 100644
index 0000000000..811a6891f3
--- /dev/null
+++ b/assets/color/swatches-range-soft-mixed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-soft.svg b/assets/color/swatches-range-soft.svg
deleted file mode 100644
index 526ad59fce..0000000000
--- a/assets/color/swatches-range-soft.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-range-warm-chunks.svg b/assets/color/swatches-range-warm-chunks.svg
new file mode 100644
index 0000000000..112a474fcf
--- /dev/null
+++ b/assets/color/swatches-range-warm-chunks.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-warm-hue.svg b/assets/color/swatches-range-warm-hue.svg
new file mode 100644
index 0000000000..cbdc4e003b
--- /dev/null
+++ b/assets/color/swatches-range-warm-hue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-warm-mixed.svg b/assets/color/swatches-range-warm-mixed.svg
new file mode 100644
index 0000000000..e581627bd2
--- /dev/null
+++ b/assets/color/swatches-range-warm-mixed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-warm.svg b/assets/color/swatches-range-warm.svg
deleted file mode 100644
index 0497aa93cf..0000000000
--- a/assets/color/swatches-range-warm.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/swatches-range-weak-chunks.svg b/assets/color/swatches-range-weak-chunks.svg
new file mode 100644
index 0000000000..4d6d196db6
--- /dev/null
+++ b/assets/color/swatches-range-weak-chunks.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-weak-hue.svg b/assets/color/swatches-range-weak-hue.svg
new file mode 100644
index 0000000000..876ca0cfaf
--- /dev/null
+++ b/assets/color/swatches-range-weak-hue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-weak-mixed.svg b/assets/color/swatches-range-weak-mixed.svg
new file mode 100644
index 0000000000..4ef7ca3d45
--- /dev/null
+++ b/assets/color/swatches-range-weak-mixed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/color/swatches-range-weak.svg b/assets/color/swatches-range-weak.svg
deleted file mode 100644
index 3a24cd3ee0..0000000000
--- a/assets/color/swatches-range-weak.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/color/wavelength.svg b/assets/color/wavelength.svg
new file mode 100644
index 0000000000..6b0b26cdb5
--- /dev/null
+++ b/assets/color/wavelength.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/examples/pixel-sorting.png b/assets/examples/pixel-sorting.png
new file mode 100644
index 0000000000..4a082dd507
Binary files /dev/null and b/assets/examples/pixel-sorting.png differ
diff --git a/examples/README.md b/examples/README.md
index 014ae04ed4..5c66721c89 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -1,7 +1,7 @@
# @thi.ng/umbrella examples
-This directory contains a growing number (currently 99) of standalone
+This directory contains a growing number (currently 100) of standalone
example projects, including live online versions, build instructions
and commented source code.
@@ -62,51 +62,52 @@ in touch via PR, issue tracker, email or twitter!
| 050 | | [package-stats](./package-stats/) | CLI util to visualize umbrella pkg stats |
| 051 | | [parse-playground](./parse-playground/) | Parser grammar livecoding editor/playground & codegen |
| 052 | | [pixel-basics](./pixel-basics/) | Pixel buffer manipulations |
-| 053 | | [pointfree-svg](./pointfree-svg/) | Generate SVG using pointfree DSL |
-| 054 | | [poisson-circles](./poisson-circles/) | 2D Poisson-disc sampler with procedural gradient map |
-| 055 | | [poly-spline](./poly-spline/) | Polygon to cubic curve conversion & visualization |
-| 056 | | [porter-duff](./porter-duff/) | Port-Duff image compositing / alpha blending |
-| 057 | | [ramp-synth](./ramp-synth/) | Unison wavetable synth with waveform editor |
-| 058 | | [rdom-basics](./rdom-basics/) | Demonstates various rdom usage patterns |
-| 059 | | [rdom-dnd](./rdom-dnd/) | rdom drag & drop example |
-| 060 | | [rdom-lissajous](./rdom-lissajous/) | rdom & hiccup-canvas interop test |
-| 061 | | [rdom-search-docs](./rdom-search-docs/) | Full umbrella repo doc string search w/ paginated results |
-| 062 | | [rdom-svg-nodes](./rdom-svg-nodes/) | rdom powered SVG graph with draggable nodes |
-| 063 | | [rotating-voronoi](./rotating-voronoi/) | Animated Voronoi diagram, cubic splines & SVG download |
-| 064 | | [router-basics](./router-basics/) | Complete mini SPA app w/ router & async content loading |
-| 065 | | [rstream-dataflow](./rstream-dataflow/) | Minimal rstream dataflow graph |
-| 066 | | [rstream-event-loop](./rstream-event-loop/) | Minimal demo of using rstream constructs to form an interceptor-style event loop |
-| 067 | | [rstream-grid](./rstream-grid/) | Interactive grid generator, SVG generation & export, undo/redo support |
-| 068 | | [rstream-hdom](./rstream-hdom/) | rstream based UI updates & state handling |
-| 069 | | [rstream-spreadsheet](./rstream-spreadsheet/) | rstream based spreadsheet w/ S-expression formula DSL |
-| 070 | | [scenegraph](./scenegraph/) | 2D scenegraph & shape picking |
-| 071 | | [scenegraph-image](./scenegraph-image/) | 2D scenegraph & image map based geometry manipulation |
-| 072 | | [shader-ast-canvas2d](./shader-ast-canvas2d/) | 2D canvas shader emulation |
-| 073 | | [shader-ast-evo](./shader-ast-evo/) | Evolutionary shader generation using genetic programming |
-| 074 | | [shader-ast-noise](./shader-ast-noise/) | HOF shader procedural noise function composition |
-| 075 | | [shader-ast-raymarch](./shader-ast-raymarch/) | WebGL & JS canvas2D raymarch shader cross-compilation |
-| 076 | | [shader-ast-sdf2d](./shader-ast-sdf2d/) | WebGL & JS canvas 2D SDF |
-| 077 | | [shader-ast-tunnel](./shader-ast-tunnel/) | WebGL & Canvas2D textured tunnel shader |
-| 078 | | [shader-ast-workers](./shader-ast-workers/) | Fork-join worker-based raymarch renderer |
-| 079 | | [shader-graph](./shader-graph/) | Minimal shader graph developed during livestream #2 |
-| 080 | | [soa-ecs](./soa-ecs/) | Entity Component System w/ 100k 3D particles |
-| 081 | | [stratified-grid](./stratified-grid/) | 2D Stratified grid sampling example |
-| 082 | | [svg-barchart](./svg-barchart/) | Simplistic SVG bar chart component |
-| 083 | | [svg-particles](./svg-particles/) | Basic 2D particle system w/ SVG shapes |
-| 084 | | [svg-waveform](./svg-waveform/) | Additive waveform synthesis & SVG visualization with undo/redo |
-| 085 | | [talk-slides](./talk-slides/) | hdom based slide deck viewer & slides from my ClojureX 2018 keynote |
-| 086 | | [text-canvas](./text-canvas/) | 3D wireframe textmode demo |
-| 087 | | [text-canvas-image](./text-canvas-image/) | Textmode image warping w/ 16bit color output |
-| 088 | | [todo-list](./todo-list/) | Obligatory to-do list example with undo/redo |
-| 089 | | [transducers-hdom](./transducers-hdom/) | Transducer & rstream based hdom UI updates |
-| 090 | | [triple-query](./triple-query/) | Triple store query results & sortable table |
-| 091 | | [webgl-cube](./webgl-cube/) | WebGL multi-colored cube mesh |
-| 092 | | [webgl-cubemap](./webgl-cubemap/) | WebGL cube maps with async texture loading |
-| 093 | | [webgl-grid](./webgl-grid/) | WebGL instancing, animated grid |
-| 094 | | [webgl-msdf](./webgl-msdf/) | WebGL MSDF text rendering & particle system |
-| 095 | | [webgl-multipass](./webgl-multipass/) | Minimal multi-pass / GPGPU example |
-| 096 | | [webgl-shadertoy](./webgl-shadertoy/) | Shadertoy-like WebGL setup |
-| 097 | | [webgl-ssao](./webgl-ssao/) | WebGL screenspace ambient occlusion |
-| 098 | | [wolfram](./wolfram/) | 1D Wolfram automata with OBJ point cloud export |
-| 099 | | [xml-converter](./xml-converter/) | XML/HTML/SVG to hiccup/JS conversion |
+| 053 | | [pixel-sorting](./pixel-sorting/) | Interactive pixel sorting tool using thi.ng/color & thi.ng/pixel |
+| 054 | | [pointfree-svg](./pointfree-svg/) | Generate SVG using pointfree DSL |
+| 055 | | [poisson-circles](./poisson-circles/) | 2D Poisson-disc sampler with procedural gradient map |
+| 056 | | [poly-spline](./poly-spline/) | Polygon to cubic curve conversion & visualization |
+| 057 | | [porter-duff](./porter-duff/) | Port-Duff image compositing / alpha blending |
+| 058 | | [ramp-synth](./ramp-synth/) | Unison wavetable synth with waveform editor |
+| 059 | | [rdom-basics](./rdom-basics/) | Demonstates various rdom usage patterns |
+| 060 | | [rdom-dnd](./rdom-dnd/) | rdom drag & drop example |
+| 061 | | [rdom-lissajous](./rdom-lissajous/) | rdom & hiccup-canvas interop test |
+| 062 | | [rdom-search-docs](./rdom-search-docs/) | Full umbrella repo doc string search w/ paginated results |
+| 063 | | [rdom-svg-nodes](./rdom-svg-nodes/) | rdom powered SVG graph with draggable nodes |
+| 064 | | [rotating-voronoi](./rotating-voronoi/) | Animated Voronoi diagram, cubic splines & SVG download |
+| 065 | | [router-basics](./router-basics/) | Complete mini SPA app w/ router & async content loading |
+| 066 | | [rstream-dataflow](./rstream-dataflow/) | Minimal rstream dataflow graph |
+| 067 | | [rstream-event-loop](./rstream-event-loop/) | Minimal demo of using rstream constructs to form an interceptor-style event loop |
+| 068 | | [rstream-grid](./rstream-grid/) | Interactive grid generator, SVG generation & export, undo/redo support |
+| 069 | | [rstream-hdom](./rstream-hdom/) | rstream based UI updates & state handling |
+| 070 | | [rstream-spreadsheet](./rstream-spreadsheet/) | rstream based spreadsheet w/ S-expression formula DSL |
+| 071 | | [scenegraph](./scenegraph/) | 2D scenegraph & shape picking |
+| 072 | | [scenegraph-image](./scenegraph-image/) | 2D scenegraph & image map based geometry manipulation |
+| 073 | | [shader-ast-canvas2d](./shader-ast-canvas2d/) | 2D canvas shader emulation |
+| 074 | | [shader-ast-evo](./shader-ast-evo/) | Evolutionary shader generation using genetic programming |
+| 075 | | [shader-ast-noise](./shader-ast-noise/) | HOF shader procedural noise function composition |
+| 076 | | [shader-ast-raymarch](./shader-ast-raymarch/) | WebGL & JS canvas2D raymarch shader cross-compilation |
+| 077 | | [shader-ast-sdf2d](./shader-ast-sdf2d/) | WebGL & JS canvas 2D SDF |
+| 078 | | [shader-ast-tunnel](./shader-ast-tunnel/) | WebGL & Canvas2D textured tunnel shader |
+| 079 | | [shader-ast-workers](./shader-ast-workers/) | Fork-join worker-based raymarch renderer |
+| 080 | | [shader-graph](./shader-graph/) | Minimal shader graph developed during livestream #2 |
+| 081 | | [soa-ecs](./soa-ecs/) | Entity Component System w/ 100k 3D particles |
+| 082 | | [stratified-grid](./stratified-grid/) | 2D Stratified grid sampling example |
+| 083 | | [svg-barchart](./svg-barchart/) | Simplistic SVG bar chart component |
+| 084 | | [svg-particles](./svg-particles/) | Basic 2D particle system w/ SVG shapes |
+| 085 | | [svg-waveform](./svg-waveform/) | Additive waveform synthesis & SVG visualization with undo/redo |
+| 086 | | [talk-slides](./talk-slides/) | hdom based slide deck viewer & slides from my ClojureX 2018 keynote |
+| 087 | | [text-canvas](./text-canvas/) | 3D wireframe textmode demo |
+| 088 | | [text-canvas-image](./text-canvas-image/) | Textmode image warping w/ 16bit color output |
+| 089 | | [todo-list](./todo-list/) | Obligatory to-do list example with undo/redo |
+| 090 | | [transducers-hdom](./transducers-hdom/) | Transducer & rstream based hdom UI updates |
+| 091 | | [triple-query](./triple-query/) | Triple store query results & sortable table |
+| 092 | | [webgl-cube](./webgl-cube/) | WebGL multi-colored cube mesh |
+| 093 | | [webgl-cubemap](./webgl-cubemap/) | WebGL cube maps with async texture loading |
+| 094 | | [webgl-grid](./webgl-grid/) | WebGL instancing, animated grid |
+| 095 | | [webgl-msdf](./webgl-msdf/) | WebGL MSDF text rendering & particle system |
+| 096 | | [webgl-multipass](./webgl-multipass/) | Minimal multi-pass / GPGPU example |
+| 097 | | [webgl-shadertoy](./webgl-shadertoy/) | Shadertoy-like WebGL setup |
+| 098 | | [webgl-ssao](./webgl-ssao/) | WebGL screenspace ambient occlusion |
+| 099 | | [wolfram](./wolfram/) | 1D Wolfram automata with OBJ point cloud export |
+| 100 | | [xml-converter](./xml-converter/) | XML/HTML/SVG to hiccup/JS conversion |
diff --git a/examples/adaptive-threshold/README.md b/examples/adaptive-threshold/README.md
index bee16003a5..68afc2e492 100644
--- a/examples/adaptive-threshold/README.md
+++ b/examples/adaptive-threshold/README.md
@@ -1,5 +1,7 @@
# adaptive-threshold
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/adaptive-threshold.png)
+
[Live demo](http://demo.thi.ng/umbrella/adaptive-threshold/)
Image processing via
diff --git a/examples/adaptive-threshold/package.json b/examples/adaptive-threshold/package.json
index 1890186542..bcb3fd0227 100644
--- a/examples/adaptive-threshold/package.json
+++ b/examples/adaptive-threshold/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/async-effect/package.json b/examples/async-effect/package.json
index 463a8ebd8b..683cea5b89 100644
--- a/examples/async-effect/package.json
+++ b/examples/async-effect/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/bitmap-font/README.md b/examples/bitmap-font/README.md
index 3fac6ba767..bdf6dc0e16 100644
--- a/examples/bitmap-font/README.md
+++ b/examples/bitmap-font/README.md
@@ -1,5 +1,7 @@
# bitmap-font
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/bitmap-font.gif)
+
[Live demo](http://demo.thi.ng/umbrella/bitmap-font/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/bitmap-font/package.json b/examples/bitmap-font/package.json
index f880b6cef2..a13066ffd1 100644
--- a/examples/bitmap-font/package.json
+++ b/examples/bitmap-font/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/canvas-dial/README.md b/examples/canvas-dial/README.md
index f0277ca369..fc099cd737 100644
--- a/examples/canvas-dial/README.md
+++ b/examples/canvas-dial/README.md
@@ -1,5 +1,7 @@
# canvas-dial
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/canvas-dial.png)
+
[Live demo](http://demo.thi.ng/umbrella/canvas-dial/)
Customizable canvas-based radial dial component with mouse & touch
diff --git a/examples/canvas-dial/package.json b/examples/canvas-dial/package.json
index 9611625641..df904d1643 100644
--- a/examples/canvas-dial/package.json
+++ b/examples/canvas-dial/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/cellular-automata/README.md b/examples/cellular-automata/README.md
index 89bcf409eb..587d86c867 100644
--- a/examples/cellular-automata/README.md
+++ b/examples/cellular-automata/README.md
@@ -1,5 +1,7 @@
# Cellular automata
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/cellular-automata.png)
+
[Live demo](https://demo.thi.ng/umbrella/cellular-automata/)
Please refer to the [example build
diff --git a/examples/cellular-automata/package.json b/examples/cellular-automata/package.json
index bdf71b4b2c..19f92cea17 100644
--- a/examples/cellular-automata/package.json
+++ b/examples/cellular-automata/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/commit-heatmap/README.md b/examples/commit-heatmap/README.md
index 0ef7e1677b..2db8d69b56 100644
--- a/examples/commit-heatmap/README.md
+++ b/examples/commit-heatmap/README.md
@@ -1,6 +1,6 @@
# commit-heatmap
-![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/master/assets/examples/commit-heatmap.png)
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/commit-heatmap.png)
This is offline example creates a heatmap visualization of per-package
commits in this mono-repo, but could also be used for other mono-repos
diff --git a/examples/commit-heatmap/src/index.ts b/examples/commit-heatmap/src/index.ts
index eebd9041a0..eba35da601 100644
--- a/examples/commit-heatmap/src/index.ts
+++ b/examples/commit-heatmap/src/index.ts
@@ -1,5 +1,5 @@
import { withoutKeysObj } from "@thi.ng/associative";
-import { cosineGradient, GRADIENTS } from "@thi.ng/color";
+import { cosineGradient, COSINE_GRADIENTS } from "@thi.ng/color";
import { threadLast } from "@thi.ng/compose";
import { serialize } from "@thi.ng/hiccup";
import { defs, group, line, rect, svg, text } from "@thi.ng/hiccup-svg";
@@ -55,7 +55,7 @@ const IGNORE_PACKAGES = [
];
// heatmap gradient
-const GRAD = cosineGradient(32, GRADIENTS["blue-magenta-orange"]);
+const GRAD = cosineGradient(32, COSINE_GRADIENTS["blue-magenta-orange"]);
const MIN_DATE = Date.parse("2018-01-01T00:00:00+00:00");
const MAX_DATE = Date.now();
diff --git a/examples/commit-table-ssr/README.md b/examples/commit-table-ssr/README.md
index 64d5d8dd1a..a2bc9c17f9 100644
--- a/examples/commit-table-ssr/README.md
+++ b/examples/commit-table-ssr/README.md
@@ -1,5 +1,7 @@
# commit-table-ssr
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/commit-table-ssr.png)
+
[Live version](http://demo.thi.ng/umbrella/commit-table-ssr/)
This example demonstrates isomorphic,
diff --git a/examples/commit-table-ssr/package.json b/examples/commit-table-ssr/package.json
index 60cc1a0051..0122c680ad 100644
--- a/examples/commit-table-ssr/package.json
+++ b/examples/commit-table-ssr/package.json
@@ -12,8 +12,8 @@
"start": "../../node_modules/.bin/ts-node src/server/index.ts"
},
"devDependencies": {
- "ts-node": "^9.1.0",
- "typescript": "^4.1.3"
+ "ts-node": "^9.1.1",
+ "typescript": "^4.1.5"
},
"dependencies": {
"@thi.ng/api": "latest",
diff --git a/examples/crypto-chart/README.md b/examples/crypto-chart/README.md
index 8a9ea2671a..1b99f2056b 100644
--- a/examples/crypto-chart/README.md
+++ b/examples/crypto-chart/README.md
@@ -1,8 +1,8 @@
# crypto-chart
-[Live demo](https://s3.amazonaws.com/demo.thi.ng/umbrella/crypto-chart/index.html)
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/crypto-chart.png)
-![chart](https://raw.githubusercontent.com/thi-ng/umbrella/master/assets/examples/crypto-chart.png)
+[Live demo](https://s3.amazonaws.com/demo.thi.ng/umbrella/crypto-chart/index.html)
Price data provided by [cryptocompare.com](https://min-api.cryptocompare.com/).
@@ -20,7 +20,7 @@ updates / diffs when there were any relevant upstream value changes.
The diagram below shows a schematic of the dataflow graph used:
-![dataflow](https://raw.githubusercontent.com/thi-ng/umbrella/master/assets/examples/crypto-dflow.png)
+![dataflow](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/crypto-dflow.png)
## Building
diff --git a/examples/crypto-chart/package.json b/examples/crypto-chart/package.json
index 12326718ee..9eb6b574c8 100644
--- a/examples/crypto-chart/package.json
+++ b/examples/crypto-chart/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/devcards/package.json b/examples/devcards/package.json
index e24a4bfc4d..49d7fcb082 100644
--- a/examples/devcards/package.json
+++ b/examples/devcards/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/ellipse-proximity/README.md b/examples/ellipse-proximity/README.md
index 76a9b30914..6404c0e326 100644
--- a/examples/ellipse-proximity/README.md
+++ b/examples/ellipse-proximity/README.md
@@ -1,5 +1,7 @@
# ellipse-proximity
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/ellipse-proximity.png)
+
[Live demo](http://demo.thi.ng/umbrella/ellipse-proximity/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/ellipse-proximity/package.json b/examples/ellipse-proximity/package.json
index 6a9a9eb55a..17cb5a0e55 100644
--- a/examples/ellipse-proximity/package.json
+++ b/examples/ellipse-proximity/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/fft-synth/README.md b/examples/fft-synth/README.md
index 100afde951..6f7c45e0e9 100644
--- a/examples/fft-synth/README.md
+++ b/examples/fft-synth/README.md
@@ -1,6 +1,6 @@
# fft-synth
-![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/master/assets/examples/fft-synth.png)
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/fft-synth.png)
[Live demo](http://demo.thi.ng/umbrella/fft-synth/)
diff --git a/examples/fft-synth/package.json b/examples/fft-synth/package.json
index 7fa047f3ca..7aa492bab4 100644
--- a/examples/fft-synth/package.json
+++ b/examples/fft-synth/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/geom-convex-hull/README.md b/examples/geom-convex-hull/README.md
index 82b5377f19..8bded7db06 100644
--- a/examples/geom-convex-hull/README.md
+++ b/examples/geom-convex-hull/README.md
@@ -1,5 +1,7 @@
# geom-convex-hull
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/geom-convex-hull.png)
+
[Live demo](http://demo.thi.ng/umbrella/geom-convex-hull/)
A refactored version of a [blog post code example by Pete
diff --git a/examples/geom-convex-hull/package.json b/examples/geom-convex-hull/package.json
index 6a1e66cd69..18fb6b94ed 100644
--- a/examples/geom-convex-hull/package.json
+++ b/examples/geom-convex-hull/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/geom-fuzz-basics/README.md b/examples/geom-fuzz-basics/README.md
index b91f5bccb7..89a2bed755 100644
--- a/examples/geom-fuzz-basics/README.md
+++ b/examples/geom-fuzz-basics/README.md
@@ -1,5 +1,7 @@
# geom-fuzz-basics
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/geom/geom-fuzz.png)
+
[Live demo](http://demo.thi.ng/umbrella/geom-fuzz-basics/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/geom-fuzz-basics/package.json b/examples/geom-fuzz-basics/package.json
index 4347e95286..58a414527a 100644
--- a/examples/geom-fuzz-basics/package.json
+++ b/examples/geom-fuzz-basics/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/geom-knn/README.md b/examples/geom-knn/README.md
index 3bf327d5c4..61fc5951a8 100644
--- a/examples/geom-knn/README.md
+++ b/examples/geom-knn/README.md
@@ -1,5 +1,7 @@
# geom-knn
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/geom-knn.jpg)
+
[Live demo](http://demo.thi.ng/umbrella/geom-knn/)
Drawing / debug toy based on 2x recursive KNN search using the k-D tree
diff --git a/examples/geom-knn/package.json b/examples/geom-knn/package.json
index eb8cd40f82..55eea84f3d 100644
--- a/examples/geom-knn/package.json
+++ b/examples/geom-knn/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/geom-tessel/README.md b/examples/geom-tessel/README.md
index 4c12ff489e..72c07d8811 100644
--- a/examples/geom-tessel/README.md
+++ b/examples/geom-tessel/README.md
@@ -1,5 +1,7 @@
# geom-tessel
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/geom/tessel.png)
+
[Live demo](http://demo.thi.ng/umbrella/geom-tessel/)
Test example of
diff --git a/examples/geom-tessel/package.json b/examples/geom-tessel/package.json
index 4bea359252..809499f550 100644
--- a/examples/geom-tessel/package.json
+++ b/examples/geom-tessel/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/geom-voronoi-mst/README.md b/examples/geom-voronoi-mst/README.md
index 4dfb34e666..ac45f5035e 100644
--- a/examples/geom-voronoi-mst/README.md
+++ b/examples/geom-voronoi-mst/README.md
@@ -1,5 +1,7 @@
# geom-voronoi-mst
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/geom-voronoi-mst.jpg)
+
[Live demo](http://demo.thi.ng/umbrella/geom-voronoi-mst/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/geom-voronoi-mst/package.json b/examples/geom-voronoi-mst/package.json
index 11f841154c..e5d4340ab0 100644
--- a/examples/geom-voronoi-mst/package.json
+++ b/examples/geom-voronoi-mst/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/gesture-analysis/README.md b/examples/gesture-analysis/README.md
index 8e2fd812fc..8b0f67f818 100644
--- a/examples/gesture-analysis/README.md
+++ b/examples/gesture-analysis/README.md
@@ -1,5 +1,7 @@
# gesture-analysis
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/gesture-analysis.png)
+
[Live demo](http://demo.thi.ng/umbrella/gesture-analysis/)
Mouse / touch gesture processing, analysis and SVG visualization, using
diff --git a/examples/gesture-analysis/package.json b/examples/gesture-analysis/package.json
index 8d60e1f79c..45dc45eb08 100644
--- a/examples/gesture-analysis/package.json
+++ b/examples/gesture-analysis/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/grid-iterators/README.md b/examples/grid-iterators/README.md
index 0d69adb255..311a06b811 100644
--- a/examples/grid-iterators/README.md
+++ b/examples/grid-iterators/README.md
@@ -1,5 +1,7 @@
# grid-iterators
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/grid-iterators.png)
+
[Live demo](http://demo.thi.ng/umbrella/grid-iterators/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/grid-iterators/package.json b/examples/grid-iterators/package.json
index ebadb9e1a3..e6aa888029 100644
--- a/examples/grid-iterators/package.json
+++ b/examples/grid-iterators/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/grid-iterators/src/index.ts b/examples/grid-iterators/src/index.ts
index 7e58cd800f..6a671529cb 100644
--- a/examples/grid-iterators/src/index.ts
+++ b/examples/grid-iterators/src/index.ts
@@ -1,4 +1,4 @@
-import { hueRgba, rgbaCss } from "@thi.ng/color";
+import { hueRgb, srgbCss } from "@thi.ng/color";
import {
diagonal2d,
hilbert2d,
@@ -49,6 +49,6 @@ setInterval(() => {
let [x, y] = b.value;
x *= BW;
y *= BH;
- ctx.fillStyle = rgbaCss(hueRgba([], frame++ / (NB * NB)));
+ ctx.fillStyle = srgbCss(hueRgb([], frame++ / (NB * NB)));
ctx.fillRect(x, y, BW, BH);
}, 16);
diff --git a/examples/hdom-basics/package.json b/examples/hdom-basics/package.json
index 0c42a00a13..5193fd376c 100644
--- a/examples/hdom-basics/package.json
+++ b/examples/hdom-basics/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-benchmark/README.md b/examples/hdom-benchmark/README.md
index 7c259cfa1e..82d679f130 100644
--- a/examples/hdom-benchmark/README.md
+++ b/examples/hdom-benchmark/README.md
@@ -1,5 +1,7 @@
# hdom-benchmark
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/hdom-benchmark.png)
+
[Live demo](https://demo.thi.ng/umbrella/hdom-benchmark/)
Please refer to the [example build
diff --git a/examples/hdom-benchmark/package.json b/examples/hdom-benchmark/package.json
index b21ab72de3..cb490b638d 100644
--- a/examples/hdom-benchmark/package.json
+++ b/examples/hdom-benchmark/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-benchmark2/README.md b/examples/hdom-benchmark2/README.md
index ff2d2933f1..f804edc72a 100644
--- a/examples/hdom-benchmark2/README.md
+++ b/examples/hdom-benchmark2/README.md
@@ -1,5 +1,7 @@
# hdom-benchmark2
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/hdom-benchmark2.png)
+
[Live demo](http://demo.thi.ng/umbrella/hdom-benchmark2/)
Please refer to the [example build
diff --git a/examples/hdom-benchmark2/package.json b/examples/hdom-benchmark2/package.json
index 551e7dfd30..bdf6a13d6b 100644
--- a/examples/hdom-benchmark2/package.json
+++ b/examples/hdom-benchmark2/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-canvas-clock/README.md b/examples/hdom-canvas-clock/README.md
index aa97c047bb..f995fa096a 100644
--- a/examples/hdom-canvas-clock/README.md
+++ b/examples/hdom-canvas-clock/README.md
@@ -1,5 +1,7 @@
# hdom-canvas-clock
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/hdom-canvas-clock.png)
+
[Live demo](http://demo.thi.ng/umbrella/hdom-canvas-clock/)
Declarative canvas drawing using the
diff --git a/examples/hdom-canvas-clock/package.json b/examples/hdom-canvas-clock/package.json
index 72bd0e3616..31fa4affa7 100644
--- a/examples/hdom-canvas-clock/package.json
+++ b/examples/hdom-canvas-clock/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-canvas-draw/README.md b/examples/hdom-canvas-draw/README.md
index da13473855..f91c21e30b 100644
--- a/examples/hdom-canvas-draw/README.md
+++ b/examples/hdom-canvas-draw/README.md
@@ -1,5 +1,7 @@
# hdom-canvas-draw
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/hdom-canvas-draw.jpg)
+
[Live demo](http://demo.thi.ng/umbrella/hdom-canvas-draw/)
Please refer to the [example build
diff --git a/examples/hdom-canvas-draw/package.json b/examples/hdom-canvas-draw/package.json
index 5b004c6dc3..b0faef89e3 100644
--- a/examples/hdom-canvas-draw/package.json
+++ b/examples/hdom-canvas-draw/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-canvas-particles/README.md b/examples/hdom-canvas-particles/README.md
index 51e26d37fd..c85a993176 100644
--- a/examples/hdom-canvas-particles/README.md
+++ b/examples/hdom-canvas-particles/README.md
@@ -1,5 +1,7 @@
# hdom-canvas-particles
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/hdom-canvas-particles.jpg)
+
[Live demo](http://demo.thi.ng/umbrella/hdom-canvas-particles/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/hdom-canvas-particles/package.json b/examples/hdom-canvas-particles/package.json
index 41c558d81e..247d30a85c 100644
--- a/examples/hdom-canvas-particles/package.json
+++ b/examples/hdom-canvas-particles/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-canvas-shapes/README.md b/examples/hdom-canvas-shapes/README.md
index 27dc81ad7e..2fd1c1d879 100644
--- a/examples/hdom-canvas-shapes/README.md
+++ b/examples/hdom-canvas-shapes/README.md
@@ -1,6 +1,6 @@
# hdom-canvas-shapes
-![screenshots](https://raw.githubusercontent.com/thi-ng/umbrella/master/assets/hdom-canvas/hdom-canvas-shapes-results.png)
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/hdom-canvas/hdom-canvas-shapes-results.png)
[Live demo](http://demo.thi.ng/umbrella/hdom-canvas-shapes/)
@@ -32,7 +32,7 @@ Related examples:
Dataflow diagram:
-![dataflow](https://raw.githubusercontent.com/thi-ng/umbrella/master/assets/hdom-canvas/hdom-canvas-shapes.png)
+![dataflow](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/hdom-canvas/hdom-canvas-shapes.png)
## Building
diff --git a/examples/hdom-canvas-shapes/package.json b/examples/hdom-canvas-shapes/package.json
index 77e9f5ce79..48d85c0b12 100644
--- a/examples/hdom-canvas-shapes/package.json
+++ b/examples/hdom-canvas-shapes/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-canvas-shapes/src/index.ts b/examples/hdom-canvas-shapes/src/index.ts
index e40da4456e..8ab3b83f11 100644
--- a/examples/hdom-canvas-shapes/src/index.ts
+++ b/examples/hdom-canvas-shapes/src/index.ts
@@ -1,4 +1,4 @@
-import { hsva } from "@thi.ng/color";
+import { hsv } from "@thi.ng/color";
import { download } from "@thi.ng/dl-asset";
import { pathBuilder, points } from "@thi.ng/geom";
import { canvas, normalizeTree } from "@thi.ng/hdom-canvas";
@@ -284,7 +284,7 @@ const TESTS: any = {
map(
(x) => [
"ellipse",
- { stroke: hsva(x / 20, 1, 1) },
+ { stroke: hsv(x / 20, 1, 1) },
[150, 150], // pos
addN(null, sincos(t + x * 0.1, 75), 75), // radii
Math.sin(t * 0.25), // axis
diff --git a/examples/hdom-dropdown-fuzzy/package.json b/examples/hdom-dropdown-fuzzy/package.json
index 3145d57223..483ade352c 100644
--- a/examples/hdom-dropdown-fuzzy/package.json
+++ b/examples/hdom-dropdown-fuzzy/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-dropdown/package.json b/examples/hdom-dropdown/package.json
index 1f6e99faf2..835f3fd3c0 100644
--- a/examples/hdom-dropdown/package.json
+++ b/examples/hdom-dropdown/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-dyn-context/package.json b/examples/hdom-dyn-context/package.json
index d859436a1d..82216eddf5 100644
--- a/examples/hdom-dyn-context/package.json
+++ b/examples/hdom-dyn-context/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-elm/package.json b/examples/hdom-elm/package.json
index f23f03559b..29e41797fc 100644
--- a/examples/hdom-elm/package.json
+++ b/examples/hdom-elm/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-inner-html/package.json b/examples/hdom-inner-html/package.json
index e02daaddbf..6211f2fab4 100644
--- a/examples/hdom-inner-html/package.json
+++ b/examples/hdom-inner-html/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-local-render/package.json b/examples/hdom-local-render/package.json
index ad7fc2c9b1..52a81dcbb6 100644
--- a/examples/hdom-local-render/package.json
+++ b/examples/hdom-local-render/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-localstate/package.json b/examples/hdom-localstate/package.json
index 8ea816382f..be80b65907 100644
--- a/examples/hdom-localstate/package.json
+++ b/examples/hdom-localstate/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-skip-nested/package.json b/examples/hdom-skip-nested/package.json
index 8a29598859..5f41c86071 100644
--- a/examples/hdom-skip-nested/package.json
+++ b/examples/hdom-skip-nested/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-skip/package.json b/examples/hdom-skip/package.json
index 3ab471b0e0..f8ca0171a1 100644
--- a/examples/hdom-skip/package.json
+++ b/examples/hdom-skip/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-theme-adr-0003/package.json b/examples/hdom-theme-adr-0003/package.json
index 2142959a36..2e14901a61 100644
--- a/examples/hdom-theme-adr-0003/package.json
+++ b/examples/hdom-theme-adr-0003/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-toggle/README.md b/examples/hdom-toggle/README.md
index ca49457a6f..f01b30ad33 100644
--- a/examples/hdom-toggle/README.md
+++ b/examples/hdom-toggle/README.md
@@ -1,5 +1,7 @@
# hdom-toggle
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/hdom-toggle.png)
+
[Live demo](http://demo.thi.ng/umbrella/hdom-toggle/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/hdom-toggle/package.json b/examples/hdom-toggle/package.json
index bd90e93969..2e2fad5fc9 100644
--- a/examples/hdom-toggle/package.json
+++ b/examples/hdom-toggle/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hdom-vscroller/package.json b/examples/hdom-vscroller/package.json
index 85b9a556ac..a3453bbb06 100644
--- a/examples/hdom-vscroller/package.json
+++ b/examples/hdom-vscroller/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hiccup-canvas-arcs/README.md b/examples/hiccup-canvas-arcs/README.md
index 52ed0d9df8..4eb7e6ab2c 100644
--- a/examples/hiccup-canvas-arcs/README.md
+++ b/examples/hiccup-canvas-arcs/README.md
@@ -1,5 +1,7 @@
# hiccup-canvas-arcs
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/hiccup-canvas-arcs.png)
+
[Live demo](http://demo.thi.ng/umbrella/hiccup-canvas-arcs/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/hiccup-canvas-arcs/package.json b/examples/hiccup-canvas-arcs/package.json
index bf08074e5f..fee935241a 100644
--- a/examples/hiccup-canvas-arcs/package.json
+++ b/examples/hiccup-canvas-arcs/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/hiccup-canvas-arcs/src/index.ts b/examples/hiccup-canvas-arcs/src/index.ts
index 2dc266fbc2..ee33ea54fe 100644
--- a/examples/hiccup-canvas-arcs/src/index.ts
+++ b/examples/hiccup-canvas-arcs/src/index.ts
@@ -1,4 +1,4 @@
-import { hsla } from "@thi.ng/color";
+import { hsl } from "@thi.ng/color";
import {
arc,
asCubic,
@@ -34,7 +34,7 @@ const arcs = [
// stroke width
w: SYSTEM.minmax(1, 5),
// randomized HSLA color
- col: hsla([SYSTEM.norm(0.1), SYSTEM.minmax(0.5, 1), 0.5]),
+ col: hsl([SYSTEM.norm(0.1), SYSTEM.minmax(0.5, 1), 0.5]),
// start angle
theta: SYSTEM.float(TAU),
// angle spread
diff --git a/examples/hydrate-basics/package.json b/examples/hydrate-basics/package.json
index 29ddd8622b..13e98ae372 100644
--- a/examples/hydrate-basics/package.json
+++ b/examples/hydrate-basics/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/imgui-basics/README.md b/examples/imgui-basics/README.md
index a07527c3a3..3b3136307e 100644
--- a/examples/imgui-basics/README.md
+++ b/examples/imgui-basics/README.md
@@ -1,5 +1,7 @@
# imgui-basics
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/imgui-basics.png)
+
[Live demo](http://demo.thi.ng/umbrella/imgui-basics/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/imgui-basics/package.json b/examples/imgui-basics/package.json
index 49418b451e..8e910f078f 100644
--- a/examples/imgui-basics/package.json
+++ b/examples/imgui-basics/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/imgui/README.md b/examples/imgui/README.md
index 3a9129b38d..c0a599425c 100644
--- a/examples/imgui/README.md
+++ b/examples/imgui/README.md
@@ -1,6 +1,6 @@
# imgui
-![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/master/assets/imgui/imgui-all.png)
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/imgui/imgui-all.png)
[Live demo](http://demo.thi.ng/umbrella/imgui/)
diff --git a/examples/imgui/package.json b/examples/imgui/package.json
index 823932b0be..4358f79c07 100644
--- a/examples/imgui/package.json
+++ b/examples/imgui/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/interceptor-basics/package.json b/examples/interceptor-basics/package.json
index a26bf5a205..2e444610cd 100644
--- a/examples/interceptor-basics/package.json
+++ b/examples/interceptor-basics/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/interceptor-basics2/package.json b/examples/interceptor-basics2/package.json
index 76e2ca3f7b..34e67ad6e3 100644
--- a/examples/interceptor-basics2/package.json
+++ b/examples/interceptor-basics2/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/iso-plasma/README.md b/examples/iso-plasma/README.md
index 28dfd44ad2..0ecf9d3ed9 100644
--- a/examples/iso-plasma/README.md
+++ b/examples/iso-plasma/README.md
@@ -1,5 +1,7 @@
# iso-plasma
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/geom/geom-isoline.png)
+
[Live demo](http://demo.thi.ng/umbrella/iso-plasma/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/iso-plasma/package.json b/examples/iso-plasma/package.json
index 3222b450d8..21ecf17a5e 100644
--- a/examples/iso-plasma/package.json
+++ b/examples/iso-plasma/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/json-components/README.md b/examples/json-components/README.md
index b33c2e93ea..93bbbed042 100644
--- a/examples/json-components/README.md
+++ b/examples/json-components/README.md
@@ -1,5 +1,7 @@
# json-components
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/json-components.jpg)
+
[Live demo](https://demo.thi.ng/umbrella/json-components/)
Please refer to the [example build
diff --git a/examples/json-components/package.json b/examples/json-components/package.json
index bb7e2b6996..fea63812f3 100644
--- a/examples/json-components/package.json
+++ b/examples/json-components/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/login-form/package.json b/examples/login-form/package.json
index 5d0ae87e4c..ed9ad3a067 100644
--- a/examples/login-form/package.json
+++ b/examples/login-form/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/mandelbrot/README.md b/examples/mandelbrot/README.md
index ab087eb66a..fdf931f6fb 100644
--- a/examples/mandelbrot/README.md
+++ b/examples/mandelbrot/README.md
@@ -1,5 +1,7 @@
# mandelbrot
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/mandelbrot.jpg)
+
[Live demo](http://demo.thi.ng/umbrella/mandelbrot/)
Please refer to the [example build
diff --git a/examples/mandelbrot/package.json b/examples/mandelbrot/package.json
index 31b67323e5..6f5f27e24f 100644
--- a/examples/mandelbrot/package.json
+++ b/examples/mandelbrot/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "yarn build:worker && ../../node_modules/.bin/snowpack dev",
+ "start": "yarn build:worker && ../../node_modules/.bin/snowpack dev --reload",
"build": "yarn build:worker && ../../node_modules/.bin/snowpack build",
"build:worker": "../../node_modules/.bin/webpack --config webpack.worker.js --mode production"
},
diff --git a/examples/markdown/README.md b/examples/markdown/README.md
index ebc4e57afe..00640da84a 100644
--- a/examples/markdown/README.md
+++ b/examples/markdown/README.md
@@ -1,5 +1,7 @@
# Minimal Markdown parser
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/markdown-parser.jpg)
+
This project is part of the
[@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo.
@@ -91,6 +93,8 @@ import { parse } from "@thi.ng/hiccup-markdown";
const src = `
# Hello world
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/Hello world.png)
+
[This](http://example.com) is a _test_.
`;
diff --git a/examples/markdown/package.json b/examples/markdown/package.json
index 4f0e17fb97..128a0d2fa1 100644
--- a/examples/markdown/package.json
+++ b/examples/markdown/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/multitouch/package.json b/examples/multitouch/package.json
index 853dc6b679..b8059110ab 100644
--- a/examples/multitouch/package.json
+++ b/examples/multitouch/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/package-stats/package.json b/examples/package-stats/package.json
index 3fdc45f71f..3df0164ecf 100644
--- a/examples/package-stats/package.json
+++ b/examples/package-stats/package.json
@@ -10,8 +10,8 @@
"build": "yarn clean && ../../node_modules/.bin/ts-node src/index.ts"
},
"devDependencies": {
- "ts-node": "^9.1.0",
- "typescript": "^4.1.3"
+ "ts-node": "^9.1.1",
+ "typescript": "^4.1.5"
},
"dependencies": {
"@thi.ng/checks": "latest",
diff --git a/examples/parse-playground/README.md b/examples/parse-playground/README.md
index a26bcd00ac..dd66f99b23 100644
--- a/examples/parse-playground/README.md
+++ b/examples/parse-playground/README.md
@@ -1,5 +1,7 @@
# parse-playground
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/parse-playground.png)
+
[Visit playground](http://demo.thi.ng/umbrella/parse-playground/)
This project was largely created during the very first [thi.ng/umbrella
diff --git a/examples/parse-playground/package.json b/examples/parse-playground/package.json
index 1176b2b3a3..6fe946bcc9 100644
--- a/examples/parse-playground/package.json
+++ b/examples/parse-playground/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/pixel-basics/README.md b/examples/pixel-basics/README.md
index 62356bf182..5f7ea35bca 100644
--- a/examples/pixel-basics/README.md
+++ b/examples/pixel-basics/README.md
@@ -1,8 +1,8 @@
# pixel-basics
-[Live demo](http://demo.thi.ng/umbrella/pixel-basics/)
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/pixel/pixel-basics.png)
-![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/master/assets/pixel/pixel-basics.png)
+[Live demo](http://demo.thi.ng/umbrella/pixel-basics/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/pixel-basics/package.json b/examples/pixel-basics/package.json
index 54815faa45..59cc7f51ae 100644
--- a/examples/pixel-basics/package.json
+++ b/examples/pixel-basics/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/pixel-sorting/.gitignore b/examples/pixel-sorting/.gitignore
new file mode 100644
index 0000000000..211b157174
--- /dev/null
+++ b/examples/pixel-sorting/.gitignore
@@ -0,0 +1,6 @@
+build
+dev
+node_modules
+yarn.lock
+!snowpack.config.js
+!*.d.ts
diff --git a/examples/pixel-sorting/README.md b/examples/pixel-sorting/README.md
new file mode 100644
index 0000000000..5bcad3d539
--- /dev/null
+++ b/examples/pixel-sorting/README.md
@@ -0,0 +1,15 @@
+# pixel-sorting
+
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/pixel-sorting.png)
+
+[Live demo](http://demo.thi.ng/umbrella/pixel-sorting/)
+
+Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
+
+## Authors
+
+- Karsten Schmidt
+
+## License
+
+© 2020 Karsten Schmidt // Apache Software License 2.0
diff --git a/examples/pixel-sorting/package.json b/examples/pixel-sorting/package.json
new file mode 100644
index 0000000000..3dbed45bf5
--- /dev/null
+++ b/examples/pixel-sorting/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "pixel-sorting",
+ "version": "0.0.1",
+ "description": "Interactive pixel sorting tool using thi.ng/color & thi.ng/pixel",
+ "repository": "https://github.com/thi-ng/umbrella",
+ "author": "Karsten Schmidt ",
+ "license": "Apache-2.0",
+ "scripts": {
+ "clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
+ "build": "../../node_modules/.bin/snowpack build"
+ },
+ "devDependencies": {
+ "@thi.ng/snowpack-env": "^2.3.3"
+ },
+ "dependencies": {
+ "@thi.ng/color": "latest",
+ "@thi.ng/hiccup-html": "latest",
+ "@thi.ng/intervals": "latest",
+ "@thi.ng/pixel": "latest",
+ "@thi.ng/random": "latest",
+ "@thi.ng/rdom": "latest",
+ "@thi.ng/rstream": "latest",
+ "@thi.ng/transducers": "latest"
+ },
+ "browserslist": [
+ "last 3 Chrome versions"
+ ],
+ "browser": {
+ "process": false
+ },
+ "thi.ng": {
+ "readme": [
+ "color",
+ "hiccup-html",
+ "intervals",
+ "pixel",
+ "random",
+ "rdom",
+ "rstream"
+ ],
+ "screenshot": "examples/pixel-sorting.png"
+ }
+}
diff --git a/examples/pixel-sorting/public/index.html b/examples/pixel-sorting/public/index.html
new file mode 100644
index 0000000000..425e6fb4f1
--- /dev/null
+++ b/examples/pixel-sorting/public/index.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ pixel-sorting
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/pixel-sorting/snowpack.config.js b/examples/pixel-sorting/snowpack.config.js
new file mode 100644
index 0000000000..13b0d72bb7
--- /dev/null
+++ b/examples/pixel-sorting/snowpack.config.js
@@ -0,0 +1,29 @@
+/** @type {import("snowpack").SnowpackUserConfig } */
+module.exports = {
+ mount: {
+ public: "/",
+ src: "/_dist_",
+ },
+ plugins: [
+ "@snowpack/plugin-typescript",
+ [
+ "@snowpack/plugin-webpack",
+ {
+ extendConfig: (config) => {
+ config.node = {
+ process: false,
+ setImmediate: false,
+ util: "empty",
+ };
+ return config;
+ },
+ },
+ ],
+ ],
+ installOptions: {
+ installTypes: true,
+ },
+ buildOptions: {
+ baseUrl: "/umbrella/pixel-sorting",
+ },
+};
diff --git a/examples/pixel-sorting/src/index.ts b/examples/pixel-sorting/src/index.ts
new file mode 100644
index 0000000000..c66a0e5ecd
--- /dev/null
+++ b/examples/pixel-sorting/src/index.ts
@@ -0,0 +1,234 @@
+import { timed } from "@thi.ng/bench";
+import { abgr32, luminanceAbgr32, sortMapped } from "@thi.ng/color";
+import {
+ checkbox,
+ div,
+ h1,
+ inputFile,
+ inputNumber,
+ InputNumericAttribs,
+ inputRange,
+ label,
+} from "@thi.ng/hiccup-html";
+import { closedOpen, intersection } from "@thi.ng/intervals";
+import { ABGR8888, PackedBuffer } from "@thi.ng/pixel";
+import { SYSTEM } from "@thi.ng/random";
+import { $compile, $refresh, Component, NumOrElement } from "@thi.ng/rdom";
+import { CloseMode, reactive, Stream, stream, sync } from "@thi.ng/rstream";
+import { map } from "@thi.ng/transducers";
+
+interface ProcessParams {
+ iter: number;
+ horizontal: boolean;
+ reverse: boolean;
+ min: number;
+ max: number;
+}
+
+/**
+ * Takes a ABGR pixel buffer and performs randomized pixel sorting based on
+ * given config options.
+ *
+ * @param buf
+ * @param param1
+ */
+const pixelSortBuffer = (
+ buf: PackedBuffer,
+ { iter, horizontal, reverse, min, max }: ProcessParams
+) => {
+ const { pixels, width, height } = buf;
+ const row = closedOpen(0, width);
+ const column = closedOpen(0, height);
+ for (let i = iter; --i >= 0; ) {
+ const num = SYSTEM.minmax(min, max) | 0;
+ const n2 = num >> 1;
+ // random start/pixel position in image
+ const x = SYSTEM.minmax(horizontal ? -n2 : 0, width) | 0;
+ const y = SYSTEM.minmax(horizontal ? 0 : -n2, height) | 0;
+ // build & clamp intervals so that depending on process direction
+ // we're not reading beyond RHS of selected row or bottom of selected column
+ const ix = intersection(closedOpen(x, x + num), row)!;
+ const iy = intersection(closedOpen(y, y + num), column)!;
+ // skip if interval is empty
+ if (!(ix && iy && ix.size && iy.size)) continue;
+ // memory map selected pixels in either horizontal or vertical order
+ // `mapBuffer()` returns an array of sRGB views of the underlying pixel buffer.
+ // if vertical order, there will be `width` elements between each selected pixel
+ const strip = abgr32.mapBuffer(
+ // buffer to map
+ pixels,
+ // num pixels to map
+ (horizontal ? ix : iy).size,
+ // start index in pixel buffer
+ iy.l * width + ix.l,
+ // channel stride (ignored in our case)
+ 1,
+ // pixel stride
+ horizontal ? 1 : width
+ );
+ // now we're sorting these selected pixels in place (i.e. directly
+ // within the pixel buffer) and by luminance
+ sortMapped(strip, luminanceAbgr32, reverse);
+ // mark sorted pixels
+ // strip.forEach((x) => ((x[0] += 0.05), x.clamp()));
+ }
+ return buf;
+};
+
+const processImage = (img: HTMLImageElement, opts: ProcessParams) =>
+ timed(() => pixelSortBuffer(PackedBuffer.fromImage(img, ABGR8888), opts));
+
+// stream of input files
+const file = stream();
+// images read from files
+const image = stream();
+
+// processing params
+// number of iterations
+const iter = reactive(1000);
+// sort slice min pixel width
+const min = reactive(50);
+// sort slice max pixel width
+const max = reactive(200);
+// sort pixels horizontally
+const horizontal = reactive(true);
+// sort pixels in reverse order (bright -> dark)
+const reverse = reactive(false);
+
+// stream combinator & image processor
+const result = sync({
+ src: {
+ image,
+ iter,
+ horizontal,
+ reverse,
+ min,
+ max,
+ },
+ closeOut: CloseMode.NEVER,
+ xform: map((params) => processImage(params.image, params)),
+});
+
+// triggers reading file as an image
+// once ready, puts image into `image` stream for further processing
+file.subscribe({
+ next(file) {
+ const url = URL.createObjectURL(file);
+ const img = new Image();
+ img.onload = () => {
+ image.next(img);
+ URL.revokeObjectURL(url); // house keeping!
+ };
+ img.src = url;
+ },
+});
+
+// thi.ng/rdom UI component
+// creates a canvas element and blits given pixel buffer into it
+// when the component mounts
+class PixelCanvas extends Component {
+ constructor(protected buffer: PackedBuffer) {
+ super();
+ }
+
+ async mount(parent: Element, index?: NumOrElement) {
+ const buf = this.buffer;
+ this.el = this.$el(
+ "canvas",
+ { width: buf.width, height: buf.height },
+ null,
+ parent,
+ index
+ );
+ buf.blitCanvas(this.el);
+ return this.el;
+ }
+}
+
+// UI component, grouping a form field label & input slider
+// slider is linked w/ given value stream
+const labeledRange = (
+ stream: Stream,
+ id: string,
+ labelBody: string,
+ opts: Partial
+) => {
+ const onchange = (e: InputEvent) =>
+ stream.next(parseInt((e.target).value));
+ return div(
+ ".mb2",
+ {},
+ label(".dib.w4", { for: id }, labelBody),
+ inputRange({
+ ...opts,
+ id,
+ value: stream,
+ onchange,
+ }),
+ inputNumber(".ml3.w4.tr", {
+ ...opts,
+ value: stream,
+ onchange,
+ })
+ );
+};
+
+// UI component, grouping a form field label & checkbox
+// checkbox is linked w/ given value stream
+const labeledCheckbox = (
+ stream: Stream,
+ id: string,
+ labelBody: string
+) =>
+ div(
+ ".mb2",
+ {},
+ label(".dib.w4", { for: id }, labelBody),
+ checkbox({
+ id,
+ checked: stream,
+ onchange: (e) =>
+ stream.next(!!(e.target).checked),
+ })
+ );
+
+// compile & mount main UI
+$compile(
+ div(
+ {},
+ h1({}, "Glitch my pic!"),
+ div(
+ ".mb2",
+ {},
+ label(".dib.w4", { for: "file" }, "Image"),
+ inputFile({
+ id: "file",
+ accept: ["image/jpg", "image/png", "image/gif"],
+ multiple: false,
+ onchange: (e) =>
+ file.next((e.target).files![0]),
+ })
+ ),
+ labeledRange(iter, "iter", "Iterations", {
+ min: 0,
+ max: 50000,
+ step: 1000,
+ }),
+ labeledRange(min, "min", "Min. scatter", {
+ min: 0,
+ max: 200,
+ step: 5,
+ }),
+ labeledRange(max, "max", "Max. scatter", {
+ min: 0,
+ max: 200,
+ step: 5,
+ }),
+ labeledCheckbox(horizontal, "horizontal", "Horizontal"),
+ labeledCheckbox(reverse, "order", "Reverse order"),
+ div(
+ {},
+ $refresh(result, async (buf) => new PixelCanvas(buf))
+ )
+ )
+).mount(document.getElementById("app")!);
diff --git a/examples/pixel-sorting/src/static.d.ts b/examples/pixel-sorting/src/static.d.ts
new file mode 100644
index 0000000000..67d9623753
--- /dev/null
+++ b/examples/pixel-sorting/src/static.d.ts
@@ -0,0 +1,51 @@
+/* Use this file to declare any custom file extensions for importing */
+/* Use this folder to also add/extend a package d.ts file, if needed. */
+
+/* CSS MODULES */
+declare module "*.module.css" {
+ const classes: { [key: string]: string };
+ export default classes;
+}
+declare module "*.module.scss" {
+ const classes: { [key: string]: string };
+ export default classes;
+}
+declare module "*.module.sass" {
+ const classes: { [key: string]: string };
+ export default classes;
+}
+declare module "*.module.less" {
+ const classes: { [key: string]: string };
+ export default classes;
+}
+declare module "*.module.styl" {
+ const classes: { [key: string]: string };
+ export default classes;
+}
+
+/* CSS */
+declare module "*.css";
+declare module "*.scss";
+declare module "*.sass";
+declare module "*.less";
+declare module "*.styl";
+
+/* IMAGES */
+declare module "*.svg" {
+ const ref: string;
+ export default ref;
+}
+declare module "*.gif" {
+ const ref: string;
+ export default ref;
+}
+declare module "*.jpg" {
+ const ref: string;
+ export default ref;
+}
+declare module "*.png" {
+ const ref: string;
+ export default ref;
+}
+
+/* CUSTOM: ADD YOUR OWN HERE */
diff --git a/examples/pixel-sorting/tsconfig.json b/examples/pixel-sorting/tsconfig.json
new file mode 100644
index 0000000000..48d558b4f8
--- /dev/null
+++ b/examples/pixel-sorting/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../tsconfig.json",
+ "include": ["src"],
+ "compilerOptions": {
+ "baseUrl": "./",
+ "paths": { "*": ["web_modules/.types/*"] }
+ }
+}
diff --git a/examples/pointfree-svg/README.md b/examples/pointfree-svg/README.md
index 6c7fb04f83..7a80e07ad4 100644
--- a/examples/pointfree-svg/README.md
+++ b/examples/pointfree-svg/README.md
@@ -1,17 +1,17 @@
# pointfree-svg
-This is a non-browser demo combining the following packages to generate
-the SVG graphic below:
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/pointfree-svg.png)
+
+This is a non-browser demo combining the following packages to generate the
+above SVG graphic:
- [@thi.ng/hiccup](https://github.com/thi-ng/umbrella/tree/develop/packages/hiccup)
- [@thi.ng/hiccup-svg](https://github.com/thi-ng/umbrella/tree/develop/packages/hiccup-svg)
- [@thi.ng/pointfree](https://github.com/thi-ng/umbrella/tree/develop/packages/pointfree)
- [@thi.ng/pointfree-lang](https://github.com/thi-ng/umbrella/tree/develop/packages/pointfree-lang)
-![generated result](https://raw.githubusercontent.com/thi-ng/umbrella/master/examples/pointfree-svg/output.svg)
-
Most of the [source
-code](https://raw.githubusercontent.com/thi-ng/umbrella/master/examples/pointfree-svg/src/index.ts)
+code](https://raw.githubusercontent.com/thi-ng/umbrella/develop/examples/pointfree-svg/src/index.ts)
is written in the pointfree DSL syntax and includes a rudimentary
graphics lib to generate SVG shapes in hiccup format (basically a DOM
defined by nested arrays). The example also demonstrates how to define
diff --git a/examples/pointfree-svg/package.json b/examples/pointfree-svg/package.json
index 8720e91c5e..04f0b60ed4 100644
--- a/examples/pointfree-svg/package.json
+++ b/examples/pointfree-svg/package.json
@@ -16,8 +16,8 @@
"@thi.ng/pointfree-lang": "latest"
},
"devDependencies": {
- "ts-node": "^9.1.0",
- "typescript": "^4.1.3"
+ "ts-node": "^9.1.1",
+ "typescript": "^4.1.5"
},
"thi.ng": {
"online": false,
diff --git a/examples/poisson-circles/README.md b/examples/poisson-circles/README.md
index 6b7cd73bb5..df4af07479 100644
--- a/examples/poisson-circles/README.md
+++ b/examples/poisson-circles/README.md
@@ -1,5 +1,7 @@
# poisson-circles
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/poisson/poisson.jpg)
+
[Live demo](http://demo.thi.ng/umbrella/poisson-circles/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/poisson-circles/package.json b/examples/poisson-circles/package.json
index 223bdbd1e1..9e38e96155 100644
--- a/examples/poisson-circles/package.json
+++ b/examples/poisson-circles/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/poly-spline/README.md b/examples/poly-spline/README.md
index 89971ee483..071e330f35 100644
--- a/examples/poly-spline/README.md
+++ b/examples/poly-spline/README.md
@@ -1,5 +1,7 @@
# poly-spline
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/poly-spline.png)
+
[Live demo](http://demo.thi.ng/umbrella/poly-spline/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/poly-spline/package.json b/examples/poly-spline/package.json
index 4cbb3de5ac..fe44de60dd 100644
--- a/examples/poly-spline/package.json
+++ b/examples/poly-spline/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/porter-duff/README.md b/examples/porter-duff/README.md
index 1c7b2819db..c4e23d469e 100644
--- a/examples/porter-duff/README.md
+++ b/examples/porter-duff/README.md
@@ -1,5 +1,7 @@
# porter-duff
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/porter-duff/porter-duff2.png)
+
[Live demo](http://demo.thi.ng/umbrella/porter-duff/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/porter-duff/package.json b/examples/porter-duff/package.json
index 902228c663..97fe5ca4da 100644
--- a/examples/porter-duff/package.json
+++ b/examples/porter-duff/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/ramp-synth/README.md b/examples/ramp-synth/README.md
index 761e09778c..6f699ea5c8 100644
--- a/examples/ramp-synth/README.md
+++ b/examples/ramp-synth/README.md
@@ -1,6 +1,6 @@
# ramp-synth
-![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/master/assets/examples/ramp-synth.png)
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/ramp-synth.png)
[Live demo](http://demo.thi.ng/umbrella/ramp-synth/)
diff --git a/examples/ramp-synth/package.json b/examples/ramp-synth/package.json
index aa28e70ab1..d8ca93252c 100644
--- a/examples/ramp-synth/package.json
+++ b/examples/ramp-synth/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/rdom-basics/package.json b/examples/rdom-basics/package.json
index 529d68106b..86a49bedea 100644
--- a/examples/rdom-basics/package.json
+++ b/examples/rdom-basics/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/rdom-dnd/README.md b/examples/rdom-dnd/README.md
index 98872d83bc..3e02b7bc16 100644
--- a/examples/rdom-dnd/README.md
+++ b/examples/rdom-dnd/README.md
@@ -1,5 +1,7 @@
# rdom-dnd
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rdom-dnd.png)
+
[Live demo](http://demo.thi.ng/umbrella/rdom-dnd/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/rdom-dnd/package.json b/examples/rdom-dnd/package.json
index 433b69b43e..4a95139263 100644
--- a/examples/rdom-dnd/package.json
+++ b/examples/rdom-dnd/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/rdom-lissajous/README.md b/examples/rdom-lissajous/README.md
index c56f1c905d..554716a316 100644
--- a/examples/rdom-lissajous/README.md
+++ b/examples/rdom-lissajous/README.md
@@ -1,5 +1,7 @@
# rdom-lissajous
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rdom-lissajous.png)
+
[Live demo](http://demo.thi.ng/umbrella/rdom-lissajous/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/rdom-lissajous/package.json b/examples/rdom-lissajous/package.json
index f9946c991e..79ee8d80f7 100644
--- a/examples/rdom-lissajous/package.json
+++ b/examples/rdom-lissajous/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/rdom-search-docs/package.json b/examples/rdom-search-docs/package.json
index 80ed67afb7..f3258e09dd 100644
--- a/examples/rdom-search-docs/package.json
+++ b/examples/rdom-search-docs/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/rdom-svg-nodes/README.md b/examples/rdom-svg-nodes/README.md
index d58cf511e8..225fc603df 100644
--- a/examples/rdom-svg-nodes/README.md
+++ b/examples/rdom-svg-nodes/README.md
@@ -1,5 +1,7 @@
# rdom-svg-nodes
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rdom-svg-nodes.png)
+
[Live demo](http://demo.thi.ng/umbrella/rdom-svg-nodes/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/rdom-svg-nodes/package.json b/examples/rdom-svg-nodes/package.json
index a41a167422..089b836013 100644
--- a/examples/rdom-svg-nodes/package.json
+++ b/examples/rdom-svg-nodes/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/rotating-voronoi/README.md b/examples/rotating-voronoi/README.md
index b3d78eff4e..913b73aad7 100644
--- a/examples/rotating-voronoi/README.md
+++ b/examples/rotating-voronoi/README.md
@@ -1,5 +1,7 @@
# rotating-voronoi
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rotating-voronoi.jpg)
+
[Live demo](http://demo.thi.ng/umbrella/rotating-voronoi/)
Example to show 2d spline in combination with voronoi tessellation.
@@ -9,7 +11,7 @@ Please refer to the [example build instructions](https://github.com/thi-ng/umbre
## Authors
-- Alberto Massa
+- Alberto Massa
## License
diff --git a/examples/rotating-voronoi/package.json b/examples/rotating-voronoi/package.json
index c6d2be81e8..f5c91a802b 100644
--- a/examples/rotating-voronoi/package.json
+++ b/examples/rotating-voronoi/package.json
@@ -15,7 +15,7 @@
],
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/router-basics/README.md b/examples/router-basics/README.md
index f2e6ed58a2..bd1414fafa 100644
--- a/examples/router-basics/README.md
+++ b/examples/router-basics/README.md
@@ -1,5 +1,7 @@
# router-basics
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/router-basics.jpg)
+
[Live demo](https://demo.thi.ng/umbrella/router-basics/)
Please refer to the [example build
diff --git a/examples/router-basics/package.json b/examples/router-basics/package.json
index c7a20baf4a..b9cbabc788 100644
--- a/examples/router-basics/package.json
+++ b/examples/router-basics/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/rstream-dataflow/README.md b/examples/rstream-dataflow/README.md
index 527cccf14a..c9ee831c68 100644
--- a/examples/rstream-dataflow/README.md
+++ b/examples/rstream-dataflow/README.md
@@ -8,7 +8,7 @@ on the wiki.
## About
-![dataflow graph](https://raw.githubusercontent.com/thi-ng/umbrella/master/assets/examples/rs-dflow.png)
+![dataflow graph](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rs-dflow.png)
This example combines the following packages to create & execute the
above dataflow graph in a declarative manner. The diagram generation
diff --git a/examples/rstream-dataflow/package.json b/examples/rstream-dataflow/package.json
index 46fc724fbd..e4b9b026e2 100644
--- a/examples/rstream-dataflow/package.json
+++ b/examples/rstream-dataflow/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/rstream-event-loop/README.md b/examples/rstream-event-loop/README.md
index 19f170fa28..6278a485fe 100644
--- a/examples/rstream-event-loop/README.md
+++ b/examples/rstream-event-loop/README.md
@@ -1,13 +1,13 @@
# rstream-event-loop
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rstream-event-loop.png)
+
[Live demo](http://demo.thi.ng/umbrella/rstream-event-loop/)
This example demonstrates the use of
[@thi.ng/rstream](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream)
constructs to define a basic event-loop, event handlers and reactive DOM
-updates, based on the dataflow topology shown below:
-
-![generated result](https://raw.githubusercontent.com/thi-ng/umbrella/master/assets/examples/rstream-event-loop.png)
+updates, based on the dataflow topology shown above.
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/rstream-event-loop/package.json b/examples/rstream-event-loop/package.json
index 4fa01fcab8..74a4a13e84 100644
--- a/examples/rstream-event-loop/package.json
+++ b/examples/rstream-event-loop/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/rstream-grid/README.md b/examples/rstream-grid/README.md
index 81652ee063..24363a0ae2 100644
--- a/examples/rstream-grid/README.md
+++ b/examples/rstream-grid/README.md
@@ -1,5 +1,7 @@
# rstream-grid
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rstream-grid.jpg)
+
## About
[Live demo](https://demo.thi.ng/umbrella/rstream-grid/)
diff --git a/examples/rstream-grid/package.json b/examples/rstream-grid/package.json
index 8f9a508d08..f597e58974 100644
--- a/examples/rstream-grid/package.json
+++ b/examples/rstream-grid/package.json
@@ -7,7 +7,7 @@
"license": "MIT",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/rstream-hdom/package.json b/examples/rstream-hdom/package.json
index af8531b9af..817cdb27ae 100644
--- a/examples/rstream-hdom/package.json
+++ b/examples/rstream-hdom/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/rstream-spreadsheet/README.md b/examples/rstream-spreadsheet/README.md
index 073255ca7d..c73b61abfb 100644
--- a/examples/rstream-spreadsheet/README.md
+++ b/examples/rstream-spreadsheet/README.md
@@ -1,5 +1,7 @@
# rstream-spreadsheet
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rstream-spreadsheet.png)
+
[Live demo](http://demo.thi.ng/umbrella/rstream-spreadsheet/)
Spreadsheet demo built w/
diff --git a/examples/rstream-spreadsheet/package.json b/examples/rstream-spreadsheet/package.json
index 758cc505cc..cad61173b6 100644
--- a/examples/rstream-spreadsheet/package.json
+++ b/examples/rstream-spreadsheet/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/scenegraph-image/README.md b/examples/scenegraph-image/README.md
index 2770a1077f..fd6f715a7f 100644
--- a/examples/scenegraph-image/README.md
+++ b/examples/scenegraph-image/README.md
@@ -1,5 +1,7 @@
# scenegraph-image
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/scenegraph-image.png)
+
[Live demo](http://demo.thi.ng/umbrella/scenegraph-image/)
Similar to the other [scenegraph](../scenegraph/) example, only here
diff --git a/examples/scenegraph-image/package.json b/examples/scenegraph-image/package.json
index aca4a3e2fe..40cbeef2f5 100644
--- a/examples/scenegraph-image/package.json
+++ b/examples/scenegraph-image/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/scenegraph/README.md b/examples/scenegraph/README.md
index d9a8d90bc0..2c375b7cef 100644
--- a/examples/scenegraph/README.md
+++ b/examples/scenegraph/README.md
@@ -1,5 +1,7 @@
# scenegraph
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/scenegraph.png)
+
[Live demo](http://demo.thi.ng/umbrella/scenegraph/)
Minimal 2D scene graph with support for
diff --git a/examples/scenegraph/package.json b/examples/scenegraph/package.json
index 8aba0805a2..f51de6888d 100644
--- a/examples/scenegraph/package.json
+++ b/examples/scenegraph/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/shader-ast-canvas2d/README.md b/examples/shader-ast-canvas2d/README.md
index 9b34ade718..dfb9dc425e 100644
--- a/examples/shader-ast-canvas2d/README.md
+++ b/examples/shader-ast-canvas2d/README.md
@@ -1,5 +1,7 @@
# shader-ast-canvas2d
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/shader-ast/shader-ast-01.jpg)
+
[Live demo](http://demo.thi.ng/umbrella/shader-ast-canvas2d/)
WIP example of using
diff --git a/examples/shader-ast-canvas2d/package.json b/examples/shader-ast-canvas2d/package.json
index eb220f828e..9ecd33fcee 100644
--- a/examples/shader-ast-canvas2d/package.json
+++ b/examples/shader-ast-canvas2d/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/shader-ast-evo/README.md b/examples/shader-ast-evo/README.md
index 3918156a63..2efa233322 100644
--- a/examples/shader-ast-evo/README.md
+++ b/examples/shader-ast-evo/README.md
@@ -1,5 +1,7 @@
# shader-ast-evo
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/shader-ast-evo.jpg)
+
[Live demo](http://demo.thi.ng/umbrella/shader-ast-evo/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/shader-ast-evo/package.json b/examples/shader-ast-evo/package.json
index 660a44fdcb..f5aae236ff 100644
--- a/examples/shader-ast-evo/package.json
+++ b/examples/shader-ast-evo/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/shader-ast-noise/README.md b/examples/shader-ast-noise/README.md
index a20c798013..de7ae522c6 100644
--- a/examples/shader-ast-noise/README.md
+++ b/examples/shader-ast-noise/README.md
@@ -1,5 +1,7 @@
# shader-ast-noise
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/shader-ast-noise.jpg)
+
- [Live demo (WebGL)](http://demo.thi.ng/umbrella/shader-ast-noise/)
- [Live demo (Canvas 2D)](http://demo.thi.ng/umbrella/shader-ast-noise/#2d)
diff --git a/examples/shader-ast-noise/package.json b/examples/shader-ast-noise/package.json
index f6312754b4..7f4f47fe68 100644
--- a/examples/shader-ast-noise/package.json
+++ b/examples/shader-ast-noise/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/shader-ast-raymarch/README.md b/examples/shader-ast-raymarch/README.md
index 2d32e7ea1e..6ff63952df 100644
--- a/examples/shader-ast-raymarch/README.md
+++ b/examples/shader-ast-raymarch/README.md
@@ -1,5 +1,7 @@
# shader-ast-raymarch
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/shader-ast/shader-ast-raymarch.jpg)
+
- [Live demo (WebGL)](http://demo.thi.ng/umbrella/shader-ast-raymarch/)
- [Live demo (Canvas 2D)](http://demo.thi.ng/umbrella/shader-ast-raymarch/#2d)
diff --git a/examples/shader-ast-raymarch/package.json b/examples/shader-ast-raymarch/package.json
index 37a0bdc4ea..2ae4039644 100644
--- a/examples/shader-ast-raymarch/package.json
+++ b/examples/shader-ast-raymarch/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/shader-ast-sdf2d/README.md b/examples/shader-ast-sdf2d/README.md
index 197640a2b2..666f223546 100644
--- a/examples/shader-ast-sdf2d/README.md
+++ b/examples/shader-ast-sdf2d/README.md
@@ -1,5 +1,7 @@
# shader-ast-sdf2
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/shader-ast-sdf2d.jpg)
+
- [Live demo (WebGL)](http://demo.thi.ng/umbrella/shader-ast-sdf2d/)
- [Live demo (Canvas 2D)](http://demo.thi.ng/umbrella/shader-ast-sdf2d/#2d)
diff --git a/examples/shader-ast-sdf2d/package.json b/examples/shader-ast-sdf2d/package.json
index 2d5aa69d78..6d02eae312 100644
--- a/examples/shader-ast-sdf2d/package.json
+++ b/examples/shader-ast-sdf2d/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/shader-ast-tunnel/README.md b/examples/shader-ast-tunnel/README.md
index a23a7593fd..88b0fa5dcd 100644
--- a/examples/shader-ast-tunnel/README.md
+++ b/examples/shader-ast-tunnel/README.md
@@ -1,5 +1,7 @@
# shader-ast-tunnel
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/shader-ast-tunnel.jpg)
+
- [Live demo (WebGL)](http://demo.thi.ng/umbrella/shader-ast-tunnel/)
- [Live demo (Canvas 2D)](http://demo.thi.ng/umbrella/shader-ast-tunnel/#2d)
diff --git a/examples/shader-ast-tunnel/package.json b/examples/shader-ast-tunnel/package.json
index 854cc06e6a..4e601d3882 100644
--- a/examples/shader-ast-tunnel/package.json
+++ b/examples/shader-ast-tunnel/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/shader-ast-tunnel/src/index.ts b/examples/shader-ast-tunnel/src/index.ts
index 346039f5d0..e3e5f7d6fe 100644
--- a/examples/shader-ast-tunnel/src/index.ts
+++ b/examples/shader-ast-tunnel/src/index.ts
@@ -1,5 +1,5 @@
import { swizzle8 } from "@thi.ng/binary";
-import { int32Rgba } from "@thi.ng/color";
+import { int32Srgb } from "@thi.ng/color";
import {
$x,
$xy,
@@ -123,7 +123,7 @@ if (JS_MODE) {
let y = ((uv[1] * TH) | 0) % TH;
x < 0 && (x += TW);
y < 0 && (y += TH);
- return int32Rgba([], swizzle8(texData[y * TW + x], 0, 3, 2, 1));
+ return int32Srgb([], swizzle8(texData[y * TW + x], 0, 3, 2, 1));
};
// compile AST to actual JS:
diff --git a/examples/shader-ast-workers/README.md b/examples/shader-ast-workers/README.md
index b9cfa12069..9b158eb851 100644
--- a/examples/shader-ast-workers/README.md
+++ b/examples/shader-ast-workers/README.md
@@ -1,5 +1,7 @@
# shader-ast-workers
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/shader-ast-workers.jpg)
+
[Live demo](http://demo.thi.ng/umbrella/shader-ast-workers/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/shader-ast-workers/package.json b/examples/shader-ast-workers/package.json
index cd8209bade..9eccb3a74b 100644
--- a/examples/shader-ast-workers/package.json
+++ b/examples/shader-ast-workers/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "yarn build:worker && ../../node_modules/.bin/snowpack dev",
+ "start": "yarn build:worker && ../../node_modules/.bin/snowpack dev --reload",
"build": "yarn build:worker && ../../node_modules/.bin/snowpack build",
"build:worker": "../../node_modules/.bin/webpack --config webpack.worker.js --mode production"
},
diff --git a/examples/shader-ast-workers/src/worker.ts b/examples/shader-ast-workers/src/worker.ts
index 0218cc12ed..36ccb5cac4 100644
--- a/examples/shader-ast-workers/src/worker.ts
+++ b/examples/shader-ast-workers/src/worker.ts
@@ -1,5 +1,5 @@
import { timedResult } from "@thi.ng/bench";
-import { hueRgba } from "@thi.ng/color";
+import { hueRgb } from "@thi.ng/color";
import {
$x,
$xyz,
@@ -43,7 +43,7 @@ import { sma } from "@thi.ng/transducers-stats";
import { NUM_WORKERS, WorkerJob, WorkerResult } from "./api";
// color table to tint each worker's region
-const COLORS = [...map((i) => hueRgba([], i), normRange(NUM_WORKERS))];
+const COLORS = [...map((i) => hueRgb([], i), normRange(NUM_WORKERS))];
// shader AST functions from the shader-ast-raymarch example
const scene = defn("vec2", "scene", ["vec3"], (pos) => {
diff --git a/examples/shader-graph/README.md b/examples/shader-graph/README.md
index 1e5db38f05..c01ce28dd2 100644
--- a/examples/shader-graph/README.md
+++ b/examples/shader-graph/README.md
@@ -1,10 +1,14 @@
# shader-graph
-[Live demo](http://demo.thi.ng/umbrella/shader-graph/)
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/shader-graph.jpg)
-![demo screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/shader-graph.jpg)
+[Live demo](http://demo.thi.ng/umbrella/shader-graph/)
-Minimal shader graph setup based on [@thi.ng/webgl](https://github.com/thi-ng/umbrella/tree/develop/packages/webgl), [@thi.ng/shader-ast](https://github.com/thi-ng/umbrella/tree/develop/packages/shader-ast) and [@thi.ng/scenegraph](https://github.com/thi-ng/umbrella/tree/develop/packages/scenegraph).
+Minimal shader graph setup based on
+[@thi.ng/webgl](https://github.com/thi-ng/umbrella/tree/develop/packages/webgl),
+[@thi.ng/shader-ast](https://github.com/thi-ng/umbrella/tree/develop/packages/shader-ast)
+and
+[@thi.ng/scenegraph](https://github.com/thi-ng/umbrella/tree/develop/packages/scenegraph).
This project was developed from scratch during the [2nd thi.ng livestream on
Youtube](https://www.youtube.com/watch?v=hEC_qbUXDo8). Please see video for
diff --git a/examples/shader-graph/package.json b/examples/shader-graph/package.json
index 88fbc21d2b..787acb8d15 100644
--- a/examples/shader-graph/package.json
+++ b/examples/shader-graph/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/soa-ecs/README.md b/examples/soa-ecs/README.md
index 1581428cd9..d8d1587e5d 100644
--- a/examples/soa-ecs/README.md
+++ b/examples/soa-ecs/README.md
@@ -1,6 +1,6 @@
# soa-ecs
-![100k particle system](https://raw.githubusercontent.com/thi-ng/umbrella/master/assets/examples/soa-ecs-100k.png)
+![100k particle system](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/soa-ecs-100k.png)
[Live demo](http://demo.thi.ng/umbrella/soa-ecs/)
diff --git a/examples/soa-ecs/package.json b/examples/soa-ecs/package.json
index 6ad2163da9..936615ccf2 100644
--- a/examples/soa-ecs/package.json
+++ b/examples/soa-ecs/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/soa-ecs/src/index.ts b/examples/soa-ecs/src/index.ts
index 63799eea03..6e9064c2d5 100644
--- a/examples/soa-ecs/src/index.ts
+++ b/examples/soa-ecs/src/index.ts
@@ -1,5 +1,4 @@
import { adaptDPI } from "@thi.ng/adapt-dpi";
-import { Type } from "@thi.ng/api";
import { ECS, GroupInfo, GroupTuple } from "@thi.ng/ecs";
import { start } from "@thi.ng/hdom";
import { canvasWebGL } from "@thi.ng/hdom-components";
@@ -65,13 +64,13 @@ const ecs = new ECS({ capacity: NUM });
const pos = ecs.defComponent({
id: "pos",
- type: Type.F32,
+ type: "f32",
size: 2,
})!;
const vel = ecs.defComponent({
id: "vel",
- type: Type.F32,
+ type: "f32",
size: 2,
default: () => randNormS2([0, 0]),
})!;
diff --git a/examples/stratified-grid/README.md b/examples/stratified-grid/README.md
index e3e17836db..b656093cac 100644
--- a/examples/stratified-grid/README.md
+++ b/examples/stratified-grid/README.md
@@ -1,5 +1,7 @@
# stratified-grid
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/poisson/stratified-grid.png)
+
[Live demo](http://demo.thi.ng/umbrella/stratified-grid/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/stratified-grid/package.json b/examples/stratified-grid/package.json
index b4ec27ed50..1760099e40 100644
--- a/examples/stratified-grid/package.json
+++ b/examples/stratified-grid/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/svg-barchart/README.md b/examples/svg-barchart/README.md
index fa7de9ffbb..d052eddab5 100644
--- a/examples/svg-barchart/README.md
+++ b/examples/svg-barchart/README.md
@@ -1,10 +1,12 @@
# svg-barchart
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/svg-barchart.png)
+
[Live demo](http://demo.thi.ng/umbrella/svg-barchart/)
SVG bar chart component & one-off rendering.
-![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/master/assets/examples/svg-barchart.png)
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/svg-barchart.png)
Please refer to the [example build
instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions)
diff --git a/examples/svg-barchart/package.json b/examples/svg-barchart/package.json
index 0238b81ec1..7821085324 100644
--- a/examples/svg-barchart/package.json
+++ b/examples/svg-barchart/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/svg-particles/package.json b/examples/svg-particles/package.json
index 41bba9030e..517649e22a 100644
--- a/examples/svg-particles/package.json
+++ b/examples/svg-particles/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/svg-waveform/README.md b/examples/svg-waveform/README.md
index 5d9cb17a14..6694d99ed9 100644
--- a/examples/svg-waveform/README.md
+++ b/examples/svg-waveform/README.md
@@ -1,4 +1,7 @@
# svg-waveform
+
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/svg-waveform.png)
+
## About
Interactive, additive waveform synthesis (no audio) and SVG waveform
diff --git a/examples/svg-waveform/package.json b/examples/svg-waveform/package.json
index 2de146f4e2..aee5706f8f 100644
--- a/examples/svg-waveform/package.json
+++ b/examples/svg-waveform/package.json
@@ -7,7 +7,7 @@
"license": "MIT",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/talk-slides/README.md b/examples/talk-slides/README.md
index d8cac3d8cf..72a451d92b 100644
--- a/examples/talk-slides/README.md
+++ b/examples/talk-slides/README.md
@@ -1,5 +1,7 @@
# talk-slides
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/talk-slides.png)
+
[Live demo](http://media.thi.ng/2018/talks/clojurex/index.html) |
[Exported PDF](http://media.thi.ng/2018/talks/clojurex/slides.pdf)
diff --git a/examples/talk-slides/package.json b/examples/talk-slides/package.json
index 1a850372f6..a7d99ef9cc 100644
--- a/examples/talk-slides/package.json
+++ b/examples/talk-slides/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/text-canvas-image/README.md b/examples/text-canvas-image/README.md
index f65afd4f91..fd443fb80b 100644
--- a/examples/text-canvas-image/README.md
+++ b/examples/text-canvas-image/README.md
@@ -1,5 +1,7 @@
# text-canvas-image
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/text-canvas-image.png)
+
[Live demo](http://demo.thi.ng/umbrella/text-canvas-image/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/text-canvas-image/package.json b/examples/text-canvas-image/package.json
index d42ffb9319..a0448d0a0a 100644
--- a/examples/text-canvas-image/package.json
+++ b/examples/text-canvas-image/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"devDependencies": {
diff --git a/examples/text-canvas/README.md b/examples/text-canvas/README.md
index 38b65403f0..4730270711 100644
--- a/examples/text-canvas/README.md
+++ b/examples/text-canvas/README.md
@@ -1,5 +1,7 @@
# text-canvas
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/text-canvas.png)
+
[Live demo](http://demo.thi.ng/umbrella/text-canvas/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/text-canvas/package.json b/examples/text-canvas/package.json
index 3e0c96f55c..9f3badb15b 100644
--- a/examples/text-canvas/package.json
+++ b/examples/text-canvas/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/todo-list/README.md b/examples/todo-list/README.md
index a2260e0264..1042c3afc1 100644
--- a/examples/todo-list/README.md
+++ b/examples/todo-list/README.md
@@ -1,4 +1,6 @@
-# @thi.ng/hdom todo list example
+# Todo list with undo/redo
+
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/todo-list.png)
[Live demo here](https://demo.thi.ng/umbrella/todo-list/)
diff --git a/examples/todo-list/package.json b/examples/todo-list/package.json
index e94405fc58..bc722bea7f 100644
--- a/examples/todo-list/package.json
+++ b/examples/todo-list/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/transducers-hdom/package.json b/examples/transducers-hdom/package.json
index f5792711d3..5991e0525e 100644
--- a/examples/transducers-hdom/package.json
+++ b/examples/transducers-hdom/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/triple-query/README.md b/examples/triple-query/README.md
index c10f1deb11..203b539b5a 100644
--- a/examples/triple-query/README.md
+++ b/examples/triple-query/README.md
@@ -1,5 +1,7 @@
# triple-query
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/triple-query.png)
+
[Live demo](https://demo.thi.ng/umbrella/triple-query/)
Please refer to the [example build
diff --git a/examples/triple-query/package.json b/examples/triple-query/package.json
index 5b026dbb8e..5cd840e4e3 100644
--- a/examples/triple-query/package.json
+++ b/examples/triple-query/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/webgl-cube/README.md b/examples/webgl-cube/README.md
index 03e45d8cf9..5c9907113c 100644
--- a/examples/webgl-cube/README.md
+++ b/examples/webgl-cube/README.md
@@ -1,5 +1,7 @@
# webgl-cube
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/webgl-cube.png)
+
[Live demo](http://demo.thi.ng/umbrella/webgl-cube/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/webgl-cube/package.json b/examples/webgl-cube/package.json
index cb62e0c0e0..6e96175ccd 100644
--- a/examples/webgl-cube/package.json
+++ b/examples/webgl-cube/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/webgl-cubemap/README.md b/examples/webgl-cubemap/README.md
index d195e78c10..97e1d8d1f1 100644
--- a/examples/webgl-cubemap/README.md
+++ b/examples/webgl-cubemap/README.md
@@ -1,5 +1,7 @@
# webgl-cubemap
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/webgl-cubemap.jpg)
+
WebGL 360Λ panorama / cube map example. Images by [Emil
Persson](http://www.humus.name/index.php?page=Textures).
diff --git a/examples/webgl-cubemap/package.json b/examples/webgl-cubemap/package.json
index 5123c55322..a7e1f9506e 100644
--- a/examples/webgl-cubemap/package.json
+++ b/examples/webgl-cubemap/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/webgl-grid/README.md b/examples/webgl-grid/README.md
index 58690b02df..702d49b3c2 100644
--- a/examples/webgl-grid/README.md
+++ b/examples/webgl-grid/README.md
@@ -1,5 +1,7 @@
# webgl-grid
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/webgl-grid.jpg)
+
[Live demo](http://demo.thi.ng/umbrella/webgl-grid/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/webgl-grid/package.json b/examples/webgl-grid/package.json
index 3da93715b6..672fb5c080 100644
--- a/examples/webgl-grid/package.json
+++ b/examples/webgl-grid/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/webgl-msdf/README.md b/examples/webgl-msdf/README.md
index 37974f31b0..b1bc3a5ef5 100644
--- a/examples/webgl-msdf/README.md
+++ b/examples/webgl-msdf/README.md
@@ -1,8 +1,12 @@
# webgl-msdf
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/webgl-msdf.jpg)
+
[Live demo](http://demo.thi.ng/umbrella/webgl-msdf/)
-Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
+Please refer to the [example build
+instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions)
+on the wiki.
## Authors
diff --git a/examples/webgl-msdf/package.json b/examples/webgl-msdf/package.json
index 0bf6634945..541a216dd6 100644
--- a/examples/webgl-msdf/package.json
+++ b/examples/webgl-msdf/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/webgl-msdf/src/index.ts b/examples/webgl-msdf/src/index.ts
index 56877341a2..e1b94557d9 100644
--- a/examples/webgl-msdf/src/index.ts
+++ b/examples/webgl-msdf/src/index.ts
@@ -1,5 +1,4 @@
import { adaptDPI } from "@thi.ng/adapt-dpi";
-import { GLType } from "@thi.ng/api";
import { start } from "@thi.ng/hdom";
import { canvasWebGL } from "@thi.ng/hdom-components";
import { fitClamped } from "@thi.ng/math";
@@ -120,9 +119,9 @@ const createText = (
const createStarField = (gl: WebGLRenderingContext, num = 1000) => {
const pool = new AttribPool({
attribs: {
- position: { type: GLType.F32, size: 3, byteOffset: 0 },
- dir: { type: GLType.F32, size: 3, byteOffset: 12 },
- id: { type: GLType.F32, size: 1, byteOffset: 24 },
+ position: { type: "f32", size: 3, byteOffset: 0 },
+ dir: { type: "f32", size: 3, byteOffset: 12 },
+ id: { type: "f32", size: 1, byteOffset: 24 },
},
mem: {
size: num * 28 + 8 /* FIXME */ + 40,
diff --git a/examples/webgl-multipass/package.json b/examples/webgl-multipass/package.json
index 274091bf4c..03d5d74ece 100644
--- a/examples/webgl-multipass/package.json
+++ b/examples/webgl-multipass/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/webgl-shadertoy/README.md b/examples/webgl-shadertoy/README.md
index 014b01d782..54397496c2 100644
--- a/examples/webgl-shadertoy/README.md
+++ b/examples/webgl-shadertoy/README.md
@@ -1,5 +1,7 @@
# webgl-shadertoy
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/webgl-shadertoy.jpg)
+
[Live demo](http://demo.thi.ng/umbrella/webgl-shadertoy/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/webgl-shadertoy/package.json b/examples/webgl-shadertoy/package.json
index c1affe9806..4bf2d8a75f 100644
--- a/examples/webgl-shadertoy/package.json
+++ b/examples/webgl-shadertoy/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/webgl-ssao/README.md b/examples/webgl-ssao/README.md
index c2de9d5fa7..1a80462174 100644
--- a/examples/webgl-ssao/README.md
+++ b/examples/webgl-ssao/README.md
@@ -1,5 +1,7 @@
# webgl-ssao
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/webgl-ssao.jpg)
+
[Live demo](http://demo.thi.ng/umbrella/webgl-ssao/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/webgl-ssao/package.json b/examples/webgl-ssao/package.json
index 5c04277ef7..55c50442a0 100644
--- a/examples/webgl-ssao/package.json
+++ b/examples/webgl-ssao/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/wolfram/README.md b/examples/wolfram/README.md
index 9a345a30b4..4f56ebbbe0 100644
--- a/examples/wolfram/README.md
+++ b/examples/wolfram/README.md
@@ -1,5 +1,7 @@
# wolfram
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/wolfram.png)
+
[Live demo](http://demo.thi.ng/umbrella/wolfram/)
Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.
diff --git a/examples/wolfram/package.json b/examples/wolfram/package.json
index e8e0296ab2..211b46f170 100644
--- a/examples/wolfram/package.json
+++ b/examples/wolfram/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"dependencies": {
diff --git a/examples/xml-converter/README.md b/examples/xml-converter/README.md
index 308bc041f0..991a005644 100644
--- a/examples/xml-converter/README.md
+++ b/examples/xml-converter/README.md
@@ -1,5 +1,7 @@
# xml-converter
+![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/xml-converter.png)
+
[Live demo](http://demo.thi.ng/umbrella/xml-converter/)
This example uses
@@ -15,7 +17,7 @@ This diagram illustrates the
[@thi.ng/rstream](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream)
dataflow topology used by the browser app:
-![dataflow](https://raw.githubusercontent.com/thi-ng/umbrella/master/assets/examples/xml-converter.png)
+![dataflow](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/xml-converter-dflow.png)
## Browser version
diff --git a/examples/xml-converter/package.json b/examples/xml-converter/package.json
index 790644fde7..5713ea5745 100644
--- a/examples/xml-converter/package.json
+++ b/examples/xml-converter/package.json
@@ -7,7 +7,7 @@
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
- "start": "../../node_modules/.bin/snowpack dev",
+ "start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build",
"build:cli": "../../node_modules/.bin/tsc -p tsconfig-cli.json"
},
diff --git a/package.json b/package.json
index 6ea840b423..2ce532a5c6 100644
--- a/package.json
+++ b/package.json
@@ -14,15 +14,15 @@
"gzip-size": "^6.0.0",
"html-minifier-terser": "^5.1.1",
"lerna": "^3.22.1",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"rimraf": "^3.0.2",
- "rollup": "^2.35.1",
+ "rollup": "^2.39.0",
"rollup-plugin-cleanup": "^3.2.1",
"snowpack": "^2.18.5",
- "terser": "^5.5.1",
- "ts-loader": "^8.0.12",
- "typescript": "^4.1.3",
+ "terser": "^5.6.0",
+ "ts-loader": "^8.0.17",
+ "typescript": "^4.1.5",
"webpack": "^5.11.0",
"webpack-cli": "^4.2.0"
},
@@ -49,6 +49,6 @@
"tool:searchindex": "ts-node -P tools/tsconfig.json tools/src/build-search-index.ts"
},
"resolutions": {
- "typescript": "^4.1.3"
+ "typescript": "^4.1.5"
}
}
diff --git a/packages/adapt-dpi/CHANGELOG.md b/packages/adapt-dpi/CHANGELOG.md
index c7bd982d0e..fef73e2b4c 100644
--- a/packages/adapt-dpi/CHANGELOG.md
+++ b/packages/adapt-dpi/CHANGELOG.md
@@ -3,15 +3,7 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [1.0.13](https://github.com/thi-ng/umbrella/compare/@thi.ng/adapt-dpi@1.0.12...@thi.ng/adapt-dpi@1.0.13) (2021-01-02)
-
-**Note:** Version bump only for package @thi.ng/adapt-dpi
-
-
-
-
-
-## [1.0.12](https://github.com/thi-ng/umbrella/compare/@thi.ng/adapt-dpi@1.0.11...@thi.ng/adapt-dpi@1.0.12) (2020-12-22)
+## [1.0.14](https://github.com/thi-ng/umbrella/compare/@thi.ng/adapt-dpi@1.0.13...@thi.ng/adapt-dpi@1.0.14) (2021-02-20)
**Note:** Version bump only for package @thi.ng/adapt-dpi
diff --git a/packages/adapt-dpi/package.json b/packages/adapt-dpi/package.json
index 7db8a00703..44616839ee 100644
--- a/packages/adapt-dpi/package.json
+++ b/packages/adapt-dpi/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/adapt-dpi",
- "version": "1.0.13",
+ "version": "1.0.14",
"description": "HDPI canvas adapter / styling utility",
"module": "./index.js",
"main": "./lib/index.js",
@@ -41,11 +41,11 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"files": [
"*.js",
diff --git a/packages/adjacency/CHANGELOG.md b/packages/adjacency/CHANGELOG.md
index 1d7a5da518..ede714e3de 100644
--- a/packages/adjacency/CHANGELOG.md
+++ b/packages/adjacency/CHANGELOG.md
@@ -3,49 +3,38 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [0.2.6](https://github.com/thi-ng/umbrella/compare/@thi.ng/adjacency@0.2.5...@thi.ng/adjacency@0.2.6) (2021-01-22)
+# [0.3.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/adjacency@0.2.6...@thi.ng/adjacency@0.3.0) (2021-02-20)
-**Note:** Version bump only for package @thi.ng/adjacency
+### Features
+* **adjacency:** add AdjacencyList impl & initial tests ([8f44c97](https://github.com/thi-ng/umbrella/commit/8f44c9762c0856a9b96e4548d2386eca6dcbf397))
+* **adjacency:** add IGraph.degree() & impls ([9fb02ac](https://github.com/thi-ng/umbrella/commit/9fb02ac7467785a0802c544cbc3100d6ac52fb87))
+* **adjacency:** major update Adjacency(Bit)Matrix classes & API ([cd71a5f](https://github.com/thi-ng/umbrella/commit/cd71a5fca3b2d8525c5b1c6e9032e55e39fea2dd))
+### Performance Improvements
-## [0.2.5](https://github.com/thi-ng/umbrella/compare/@thi.ng/adjacency@0.2.4...@thi.ng/adjacency@0.2.5) (2021-01-21)
-
-**Note:** Version bump only for package @thi.ng/adjacency
-
-
-
-
-
-## [0.2.4](https://github.com/thi-ng/umbrella/compare/@thi.ng/adjacency@0.2.3...@thi.ng/adjacency@0.2.4) (2021-01-13)
-
-**Note:** Version bump only for package @thi.ng/adjacency
-
-
-
-
-
-## [0.2.3](https://github.com/thi-ng/umbrella/compare/@thi.ng/adjacency@0.2.2...@thi.ng/adjacency@0.2.3) (2021-01-10)
-
-**Note:** Version bump only for package @thi.ng/adjacency
-
-
-
-
-
-## [0.2.2](https://github.com/thi-ng/umbrella/compare/@thi.ng/adjacency@0.2.1...@thi.ng/adjacency@0.2.2) (2021-01-05)
-
-**Note:** Version bump only for package @thi.ng/adjacency
-
-
-
+* **adjacency:** pre-cache MST edge costs ([290f3a6](https://github.com/thi-ng/umbrella/commit/290f3a6e1f9d71ddf3bb33f4bc6e9552896903a9))
-## [0.2.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/adjacency@0.2.0...@thi.ng/adjacency@0.2.1) (2021-01-02)
+### BREAKING CHANGES
-**Note:** Version bump only for package @thi.ng/adjacency
+* **adjacency:** replace .valence() w/ more flexible .degree() methods
+
+- add IGraph.degree() with same default behavior as .valence(),
+ but supporting diff degree types (in/out/inout)
+- add .degree() impls for all
+- remove old .valence() methods
+- update tests
+* **adjacency:** fixed order add/removeEdge(), valence(), neighbors(),
+remove static methods
+
+- update IGraph, add/update methods, return types, generics
+- remove/replace static methods in Adjacency(Bit)Matrix
+- add defAdjBitMatrix/defAdjMatrix
+- refactor/extract/re-use .toDot() graphviz conversion
+- update tests
diff --git a/packages/adjacency/README.md b/packages/adjacency/README.md
index 637c66ca9e..36f090c8ec 100644
--- a/packages/adjacency/README.md
+++ b/packages/adjacency/README.md
@@ -42,14 +42,13 @@ yarn add @thi.ng/adjacency
```
-Package sizes (gzipped, pre-treeshake): ESM: 1.74 KB / CJS: 1.82 KB / UMD: 1.92 KB
+Package sizes (gzipped, pre-treeshake): ESM: 2.29 KB / CJS: 2.38 KB / UMD: 2.44 KB
## Dependencies
- [@thi.ng/api](https://github.com/thi-ng/umbrella/tree/develop/packages/api)
-- [@thi.ng/binary](https://github.com/thi-ng/umbrella/tree/develop/packages/binary)
+- [@thi.ng/arrays](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays)
- [@thi.ng/bitfield](https://github.com/thi-ng/umbrella/tree/develop/packages/bitfield)
-- [@thi.ng/checks](https://github.com/thi-ng/umbrella/tree/develop/packages/checks)
- [@thi.ng/dcons](https://github.com/thi-ng/umbrella/tree/develop/packages/dcons)
- [@thi.ng/sparse](https://github.com/thi-ng/umbrella/tree/develop/packages/sparse)
diff --git a/packages/adjacency/package.json b/packages/adjacency/package.json
index 1a3893be6c..45b5dc0ebd 100644
--- a/packages/adjacency/package.json
+++ b/packages/adjacency/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/adjacency",
- "version": "0.2.6",
+ "version": "0.3.0",
"description": "Sparse & bitwise adjacency matrices and related functions for directed & undirected graphs",
"module": "./index.js",
"main": "./lib/index.js",
@@ -40,22 +40,21 @@
"devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@microsoft/api-extractor": "^7.12.1",
- "@thi.ng/vectors": "^4.9.1",
+ "@thi.ng/vectors": "^5.0.0",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"dependencies": {
- "@thi.ng/api": "^6.13.6",
- "@thi.ng/binary": "^2.0.21",
- "@thi.ng/bitfield": "^0.3.30",
- "@thi.ng/checks": "^2.8.0",
- "@thi.ng/dcons": "^2.3.9",
- "@thi.ng/sparse": "^0.1.64"
+ "@thi.ng/api": "^7.0.0",
+ "@thi.ng/arrays": "^0.10.2",
+ "@thi.ng/bitfield": "^0.4.0",
+ "@thi.ng/dcons": "^2.3.10",
+ "@thi.ng/sparse": "^0.1.65"
},
"files": [
"*.js",
@@ -72,6 +71,7 @@
"disjointset",
"graph",
"laplacian",
+ "list",
"matrix",
"neighbors",
"path",
@@ -82,7 +82,8 @@
"typescript",
"undirected",
"unionfind",
- "valence"
+ "valence",
+ "vertex"
],
"publishConfig": {
"access": "public"
diff --git a/packages/adjacency/src/api.ts b/packages/adjacency/src/api.ts
index 6fc236ef1c..f68d14589b 100644
--- a/packages/adjacency/src/api.ts
+++ b/packages/adjacency/src/api.ts
@@ -1,19 +1,72 @@
import type { Fn2, Pair } from "@thi.ng/api";
-export type DegreeType = "in" | "out" | "both";
+export type DegreeType = "in" | "out" | "inout";
-export interface IGraph {
+/**
+ * @typeParam T - vertex type (default: `number`)
+ */
+export interface IGraph {
numEdges(): number;
numVertices(): number;
- edges(): IterableIterator>;
-
- addEdge(from: number, to: number): this;
- removeEdge(from: number, to: number): this;
- hasEdge(from: number, to: number): boolean;
-
- valence(id: number): number;
- neighbors(id: number): number[];
+ /**
+ * Returns iterator of all edges in the graph. Each edge is a tuple of
+ * `[from, to]`. For undirected graphs each edge will only be emitted once.
+ */
+ edges(): IterableIterator>;
+ /**
+ * Attempts to add an edge between given vertex IDs. Depending on the actual
+ * implementation, only max. 1 edge per unique vertex pair is supported
+ * (currently only {@link AdjacencyList} supports multi-edges). If the graph
+ * is undirected, a symmetric edge might be created automatically. Returns
+ * true, if the edge was created.
+ *
+ * @param from
+ * @param to
+ */
+ addEdge(from: T, to: T): boolean;
+ /**
+ * Attempts to remove an edge for given vertex pair. Returns true, if
+ * successful.
+ *
+ * @param from
+ * @param to
+ */
+ removeEdge(from: T, to: T): boolean;
+ /**
+ * Returns true if an edge exists for the given vertex pair. For undirected
+ * graphs, the vertex order is irrelevant.
+ *
+ * @param from
+ * @param to
+ */
+ hasEdge(from: T, to: T): boolean;
+ /**
+ * Returns number of edges for given vertex. By default only outgoing edges
+ * are counted, but can be customized via given {@link DegreeType}. Note: In
+ * undirected graphs the `type` has no relevance and essentially is always
+ * `"inout"`.
+ *
+ * @param id
+ * @param type
+ */
+ degree(id: T, type?: DegreeType): number;
+ /**
+ * Returns neighbor IDs for given vertex, i.e. those vertices connected via
+ * edges starting *from* given vertex (or, in undirected graphs, the other
+ * vertices of edges which the given vertex is part of).
+ *
+ * @param id
+ */
+ neighbors(id: T): Iterable;
+ /**
+ * Only useful for directed graphs. Returns a new graph in which the
+ * direction of edges is inverted/flipped. I.e. an edge `a -> b` becomes `b
+ * -> a`.
+ */
+ invert(): IGraph;
}
-export type CostFn = Fn2;
+export type Edge = Pair;
+
+export type CostFn = Fn2;
diff --git a/packages/adjacency/src/bfs.ts b/packages/adjacency/src/bfs.ts
index 99235ef4cc..ea97b5875a 100644
--- a/packages/adjacency/src/bfs.ts
+++ b/packages/adjacency/src/bfs.ts
@@ -1,5 +1,4 @@
import { BitField } from "@thi.ng/bitfield";
-import { isNumber } from "@thi.ng/checks";
import { DCons } from "@thi.ng/dcons";
import type { CostFn, IGraph } from "./api";
@@ -9,26 +8,24 @@ export class BFS {
edges: Uint32Array;
dist: Uint32Array;
- constructor(graph: IGraph, src: number | Iterable, cost?: CostFn) {
+ constructor(graph: IGraph, src: number, cost: CostFn = () => 1) {
this.graph = graph;
const numV = graph.numVertices();
this.edges = new Uint32Array(numV);
this.dist = new Uint32Array(numV);
this.marked = new BitField(numV);
- this.search(isNumber(src) ? [src] : src, cost);
+ this.search(src, cost);
}
- search(ids: Iterable, cost: CostFn = () => 1) {
- const queue = new DCons(ids);
- const { dist, edges, marked } = this;
+ protected search(id: number, cost: CostFn) {
+ const queue = new DCons().cons(id);
+ const { dist, edges, graph, marked } = this;
dist.fill(0xffffffff);
- for (let id of ids) {
- dist[id] = 0;
- marked.setAt(id);
- }
+ dist[id] = 0;
+ marked.setAt(id);
while (queue.length) {
const v = queue.drop()!;
- for (let n of this.graph.neighbors(v)) {
+ for (let n of graph.neighbors(v)) {
const c = dist[v] + cost(v, n);
if (c < dist[n] || !marked.at(n)) {
edges[n] = v;
@@ -44,15 +41,39 @@ export class BFS {
return this.marked.at(id) !== 0;
}
- pathTo(id: number) {
- if (!this.hasPathTo(id)) return;
- const path: number[] = [];
+ pathTo(id: number): Iterable | undefined {
+ if (!this.marked.at(id)) return;
const { dist, edges } = this;
- let i = id;
- for (; dist[i] > 0; i = edges[i]) {
- path.push(i);
+ const path = new DCons();
+ for (; dist[id] > 0; id = edges[id]) {
+ path.cons(id);
}
- path.push(i);
+ path.cons(id);
return path;
}
}
+
+/**
+ * One-off Breadth-First / shortest path search between `src` and `dest` in
+ * `graph`, with optional `cost` function. If successful, returns path as
+ * iterable or undefined if no path connects the given vertices.
+ *
+ * @remarks
+ * For repeated queries starting from the same `src` vertex, it's much better &
+ * faster to create an {@link BFS} instance to re-use internal state and use
+ * {@link BFS.pathTo} to check/obtain paths.
+ *
+ * By default all edges have an uniform cost, i.e. the overall path cost is
+ * topological distance.
+ *
+ * Reference:
+ * - https://en.wikipedia.org/wiki/Breadth-first_search
+ * - https://algs4.cs.princeton.edu/40graphs/
+ *
+ * @param graph
+ * @param src
+ * @param dest
+ * @param cost
+ */
+export const bfs = (graph: IGraph, src: number, dest: number, cost?: CostFn) =>
+ new BFS(graph, src, cost).pathTo(dest);
diff --git a/packages/adjacency/src/binary.ts b/packages/adjacency/src/binary.ts
index a500828d9d..348892458b 100644
--- a/packages/adjacency/src/binary.ts
+++ b/packages/adjacency/src/binary.ts
@@ -1,40 +1,23 @@
-import type { Pair } from "@thi.ng/api";
-import { popCount } from "@thi.ng/binary";
import { BitMatrix } from "@thi.ng/bitfield";
-import type { IGraph } from "./api";
-
-export class AdjacencyBitMatrix implements IGraph {
- /**
- * Creates adjacency matrix with capacity `n` (max vertices) from
- * given edge pairs. Each edge is `[dest-node src-node]`.
- *
- * @remarks
- * If `undirected` is true, creates symmetrical adjacencies.
- *
- * @param n - max vertices
- * @param edges - edge pairs
- * @param undirected -true, if undirected
- */
- static fromEdges(
- n: number,
- edges: Iterable>,
- undirected = false
- ) {
- const mat = new AdjacencyBitMatrix(n, undirected);
- for (let e of edges) {
- mat.addEdge(e[0], e[1]);
- }
- return mat;
- }
+import type { DegreeType, Edge, IGraph } from "./api";
+import { into, invert, toDot } from "./utils";
+/**
+ * Adjacency matrix representation for both directed and undirected graphs and
+ * using a compact bit matrix to store edges. Each edge requires only 1 bit
+ * in directed graphs or 2 bits in undirected graphs. E.g. this is allows
+ * storing 16384 directed edges in just 2KB of memory (128 * 128 / 8 = 2048).
+ */
+export class AdjacencyBitMatrix implements IGraph {
mat: BitMatrix;
protected undirected: boolean;
protected numE: number;
- constructor(n: number, undirected = false) {
+ constructor(n: number, edges?: Iterable, undirected = false) {
this.mat = new BitMatrix(n);
this.undirected = undirected;
this.numE = 0;
+ edges && into(this, edges);
}
*edges() {
@@ -42,7 +25,7 @@ export class AdjacencyBitMatrix implements IGraph {
for (let i = this.mat.n; --i >= 0; ) {
for (let n of this.neighbors(i)) {
if (directed || n > i) {
- yield >[i, n];
+ yield [i, n];
}
}
}
@@ -67,39 +50,46 @@ export class AdjacencyBitMatrix implements IGraph {
}
addEdge(from: number, to: number) {
- !this.mat.setAt(to, from, true) && this.numE++;
- this.undirected && this.mat.setAt(from, to, true);
- return this;
+ if (!this.mat.setAt(from, to, true)) {
+ this.numE++;
+ this.undirected && this.mat.setAt(to, from, true);
+ return true;
+ }
+ return false;
}
removeEdge(from: number, to: number) {
- this.mat.setAt(to, from, false) && this.numE--;
- this.undirected && this.mat.setAt(from, to, false);
- return this;
+ if (this.mat.setAt(from, to, false)) {
+ this.numE--;
+ this.undirected && this.mat.setAt(to, from, false);
+ return true;
+ }
+ return false;
}
hasEdge(from: number, to: number) {
- return this.mat.at(to, from) !== 0;
+ return this.mat.at(from, to) !== 0;
}
- valence(id: number) {
- const s = this.mat.stride;
- const d = this.mat.data;
- let res = 0;
- id *= s;
- for (let i = id + s; --i >= id; ) {
- d[i] !== 0 && (res += popCount(d[i]));
- }
- return res;
+ degree(id: number, type: DegreeType = "out") {
+ let degree = 0;
+ if (this.undirected || type !== "in")
+ degree += this.mat.popCountRow(id);
+ if (!this.undirected && type !== "out")
+ degree += this.mat.popCountColumn(id);
+ return degree;
}
neighbors(id: number) {
- const s = this.mat.stride;
- const d = this.mat.data;
const res: number[] = [];
- id *= s;
- for (let i = this.mat.n - 1, j = id + s - 1; i >= 0; i -= 32, j--) {
- const v = d[j];
+ const { data, stride } = this.mat;
+ id *= stride;
+ for (
+ let i = this.mat.n - 1, j = id + stride - 1;
+ i >= 0;
+ i -= 32, j--
+ ) {
+ const v = data[j];
if (v !== 0) {
for (let k = 31 - Math.clz32(v); k >= 0; k--) {
(v & (1 << k)) !== 0 && res.push(i - k);
@@ -109,19 +99,34 @@ export class AdjacencyBitMatrix implements IGraph {
return res;
}
+ invert(): AdjacencyBitMatrix {
+ return invert(
+ new AdjacencyBitMatrix(this.mat.n, undefined, this.undirected),
+ this.edges()
+ );
+ }
+
toString() {
return this.mat.toString();
}
- toDot() {
- const [type, sep] = this.undirected
- ? ["graph", "--"]
- : ["digraph", "->"];
- const res = [`${type} g {`];
- for (let e of this.edges()) {
- res.push(`"${e[0]}"${sep}"${e[1]}";`);
- }
- res.push(`}`);
- return res.join("\n");
+ toDot(ids?: string[]) {
+ return toDot(this.edges(), this.undirected, ids);
}
}
+
+/**
+ * Creates adjacency matrix backed by a {@link @thi.ng/bitfield#BitMatrix}
+ * with capacity `n` (max vertices), optionally initialized with given edge
+ * pairs. Each edge is `[src-node dest-node]`. If `undirected` is true
+ * (default: false), creates symmetrical adjacencies.
+ *
+ * @param n - max vertices
+ * @param edges - edge pairs
+ * @param undirected -true, if undirected
+ */
+export const defAdjBitMatrix = (
+ n: number,
+ edges?: Iterable,
+ undirected?: boolean
+) => new AdjacencyBitMatrix(n, edges, undirected);
diff --git a/packages/adjacency/src/dfs.ts b/packages/adjacency/src/dfs.ts
index 3cc322b76a..279f816935 100644
--- a/packages/adjacency/src/dfs.ts
+++ b/packages/adjacency/src/dfs.ts
@@ -1,4 +1,5 @@
import { BitField } from "@thi.ng/bitfield";
+import { DCons } from "@thi.ng/dcons";
import type { IGraph } from "./api";
export class DFS {
@@ -17,10 +18,11 @@ export class DFS {
}
search(id: number) {
- this.marked.setAt(id);
+ const { edges, marked } = this;
+ marked.setAt(id);
for (let n of this.graph.neighbors(id)) {
- if (!this.marked.at(n)) {
- this.edges[n] = id;
+ if (!marked.at(n)) {
+ edges[n] = id;
this.search(n);
}
}
@@ -30,13 +32,26 @@ export class DFS {
return this.marked.at(id) !== 0;
}
- pathTo(id: number) {
- if (!this.hasPathTo(id)) return;
- const path = [];
- for (let i = id; i !== this.src; i = this.edges[i]) {
- path.push(i);
+ pathTo(id: number): Iterable | undefined {
+ if (!this.marked.at(id)) return;
+ const { edges, src } = this;
+ const path = new DCons();
+ for (; id !== src; id = edges[id]) {
+ path.cons(id);
}
- path.push(this.src);
+ path.cons(id);
return path;
}
}
+
+/**
+ * One-off Depth-First path search from vertex `src` to `dest` in given `graph`.
+ * If successful, returns path as iterable or undefined if no path connects the
+ * given vertices.
+ *
+ * @param graph
+ * @param src
+ * @param dest
+ */
+export const dfs = (graph: IGraph, src: number, dest: number) =>
+ new DFS(graph, src).pathTo(dest);
diff --git a/packages/adjacency/src/disjoint-set.ts b/packages/adjacency/src/disjoint-set.ts
index a6d0e211d5..21c94d008b 100644
--- a/packages/adjacency/src/disjoint-set.ts
+++ b/packages/adjacency/src/disjoint-set.ts
@@ -1,3 +1,5 @@
+import { fillRange } from "@thi.ng/arrays";
+
/**
* Typed array based Disjoint Set implementation with quick union and
* path compression, after Sedgewick & Wayne.
@@ -17,12 +19,9 @@ export class DisjointSet {
* @param n - initial capacity, ID range [0..n)
*/
constructor(n: number) {
- const roots = (this.roots = new Uint32Array(n));
- this.ranks = new Uint8Array(n).fill(0);
+ this.roots = fillRange(new Uint32Array(n));
+ this.ranks = new Uint8Array(n);
this.count = n;
- for (let i = 0; i < n; ++i) {
- roots[i] = i;
- }
}
/**
@@ -99,3 +98,10 @@ export class DisjointSet {
return sets;
}
}
+
+/**
+ * Creates a new {@link DisjointSet} with capacity `n`.
+ *
+ * @param n
+ */
+export const defDisjointSet = (n: number) => new DisjointSet(n);
diff --git a/packages/adjacency/src/index.ts b/packages/adjacency/src/index.ts
index 7a2a5a60ec..bad1961eb6 100644
--- a/packages/adjacency/src/index.ts
+++ b/packages/adjacency/src/index.ts
@@ -1,6 +1,7 @@
export * from "./api";
export * from "./binary";
export * from "./disjoint-set";
+export * from "./list";
export * from "./sparse";
export * from "./bfs";
diff --git a/packages/adjacency/src/list.ts b/packages/adjacency/src/list.ts
new file mode 100644
index 0000000000..3fa462edc9
--- /dev/null
+++ b/packages/adjacency/src/list.ts
@@ -0,0 +1,132 @@
+import { DCons } from "@thi.ng/dcons";
+import type { DegreeType, Edge, IGraph } from "./api";
+import { into, invert, toDot } from "./utils";
+
+export class AdjacencyList implements IGraph {
+ vertices: DCons[] = [];
+ indegree: number[] = [];
+ protected numE = 0;
+ protected numV = 0;
+
+ constructor(edges?: Iterable) {
+ edges && into(this, edges);
+ }
+
+ numEdges(): number {
+ return this.numE;
+ }
+
+ numVertices(): number {
+ return this.numV;
+ }
+
+ *edges() {
+ const vertices = this.vertices;
+ for (let i = 0, n = vertices.length; i < n; i++) {
+ const vertex = vertices[i];
+ if (!vertex) continue;
+ for (let j of vertex) yield [i, j];
+ }
+ }
+
+ addVertex(id: number) {
+ this.ensureVertexData(id);
+ }
+
+ removeVertex(id: number) {
+ const { vertices, indegree } = this;
+ const vertex = vertices[id];
+ if (!vertex) return false;
+ // remove outgoing
+ while (vertex.length) {
+ const to = vertex.first()!;
+ vertex.drop();
+ indegree[to]--;
+ this.numE--;
+ }
+ delete vertices[id];
+ // remove incoming
+ for (let i = 0, n = vertices.length; i < n && indegree[id] > 0; i++) {
+ const vertex = this.vertices[i];
+ if (!vertex) continue;
+ while (!!vertex.find(id)) this.removeEdge(i, id);
+ }
+ this.numV--;
+ return true;
+ }
+
+ addEdge(from: number, to: number) {
+ const vertex = this.ensureVertexData(from);
+ this.ensureVertexData(to);
+ vertex.push(to);
+ this.indegree[to]++;
+ this.numE++;
+ return true;
+ }
+
+ removeEdge(from: number, to: number) {
+ const vertex = this.vertices[from];
+ if (vertex) {
+ const dest = vertex.find(to);
+ if (dest) {
+ vertex.remove(dest);
+ this.numE--;
+ this.indegree[to]--;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ hasEdge(from: number, to: number) {
+ const vertex = this.vertices[from];
+ return vertex ? !!vertex.find(to) : false;
+ }
+
+ degree(id: number, type: DegreeType = "out") {
+ let degree = 0;
+ const vertex = this.vertices[id];
+ if (vertex) {
+ if (type !== "in") degree += vertex.length;
+ if (type !== "out") degree += this.indegree[id];
+ }
+ return degree;
+ }
+
+ neighbors(id: number): Iterable {
+ return [...(this.vertices[id] || [])];
+ }
+
+ invert(): AdjacencyList {
+ return invert(new AdjacencyList(), this.edges());
+ }
+
+ toString() {
+ const vertices = this.vertices;
+ const res: string[] = [];
+ for (let i = 0, n = vertices.length; i < n; i++) {
+ if (vertices[i]) {
+ res.push(
+ `${i}: [${[...vertices[i]]
+ .sort((a, b) => a - b)
+ .join(", ")}]`
+ );
+ }
+ }
+ return res.join("\n");
+ }
+
+ toDot(ids?: string[]) {
+ return toDot(this.edges(), false, ids);
+ }
+
+ protected ensureVertexData(id: number) {
+ const vertex = this.vertices[id];
+ if (vertex) return vertex;
+ this.numV++;
+ this.indegree[id] = 0;
+ return (this.vertices[id] = new DCons());
+ }
+}
+
+export const defAdjList = (edges?: Iterable) => new AdjacencyList(edges);
diff --git a/packages/adjacency/src/mst.ts b/packages/adjacency/src/mst.ts
index 1de139c8d8..2543756c24 100644
--- a/packages/adjacency/src/mst.ts
+++ b/packages/adjacency/src/mst.ts
@@ -1,23 +1,26 @@
import type { Fn } from "@thi.ng/api";
+import { sortByCachedKey } from "@thi.ng/arrays";
import { DisjointSet } from "./disjoint-set";
/**
* Computes the Minimum Spanning Tree from given weighted `edges`, using
- * Kruskal's algorithm.
+ * Kruskal's algorithm (O(E log V)).
*
* @remarks
- * Edges can be of any type, but requires unsigned integer vertex IDs.
- * The latter can be extracted via the user supplied `verts` function.
- * The edge weights are extracted via the `cost` function.
+ * Edges can be of any type, but requires unsigned integer vertex IDs. The
+ * latter can be extracted via the user supplied `verts` function. The edge
+ * weights are extracted via the `cost` function.
*
- * The `maxID` arg should equal or greater than the largest vertex ID
- * referenced by the given edges.
+ * The `maxID` arg should equal or greater than the largest vertex ID referenced
+ * by the given edges.
*
- * The function returns a new array of the original edges, satisfying
- * the MST criteria. The result edges will be in ascending order, based
- * on the supplied cost function.
+ * The function returns a new array of the original edges, satisfying the MST
+ * criteria. The result edges will be in ascending order, based on the supplied
+ * cost function. The cost function is called once for each edge and return
+ * values will be cached prior to sorting (see
+ * {@link @thi.ng/arrays#sortByCachedKey} for details).
*
- * {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm}
+ * Reference: {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm}
*
* @example
* ```ts
@@ -44,6 +47,8 @@ import { DisjointSet } from "./disjoint-set";
* @param maxID - max vertex ID (+1)
* @param cost - cost function
* @param verts - vertices / graph nodes
+ *
+ * @typeParam T - edge type
*/
export const mst = (
edges: T[],
@@ -53,10 +58,10 @@ export const mst = (
) => {
const graph = new DisjointSet(maxID + 1);
const res: T[] = [];
- for (let e of edges.sort((a, b) => cost(a) - cost(b))) {
+ for (let e of sortByCachedKey(edges, cost)) {
const v = verts(e);
- if (!graph.unified(...v)) {
- graph.union(...v);
+ if (!graph.unified(v[0], v[1])) {
+ graph.union(v[0], v[1]);
res.push(e);
}
}
diff --git a/packages/adjacency/src/sparse.ts b/packages/adjacency/src/sparse.ts
index e1dfc09cc9..e66b7ea17a 100644
--- a/packages/adjacency/src/sparse.ts
+++ b/packages/adjacency/src/sparse.ts
@@ -1,37 +1,8 @@
-import type { Pair } from "@thi.ng/api";
import { CSR } from "@thi.ng/sparse";
-import type { DegreeType, IGraph } from "./api";
-
-export class AdjacencyMatrix extends CSR implements IGraph {
- static newEmpty(n: number, undirected = false) {
- const raw = CSR.empty(n);
- return new AdjacencyMatrix(n, raw.data, raw.rows, raw.cols, undirected);
- }
-
- /**
- * Creates adjacency matrix from given edge pairs. Each edge is
- * `[dest-node src-node]`.
- *
- * @remarks
- * If `undirected` is true (default: false), creates symmetrical
- * edges.
- *
- * @param n - max number of vertices
- * @param edges - edge pairs
- * @param undirected - true, if undirected
- */
- static fromEdges(
- n: number,
- edges: Iterable>,
- undirected = false
- ) {
- const mat = AdjacencyMatrix.newEmpty(n, undirected);
- for (let e of edges) {
- mat.addEdge(e[0], e[1]);
- }
- return mat;
- }
+import type { DegreeType, Edge, IGraph } from "./api";
+import { into, invert, toDot } from "./utils";
+export class AdjacencyMatrix extends CSR implements IGraph {
undirected: boolean;
constructor(
@@ -53,26 +24,32 @@ export class AdjacencyMatrix extends CSR implements IGraph {
for (let j = rows[i]; j < jj; j++) {
const k = cols[j];
if (directed || i <= k) {
- yield >[i, k];
+ yield [i, k];
}
}
}
}
addEdge(from: number, to: number) {
- this.setAt(to, from, 1);
- this.undirected && this.setAt(from, to, 1);
- return this;
+ if (!this.at(from, to)) {
+ this.setAt(from, to, 1, false);
+ this.undirected && this.setAt(to, from, 1, false);
+ return true;
+ }
+ return false;
}
removeEdge(from: number, to: number) {
- this.setAt(to, from, 0);
- this.undirected && this.setAt(from, to, 0);
- return this;
+ if (this.at(from, to)) {
+ this.setAt(from, to, 0, false);
+ this.undirected && this.setAt(to, from, 0, false);
+ return true;
+ }
+ return false;
}
hasEdge(from: number, to: number) {
- return this.at(to, from) !== 0 || this.at(from, to) !== 0;
+ return this.at(from, to) !== 0;
}
numEdges() {
@@ -84,15 +61,32 @@ export class AdjacencyMatrix extends CSR implements IGraph {
return this.m;
}
- valence(id: number): number {
- return this.nnzRow(id);
+ degree(id: number, type: DegreeType = "out") {
+ let degree = 0;
+ this.ensureIndex(id, id);
+ if (this.undirected || type !== "in") degree += this.nnzRow(id);
+ if (!this.undirected && type !== "out") degree += this.nnzCol(id);
+ return degree;
}
neighbors(id: number): number[] {
return this.nzRowCols(id);
}
+ invert(): AdjacencyMatrix {
+ return invert(
+ defAdjMatrix(this.m, undefined, this.undirected),
+ this.edges()
+ );
+ }
+
/**
+ * Returns a diagonal sparse matrix {@link @thi.ng/sparse#CSR} containing
+ * information about the degree of each vertex, i.e. the number of edges
+ * attached to each vertex.
+ *
+ * @remarks
+ * Reference: https://en.wikipedia.org/wiki/Degree_matrix
*
* @param deg - degree type
*/
@@ -110,7 +104,7 @@ export class AdjacencyMatrix extends CSR implements IGraph {
res.setAt(i, i, this.nnzCol(i));
}
break;
- case "both":
+ case "inout":
for (let i = this.m; --i >= 0; ) {
res.setAt(i, i, this.nnzRow(i) + this.nnzCol(i));
}
@@ -136,7 +130,7 @@ export class AdjacencyMatrix extends CSR implements IGraph {
normalizedLaplacian(deg?: CSR) {
deg = deg || this.degreeMat();
const m = this.m;
- const res = AdjacencyMatrix.newEmpty(m);
+ const res = CSR.empty(m);
for (let i = 0; i < m; i++) {
for (let j = 0; j < m; j++) {
if (i === j && deg.at(i, i) > 0) {
@@ -154,7 +148,7 @@ export class AdjacencyMatrix extends CSR implements IGraph {
}
/**
- * Computes: `I - nA + n^2 * (D - I)`, where `I` is the unit matrix,
+ * Computes: `I - nA + n^2 * (D - I)`, where `I` is the identity matrix,
* `A` the adjacency matrix, `D` the degree matrix, and `n` is a
* (complex-valued) number.
*
@@ -165,27 +159,41 @@ export class AdjacencyMatrix extends CSR implements IGraph {
* @param deg - degree matrix
*/
deformedLaplacian(n: number, deg?: CSR) {
- deg = deg || this.degreeMat();
+ deg = deg ? deg.copy() : this.degreeMat();
const I = CSR.identity(this.m);
return I.copy()
.sub(this.copy().mulN(n))
- .add(
- deg
- .copy()
- .sub(I)
- .mulN(n * n)
- );
+ .add(deg.sub(I).mulN(n * n));
}
- toDot() {
- const [type, sep] = this.undirected
- ? ["graph", "--"]
- : ["digraph", "->"];
- const res = [`${type} g {`];
- for (let e of this.edges()) {
- res.push(`"${e[0]}"${sep}"${e[1]}";`);
- }
- res.push(`}`);
- return res.join("\n");
+ toDot(ids?: string[]) {
+ return toDot(this.edges(), this.undirected, ids);
}
}
+
+/**
+ * Creates an adjacency matrix backed by a sparse {@link @thi.ng/sparse#CSR}
+ * matrix, optionally initialize with given edge pairs. Each edge is a `[src,
+ * dest]` tuple. If `undirected` is true (default: false), creates symmetrical
+ * edges (i.e. undirected graph).
+ *
+ * @param n - max number of vertices
+ * @param edges - edge pairs
+ * @param undirected - true, if undirected
+ */
+export const defAdjMatrix = (
+ n: number,
+ edges?: Iterable,
+ undirected = false
+) => {
+ const raw = CSR.empty(n);
+ const mat = new AdjacencyMatrix(
+ n,
+ raw.data,
+ raw.rows,
+ raw.cols,
+ undirected
+ );
+ edges && into(mat, edges);
+ return mat;
+};
diff --git a/packages/adjacency/src/utils.ts b/packages/adjacency/src/utils.ts
new file mode 100644
index 0000000000..d07eaaa77a
--- /dev/null
+++ b/packages/adjacency/src/utils.ts
@@ -0,0 +1,36 @@
+import type { Pair } from "@thi.ng/api";
+import type { Edge, IGraph } from "./api";
+
+/** @internal */
+export const toDot = (
+ edges: Iterable>,
+ undirected: boolean,
+ ids?: string[]
+) => {
+ const [type, sep] = undirected ? ["graph", "--"] : ["digraph", "->"];
+ const res = [`${type} g {`];
+ for (let e of edges) {
+ res.push(
+ ids
+ ? `"${ids[e[0]]}"${sep}"${ids[e[1]]}";`
+ : `"${e[0]}"${sep}"${e[1]}";`
+ );
+ }
+ res.push(`}`);
+ return res.join("\n");
+};
+
+/** @internal */
+export const into = (graph: IGraph, edges: Iterable) => {
+ for (let e of edges) {
+ graph.addEdge(e[0], e[1]);
+ }
+};
+
+/** @internal */
+export const invert = (graph: T, edges: Iterable) => {
+ for (let e of edges) {
+ graph.addEdge(e[1], e[0]);
+ }
+ return graph;
+};
diff --git a/packages/adjacency/test/binary.ts b/packages/adjacency/test/binary.ts
index cd3b8ce000..d4a8d56bdc 100644
--- a/packages/adjacency/test/binary.ts
+++ b/packages/adjacency/test/binary.ts
@@ -1,8 +1,7 @@
-import type { Pair } from "@thi.ng/api";
import * as assert from "assert";
-import { AdjacencyBitMatrix } from "../src";
+import { defAdjBitMatrix, Edge } from "../src";
-const edges: Pair[] = [
+const edges: Edge[] = [
[2, 3],
[0, 1],
[5, 4],
@@ -10,8 +9,19 @@ const edges: Pair[] = [
];
describe("adjacency (bitmatrix)", () => {
- it("fromEdges, undirected", () => {
- const m = AdjacencyBitMatrix.fromEdges(6, edges, true);
+ it("directed", () => {
+ const m = defAdjBitMatrix(4, [[1, 2]], false);
+ assert(m.hasEdge(1, 2));
+ assert.deepStrictEqual(m.neighbors(1), [2]);
+ assert.deepStrictEqual(m.neighbors(2), []);
+ assert.strictEqual(m.degree(1), 1);
+ assert.strictEqual(m.degree(2), 0);
+ assert.deepStrictEqual([...m.edges()], [[1, 2]]);
+ console.log(m.toString());
+ });
+
+ it("undirected", () => {
+ const m = defAdjBitMatrix(6, edges, true);
assert.deepStrictEqual(
[...m.mat.data.slice(0, 6)],
[
diff --git a/packages/adjacency/test/list.ts b/packages/adjacency/test/list.ts
new file mode 100644
index 0000000000..dd86ccc064
--- /dev/null
+++ b/packages/adjacency/test/list.ts
@@ -0,0 +1,26 @@
+import * as assert from "assert";
+import { defAdjList } from "../src";
+
+describe("adjacency (list)", () => {
+ it("directed", () => {
+ const m = defAdjList([
+ [1, 2],
+ [2, 0],
+ ]);
+ assert(m.hasEdge(1, 2));
+ assert(m.hasEdge(2, 0));
+ assert(!m.hasEdge(2, 1));
+ assert(!m.hasEdge(0, 2));
+ assert.deepStrictEqual(m.neighbors(1), [2]);
+ assert.deepStrictEqual(m.neighbors(2), [0]);
+ assert.strictEqual(m.degree(1), 1);
+ assert.deepStrictEqual(
+ [...m.edges()],
+ [
+ [1, 2],
+ [2, 0],
+ ]
+ );
+ console.log(m.toString());
+ });
+});
diff --git a/packages/adjacency/test/sparse.ts b/packages/adjacency/test/sparse.ts
index a566ca7d90..152f64e15a 100644
--- a/packages/adjacency/test/sparse.ts
+++ b/packages/adjacency/test/sparse.ts
@@ -1,6 +1,6 @@
import type { Pair } from "@thi.ng/api";
import * as assert from "assert";
-import { AdjacencyMatrix } from "../src";
+import { defAdjMatrix } from "../src";
const edges: Pair[] = [
[2, 3],
@@ -10,8 +10,18 @@ const edges: Pair[] = [
];
describe("adjacency (sparse)", () => {
+ it("edges directed", () => {
+ const m = defAdjMatrix(4, [], false);
+ m.addEdge(1, 2);
+ assert(m.hasEdge(1, 2));
+ assert.deepStrictEqual(m.neighbors(1), [2]);
+ assert.deepStrictEqual(m.neighbors(2), []);
+ assert.strictEqual(m.degree(1), 1);
+ assert.deepStrictEqual([...m.edges()], [[1, 2]]);
+ });
+
it("fromEdges, undirected", () => {
- const m = AdjacencyMatrix.fromEdges(6, edges, true);
+ const m = defAdjMatrix(6, edges, true);
assert.deepStrictEqual(m.rows, [0, 2, 3, 5, 6, 7, 8], "rows");
assert.deepStrictEqual(m.cols, [1, 2, 0, 0, 3, 2, 5, 4], "cols");
assert.strictEqual(m.numEdges(), 4, "numEdges");
diff --git a/packages/api/CHANGELOG.md b/packages/api/CHANGELOG.md
index f2a09997fd..fbaa70368f 100644
--- a/packages/api/CHANGELOG.md
+++ b/packages/api/CHANGELOG.md
@@ -3,17 +3,27 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [6.13.6](https://github.com/thi-ng/umbrella/compare/@thi.ng/api@6.13.5...@thi.ng/api@6.13.6) (2021-01-02)
+# [7.0.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/api@6.13.6...@thi.ng/api@7.0.0) (2021-02-20)
-**Note:** Version bump only for package @thi.ng/api
+### Features
+* **api:** add Range type ([5d94974](https://github.com/thi-ng/umbrella/commit/5d94974c34ca81513d40743f2a9b9a3ed20146d3))
+* **api:** add typedArrayType() classifier ([5c81fd8](https://github.com/thi-ng/umbrella/commit/5c81fd859514401c2c419b2ed3ec0f12025356c3))
+* **api:** more finely grained typedarray types ([8316d05](https://github.com/thi-ng/umbrella/commit/8316d058f0b5f760afd89e8590619670210a970a))
+* **api:** replace Type enum w/ strings consts ([a333d41](https://github.com/thi-ng/umbrella/commit/a333d418222972373cc1f9b256def2f79610d3fa))
+### BREAKING CHANGES
-## [6.13.5](https://github.com/thi-ng/umbrella/compare/@thi.ng/api@6.13.4...@thi.ng/api@6.13.5) (2020-12-22)
+* **api:** replace Type enum w/ string consts
-**Note:** Version bump only for package @thi.ng/api
+- update Type, UintType, IntType, FloatType aliases
+- update GL2TYPE, TYPE2GL, SIZEOF, TYPEDARRAY_CTORS tables
+- add asNativeType(), asGLType() conversions
+- add sizeOf()
+- add uintTypeForBits(), intTypeForBits()
+- update/rename uintTypeForSize(), intTypeForSize()
diff --git a/packages/api/README.md b/packages/api/README.md
index ca6d792124..9a786c63e5 100644
--- a/packages/api/README.md
+++ b/packages/api/README.md
@@ -54,7 +54,7 @@ yarn add @thi.ng/api
```
-Package sizes (gzipped, pre-treeshake): ESM: 2.08 KB / CJS: 2.22 KB / UMD: 2.19 KB
+Package sizes (gzipped, pre-treeshake): ESM: 2.18 KB / CJS: 2.34 KB / UMD: 2.26 KB
## Dependencies
diff --git a/packages/api/package.json b/packages/api/package.json
index f6d001bae6..bb7d4c373c 100644
--- a/packages/api/package.json
+++ b/packages/api/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/api",
- "version": "6.13.6",
+ "version": "7.0.0",
"description": "Common, generic types, interfaces & mixins",
"module": "./index.js",
"main": "./lib/index.js",
@@ -42,11 +42,11 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"files": [
"*.js",
diff --git a/packages/api/src/api/range.ts b/packages/api/src/api/range.ts
index 5d9e7096d5..c306b18555 100644
--- a/packages/api/src/api/range.ts
+++ b/packages/api/src/api/range.ts
@@ -1,3 +1,5 @@
+export type Range = [number, number];
+
export type Range0_1 = 0 | 1;
export type Range0_3 = Range0_1 | 2 | 3;
diff --git a/packages/api/src/api/typedarray.ts b/packages/api/src/api/typedarray.ts
index b1745f89c0..1620a87282 100644
--- a/packages/api/src/api/typedarray.ts
+++ b/packages/api/src/api/typedarray.ts
@@ -13,45 +13,58 @@ export type TypedArray =
| Uint16Array
| Uint32Array;
-export type IntArray = Int8Array | Int16Array | Int32Array;
-export type UIntArray = Uint8Array | Uint16Array | Uint32Array;
export type FloatArray = Float32Array | Float64Array;
-export type TypedArrayConstructor =
+export type IntArray = Int8Array | Int16Array | Int32Array;
+
+export type UIntArray =
+ | Uint8Array
+ | Uint8ClampedArray
+ | Uint16Array
+ | Uint32Array;
+
+export type FloatArrayConstructor =
+ | Float32ArrayConstructor
+ | Float64ArrayConstructor;
+
+export type IntArrayConstructor =
+ | Int8ArrayConstructor
+ | Int16ArrayConstructor
+ | Int32ArrayConstructor;
+
+export type UIntArrayConstructor =
| Uint8ArrayConstructor
| Uint8ClampedArrayConstructor
- | Int8ArrayConstructor
| Uint16ArrayConstructor
- | Int16ArrayConstructor
- | Uint32ArrayConstructor
- | Int32ArrayConstructor
- | Float32ArrayConstructor
- | Float64ArrayConstructor;
+ | Uint32ArrayConstructor;
+
+export type TypedArrayConstructor =
+ | FloatArrayConstructor
+ | IntArrayConstructor
+ | UIntArrayConstructor;
/**
- * Type enums for Typedarray-backed buffers.
+ * Type IDs for typed array backed buffers and generally describing binary data
+ * values.
*
- * {@link GLType}
- * {@link GL2TYPE}
- * {@link TYPE2GL}
+ * {@link GLType} {@link GL2TYPE} {@link TYPE2GL}
*/
-export enum Type {
- U8,
- U8C,
- I8,
- U16,
- I16,
- U32,
- I32,
- F32,
- F64,
-}
+export type Type =
+ | "u8"
+ | "u8c"
+ | "i8"
+ | "u16"
+ | "i16"
+ | "u32"
+ | "i32"
+ | "f32"
+ | "f64";
-export type UintType = Type.U8 | Type.U16 | Type.U32;
+export type UintType = "u8" | "u8c" | "u16" | "u32";
-export type IntType = Type.I8 | Type.I16 | Type.I32;
+export type IntType = "i8" | "i16" | "i32";
-export type FloatType = Type.F32 | Type.F64;
+export type FloatType = "f32" | "f64";
/**
* WebGL numeric type constants. Use {@link GL2TYPE} to convert, if needed.
@@ -74,13 +87,13 @@ export enum GLType {
* Conversion from {@link GLType} to {@link Type} enums.
*/
export const GL2TYPE: Record = {
- [GLType.I8]: Type.I8,
- [GLType.U8]: Type.U8,
- [GLType.I16]: Type.I16,
- [GLType.U16]: Type.U16,
- [GLType.I32]: Type.I32,
- [GLType.U32]: Type.U32,
- [GLType.F32]: Type.F32,
+ [GLType.I8]: "i8",
+ [GLType.U8]: "u8",
+ [GLType.I16]: "i16",
+ [GLType.U16]: "u16",
+ [GLType.I32]: "i32",
+ [GLType.U32]: "u32",
+ [GLType.F32]: "f32",
};
/**
@@ -89,66 +102,69 @@ export const GL2TYPE: Record = {
* Not all enums are mappable:
*
* - `F64` maps to `undefined`, since unsupported by WebGL
- * - `U8C` maps to U8
+ * - `U8C` maps to "u8"
*/
export const TYPE2GL: Record = {
- [Type.I8]: GLType.I8,
- [Type.U8]: GLType.U8,
- [Type.U8C]: GLType.U8,
- [Type.I16]: GLType.I16,
- [Type.U16]: GLType.U16,
- [Type.I32]: GLType.I32,
- [Type.I32]: GLType.I32,
- [Type.U32]: GLType.U32,
- [Type.F32]: GLType.F32,
- [Type.F64]: undefined,
+ i8: GLType.I8,
+ u8: GLType.U8,
+ u8c: GLType.U8,
+ i16: GLType.I16,
+ u16: GLType.U16,
+ i32: GLType.I32,
+ u32: GLType.U32,
+ f32: GLType.F32,
+ f64: undefined,
};
/**
- * Size information (in bytes) for {@link Type} enums. For {@link GLType}, use this
- * form, e.g. `SIZEOF[GL2TYPE[GLType.F32]]`
+ * Size information (in bytes) for {@link Type}. Also see {@link sizeOf}.
*/
export const SIZEOF = {
- [Type.U8]: 1,
- [Type.U8C]: 1,
- [Type.I8]: 1,
- [Type.U16]: 2,
- [Type.I16]: 2,
- [Type.U32]: 4,
- [Type.I32]: 4,
- [Type.F32]: 4,
- [Type.F64]: 8,
+ u8: 1,
+ u8c: 1,
+ i8: 1,
+ u16: 2,
+ i16: 2,
+ u32: 4,
+ i32: 4,
+ f32: 4,
+ f64: 8,
+};
+
+export const FLOAT_ARRAY_CTORS: Record = {
+ f32: Float32Array,
+ f64: Float64Array,
+};
+
+export const INT_ARRAY_CTORS: Record = {
+ i8: Int8Array,
+ i16: Int16Array,
+ i32: Int32Array,
+};
+
+export const UINT_ARRAY_CTORS: Record = {
+ u8: Uint8Array,
+ u8c: Uint8ClampedArray,
+ u16: Uint16Array,
+ u32: Uint32Array,
};
-export const TYPEDARRAY_CTORS: Record = {
- [Type.U8]: Uint8Array,
- [Type.U8C]: Uint8ClampedArray,
- [Type.I8]: Int8Array,
- [Type.U16]: Uint16Array,
- [Type.I16]: Int16Array,
- [Type.U32]: Uint32Array,
- [Type.I32]: Int32Array,
- [Type.F32]: Float32Array,
- [Type.F64]: Float64Array,
- [GLType.U8]: Uint8Array,
- [GLType.I8]: Int8Array,
- [GLType.U16]: Uint16Array,
- [GLType.I16]: Int16Array,
- [GLType.U32]: Uint32Array,
- [GLType.I32]: Int32Array,
- [GLType.F32]: Float32Array,
+export const TYPEDARRAY_CTORS: Record = {
+ ...FLOAT_ARRAY_CTORS,
+ ...INT_ARRAY_CTORS,
+ ...UINT_ARRAY_CTORS,
};
export interface TypedArrayTypeMap extends Record {
- [Type.U8]: Uint8Array;
- [Type.U8C]: Uint8ClampedArray;
- [Type.I8]: Int8Array;
- [Type.U16]: Uint16Array;
- [Type.I16]: Int16Array;
- [Type.U32]: Uint32Array;
- [Type.I32]: Int32Array;
- [Type.F32]: Float32Array;
- [Type.F64]: Float64Array;
+ u8: Uint8Array;
+ u8c: Uint8ClampedArray;
+ i8: Int8Array;
+ u16: Uint16Array;
+ i16: Int16Array;
+ u32: Uint32Array;
+ i32: Int32Array;
+ f32: Float32Array;
+ f64: Float64Array;
[GLType.U8]: Uint8Array;
[GLType.I8]: Int8Array;
[GLType.U16]: Uint16Array;
@@ -158,6 +174,46 @@ export interface TypedArrayTypeMap extends Record {
[GLType.F32]: Float32Array;
}
+/**
+ * Returns canonical {@link Type} value of `type` by first
+ * attempting to resolve it as {@link GLType} enum.
+ *
+ * @example
+ * ```ts
+ * asNativeType(GLType.F32) => "f32"
+ * asNativeType("f32") => "f32"
+ * ```
+ *
+ * @param type -
+ */
+export const asNativeType = (type: GLType | Type): Type => {
+ const t = (GL2TYPE)[type];
+ return t !== undefined ? t : type;
+};
+
+/**
+ * Returns suitable {@link GLType} enum of `type`.
+ *
+ * @example
+ * ```ts
+ * asGLType("f32") => GLType.F32
+ * asGLType(GLType.F32) => GLType.F32
+ * ```
+ *
+ * @param type -
+ */
+export const asGLType = (type: GLType | Type): GLType => {
+ const t = (TYPE2GL)[type];
+ return t !== undefined ? t : type;
+};
+
+/**
+ * Returns byte size for given {@link Type} ID or {@link GLType} enum.
+ *
+ * @param type
+ */
+export const sizeOf = (type: GLType | Type) => SIZEOF[asNativeType(type)];
+
/**
* Constructs new typed array of given {@link Type}/{@link GLType}. Supports all
* arities of standard typed array ctors.
@@ -171,27 +227,53 @@ export function typedArray(type: T, src: ArrayLike(type: T, buf: ArrayBufferLike, byteOffset: number, length?: number): TypedArrayTypeMap[T];
export function typedArray(type: T, ...xs: any[]) {
- return new (TYPEDARRAY_CTORS[type])(...xs);
+ return new (TYPEDARRAY_CTORS[asNativeType(type)])(...xs);
}
+/**
+ * Takes an {@link NumericArray} and returns its corresponding {@link Type} ID.
+ * Standard JS arrays will default to {@link "f64"}.
+ *
+ * @param x
+ */
+export const typedArrayType = (x: NumericArray) => {
+ if (Array.isArray(x)) return "f64";
+ for (let id in TYPEDARRAY_CTORS) {
+ if (x instanceof (TYPEDARRAY_CTORS)[id]) return id;
+ }
+ return "f64";
+};
+
/**
* Returns the smallest possible *unsigned* int type enum for given `x`.
- * E.g. if `x <= 256`, the function returns `Type.U8`.
+ * E.g. if `x <= 256`, the function returns `"u8"`.
*
* @param x - value to classify
*/
-export const uintType = (x: number): UintType =>
- x <= 0x100 ? Type.U8 : x <= 0x10000 ? Type.U16 : Type.U32;
+export const uintTypeForSize = (x: number): UintType =>
+ x <= 0x100 ? "u8" : x <= 0x10000 ? "u16" : "u32";
/**
* Returns the smallest possible *signed* int type enum for given `x`.
- * E.g. if `x >= -128 && x < 128`, the function returns `Type.I8`.
+ * E.g. if `x >= -128 && x < 128`, the function returns `"i8"`.
*
* @param x - value to classify
*/
-export const intType = (x: number): IntType =>
- x >= -0x80 && x < 0x80
- ? Type.I8
- : x >= -0x8000 && x < 0x8000
- ? Type.I16
- : Type.I32;
+export const intTypeForSize = (x: number): IntType =>
+ x >= -0x80 && x < 0x80 ? "i8" : x >= -0x8000 && x < 0x8000 ? "i16" : "i32";
+
+/**
+ * Returns suitable {@link UintType} for given bit size (`[0,32]` range)
+ *
+ * @param x
+ */
+export const uintTypeForBits = (x: number): UintType =>
+ x > 16 ? "u32" : x > 8 ? "u16" : "u8";
+
+/**
+ * Returns suitable {@link IntType} for given bit size (`[0,32]` range)
+ *
+ * @param x
+ */
+export const intTypeForBits = (x: number): IntType =>
+ x > 16 ? "i32" : x > 8 ? "i16" : "i8";
diff --git a/packages/api/test/index.ts b/packages/api/test/index.ts
deleted file mode 100644
index 6a03f273cd..0000000000
--- a/packages/api/test/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from "./mixins";
diff --git a/packages/args/CHANGELOG.md b/packages/args/CHANGELOG.md
index b3dbe96e0a..94782b3f4b 100644
--- a/packages/args/CHANGELOG.md
+++ b/packages/args/CHANGELOG.md
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+## [0.2.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/args@0.2.0...@thi.ng/args@0.2.1) (2021-02-20)
+
+**Note:** Version bump only for package @thi.ng/args
+
+
+
+
+
# [0.2.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/args@0.1.0...@thi.ng/args@0.2.0) (2021-01-13)
diff --git a/packages/args/package.json b/packages/args/package.json
index 3efb274b3c..bffd4493ea 100644
--- a/packages/args/package.json
+++ b/packages/args/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/args",
- "version": "0.2.0",
+ "version": "0.2.1",
"description": "Declarative, functional & typechecked CLI argument/options parser, value coercions etc.",
"module": "./index.js",
"main": "./lib/index.js",
@@ -42,17 +42,17 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"dependencies": {
- "@thi.ng/api": "^6.13.6",
- "@thi.ng/checks": "^2.8.0",
- "@thi.ng/errors": "^1.2.26",
- "@thi.ng/strings": "^1.14.0"
+ "@thi.ng/api": "^7.0.0",
+ "@thi.ng/checks": "^2.9.0",
+ "@thi.ng/errors": "^1.2.27",
+ "@thi.ng/strings": "^1.15.0"
},
"files": [
"*.js",
diff --git a/packages/arrays/CHANGELOG.md b/packages/arrays/CHANGELOG.md
index 5e4e79fe6a..e1f4383e57 100644
--- a/packages/arrays/CHANGELOG.md
+++ b/packages/arrays/CHANGELOG.md
@@ -3,7 +3,7 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [0.10.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/arrays@0.10.0...@thi.ng/arrays@0.10.1) (2021-01-22)
+## [0.10.2](https://github.com/thi-ng/umbrella/compare/@thi.ng/arrays@0.10.1...@thi.ng/arrays@0.10.2) (2021-02-20)
**Note:** Version bump only for package @thi.ng/arrays
@@ -27,22 +27,6 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
-## [0.9.2](https://github.com/thi-ng/umbrella/compare/@thi.ng/arrays@0.9.1...@thi.ng/arrays@0.9.2) (2021-01-13)
-
-**Note:** Version bump only for package @thi.ng/arrays
-
-
-
-
-
-## [0.9.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/arrays@0.9.0...@thi.ng/arrays@0.9.1) (2021-01-10)
-
-**Note:** Version bump only for package @thi.ng/arrays
-
-
-
-
-
# [0.9.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/arrays@0.8.5...@thi.ng/arrays@0.9.0) (2021-01-02)
@@ -56,14 +40,6 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
-## [0.8.5](https://github.com/thi-ng/umbrella/compare/@thi.ng/arrays@0.8.4...@thi.ng/arrays@0.8.5) (2020-12-22)
-
-**Note:** Version bump only for package @thi.ng/arrays
-
-
-
-
-
# [0.8.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/arrays@0.7.0...@thi.ng/arrays@0.8.0) (2020-09-13)
diff --git a/packages/arrays/package.json b/packages/arrays/package.json
index 9e71561730..05f08a75a2 100644
--- a/packages/arrays/package.json
+++ b/packages/arrays/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/arrays",
- "version": "0.10.1",
+ "version": "0.10.2",
"description": "Array / Arraylike utilities",
"module": "./index.js",
"main": "./lib/index.js",
@@ -42,19 +42,19 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"dependencies": {
- "@thi.ng/api": "^6.13.6",
- "@thi.ng/checks": "^2.8.0",
- "@thi.ng/compare": "^1.3.22",
- "@thi.ng/equiv": "^1.0.35",
- "@thi.ng/errors": "^1.2.26",
- "@thi.ng/random": "^2.2.0"
+ "@thi.ng/api": "^7.0.0",
+ "@thi.ng/checks": "^2.9.0",
+ "@thi.ng/compare": "^1.3.23",
+ "@thi.ng/equiv": "^1.0.36",
+ "@thi.ng/errors": "^1.2.27",
+ "@thi.ng/random": "^2.3.0"
},
"files": [
"*.js",
diff --git a/packages/associative/CHANGELOG.md b/packages/associative/CHANGELOG.md
index 189420edc9..a9589b6b79 100644
--- a/packages/associative/CHANGELOG.md
+++ b/packages/associative/CHANGELOG.md
@@ -3,49 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [5.0.17](https://github.com/thi-ng/umbrella/compare/@thi.ng/associative@5.0.16...@thi.ng/associative@5.0.17) (2021-01-22)
+# [5.1.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/associative@5.0.17...@thi.ng/associative@5.1.0) (2021-02-20)
-**Note:** Version bump only for package @thi.ng/associative
+### Features
-
-
-
-## [5.0.16](https://github.com/thi-ng/umbrella/compare/@thi.ng/associative@5.0.15...@thi.ng/associative@5.0.16) (2021-01-21)
-
-**Note:** Version bump only for package @thi.ng/associative
-
-
-
-
-
-## [5.0.15](https://github.com/thi-ng/umbrella/compare/@thi.ng/associative@5.0.14...@thi.ng/associative@5.0.15) (2021-01-13)
-
-**Note:** Version bump only for package @thi.ng/associative
-
-
-
-
-
-## [5.0.14](https://github.com/thi-ng/umbrella/compare/@thi.ng/associative@5.0.13...@thi.ng/associative@5.0.14) (2021-01-10)
-
-**Note:** Version bump only for package @thi.ng/associative
-
-
-
-
-
-## [5.0.13](https://github.com/thi-ng/umbrella/compare/@thi.ng/associative@5.0.12...@thi.ng/associative@5.0.13) (2021-01-02)
-
-**Note:** Version bump only for package @thi.ng/associative
-
-
-
-
-
-## [5.0.12](https://github.com/thi-ng/umbrella/compare/@thi.ng/associative@5.0.11...@thi.ng/associative@5.0.12) (2020-12-22)
-
-**Note:** Version bump only for package @thi.ng/associative
+* **associative:** update meldApplyObj/meldObjWith() ([97dda16](https://github.com/thi-ng/umbrella/commit/97dda16a8766314b137c5af2d504eb599d6cf2c5))
diff --git a/packages/associative/README.md b/packages/associative/README.md
index a3b8cceaa2..e05e0c2419 100644
--- a/packages/associative/README.md
+++ b/packages/associative/README.md
@@ -176,7 +176,7 @@ yarn add @thi.ng/associative
```
-Package sizes (gzipped, pre-treeshake): ESM: 6.24 KB / CJS: 6.43 KB / UMD: 6.21 KB
+Package sizes (gzipped, pre-treeshake): ESM: 6.24 KB / CJS: 6.41 KB / UMD: 6.20 KB
## Dependencies
diff --git a/packages/associative/package.json b/packages/associative/package.json
index caaae93f03..3475f3cbb8 100644
--- a/packages/associative/package.json
+++ b/packages/associative/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/associative",
- "version": "5.0.17",
+ "version": "5.1.0",
"description": "Alternative Map and Set implementations with customizable equality semantics & supporting operations",
"module": "./index.js",
"main": "./lib/index.js",
@@ -42,21 +42,21 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"dependencies": {
- "@thi.ng/api": "^6.13.6",
- "@thi.ng/binary": "^2.0.21",
- "@thi.ng/checks": "^2.8.0",
- "@thi.ng/compare": "^1.3.22",
- "@thi.ng/dcons": "^2.3.9",
- "@thi.ng/equiv": "^1.0.35",
- "@thi.ng/errors": "^1.2.26",
- "@thi.ng/transducers": "^7.5.8",
+ "@thi.ng/api": "^7.0.0",
+ "@thi.ng/binary": "^2.1.0",
+ "@thi.ng/checks": "^2.9.0",
+ "@thi.ng/compare": "^1.3.23",
+ "@thi.ng/dcons": "^2.3.10",
+ "@thi.ng/equiv": "^1.0.36",
+ "@thi.ng/errors": "^1.2.27",
+ "@thi.ng/transducers": "^7.6.0",
"tslib": "2.0.1"
},
"files": [
diff --git a/packages/associative/src/merge-apply.ts b/packages/associative/src/merge-apply.ts
index 3022af4d40..007095e33c 100644
--- a/packages/associative/src/merge-apply.ts
+++ b/packages/associative/src/merge-apply.ts
@@ -1,5 +1,5 @@
import type { Fn, IObjectOf } from "@thi.ng/api";
-import { isFunction } from "@thi.ng/checks";
+import { isFunction, isIllegalKey } from "@thi.ng/checks";
import { copy } from "./utils";
/**
@@ -68,7 +68,7 @@ export const meldApplyObj = (
xs: IObjectOf>
) => {
for (let k in xs) {
- if (k === "__proto__") continue;
+ if (isIllegalKey(k)) continue;
const v = xs[k];
src[k] = isFunction(v) ? v(src[k]) : v;
}
diff --git a/packages/associative/src/merge-with.ts b/packages/associative/src/merge-with.ts
index 3d220d5dc6..a8a02bce13 100644
--- a/packages/associative/src/merge-with.ts
+++ b/packages/associative/src/merge-with.ts
@@ -1,4 +1,5 @@
import type { Fn2, IObjectOf, Nullable } from "@thi.ng/api";
+import { isIllegalKey } from "@thi.ng/checks";
import { copy } from "./utils";
export const mergeMapWith = (
@@ -56,7 +57,7 @@ export const meldObjWith = (
for (let x of xs) {
if (x != null) {
for (let k in x) {
- if (k === "__proto__") continue;
+ if (isIllegalKey(k)) continue;
const v = x[k];
dest[k] = dest.hasOwnProperty(k) ? f(dest[k], v) : v;
}
diff --git a/packages/atom/CHANGELOG.md b/packages/atom/CHANGELOG.md
index c363607a9e..67b5c45572 100644
--- a/packages/atom/CHANGELOG.md
+++ b/packages/atom/CHANGELOG.md
@@ -3,23 +3,7 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [4.1.27](https://github.com/thi-ng/umbrella/compare/@thi.ng/atom@4.1.26...@thi.ng/atom@4.1.27) (2021-01-10)
-
-**Note:** Version bump only for package @thi.ng/atom
-
-
-
-
-
-## [4.1.26](https://github.com/thi-ng/umbrella/compare/@thi.ng/atom@4.1.25...@thi.ng/atom@4.1.26) (2021-01-02)
-
-**Note:** Version bump only for package @thi.ng/atom
-
-
-
-
-
-## [4.1.25](https://github.com/thi-ng/umbrella/compare/@thi.ng/atom@4.1.24...@thi.ng/atom@4.1.25) (2020-12-22)
+## [4.1.28](https://github.com/thi-ng/umbrella/compare/@thi.ng/atom@4.1.27...@thi.ng/atom@4.1.28) (2021-02-20)
**Note:** Version bump only for package @thi.ng/atom
diff --git a/packages/atom/package.json b/packages/atom/package.json
index 7c9acaf4b4..fc8cc39d3e 100644
--- a/packages/atom/package.json
+++ b/packages/atom/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/atom",
- "version": "4.1.27",
+ "version": "4.1.28",
"description": "Mutable wrappers for nested immutable values with optional undo/redo history and transaction support",
"module": "./index.js",
"main": "./lib/index.js",
@@ -42,17 +42,17 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"dependencies": {
- "@thi.ng/api": "^6.13.6",
- "@thi.ng/equiv": "^1.0.35",
- "@thi.ng/errors": "^1.2.26",
- "@thi.ng/paths": "^4.1.13",
+ "@thi.ng/api": "^7.0.0",
+ "@thi.ng/equiv": "^1.0.36",
+ "@thi.ng/errors": "^1.2.27",
+ "@thi.ng/paths": "^4.2.0",
"tslib": "2.0.1"
},
"files": [
diff --git a/packages/base-n/CHANGELOG.md b/packages/base-n/CHANGELOG.md
index ca7623a55e..d98b56ccf8 100644
--- a/packages/base-n/CHANGELOG.md
+++ b/packages/base-n/CHANGELOG.md
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+## [0.1.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/base-n@0.1.0...@thi.ng/base-n@0.1.1) (2021-02-20)
+
+**Note:** Version bump only for package @thi.ng/base-n
+
+
+
+
+
# 0.1.0 (2021-01-13)
diff --git a/packages/base-n/package.json b/packages/base-n/package.json
index a6683efefd..b4cccb437a 100644
--- a/packages/base-n/package.json
+++ b/packages/base-n/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/base-n",
- "version": "0.1.0",
+ "version": "0.1.1",
"description": "Arbitrary base-n conversions w/ presets for base16/32/36/58/62/64/85, support for arrays & bigints",
"module": "./index.js",
"main": "./lib/index.js",
@@ -42,14 +42,14 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"dependencies": {
- "@thi.ng/hex": "^0.1.3"
+ "@thi.ng/hex": "^0.2.0"
},
"files": [
"*.js",
diff --git a/packages/bench/CHANGELOG.md b/packages/bench/CHANGELOG.md
index 5a9ce6bc1b..ee3ed9a893 100644
--- a/packages/bench/CHANGELOG.md
+++ b/packages/bench/CHANGELOG.md
@@ -3,15 +3,7 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [2.0.26](https://github.com/thi-ng/umbrella/compare/@thi.ng/bench@2.0.25...@thi.ng/bench@2.0.26) (2021-01-02)
-
-**Note:** Version bump only for package @thi.ng/bench
-
-
-
-
-
-## [2.0.25](https://github.com/thi-ng/umbrella/compare/@thi.ng/bench@2.0.24...@thi.ng/bench@2.0.25) (2020-12-22)
+## [2.0.27](https://github.com/thi-ng/umbrella/compare/@thi.ng/bench@2.0.26...@thi.ng/bench@2.0.27) (2021-02-20)
**Note:** Version bump only for package @thi.ng/bench
diff --git a/packages/bench/package.json b/packages/bench/package.json
index 568652971e..32e9531461 100644
--- a/packages/bench/package.json
+++ b/packages/bench/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/bench",
- "version": "2.0.26",
+ "version": "2.0.27",
"description": "Benchmarking utilities w/ optional statistics",
"module": "./index.js",
"main": "./lib/index.js",
@@ -42,11 +42,11 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"files": [
"*.js",
diff --git a/packages/bencode/CHANGELOG.md b/packages/bencode/CHANGELOG.md
index eb7757df9f..66589e34a9 100644
--- a/packages/bencode/CHANGELOG.md
+++ b/packages/bencode/CHANGELOG.md
@@ -3,47 +3,7 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [0.3.49](https://github.com/thi-ng/umbrella/compare/@thi.ng/bencode@0.3.48...@thi.ng/bencode@0.3.49) (2021-01-22)
-
-**Note:** Version bump only for package @thi.ng/bencode
-
-
-
-
-
-## [0.3.48](https://github.com/thi-ng/umbrella/compare/@thi.ng/bencode@0.3.47...@thi.ng/bencode@0.3.48) (2021-01-21)
-
-**Note:** Version bump only for package @thi.ng/bencode
-
-
-
-
-
-## [0.3.47](https://github.com/thi-ng/umbrella/compare/@thi.ng/bencode@0.3.46...@thi.ng/bencode@0.3.47) (2021-01-13)
-
-**Note:** Version bump only for package @thi.ng/bencode
-
-
-
-
-
-## [0.3.46](https://github.com/thi-ng/umbrella/compare/@thi.ng/bencode@0.3.45...@thi.ng/bencode@0.3.46) (2021-01-10)
-
-**Note:** Version bump only for package @thi.ng/bencode
-
-
-
-
-
-## [0.3.45](https://github.com/thi-ng/umbrella/compare/@thi.ng/bencode@0.3.44...@thi.ng/bencode@0.3.45) (2021-01-02)
-
-**Note:** Version bump only for package @thi.ng/bencode
-
-
-
-
-
-## [0.3.44](https://github.com/thi-ng/umbrella/compare/@thi.ng/bencode@0.3.43...@thi.ng/bencode@0.3.44) (2020-12-22)
+## [0.3.50](https://github.com/thi-ng/umbrella/compare/@thi.ng/bencode@0.3.49...@thi.ng/bencode@0.3.50) (2021-02-20)
**Note:** Version bump only for package @thi.ng/bencode
diff --git a/packages/bencode/package.json b/packages/bencode/package.json
index f620191eb7..546a5b410a 100644
--- a/packages/bencode/package.json
+++ b/packages/bencode/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/bencode",
- "version": "0.3.49",
+ "version": "0.3.50",
"description": "Bencode binary encoder / decoder with optional UTF8 encoding & floating point support",
"module": "./index.js",
"main": "./lib/index.js",
@@ -42,20 +42,20 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"dependencies": {
- "@thi.ng/api": "^6.13.6",
- "@thi.ng/arrays": "^0.10.1",
- "@thi.ng/checks": "^2.8.0",
- "@thi.ng/defmulti": "^1.3.4",
- "@thi.ng/errors": "^1.2.26",
- "@thi.ng/transducers": "^7.5.8",
- "@thi.ng/transducers-binary": "^0.6.5"
+ "@thi.ng/api": "^7.0.0",
+ "@thi.ng/arrays": "^0.10.2",
+ "@thi.ng/checks": "^2.9.0",
+ "@thi.ng/defmulti": "^1.3.5",
+ "@thi.ng/errors": "^1.2.27",
+ "@thi.ng/transducers": "^7.6.0",
+ "@thi.ng/transducers-binary": "^0.6.6"
},
"files": [
"*.js",
diff --git a/packages/binary/CHANGELOG.md b/packages/binary/CHANGELOG.md
index 6c4cf2a425..4631612cef 100644
--- a/packages/binary/CHANGELOG.md
+++ b/packages/binary/CHANGELOG.md
@@ -3,17 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [2.0.21](https://github.com/thi-ng/umbrella/compare/@thi.ng/binary@2.0.20...@thi.ng/binary@2.0.21) (2021-01-02)
+# [2.1.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/binary@2.0.21...@thi.ng/binary@2.1.0) (2021-02-20)
-**Note:** Version bump only for package @thi.ng/binary
+### Features
-
-
-
-## [2.0.20](https://github.com/thi-ng/umbrella/compare/@thi.ng/binary@2.0.19...@thi.ng/binary@2.0.20) (2020-12-22)
-
-**Note:** Version bump only for package @thi.ng/binary
+* **binary:** add interleave4_12_24/4_16_32() ([89044d2](https://github.com/thi-ng/umbrella/commit/89044d2dfe4035028729fff4d9e7c890bdb008ff))
+* **binary:** add MSB_BITS8/16/32 LUTs ([e0eb47b](https://github.com/thi-ng/umbrella/commit/e0eb47bf4293832347b99a6706d257b391fd31b9))
+* **binary:** add swapLane02/13 ([2e45f48](https://github.com/thi-ng/umbrella/commit/2e45f48e946aa09943b01b4a7b7a9daee9e520ca))
diff --git a/packages/binary/README.md b/packages/binary/README.md
index 6f36dd14bd..5553c2b53a 100644
--- a/packages/binary/README.md
+++ b/packages/binary/README.md
@@ -20,7 +20,7 @@ This project is part of the
## About
-95+ assorted binary / bitwise operations, conversions, utilities.
+100+ assorted binary / bitwise operations, conversions, utilities, lookup tables.
### Status
@@ -42,7 +42,7 @@ yarn add @thi.ng/binary
```
-Package sizes (gzipped, pre-treeshake): ESM: 1.88 KB / CJS: 2.19 KB / UMD: 1.87 KB
+Package sizes (gzipped, pre-treeshake): ESM: 2.02 KB / CJS: 2.36 KB / UMD: 2.01 KB
## Dependencies
diff --git a/packages/binary/package.json b/packages/binary/package.json
index 2f0ae264e2..dfe98e046b 100644
--- a/packages/binary/package.json
+++ b/packages/binary/package.json
@@ -1,7 +1,7 @@
{
"name": "@thi.ng/binary",
- "version": "2.0.21",
- "description": "95+ assorted binary / bitwise operations, conversions, utilities",
+ "version": "2.1.0",
+ "description": "100+ assorted binary / bitwise operations, conversions, utilities, lookup tables",
"module": "./index.js",
"main": "./lib/index.js",
"umd:main": "./lib/index.umd.js",
@@ -42,14 +42,14 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"dependencies": {
- "@thi.ng/api": "^6.13.6"
+ "@thi.ng/api": "^7.0.0"
},
"files": [
"*.js",
@@ -61,10 +61,17 @@
"binary",
"bitwise",
"conversion",
+ "count",
+ "float",
"graycode",
+ "int",
"logic",
+ "lut",
+ "mask",
"math",
+ "shift",
"splat",
+ "swap",
"swizzle",
"typedarray",
"typescript"
diff --git a/packages/binary/src/constants.ts b/packages/binary/src/constants.ts
index 8fbecfa8de..c23db8c61f 100644
--- a/packages/binary/src/constants.ts
+++ b/packages/binary/src/constants.ts
@@ -1 +1,18 @@
+const defBits = (n: number) =>
+ new Array(n).fill(0).map((_, i) => 1 << (n - 1 - i));
+/**
+ * 8bit values in MSB order (i.e. MSB_BITS[0] = 0x80)
+ */
+export const MSB_BITS8 = defBits(8);
+
+/**
+ * 16bit values in MSB order (i.e. MSB_BITS[0] = 0x8000)
+ */
+export const MSB_BITS16 = defBits(16);
+
+/**
+ * 32bit values in MSB order (i.e. MSB_BITS[0] = 0x80000000)
+ */
+export const MSB_BITS32 = defBits(32);
+
export const MASKS = new Array(33).fill(0).map((_, i) => Math.pow(2, i) - 1);
diff --git a/packages/binary/src/splat.ts b/packages/binary/src/splat.ts
index e466076cc0..330315dff1 100644
--- a/packages/binary/src/splat.ts
+++ b/packages/binary/src/splat.ts
@@ -48,3 +48,23 @@ export const same4 = (x: number) => ((x >> 4) & 0xf) === (x & 0xf);
* @param x -
*/
export const same8 = (x: number) => ((x >> 8) & 0xff) === (x & 0xff);
+
+/**
+ * Expands 3x4bit value like `0xabc` to 24bits: `0xaabbcc`
+ *
+ * @param x
+ */
+export const interleave4_12_24 = (x: number) =>
+ ((x & 0xf00) * 0x1100) | ((x & 0xf0) * 0x110) | ((x & 0xf) * 0x11);
+
+/**
+ * Expands 4x4bit value like `0xabcd` to 32bits: `0xaabbccdd`
+ *
+ * @param x
+ */
+export const interleave4_16_32 = (x: number) =>
+ (((x & 0xf000) * 0x11000) |
+ ((x & 0xf00) * 0x1100) |
+ ((x & 0xf0) * 0x110) |
+ ((x & 0xf) * 0x11)) >>>
+ 0;
diff --git a/packages/binary/src/swizzle.ts b/packages/binary/src/swizzle.ts
index d5807f1023..c6ccc5d697 100644
--- a/packages/binary/src/swizzle.ts
+++ b/packages/binary/src/swizzle.ts
@@ -196,3 +196,19 @@ export const flip16: FnN = (x) => mux(x << 16, x >>> 16, 0xffff);
* @deprecated renamed to {@link flip8}
*/
export const flipBytes = flip8;
+
+/**
+ * Swaps bytes lanes 0 & 2 (i.e. bits 24-31 with bits 8-15)
+ *
+ * @param x
+ */
+export const swapLane02: FnN = (x) =>
+ ((x & 0xff00) << 16) | ((x >>> 16) & 0xff00) | (x & 0x00ff00ff);
+
+/**
+ * Swaps bytes lanes 1 & 3 (i.e. bits 16-23 with bits 0-7)
+ *
+ * @param x
+ */
+export const swapLane13: FnN = (x) =>
+ ((x & 0xff) << 16) | ((x >> 16) & 0xff) | (x & 0xff00ff00);
diff --git a/packages/bitfield/CHANGELOG.md b/packages/bitfield/CHANGELOG.md
index 2e71c01817..fdbb2aed7f 100644
--- a/packages/bitfield/CHANGELOG.md
+++ b/packages/bitfield/CHANGELOG.md
@@ -3,41 +3,25 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [0.3.30](https://github.com/thi-ng/umbrella/compare/@thi.ng/bitfield@0.3.29...@thi.ng/bitfield@0.3.30) (2021-01-13)
+# [0.4.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/bitfield@0.3.30...@thi.ng/bitfield@0.4.0) (2021-02-20)
-**Note:** Version bump only for package @thi.ng/bitfield
-
-
-
-
-
-## [0.3.29](https://github.com/thi-ng/umbrella/compare/@thi.ng/bitfield@0.3.28...@thi.ng/bitfield@0.3.29) (2021-01-10)
-
-**Note:** Version bump only for package @thi.ng/bitfield
-
-
-
-
-
-## [0.3.28](https://github.com/thi-ng/umbrella/compare/@thi.ng/bitfield@0.3.27...@thi.ng/bitfield@0.3.28) (2021-01-05)
-
-**Note:** Version bump only for package @thi.ng/bitfield
-
-
-
-
-
-## [0.3.27](https://github.com/thi-ng/umbrella/compare/@thi.ng/bitfield@0.3.26...@thi.ng/bitfield@0.3.27) (2021-01-02)
-
-**Note:** Version bump only for package @thi.ng/bitfield
+### Features
+* **bitfield:** add row/column extracts, popcounts, rename factories ([0c4c112](https://github.com/thi-ng/umbrella/commit/0c4c1127cbb9bd6fb071837adef2d7b65e2de533))
+### BREAKING CHANGES
-## [0.3.26](https://github.com/thi-ng/umbrella/compare/@thi.ng/bitfield@0.3.25...@thi.ng/bitfield@0.3.26) (2020-12-22)
+* **bitfield:** rename factory fns to follow umbrella-wide naming conventions
-**Note:** Version bump only for package @thi.ng/bitfield
+- rename bitField() => defBitField()
+- rename bitMatrix() => defBitMatrix()
+- add BitMatrix.row()/column() bitfield extraction
+- add BitMatrix.popCountRow/Column()
+- add BitField.popCount()
+- update masks in bit accessors
+- update BitField ctor & accessors to allow numbers (not just booleans)
diff --git a/packages/bitfield/README.md b/packages/bitfield/README.md
index a9bbd9553b..de0f39d584 100644
--- a/packages/bitfield/README.md
+++ b/packages/bitfield/README.md
@@ -44,7 +44,7 @@ yarn add @thi.ng/bitfield
```
-Package sizes (gzipped, pre-treeshake): ESM: 947 bytes / CJS: 1008 bytes / UMD: 1.08 KB
+Package sizes (gzipped, pre-treeshake): ESM: 1.17 KB / CJS: 1.22 KB / UMD: 1.31 KB
## Dependencies
diff --git a/packages/bitfield/package.json b/packages/bitfield/package.json
index f8a20d96dd..71ac461a08 100644
--- a/packages/bitfield/package.json
+++ b/packages/bitfield/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/bitfield",
- "version": "0.3.30",
+ "version": "0.4.0",
"description": "1D / 2D bit field implementations",
"module": "./index.js",
"main": "./lib/index.js",
@@ -42,16 +42,16 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"dependencies": {
- "@thi.ng/api": "^6.13.6",
- "@thi.ng/binary": "^2.0.21",
- "@thi.ng/strings": "^1.14.0"
+ "@thi.ng/api": "^7.0.0",
+ "@thi.ng/binary": "^2.1.0",
+ "@thi.ng/strings": "^1.15.0"
},
"files": [
"*.js",
diff --git a/packages/bitfield/src/bitfield.ts b/packages/bitfield/src/bitfield.ts
index d0493448b4..c055528b9b 100644
--- a/packages/bitfield/src/bitfield.ts
+++ b/packages/bitfield/src/bitfield.ts
@@ -1,6 +1,6 @@
import { assert, Fn2, IClear, ICopy } from "@thi.ng/api";
import { align, bitAnd, bitNot, bitOr, bitXor } from "@thi.ng/binary";
-import { binOp, toString } from "./util";
+import { binOp, popCount, toString } from "./util";
/**
* 1D bit field, backed by a Uint32Array. Hence size is always rounded
@@ -10,7 +10,7 @@ export class BitField implements IClear, ICopy {
data: Uint32Array;
n: number;
- constructor(bits: number | string | ArrayLike) {
+ constructor(bits: number | string | ArrayLike) {
const isNumber = typeof bits === "number";
this.n = align(isNumber ? bits : (bits).length, 32);
this.data = new Uint32Array(this.n >>> 5);
@@ -50,7 +50,7 @@ export class BitField implements IClear, ICopy {
* @param n - bit number
*/
at(n: number) {
- return this.data[n >>> 5] & (0x80000000 >>> (n & 31));
+ return this.data[n >>> 5] & (1 << (~n & 31));
}
/**
@@ -60,9 +60,9 @@ export class BitField implements IClear, ICopy {
* @param n - bit number
* @param v - new bit value
*/
- setAt(n: number, v = true) {
+ setAt(n: number, v: boolean | number = true) {
const id = n >>> 5;
- const mask = 0x80000000 >>> (n & 31);
+ const mask = 1 << (~n & 31);
const r = this.data[id] & mask;
if (v) {
this.data[id] |= mask;
@@ -79,14 +79,14 @@ export class BitField implements IClear, ICopy {
* @param start -
* @param vals -
*/
- setRange(start: number, vals: string | ArrayLike) {
+ setRange(start: number, vals: string | ArrayLike) {
const isString = typeof vals === "string";
- for (let i = 0, n = vals.length; i < n; i++) {
+ for (let i = 0, n = Math.min(this.n, i + vals.length); i < n; i++) {
this.setAt(
start + i,
isString
? (vals)[i] === "1"
- : (>vals)[i]
+ : (>vals)[i]
);
}
}
@@ -99,7 +99,7 @@ export class BitField implements IClear, ICopy {
*/
toggleAt(n: number) {
const id = n >>> 5;
- const mask = 0x80000000 >>> (n & 31);
+ const mask = 1 << (~n & 31);
const r = this.data[id] & mask;
if (r) {
this.data[id] &= ~mask;
@@ -109,6 +109,13 @@ export class BitField implements IClear, ICopy {
return r;
}
+ /**
+ * Returns number of set bits (1's) in the bitfield.
+ */
+ popCount() {
+ return popCount(this.data);
+ }
+
and(field: BitField) {
return this.binOp(field, bitAnd);
}
@@ -140,5 +147,6 @@ export class BitField implements IClear, ICopy {
}
}
-export const bitField = (bits: number | string | ArrayLike) =>
- new BitField(bits);
+export const defBitField = (
+ bits: number | string | ArrayLike
+) => new BitField(bits);
diff --git a/packages/bitfield/src/bitmatrix.ts b/packages/bitfield/src/bitmatrix.ts
index ce9b815184..59520861e4 100644
--- a/packages/bitfield/src/bitmatrix.ts
+++ b/packages/bitfield/src/bitmatrix.ts
@@ -1,6 +1,7 @@
import { assert, Fn2, IClear, ICopy } from "@thi.ng/api";
import { align, bitAnd, bitNot, bitOr, bitXor } from "@thi.ng/binary";
-import { binOp, toString } from "./util";
+import { BitField } from "./bitfield";
+import { binOp, popCount, toString } from "./util";
/**
* MxN row-major 2D bit matrix, backed by a Uint32Array. Hence the width
@@ -66,9 +67,7 @@ export class BitMatrix implements IClear, ICopy {
* @param n - column
*/
at(m: number, n: number) {
- return (
- this.data[(n >>> 5) + m * this.stride] & (0x80000000 >>> (n & 31))
- );
+ return this.data[(n >>> 5) + m * this.stride] & (1 << (~n & 31));
}
/**
@@ -79,9 +78,9 @@ export class BitMatrix implements IClear, ICopy {
* @param n - column
* @param v - bit value
*/
- setAt(m: number, n: number, v = true) {
+ setAt(m: number, n: number, v: boolean | number = true) {
const id = (n >>> 5) + m * this.stride;
- const mask = 0x80000000 >>> (n & 31);
+ const mask = 1 << (~n & 31);
const r = this.data[id] & mask;
if (v) {
this.data[id] |= mask;
@@ -100,7 +99,7 @@ export class BitMatrix implements IClear, ICopy {
*/
toggleAt(m: number, n: number) {
const id = (n >>> 5) + m * this.stride;
- const mask = 0x80000000 >>> (n & 31);
+ const mask = 1 << (~n & 31);
const r = this.data[id] & mask;
if (r) {
this.data[id] &= ~mask;
@@ -126,6 +125,42 @@ export class BitMatrix implements IClear, ICopy {
return this.binOp(this, bitNot);
}
+ popCountRow(m: number) {
+ this.ensureRow(m);
+ m *= this.stride;
+ return popCount(this.data.subarray(m, m + this.stride));
+ }
+
+ popCountColumn(n: number) {
+ this.ensureColumn(n);
+ const { data, stride, m } = this;
+ const mask = 1 << (~n & 31);
+ let res = 0;
+ for (let i = n >>> 5, j = 0; j < m; i += stride, j++) {
+ data[i] & mask && res++;
+ }
+ return res;
+ }
+
+ row(m: number) {
+ this.ensureRow(m);
+ const row = new BitField(this.n);
+ m *= this.stride;
+ row.data.set(this.data.subarray(m, m + this.stride));
+ return row;
+ }
+
+ column(n: number) {
+ this.ensureColumn(n);
+ const { data, stride, m } = this;
+ const column = new BitField(m);
+ const mask = 1 << (~n & 31);
+ for (let i = n >>> 5, j = 0; j < m; i += stride, j++) {
+ data[i] & mask && column.setAt(j);
+ }
+ return column;
+ }
+
toString() {
const res: string[] = [];
for (let i = 0, j = 0, s = this.stride; i < this.m; i++, j += s) {
@@ -146,7 +181,15 @@ export class BitMatrix implements IClear, ICopy {
`matrices must be same size`
);
}
+
+ protected ensureRow(m: number) {
+ assert(m >= 0 && m < this.m, `row index out of range: ${m}`);
+ }
+
+ protected ensureColumn(n: number) {
+ assert(n >= 0 && n < this.n, `column index out of range: ${n}`);
+ }
}
-export const bitMatrix = (rows: number, cols = rows) =>
+export const defBitMatrix = (rows: number, cols = rows) =>
new BitMatrix(rows, cols);
diff --git a/packages/bitfield/src/util.ts b/packages/bitfield/src/util.ts
index 2f51117bdd..7b2c527a65 100644
--- a/packages/bitfield/src/util.ts
+++ b/packages/bitfield/src/util.ts
@@ -1,3 +1,4 @@
+import { popCount as $popCount } from "@thi.ng/binary";
import { B32 } from "@thi.ng/strings";
import type { Fn2 } from "@thi.ng/api";
@@ -24,3 +25,21 @@ export const binOp = (
) => {
for (let i = src.length; --i >= 0; ) dest[i] = op(src[i], dest[i]);
};
+
+/**
+ * Returns number of set bits (1's) in the given array (index range).
+ *
+ * @param data
+ * @param i
+ * @param n
+ *
+ * @internal
+ **/
+export const popCount = (data: Uint32Array, i = 0, n = data.length) => {
+ let num = 0;
+ for (let m = i + n; i < m; i++) {
+ const x = data[i];
+ x > 0 && (num += $popCount(x));
+ }
+ return num;
+};
diff --git a/packages/bitstream/CHANGELOG.md b/packages/bitstream/CHANGELOG.md
index e811d6051a..b3e364532e 100644
--- a/packages/bitstream/CHANGELOG.md
+++ b/packages/bitstream/CHANGELOG.md
@@ -3,15 +3,7 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [1.1.31](https://github.com/thi-ng/umbrella/compare/@thi.ng/bitstream@1.1.30...@thi.ng/bitstream@1.1.31) (2021-01-02)
-
-**Note:** Version bump only for package @thi.ng/bitstream
-
-
-
-
-
-## [1.1.30](https://github.com/thi-ng/umbrella/compare/@thi.ng/bitstream@1.1.29...@thi.ng/bitstream@1.1.30) (2020-12-22)
+## [1.1.32](https://github.com/thi-ng/umbrella/compare/@thi.ng/bitstream@1.1.31...@thi.ng/bitstream@1.1.32) (2021-02-20)
**Note:** Version bump only for package @thi.ng/bitstream
diff --git a/packages/bitstream/package.json b/packages/bitstream/package.json
index ec2392fc22..e516f354a9 100644
--- a/packages/bitstream/package.json
+++ b/packages/bitstream/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/bitstream",
- "version": "1.1.31",
+ "version": "1.1.32",
"description": "ES6 iterator based read/write bit streams with support for variable word widths",
"module": "./index.js",
"main": "./lib/index.js",
@@ -42,14 +42,14 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"dependencies": {
- "@thi.ng/errors": "^1.2.26"
+ "@thi.ng/errors": "^1.2.27"
},
"files": [
"*.js",
diff --git a/packages/cache/CHANGELOG.md b/packages/cache/CHANGELOG.md
index 74aaf10c20..eed647b270 100644
--- a/packages/cache/CHANGELOG.md
+++ b/packages/cache/CHANGELOG.md
@@ -3,47 +3,7 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [1.0.69](https://github.com/thi-ng/umbrella/compare/@thi.ng/cache@1.0.68...@thi.ng/cache@1.0.69) (2021-01-22)
-
-**Note:** Version bump only for package @thi.ng/cache
-
-
-
-
-
-## [1.0.68](https://github.com/thi-ng/umbrella/compare/@thi.ng/cache@1.0.67...@thi.ng/cache@1.0.68) (2021-01-21)
-
-**Note:** Version bump only for package @thi.ng/cache
-
-
-
-
-
-## [1.0.67](https://github.com/thi-ng/umbrella/compare/@thi.ng/cache@1.0.66...@thi.ng/cache@1.0.67) (2021-01-13)
-
-**Note:** Version bump only for package @thi.ng/cache
-
-
-
-
-
-## [1.0.66](https://github.com/thi-ng/umbrella/compare/@thi.ng/cache@1.0.65...@thi.ng/cache@1.0.66) (2021-01-10)
-
-**Note:** Version bump only for package @thi.ng/cache
-
-
-
-
-
-## [1.0.65](https://github.com/thi-ng/umbrella/compare/@thi.ng/cache@1.0.64...@thi.ng/cache@1.0.65) (2021-01-02)
-
-**Note:** Version bump only for package @thi.ng/cache
-
-
-
-
-
-## [1.0.64](https://github.com/thi-ng/umbrella/compare/@thi.ng/cache@1.0.63...@thi.ng/cache@1.0.64) (2020-12-22)
+## [1.0.70](https://github.com/thi-ng/umbrella/compare/@thi.ng/cache@1.0.69...@thi.ng/cache@1.0.70) (2021-02-20)
**Note:** Version bump only for package @thi.ng/cache
diff --git a/packages/cache/package.json b/packages/cache/package.json
index 5f8a591fdd..27b20f1091 100644
--- a/packages/cache/package.json
+++ b/packages/cache/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/cache",
- "version": "1.0.69",
+ "version": "1.0.70",
"description": "In-memory cache implementations with ES6 Map-like API and different eviction strategies",
"module": "./index.js",
"main": "./lib/index.js",
@@ -42,16 +42,16 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"dependencies": {
- "@thi.ng/api": "^6.13.6",
- "@thi.ng/dcons": "^2.3.9",
- "@thi.ng/transducers": "^7.5.8"
+ "@thi.ng/api": "^7.0.0",
+ "@thi.ng/dcons": "^2.3.10",
+ "@thi.ng/transducers": "^7.6.0"
},
"files": [
"*.js",
diff --git a/packages/checks/CHANGELOG.md b/packages/checks/CHANGELOG.md
index f44ffe3b54..137b7a7945 100644
--- a/packages/checks/CHANGELOG.md
+++ b/packages/checks/CHANGELOG.md
@@ -3,28 +3,24 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-# [2.8.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/checks@2.7.13...@thi.ng/checks@2.8.0) (2021-01-10)
+# [2.9.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/checks@2.8.0...@thi.ng/checks@2.9.0) (2021-02-20)
### Features
-* **checks:** add isNumericInt/Float() checks ([7e054c1](https://github.com/thi-ng/umbrella/commit/7e054c14b06850800869ba0bc8c8174e233dda53))
-
-
-
+* **checks:** add isIllegalKey() (make public) ([507fc80](https://github.com/thi-ng/umbrella/commit/507fc806903e766e42a98ddd569ba4031925204b))
+* **checks:** replace isPrototypePolluted() w/ isProtoPath() ([d276b84](https://github.com/thi-ng/umbrella/commit/d276b8465eda21a32f3613d20c043ea50fce7f57))
-## [2.7.13](https://github.com/thi-ng/umbrella/compare/@thi.ng/checks@2.7.12...@thi.ng/checks@2.7.13) (2021-01-02)
-
-**Note:** Version bump only for package @thi.ng/checks
+# [2.8.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/checks@2.7.13...@thi.ng/checks@2.8.0) (2021-01-10)
-## [2.7.12](https://github.com/thi-ng/umbrella/compare/@thi.ng/checks@2.7.11...@thi.ng/checks@2.7.12) (2020-12-22)
+### Features
-**Note:** Version bump only for package @thi.ng/checks
+* **checks:** add isNumericInt/Float() checks ([7e054c1](https://github.com/thi-ng/umbrella/commit/7e054c14b06850800869ba0bc8c8174e233dda53))
diff --git a/packages/checks/README.md b/packages/checks/README.md
index c148c5fa3e..e91f92929a 100644
--- a/packages/checks/README.md
+++ b/packages/checks/README.md
@@ -43,7 +43,7 @@ yarn add @thi.ng/checks
```
-Package sizes (gzipped, pre-treeshake): ESM: 1.51 KB / CJS: 1.77 KB / UMD: 1.50 KB
+Package sizes (gzipped, pre-treeshake): ESM: 1.63 KB / CJS: 1.89 KB / UMD: 1.59 KB
## Dependencies
diff --git a/packages/checks/package.json b/packages/checks/package.json
index dbfa8cfe07..8e0f890f94 100644
--- a/packages/checks/package.json
+++ b/packages/checks/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/checks",
- "version": "2.8.0",
+ "version": "2.9.0",
"description": "Collection of 50+ type, feature & value checks",
"module": "./index.js",
"main": "./lib/index.js",
@@ -42,11 +42,11 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"dependencies": {
"tslib": "2.0.1"
diff --git a/packages/checks/src/index.ts b/packages/checks/src/index.ts
index cff744c075..0e9ec6167c 100644
--- a/packages/checks/src/index.ts
+++ b/packages/checks/src/index.ts
@@ -49,6 +49,7 @@ export * from "./is-positive";
export * from "./is-primitive";
export * from "./is-promise";
export * from "./is-promiselike";
+export * from "./is-proto-path";
export * from "./is-regexp";
export * from "./is-safari";
export * from "./is-set";
diff --git a/packages/checks/src/is-proto-path.ts b/packages/checks/src/is-proto-path.ts
new file mode 100644
index 0000000000..5c8b23d010
--- /dev/null
+++ b/packages/checks/src/is-proto-path.ts
@@ -0,0 +1,39 @@
+import { isArray } from "./is-array";
+import { isString } from "./is-string";
+
+const ILLEGAL_KEYS = new Set(["__proto__", "prototype", "constructor"]);
+
+/**
+ * Returns true, if given `x` is an illegal object key as per
+ * {@link ILLEGAL_KEYS}.
+ *
+ * @see {@link isProtoPath} for more details
+ *
+ * @param x
+ */
+export const isIllegalKey = (x: any) => ILLEGAL_KEYS.has(x);
+
+/**
+ * Returns true if given `path` contains any {@link ILLEGAL_KEYS}, i.e. could be
+ * used to poison the prototype chain of an object.
+ *
+ * @remarks
+ * If given an array, each item is considered a single sub-path property and
+ * will be checked as is. If given a string it will be split using "." as
+ * delimiter and each item checked as is (same way array paths are handled).
+ *
+ * Original discussion here, implementation updated to be more encompassing:
+ * https://github.com/thi-ng/umbrella/pull/273
+ *
+ * @param path
+ */
+export const isProtoPath = (
+ path: string | number | readonly (string | number)[]
+) =>
+ isArray(path)
+ ? path.some(isIllegalKey)
+ : isString(path)
+ ? path.indexOf(".") !== -1
+ ? path.split(".").some(isIllegalKey)
+ : isIllegalKey(path)
+ : false;
diff --git a/packages/checks/test/index.ts b/packages/checks/test/index.ts
index 4270d2d127..cb0d72576f 100644
--- a/packages/checks/test/index.ts
+++ b/packages/checks/test/index.ts
@@ -10,6 +10,7 @@ import {
isNil,
isObject,
isPlainObject,
+ isProtoPath,
isString,
isSymbol,
isTransferable,
@@ -192,4 +193,20 @@ describe("checks", function () {
assert.ok(!isHexColor("hi #ff3300 hi"), "invalid: hi #ff3300 hi");
assert.ok(!isHexColor("#123 #123"), "invalid: #123 #123");
});
+
+ it("isProtoPath", () => {
+ assert.ok(!isProtoPath("foo.__proto.bar"), "0");
+ assert.ok(!isProtoPath("foo.bar"), "1");
+ assert.ok(!isProtoPath(""), "2");
+ assert.ok(isProtoPath("__proto__"), "3");
+ assert.ok(isProtoPath("prototype"), "4");
+ assert.ok(isProtoPath("constructor"), "5");
+ assert.ok(isProtoPath("foo.__proto__.bar"), "6");
+ assert.ok(!isProtoPath([]), "7");
+ assert.ok(!isProtoPath([""]), "8");
+ assert.ok(!isProtoPath(["foo", 23]), "9");
+ assert.ok(!isProtoPath(["prototype.foo"]), "10");
+ assert.ok(isProtoPath(["__proto__"]), "11");
+ assert.ok(isProtoPath(["foo", "__proto__", "bar"]), "12");
+ });
});
diff --git a/packages/color/CHANGELOG.md b/packages/color/CHANGELOG.md
index e6b5f416a1..ae63f04978 100644
--- a/packages/color/CHANGELOG.md
+++ b/packages/color/CHANGELOG.md
@@ -3,41 +3,130 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [2.1.5](https://github.com/thi-ng/umbrella/compare/@thi.ng/color@2.1.4...@thi.ng/color@2.1.5) (2021-01-22)
+# [3.0.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/color@2.1.5...@thi.ng/color@3.0.0) (2021-02-20)
-**Note:** Version bump only for package @thi.ng/color
+### Bug Fixes
+* **color:** div-by-zero in XYY<>XYZ conversions ([8a71c6e](https://github.com/thi-ng/umbrella/commit/8a71c6ec25766967c20e27cfd6a0d44abde85a57))
+* **color:** don't clamp Oklab/XYZ<>RGB conversions ([fab3639](https://github.com/thi-ng/umbrella/commit/fab3639ec59d8346752bb8a3831e9fac8d1663f7))
+* **color:** fix resolveAsCSS() ([7b1eeff](https://github.com/thi-ng/umbrella/commit/7b1eeff17003229b9d38705dbee8e7da790699a1))
+* **color:** fix typo in parseHex, update parse helpers ([a7315c0](https://github.com/thi-ng/umbrella/commit/a7315c0545bc4ef55f05a3b909f113fb9ca98041))
+* **color:** kelvinRgb() results are sRGB ([31cd4b5](https://github.com/thi-ng/umbrella/commit/31cd4b5af37d72c0eded08c2e5bf9a520dcdd400))
+* **color:** normalize LCH hue channel ([c0b9e9d](https://github.com/thi-ng/umbrella/commit/c0b9e9d90172487c7b0dce7d252d30bba92e425e))
+* **color:** rescale labXyz(), use D50 for LCH->RGB ([9e59545](https://github.com/thi-ng/umbrella/commit/9e59545fb0cca91dfe7050a1a7db70239f818e9d))
+* **color:** unconstrained analog() for some modes ([439265b](https://github.com/thi-ng/umbrella/commit/439265bbc6a2510a8fa6897e6165d805079c6db9))
+* **color:** update Lab/LCH rules in parseCss() ([cb7f15e](https://github.com/thi-ng/umbrella/commit/cb7f15e1a98b78bdc6a61b3cdb5cdc55f2bc828f))
+* **color:** update resolveAsCss() ([0e7e955](https://github.com/thi-ng/umbrella/commit/0e7e955e176bd7b3e440dc7190dee26f9843fe8b))
+### Code Refactoring
-## [2.1.4](https://github.com/thi-ng/umbrella/compare/@thi.ng/color@2.1.3...@thi.ng/color@2.1.4) (2021-01-21)
-
-**Note:** Version bump only for package @thi.ng/color
-
-
-
-
-
-## [2.1.3](https://github.com/thi-ng/umbrella/compare/@thi.ng/color@2.1.2...@thi.ng/color@2.1.3) (2021-01-13)
-
-**Note:** Version bump only for package @thi.ng/color
-
-
-
+* **color:** major update/rename all types/conversions ([4143c8f](https://github.com/thi-ng/umbrella/commit/4143c8fe746a692e61be7696053c883eef7ab326))
-## [2.1.2](https://github.com/thi-ng/umbrella/compare/@thi.ng/color@2.1.1...@thi.ng/color@2.1.2) (2021-01-10)
+### Features
-**Note:** Version bump only for package @thi.ng/color
+* **color:** add AColor.set() ([7e7a05c](https://github.com/thi-ng/umbrella/commit/7e7a05c0a1f9bfe57e304ab2afe3b314b048ea5e))
+* **color:** add AColor.toJSON() ([ee96412](https://github.com/thi-ng/umbrella/commit/ee96412656fb6bd019f356a50f83651150ee7293))
+* **color:** add ARGB32/ABGR32 int types/conversions ([1993beb](https://github.com/thi-ng/umbrella/commit/1993bebce4ee8c44a6dbcde01bc3635757d5d3f2))
+* **color:** add barebones support for LAB & LCH ([6e3b8c9](https://github.com/thi-ng/umbrella/commit/6e3b8c9b84b33b5280247c17ae3f9b862dd44d04))
+* **color:** add generic analog() (for all color types) ([117a5bc](https://github.com/thi-ng/umbrella/commit/117a5bcdcdd3c84f7c9eb8d68197963db4515b07))
+* **color:** add gradient and mix fns ([f31966c](https://github.com/thi-ng/umbrella/commit/f31966ca8612415fb8faaff02a13b5f8eddb2753))
+* **color:** add Int32.alpha accessor, minor update int->srgb ([b65f9ee](https://github.com/thi-ng/umbrella/commit/b65f9ee2896636df5bb5882e07186043d7ddc466))
+* **color:** add lab D50/65 conv, update HSx<>CSS conv ([014e41d](https://github.com/thi-ng/umbrella/commit/014e41de9d7b051c58f4ea4a90ff0d3783884b6f))
+* **color:** add multiColorGradient(), update cos version ([dc88f37](https://github.com/thi-ng/umbrella/commit/dc88f37abed0c5ab7dbdf2ea42fa60ddb4d5a353))
+* **color:** add Oklab color space support ([57a5bad](https://github.com/thi-ng/umbrella/commit/57a5bad8cff99636b28f9d17124c7c445f36eebb))
+* **color:** add rgbSrgbApprox() and vice versa ([c1efada](https://github.com/thi-ng/umbrella/commit/c1efada4f2b546c7515a34e12e31ea6a8857ec03))
+* **color:** add setPrecision(), LCH cleanup ([778f84a](https://github.com/thi-ng/umbrella/commit/778f84aa5a080ffd8afb12967553f53463a34d2c))
+* **color:** add sortMapped() for mapped memory cols ([9a548ec](https://github.com/thi-ng/umbrella/commit/9a548eccf3553d03afaff7817ce47f4bfeb98691))
+* **color:** add SystemColors and defaults ([16bad21](https://github.com/thi-ng/umbrella/commit/16bad2194d52b2aa3880ec8e37cc3a3891f0c20e))
+* **color:** add TypedColor/ColorFactory.range impls ([7ecfa0c](https://github.com/thi-ng/umbrella/commit/7ecfa0c5840722b8f4bb8965063f545a2d5348af))
+* **color:** add wavelengthXyza() ([d29ce23](https://github.com/thi-ng/umbrella/commit/d29ce236e2d0a4a43053b18bc8d4b41f69f4f66b))
+* **color:** add XYY mode ([7a743f2](https://github.com/thi-ng/umbrella/commit/7a743f2cc824ba2a46e32d72be8519a34d99b94c))
+* **color:** add XYZ/Oklab conversions, update/fix XYZ matrices ([e07a038](https://github.com/thi-ng/umbrella/commit/e07a038f9fc0317008c9a2a2e05bdba88eff0712))
+* **color:** add/update conversions ([e979044](https://github.com/thi-ng/umbrella/commit/e9790440dcf37ace01d4ea5f4c42ae76a556dc86))
+* **color:** add/update distance functions ([6d15065](https://github.com/thi-ng/umbrella/commit/6d15065c07cb8e434f0d964c98d5fd1878738868))
+* **color:** add/update Lab/XYZ/LCH conversions ([9feb251](https://github.com/thi-ng/umbrella/commit/9feb251def42ac12b6f522a8ea390e4e836cacaa))
+* **color:** add/update luminance & YCC conversion ([89ca131](https://github.com/thi-ng/umbrella/commit/89ca131a4b3878ca30d3199d8647b67ed426f287))
+* **color:** convert mix() to defmulti, color mode aware ([faed98b](https://github.com/thi-ng/umbrella/commit/faed98b3ced6a6e30bfd3d3afc95f493b39dc707))
+* **color:** generic isBlack/Gray/White, LCH color ranges ([598afdf](https://github.com/thi-ng/umbrella/commit/598afdf045c7a56261a5edb96d21686bd2d2a2d8))
+* **color:** improve int ARGB/ABGR support ([6460e4d](https://github.com/thi-ng/umbrella/commit/6460e4d04db8e548e575a586f24143c1ed674cde))
+* **color:** major restructure, new types/conversions ([6389f7c](https://github.com/thi-ng/umbrella/commit/6389f7c4baf2b8ef184cf76b8d71b8d0a44237a6))
+* **color:** new parseCSS(), add SRGBA, update conversions ([f748d65](https://github.com/thi-ng/umbrella/commit/f748d65934fe9472cc19b3e6bbfcce2578129fb7))
+* **color:** replace proximity functions ([7a0be62](https://github.com/thi-ng/umbrella/commit/7a0be62c08ea2717298f2365292fa4c9eca6f911))
+* **color:** split Lab & XYZ types into D50/D65 ([29e1e74](https://github.com/thi-ng/umbrella/commit/29e1e74a259bc8c73a79ccc77c654649f95c7d8c))
+* **color:** update ColorFactory, TypedColor ([8c5f8fb](https://github.com/thi-ng/umbrella/commit/8c5f8fb5255beed3a272d987c99fd3539f92b9d6))
+* **color:** update ColorMix & gradient types/functions ([829fcf6](https://github.com/thi-ng/umbrella/commit/829fcf6b61079e2ffaafadfd0ac115e341db6743))
+* **color:** update CSS_NAMES ([7ea0cf0](https://github.com/thi-ng/umbrella/commit/7ea0cf073cc39c165b24258be3b13cfddfb3dd41))
+* **color:** update types, CSS formatting ([f0502a2](https://github.com/thi-ng/umbrella/commit/f0502a2518a4e90edf45e35df180d2d273cdff68))
+* **color:** update/restructure types, add buffer mapping ([cebaafa](https://github.com/thi-ng/umbrella/commit/cebaafa3bff43409a39162374ede7b0b07086b05))
+* **color:** use RGB fallbacks for Lab/LCH CSS ([53ddaeb](https://github.com/thi-ng/umbrella/commit/53ddaeb5b3ff18c443b8308ad14ddba468dbe9da))
+### Performance Improvements
+* **color:** make defColor() fixed for 4 channels ([4ea77ef](https://github.com/thi-ng/umbrella/commit/4ea77eff4ef89b771268c6244628b71ec869ab8b))
-## [2.1.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/color@2.1.0...@thi.ng/color@2.1.1) (2021-01-05)
+### BREAKING CHANGES
-**Note:** Version bump only for package @thi.ng/color
+* **color:** remove obsolete resolveAsCss(), use css() instead
+
+- update MaybeColor alias
+- update TypedColor
+- merge resolveAsCss() cases into css()
+- fix color factory for int args
+* **color:** replace color classes w/ dynamically generated impls
+
+- add ColorSpec, ColorType, ColorFactory types
+- add defColor() color type factory based on declarative ColorSpec
+- all color types now based on defColor()
+- remove obsolete AColor class
+- color factories now also act as converters
+- add color() factory to wrap color in class for given mode
+- remove CSS and Int types (use plain strings/ints now, and use css()
+ or resolveAsCss() to convert to CSS strings)
+- parseCss() now returns ParsedColor (circumvents circular deps)
+- replace convert() w/ new simplified version
+- add/update generic isGray(), isBlack(), isWhite(), luminance()
+* **color:** update/rename all color types/conversions
+
+- rename YCbCrA => YCC
+- remove `A` suffix from all color types
+ (e.g. `HSVA` => `HSV`, `XYZA` => `XYZ` etc.)
+- accordingly, rename all conversions (e.g. `rgbaHsva()` => `rgbHsv()`)
+- rename `.alpha` accessor in all color types
+ (previously a mixture of `.a` vs `.alpha`, now always latter)
+- standardize casing in all function names (now always camelCase)
+ e.g. `asCSS()` => `asCss()`
+- resolveAsCss() untyped default now sRGB
+- rename distSatHsv() => distHsvSat()
+- rename distLumaHsv() => distHsvLuma()
+- rename distLumaRGB() => distRgbLuma()
+- add distChannel() HOF
+- add basic convert() support for Lab<>LCH<>CSS
+- add/update docstrings
+- rename RANGES => COLOR_RANGES
+- update colorFromRange(), colorsFromRange() and
+ colorsFromTheme() to return wrapped HSV colors
+* **color:** multiCosineGradient() args now given as options object
+
+- add MultiGradientOpts
+- add support for per-interval easing
+- add support for result color coercion
+* **color:** parseCSS() now returns wrapped color types,
+not raw RGBA arrays as previously
+
+- parseCSS() now returns SRGBA, HSLA, LAB or LCH color types and supports more CSS syntax opts
+- all asXXX() functions also return wrapped colors,
+ only asCSS() still returns strings
+- add SRGBA type/color mode reserve existing RGBA for
+ linear colors (non-gamma corrected)
+- rename existing conversions, now using SRGBA (i.e. srgbaCss(),
+ srgbaInt()), add new versions for (now linear) RGBA
+- parseCSS() RGB colors now result in SRGB instances,
+ use asRGBA() or srgbRgba() to convert to linear RGB
diff --git a/packages/color/README.md b/packages/color/README.md
index 321df95047..cf56b57885 100644
--- a/packages/color/README.md
+++ b/packages/color/README.md
@@ -12,16 +12,18 @@ This project is part of the
For the Clojure version, please visit: [thi.ng/color-clj](https://thi.ng/color-clj)
- [About](#about)
- - [Color spaces / modes](#color-spaces--modes)
- - [Class wrappers](#class-wrappers)
+ - [Supported color spaces / modes](#supported-color-spaces--modes)
+ - [Color creation / conversion](#color-creation--conversion)
+ - [Storage & memory mapping](#storage--memory-mapping)
- [Color theme generation](#color-theme-generation)
- - [Color sorting](#color-sorting)
- - [RGBA transformations](#rgba-transformations)
- - [RGBA Porter-Duff compositing](#rgba-porter-duff-compositing)
- - [Cosine gradients](#cosine-gradients)
- - [Two-color gradients](#two-color-gradients)
- - [Multi-stop gradients](#multi-stop-gradients)
+ - [Color sorting & distance](#color-sorting--distance)
+ - [Sorting memory-mapped colors](#sorting-memory-mapped-colors)
+ - [Gradients](#gradients)
+ - [Multi-stop gradients in any color space](#multi-stop-gradients-in-any-color-space)
+ - [Cosine gradients](#cosine-gradients)
+ - [RGB color transformations](#rgb-color-transformations)
- [Status](#status)
+ - [Related packages](#related-packages)
- [Installation](#installation)
- [Dependencies](#dependencies)
- [Usage examples](#usage-examples)
@@ -31,136 +33,297 @@ For the Clojure version, please visit: [thi.ng/color-clj](https://thi.ng/color-c
## About
-Array-based color types, conversions, transformations, declarative theme generation, multi-color gradients, presets.
+Array-based color types, CSS parsing, conversions, transformations, declarative theme generation, gradients, presets.
+
+---
+
+**Note: Version 3.0.0 constitutes an almost complete overhaul of the entire
+package, providing a more simple and flexible API, as well as various new
+additional features (compared to previous versions).**
+
+---
+
+### Supported color spaces / modes
+
+Fast color model/space conversions (any direction) between (in alphabetical
+order). All types support an alpha channel, which defaults to 100% opaque (apart
+from the integer types).
+
+- ABGR (uint32, `0xaabbggrr`, aka sRGB(A) as packed int)
+- [ARGB](https://en.wikipedia.org/wiki/RGBA_color_model#ARGB32) (uint32, `0xaarrggbb`, aka sRGB(A) as packed int)
+- [CSS](https://www.w3.org/TR/css-color-4/) (string, hex3/4/6/8, named colors, system colors, rgba(), hsla(), lch(), lab(), etc.)
+- [HCY](http://www.chilliant.com/rgb2hsv.html) (float4, similar to LCH)
+- [HSI](https://en.wikipedia.org/wiki/HSL_and_HSV#HSI_to_RGB) (float4)
+- [HSL](https://en.wikipedia.org/wiki/HSL_and_HSV) (float4)
+- [HSV](https://en.wikipedia.org/wiki/HSL_and_HSV) (float4)
+- [Lab](https://en.wikipedia.org/wiki/CIELAB_color_space) (float4, D50/D65 versions)
+- [LCH](https://en.wikipedia.org/wiki/HCL_color_space) (float4)
+- [Oklab](https://bottosson.github.io/posts/oklab/) (float4)
+- [RGB](https://en.wikipedia.org/wiki/RGB_color_space) (float4, _linear_)
+- [sRGB](https://en.wikipedia.org/wiki/SRGB) (float4, [gamma corrected](https://en.wikipedia.org/wiki/Gamma_correction))
+- [XYY](https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space) (float4)
+- [XYZ](https://en.wikipedia.org/wiki/CIE_1931_color_space) (float4, aka CIE 1931, D50/D65 versions)
+- [YCC](https://en.wikipedia.org/wiki/YCbCr) (float4, aka YCbCr)
+
+| From/To | CSS | HCY | HSI | HSL | HSV | Int | Lab | LCH | Oklab | RGB | sRGB | XYY | XYZ | YCC |
+|-----------|-----|-----------------|-----------------|-----------------|-----------------|-----------------|-----------------|-----|-------|-----------------|-----------------|-----|-----------------|-----------------|
+| **CSS** | β
| π | π | β
| π | β
(1) | β
(4) | β
| π | β
| β
| π | π | π |
+| **HCY** | π | β
| π | π | π | β | π | π | π | β
(2) | β
(2) | π | π | π |
+| **HSI** | π | π | β
| π | π | β | π | π | π | β
(2) | β
(2) | π | π | π |
+| **HSL** | β
| π | π | β
| π | β | π | π | π | β
(2) | β
(2) | π | π | π |
+| **HSV** | π | π | π | β
| β
| β | π | π | π | β
(2) | β
(2) | π | π | π |
+| **Int** | β
| π | π | π | π | β | π | π | π | π | β
| β
| π | π |
+| **Lab** | β
| π | π | π | π | β | β
(3) | β
| π | β
(3) | π | π | β
(3) | π |
+| **LCH** | β
| π | π | π | π | β | β
| β
| π | π | π | π | π | π |
+| **Oklab** | π | π | π | π | π | β | π | π | β
| β
| π | π | β
| π |
+| **RGB** | π | β
(2) | β
(2) | β
(2) | β
(2) | β
| β
(3) | β
| β
| β
| β
| π | β
(3) | β
(2) |
+| **sRGB** | β
| β
(2) | β
(2) | β
(2) | β
(2) | β
| π | π | π | β
| β
| π | π | π |
+| **XYY** | π | π | π | π | π | β | π | π | π | π | π | β
| β
| π |
+| **XYZ** | π | π | π | π | π | β | β
| π | π | β
| π | β
| β
(3) | π |
+| **YCC** | π | π | π | π | π | β | π | π | π | β
(2) | π | π | π | β
|
+
+- β
- direct conversion
+- π - indirect conversion (mostly via RGB/sRGB)
+- (1) - only via `parseHex()`
+- (2) - no consideration for linear/gamma encoded RGB/sRGB
+ (see [Wikipedia](https://en.wikipedia.org/wiki/HSL_and_HSV#cite_note-26))
+- (3) - including [D50/D65 illuminant](https://en.wikipedia.org/wiki/Illuminant_D65) options
+- (4) - parsed as Lab w/ D50 illuminant as per [CSS Color Module Level 4](https://www.w3.org/TR/css-color-4/#lab-colors)
+
+#### Color creation / conversion
+
+Each color type provides a factory function to create & convert color instances
+from other models/spaces. These functions can take the following arguments:
+
+- CSS string
+- number (interpreted as packed ARGB int32)
+- array (used as is)
+- scalars (one per channel, alpha optional, always defaults to 1.0)
+- color instance (triggers conversion)
+
+Additionally, an optional target backing buffer, start index and stride can be
+given. See [next section](#storage--memory-mapping).
+
+Some examples:
-### Color spaces / modes
+```ts
+srgb("#ff0")
+// $Color { offset: 0, stride: 1, buf: [ 1, 1, 0, 1 ] }
+
+srgb(0x44ffff00)
+// $Color { offset: 0, stride: 1, buf: [ 1, 1, 0, 0.26666666666666666 ] }
+
+srgb(1,1,0)
+// $Color { offset: 0, stride: 1, buf: [ 1, 1, 0, 1 ] }
+
+srgb([0.1, 0.2, 0.3, 0.4])
+// $Color { offset: 0, stride: 1, buf: [ 0.1, 0.2, 0.3, 0.4 ] }
+
+// convert RGB CSS into Lab (D50)
+labD50("#ff0")
+// $Color {
+// offset: 0,
+// stride: 1,
+// buf: [ 0.9760712516622824, -0.1575287517691254, 0.9338847788323792, 1 ]
+// }
+
+// convert RGB CSS into Lab CSS (CSS Level 4 only)
+css(labD50("#ff0"))
+// 'lab(97.607% -15.753 93.388)'
+
+// round trip:
+// CSS -> sRGB -> lin RGB -> Lab -> lin RGB -> sRGB -> CSS
+css(rgb(labD50("#ff0")))
+// '#ffff00'
+```
+
+Additionally, colors can be created from black body temperatures
+([`kelvinRgb()`](https://github.com/thi-ng/umbrella/blob/develop/packages/color/src/rgb/kelvin-rgba.ts))
+or wavelengths
+([`wavelengthXyz()`](https://github.com/thi-ng/umbrella/blob/develop/packages/color/src/xyz/wavelength-xyz.ts)).
-Fast color space conversions (any direction) between:
+![kelvinRgb() result swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/blackbody.svg)
-- CSS (string, hex3/hex4/hex6/hex8, rgba(), hsla(), named colors)
-- HCYA (float4)
-- HSIA (float4)
-- HSLA (float4)
-- HSVA (float4)
-- Int32 (uint32, `0xaarrggbb`)
-- RGBA (float4)
-- XYZA (float4, aka CIE 1931)
-- YCbCr (float4)
+![wavelengthXyz() result swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/wavelength.svg)
-Apart from `CSS` and `Int32` colors, all others can be stored as plain
-arrays, typed array or custom array-like types of (mostly) normalized
-values (`[0,1]` interval). Where applicable, the hue too is stored in
-that range, NOT in degrees.
+### Storage & memory mapping
-Apart from conversions, most other operations provided by this package
-are currently only supporting RGBA colors. These can also be converted
-to / from sRGB (i.e. linear vs gamma corrected).
+All color types store their channel values in plain arrays, typed arrays of
+(mostly) normalized values (`[0,1]` interval). Where applicable, the hue too is
+stored in that range (similar to [CSS
+`turn`](https://www.w3.org/TR/css-values-3/#angle-value) units), NOT in degrees.
+Likewise, luminance is always stored in the `[0,1]` too, even for Lab, LCH where
+often the `[0,100]` range is used instead.
-#### Class wrappers
+As a fairly unique feature, all color types can be used to provided views of a
+backing memory buffer (e.g. for WASM/WebGL/WebGPU interop, pixel buffers etc.),
+incl. support for arbitrary component strides.
-The package provides lightweight class wrappers for each color mode /
-space. These wrappers act similarly to the `Vec2/3/4` wrappers in
+The lightweight class wrappers act similarly to the `Vec2/3/4` wrappers in
[@thi.ng/vectors](https://github.com/thi-ng/umbrella/tree/develop/packages/vectors),
support striding (for mapped memory views), named channel accessor
aliases (in addition to array indexing) and are fully compatible with
-all functions (and act as syntax sugar for generic conversion
-functions). Wrapper factory functions are provided for convenience.
+all vector functions.
+
+![Memory diagram of densely packed buffer](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/mapped-colors-01.png)
+
+```ts
+const memory = new Float32Array(16);
+
+// create RGBA color views of buffer: num, start index, strides
+// here the colors are tightly packed w/o gaps in between
+// (by default entire buffer is mapped, last 4 args are optional)
+const colors = rgb.mapBuffer(memory, 4, 0, 1, 4);
+
+// manipulating the colors, will directly manipulate the underlying buffer
+namedHueRgb(colors[0], Hue.ORANGE);
+namedHueRgb(colors[1], Hue.CHARTREUSE);
+namedHueRgb(colors[2], Hue.SPRING_GREEN);
+namedHueRgb(colors[3], Hue.AZURE);
+
+memory
+// Float32Array(16) [ 1, 0.5, 0, 1, 0.5, 1, 0, 1, 0, 1, 0.5, 1, 0, 0.5, 1, 1 ]
+
+css(colors[0])
+// '#ff8000'
+css(colors[1])
+// '#80ff00'
+css(colors[2])
+// '#00ff80'
+css(colors[3])
+// '#0080ff'
+
+// use deref() to obtain a packed copy
+colors[0].deref()
+// [ 1, 0.5, 0, 1 ]
+```
+
+![Memory diagram of strided & interleaved buffer](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/mapped-colors-02.png)
+
+```ts
+// here we create a *strided* WebGL attrib buffer for 3 points
+// each point defines a: 3D position, UV coords and RGB(A) color
+const attribs = new Float32Array([
+ // pos uv color
+ 0,0,0, 0,0, 0.25,0.5,0,1,
+ 100,0,0, 1,0, 0.5,0.5,0.25,1,
+ 100,100,0, 1,1, 0,1,0.5,1,
+]);
+
+// create strided view of colors
+// 3 items, start index 5, component stride 1, element stride 9
+colors = srgb.mapBuffer(attribs, 3, 5, 1, 9);
+
+css(colors[0])
+// '#408000'
+css(colors[1])
+// '#808040'
+css(colors[2])
+// '#00ff80'
+```
### Color theme generation
-The package provides several methods for procedural & declarative color theme
-generations. The latter relies on the concept of HSV color ranges, which can be
-sampled directly and/or mixed with a base color to produce randomized
-variations. Furthermore, multiple such ranges can be combined into a weighted
-set to define probabilistic color themes.
+The package provides several methods for declarative & probabilistic color theme
+generation. The latter relies on the concept of LCH color ranges, which can be
+sampled directly and/or mixed with a base color (of any type) to produce
+randomized variations. Furthermore, multiple such ranges can be combined into a
+weighted set to define probabilistic color themes.
```ts
// single random color drawn from the "bright" color range preset
-colorFromRange(RANGES.bright);
+colorFromRange("bright");
// [ 0.7302125322518669, 0.8519945301256682, 0.8134374983367859, 1 ]
-// single random color based on given HSV base color and preset
-colorFromRange(RANGES.warm, [0.33, 1, 1])
-// [ 0.3065587375218628, 0.8651353734302525, 0.748781892650323, 1 ]
+// single random color based on given raw HSV base color and preset
+colorFromRange("warm", { base: hsv(0.33, 1, 1) })
+// $Color {
+// offset: 0,
+// stride: 1,
+// buf: [ 0.774977122048776, 0.7432832945738063, 0.3186095419992927, 1 ]
+// }
// infinite iterator of colors sampled from the preset
// (see table below)
-const colors = colorsFromRange(RANGES.bright);
+const colors = colorsFromRange("bright");
colors.next();
// {
// value: [ 0.006959075656347791, 0.8760165887192115, 0.912149937028727, 1 ],
// done: false
// }
-// 10 cool reds, w/ 10% hue variance
-[...colorsFromRange(RANGES.cool, [0, 0.8, 1], { num: 10, variance: 0.1 })]
+// 10 cool reds, w/ Β±10% hue variance
+[...colorsFromRange("cool", { num: 10, base: lch(1, 0.8, 0), variance: 0.1 })]
// generate colors based on given (weighted) textual description(s)
-// here using named CSS colors, but could also be HSV tuples
+// here using named CSS colors, but could also be or typed colors or raw LCH tuples
[...colorsFromTheme(
[["warm", "goldenrod"], ["cool", "springgreen", 0.1]],
{ num: 100, variance: 0.05 }
)]
// theme parts can also be given in the format used internally
-// note: base colors are always in HSV
// all keys are optional (range, base, weight),
// but at least `range` or `base` must be given...
[...colorsFromTheme(
[
{ range: "warm", base: "goldenrod" },
- { range: RANGES.cool, base: [0, 1, 0.5], weight: 0.1 }
+ { range: COLOR_RANGES.cool, base: hsv(0, 1, 0.5), weight: 0.1 }
],
{ num: 100, variance: 0.05 }
)]
```
-| ID | 100 colors drawn from color range preset only, sorted by hue |
-|-----------|--------------------------------------------------------------------------------------------------------------------|
-| `bright` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-bright.svg) |
-| `cool` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-cool.svg) |
-| `dark` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-dark.svg) |
-| `fresh` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-fresh.svg) |
-| `hard` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-hard.svg) |
-| `intense` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-intense.svg) |
-| `light` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-light.svg) |
-| `neutral` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-neutral.svg) |
-| `soft` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-soft.svg) |
-| `warm` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-warm.svg) |
-| `weak` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-weak.svg) |
-
-| ID | 100 colors, single base color w/ color range preset, sorted by hue |
-|-----------|--------------------------------------------------------------------------------------------------------------------|
-| `bright` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-green-bright.svg) |
-| `cool` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-green-cool.svg) |
-| `dark` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-green-dark.svg) |
-| `fresh` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-green-fresh.svg) |
-| `hard` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-green-hard.svg) |
-| `intense` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-green-intense.svg) |
-| `light` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-green-light.svg) |
-| `neutral` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-green-neutral.svg) |
-| `soft` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-green-soft.svg) |
-| `warm` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-green-warm.svg) |
-| `weak` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-green-weak.svg) |
-
-| ID | 100 colors, 2 base colors w/ color range preset, sorted by brightness |
-|-----------|------------------------------------------------------------------------------------------------------------------|
-| `bright` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-duo-bright.svg) |
-| `cool` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-duo-cool.svg) |
-| `dark` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-duo-dark.svg) |
-| `fresh` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-duo-fresh.svg) |
-| `hard` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-duo-hard.svg) |
-| `intense` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-duo-intense.svg) |
-| `light` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-duo-light.svg) |
-| `neutral` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-duo-neutral.svg) |
-| `soft` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-duo-soft.svg) |
-| `warm` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-duo-warm.svg) |
-| `weak` | ![color swatch](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-duo-weak.svg) |
+This table below shows three sets of sample swatches for each color range preset
+and the following color theme (raw samples and chunked & sorted):
+
+- 1/3 goldenrod
+- 1/3 turquoise
+- 1/3 pink
+- 1/6 black
+- 1/6 gray
+- 1/6 white
+
+| ID | 100 colors drawn from color range preset |
+|-----------|-----------------------------------------------------------------------------------------------------------------------------|
+| `bright` | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-bright-hue.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-bright-mixed.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-bright-chunks.svg) |
+| `cool` | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-cool-hue.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-cool-mixed.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-cool-chunks.svg) |
+| `dark` | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-dark-hue.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-dark-mixed.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-dark-chunks.svg) |
+| `fresh` | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-fresh-hue.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-fresh-mixed.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-fresh-chunks.svg) |
+| `hard` | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-hard-hue.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-hard-mixed.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-hard-chunks.svg) |
+| `intense` | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-intense-hue.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-intense-mixed.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-intense-chunks.svg) |
+| `light` | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-light-hue.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-light-mixed.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-light-chunks.svg) |
+| `neutral` | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-neutral-hue.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-neutral-mixed.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-neutral-chunks.svg) |
+| `soft` | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-soft-hue.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-soft-mixed.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-soft-chunks.svg) |
+| `warm` | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-warm-hue.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-warm-mixed.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-warm-chunks.svg) |
+| `weak` | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-weak-hue.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-weak-mixed.svg) |
+| | ![color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-range-weak-chunks.svg) |
Full example:
```ts
-import { colorsFromTheme, hsva, swatchesH } from "@thi.ng/color";
+import { colorsFromTheme, swatchesH } from "@thi.ng/color";
import { serialize } from "@thi.ng/hiccup";
import { svg } from "@thi.ng/hiccup-svg";
import { writeFileSync } from "fs";
@@ -169,18 +332,17 @@ import { writeFileSync } from "fs";
// color range preset names, CSS colors and weights
const theme: ColorThemePartTuple[] = [
["cool", "goldenrod"],
- ["fresh", "hotpink", 0.1],
- ["light", "springgreen", 0.1],
+ ["hard", "hotpink", 0.1],
+ ["fresh", "springgreen", 0.1],
];
-// generate 200 HSV colors based on above description
+// generate 200 LCH colors based on above description
const colors = [...colorsFromTheme(theme, { num: 200, variance: 0.05 })];
// create SVG doc of color swatches (hiccup format)
-// (convert colors to RGB for smaller file size)
const doc = svg(
{ width: 1000, height: 50, convert: true },
- swatchesH(colors.map((x) => hsvaRgba([], x)), 5, 50)
+ swatchesH(colors, 5, 50)
);
// serialize to SVG file
@@ -189,52 +351,114 @@ writeFileSync("export/swatches-ex01.svg", serialize(doc));
![example result color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-ex01.svg)
-### Color sorting
+### Color sorting & distance
-The `sortColors()` function can be used to sort an array of colors using
-arbitrary sort criteria. The following comparators are bundled:
+The package provides several functions to compute full or channel-wise distances
+between colors. These functions can also be used for sorting color arrays (see below).
+
+- `distChannel` - single channel distance only
+- `distHsv` / `distHsvSat` / `distHsvLuma`
+- `distEucledian3` / `distEucledian4`
+- `distRgbLuma` / `distSrgbLuma`
+- `distCIEDE2000`
+- `distCMC`
+
+The `sort()` function can be used to sort an array of colors using arbitrary
+sort criteria (basically any function which can transform a color into a
+number). The following comparators are bundled:
- `selectChannel(i)` - sort by channel
-- `proximityHSV(target)` - sort by distance to target color (HSV colors)
-- `proximityRGB(target)` - sort by distance to target color (RGB colors)
+- `proximity(target, distFn)` - sort by distance to target color using given distance function
+- `luminance` / `luminanceRgb` / `luminanceSrgb` etc.
```ts
// (see above example)
const colors = [...colorsFromTheme(theme, { num: 200, variance: 0.05 })];
-sortColors(colors, proximityHSV([0,1,0.5]));
+sortColors(colors, proximity(lch("#fff"), distCIEDE2000()));
```
![sorted color swatches](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/swatches-ex02.svg)
-### RGBA transformations
+#### Sorting memory-mapped colors
-RGBA [color matrix
-transformations](https://github.com/thi-ng/umbrella/tree/develop/packages/color/src/transform.ts),
-including parametric preset transforms:
+Memory mapped colors (e.g. a mapped pixel buffer) can be sorted (in place) via
+`sortMapped()`. This function does NOT change the order of elements in the given
+colors array, BUT instead sorts the apparent order by swapping the contents of
+the backing memory.
-- brightness
-- contrast
-- exposure
-- saturation (luminance aware)
-- hue rotation
-- color temperature (warm / cold)
-- sepia (w/ fade amount)
-- tint (green / magenta)
-- grayscale (luminance aware)
-- subtraction/inversion (also available as non-matrix op)
-- luminance to alpha
+See the [pixel sorting
+example](https://github.com/thi-ng/umbrella/tree/develop/examples/pixel-sorting)
+for a concrete use case...
-Transformation matrices can be combined using matrix multiplication /
-concatenation (see `concat()`) for more efficient application.
+```ts
+// memory buffer of 4 sRGB colors
+const buf = new Float32Array([0,1,0,1, 0,0.5,0,1, 0,0.25,0,1, 0,0.75,0,1]);
+
+// map buffer (creates 4 SRGB instances linked to the buffer)
+const pix = srgb.mapBuffer(buf);
+
+// display original order
+pix.map(css);
+// [ '#00ff00', '#008000', '#004000', '#00bf00' ]
+
+// sort colors (buffer!) by luminance
+sortMapped(pix, luminanceSrgb);
+
+// new order
+pix.map(css);
+// [ '#004000', '#008000', '#00bf00', '#00ff00' ]
+
+// buffer contents have been re-ordered
+buf
+// Float32Array(16) [
+// 0, 0.25, 0, 1, 0,
+// 0.5, 0, 1, 0, 0.75,
+// 0, 1, 0, 1, 0,
+// 1
+// ]
+```
+
+### Gradients
+
+#### Multi-stop gradients in any color space
+
+The `multiColorGradient()` function can be used to generate gradients in any
+color space and gradient stops must be using all the same color type. Colors are
+pairwise interpolated, and by default, uses generic `mix()` function which
+delegates to type specific strategies. See `GradientOpts` for details.
-### RGBA Porter-Duff compositing
+![LCH example gradient](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/lch-gradient.svg)
-This feature has been moved to the separate
-[@thi.ng/porter-duff](https://github.com/thi-ng/umbrella/tree/develop/packages/porter-duff)
-package.
+```ts
+const L = 0.8;
+const C = 0.8;
+
+const gradient = multiColorGradient({
+ num: 100,
+ // gradient stops
+ stops: [
+ [0, lch(L, C, 0)],
+ [1 / 3, lch(L, C, 1 / 3)],
+ [2 / 3, lch(L, C, 2 / 3)],
+ [1, lch(L, 0, 1)],
+ ],
+ // optionally with easing function
+ // easing: (t) => t * t,
+});
+
+writeFileSync(
+ `export/lch-gradient.svg`,
+ serialize(
+ svg(
+ { width: 500, height: 50, convert: true },
+ swatchesH(gradient, 5, 50)
+ )
+ )
+);
+```
-### Cosine gradients
+#### Cosine gradients
- [Original article](http://www.iquilezles.org/www/articles/palettes/palettes.htm)
- [Gradient generator](http://dev.thi.ng/gradients/)
@@ -266,42 +490,42 @@ The following presets are bundled (in [`cosine-gradients.ts`](https://github.com
| ![gradient: yellow-purple-magenta](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/gradient-yellow-purple-magenta.png) | `yellow-purple-magenta` |
| ![gradient: yellow-red](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/color/gradient-yellow-red.png) | `yellow-red` |
-### Two-color gradients
+##### Two-color cosine gradients
The `cosineCoeffs()` function can be used to compute the cosine gradient
coefficients between 2 start/end colors:
```ts
// compute gradient coeffs between red / green
-cosineGradient(10, cosineCoeffs([1,0,0,1], [0,1,0,1])).map(rgbaCss)
-// #ff0000
-// #f70800
-// #e11e00
-// #bf4000
-// #966900
-// #699600
-// #40bf00
-// #1ee100
-// #08f700
-// #00ff00
+cosineGradient(10, cosineCoeffs([1,0,1,1], [0,1,0,1])).map(css)
+// '#ff00ff'
+// '#f708f7'
+// '#e11ee1'
+// '#bf40bf'
+// '#966996'
+// '#699669'
+// '#40bf40'
+// '#1ee11e'
+// '#08f708'
+// '#00ff00'
```
-### Multi-stop gradients
+##### Multi-stop gradients
-The `multiCosineGradient()` function returns an iterator of raw RGBA
+The `multiCosineGradient()` function returns an iterator of raw RGB
colors based on given gradient stops. This iterator computes a cosine
-gradient between each color stop and yields a sequence of RGBA values.
+gradient between each color stop and yields a sequence of RGB values.
```ts
-col.multiCosineGradient(
- // num colors to produce
- 10,
- // gradient stops (normalized positions, only RGBA colors supported)
- [0.1, col.RED], [0.5, col.GREEN], [0.9, col.BLUE]
-)
+multiCosineGradient({
+ num: 10,
+ // gradient stops (normalized positions)
+ stops: [[0.1, [1, 0, 0, 1]], [0.5, [0, 1, 0, 1]], [0.9, [0, 0, 1, 1]]],
+ // optional color transform/coercion
+ tx: srgba
+})
// convert to CSS
-.map(col.rgbaCss)
-
+.map(css)
// [
// "#ff0000",
// "#ff0000",
@@ -317,12 +541,38 @@ col.multiCosineGradient(
// ]
```
+### RGB color transformations
+
+RGB [color matrix
+transformations](https://github.com/thi-ng/umbrella/tree/develop/packages/color/src/transform.ts),
+including parametric preset transforms:
+
+- brightness
+- contrast
+- exposure
+- saturation (luminance aware)
+- hue rotation
+- color temperature (warm / cold)
+- sepia (w/ fade amount)
+- tint (green / magenta)
+- grayscale (luminance aware)
+- subtraction/inversion (also available as non-matrix op)
+- luminance to alpha
+
+Transformation matrices can be combined using matrix multiplication /
+concatenation (see `concat()`) for more efficient application.
+
### Status
**STABLE** - used in production
[Search or submit any issues for this package](https://github.com/thi-ng/umbrella/issues?q=%5Bcolor%5D+in%3Atitle)
+### Related packages
+
+- [@thi.ng/pixel](https://github.com/thi-ng/umbrella/tree/develop/packages/pixel) - Typed array backed, integer and floating point pixel buffers w/ customizable formats, blitting, dithering, conversions
+- [@thi.ng/vectors](https://github.com/thi-ng/umbrella/tree/develop/packages/vectors) - Optimized 2d/3d/4d and arbitrary length vector operations
+
## Installation
```bash
@@ -337,12 +587,13 @@ yarn add @thi.ng/color
```
-Package sizes (gzipped, pre-treeshake): ESM: 8.42 KB / CJS: 8.85 KB / UMD: 8.31 KB
+Package sizes (gzipped, pre-treeshake): ESM: 13.67 KB / CJS: 14.33 KB / UMD: 13.41 KB
## Dependencies
- [@thi.ng/api](https://github.com/thi-ng/umbrella/tree/develop/packages/api)
- [@thi.ng/arrays](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays)
+- [@thi.ng/binary](https://github.com/thi-ng/umbrella/tree/develop/packages/binary)
- [@thi.ng/checks](https://github.com/thi-ng/umbrella/tree/develop/packages/checks)
- [@thi.ng/compare](https://github.com/thi-ng/umbrella/tree/develop/packages/compare)
- [@thi.ng/compose](https://github.com/thi-ng/umbrella/tree/develop/packages/compose)
@@ -362,56 +613,17 @@ directory are using this package.
A selection:
-| Screenshot | Description | Live demo | Source |
-| ------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------- |
-| | Heatmap visualization of this mono-repo's commits | | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/commit-heatmap) |
-| | Visualization of different grid iterator strategies | [Demo](https://demo.thi.ng/umbrella/grid-iterators/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/grid-iterators) |
-| | Fork-join worker-based raymarch renderer | [Demo](https://demo.thi.ng/umbrella/shader-ast-workers/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/shader-ast-workers) |
+| Screenshot | Description | Live demo | Source |
+| ------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------- |
+| | Heatmap visualization of this mono-repo's commits | | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/commit-heatmap) |
+| | Visualization of different grid iterator strategies | [Demo](https://demo.thi.ng/umbrella/grid-iterators/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/grid-iterators) |
+| | Interactive pixel sorting tool using thi.ng/color & thi.ng/pixel | [Demo](https://demo.thi.ng/umbrella/pixel-sorting/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/pixel-sorting) |
+| | Fork-join worker-based raymarch renderer | [Demo](https://demo.thi.ng/umbrella/shader-ast-workers/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/shader-ast-workers) |
## API
[Generated API docs](https://docs.thi.ng/umbrella/color/)
-```ts
-import * as col from "@thi.ng/color";
-
-// route #1: asXXX() converters: string -> CSS -> ARGB (int) -> RGBA
-const a = col.asRGBA(col.css("#3cf"));
-// [0.2, 0.8, 1, 1]
-
-// route #2: parseCSS(): string -> RGBA
-const b = col.parseCss("hsla(30,100%,50%,0.75)");
-// [ 1, 0.5, 0, 0.75 ]
-
-// route #3: convert() multi-method: CSS -> RGBA -> HSVA
-// (see convert.ts)
-const c = col.convert("rgb(0,255,255)", "hsv", "css");
-// [ 0.4999999722222268, 0.9999990000010001, 1, 1 ]
-
-// route #4: direct conversion RGBA -> HSLA -> CSS
-// first arg is output color (same calling convention as @thi.ng/vectors)
-// (use `null` to mutate the input color)
-col.hslaCss(col.rgbaHsla([], [1, 0.5, 0.5, 1]))
-// "hsl(0.00,100.00%,75.00%)"
-
-col.luminance(col.css("white"))
-col.luminance(0xffffff, "int")
-// 1
-
-// apply color matrix (RGBA only)
-col.transform([], col.saturation(1.25), a)
-// [ 0.07835000000000002, 0.82835, 1, 1 ]
-
-// combine matrix transformations
-filter = col.concat(
- col.saturation(0.5), // 50% saturation
- col.brightness(0.1), // +10% brightness
-);
-
-col.transform([], filter, col.RED);
-// [ 0.7065, 0.2065, 0.2065, 1 ]
-```
-
## Authors
Karsten Schmidt
diff --git a/packages/color/package.json b/packages/color/package.json
index 785e081799..2f2a4ac099 100644
--- a/packages/color/package.json
+++ b/packages/color/package.json
@@ -1,7 +1,7 @@
{
"name": "@thi.ng/color",
- "version": "2.1.5",
- "description": "Array-based color types, conversions, transformations, declarative theme generation, multi-color gradients, presets",
+ "version": "3.0.0",
+ "description": "Array-based color types, CSS parsing, conversions, transformations, declarative theme generation, gradients, presets",
"module": "./index.js",
"main": "./lib/index.js",
"umd:main": "./lib/index.umd.js",
@@ -31,7 +31,7 @@
"build:check": "tsc --isolatedModules --noEmit",
"test": "mocha test",
"cover": "nyc mocha test && nyc report --reporter=lcov",
- "clean": "rimraf *.js *.d.ts *.map .nyc_output build coverage doc lib internal",
+ "clean": "rimraf *.js *.d.ts *.map .nyc_output build coverage doc lib api css hcy hsi hsl hsv int internal lab lch oklab ops rgb srgb xyy xyz ycc",
"doc:readme": "ts-node -P ../../tools/tsconfig.json ../../tools/src/readme.ts",
"doc": "node_modules/.bin/typedoc --excludePrivate --out doc --theme ../../tools/doc/typedoc-theme src/index.ts",
"doc:ae": "mkdir -p .ae/doc .ae/temp && node_modules/.bin/api-extractor run --local --verbose",
@@ -43,57 +43,82 @@
"@microsoft/api-extractor": "^7.12.1",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.14",
- "mocha": "^8.2.1",
+ "mocha": "^8.3.0",
"nyc": "^15.1.0",
"ts-node": "^9.1.1",
- "typedoc": "^0.20.4",
- "typescript": "^4.1.3"
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
},
"dependencies": {
- "@thi.ng/api": "^6.13.6",
- "@thi.ng/arrays": "^0.10.1",
- "@thi.ng/checks": "^2.8.0",
- "@thi.ng/compare": "^1.3.22",
- "@thi.ng/compose": "^1.4.23",
- "@thi.ng/defmulti": "^1.3.4",
- "@thi.ng/errors": "^1.2.26",
- "@thi.ng/math": "^3.1.0",
- "@thi.ng/random": "^2.2.0",
- "@thi.ng/strings": "^1.14.0",
- "@thi.ng/transducers": "^7.5.8",
- "@thi.ng/vectors": "^4.9.1"
+ "@thi.ng/api": "^7.0.0",
+ "@thi.ng/arrays": "^0.10.2",
+ "@thi.ng/binary": "^2.1.0",
+ "@thi.ng/checks": "^2.9.0",
+ "@thi.ng/compare": "^1.3.23",
+ "@thi.ng/compose": "^1.4.24",
+ "@thi.ng/defmulti": "^1.3.5",
+ "@thi.ng/errors": "^1.2.27",
+ "@thi.ng/math": "^3.2.0",
+ "@thi.ng/random": "^2.3.0",
+ "@thi.ng/strings": "^1.15.0",
+ "@thi.ng/transducers": "^7.6.0",
+ "@thi.ng/vectors": "^5.0.0"
},
"files": [
"*.js",
"*.d.ts",
"lib",
- "internal"
+ "api",
+ "css",
+ "hcy",
+ "hsi",
+ "hsl",
+ "hsv",
+ "int",
+ "internal",
+ "lab",
+ "lch",
+ "oklab",
+ "ops",
+ "rgb",
+ "srgb",
+ "xyy",
+ "xyz",
+ "ycc"
],
"keywords": [
- "alpha",
- "blend",
- "channel",
- "cie1931",
"color",
"conversion",
"cosine",
"css",
- "declarative",
+ "D50",
+ "D65",
+ "distance",
"filter",
+ "gamma",
+ "generator",
"gradient",
"hcy",
"hsi",
"hsl",
"hsv",
+ "interpolation",
+ "iterator",
+ "lab",
+ "lch",
"matrix",
- "porter-duff",
+ "oklab",
+ "random",
"rgb",
+ "sort",
"srgb",
"swatches",
"theme",
"typescript",
+ "xyy",
"xyz",
- "ycbcr"
+ "ycbcr",
+ "ycc"
],
"publishConfig": {
"access": "public"
@@ -103,5 +128,10 @@
"setTimeout": false
},
"sideEffects": false,
- "thi.ng": {}
+ "thi.ng": {
+ "related": [
+ "pixel",
+ "vectors"
+ ]
+ }
}
diff --git a/packages/color/src/analog.ts b/packages/color/src/analog.ts
deleted file mode 100644
index e0e24fdefd..0000000000
--- a/packages/color/src/analog.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-import type { FnN } from "@thi.ng/api";
-import { clamp01 } from "@thi.ng/math";
-import { IRandom, SYSTEM } from "@thi.ng/random";
-import { setC4 } from "@thi.ng/vectors";
-import type { Color, ReadonlyColor } from "./api";
-import { ensureAlpha } from "./internal/ensure-alpha";
-import { ensureHue } from "./internal/ensure-hue";
-
-const $analog = (x: number, delta: number, rnd: IRandom, post: FnN = clamp01) =>
- delta !== 0 ? post(x + rnd.norm(delta)) : x;
-
-const $alpha = (a: number, delta: number, rnd: IRandom) =>
- delta !== 0
- ? clamp01((a !== undefined ? a : 1) + rnd.norm(delta))
- : ensureAlpha(a);
-
-/**
- * Similar to {@link analogRGB}. Returns an analog color based on given HSVA
- * color,with each channel randomly varied by given delta amounts (and
- * optionally given {@link @thi.ng/random#IRandom} PRNG).
- *
- * @remarks
- * By default (unless `deltaS`, `deltaV`, `deltaA` are provided) only the hue of
- * the color will be modulated.
- *
- * @param out
- * @param src
- * @param deltaH
- * @param deltaS
- * @param deltaV
- * @param deltaA
- * @param rnd
- */
-export const analogHSV = (
- out: Color | null,
- src: ReadonlyColor,
- deltaH: number,
- deltaS = 0,
- deltaV = 0,
- deltaA = 0,
- rnd: IRandom = SYSTEM
-) =>
- setC4(
- out || src,
- $analog(src[0], deltaH, rnd, ensureHue),
- $analog(src[1], deltaS, rnd),
- $analog(src[2], deltaV, rnd),
- $alpha(src[3], deltaA, rnd)
- );
-
-/**
- * Similar to {@link analogHSV}. Returns an analog color based on given RGBA
- * color, with each channel randomly varied by given delta amounts (and
- * optionally given {@link @thi.ng/random#IRandom} PRNG).
- *
- * @remarks
- * By default the green and blue channel variance will be the same as `deltaR`.
- *
- * @param out
- * @param src
- * @param deltaR
- * @param deltaG
- * @param deltaB
- * @param deltaA
- * @param rnd
- */
-export const analogRGB = (
- out: Color | null,
- src: ReadonlyColor,
- deltaR: number,
- deltaG = deltaR,
- deltaB = deltaR,
- deltaA = 0,
- rnd: IRandom = SYSTEM
-) =>
- setC4(
- out || src,
- $analog(src[0], deltaR, rnd),
- $analog(src[1], deltaG, rnd),
- $analog(src[2], deltaB, rnd),
- $alpha(src[3], deltaA, rnd)
- );
diff --git a/packages/color/src/api.ts b/packages/color/src/api.ts
index 360eaef342..a49e24ea7f 100644
--- a/packages/color/src/api.ts
+++ b/packages/color/src/api.ts
@@ -1,300 +1,233 @@
-import type { FnU2, Tuple } from "@thi.ng/api";
+import type { FnU2, IDeref, NumericArray, Range, Tuple } from "@thi.ng/api";
import type { IRandom } from "@thi.ng/random";
-import type { ReadonlyVec, Vec } from "@thi.ng/vectors";
-
-export type ColorMode =
- | "rgb"
- | "hcy"
- | "hsv"
- | "hsl"
- | "hsi"
- | "int"
- | "css"
- | "xyz"
- | "ycbcr";
-
-export type CSSColorName =
- | "aliceblue"
- | "antiquewhite"
- | "aqua"
- | "aquamarine"
- | "azure"
- | "beige"
- | "bisque"
- | "black"
- | "blanchedalmond"
- | "blue"
- | "blueviolet"
- | "brown"
- | "burlywood"
- | "cadetblue"
- | "chartreuse"
- | "chocolate"
- | "coral"
- | "cornflowerblue"
- | "cornsilk"
- | "crimson"
- | "cyan"
- | "darkblue"
- | "darkcyan"
- | "darkgoldenrod"
- | "darkgray"
- | "darkgreen"
- | "darkgrey"
- | "darkkhaki"
- | "darkmagenta"
- | "darkolivegreen"
- | "darkorange"
- | "darkorchid"
- | "darkred"
- | "darksalmon"
- | "darkseagreen"
- | "darkslateblue"
- | "darkslategray"
- | "darkslategrey"
- | "darkturquoise"
- | "darkviolet"
- | "deeppink"
- | "deepskyblue"
- | "dimgray"
- | "dimgrey"
- | "dodgerblue"
- | "firebrick"
- | "floralwhite"
- | "forestgreen"
- | "fuchsia"
- | "gainsboro"
- | "ghostwhite"
- | "gold"
- | "goldenrod"
- | "gray"
- | "grey"
- | "green"
- | "greenyellow"
- | "honeydew"
- | "hotpink"
- | "indianred"
- | "indigo"
- | "ivory"
- | "khaki"
- | "lavender"
- | "lavenderblush"
- | "lawngreen"
- | "lemonchiffon"
- | "lightblue"
- | "lightcoral"
- | "lightcyan"
- | "lightgoldenrodyellow"
- | "lightgray"
- | "lightgreen"
- | "lightgrey"
- | "lightpink"
- | "lightsalmon"
- | "lightseagreen"
- | "lightskyblue"
- | "lightslategray"
- | "lightslategrey"
- | "lightsteelblue"
- | "lightyellow"
- | "lime"
- | "limegreen"
- | "linen"
- | "magenta"
- | "maroon"
- | "mediumaquamarine"
- | "mediumblue"
- | "mediumorchid"
- | "mediumpurple"
- | "mediumseagreen"
- | "mediumslateblue"
- | "mediumspringgreen"
- | "mediumturquoise"
- | "mediumvioletred"
- | "midnightblue"
- | "mintcream"
- | "mistyrose"
- | "moccasin"
- | "navajowhite"
- | "navy"
- | "oldlace"
- | "olive"
- | "olivedrab"
- | "orange"
- | "orangered"
- | "orchid"
- | "palegoldenrod"
- | "palegreen"
- | "paleturquoise"
- | "palevioletred"
- | "papayawhip"
- | "peachpuff"
- | "peru"
- | "pink"
- | "plum"
- | "powderblue"
- | "purple"
- | "red"
- | "rosybrown"
- | "royalblue"
- | "saddlebrown"
- | "salmon"
- | "sandybrown"
- | "seagreen"
- | "seashell"
- | "sienna"
- | "silver"
- | "skyblue"
- | "slateblue"
- | "slategray"
- | "slategrey"
- | "snow"
- | "springgreen"
- | "steelblue"
- | "tan"
- | "teal"
- | "thistle"
- | "tomato"
- | "turquoise"
- | "violet"
- | "wheat"
- | "white"
- | "whitesmoke"
- | "yellow"
- | "yellowgreen";
-
-export type ColorRangePreset =
- | "light"
- | "dark"
- | "bright"
- | "weak"
- | "neutral"
- | "fresh"
- | "soft"
- | "hard"
- | "warm"
- | "cool"
- | "intense";
-
-export type CosineGradientPreset =
- | "blue-cyan"
- | "blue-magenta-orange"
- | "blue-white-red"
- | "cyan-magenta"
- | "green-blue-orange"
- | "green-cyan"
- | "green-magenta"
- | "green-red"
- | "heat1"
- | "magenta-green"
- | "orange-blue"
- | "orange-magenta-blue"
- | "purple-orange-cyan"
- | "rainbow1"
- | "rainbow2"
- | "rainbow3"
- | "rainbow4"
- | "red-blue"
- | "yellow-green-blue"
- | "yellow-magenta-cyan"
- | "yellow-purple-magenta"
- | "yellow-red";
+import type { IVector, ReadonlyVec, Vec } from "@thi.ng/vectors";
export type Color = Vec;
export type ReadonlyColor = ReadonlyVec;
-/**
- * A 4x5 matrix in column-major order
- */
-export type ColorMatrix = Tuple;
-
-export type CosCoeffs = Tuple;
-export type CosGradientSpec = Tuple;
+export type MaybeColor =
+ | TypedColor
+ | IParsedColor
+ | ReadonlyColor
+ | string
+ | number;
-export type ColorConversion = (out: Color, src: T) => Color;
export type ColorOp = (out: Color | null, src: ReadonlyColor) => Color;
-export type ColorDistance = FnU2;
+export type ColorMode =
+ | "argb32"
+ | "abgr32"
+ | "hcy"
+ | "hsi"
+ | "hsl"
+ | "hsv"
+ | "lab50"
+ | "lab65"
+ | "lch"
+ | "oklab"
+ | "rgb"
+ | "srgb"
+ | "xyy"
+ | "xyz50"
+ | "xyz65"
+ | "ycc";
+
+/**
+ * Hue names in radial order, e.g. used by {@link namedHueRgb}.
+ */
+export enum Hue {
+ RED,
+ ORANGE,
+ YELLOW,
+ CHARTREUSE,
+ GREEN,
+ SPRING_GREEN,
+ CYAN,
+ AZURE,
+ BLUE,
+ VIOLET,
+ MAGENTA,
+ ROSE,
+}
export interface IColor {
readonly mode: ColorMode;
}
-export type Range = [number, number];
+export interface ChannelSpec {
+ /**
+ * Acceptable value range for this channel. Used by {@link TypedColor.clamp}.
+ * @defaultValue [0,1]
+ */
+ range?: Range;
+}
-export interface ColorRange {
+export interface ColorSpec {
+ mode: M;
/**
- * Hue ranges
+ * Define additional per-channel constraints, information. Currently only
+ * used to define limits.
*/
- h?: Range[];
+ channels?: Partial>;
/**
- * Saturation ranges
+ * Channel names in index order (used to define channel accessors).
*/
- s?: Range[];
+ order: readonly K[];
/**
- * Brightness ranges
+ * Conversions from source modes. `rgb` is mandatory, others optional. If a
+ * key specifies an array of functions, these will be applied to source
+ * color in LTR order.
*/
- v?: Range[];
+ from: Partial>> & {
+ rgb: ColorOp;
+ };
+}
+
+export type Conversions = Partial> & {
+ rgb: ColorOp;
+};
+
+export interface ColorFactory> {
+ (col: MaybeColor, buf?: NumericArray, idx?: number, stride?: number): T;
+ (col?: Vec, idx?: number, stride?: number): T;
+ (a: number, b: number, c: number, ...xs: number[]): T;
+
+ readonly class: TypedColorConstructor;
+
/**
- * Alpha ranges
+ * Returns a new random color, optionally backed by given memory. I.e. if
+ * `buf` is given, the returned color will wrap `buf` from given `index`
+ * (default: 0) and `stride` step size (default: 1).
+ *
+ * @param rnd
+ * @param buf
+ * @param index
+ * @param stride
*/
- a?: Range[];
+ random(
+ rnd?: IRandom,
+ buf?: NumericArray,
+ index?: number,
+ stride?: number
+ ): T;
+
/**
- * Black point ranges
+ * Same as {@link TypedColor.range}.
*/
- b?: Range[];
+ readonly range: [ReadonlyColor, ReadonlyColor];
+
/**
- * White point ranges
+ * Returns array of memory mapped colors using given backing array and
+ * stride settings.
+ *
+ * @remarks
+ * The `cstride` is the step size between individual color components.
+ * `estride` is the step size between successive colors and will default to
+ * number of channels supported by given color type/space. This arrangement
+ * allows for different storage approaches, incl. SOA, AOS, striped /
+ * interleaved etc.
+ *
+ * @param buf - backing array
+ * @param num - num vectors (default: buf.length / numChannels)
+ * @param start - start index (default: 0)
+ * @param cstride - component stride (default: 1)
+ * @param estride - element stride (default: numChannels)
*/
- w?: Range[];
+ mapBuffer(
+ buf: NumericArray,
+ num?: number,
+ start?: number,
+ cstride?: number,
+ estride?: number
+ ): T[];
+}
+
+export interface TypedColorConstructor> {
+ new (buf?: NumericArray, offset?: number, stride?: number): T;
}
-export interface ColorRangeOpts {
+export interface TypedColor extends IColor, IDeref, IVector {
/**
- * Nunber of result colors.
- *
- * @defaultValue β
+ * Backing array / memory
*/
- num: number;
+ buf: NumericArray;
/**
- * Max. normalized & randomized hue shift for result colors. Only used if a
- * base color is given.
- *
- * @defaultValue 0.025
+ * Start index in array
*/
- variance: number;
+ offset: number;
/**
- * Tolerance for grayscale check (used for both saturation and brightness).
- *
- * @defaultValue 0.001
+ * Step size between channels
*/
- eps: number;
+ stride: number;
+
/**
- * PRNG instance to use for randomized values
+ * A tuple of `[min, max]` where both are vectors specifying the
+ * min/max channel ranges for this color type.
*
- * @defaultValue {@link @thi.ng/random#SYSTEM}
+ * @remarks
+ * Even though there're several color spaces which do not impose limits on
+ * at least some of their axes, the limits returned by this function
+ * indicate RGB "safe" colors and were determined by projecting all RGB
+ * colors into the color space used by this type.
*/
- rnd: IRandom;
-}
+ readonly range: [ReadonlyColor, ReadonlyColor];
-export interface ColorThemePart {
/**
- * Color range spec to use
+ * Clamps all color channels so that colors is inside RGB gamut.
+ *
+ * @remarks
+ * Note: This is not a 100% guarantee, due to each channel being clamped
+ * individually based on pre-determined limits.
*/
- range?: ColorRange | ColorRangePreset;
+ clamp(): this;
+
/**
- * HSV(A) base color
+ * Randomizes all color channels based on channel ranges defined for this
+ * color type (usually [0..1] interval). Alpha channel will remain
+ * untouched.
+ *
+ * @param rnd
*/
- base?: ReadonlyColor | CSSColorName;
+ randomize(rnd?: IRandom): this;
+
/**
- * Relative weight of this theme part
+ * Copies `src` into this color's array.
*
- * @defaultValue 1.0
+ * @param src
+ */
+ set(src: ReadonlyColor): this;
+
+ /**
+ * For memory mapped colors, this ensures only the elements used by this
+ * color are being serialized (as array) by `JSON.stringify()`.
*/
- weight?: number;
+ toJSON(): number[];
+}
+
+export interface IParsedColor extends IColor, IDeref {}
+
+/**
+ * Result type returned by {@link parseCss}, a simple wrapper for a raw color
+ * array and color mode.
+ */
+export class ParsedColor implements IParsedColor {
+ constructor(public readonly mode: ColorMode, public value: Color) {}
+
+ deref() {
+ return this.value;
+ }
}
-export type ColorThemePartTuple =
- | [ColorRangePreset, CSSColorName, number?]
- | [ColorRangePreset | CSSColorName, number?]
- | ColorRangePreset
- | CSSColorName;
+/**
+ * A 4x5 matrix in column-major order
+ */
+export type ColorMatrix = Tuple;
+
+export type ColorDistance = FnU2;
+
+export type ColorMixFn = (
+ out: Color | null,
+ a: T,
+ b: T,
+ t: number
+) => Color;
diff --git a/packages/color/src/api/constants.ts b/packages/color/src/api/constants.ts
new file mode 100644
index 0000000000..99d02dcef9
--- /dev/null
+++ b/packages/color/src/api/constants.ts
@@ -0,0 +1,240 @@
+import { float, percent } from "@thi.ng/strings";
+
+/**
+ * RGB black
+ */
+export const BLACK = Object.freeze([0, 0, 0, 1]);
+/**
+ * RGB white
+ */
+export const WHITE = Object.freeze([1, 1, 1, 1]);
+/**
+ * RGB red
+ */
+export const RED = Object.freeze([1, 0, 0, 1]);
+/**
+ * RGB green
+ */
+export const GREEN = Object.freeze([0, 1, 0, 1]);
+/**
+ * RGB blue
+ */
+export const BLUE = Object.freeze([0, 0, 1, 1]);
+/**
+ * RGB cyan
+ */
+export const CYAN = Object.freeze([0, 1, 1, 1]);
+/**
+ * RGB magenta
+ */
+export const MAGENTA = Object.freeze([1, 0, 1, 1]);
+/**
+ * RGB yellow
+ */
+export const YELLOW = Object.freeze([1, 1, 0, 1]);
+
+/**
+ * ITU-R BT.601 RGB luminance coeffs
+ *
+ * @remarks
+ * Reference:
+ * https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
+ */
+export const RGB_LUMINANCE_REC601 = [0.299, 0.587, 0.114];
+
+/**
+ * ITU-R BT.709 RGB luminance coeffs
+ *
+ * @remarks
+ * Reference:
+ * https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.709_conversion
+ */
+export const RGB_LUMINANCE_REC709 = [0.2126, 0.7152, 0.0722];
+
+/**
+ * ITU-R BT.2020 RGB luminance coeffs
+ *
+ * @remarks
+ * Reference:
+ * https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.2020_conversion
+ */
+export const RGB_LUMINANCE_REC2020 = [0.2627, 0.678, 0.0593];
+
+/**
+ * sRGB to XYZ D65 conversion matrix
+ *
+ * @remarks
+ * Reference:
+ * http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+export const RGB_XYZ_D50 = [
+ 0.4360747,
+ 0.2225045,
+ 0.0139322,
+ 0.3850649,
+ 0.7168786,
+ 0.0971045,
+ 0.1430804,
+ 0.0606169,
+ 0.7141733,
+];
+
+/**
+ * XYZ D50 to sRGB conversion matrix
+ *
+ * @remarks
+ * Reference:
+ * http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+export const XYZ_RGB_D50 = [
+ 3.1338561,
+ -0.9787684,
+ 0.0719453,
+ -1.6168667,
+ 1.9161415,
+ -0.2289914,
+ -0.4906146,
+ 0.033454,
+ 1.4052427,
+];
+
+/**
+ * sRGB to XYZ D65 conversion matrix
+ *
+ * @remarks
+ * Reference:
+ * http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+export const RGB_XYZ_D65 = [
+ 0.4124564,
+ 0.2126729,
+ 0.0193339,
+ 0.3575761,
+ 0.7151522,
+ 0.119192,
+ 0.1804375,
+ 0.072175,
+ 0.9503041,
+];
+
+/**
+ * XYZ D65 to sRGB conversion matrix
+ *
+ * @remarks
+ * Reference:
+ * http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+ */
+export const XYZ_RGB_D65 = [
+ 3.2404542,
+ -0.969266,
+ 0.0556434,
+ -1.5371385,
+ 1.8760108,
+ -0.2040259,
+ -0.4985314,
+ 0.041556,
+ 1.0572252,
+];
+
+/**
+ * D50 -> D65 chromatic adaptation matrix. Inverse of {@link BRADFORD_D65_D50}.
+ *
+ * @remarks
+ * Reference:
+ * http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
+ */
+export const BRADFORD_D50_D65 = [
+ 0.9555766,
+ -0.0282895,
+ 0.0122982,
+ -0.0230393,
+ 1.0099416,
+ -0.020483,
+ 0.0631636,
+ 0.0210077,
+ 1.3299098,
+];
+
+/**
+ * D65 -> D50 chromatic adaptation matrix. Inverse of {@link BRADFORD_D50_D65}.
+ *
+ * @remarks
+ * Reference:
+ * http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
+ */
+export const BRADFORD_D65_D50 = [
+ 1.0478112,
+ 0.0295424,
+ -0.0092345,
+ 0.0228866,
+ 0.9904844,
+ 0.0150436,
+ -0.050127,
+ -0.0170491,
+ 0.7521316,
+];
+
+/**
+ * CIE Standard Illuminant D50
+ */
+export const D50 = [0.96422, 1, 0.82521];
+
+/**
+ * CIE Standard Illuminant D65
+ *
+ * Reference:
+ * https://en.wikipedia.org/wiki/Illuminant_D65
+ */
+export const D65 = [0.95047, 1, 1.08883];
+
+export const OKLAB_M1 = [
+ 0.8189330101,
+ 0.0329845436,
+ 0.0482003018,
+ 0.3618667424,
+ 0.9293118715,
+ 0.2643662691,
+ -0.1288597137,
+ 0.0361456387,
+ 0.633851707,
+];
+
+export const OKLAB_M2 = [
+ 0.2104542553,
+ 1.9779984951,
+ 0.0259040371,
+ 0.793617785,
+ -2.428592205,
+ 0.7827717662,
+ -0.0040720468,
+ 0.4505937099,
+ -0.808675766,
+];
+
+/**
+ * Float value formatter
+ *
+ * @internal
+ */
+export let FF = float(3);
+/**
+ * Percentage value formatter
+ *
+ * @internal
+ */
+export let PC = percent(3);
+
+/**
+ * Sets precision for CSS formatted values to `x` significant digits (default:
+ * 3).
+ *
+ * @param x
+ */
+export const setPrecision = (x: number) => {
+ FF = float(x);
+ PC = percent(x);
+};
+
+export const INV8BIT = 1 / 0xff;
+
+export const EPS = 1 / 256;
diff --git a/packages/color/src/api/gradients.ts b/packages/color/src/api/gradients.ts
new file mode 100644
index 0000000000..8bcf8c342c
--- /dev/null
+++ b/packages/color/src/api/gradients.ts
@@ -0,0 +1,61 @@
+import type { FnN, FnU, Tuple } from "@thi.ng/api";
+import type { Color, ColorMixFn, ReadonlyColor } from "../api";
+
+export type CosineGradientPreset =
+ | "blue-cyan"
+ | "blue-magenta-orange"
+ | "blue-white-red"
+ | "cyan-magenta"
+ | "green-blue-orange"
+ | "green-cyan"
+ | "green-magenta"
+ | "green-red"
+ | "heat1"
+ | "magenta-green"
+ | "orange-blue"
+ | "orange-magenta-blue"
+ | "purple-orange-cyan"
+ | "rainbow1"
+ | "rainbow2"
+ | "rainbow3"
+ | "rainbow4"
+ | "red-blue"
+ | "yellow-green-blue"
+ | "yellow-magenta-cyan"
+ | "yellow-purple-magenta"
+ | "yellow-red";
+
+export type CosineCoeffs = Tuple;
+
+export type CosGradientSpec = Tuple;
+
+/**
+ * A tuple of normalized position and color for a gradient stop.
+ */
+export type GradientColorStop = [number, T];
+
+export interface GradientOpts {
+ /**
+ * Number of colors to generate
+ */
+ num: number;
+ /**
+ * Gradient color stops, each a `[pos, color]`
+ */
+ stops: GradientColorStop[];
+ /**
+ * Interpolation function
+ */
+ mix?: ColorMixFn;
+ /**
+ * Easing function
+ */
+ easing?: FnN;
+}
+
+export interface CosineGradientOpts extends GradientOpts {
+ /**
+ * Post transformation function for each color
+ */
+ tx?: FnU;
+}
diff --git a/packages/color/src/names.ts b/packages/color/src/api/names.ts
similarity index 56%
rename from packages/color/src/names.ts
rename to packages/color/src/api/names.ts
index 0693bcaf36..c8865d1f74 100644
--- a/packages/color/src/names.ts
+++ b/packages/color/src/api/names.ts
@@ -1,4 +1,154 @@
-import type { CSSColorName } from "./api";
+export type CSSColorName =
+ | "aliceblue"
+ | "antiquewhite"
+ | "aqua"
+ | "aquamarine"
+ | "azure"
+ | "beige"
+ | "bisque"
+ | "black"
+ | "blanchedalmond"
+ | "blue"
+ | "blueviolet"
+ | "brown"
+ | "burlywood"
+ | "cadetblue"
+ | "chartreuse"
+ | "chocolate"
+ | "coral"
+ | "cornflowerblue"
+ | "cornsilk"
+ | "crimson"
+ | "cyan"
+ | "darkblue"
+ | "darkcyan"
+ | "darkgoldenrod"
+ | "darkgray"
+ | "darkgreen"
+ | "darkgrey"
+ | "darkkhaki"
+ | "darkmagenta"
+ | "darkolivegreen"
+ | "darkorange"
+ | "darkorchid"
+ | "darkred"
+ | "darksalmon"
+ | "darkseagreen"
+ | "darkslateblue"
+ | "darkslategray"
+ | "darkslategrey"
+ | "darkturquoise"
+ | "darkviolet"
+ | "deeppink"
+ | "deepskyblue"
+ | "dimgray"
+ | "dimgrey"
+ | "dodgerblue"
+ | "firebrick"
+ | "floralwhite"
+ | "forestgreen"
+ | "fuchsia"
+ | "gainsboro"
+ | "ghostwhite"
+ | "gold"
+ | "goldenrod"
+ | "gray"
+ | "grey"
+ | "green"
+ | "greenyellow"
+ | "honeydew"
+ | "hotpink"
+ | "indianred"
+ | "indigo"
+ | "ivory"
+ | "khaki"
+ | "lavender"
+ | "lavenderblush"
+ | "lawngreen"
+ | "lemonchiffon"
+ | "lightblue"
+ | "lightcoral"
+ | "lightcyan"
+ | "lightgoldenrodyellow"
+ | "lightgray"
+ | "lightgreen"
+ | "lightgrey"
+ | "lightpink"
+ | "lightsalmon"
+ | "lightseagreen"
+ | "lightskyblue"
+ | "lightslategray"
+ | "lightslategrey"
+ | "lightsteelblue"
+ | "lightyellow"
+ | "lime"
+ | "limegreen"
+ | "linen"
+ | "magenta"
+ | "maroon"
+ | "mediumaquamarine"
+ | "mediumblue"
+ | "mediumorchid"
+ | "mediumpurple"
+ | "mediumseagreen"
+ | "mediumslateblue"
+ | "mediumspringgreen"
+ | "mediumturquoise"
+ | "mediumvioletred"
+ | "midnightblue"
+ | "mintcream"
+ | "mistyrose"
+ | "moccasin"
+ | "navajowhite"
+ | "navy"
+ | "oldlace"
+ | "olive"
+ | "olivedrab"
+ | "orange"
+ | "orangered"
+ | "orchid"
+ | "palegoldenrod"
+ | "palegreen"
+ | "paleturquoise"
+ | "palevioletred"
+ | "papayawhip"
+ | "peachpuff"
+ | "peru"
+ | "pink"
+ | "plum"
+ | "powderblue"
+ | "purple"
+ | "red"
+ | "rosybrown"
+ | "royalblue"
+ | "saddlebrown"
+ | "salmon"
+ | "sandybrown"
+ | "seagreen"
+ | "seashell"
+ | "sienna"
+ | "silver"
+ | "skyblue"
+ | "slateblue"
+ | "slategray"
+ | "slategrey"
+ | "snow"
+ | "springgreen"
+ | "steelblue"
+ | "tan"
+ | "teal"
+ | "thistle"
+ | "tomato"
+ | "turquoise"
+ | "violet"
+ | "wheat"
+ | "white"
+ | "whitesmoke"
+ | "yellow"
+ | "yellowgreen"
+ // additions
+ | "rebeccapurple"
+ | "transparent";
export const CSS_NAMES: Record = {
aliceblue: "f0f8ff",
@@ -148,4 +298,7 @@ export const CSS_NAMES: Record = {
whitesmoke: "f5f5f5",
yellow: "ff0",
yellowgreen: "9acd32",
+ // additions
+ transparent: "0000",
+ rebeccapurple: "639",
};
diff --git a/packages/color/src/api/ranges.ts b/packages/color/src/api/ranges.ts
new file mode 100644
index 0000000000..f3a2203592
--- /dev/null
+++ b/packages/color/src/api/ranges.ts
@@ -0,0 +1,102 @@
+import type { Range } from "@thi.ng/api";
+import type { IRandom } from "@thi.ng/random";
+import type { ReadonlyColor } from "../api";
+import type { CSSColorName } from "./names";
+
+export type ColorRangePreset =
+ | "light"
+ | "dark"
+ | "bright"
+ | "weak"
+ | "neutral"
+ | "fresh"
+ | "soft"
+ | "hard"
+ | "warm"
+ | "cool"
+ | "intense";
+
+export interface ColorRange {
+ /**
+ * Hue ranges
+ */
+ h?: Range[];
+ /**
+ * Saturation ranges
+ */
+ c?: Range[];
+ /**
+ * Brightness ranges
+ */
+ l?: Range[];
+ /**
+ * Alpha ranges
+ */
+ a?: Range[];
+ /**
+ * Black point ranges
+ */
+ b?: Range[];
+ /**
+ * White point ranges
+ */
+ w?: Range[];
+}
+
+export interface ColorRangeOpts {
+ /**
+ * Nunber of result colors.
+ *
+ * @defaultValue β
+ */
+ num: number;
+ /**
+ * Base color. Either a {@link TypedColor} instance, {@link CSSColorName} or
+ * raw LCH tuple. Its hue will be used as bias to create a randomized
+ * variation (based on {@link ColorRangeOpts.variance}).
+ */
+ base?: ReadonlyColor | CSSColorName;
+ /**
+ * Max. normalized & randomized hue shift for result colors. Only used if a
+ * base color is given.
+ *
+ * @defaultValue 0.025 (i.e. +/- 9 degrees)
+ */
+ variance: number;
+ /**
+ * Tolerance for grayscale check (used for both saturation and brightness).
+ *
+ * @defaultValue 0.001
+ */
+ eps: number;
+ /**
+ * PRNG instance to use for randomized values
+ *
+ * @defaultValue {@link @thi.ng/random#SYSTEM}
+ */
+ rnd: IRandom;
+}
+
+export interface ColorThemePart {
+ /**
+ * Color range spec to use
+ */
+ range?: ColorRange | ColorRangePreset;
+ /**
+ * Base color. Either a {@link TypedColor} instance, {@link CSSColorName} or
+ * raw LCH tuple.
+ */
+ base?: ReadonlyColor | CSSColorName;
+ /**
+ * Relative weight of this theme part
+ *
+ * @defaultValue 1.0
+ */
+ weight?: number;
+}
+
+export type ColorThemePartTuple =
+ | [ColorRangePreset, CSSColorName, number?]
+ | [ColorRangePreset | CSSColorName, number?]
+ | ColorRangePreset
+ | CSSColorName;
diff --git a/packages/color/src/api/system.ts b/packages/color/src/api/system.ts
new file mode 100644
index 0000000000..c50f965cee
--- /dev/null
+++ b/packages/color/src/api/system.ts
@@ -0,0 +1,98 @@
+/**
+ * @remarks
+ * Reference: https://www.w3.org/TR/css-color-4/#typedef-system-color
+ */
+export interface SystemColors {
+ /**
+ * Background of application content or documents.
+ */
+ canvas: string;
+ /**
+ * Text in application content or documents.
+ */
+ canvastext: string;
+ /**
+ * Text in non-active, non-visited links. For light backgrounds,
+ * traditionally blue.
+ */
+ linktext: string;
+ /**
+ * Text in visited links. For light backgrounds, traditionally purple.
+ */
+ visitedtext: string;
+ /**
+ * Text in active links. For light backgrounds, traditionally red.
+ */
+ activetext: string;
+ /**
+ * The face background color for push buttons.
+ */
+ buttonface: string;
+ /**
+ * Text on push buttons.
+ */
+ buttontext: string;
+ /**
+ * The base border color for push buttons.
+ */
+ buttonborder: string;
+ /**
+ * Background of input fields.
+ */
+ field: string;
+ /**
+ * Text in input fields.
+ */
+ fieldtext: string;
+ /**
+ * Background of selected items/text.
+ */
+ highlight: string;
+ /**
+ * Text of selected items/text.
+ */
+ highlighttext: string;
+ /**
+ * Background of text that has been specially marked (such as by the HTML
+ * mark element).
+ */
+ mark: string;
+ /**
+ * Text that has been specially marked (such as by the HTML mark element).
+ */
+ marktext: string;
+ /**
+ * Disabled text. (Often, but not necessarily, gray.)
+ */
+ graytext: string;
+}
+
+/**
+ * Default CSS system colors used by {@link parseCss}. Use
+ * {@link setSystemColors} to provide custom defaults.
+ */
+export let CSS_SYSTEM_COLORS: SystemColors = {
+ canvas: "fff",
+ canvastext: "000",
+ linktext: "001ee4",
+ visitedtext: "4e2386",
+ activetext: "eb3323",
+ buttonface: "ddd",
+ buttontext: "000",
+ buttonborder: "000",
+ field: "fff",
+ fieldtext: "000",
+ highlight: "bbd5fb",
+ highlighttext: "000",
+ mark: "000",
+ marktext: "fff",
+ graytext: "808080",
+};
+
+/**
+ * Merges {@link CSS_SYSTEM_COLORS} w/ new values.
+ *
+ * @param cols
+ */
+export const setSystemColors = (cols: Partial) =>
+ Object.assign(CSS_SYSTEM_COLORS, cols);
diff --git a/packages/color/src/checks.ts b/packages/color/src/checks.ts
deleted file mode 100644
index b844580cb8..0000000000
--- a/packages/color/src/checks.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { eqDelta } from "@thi.ng/math";
-import type { ReadonlyColor } from "./api";
-
-const EPS = 1e-3;
-
-export const isGrayHsv = (x: ReadonlyColor, eps = EPS) => x[1] <= eps;
-
-export const isGrayRGB = (x: ReadonlyColor, eps = EPS) =>
- eqDelta(x[0], x[1], eps) && eqDelta(x[0], x[2], eps);
-
-export const isBlackHsv = (x: ReadonlyColor, eps = EPS) => x[2] <= eps;
-
-export const isBlackRGB = (x: ReadonlyColor, eps = EPS) =>
- x[0] <= eps && x[1] <= eps && x[2] <= eps;
-
-export const isWhiteHsv = (x: ReadonlyColor, eps = EPS) =>
- x[1] <= eps && x[2] >= 1 - eps;
-
-export const isWhiteRGB = (x: ReadonlyColor, eps = EPS) => {
- eps = 1 - eps;
- return x[0] >= eps && x[1] >= eps && x[2] >= eps;
-};
diff --git a/packages/color/src/closest-hue.ts b/packages/color/src/closest-hue.ts
deleted file mode 100644
index 997cdeecbb..0000000000
--- a/packages/color/src/closest-hue.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import type { Hue } from "./constants";
-import { ensureHue } from "./internal/ensure-hue";
-
-/**
- * Returns the {@link Hue} constant of the closest of 12 defined hues.
- *
- * @param h - normalized hue
- */
-export const closestHue = (h: number): Hue =>
- Math.round(ensureHue(h) * 12) % 12;
-
-/**
- * Returns the {@link Hue} constant of the closest primary or secondary hue.
- *
- * @param h - normalized hue
- */
-export const closestPrimaryHue = (h: number): Hue =>
- Math.round(ensureHue(h) * 12) % 12 & 0xe;
diff --git a/packages/color/src/color-range.ts b/packages/color/src/color-range.ts
deleted file mode 100644
index 5c789b64fe..0000000000
--- a/packages/color/src/color-range.ts
+++ /dev/null
@@ -1,265 +0,0 @@
-import { peek } from "@thi.ng/arrays";
-import { isArray, isNumber, isString } from "@thi.ng/checks";
-import { illegalArgs } from "@thi.ng/errors";
-import { IRandom, SYSTEM, weightedRandom } from "@thi.ng/random";
-import { analogHSV } from "./analog";
-import type {
- Color,
- ColorRange,
- ColorRangeOpts,
- ColorRangePreset,
- ColorThemePart,
- ColorThemePartTuple,
- Range,
- ReadonlyColor,
-} from "./api";
-import { isBlackHsv, isGrayHsv, isWhiteHsv } from "./checks";
-import { ensureAlpha } from "./internal/ensure-alpha";
-import { ensureHue } from "./internal/ensure-hue";
-import { parseCss } from "./parse-css";
-import { rgbaHsva } from "./rgba-hsva";
-
-/**
- * Preset {@link ColorRange}s for use with {@link colorsFromRange},
- * {@link colorsFromTheme} etc.
- */
-export const RANGES: Record = {
- light: {
- s: [[0.3, 0.7]],
- v: [[0.9, 1]],
- b: [[0.15, 0.3]],
- w: [[0.3, 1]],
- },
- dark: {
- s: [[0.7, 1]],
- v: [[0.15, 0.4]],
- b: [[0, 0.5]],
- w: [[0.5, 0.75]],
- },
- bright: {
- s: [[0.8, 1]],
- v: [[0.8, 1]],
- },
- weak: {
- s: [[0.15, 0.3]],
- v: [[0.7, 1]],
- b: [[0.2, 0.2]],
- w: [[0.2, 1]],
- },
- neutral: {
- s: [[0.25, 0.35]],
- v: [[0.3, 0.7]],
- b: [[0.15, 0.15]],
- w: [[0.9, 1]],
- },
- fresh: {
- s: [[0.4, 0.8]],
- v: [[0.8, 1]],
- b: [[0.05, 0.3]],
- w: [[0.8, 1]],
- },
- soft: {
- s: [[0.2, 0.3]],
- v: [[0.6, 0.9]],
- b: [[0.05, 0.15]],
- w: [[0.6, 0.9]],
- },
- hard: {
- s: [[0.9, 1]],
- v: [[0.4, 1]],
- },
- warm: {
- s: [[0.6, 0.9]],
- v: [[0.4, 0.9]],
- b: [[0.2, 0.2]],
- w: [[0.8, 1]],
- },
- cool: {
- s: [[0.05, 0.2]],
- v: [[0.9, 1]],
- b: [[0, 0.95]],
- w: [[0.95, 1]],
- },
- intense: {
- s: [[0.9, 1]],
- v: [
- [0.2, 0.35],
- [0.8, 1],
- ],
- },
-};
-
-const FULL: Range[] = [[0, 1]];
-
-const DEFAULT_RANGE: ColorRange = {
- h: FULL,
- s: FULL,
- v: FULL,
- b: FULL,
- w: FULL,
- a: [[1, 1]],
-};
-
-const DEFAULT_OPTS: ColorRangeOpts = {
- num: Infinity,
- variance: 0.025,
- eps: 1e-3,
- rnd: SYSTEM,
-};
-
-const $rnd = (ranges: Range[], rnd: IRandom) =>
- rnd.minmax(...ranges[rnd.int() % ranges.length]);
-
-/**
- * Takes a {@link ColorRange}, optional base color (HSV(A)) and options to produce
- * a single new result color. This color is randomized within the channel limits
- * of the given `range`. If a `base` color is provided, its hue is used as bias
- * and the `variance` option defines the max. -/+ normalized hue shift of the
- * result color.
- *
- * @remarks
- * If the base color is a shade of gray (incl. black & white), the result will
- * be another gray and is based on the range's black and white point sub-ranges.
- *
- * The alpha channel of the result color will only be randomized (based on
- * `range.a` settings) iff no `base` color was provided. If `base` is given, the
- * result will used the same alpha.
- *
- * A custom PRNG can be defined via the `rnd` option (default: `Math.random`).
- *
- * @param range
- * @param base
- * @param opts
- */
-export const colorFromRange = (
- range: ColorRange,
- base?: ReadonlyColor,
- opts?: Partial>
-): Color => {
- range = { ...DEFAULT_RANGE, ...range };
- const { variance, rnd, eps } = { ...DEFAULT_OPTS, ...opts };
- let h: number, a: number;
- if (base) {
- h = base[0];
- a = ensureAlpha(base[3]);
- if (isBlackHsv(base, eps)) return [h, 0, $rnd(range.b!, rnd), a];
- if (isWhiteHsv(base, eps)) return [h, 0, $rnd(range.w!, rnd), a];
- if (isGrayHsv(base, eps))
- return [
- h,
- 0,
- $rnd(rnd.float() < 0.5 ? range.b! : range.w!, rnd),
- a,
- ];
- h = ensureHue(h + rnd.norm(variance));
- } else {
- h = $rnd(range.h!, rnd);
- a = $rnd(range.a!, rnd);
- }
- return [h, $rnd(range.s!, rnd), $rnd(range.v!, rnd), a];
-};
-
-/**
- * Generator version of {@link colorFromRange}, by default yielding an infinite
- * sequence of random colors based on given range, base color (optional) and
- * other opts. Use `num` option to limit number of results.
- *
- * @param range
- * @param base
- * @param opts
- */
-export function* colorsFromRange(
- range: ColorRange,
- base?: ReadonlyColor,
- opts: Partial = {}
-) {
- let num = opts.num != undefined ? opts.num : Infinity;
- while (--num >= 0) yield colorFromRange(range, base, opts);
-}
-
-/** @internal */
-const asThemePart = (p: ColorThemePart | ColorThemePartTuple) => {
- let spec: ColorThemePart;
- let weight: number;
- if (isArray(p)) {
- const [a, ...xs] = p;
- if (isNumber(peek(xs))) {
- weight = peek(xs);
- xs.pop();
- } else {
- weight = 1;
- }
- spec = (
- (xs.length === 1
- ? { range: a, base: xs[0], weight }
- : xs.length === 0
- ? RANGES[a]
- ? { range: a, weight }
- : { base: a, weight }
- : illegalArgs(`invalid theme part: "${p}"`))
- );
- } else if (isString(p)) {
- spec = (
- (RANGES[p]
- ? { range: p, weight: 1 }
- : { base: p, weight: 1 })
- );
- } else {
- spec = p;
- spec.weight == null && (spec.weight = 1);
- }
- isString(spec.range) && (spec.range = RANGES[spec.range]);
- isString(spec.base) && (spec.base = rgbaHsva([], parseCss(spec.base)));
- return spec;
-};
-
-/**
- * Probabilistic color theme generator. Yield randomized colors based on given
- * weighted set of theme part specs.
- *
- * @remarks
- * Each theme part is a tuple of either:
- *
- * - `[range, color, weight?]`
- * - `[range, weight?]`
- * - `[color, weight?]`
- *
- * `range` can be either a {@link ColorRange} or the name of a {@link RANGE}
- * preset. Likewise, `color` can be an HSV(A) color tuple or a CSS color name.
- * The `weight` of each part defines the relative importance/probability of this
- * theme part, compared to others. Default weight is 1.0.
- *
- * @example
- * ```ts
- * [...colorsFromTheme(
- * [["cool", "aliceblue"], ["bright", "orange", 0.25], ["hotpink", 0.1]],
- * { num: 10 }
- * )]
- * ```
- *
- * @param parts
- * @param opts
- */
-export function* colorsFromTheme(
- parts: (ColorThemePart | ColorThemePartTuple)[],
- opts: Partial = {}
-) {
- let { num, variance } = { ...DEFAULT_OPTS, ...opts };
- const theme = parts.map(asThemePart);
- const choice = weightedRandom(
- theme,
- theme.map((x) => x.weight!)
- );
- while (--num! >= 0) {
- const spec = choice();
- if (spec.range) {
- yield colorFromRange(
- spec.range,
- spec.base,
- opts
- );
- } else if (spec.base) {
- yield analogHSV([], spec.base, variance!);
- }
- }
-}
diff --git a/packages/color/src/color.ts b/packages/color/src/color.ts
new file mode 100644
index 0000000000..55af530b0f
--- /dev/null
+++ b/packages/color/src/color.ts
@@ -0,0 +1,69 @@
+import { isString } from "@thi.ng/checks";
+import type {
+ Color,
+ ColorFactory,
+ ColorMode,
+ ParsedColor,
+ TypedColor,
+} from "./api";
+import { hcy } from "./hcy/hcy";
+import { hsi } from "./hsi/hsi";
+import { hsl } from "./hsl/hsl";
+import { hsv } from "./hsv/hsv";
+import { argb32, abgr32 } from "./int/int";
+import { labD50 } from "./lab/lab50";
+import { labD65 } from "./lab/lab65";
+import { lch } from "./lch/lch";
+import { oklab } from "./oklab/oklab";
+import { rgb } from "./rgb/rgb";
+import { srgb } from "./srgb/srgb";
+import { xyy } from "./xyy/xyy";
+import { xyzD50 } from "./xyz/xyz50";
+import { xyzD65 } from "./xyz/xyz65";
+import { ycc } from "./ycc/ycc";
+
+const FACTORIES: Record> = {
+ argb32,
+ abgr32,
+ hcy,
+ hsi,
+ hsl,
+ hsv,
+ lab50: labD50,
+ lab65: labD65,
+ lch,
+ oklab,
+ rgb,
+ srgb,
+ xyy,
+ xyz50: xyzD50,
+ xyz65: xyzD65,
+ ycc,
+};
+
+export function color(
+ src: ParsedColor,
+ buf?: Color,
+ idx?: number,
+ stride?: number
+): TypedColor;
+export function color(
+ mode: ColorMode,
+ buf: Color,
+ idx?: number,
+ stride?: number
+): TypedColor;
+export function color(
+ src: any,
+ buf?: any,
+ idx?: number,
+ stride?: number
+): TypedColor {
+ if (isString(src)) return FACTORIES[src](buf, idx, stride);
+ if (buf) {
+ const res = FACTORIES[(src).mode](buf, idx, stride);
+ res.set(src.deref());
+ return res;
+ }
+ return FACTORIES[(src).mode](src.deref());
+}
diff --git a/packages/color/src/constants.ts b/packages/color/src/constants.ts
deleted file mode 100644
index bf114b6e08..0000000000
--- a/packages/color/src/constants.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import { float, percent } from "@thi.ng/strings";
-
-// RGBA constants
-
-export const BLACK = Object.freeze([0, 0, 0, 1]);
-export const WHITE = Object.freeze([1, 1, 1, 1]);
-
-export const RED = Object.freeze([1, 0, 0, 1]);
-export const GREEN = Object.freeze([0, 1, 0, 1]);
-export const BLUE = Object.freeze([0, 0, 1, 1]);
-
-export const CYAN = Object.freeze([0, 1, 1, 1]);
-export const MAGENTA = Object.freeze([1, 0, 1, 1]);
-export const YELLOW = Object.freeze([1, 1, 0, 1]);
-
-export const RGB_LUMINANCE = [0.299, 0.587, 0.114];
-
-// Hue names
-
-export enum Hue {
- RED,
- ORANGE,
- YELLOW,
- CHARTREUSE,
- GREEN,
- SPRING_GREEN,
- CYAN,
- AZURE,
- BLUE,
- VIOLET,
- MAGENTA,
- ROSE,
-}
-
-// internal helpers
-
-export const SRGB_ALPHA = 0.055;
-
-export const RGB_XYZ = [
- 0.4124564,
- 0.3575761,
- 0.1804375,
- 0.2126729,
- 0.7151522,
- 0.072175,
- 0.0193339,
- 0.119192,
- 0.9503041,
-];
-
-export const XYZ_RGB = [
- 3.2404542,
- -1.5371385,
- -0.4985314,
- -0.969266,
- 1.8760108,
- 0.041556,
- 0.0556434,
- -0.2040259,
- 1.0572252,
-];
-
-export const FF = float(2);
-export const PC = percent(2);
-export const INV8BIT = 1 / 0xff;
diff --git a/packages/color/src/convert.ts b/packages/color/src/convert.ts
index 9abd2648d7..ef40d8be80 100644
--- a/packages/color/src/convert.ts
+++ b/packages/color/src/convert.ts
@@ -1,242 +1,55 @@
-import type { Implementation2O, MultiFn2O } from "@thi.ng/defmulti";
-import { DEFAULT, defmulti } from "@thi.ng/defmulti";
-import { illegalArgs } from "@thi.ng/errors";
+import { assert } from "@thi.ng/api";
+import { isArray } from "@thi.ng/checks";
+import { unsupported } from "@thi.ng/errors";
import type {
Color,
- ColorConversion,
ColorMode,
- IColor,
+ ColorSpec,
+ Conversions,
ReadonlyColor,
} from "./api";
-import { hcyaRgba } from "./hcya-rgba";
-import { hsiaRgba } from "./hsia-rgba";
-import { hslaCss } from "./hsla-css";
-import { hslaHsva } from "./hsla-hsva";
-import { hslaRgba } from "./hsla-rgba";
-import { hsvaCss } from "./hsva-css";
-import { hsvaHsla } from "./hsva-hsla";
-import { hsvaRgba } from "./hsva-rgba";
-import { int32Css } from "./int-css";
-import { int32Rgba } from "./int-rgba";
-import { parseCss } from "./parse-css";
-import { rgbaCss } from "./rgba-css";
-import { rgbaHcya } from "./rgba-hcya";
-import { rgbaHsia } from "./rgba-hsia";
-import { rgbaHsla } from "./rgba-hsla";
-import { rgbaHsva } from "./rgba-hsva";
-import { rgbaInt } from "./rgba-int";
-import { rgbaXyza } from "./rgba-xyza";
-import { rgbaYcbcra } from "./rgba-ycbcra";
-import { xyzaRgba } from "./xyza-rgba";
-import { ycbcraRgba } from "./ycbcra-rgba";
-export const convert: MultiFn2O<
- string | number | ReadonlyColor | IColor,
- ColorMode,
- ColorMode,
- Color | string | number
-> = defmulti((col: any, mdest, msrc) =>
- col.mode !== undefined
- ? `${mdest}-${col.mode}`
- : msrc !== undefined
- ? `${mdest}-${msrc}`
- : illegalArgs(`missing src color mode`)
-);
-convert.add(DEFAULT, (col: any, mdest, msrc) =>
- (col.mode !== undefined && col.mode === mdest) || mdest === msrc
- ? col
- : illegalArgs(`missing conversion for mode ${msrc} -> ${mdest}`)
-);
-
-export function asCSS(col: IColor): string;
-export function asCSS(
- col: string | number | ReadonlyColor,
- mode: ColorMode
-): string;
-export function asCSS(col: any, mode?: ColorMode) {
- return convert(col, "css", mode);
-}
-
-export function asRGBA(col: IColor): Color;
-export function asRGBA(
- col: string | number | ReadonlyColor,
- mode: ColorMode
-): Color;
-export function asRGBA(col: any, mode?: ColorMode) {
- return convert(col, "rgb", mode);
-}
-
-export function asHCYA(col: IColor): Color;
-export function asHCYA(
- col: string | number | ReadonlyColor,
- mode: ColorMode
-): Color;
-export function asHCYA(col: any, mode?: ColorMode) {
- return convert(col, "hcy", mode);
-}
-
-export function asHSIA(col: IColor): Color;
-export function asHSIA(
- col: string | number | ReadonlyColor,
- mode: ColorMode
-): Color;
-export function asHSIA(col: any, mode?: ColorMode) {
- return convert(col, "hsi", mode);
-}
-
-export function asHSLA(col: IColor): Color;
-export function asHSLA(
- col: string | number | ReadonlyColor,
- mode: ColorMode
-): Color;
-export function asHSLA(col: any, mode?: ColorMode) {
- return convert(col, "hsl", mode);
-}
-
-export function asHSVA(col: IColor): Color;
-export function asHSVA(
- col: string | number | ReadonlyColor,
- mode: ColorMode
-): Color;
-export function asHSVA(col: any, mode?: ColorMode) {
- return convert(col, "hsv", mode);
-}
-
-export function asXYZA(col: IColor): Color;
-export function asXYZA(
- col: string | number | ReadonlyColor,
- mode: ColorMode
-): Color;
-export function asXYZA(col: any, mode?: ColorMode) {
- return convert(col, "xyz", mode);
-}
-
-export function asYCbCrA(col: IColor): Color;
-export function asYCbCrA(
- col: string | number | ReadonlyColor,
- mode: ColorMode
-): Color;
-export function asYCbCrA(col: any, mode?: ColorMode) {
- return convert(col, "ycbcr", mode);
-}
-
-const defConversion = (
- dest: ColorMode,
- src: ColorMode,
- impl: Implementation2O<
- string | number | ReadonlyColor | IColor,
- ColorMode,
- ColorMode,
- Color | string | number
- >
-) => convert.add(`${dest}-${src}`, impl);
-
-const defConversions = (
- src: ColorMode,
- toRGBA: ColorConversion,
- ...dest: ColorMode[]
+export const CONVERSIONS: Partial> = {};
+
+/**
+ * Registers conversions for given {@link ColorSpec}. Called by
+ * {@link defColor}.
+ *
+ * @param spec
+ *
+ * @internal
+ */
+export const defConversions = (
+ mode: ColorMode,
+ spec: ColorSpec["from"]
) => {
- defConversion("rgb", src, (x: any) => toRGBA([], x));
- dest.forEach((id) =>
- defConversion(id, src, (x: any) => convert(toRGBA([], x), id, "rgb"))
- );
+ for (let id in spec) {
+ const val = spec[id];
+ if (isArray(val)) {
+ const [a, b, c, d] = val;
+ spec[id] =
+ val.length === 2
+ ? (out, src) => b(out, a(out, src))
+ : val.length === 3
+ ? (out, src) => c!(out, b(out, a(out, src)))
+ : (out, src) => d!(out, c!(out, b(out, a(out, src))));
+ }
+ }
+ CONVERSIONS[mode] = spec;
};
-// CSS
-
-defConversion("rgb", "css", (x: any) => parseCss(x));
-
-([
- "hcy",
- "hsi",
- "hsl",
- "hsv",
- "int",
- "xyz",
- "ycbcr",
-]).forEach((id) =>
- defConversion(id, "css", (x: any) => convert(parseCss(x), id, "rgb"))
-);
-
-// Int
-
-defConversions("int", int32Rgba, "hcy", "hsi", "hsl", "hsv", "xyz", "ycbcr");
-
-defConversion("css", "int", (x: any) => int32Css(x));
-
-// HCYA
-
-defConversions("hcy", hcyaRgba, "css", "int", "hsl", "hsv", "xyz", "ycbcr");
-
-// HSIA
-
-defConversions(
- "hsi",
- hsiaRgba,
- "css",
- "int",
- "hcy",
- "hsl",
- "hsv",
- "xyz",
- "ycbcr"
-);
-
-// HSLA
-
-defConversions("hsl", hslaRgba, "hcy", "hsi", "int", "xyz", "ycbcr");
-
-defConversion("css", "hsl", (x: any) => hslaCss(x));
-
-defConversion("hsv", "hsl", (x: any) => hslaHsva([], x));
-
-// HSVA
-
-defConversions("hsv", hsvaRgba, "hcy", "hsi", "int", "xyz", "ycbcr");
-
-defConversion("css", "hsv", (x: any) => hsvaCss(x));
-
-defConversion("hsl", "hsv", (x: any) => hsvaHsla([], x));
-
-// RGBA
-
-(<[ColorMode, ColorConversion][]>[
- ["hcy", rgbaHcya],
- ["hsi", rgbaHsia],
- ["hsl", rgbaHsla],
- ["hsv", rgbaHsva],
- ["xyz", rgbaXyza],
- ["ycbcr", rgbaYcbcra],
-]).forEach(([id, fn]) => defConversion(id, "rgb", (x: any) => fn([], x)));
-
-defConversion("css", "rgb", (x: any) => rgbaCss(x));
-
-defConversion("int", "rgb", (x: any) => rgbaInt(x));
-
-// XYZA
-
-defConversions(
- "xyz",
- xyzaRgba,
- "css",
- "hcy",
- "hsi",
- "hsl",
- "hsv",
- "int",
- "ycbcr"
-);
-
-// YCbCr
-
-defConversions(
- "ycbcr",
- ycbcraRgba,
- "css",
- "hcy",
- "hsi",
- "hsl",
- "hsv",
- "int",
- "xyz"
-);
+export const convert = (
+ res: T | null,
+ src: ReadonlyColor,
+ destMode: ColorMode,
+ srcMode: ColorMode
+): T => {
+ const spec = CONVERSIONS[destMode];
+ assert(!!spec, `no conversions available for ${destMode}`);
+ let $convert = spec![srcMode];
+ return $convert
+ ? $convert(res, src)
+ : CONVERSIONS.rgb![srcMode]
+ ? spec!.rgb(res, CONVERSIONS.rgb![srcMode]!([], src))
+ : unsupported(`can't convert: ${srcMode} -> ${destMode}`);
+};
diff --git a/packages/color/src/css.ts b/packages/color/src/css.ts
deleted file mode 100644
index 6ff35db131..0000000000
--- a/packages/color/src/css.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import type { ICopy, IDeref } from "@thi.ng/api";
-import type { ColorMode, IColor } from "./api";
-
-export const css = (col: string) => new CSS(col);
-
-export class CSS implements IColor, ICopy, IDeref {
- value: string;
-
- constructor(col: string) {
- this.value = col;
- }
-
- get mode() {
- return "css";
- }
-
- copy() {
- return new CSS(this.value);
- }
-
- deref() {
- return this.value;
- }
-}
diff --git a/packages/color/src/css/css.ts b/packages/color/src/css/css.ts
new file mode 100644
index 0000000000..3b0baa25a4
--- /dev/null
+++ b/packages/color/src/css/css.ts
@@ -0,0 +1,57 @@
+import type { Fn } from "@thi.ng/api";
+import { isNumber, isString } from "@thi.ng/checks";
+import type { ColorMode, IParsedColor, MaybeColor, TypedColor } from "../api";
+import { convert } from "../convert";
+import { hslCss } from "../hsl/hsl-css";
+import { hsvCss } from "../hsv/hsv-css";
+import { intArgb32Css } from "../int/int-css";
+import { intAbgr32Argb32 } from "../int/int-int";
+import { lchLab } from "../lab/lab-lch";
+import { labRgb, labRgbD65 } from "../lab/lab-rgb";
+import { rgbCss } from "../rgb/rgb-css";
+import { rgbSrgb } from "../rgb/rgb-srgb";
+import { srgbCss } from "../srgb/srgb-css";
+
+/** @internal */
+const CSS_CONVERSIONS: Partial>> = {
+ abgr32: (x) => intArgb32Css(intAbgr32Argb32(x[0])),
+ argb32: (x) => intArgb32Css(x[0]),
+ hsl: hslCss,
+ hsv: hsvCss,
+ // TODO temporarily disabled until CSS L4 is officially supported in browsers
+ // currently serializing as sRGB CSS
+ // lab50: labCss,
+ // lab65: (x) => labCss(labLabD65_50([], x)),
+ // lch: lchCss,
+ lab50: (src) => srgbCss(rgbSrgb(null, labRgb([], src))),
+ lab65: (src) => srgbCss(rgbSrgb(null, labRgbD65([], src))),
+ lch: (src) => srgbCss(rgbSrgb(null, labRgb(null, lchLab([], src)))),
+ rgb: rgbCss,
+ srgb: srgbCss,
+};
+
+/**
+ * Takes a color in one of the following formats and tries to convert it
+ * to a CSS string:
+ *
+ * - any {@link TypedColor} instance
+ * - raw sRGB(A) vector
+ * - number (packed 0xaarrggbb int, MUST provide alpha channel)
+ * - string (passthrough)
+ *
+ * @param col - source color
+ */
+export const css = (src: Exclude) => {
+ let asCss: Fn | undefined;
+ return isString(src)
+ ? src
+ : isNumber(src)
+ ? intArgb32Css(src)
+ : (>src).mode
+ ? (asCss = CSS_CONVERSIONS[(>src).mode])
+ ? asCss(src)
+ : CSS_CONVERSIONS.rgb!(
+ convert([], src, "rgb", (>src).mode)
+ )
+ : srgbCss(src);
+};
diff --git a/packages/color/src/css/parse-css.ts b/packages/color/src/css/parse-css.ts
new file mode 100644
index 0000000000..11e513e0ab
--- /dev/null
+++ b/packages/color/src/css/parse-css.ts
@@ -0,0 +1,149 @@
+import type { IDeref } from "@thi.ng/api";
+import { assert } from "@thi.ng/api";
+import { interleave4_12_24, interleave4_16_32 } from "@thi.ng/binary";
+import { isString } from "@thi.ng/checks";
+import { illegalArgs, unsupported } from "@thi.ng/errors";
+import { clamp01, fract, TAU } from "@thi.ng/math";
+import { IParsedColor, ParsedColor } from "../api";
+import { CSS_NAMES } from "../api/names";
+import { CSS_SYSTEM_COLORS } from "../api/system";
+import { intArgb32Srgb } from "../int/int-srgb";
+
+/**
+ * Attempts to parse given CSS color into an interim {@link ParsedColor} type
+ * with {@link srgb}, {@link hsl}, {@link labD50} or {@link lch} color modes.
+ * Throws an error if any of the validations during parsing failed.
+ *
+ * @remarks
+ * The following syntax versions are supported:
+ *
+ * - CSS named colors
+ * - CSS system colors @see {@link CSS_SYSTEM_COLORS}
+ * - hex3/4/6/8
+ * - `rgb(r% g% b% / a%?)`
+ * - `rgb(r g b / a?)`
+ * - `rgb(r,g,b)`
+ * - `rgba(r,g,b,a)`
+ * - `hsl(h s% l% / a%?)`
+ * - `hsl(h,s%,l%)`
+ * - `hsla(h,s%,l%,a)`
+ * - `lab(l a b / alpha?)`
+ * - `lch(l c h / alpha?)`
+ *
+ * Hue values can be given according to CSS Color L4 spec (raw, deg, rad, grad,
+ * turn): https://www.w3.org/TR/css-color-4/#typedef-hue
+ *
+ * If no alpha channel is given, it will default to 1.0 (fully opaque).
+ *
+ * Note that any named or system CSS colors, hex colors and any RGB colors will
+ * be returned as sRGB instance. In former versions of this library (pre 3.0.0),
+ * there was only a single RGB type with undefined behaviour re: linear or
+ * gamma-encoded versions. Since v3.0.0, {@link rgb} is only used for _linear_
+ * and {@link srgb} for non-linear (gamma encoded) RGB colors (CSS uses sRGB by
+ * default).
+ *
+ * @param src
+ */
+export const parseCss = (src: string | IDeref): IParsedColor => {
+ src = (isString(src) ? src : src.deref()).toLowerCase();
+ const named = (CSS_NAMES)[src] || (CSS_SYSTEM_COLORS)[src];
+ if (named || src[0] === "#")
+ return new ParsedColor(
+ "srgb",
+ intArgb32Srgb([], parseHex(named || src))
+ );
+ const parts = src.split(/[(),/ ]+/);
+ const [mode, a, b, c, d] = parts;
+ assert(
+ parts.length === 5 || parts.length === 6,
+ `invalid ${mode} color: ${src}`
+ );
+ switch (mode) {
+ case "rgb":
+ case "rgba":
+ return new ParsedColor("srgb", [
+ parseNumOrPercent(a),
+ parseNumOrPercent(b),
+ parseNumOrPercent(c),
+ parseAlpha(d),
+ ]);
+ case "hsl":
+ case "hsla":
+ return new ParsedColor("hsl", [
+ parseHue(a),
+ parsePercent(b),
+ parsePercent(c),
+ parseAlpha(d),
+ ]);
+ case "lab":
+ return new ParsedColor("lab50", [
+ parsePercent(a, false),
+ parseNumber(b) * 0.01,
+ parseNumber(c) * 0.01,
+ parseAlpha(d),
+ ]);
+ case "lch":
+ return new ParsedColor("lch", [
+ parsePercent(a, false),
+ parseNumber(b) * 0.01,
+ parseHue(c),
+ parseAlpha(d),
+ ]);
+ default:
+ unsupported(`color mode: ${mode}`);
+ }
+};
+
+const HUE_NORMS: Record = {
+ rad: TAU,
+ grad: 400,
+ turn: 1,
+ deg: 360,
+ undefined: 360,
+};
+
+const parseHue = (x: string) => {
+ const match = /^(-?[0-9.]+)(deg|rad|grad|turn)?$/.exec(x);
+ assert(!!match, `expected hue, got: ${x}`);
+ return fract(parseFloat(match![1]) / HUE_NORMS[match![2]]);
+};
+
+const parseAlpha = (x?: string) => (x ? parseNumOrPercent(x, 1) : 1);
+
+const parsePercent = (x: string, clamp = true) => {
+ assert(/^([0-9.]+)%$/.test(x), `expected percentage, got: ${x}`);
+ const res = parseFloat(x) / 100;
+ return clamp ? clamp01(res) : res;
+};
+
+const parseNumber = (x: string) => {
+ assert(/^-?[0-9.]+$/.test(x), `expected number, got: ${x}`);
+ return parseFloat(x);
+};
+
+const parseNumOrPercent = (x: string, norm = 255, clamp = true) => {
+ assert(/^-?[0-9.]+%?$/.test(x), `expected number or percentage, got: ${x}`);
+ const res = parseFloat(x) / (x.endsWith("%") ? 100 : norm);
+ return clamp ? clamp01(res) : res;
+};
+
+export const parseHex = (src: string): number => {
+ const match = /^#?([0-9a-f]{3,8})$/i.exec(src);
+ if (match) {
+ const hex = match[1];
+ switch (hex.length) {
+ case 3:
+ return (
+ (interleave4_12_24(parseInt(hex, 16)) | 0xff000000) >>> 0
+ );
+ case 4:
+ return interleave4_16_32(parseInt(hex, 16)) >>> 0;
+ case 6:
+ return (parseInt(hex, 16) | 0xff000000) >>> 0;
+ case 8:
+ return parseInt(hex, 16) >>> 0;
+ default:
+ }
+ }
+ return illegalArgs(`invalid hex color: "${src}"`);
+};
diff --git a/packages/color/src/defcolor.ts b/packages/color/src/defcolor.ts
new file mode 100644
index 0000000000..bcf198f6dd
--- /dev/null
+++ b/packages/color/src/defcolor.ts
@@ -0,0 +1,183 @@
+import type { IDeref, NumericArray } from "@thi.ng/api";
+import {
+ implementsFunction,
+ isArrayLike,
+ isNumber,
+ isString,
+} from "@thi.ng/checks";
+import { illegalArgs } from "@thi.ng/errors";
+import { EPS } from "@thi.ng/math";
+import type { IRandom } from "@thi.ng/random";
+import {
+ clamp4,
+ declareIndices,
+ eqDelta4,
+ mapStridedBuffer,
+ randMinMax,
+ set4,
+ stridedValues,
+} from "@thi.ng/vectors";
+import type {
+ ChannelSpec,
+ ColorFactory,
+ ColorMode,
+ ColorSpec,
+ IColor,
+ MaybeColor,
+ ReadonlyColor,
+ TypedColor,
+} from "./api";
+import { convert, defConversions } from "./convert";
+import { parseCss } from "./css/parse-css";
+import { intArgb32Rgb } from "./int/int-rgb";
+import { ensureArgs } from "./internal/ensure-args";
+
+type $DefColor = {
+ [k in K]: number;
+} & {
+ readonly mode: M;
+ random(rnd?: IRandom): $DefColor;
+ set(src: ReadonlyColor): $DefColor;
+ toJSON(): number[];
+} & TypedColor<$DefColor>;
+
+export const defColor = (
+ spec: ColorSpec
+) => {
+ const channels: Partial> = spec.channels || {};
+ const order = spec.order;
+ const numChannels = order.length;
+ order.reduce((acc, id) => {
+ acc[id] = {
+ range: [0, 1],
+ ...channels[id],
+ };
+ return acc;
+ }, channels);
+ const min = order.map((id) => channels[id]!.range![0]);
+ const max = order.map((id) => channels[id]!.range![1]);
+ // fix alpha channel for randomize()
+ const minR = set4([], min);
+ const maxR = set4([], max);
+ minR[numChannels - 1] = 1;
+
+ const $Color = class implements TypedColor<$DefColor> {
+ buf: NumericArray;
+ [id: number]: number;
+
+ constructor(buf?: NumericArray, public offset = 0, public stride = 1) {
+ this.buf = buf || [0, 0, 0, 0];
+ this.offset = offset;
+ this.stride = stride;
+ }
+
+ get mode() {
+ return spec.mode;
+ }
+
+ get length() {
+ return numChannels;
+ }
+
+ get range(): [ReadonlyColor, ReadonlyColor] {
+ return [min, max];
+ }
+
+ get [Symbol.toStringTag]() {
+ return spec.mode;
+ }
+
+ [Symbol.iterator]() {
+ return stridedValues(
+ this.buf,
+ this.length,
+ this.offset,
+ this.stride
+ );
+ }
+
+ copy(): $DefColor {
+ return new $Color(this.deref());
+ }
+
+ copyView(): $DefColor {
+ return new $Color(this.buf, this.offset, this.stride);
+ }
+
+ empty(): $DefColor {
+ return new $Color();
+ }
+
+ deref() {
+ return [this[0], this[1], this[2], this[3]];
+ }
+
+ set(src: ReadonlyColor) {
+ return set4(this, src);
+ }
+
+ clamp() {
+ return clamp4(null, this, min, max);
+ }
+
+ eqDelta(o: $DefColor, eps = EPS): boolean {
+ return eqDelta4(this, o, eps);
+ }
+
+ toJSON() {
+ return this.deref();
+ }
+
+ randomize(rnd?: IRandom): this {
+ return randMinMax(this, minR, maxR, rnd);
+ }
+ };
+
+ declareIndices($Color.prototype, order);
+ defConversions(spec.mode, spec.from);
+
+ const fromColor = (src: ReadonlyColor, mode: ColorMode, xs: any[]): any => {
+ const res = new $Color(...xs);
+ return mode !== spec.mode
+ ? convert(res, src, spec.mode, mode)
+ : res.set(src);
+ };
+
+ const factory = (src?: MaybeColor, ...xs: any[]): $DefColor =>
+ src == null
+ ? new $Color()
+ : isString(src)
+ ? factory(parseCss(src), ...xs)
+ : isArrayLike(src)
+ ? isString((src).mode)
+ ? fromColor(src, (src).mode, xs)
+ : new $Color(src, ...xs)
+ : implementsFunction(src, "deref")
+ ? fromColor((>src).deref(), (src).mode, xs)
+ : isNumber(src)
+ ? xs.length && xs.every(isNumber)
+ ? new $Color(...ensureArgs([src, ...xs]))
+ : fromColor(intArgb32Rgb([], src), "rgb", xs)
+ : illegalArgs(`can't create a ${spec.mode} color from: ${src}`);
+
+ factory.class = $Color;
+
+ factory.range = <[ReadonlyColor, ReadonlyColor]>[min, max];
+
+ factory.random = (
+ rnd?: IRandom,
+ buf?: NumericArray,
+ idx?: number,
+ stride?: number
+ ) => new $Color(buf, idx, stride).randomize(rnd);
+
+ factory.mapBuffer = (
+ buf: NumericArray,
+ num = (buf.length / numChannels) | 0,
+ start = 0,
+ cstride = 1,
+ estride = numChannels
+ ) => mapStridedBuffer($Color, buf, num, start, cstride, estride);
+
+ return >>factory;
+};
diff --git a/packages/color/src/distance.ts b/packages/color/src/distance.ts
deleted file mode 100644
index eee9e96c37..0000000000
--- a/packages/color/src/distance.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import { cossin, TAU } from "@thi.ng/math";
-import type { ColorDistance } from "./api";
-import { luminanceRGB } from "./luminance-rgb";
-
-/**
- * Computes distance between two HSV colors, i.e. the eucledian distance between
- * points in a cyclinder.
- *
- * @param a
- * @param b
- */
-export const distHSV: ColorDistance = (a, b) => {
- const aa = cossin(a[0] * TAU, a[1]);
- const bb = cossin(b[0] * TAU, b[1]);
- return Math.hypot(aa[0] - bb[0], aa[1] - bb[1], a[2] - b[2]);
-};
-
-/**
- * Computes difference in saturation between two HSV colors.
- *
- * @param a
- * @param b
- */
-export const distSatHSV: ColorDistance = (a, b) => Math.abs(a[1] - b[1]);
-
-/**
- * Computes difference in brightness between two HSV or two HSL colors.
- *
- * @param a
- * @param b
- */
-export const distLumaHSV: ColorDistance = (a, b) => Math.abs(a[2] - b[2]);
-
-/**
- * Computes eucledian distance between two RGB colors.
- *
- * @param a
- * @param b
- */
-export const distRGB: ColorDistance = (a, b) =>
- Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);
-
-/**
- * Computes difference in luminance between two RGB colors.
- *
- * @param a
- * @param b
- */
-export const distLumaRGB: ColorDistance = (a, b) =>
- Math.abs(luminanceRGB(a) - luminanceRGB(b));
diff --git a/packages/color/src/hcya-rgba.ts b/packages/color/src/hcy/hcy-rgb.ts
similarity index 50%
rename from packages/color/src/hcya-rgba.ts
rename to packages/color/src/hcy/hcy-rgb.ts
index 17d39287cf..3158cd4af6 100644
--- a/packages/color/src/hcya-rgba.ts
+++ b/packages/color/src/hcy/hcy-rgb.ts
@@ -1,16 +1,16 @@
import { clamp01 } from "@thi.ng/math";
-import { dot3, setC3 } from "@thi.ng/vectors";
-import type { ColorOp } from "./api";
-import { RGB_LUMINANCE } from "./constants";
-import { hueRgba } from "./hue-rgba";
-import { ensureAlpha } from "./internal/ensure-alpha";
+import { setC3 } from "@thi.ng/vectors";
+import type { ColorOp } from "../api";
+import { hueRgb } from "../rgb/hue-rgb";
+import { ensureAlpha } from "../internal/ensure-alpha";
+import { luminanceRgb } from "../ops/luminance-rgb";
-export const hcyaRgba: ColorOp = (out, src) => {
+export const hcyRgb: ColorOp = (out, src) => {
const h = src[0];
let c = src[1];
const y = src[2];
- const rgb = hueRgba(out || src, h, ensureAlpha(src[3]));
- const lum = dot3(rgb, RGB_LUMINANCE);
+ const rgb = hueRgb(out || src, h, ensureAlpha(src[3]));
+ const lum = luminanceRgb(rgb);
if (y < lum) {
c *= y / lum;
} else if (lum < 1) {
diff --git a/packages/color/src/hcy/hcy.ts b/packages/color/src/hcy/hcy.ts
new file mode 100644
index 0000000000..d057e39760
--- /dev/null
+++ b/packages/color/src/hcy/hcy.ts
@@ -0,0 +1,35 @@
+import type { NumericArray } from "@thi.ng/api";
+import type { IRandom } from "@thi.ng/random";
+import type { Color, ColorFactory, ReadonlyColor, TypedColor } from "../api";
+import { defColor } from "../defcolor";
+import { rgbHcy } from "../rgb/rgb-hcy";
+
+export declare class HCY implements TypedColor {
+ buf: NumericArray;
+ offset: number;
+ stride: number;
+ h: number;
+ c: number;
+ y: number;
+ alpha: number;
+ [id: number]: number;
+ readonly mode: "hcy";
+ readonly length: 4;
+ readonly range: [ReadonlyColor, ReadonlyColor];
+ [Symbol.iterator](): Iterator;
+ clamp(): this;
+ copy(): HCY;
+ copyView(): HCY;
+ deref(): Color;
+ empty(): HCY;
+ eqDelta(o: HCY, eps?: number): boolean;
+ randomize(rnd?: IRandom): this;
+ set(src: ReadonlyColor): this;
+ toJSON(): number[];
+}
+
+export const hcy = >defColor({
+ mode: "hcy",
+ order: ["h", "c", "y", "alpha"],
+ from: { rgb: rgbHcy, srgb: rgbHcy },
+});
diff --git a/packages/color/src/hcya.ts b/packages/color/src/hcya.ts
deleted file mode 100644
index 30c899503e..0000000000
--- a/packages/color/src/hcya.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { declareIndices, IVector } from "@thi.ng/vectors";
-import type { Color, ColorMode } from "./api";
-import { AColor } from "./internal/acolor";
-import { ensureArgs } from "./internal/ensure-args";
-
-export function hcya(col: Color, offset?: number, stride?: number): HCYA;
-export function hcya(h?: number, c?: number, y?: number, a?: number): HCYA;
-export function hcya(...args: any[]) {
- return new HCYA(...ensureArgs(args));
-}
-
-export class HCYA extends AColor implements IVector {
- h!: number;
- c!: number;
- y!: number;
- a!: number;
-
- get mode() {
- return "hcy";
- }
-
- copy() {
- return new HCYA(this.deref());
- }
-
- copyView() {
- return new HCYA(this.buf, this.offset, this.stride);
- }
-
- empty() {
- return new HCYA();
- }
-}
-
-declareIndices(HCYA.prototype, ["h", "c", "y", "a"]);
diff --git a/packages/color/src/hsia-rgba.ts b/packages/color/src/hsi/hsi-rgb.ts
similarity index 86%
rename from packages/color/src/hsia-rgba.ts
rename to packages/color/src/hsi/hsi-rgb.ts
index 036801a8de..3c3cd6b009 100644
--- a/packages/color/src/hsia-rgba.ts
+++ b/packages/color/src/hsi/hsi-rgb.ts
@@ -1,10 +1,10 @@
import { setC3 } from "@thi.ng/vectors";
-import type { ColorOp } from "./api";
-import { clampH } from "./clamp";
+import type { ColorOp } from "../api";
+import { clampH } from "../ops/clamp";
// https://en.wikipedia.org/wiki/HSL_and_HSV#From_HSI
-export const hsiaRgba: ColorOp = (out, src) => {
+export const hsiRgb: ColorOp = (out, src) => {
out = clampH(out || src, src);
const s = out[1];
const i = out[2];
diff --git a/packages/color/src/hsi/hsi.ts b/packages/color/src/hsi/hsi.ts
new file mode 100644
index 0000000000..e321d75c9b
--- /dev/null
+++ b/packages/color/src/hsi/hsi.ts
@@ -0,0 +1,35 @@
+import type { NumericArray } from "@thi.ng/api";
+import type { IRandom } from "@thi.ng/random";
+import type { Color, ColorFactory, ReadonlyColor, TypedColor } from "../api";
+import { defColor } from "../defcolor";
+import { rgbHsi } from "../rgb/rgb-hsi";
+
+export declare class HSI implements TypedColor {
+ buf: NumericArray;
+ offset: number;
+ stride: number;
+ h: number;
+ s: number;
+ i: number;
+ alpha: number;
+ [id: number]: number;
+ readonly mode: "hsi";
+ readonly length: 4;
+ readonly range: [ReadonlyColor, ReadonlyColor];
+ [Symbol.iterator](): Iterator;
+ clamp(): this;
+ copy(): HSI;
+ copyView(): HSI;
+ deref(): Color;
+ empty(): HSI;
+ eqDelta(o: HSI, eps?: number): boolean;
+ randomize(rnd?: IRandom): this;
+ set(src: ReadonlyColor): this;
+ toJSON(): number[];
+}
+
+export const hsi = >defColor({
+ mode: "hsi",
+ order: ["h", "s", "i", "alpha"],
+ from: { rgb: rgbHsi, srgb: rgbHsi },
+});
diff --git a/packages/color/src/hsia.ts b/packages/color/src/hsia.ts
deleted file mode 100644
index abfed2879e..0000000000
--- a/packages/color/src/hsia.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { declareIndices, IVector } from "@thi.ng/vectors";
-import type { Color, ColorMode } from "./api";
-import { AColor } from "./internal/acolor";
-import { ensureArgs } from "./internal/ensure-args";
-
-export function hsia(col: Color, offset?: number, stride?: number): HSIA;
-export function hsia(h?: number, s?: number, i?: number, a?: number): HSIA;
-export function hsia(...args: any[]) {
- return new HSIA(...ensureArgs(args));
-}
-
-export class HSIA extends AColor implements IVector {
- h!: number;
- s!: number;
- i!: number;
- a!: number;
-
- get mode() {
- return "hsi";
- }
-
- copy() {
- return new HSIA(this.deref());
- }
-
- copyView() {
- return new HSIA(this.buf, this.offset, this.stride);
- }
-
- empty() {
- return new HSIA();
- }
-}
-
-declareIndices(HSIA.prototype, ["h", "s", "i", "a"]);
diff --git a/packages/color/src/hsl/hsl-css.ts b/packages/color/src/hsl/hsl-css.ts
new file mode 100644
index 0000000000..22d4bafc68
--- /dev/null
+++ b/packages/color/src/hsl/hsl-css.ts
@@ -0,0 +1,16 @@
+import { clamp01, fract } from "@thi.ng/math";
+import type { ReadonlyColor } from "../api";
+import { FF, PC } from "../api/constants";
+import { ensureAlpha } from "../internal/ensure-alpha";
+
+export const hslCss = (src: ReadonlyColor) => {
+ const h = FF(fract(src[0]) * 360);
+ const s = PC(clamp01(src[1]));
+ const l = PC(clamp01(src[2]));
+ const a = ensureAlpha(src[3]);
+ // TODO update to new syntax once CSS Color L4 is more widely supported
+ // https://www.w3.org/TR/css-color-4/#serializing-lab-lch
+ // https://test.csswg.org/harness/results/css-color-4_dev/grouped/ (test reports)
+ // return `hsl(${h} ${s} ${l}` + (a < 1 ? `/${FF(a)})` : ")");
+ return a < 1 ? `hsla(${h},${s},${l},${FF(a)})` : `hsl(${h},${s},${l})`;
+};
diff --git a/packages/color/src/hsla-hsva.ts b/packages/color/src/hsl/hsl-hsv.ts
similarity index 64%
rename from packages/color/src/hsla-hsva.ts
rename to packages/color/src/hsl/hsl-hsv.ts
index 6137738e6b..06f03bcc3a 100644
--- a/packages/color/src/hsla-hsva.ts
+++ b/packages/color/src/hsl/hsl-hsv.ts
@@ -1,7 +1,7 @@
-import type { ColorOp } from "./api";
-import { clampH } from "./clamp";
+import type { ColorOp } from "../api";
+import { clampH } from "../ops/clamp";
-export const hslaHsva: ColorOp = (out, src) => {
+export const hslHsv: ColorOp = (out, src) => {
out = clampH(out || src, src);
const s = out[1];
const l = out[2];
diff --git a/packages/color/src/hsla-rgba.ts b/packages/color/src/hsl/hsl-rgb.ts
similarity index 57%
rename from packages/color/src/hsla-rgba.ts
rename to packages/color/src/hsl/hsl-rgb.ts
index b0b6f4f91b..51b0778e05 100644
--- a/packages/color/src/hsla-rgba.ts
+++ b/packages/color/src/hsl/hsl-rgb.ts
@@ -1,13 +1,13 @@
import { clamp01 } from "@thi.ng/math";
import { setC3 } from "@thi.ng/vectors";
-import type { ColorOp } from "./api";
-import { hueRgba } from "./hue-rgba";
-import { ensureAlpha } from "./internal/ensure-alpha";
+import type { ColorOp } from "../api";
+import { hueRgb } from "../rgb/hue-rgb";
+import { ensureAlpha } from "../internal/ensure-alpha";
-export const hslaRgba: ColorOp = (out, src) => {
+export const hslRgb: ColorOp = (out, src) => {
const s = clamp01(src[1]);
const l = clamp01(src[2]);
- out = hueRgba(out || src, src[0], ensureAlpha(src[3]));
+ out = hueRgb(out || src, src[0], ensureAlpha(src[3]));
const c = (1 - Math.abs(2 * l - 1)) * s;
return setC3(
out,
diff --git a/packages/color/src/hsl/hsl.ts b/packages/color/src/hsl/hsl.ts
new file mode 100644
index 0000000000..426ffa622a
--- /dev/null
+++ b/packages/color/src/hsl/hsl.ts
@@ -0,0 +1,36 @@
+import type { NumericArray } from "@thi.ng/api";
+import type { IRandom } from "@thi.ng/random";
+import type { Color, ColorFactory, ReadonlyColor, TypedColor } from "../api";
+import { defColor } from "../defcolor";
+import { hsvHsl } from "../hsv/hsv-hsl";
+import { rgbHsl } from "../rgb/rgb-hsl";
+
+export declare class HSL implements TypedColor {
+ buf: NumericArray;
+ offset: number;
+ stride: number;
+ h: number;
+ s: number;
+ l: number;
+ alpha: number;
+ [id: number]: number;
+ readonly mode: "hsl";
+ readonly length: 4;
+ readonly range: [ReadonlyColor, ReadonlyColor];
+ [Symbol.iterator](): Iterator;
+ clamp(): this;
+ copy(): HSL;
+ copyView(): HSL;
+ deref(): Color;
+ empty(): HSL;
+ eqDelta(o: HSL, eps?: number): boolean;
+ randomize(rnd?: IRandom): this;
+ set(src: ReadonlyColor): this;
+ toJSON(): number[];
+}
+
+export const hsl = >defColor({
+ mode: "hsl",
+ order: ["h", "s", "l", "alpha"],
+ from: { rgb: rgbHsl, srgb: rgbHsl, hsv: hsvHsl },
+});
diff --git a/packages/color/src/hsla-css.ts b/packages/color/src/hsla-css.ts
deleted file mode 100644
index 23e93f52d2..0000000000
--- a/packages/color/src/hsla-css.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { clamp01 } from "@thi.ng/math";
-import type { ReadonlyColor } from "./api";
-import { FF, PC } from "./constants";
-import { ensureAlpha } from "./internal/ensure-alpha";
-import { ensureHue } from "./internal/ensure-hue";
-
-export const hslaCss = (src: ReadonlyColor) => {
- const h = FF(ensureHue(src[0]) * 360);
- const s = PC(clamp01(src[1]));
- const l = PC(clamp01(src[2]));
- const a = ensureAlpha(src[3]);
- return a < 1 ? `hsla(${h},${s},${l},${FF(a)})` : `hsl(${h},${s},${l})`;
-};
diff --git a/packages/color/src/hsla.ts b/packages/color/src/hsla.ts
deleted file mode 100644
index e49ad0dc4e..0000000000
--- a/packages/color/src/hsla.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { declareIndices, IVector } from "@thi.ng/vectors";
-import type { Color, ColorMode } from "./api";
-import { AColor } from "./internal/acolor";
-import { ensureArgs } from "./internal/ensure-args";
-
-export function hsla(col: Color, offset?: number, stride?: number): HSLA;
-export function hsla(h?: number, s?: number, l?: number, a?: number): HSLA;
-export function hsla(...args: any[]) {
- return new HSLA(...ensureArgs(args));
-}
-
-export class HSLA extends AColor implements IVector {
- h!: number;
- s!: number;
- l!: number;
- a!: number;
-
- get mode() {
- return "hsl";
- }
-
- copy() {
- return new HSLA(this.deref());
- }
-
- copyView() {
- return new HSLA(this.buf, this.offset, this.stride);
- }
-
- empty() {
- return new HSLA();
- }
-}
-
-declareIndices(HSLA.prototype, ["h", "s", "l", "a"]);
diff --git a/packages/color/src/hsv/hsv-css.ts b/packages/color/src/hsv/hsv-css.ts
new file mode 100644
index 0000000000..9aeb110fca
--- /dev/null
+++ b/packages/color/src/hsv/hsv-css.ts
@@ -0,0 +1,5 @@
+import type { ReadonlyColor } from "../api";
+import { hslCss } from "../hsl/hsl-css";
+import { hsvHsl } from "./hsv-hsl";
+
+export const hsvCss = (src: ReadonlyColor) => hslCss(hsvHsl([], src));
diff --git a/packages/color/src/hsva-hsla.ts b/packages/color/src/hsv/hsv-hsl.ts
similarity index 63%
rename from packages/color/src/hsva-hsla.ts
rename to packages/color/src/hsv/hsv-hsl.ts
index bbec94cb6e..23c61f1381 100644
--- a/packages/color/src/hsva-hsla.ts
+++ b/packages/color/src/hsv/hsv-hsl.ts
@@ -1,7 +1,7 @@
-import type { ColorOp } from "./api";
-import { clampH } from "./clamp";
+import type { ColorOp } from "../api";
+import { clampH } from "../ops/clamp";
-export const hsvaHsla: ColorOp = (out, src) => {
+export const hsvHsl: ColorOp = (out, src) => {
out = clampH(out || src, src);
const s = out[1];
const v = out[2];
diff --git a/packages/color/src/hsva-rgba.ts b/packages/color/src/hsv/hsv-rgb.ts
similarity index 57%
rename from packages/color/src/hsva-rgba.ts
rename to packages/color/src/hsv/hsv-rgb.ts
index 26056ad15d..5f3a196eb1 100644
--- a/packages/color/src/hsva-rgba.ts
+++ b/packages/color/src/hsv/hsv-rgb.ts
@@ -1,13 +1,13 @@
import { setC3 } from "@thi.ng/vectors";
-import type { ColorOp } from "./api";
-import { clampH } from "./clamp";
-import { hueRgba } from "./hue-rgba";
+import type { ColorOp } from "../api";
+import { clampH } from "../ops/clamp";
+import { hueRgb } from "../rgb/hue-rgb";
-export const hsvaRgba: ColorOp = (out, src) => {
+export const hsvRgb: ColorOp = (out, src) => {
out = clampH(out || src, src);
const s = out[1];
const v = out[2];
- hueRgba(out, src[0], out[3]);
+ hueRgb(out, src[0], out[3]);
return setC3(
out,
((out[0] - 1) * s + 1) * v,
diff --git a/packages/color/src/hsv/hsv.ts b/packages/color/src/hsv/hsv.ts
new file mode 100644
index 0000000000..fabcdccf79
--- /dev/null
+++ b/packages/color/src/hsv/hsv.ts
@@ -0,0 +1,36 @@
+import type { NumericArray } from "@thi.ng/api";
+import type { IRandom } from "@thi.ng/random";
+import type { Color, ColorFactory, ReadonlyColor, TypedColor } from "../api";
+import { defColor } from "../defcolor";
+import { hslHsv } from "../hsl/hsl-hsv";
+import { rgbHsv } from "../rgb/rgb-hsv";
+
+export declare class HSV implements TypedColor {
+ buf: NumericArray;
+ offset: number;
+ stride: number;
+ h: number;
+ s: number;
+ v: number;
+ alpha: number;
+ [id: number]: number;
+ readonly mode: "hsv";
+ readonly length: 4;
+ readonly range: [ReadonlyColor, ReadonlyColor];
+ [Symbol.iterator](): Iterator;
+ clamp(): this;
+ copy(): HSV;
+ copyView(): HSV;
+ deref(): Color;
+ empty(): HSV;
+ eqDelta(o: HSV, eps?: number): boolean;
+ randomize(rnd?: IRandom): this;
+ set(src: ReadonlyColor): this;
+ toJSON(): number[];
+}
+
+export const hsv = >defColor({
+ mode: "hsv",
+ order: ["h", "s", "v", "alpha"],
+ from: { rgb: rgbHsv, srgb: rgbHsv, hsl: hslHsv },
+});
diff --git a/packages/color/src/hsva-css.ts b/packages/color/src/hsva-css.ts
deleted file mode 100644
index 68d0f119f4..0000000000
--- a/packages/color/src/hsva-css.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import type { ReadonlyColor } from "./api";
-import { hslaCss } from "./hsla-css";
-import { hsvaHsla } from "./hsva-hsla";
-
-export const hsvaCss = (src: ReadonlyColor) => hslaCss(hsvaHsla([], src));
diff --git a/packages/color/src/hsva.ts b/packages/color/src/hsva.ts
deleted file mode 100644
index bb3807f542..0000000000
--- a/packages/color/src/hsva.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { declareIndices, IVector } from "@thi.ng/vectors";
-import type { Color, ColorMode } from "./api";
-import { AColor } from "./internal/acolor";
-import { ensureArgs } from "./internal/ensure-args";
-
-export function hsva(col: Color, offset?: number, stride?: number): HSVA;
-export function hsva(h?: number, s?: number, v?: number, a?: number): HSVA;
-export function hsva(...args: any[]) {
- return new HSVA(...ensureArgs(args));
-}
-
-export class HSVA extends AColor implements IVector {
- h!: number;
- s!: number;
- v!: number;
- a!: number;
-
- get mode() {
- return "hsv";
- }
-
- copy() {
- return new HSVA(this.deref());
- }
-
- copyView() {
- return new HSVA(this.buf, this.offset, this.stride);
- }
-
- empty() {
- return new HSVA();
- }
-}
-
-declareIndices(HSVA.prototype, ["h", "s", "v", "a"]);
diff --git a/packages/color/src/hue-rgba.ts b/packages/color/src/hue-rgba.ts
deleted file mode 100644
index 8e7d5f57eb..0000000000
--- a/packages/color/src/hue-rgba.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { clamp01 } from "@thi.ng/math";
-import { setC4 } from "@thi.ng/vectors";
-import type { Color } from "./api";
-import type { Hue } from "./constants";
-import { ensureHue } from "./internal/ensure-hue";
-
-/**
- * Converts a normalized hue to RGBA with given optional `alpha`
- * value (default: 1).
- *
- * @param out - result
- * @param hue - normalized hue
- */
-export const hueRgba = (out: Color | null, hue: number, alpha = 1): Color => {
- hue = ensureHue(hue) * 6;
- return setC4(
- out || [],
- clamp01(Math.abs(hue - 3) - 1),
- clamp01(2 - Math.abs(hue - 2)),
- clamp01(2 - Math.abs(hue - 4)),
- alpha
- );
-};
-
-export const namedHueRgba = (out: Color | null, hue: Hue, alpha = 1) =>
- hueRgba(out, hue / 12, alpha);
diff --git a/packages/color/src/index.ts b/packages/color/src/index.ts
index f08948cf1c..caec92a1cf 100644
--- a/packages/color/src/index.ts
+++ b/packages/color/src/index.ts
@@ -1,58 +1,103 @@
export * from "./api";
-export * from "./constants";
-export * from "./names";
-
-export * from "./hcya-rgba";
-export * from "./hsia-rgba";
-export * from "./hsla-css";
-export * from "./hsla-hsva";
-export * from "./hsla-rgba";
-export * from "./hsva-css";
-export * from "./hsva-hsla";
-export * from "./hsva-rgba";
-export * from "./hue-rgba";
-export * from "./int-css";
-export * from "./int-rgba";
-export * from "./kelvin-rgba";
-export * from "./resolve";
-export * from "./rgba-css";
-export * from "./rgba-hcva";
-export * from "./rgba-hcya";
-export * from "./rgba-hsia";
-export * from "./rgba-hsla";
-export * from "./rgba-hsva";
-export * from "./rgba-int";
-export * from "./rgba-xyza";
-export * from "./rgba-ycbcra";
-export * from "./srgba";
-export * from "./xyza-rgba";
-export * from "./ycbcra-rgba";
+export * from "./api/constants";
+export * from "./api/gradients";
+export * from "./api/names";
+export * from "./api/ranges";
+export * from "./api/system";
+export * from "./color";
export * from "./convert";
-export * from "./parse-css";
-
-export * from "./int";
-export * from "./css";
-export * from "./hcya";
-export * from "./hsia";
-export * from "./hsla";
-export * from "./hsva";
-export * from "./rgba";
-export * from "./xyza";
-export * from "./ycbcr";
-
-export * from "./alpha";
-export * from "./analog";
-export * from "./checks";
-export * from "./clamp";
-export * from "./closest-hue";
-export * from "./color-range";
-export * from "./cosine-gradients";
-export * from "./distance";
-export * from "./invert";
-export * from "./luminance";
-export * from "./luminance-rgb";
-export * from "./mix";
-export * from "./sort";
-export * from "./swatches";
-export * from "./transform";
+export * from "./defcolor";
+
+export * from "./css/css";
+export * from "./css/parse-css";
+
+export * from "./hcy/hcy-rgb";
+export * from "./hcy/hcy";
+
+export * from "./hsi/hsi-rgb";
+export * from "./hsi/hsi";
+
+export * from "./hsl/hsl-css";
+export * from "./hsl/hsl-hsv";
+export * from "./hsl/hsl-rgb";
+export * from "./hsl/hsl";
+
+export * from "./hsv/hsv-css";
+export * from "./hsv/hsv-hsl";
+export * from "./hsv/hsv-rgb";
+export * from "./hsv/hsv";
+
+export * from "./int/int-css";
+export * from "./int/int-int";
+export * from "./int/int-rgb";
+export * from "./int/int-srgb";
+export * from "./int/int";
+
+export * from "./lab/lab-css";
+export * from "./lab/lab-lab";
+export * from "./lab/lab-lch";
+export * from "./lab/lab-rgb";
+export * from "./lab/lab-xyz";
+export * from "./lab/lab50";
+export * from "./lab/lab65";
+
+export * from "./lch/lch-css";
+export * from "./lch/lch";
+
+export * from "./oklab/oklab-rgb";
+export * from "./oklab/oklab-xyz";
+export * from "./oklab/oklab";
+
+export * from "./ops/alpha";
+export * from "./ops/analog";
+export * from "./ops/clamp";
+export * from "./ops/closest-hue";
+export * from "./ops/color-range";
+export * from "./ops/cosine-gradients";
+export * from "./ops/distance";
+export * from "./ops/gradients";
+export * from "./ops/invert";
+export * from "./ops/is-gray";
+export * from "./ops/linear";
+export * from "./ops/luminance-rgb";
+export * from "./ops/luminance";
+export * from "./ops/mix";
+export * from "./ops/sort";
+export * from "./ops/swatches";
+export * from "./ops/transform";
+
+export * from "./rgb/hue-rgb";
+export * from "./rgb/kelvin-rgba";
+export * from "./rgb/rgb-css";
+export * from "./rgb/rgb-hcv";
+export * from "./rgb/rgb-hcy";
+export * from "./rgb/rgb-hsi";
+export * from "./rgb/rgb-hsl";
+export * from "./rgb/rgb-hsv";
+export * from "./rgb/rgb-lab";
+export * from "./rgb/rgb-oklab";
+export * from "./rgb/rgb-srgb";
+export * from "./rgb/rgb-xyz";
+export * from "./rgb/rgb-ycc";
+export * from "./rgb/rgb";
+
+export * from "./srgb/srgb-css";
+export * from "./srgb/srgb-int";
+export * from "./srgb/srgb-rgb";
+export * from "./srgb/srgb";
+
+export * from "./xyy/xyy-xyz";
+export * from "./xyy/xyy";
+
+export * from "./xyz/wavelength-xyz";
+export * from "./xyz/xyz-lab";
+export * from "./xyz/xyz-oklab";
+export * from "./xyz/xyz-rgb";
+export * from "./xyz/xyz-xyy";
+export * from "./xyz/xyz-xyz";
+export * from "./xyz/xyz50";
+export * from "./xyz/xyz65";
+
+export * from "./ycc/ycc-rgb";
+export * from "./ycc/ycc";
diff --git a/packages/color/src/int-css.ts b/packages/color/src/int-css.ts
deleted file mode 100644
index 649257162d..0000000000
--- a/packages/color/src/int-css.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import type { IDeref } from "@thi.ng/api";
-import { U24 } from "@thi.ng/strings";
-import { FF, INV8BIT } from "./constants";
-
-export const int32Css = (src: number | IDeref) => {
- src = typeof src === "number" ? src : src.deref();
- const a = src >>> 24;
- return a < 255
- ? `rgba(${(src >> 16) & 0xff},${(src >> 8) & 0xff},${src & 0xff},${FF(
- a * INV8BIT
- )})`
- : `#${U24(src & 0xffffff)}`;
-};
-
-export const int24Css = (src: number | IDeref) => {
- src = typeof src === "number" ? src : src.deref();
- return int32Css(src | 0xff000000);
-};
diff --git a/packages/color/src/int-rgba.ts b/packages/color/src/int-rgba.ts
deleted file mode 100644
index 829939b3fb..0000000000
--- a/packages/color/src/int-rgba.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import type { IDeref } from "@thi.ng/api";
-import { setC4 } from "@thi.ng/vectors";
-import type { Color } from "./api";
-import { INV8BIT } from "./constants";
-
-export const int32Rgba = (out: Color | null, src: number | IDeref