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 d478edd0a4..daf9432fe7 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
> the composer of. Geared towards versatility, not any specific type of music."
> — [@loganpowell](https://twitter.com/logantpowell/status/1186334119812304901) via Twitter
-Mono-repository for 144+ thi.ng TypeScript/ES6 projects, a wide
+Mono-repository for 148+ thi.ng TypeScript/ES6 projects, a wide
collection of largely data transformation oriented packages and building
blocks for (non-exhaustive list of topics):
@@ -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,50 +120,90 @@ 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 (2020-12-22)
+### Latest additions (2021-01-21)
-| Project | Version | Changelog | Description |
-|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------|--------------------------------------------------|
-| [`@thi.ng/fuzzy`](./packages/fuzzy) | [![version](https://img.shields.io/npm/v/@thi.ng/fuzzy.svg)](https://www.npmjs.com/package/@thi.ng/fuzzy) | [changelog](./packages/fuzzy/CHANGELOG.md) | Fuzzy logic primitives & rule inference engine |
-| [`@thi.ng/fuzzy-viz`](./packages/fuzzy-viz) | [![version](https://img.shields.io/npm/v/@thi.ng/fuzzy-viz.svg)](https://www.npmjs.com/package/@thi.ng/fuzzy-viz) | [changelog](./packages/fuzzy-viz/CHANGELOG.md) | Visualization, instrumentation for @thi.ng/fuzzy |
-| [`@thi.ng/vclock`](./packages/vclock) | [![version](https://img.shields.io/npm/v/@thi.ng/vclock.svg)](https://www.npmjs.com/package/@thi.ng/vclock) | [changelog](./packages/vclock/CHANGELOG.md) | Vector clock functions / comparators |
+| Project | Version | Changelog | Description |
+|-------------------------------------------|-----------------------------------------------------------------------------------------------------------------|-----------------------------------------------|--------------------------------------------------------|
+| [`@thi.ng/args`](./packages/args) | [![version](https://img.shields.io/npm/v/@thi.ng/args.svg)](https://www.npmjs.com/package/@thi.ng/args) | [changelog](./packages/args/CHANGELOG.md) | Declarative & functional CLI arg parsing & coercions |
+| [`@thi.ng/distance`](./packages/distance) | [![version](https://img.shields.io/npm/v/@thi.ng/distance.svg)](https://www.npmjs.com/package/@thi.ng/distance) | [changelog](./packages/distance/CHANGELOG.md) | n-D distance metrics & K-nearest neighborhoods |
+| [`@thi.ng/base-n`](./packages/base-n) | [![version](https://img.shields.io/npm/v/@thi.ng/base-n.svg)](https://www.npmjs.com/package/@thi.ng/base-n) | [changelog](./packages/base-n/CHANGELOG.md) | Arbitrary base-n encoding/decoding with presets |
+| [`@thi.ng/ksuid`](./packages/ksuid) | [![version](https://img.shields.io/npm/v/@thi.ng/ksuid.svg)](https://www.npmjs.com/package/@thi.ng/ksuid) | [changelog](./packages/ksuid/CHANGELOG.md) | K-sortable unique identifiers, binary & base-N encoded |
### Fundamentals
+| Project | Version | Changelog | Description |
+|-------------------------------------------|-----------------------------------------------------------------------------------------------------------------|-----------------------------------------------|----------------------------------------------------------|
+| [`@thi.ng/args`](./packages/args) | [![version](https://img.shields.io/npm/v/@thi.ng/args.svg)](https://www.npmjs.com/package/@thi.ng/args) | [changelog](./packages/args/CHANGELOG.md) | Declarative & functional CLI arg parsing & coercions |
+| [`@thi.ng/api`](./packages/api) | [![version](https://img.shields.io/npm/v/@thi.ng/api.svg)](https://www.npmjs.com/package/@thi.ng/api) | [changelog](./packages/api/CHANGELOG.md) | Common types, decorators, mixins |
+| [`@thi.ng/bench`](./packages/bench) | [![version](https://img.shields.io/npm/v/@thi.ng/bench.svg)](https://www.npmjs.com/package/@thi.ng/bench) | [changelog](./packages/bench/CHANGELOG.md) | Basic benchmarking helpers |
+| [`@thi.ng/checks`](./packages/checks) | [![version](https://img.shields.io/npm/v/@thi.ng/checks.svg)](https://www.npmjs.com/package/@thi.ng/checks) | [changelog](./packages/checks/CHANGELOG.md) | Type & value checks |
+| [`@thi.ng/compare`](./packages/compare) | [![version](https://img.shields.io/npm/v/@thi.ng/compare.svg)](https://www.npmjs.com/package/@thi.ng/compare) | [changelog](./packages/compare/CHANGELOG.md) | Comparators |
+| [`@thi.ng/compose`](./packages/compose) | [![version](https://img.shields.io/npm/v/@thi.ng/compose.svg)](https://www.npmjs.com/package/@thi.ng/compose) | [changelog](./packages/compose/CHANGELOG.md) | Functional composition helpers |
+| [`@thi.ng/date`](./packages/date) | [![version](https://img.shields.io/npm/v/@thi.ng/date.svg)](https://www.npmjs.com/package/@thi.ng/date) | [changelog](./packages/date/CHANGELOG.md) | Date/time iterators, formatters, rounding |
+| [`@thi.ng/defmulti`](./packages/defmulti) | [![version](https://img.shields.io/npm/v/@thi.ng/defmulti.svg)](https://www.npmjs.com/package/@thi.ng/defmulti) | [changelog](./packages/defmulti/CHANGELOG.md) | Dynamic multiple dispatch |
+| [`@thi.ng/distance`](./packages/distance) | [![version](https://img.shields.io/npm/v/@thi.ng/distance.svg)](https://www.npmjs.com/package/@thi.ng/distance) | [changelog](./packages/distance/CHANGELOG.md) | n-D distance metrics & K-nearest neighborhoods |
+| [`@thi.ng/equiv`](./packages/equiv) | [![version](https://img.shields.io/npm/v/@thi.ng/equiv.svg)](https://www.npmjs.com/package/@thi.ng/equiv) | [changelog](./packages/equiv/CHANGELOG.md) | Deep value equivalence checking |
+| [`@thi.ng/errors`](./packages/errors) | [![version](https://img.shields.io/npm/v/@thi.ng/errors.svg)](https://www.npmjs.com/package/@thi.ng/errors) | [changelog](./packages/errors/CHANGELOG.md) | Custom error types |
+| [`@thi.ng/hex`](./packages/hex) | [![version](https://img.shields.io/npm/v/@thi.ng/hex.svg)](https://www.npmjs.com/package/@thi.ng/hex) | [changelog](./packages/hex/CHANGELOG.md) | Hex value formatters for U4-64 words |
+| [`@thi.ng/memoize`](./packages/memoize) | [![version](https://img.shields.io/npm/v/@thi.ng/memoize.svg)](https://www.npmjs.com/package/@thi.ng/memoize) | [changelog](./packages/memoize/CHANGELOG.md) | Function memoization w/ customizable caching |
+| [`@thi.ng/oquery`](./packages/oquery) | [![version](https://img.shields.io/npm/v/@thi.ng/oquery.svg)](https://www.npmjs.com/package/@thi.ng/oquery) | [changelog](./packages/oquery/CHANGELOG.md) | Pattern based query engine for JS objects |
+| [`@thi.ng/parse`](./packages/parse) | [![version](https://img.shields.io/npm/v/@thi.ng/parse.svg)](https://www.npmjs.com/package/@thi.ng/parse) | [changelog](./packages/parse/CHANGELOG.md) | Parser combinators & AST generator/transformer |
+| [`@thi.ng/paths`](./packages/paths) | [![version](https://img.shields.io/npm/v/@thi.ng/paths.svg)](https://www.npmjs.com/package/@thi.ng/paths) | [changelog](./packages/paths/CHANGELOG.md) | Immutable nested object accessors |
+| [`@thi.ng/strings`](./packages/strings) | [![version](https://img.shields.io/npm/v/@thi.ng/strings.svg)](https://www.npmjs.com/package/@thi.ng/strings) | [changelog](./packages/strings/CHANGELOG.md) | Higher-order string formatting utils |
+| [`@thi.ng/system`](./packages/system) | [![version](https://img.shields.io/npm/v/@thi.ng/system.svg)](https://www.npmjs.com/package/@thi.ng/system) | [changelog](./packages/system/CHANGELOG.md) | Minimal life cycle container for stateful app components |
+
+### Maths
+
+| Project | Version | Changelog | Description |
+|---------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------|-------------------------------------------------|
+| [`@thi.ng/dual-algebra`](./packages/dual-algebra) | [![version](https://img.shields.io/npm/v/@thi.ng/dual-algebra.svg)](https://www.npmjs.com/package/@thi.ng/dual-algebra) | [changelog](./packages/dual-algebra/CHANGELOG.md) | Dual number algebra / automatic differentiation |
+| [`@thi.ng/dsp`](./packages/dsp) | [![version](https://img.shields.io/npm/v/@thi.ng/dsp.svg)](https://www.npmjs.com/package/@thi.ng/dsp) | [changelog](./packages/dsp/CHANGELOG.md) | DSP utils, composable signal gens/processors |
+| [`@thi.ng/fuzzy`](./packages/fuzzy) | [![version](https://img.shields.io/npm/v/@thi.ng/fuzzy.svg)](https://www.npmjs.com/package/@thi.ng/fuzzy) | [changelog](./packages/fuzzy/CHANGELOG.md) | Fuzzy logic primitives & rule inference engine |
+| [`@thi.ng/intervals`](./packages/intervals) | [![version](https://img.shields.io/npm/v/@thi.ng/intervals.svg)](https://www.npmjs.com/package/@thi.ng/intervals) | [changelog](./packages/intervals/CHANGELOG.md) | Open/closed intervals, queries, set ops |
+| [`@thi.ng/math`](./packages/math) | [![version](https://img.shields.io/npm/v/@thi.ng/math.svg)](https://www.npmjs.com/package/@thi.ng/math) | [changelog](./packages/math/CHANGELOG.md) | Assorted common math functions & utilities |
+| [`@thi.ng/matrices`](./packages/matrices) | [![version](https://img.shields.io/npm/v/@thi.ng/matrices.svg)](https://www.npmjs.com/package/@thi.ng/matrices) | [changelog](./packages/matrices/CHANGELOG.md) | Matrix operations |
+| [`@thi.ng/sparse`](./packages/sparse) | [![version](https://img.shields.io/npm/v/@thi.ng/sparse.svg)](https://www.npmjs.com/package/@thi.ng/sparse) | [changelog](./packages/sparse/CHANGELOG.md) | Sparse matrix & vector impls |
+| [`@thi.ng/vectors`](./packages/vectors) | [![version](https://img.shields.io/npm/v/@thi.ng/vectors.svg)](https://www.npmjs.com/package/@thi.ng/vectors) | [changelog](./packages/vectors/CHANGELOG.md) | Fixed & arbitrary-length vector ops |
+
+### Randomness
+
| Project | Version | Changelog | Description |
|-----------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------|----------------------------------------------------------|
-| [`@thi.ng/api`](./packages/api) | [![version](https://img.shields.io/npm/v/@thi.ng/api.svg)](https://www.npmjs.com/package/@thi.ng/api) | [changelog](./packages/api/CHANGELOG.md) | Common types, decorators, mixins |
-| [`@thi.ng/bench`](./packages/bench) | [![version](https://img.shields.io/npm/v/@thi.ng/bench.svg)](https://www.npmjs.com/package/@thi.ng/bench) | [changelog](./packages/bench/CHANGELOG.md) | Basic benchmarking helpers |
-| [`@thi.ng/checks`](./packages/checks) | [![version](https://img.shields.io/npm/v/@thi.ng/checks.svg)](https://www.npmjs.com/package/@thi.ng/checks) | [changelog](./packages/checks/CHANGELOG.md) | Type & value checks |
| [`@thi.ng/colored-noise`](./packages/colored-noise) | [![version](https://img.shields.io/npm/v/@thi.ng/colored-noise.svg)](https://www.npmjs.com/package/@thi.ng/colored-noise) | [changelog](./packages/colored-noise/CHANGELOG.md) | 1D colored noise generators |
-| [`@thi.ng/compare`](./packages/compare) | [![version](https://img.shields.io/npm/v/@thi.ng/compare.svg)](https://www.npmjs.com/package/@thi.ng/compare) | [changelog](./packages/compare/CHANGELOG.md) | Comparators |
-| [`@thi.ng/compose`](./packages/compose) | [![version](https://img.shields.io/npm/v/@thi.ng/compose.svg)](https://www.npmjs.com/package/@thi.ng/compose) | [changelog](./packages/compose/CHANGELOG.md) | Functional composition helpers |
-| [`@thi.ng/date`](./packages/date) | [![version](https://img.shields.io/npm/v/@thi.ng/date.svg)](https://www.npmjs.com/package/@thi.ng/date) | [changelog](./packages/date/CHANGELOG.md) | Date/time iterators, formatters, rounding |
-| [`@thi.ng/defmulti`](./packages/defmulti) | [![version](https://img.shields.io/npm/v/@thi.ng/defmulti.svg)](https://www.npmjs.com/package/@thi.ng/defmulti) | [changelog](./packages/defmulti/CHANGELOG.md) | Dynamic multiple dispatch |
-| [`@thi.ng/dsp`](./packages/dsp) | [![version](https://img.shields.io/npm/v/@thi.ng/dsp.svg)](https://www.npmjs.com/package/@thi.ng/dsp) | [changelog](./packages/dsp/CHANGELOG.md) | DSP utils, oscillators |
-| [`@thi.ng/dual-algebra`](./packages/dual-algebra) | [![version](https://img.shields.io/npm/v/@thi.ng/dual-algebra.svg)](https://www.npmjs.com/package/@thi.ng/dual-algebra) | [changelog](./packages/dual-algebra/CHANGELOG.md) | Dual number algebra / automatic differentiation |
-| [`@thi.ng/ecs`](./packages/ecs) | [![version](https://img.shields.io/npm/v/@thi.ng/ecs.svg)](https://www.npmjs.com/package/@thi.ng/ecs) | [changelog](./packages/ecs/CHANGELOG.md) | Entity-Component System |
-| [`@thi.ng/equiv`](./packages/equiv) | [![version](https://img.shields.io/npm/v/@thi.ng/equiv.svg)](https://www.npmjs.com/package/@thi.ng/equiv) | [changelog](./packages/equiv/CHANGELOG.md) | Deep value equivalence checking |
-| [`@thi.ng/errors`](./packages/errors) | [![version](https://img.shields.io/npm/v/@thi.ng/errors.svg)](https://www.npmjs.com/package/@thi.ng/errors) | [changelog](./packages/errors/CHANGELOG.md) | Custom error types |
-| [`@thi.ng/fuzzy`](./packages/fuzzy) | [![version](https://img.shields.io/npm/v/@thi.ng/fuzzy.svg)](https://www.npmjs.com/package/@thi.ng/fuzzy) | [changelog](./packages/fuzzy/CHANGELOG.md) | Fuzzy logic primitives & rule inference engine |
-| [`@thi.ng/hex`](./packages/hex) | [![version](https://img.shields.io/npm/v/@thi.ng/hex.svg)](https://www.npmjs.com/package/@thi.ng/hex) | [changelog](./packages/hex/CHANGELOG.md) | Hex value formatters for U4-64 words |
-| [`@thi.ng/math`](./packages/math) | [![version](https://img.shields.io/npm/v/@thi.ng/math.svg)](https://www.npmjs.com/package/@thi.ng/math) | [changelog](./packages/math/CHANGELOG.md) | Assorted common math functions & utilities |
-| [`@thi.ng/memoize`](./packages/memoize) | [![version](https://img.shields.io/npm/v/@thi.ng/memoize.svg)](https://www.npmjs.com/package/@thi.ng/memoize) | [changelog](./packages/memoize/CHANGELOG.md) | Function memoization w/ customizable caching |
-| [`@thi.ng/mime`](./packages/mime) | [![version](https://img.shields.io/npm/v/@thi.ng/mime.svg)](https://www.npmjs.com/package/@thi.ng/mime) | [changelog](./packages/mime/CHANGELOG.md) | File extension to MIME type mappings |
-| [`@thi.ng/oquery`](./packages/oquery) | [![version](https://img.shields.io/npm/v/@thi.ng/oquery.svg)](https://www.npmjs.com/package/@thi.ng/oquery) | [changelog](./packages/oquery/CHANGELOG.md) | Pattern based query engine for JS objects |
-| [`@thi.ng/parse`](./packages/parse) | [![version](https://img.shields.io/npm/v/@thi.ng/parse.svg)](https://www.npmjs.com/package/@thi.ng/parse) | [changelog](./packages/parse/CHANGELOG.md) | Parser combinators & AST generator/transformer |
-| [`@thi.ng/paths`](./packages/paths) | [![version](https://img.shields.io/npm/v/@thi.ng/paths.svg)](https://www.npmjs.com/package/@thi.ng/paths) | [changelog](./packages/paths/CHANGELOG.md) | Immutable nested object accessors |
-| [`@thi.ng/prefixes`](./packages/prefixes) | [![version](https://img.shields.io/npm/v/@thi.ng/prefixes.svg)](https://www.npmjs.com/package/@thi.ng/prefixes) | [changelog](./packages/prefixes/CHANGELOG.md) | Linked Data & xmlns prefixes/URLs |
-| [`@thi.ng/random`](./packages/random) | [![version](https://img.shields.io/npm/v/@thi.ng/random.svg)](https://www.npmjs.com/package/@thi.ng/random) | [changelog](./packages/random/CHANGELOG.md) | Seedable PRNG implementations w/ unified API |
-| [`@thi.ng/strings`](./packages/strings) | [![version](https://img.shields.io/npm/v/@thi.ng/strings.svg)](https://www.npmjs.com/package/@thi.ng/strings) | [changelog](./packages/strings/CHANGELOG.md) | Higher-order string formatting utils |
-| [`@thi.ng/system`](./packages/system) | [![version](https://img.shields.io/npm/v/@thi.ng/system.svg)](https://www.npmjs.com/package/@thi.ng/system) | [changelog](./packages/system/CHANGELOG.md) | Minimal life cycle container for stateful app components |
+| [`@thi.ng/ksuid`](./packages/ksuid) | [![version](https://img.shields.io/npm/v/@thi.ng/ksuid.svg)](https://www.npmjs.com/package/@thi.ng/ksuid) | [changelog](./packages/ksuid/CHANGELOG.md) | K-sortable unique identifiers, binary & base-N encoded |
+| [`@thi.ng/random`](./packages/random) | [![version](https://img.shields.io/npm/v/@thi.ng/random.svg)](https://www.npmjs.com/package/@thi.ng/random) | [changelog](./packages/random/CHANGELOG.md) | Seedable PRNG implementations, distributions & utilities |
+
+### File format support
+
+| Project | Version | Changelog | Description |
+|---------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------|------------------------------------------------|
+| [`@thi.ng/bencode`](./packages/bencode) | [![version](https://img.shields.io/npm/v/@thi.ng/bencode.svg)](https://www.npmjs.com/package/@thi.ng/bencode) | [changelog](./packages/bencode/CHANGELOG.md) | Bencode binary format encoding |
+| [`@thi.ng/csv`](./packages/csv) | [![version](https://img.shields.io/npm/v/@thi.ng/csv.svg)](https://www.npmjs.com/package/@thi.ng/csv) | [changelog](./packages/csv/CHANGELOG.md) | Customizable CSV parser/object mapper |
+| [`@thi.ng/dot`](./packages/dot) | [![version](https://img.shields.io/npm/v/@thi.ng/dot.svg)](https://www.npmjs.com/package/@thi.ng/dot) | [changelog](./packages/dot/CHANGELOG.md) | Graphviz DOM & export |
+| [`@thi.ng/dsp-io-wav`](./packages/dsp-io-wav) | [![version](https://img.shields.io/npm/v/@thi.ng/dsp-io-wav.svg)](https://www.npmjs.com/package/@thi.ng/dsp-io-wav) | [changelog](./packages/dsp-io-wav/CHANGELOG.md) | WAV file format exporter |
+| [`@thi.ng/geom-io-obj`](./packages/geom-io-obj) | [![version](https://img.shields.io/npm/v/@thi.ng/geom-io-obj.svg)](https://www.npmjs.com/package/@thi.ng/geom-io-obj) | [changelog](./packages/geom-io-obj/CHANGELOG.md) | Wavefront OBJ model parser |
+| [`@thi.ng/hiccup-css`](./packages/hiccup-css) | [![version](https://img.shields.io/npm/v/@thi.ng/hiccup-css.svg)](https://www.npmjs.com/package/@thi.ng/hiccup-css) | [changelog](./packages/hiccup-css/CHANGELOG.md) | CSS from nested JS data structures |
+| [`@thi.ng/hiccup-html`](./packages/hiccup-html) | [![version](https://img.shields.io/npm/v/@thi.ng/hiccup-html.svg)](https://www.npmjs.com/package/@thi.ng/hiccup-html) | [changelog](./packages/hiccup-html/CHANGELOG.md) | Type-checked HTML5 element wrappers for hiccup |
+| [`@thi.ng/hiccup-markdown`](./packages/hiccup-markdown) | [![version](https://img.shields.io/npm/v/@thi.ng/hiccup-markdown.svg)](https://www.npmjs.com/package/@thi.ng/hiccup-markdown) | [changelog](./packages/hiccup-markdown/CHANGELOG.md) | Hiccup-to-Markdown serialization |
+| [`@thi.ng/hiccup-svg`](./packages/hiccup-svg) | [![version](https://img.shields.io/npm/v/@thi.ng/hiccup-svg.svg)](https://www.npmjs.com/package/@thi.ng/hiccup-svg) | [changelog](./packages/hiccup-svg/CHANGELOG.md) | hiccup based SVG vocab |
+| [`@thi.ng/iges`](./packages/iges) | [![version](https://img.shields.io/npm/v/@thi.ng/iges.svg)](https://www.npmjs.com/package/@thi.ng/iges) | [changelog](./packages/iges/CHANGELOG.md) | IGES format geometry serialization |
+| [`@thi.ng/mime`](./packages/mime) | [![version](https://img.shields.io/npm/v/@thi.ng/mime.svg)](https://www.npmjs.com/package/@thi.ng/mime) | [changelog](./packages/mime/CHANGELOG.md) | File extension to MIME type mappings |
+| [`@thi.ng/prefixes`](./packages/prefixes) | [![version](https://img.shields.io/npm/v/@thi.ng/prefixes.svg)](https://www.npmjs.com/package/@thi.ng/prefixes) | [changelog](./packages/prefixes/CHANGELOG.md) | Linked Data, RDF & xmlns prefixes/URLs |
+| [`@thi.ng/sax`](./packages/sax) | [![version](https://img.shields.io/npm/v/@thi.ng/sax.svg)](https://www.npmjs.com/package/@thi.ng/sax) | [changelog](./packages/sax/CHANGELOG.md) | SAX-like XML parser / transducer |
+
### Iterator, stream & sequence processing
| Project | Version | Changelog | Description |
@@ -172,7 +212,6 @@ feature or `develop` branches) -->
| [`@thi.ng/fsm`](./packages/fsm) | [![version](https://img.shields.io/npm/v/@thi.ng/fsm.svg)](https://www.npmjs.com/package/@thi.ng/fsm) | [changelog](./packages/fsm/CHANGELOG.md) | FSM / parser primitives |
| [`@thi.ng/grid-iterators`](./packages/grid-iterators) | [![version](https://img.shields.io/npm/v/@thi.ng/grid-iterators.svg)](https://www.npmjs.com/package/@thi.ng/grid-iterators) | [changelog](./packages/grid-iterators/CHANGELOG.md) | 2D grid iterator strategies |
| [`@thi.ng/iterators`](./packages/iterators) | [![version](https://img.shields.io/npm/v/@thi.ng/iterators.svg)](https://www.npmjs.com/package/@thi.ng/iterators) | [changelog](./packages/iterators/CHANGELOG.md) | ES6 generators / iterators |
-| [`@thi.ng/sax`](./packages/sax) | [![version](https://img.shields.io/npm/v/@thi.ng/sax.svg)](https://www.npmjs.com/package/@thi.ng/sax) | [changelog](./packages/sax/CHANGELOG.md) | SAX-like XML parser / transducer |
| [`@thi.ng/seq`](./packages/seq) | [![version](https://img.shields.io/npm/v/@thi.ng/seq.svg)](https://www.npmjs.com/package/@thi.ng/seq) | [changelog](./packages/seq/CHANGELOG.md) | Lisp/Clojure-style sequence abstraction |
| [`@thi.ng/transducers`](./packages/transducers) | [![version](https://img.shields.io/npm/v/@thi.ng/transducers.svg)](https://www.npmjs.com/package/@thi.ng/transducers) | [changelog](./packages/transducers/CHANGELOG.md) | Composable data transformations |
| [`@thi.ng/transducers-binary`](./packages/transducers-binary) | [![version](https://img.shields.io/npm/v/@thi.ng/transducers-binary.svg)](https://www.npmjs.com/package/@thi.ng/transducers-binary) | [changelog](./packages/transducers-binary/CHANGELOG.md) | Binary data related transducers |
@@ -204,19 +243,17 @@ feature or `develop` branches) -->
| [`@thi.ng/atom`](./packages/atom) | [![version](https://img.shields.io/npm/v/@thi.ng/atom.svg)](https://www.npmjs.com/package/@thi.ng/atom) | [changelog](./packages/atom/CHANGELOG.md) | Immutable value wrappers, views, history |
| [`@thi.ng/bitfield`](./packages/bitfield) | [![version](https://img.shields.io/npm/v/@thi.ng/bitfield.svg)](https://www.npmjs.com/package/@thi.ng/bitfield) | [changelog](./packages/bitfield/CHANGELOG.md) | 1D/2D bit field implementations |
| [`@thi.ng/cache`](./packages/cache) | [![version](https://img.shields.io/npm/v/@thi.ng/cache.svg)](https://www.npmjs.com/package/@thi.ng/cache) | [changelog](./packages/cache/CHANGELOG.md) | In-memory caches / strategies |
-| [`@thi.ng/csv`](./packages/csv) | [![version](https://img.shields.io/npm/v/@thi.ng/csv.svg)](https://www.npmjs.com/package/@thi.ng/csv) | [changelog](./packages/csv/CHANGELOG.md) | Customizable CSV parser/object mapper |
| [`@thi.ng/dcons`](./packages/dcons) | [![version](https://img.shields.io/npm/v/@thi.ng/dcons.svg)](https://www.npmjs.com/package/@thi.ng/dcons) | [changelog](./packages/dcons/CHANGELOG.md) | Doubly-linked list |
| [`@thi.ng/diff`](./packages/diff) | [![version](https://img.shields.io/npm/v/@thi.ng/diff.svg)](https://www.npmjs.com/package/@thi.ng/diff) | [changelog](./packages/diff/CHANGELOG.md) | Array & object diffing |
| [`@thi.ng/dgraph`](./packages/dgraph) | [![version](https://img.shields.io/npm/v/@thi.ng/dgraph.svg)](https://www.npmjs.com/package/@thi.ng/dgraph) | [changelog](./packages/dgraph/CHANGELOG.md) | Dependency graph |
+| [`@thi.ng/ecs`](./packages/ecs) | [![version](https://img.shields.io/npm/v/@thi.ng/ecs.svg)](https://www.npmjs.com/package/@thi.ng/ecs) | [changelog](./packages/ecs/CHANGELOG.md) | Entity-Component System |
| [`@thi.ng/egf`](./packages/egf) | [![version](https://img.shields.io/npm/v/@thi.ng/egf.svg)](https://www.npmjs.com/package/@thi.ng/egf) | [changelog](./packages/egf/CHANGELOG.md) | Extensible Graph Format |
| [`@thi.ng/gp`](./packages/gp) | [![version](https://img.shields.io/npm/v/@thi.ng/gp.svg)](https://www.npmjs.com/package/@thi.ng/gp) | [changelog](./packages/gp/CHANGELOG.md) | Genetic programming helpers / AST gen |
| [`@thi.ng/heaps`](./packages/heaps) | [![version](https://img.shields.io/npm/v/@thi.ng/heaps.svg)](https://www.npmjs.com/package/@thi.ng/heaps) | [changelog](./packages/heaps/CHANGELOG.md) | Binary & d-ary heap impls |
| [`@thi.ng/idgen`](./packages/idgen) | [![version](https://img.shields.io/npm/v/@thi.ng/idgen.svg)](https://www.npmjs.com/package/@thi.ng/idgen) | [changelog](./packages/idgen/CHANGELOG.md) | Versioned ID generation / free-list |
-| [`@thi.ng/intervals`](./packages/intervals) | [![version](https://img.shields.io/npm/v/@thi.ng/intervals.svg)](https://www.npmjs.com/package/@thi.ng/intervals) | [changelog](./packages/intervals/CHANGELOG.md) | Open/closed intervals, queries, set ops |
| [`@thi.ng/ramp`](./packages/ramp) | [![version](https://img.shields.io/npm/v/@thi.ng/ramp.svg)](https://www.npmjs.com/package/@thi.ng/ramp) | [changelog](./packages/ramp/CHANGELOG.md) | Parametric, interpolated lookup tables |
| [`@thi.ng/quad-edge`](./packages/quad-edge) | [![version](https://img.shields.io/npm/v/@thi.ng/quad-edge.svg)](https://www.npmjs.com/package/@thi.ng/quad-edge) | [changelog](./packages/quad-edge/CHANGELOG.md) | Quad-edge, dual-graph data structure |
| [`@thi.ng/resolve-map`](./packages/resolve-map) | [![version](https://img.shields.io/npm/v/@thi.ng/resolve-map.svg)](https://www.npmjs.com/package/@thi.ng/resolve-map) | [changelog](./packages/resolve-map/CHANGELOG.md) | DAG computations & value resolution |
-| [`@thi.ng/sparse`](./packages/sparse) | [![version](https://img.shields.io/npm/v/@thi.ng/sparse.svg)](https://www.npmjs.com/package/@thi.ng/sparse) | [changelog](./packages/sparse/CHANGELOG.md) | Sparse matrix & vector impls |
| [`@thi.ng/vclock`](./packages/vclock) | [![version](https://img.shields.io/npm/v/@thi.ng/vclock.svg)](https://www.npmjs.com/package/@thi.ng/vclock) | [changelog](./packages/vclock/CHANGELOG.md) | Vector clock functions / comparators |
| [`@thi.ng/zipper`](./packages/zipper) | [![version](https://img.shields.io/npm/v/@thi.ng/zipper.svg)](https://www.npmjs.com/package/@thi.ng/zipper) | [changelog](./packages/zipper/CHANGELOG.md) | Immutable tree editing / navigation |
@@ -234,10 +271,6 @@ feature or `develop` branches) -->
| [`@thi.ng/hiccup`](./packages/hiccup) | [![version](https://img.shields.io/npm/v/@thi.ng/hiccup.svg)](https://www.npmjs.com/package/@thi.ng/hiccup) | [changelog](./packages/hiccup/CHANGELOG.md) | S-expression based HTML/XML serialization |
| [`@thi.ng/hiccup-canvas`](./packages/hiccup-canvas) | [![version](https://img.shields.io/npm/v/@thi.ng/hiccup-canvas.svg)](https://www.npmjs.com/package/@thi.ng/hiccup-canvas) | [changelog](./packages/hiccup-canvas/CHANGELOG.md) | hiccup interpreter for canvas api |
| [`@thi.ng/hiccup-carbon-icons`](./packages/hiccup-carbon-icons) | [![version](https://img.shields.io/npm/v/@thi.ng/hiccup-carbon-icons.svg)](https://www.npmjs.com/package/@thi.ng/hiccup-carbon-icons) | [changelog](./packages/hiccup-carbon-icons/CHANGELOG.md) | IBM Carbon icons in hiccup format |
-| [`@thi.ng/hiccup-css`](./packages/hiccup-css) | [![version](https://img.shields.io/npm/v/@thi.ng/hiccup-css.svg)](https://www.npmjs.com/package/@thi.ng/hiccup-css) | [changelog](./packages/hiccup-css/CHANGELOG.md) | CSS from nested JS data structures |
-| [`@thi.ng/hiccup-html`](./packages/hiccup-html) | [![version](https://img.shields.io/npm/v/@thi.ng/hiccup-html.svg)](https://www.npmjs.com/package/@thi.ng/hiccup-html) | [changelog](./packages/hiccup-html/CHANGELOG.md) | Type-checked HTML5 element wrappers for hiccup |
-| [`@thi.ng/hiccup-markdown`](./packages/hiccup-markdown) | [![version](https://img.shields.io/npm/v/@thi.ng/hiccup-markdown.svg)](https://www.npmjs.com/package/@thi.ng/hiccup-markdown) | [changelog](./packages/hiccup-markdown/CHANGELOG.md) | Hiccup-to-Markdown serialization |
-| [`@thi.ng/hiccup-svg`](./packages/hiccup-svg) | [![version](https://img.shields.io/npm/v/@thi.ng/hiccup-svg.svg)](https://www.npmjs.com/package/@thi.ng/hiccup-svg) | [changelog](./packages/hiccup-svg/CHANGELOG.md) | hiccup based SVG vocab |
| [`@thi.ng/imgui`](./packages/imgui) | [![version](https://img.shields.io/npm/v/@thi.ng/imgui.svg)](https://www.npmjs.com/package/@thi.ng/imgui) | [changelog](./packages/imgui/CHANGELOG.md) | Immediate mode GUI |
| [`@thi.ng/interceptors`](./packages/interceptors) | [![version](https://img.shields.io/npm/v/@thi.ng/interceptors.svg)](https://www.npmjs.com/package/@thi.ng/interceptors) | [changelog](./packages/interceptors/CHANGELOG.md) | Composable event handlers & processor |
| [`@thi.ng/rdom`](./packages/rdom) | [![version](https://img.shields.io/npm/v/@thi.ng/rdom.svg)](https://www.npmjs.com/package/@thi.ng/rdom) | [changelog](./packages/rdom/CHANGELOG.md) | Reactive, diff-less, async UI components |
@@ -246,13 +279,12 @@ feature or `develop` branches) -->
| [`@thi.ng/router`](./packages/router) | [![version](https://img.shields.io/npm/v/@thi.ng/router.svg)](https://www.npmjs.com/package/@thi.ng/router) | [changelog](./packages/router/CHANGELOG.md) | Customizable browser & non-browser router |
| [`@thi.ng/text-canvas`](./packages/text-canvas) | [![version](https://img.shields.io/npm/v/@thi.ng/text-canvas.svg)](https://www.npmjs.com/package/@thi.ng/text-canvas) | [changelog](./packages/text-canvas/CHANGELOG.md) | Text-mode canvas, drawing, tables, charts |
-### Geometry & visualization
+### Geometry, image & visualization
| Project | Version | Changelog | Description |
|---------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------|-----------------------------------------------------|
| [`@thi.ng/color`](./packages/color) | [![version](https://img.shields.io/npm/v/@thi.ng/color.svg)](https://www.npmjs.com/package/@thi.ng/color) | [changelog](./packages/color/CHANGELOG.md) | Color conversions, gradients |
| [`@thi.ng/dgraph-dot`](./packages/dgraph-dot) | [![version](https://img.shields.io/npm/v/@thi.ng/dgraph-dot.svg)](https://www.npmjs.com/package/@thi.ng/dgraph-dot) | [changelog](./packages/dgraph-dot/CHANGELOG.md) | Dependency graph -> Graphviz |
-| [`@thi.ng/dot`](./packages/dot) | [![version](https://img.shields.io/npm/v/@thi.ng/dot.svg)](https://www.npmjs.com/package/@thi.ng/dot) | [changelog](./packages/dot/CHANGELOG.md) | Graphviz DOM & export |
| [`@thi.ng/fuzzy-viz`](./packages/fuzzy-viz) | [![version](https://img.shields.io/npm/v/@thi.ng/fuzzy-viz.svg)](https://www.npmjs.com/package/@thi.ng/fuzzy-viz) | [changelog](./packages/fuzzy-viz/CHANGELOG.md) | Visualization, instrumentation for @thi.ng/fuzzy |
| [`@thi.ng/geom`](./packages/geom) | [![version](https://img.shields.io/npm/v/@thi.ng/geom.svg)](https://www.npmjs.com/package/@thi.ng/geom) | [changelog](./packages/geom/CHANGELOG.md) | 2D only geometry types & ops |
| [`@thi.ng/geom-accel`](./packages/geom-accel) | [![version](https://img.shields.io/npm/v/@thi.ng/geom-accel.svg)](https://www.npmjs.com/package/@thi.ng/geom-accel) | [changelog](./packages/geom-accel/CHANGELOG.md) | Spatial indexing data structures |
@@ -263,7 +295,6 @@ feature or `develop` branches) -->
| [`@thi.ng/geom-closest-point`](./packages/geom-closest-point) | [![version](https://img.shields.io/npm/v/@thi.ng/geom-closest-point.svg)](https://www.npmjs.com/package/@thi.ng/geom-closest-point) | [changelog](./packages/geom-closest-point/CHANGELOG.md) | Closest point helpers |
| [`@thi.ng/geom-fuzz`](./packages/geom-fuzz) | [![version](https://img.shields.io/npm/v/@thi.ng/geom-fuzz.svg)](https://www.npmjs.com/package/@thi.ng/geom-fuzz) | [changelog](./packages/geom-fuzz/CHANGELOG.md) | Fuzzy 2D shape drawing / filling |
| [`@thi.ng/geom-hull`](./packages/geom-hull) | [![version](https://img.shields.io/npm/v/@thi.ng/geom-hull.svg)](https://www.npmjs.com/package/@thi.ng/geom-hull) | [changelog](./packages/geom-hull/CHANGELOG.md) | 2D convex hull (Graham scan) |
-| [`@thi.ng/geom-io-obj`](./packages/geom-io-obj) | [![version](https://img.shields.io/npm/v/@thi.ng/geom-io-obj.svg)](https://www.npmjs.com/package/@thi.ng/geom-io-obj) | [changelog](./packages/geom-io-obj/CHANGELOG.md) | Wavefront OBJ model parser |
| [`@thi.ng/geom-isec`](./packages/geom-isec) | [![version](https://img.shields.io/npm/v/@thi.ng/geom-isec.svg)](https://www.npmjs.com/package/@thi.ng/geom-isec) | [changelog](./packages/geom-isec/CHANGELOG.md) | Point & shape intersection tests |
| [`@thi.ng/geom-isoline`](./packages/geom-isoline) | [![version](https://img.shields.io/npm/v/@thi.ng/geom-isoline.svg)](https://www.npmjs.com/package/@thi.ng/geom-isoline) | [changelog](./packages/geom-isoline/CHANGELOG.md) | 2D contour line extraction |
| [`@thi.ng/geom-poly-utils`](./packages/geom-poly-utils) | [![version](https://img.shields.io/npm/v/@thi.ng/geom-poly-utils.svg)](https://www.npmjs.com/package/@thi.ng/geom-poly-utils) | [changelog](./packages/geom-poly-utils/CHANGELOG.md) | 2D polygon helpers |
@@ -272,15 +303,12 @@ feature or `develop` branches) -->
| [`@thi.ng/geom-subdiv-curve`](./packages/geom-subdiv-curve) | [![version](https://img.shields.io/npm/v/@thi.ng/geom-subdiv-curve.svg)](https://www.npmjs.com/package/@thi.ng/geom-subdiv-curve) | [changelog](./packages/geom-subdiv-curve/CHANGELOG.md) | nD iterative subdivision curves |
| [`@thi.ng/geom-tessellate`](./packages/geom-tessellate) | [![version](https://img.shields.io/npm/v/@thi.ng/geom-tessellate.svg)](https://www.npmjs.com/package/@thi.ng/geom-tessellate) | [changelog](./packages/geom-tessellate/CHANGELOG.md) | nD convex polygon tessellators |
| [`@thi.ng/geom-voronoi`](./packages/geom-voronoi) | [![version](https://img.shields.io/npm/v/@thi.ng/geom-voronoi.svg)](https://www.npmjs.com/package/@thi.ng/geom-voronoi) | [changelog](./packages/geom-voronoi/CHANGELOG.md) | 2D iterative delaunay/voronoi |
-| [`@thi.ng/iges`](./packages/iges) | [![version](https://img.shields.io/npm/v/@thi.ng/iges.svg)](https://www.npmjs.com/package/@thi.ng/iges) | [changelog](./packages/iges/CHANGELOG.md) | IGES format geometry serialization |
| [`@thi.ng/lsys`](./packages/lsys) | [![version](https://img.shields.io/npm/v/@thi.ng/lsys.svg)](https://www.npmjs.com/package/@thi.ng/lsys) | [changelog](./packages/lsys/CHANGELOG.md) | Extensible L-System architecture |
-| [`@thi.ng/matrices`](./packages/matrices) | [![version](https://img.shields.io/npm/v/@thi.ng/matrices.svg)](https://www.npmjs.com/package/@thi.ng/matrices) | [changelog](./packages/matrices/CHANGELOG.md) | Matrix operations |
| [`@thi.ng/pixel`](./packages/pixel) | [![version](https://img.shields.io/npm/v/@thi.ng/pixel.svg)](https://www.npmjs.com/package/@thi.ng/pixel) | [changelog](./packages/pixel/CHANGELOG.md) | Multi-format pixel buffers |
| [`@thi.ng/poisson`](./packages/poisson) | [![version](https://img.shields.io/npm/v/@thi.ng/poisson.svg)](https://www.npmjs.com/package/@thi.ng/poisson) | [changelog](./packages/poisson/CHANGELOG.md) | nD Poisson disk sampling |
| [`@thi.ng/porter-duff`](./packages/porter-duff) | [![version](https://img.shields.io/npm/v/@thi.ng/porter-duff.svg)](https://www.npmjs.com/package/@thi.ng/porter-duff) | [changelog](./packages/porter-duff/CHANGELOG.md) | Alpha blending / compositing ops |
| [`@thi.ng/scenegraph`](./packages/scenegraph) | [![version](https://img.shields.io/npm/v/@thi.ng/scenegraph.svg)](https://www.npmjs.com/package/@thi.ng/scenegraph) | [changelog](./packages/scenegraph/CHANGELOG.md) | Extensible 2D/3D scenegraph |
| [`@thi.ng/simd`](./packages/simd) | [![version](https://img.shields.io/npm/v/@thi.ng/simd.svg)](https://www.npmjs.com/package/@thi.ng/simd) | [changelog](./packages/simd/CHANGELOG.md) | WebAssembly SIMD vector batch processing |
-| [`@thi.ng/vectors`](./packages/vectors) | [![version](https://img.shields.io/npm/v/@thi.ng/vectors.svg)](https://www.npmjs.com/package/@thi.ng/vectors) | [changelog](./packages/vectors/CHANGELOG.md) | Fixed & arbitrary-length vector ops |
| [`@thi.ng/viz`](./packages/viz) | [![version](https://img.shields.io/npm/v/@thi.ng/viz.svg)](https://www.npmjs.com/package/@thi.ng/viz) | [changelog](./packages/viz/CHANGELOG.md) | Declarative & functional data visualization toolkit |
### WebGL / GPGPU
@@ -297,20 +325,20 @@ feature or `develop` branches) -->
### Low-level, binary, memory management
-| Project | Version | Changelog | Description |
-|---------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------|-----------------------------------------------|
-| [`@thi.ng/bencode`](./packages/bencode) | [![version](https://img.shields.io/npm/v/@thi.ng/bencode.svg)](https://www.npmjs.com/package/@thi.ng/bencode) | [changelog](./packages/bencode/CHANGELOG.md) | Bencode binary format encoding |
-| [`@thi.ng/binary`](./packages/binary) | [![version](https://img.shields.io/npm/v/@thi.ng/binary.svg)](https://www.npmjs.com/package/@thi.ng/binary) | [changelog](./packages/binary/CHANGELOG.md) | Assorted binary / bitwise ops, utilities |
-| [`@thi.ng/bitstream`](./packages/bitstream) | [![version](https://img.shields.io/npm/v/@thi.ng/bitstream.svg)](https://www.npmjs.com/package/@thi.ng/bitstream) | [changelog](./packages/bitstream/CHANGELOG.md) | Bitwise input / output streams |
-| [`@thi.ng/dlogic`](./packages/dlogic) | [![version](https://img.shields.io/npm/v/@thi.ng/dlogic.svg)](https://www.npmjs.com/package/@thi.ng/dlogic) | [changelog](./packages/dlogic/CHANGELOG.md) | Digital logic ops / constructs |
-| [`@thi.ng/leb128`](./packages/leb128) | [![version](https://img.shields.io/npm/v/@thi.ng/leb128.svg)](https://www.npmjs.com/package/@thi.ng/leb128) | [changelog](./packages/leb128/CHANGELOG.md) | WASM based LEB128 varint encoder / decoder |
-| [`@thi.ng/malloc`](./packages/malloc) | [![version](https://img.shields.io/npm/v/@thi.ng/malloc.svg)](https://www.npmjs.com/package/@thi.ng/malloc) | [changelog](./packages/malloc/CHANGELOG.md) | Raw & typed array memory pool & allocator |
-| [`@thi.ng/morton`](./packages/morton) | [![version](https://img.shields.io/npm/v/@thi.ng/morton.svg)](https://www.npmjs.com/package/@thi.ng/morton) | [changelog](./packages/morton/CHANGELOG.md) | Z-order-curve / Morton coding |
-| [`@thi.ng/range-coder`](./packages/range-coder) | [![version](https://img.shields.io/npm/v/@thi.ng/range-coder.svg)](https://www.npmjs.com/package/@thi.ng/range-coder) | [changelog](./packages/range-coder/CHANGELOG.md) | Binary data Range encoder / decoder |
-| [`@thi.ng/rle-pack`](./packages/rle-pack) | [![version](https://img.shields.io/npm/v/@thi.ng/rle-pack.svg)](https://www.npmjs.com/package/@thi.ng/rle-pack) | [changelog](./packages/rle-pack/CHANGELOG.md) | Run-length encoding data compression |
-| [`@thi.ng/soa`](./packages/soa) | [![version](https://img.shields.io/npm/v/@thi.ng/soa.svg)](https://www.npmjs.com/package/@thi.ng/soa) | [changelog](./packages/soa/CHANGELOG.md) | Memory mapped data structures & serialization |
-| [`@thi.ng/unionstruct`](./packages/unionstruct) | [![version](https://img.shields.io/npm/v/@thi.ng/unionstruct.svg)](https://www.npmjs.com/package/@thi.ng/unionstruct) | [changelog](./packages/unionstruct/CHANGELOG.md) | Wrapper for C-like structs / unions |
-| [`@thi.ng/vector-pools`](./packages/vector-pools) | [![version](https://img.shields.io/npm/v/@thi.ng/vector-pools.svg)](https://www.npmjs.com/package/@thi.ng/vector-pools) | [changelog](./packages/vector-pools/CHANGELOG.md) | Data structures for memory mapped vectors |
+| Project | Version | Changelog | Description |
+|---------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------|-------------------------------------------------|
+| [`@thi.ng/base-n`](./packages/base-n) | [![version](https://img.shields.io/npm/v/@thi.ng/base-n.svg)](https://www.npmjs.com/package/@thi.ng/base-n) | [changelog](./packages/base-n/CHANGELOG.md) | Arbitrary base-n encoding/decoding with presets |
+| [`@thi.ng/binary`](./packages/binary) | [![version](https://img.shields.io/npm/v/@thi.ng/binary.svg)](https://www.npmjs.com/package/@thi.ng/binary) | [changelog](./packages/binary/CHANGELOG.md) | Assorted binary / bitwise ops, utilities |
+| [`@thi.ng/bitstream`](./packages/bitstream) | [![version](https://img.shields.io/npm/v/@thi.ng/bitstream.svg)](https://www.npmjs.com/package/@thi.ng/bitstream) | [changelog](./packages/bitstream/CHANGELOG.md) | Bitwise input / output streams |
+| [`@thi.ng/dlogic`](./packages/dlogic) | [![version](https://img.shields.io/npm/v/@thi.ng/dlogic.svg)](https://www.npmjs.com/package/@thi.ng/dlogic) | [changelog](./packages/dlogic/CHANGELOG.md) | Digital logic ops / constructs |
+| [`@thi.ng/leb128`](./packages/leb128) | [![version](https://img.shields.io/npm/v/@thi.ng/leb128.svg)](https://www.npmjs.com/package/@thi.ng/leb128) | [changelog](./packages/leb128/CHANGELOG.md) | WASM based LEB128 varint encoder / decoder |
+| [`@thi.ng/malloc`](./packages/malloc) | [![version](https://img.shields.io/npm/v/@thi.ng/malloc.svg)](https://www.npmjs.com/package/@thi.ng/malloc) | [changelog](./packages/malloc/CHANGELOG.md) | Raw & typed array memory pool & allocator |
+| [`@thi.ng/morton`](./packages/morton) | [![version](https://img.shields.io/npm/v/@thi.ng/morton.svg)](https://www.npmjs.com/package/@thi.ng/morton) | [changelog](./packages/morton/CHANGELOG.md) | Z-order-curve / Morton coding |
+| [`@thi.ng/range-coder`](./packages/range-coder) | [![version](https://img.shields.io/npm/v/@thi.ng/range-coder.svg)](https://www.npmjs.com/package/@thi.ng/range-coder) | [changelog](./packages/range-coder/CHANGELOG.md) | Binary data Range encoder / decoder |
+| [`@thi.ng/rle-pack`](./packages/rle-pack) | [![version](https://img.shields.io/npm/v/@thi.ng/rle-pack.svg)](https://www.npmjs.com/package/@thi.ng/rle-pack) | [changelog](./packages/rle-pack/CHANGELOG.md) | Run-length encoding data compression |
+| [`@thi.ng/soa`](./packages/soa) | [![version](https://img.shields.io/npm/v/@thi.ng/soa.svg)](https://www.npmjs.com/package/@thi.ng/soa) | [changelog](./packages/soa/CHANGELOG.md) | Memory mapped data structures & serialization |
+| [`@thi.ng/unionstruct`](./packages/unionstruct) | [![version](https://img.shields.io/npm/v/@thi.ng/unionstruct.svg)](https://www.npmjs.com/package/@thi.ng/unionstruct) | [changelog](./packages/unionstruct/CHANGELOG.md) | Wrapper for C-like structs / unions |
+| [`@thi.ng/vector-pools`](./packages/vector-pools) | [![version](https://img.shields.io/npm/v/@thi.ng/vector-pools.svg)](https://www.npmjs.com/package/@thi.ng/vector-pools) | [changelog](./packages/vector-pools/CHANGELOG.md) | Data structures for memory mapped vectors |
### DSLs
@@ -381,7 +409,7 @@ https://github.com/thi-ng/umbrella-docs-temp
## License
-© 2015 - 2020 Karsten Schmidt // Apache Software License 2.0
+© 2015 - 2021 Karsten Schmidt // Apache Software License 2.0
## Contributors β¨
@@ -392,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/diagrams/mesh.drawio b/assets/diagrams/mesh.drawio
new file mode 100644
index 0000000000..38f6a12090
--- /dev/null
+++ b/assets/diagrams/mesh.drawio
@@ -0,0 +1 @@
+3VZNb5wwEP01SO0hFWuHzV6zZJseUvVApDZHL56AK4ORGb7y62vAXkCk21ZKtFIv4HkzDw/vmdn1aJi195oV6VfFQXrE561H7zxCAuqbaw90I3C9IyOQaMFHaDMBkXgBC1peUgkO5aIQlZIoiiUYqzyHGBcY01o1y7JnJZe7FiyBFRDFTK7R74JjOqK7wJ/wLyCS1O288W0mY67YAmXKuGpmED14NNRK4bjK2hBkr53TZeR9/k321JiGHP+G8HhV1Zzy8PH2pThinT/cfCuurm1v2LkX1qrKOfQc36N7pTFVicqZfFCqMODGgD8BsbNWsQqVgVLMpM1CK/BHT/9EAhs+zVJ3rX30EHQuyFF3Iytw4dM8N9GGyPHG9oGvTJxUsVCpKh3DGSnc6WI6ATxTR07emTMPKgPTj+FpkAxFveyD2dOXnOomg8zCevQPfgUrv/p3j2yYq9zc9m9o4c1/aSG9pIX2uTWTld3pFlGLY+mRrTRd74/arBIc9EXIuUn4hzC6N7YWf/hcm1QgRAUbVGrMQF76ancGjdCeF3stjiXs7DTr3Ji2cTMNx42beOlsMG79d5KTrOQs1CtSfqghph8vJ5/Vi1xcL7rSq6pfkavsZwPxyQUlc4Tt8si9p4QmnH6Qh9zsXw09/AI=
\ No newline at end of file
diff --git a/assets/diagrams/rstream-event-loop.drawio b/assets/diagrams/rstream-event-loop.drawio
new file mode 100644
index 0000000000..d003b2117c
--- /dev/null
+++ b/assets/diagrams/rstream-event-loop.drawio
@@ -0,0 +1 @@
+7VzbcqM4EP0aV2UfkuKO/RjfZqZqJklNtmaTpy0ZFKONQJQQsT1fv+JmwHISj0MskYpfjBoJiz46re6m8cCchOsvFMTBD+JDPDA0fz0wpwPDMFzL4F+ZZFNIdNPRCsmSIr+U1YJb9BuWwqpbinyYtDoyQjBDcVvokSiCHmvJAKVk1e72QHD7V2OwhILg1gNYlP6DfBYU0qGt1fKvEC2D6pd1rTwTgqpzKUgC4JNVQ2TOBuaEEsKKo3A9gTjTXqWXYtz8mbPbiVEYsUMGPGnrq8WGOPr4Ub9n6ygZulfnenmZhG2qO4Y+V0DZJJQFZEkigGe1dExJGvkwu6zGW3Wf74TEXKhz4X+QsU2JJkgZ4aKAhbg8C9eI3TWO77NLXdhla7our5w3NlUjYnRz12w0RmXNeljeqsYV95fd1LN6q3RAUurBl5RVrj9Al5C90M/aost5AUkI+Xz4OAoxYOipPQ9Qrs/ltl8NIT8oUfwTRIvrPgGcVoA+8TtNBJzbKK4CxOBtDHIFrDiZ24g9IIwnBBOajzUnk/l85my1+wQpg+uX9SvqoxxwrlcMqWxE1V7VhNvKggbZLO29dGh/dFbAyL/MrCNvLjDxHgvRHOFqMh3SxjiQNkOptBnJhLyG+b6J8iuQX7h2C/UeYu7IxNwYSsW8RXPjQJ7rbZ4bfSS6KxN0U6rH0ya6fhzR9R5ibksluuATJQww2KlLNBrN+acbl8jSlPOI5JrK47ZHZUlj9sEjMgXS/Lycv40yHVDDdtrUMDTZ1DA+g4UOqWH1wYewJFtD92OZw0Mxt6RGC7Zkx9E9ynNUNkI8FHRbk8p0YRO8SRe36aJT17HLbJqlmudoaoKulN8eG2G1arbSPpA2hlTX0ZBrKo23m8o+Yv6MZTjR9ihYyqvZ3d/K2klDUy6OMHtvKFXyL5xeGEqpmO8YytcCCfWwk2rwHNE1/Dn71RuDZ0m3d6469s49LnHiqpQ5cftg8FyRNJdfZv9+v76czqa94Y78qEp31CFP/5OOwwOpM5JJnaFAnQT50AsAim4AZYghEnXKoOx51mTSDYN20/YKMEih7af/DBod6rFJzeaNBAqBOD77S1nWuMpVxlX1vB+XNT5Ignyu+okpVFU8v8ohU2otRTXNBonS2AcMTq9/KEyl4VA1KplSXbjjCpF6QiXzVBnTfCi/LbBpdIgJKuutyyvfZIJ6KdbvCFS5x9FO5f7OAO7tv3GAbmk767WYdL16t3f/hr1BfFjGbUKGaVaAPjAczKEYLyg/WmZHGCUMRpCKpemc5qy9bClM0G+wyDtkS6vUMe9tjwf2lEsARsuICzz+W5AbkHFmLpAH8GV5IkS+n3MIgwXEY+A9LnM2NQzOQ/55yeCUr5mUMxlsX+5ortIX2P6seTrXLkZmFdRVKBetP1uM4lowWhd12uPJw0PCGbJryzpYDab4QCBfDYruD7qm3pNTMVkyK5ikBSDiazljzi6pzpJ0kXgUxVk4mIj7cRKAODuMCIOvK3yxZcl1yjCKYCn3AX285qMQy239hWbvRycviEyKvcjoqAJMH7WBMvcBZe0Bynk3oMTQ/FsYpoWVEBDiIUcOSV6AKsLHKAShSrjpw25wM9XDTYwHbzeRF1AS8c2myKfsArRCfK6Gtq8UUiK1tI6yNLZqEFlitBH4JMx34jAm0V7HglMIZj04k/YmxfoPlKsrB5T43mHh/BXB4QfEYOgqh4HoclUOA4ridA9Tit1GJXA6chLOdVM5dKS+YfjREs7WoTUCUmuGLbFIQFwEGKM4OYBnAnUmk86in539ZE9xwD6uvFvoY+9R0ydXjuVK5dWp/ZKeLbp6veDKvsrB05JFfFPrF8DIfyaCOWMURImfepCqFGZ2tvMbr8Nz2jyOLeZFP/E5RR0ab9Z/r1PkNet/KTJn/wM=
\ No newline at end of file
diff --git a/assets/diagrams/dot-example.dot b/assets/dot/dot-example.dot
similarity index 100%
rename from assets/diagrams/dot-example.dot
rename to assets/dot/dot-example.dot
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/assets/diagrams/hdom-v5.xml b/assets/hdom/hdom-v5.xml
similarity index 100%
rename from assets/diagrams/hdom-v5.xml
rename to assets/hdom/hdom-v5.xml
diff --git a/assets/diagrams/hdom.xml b/assets/hdom/hdom.xml
similarity index 100%
rename from assets/diagrams/hdom.xml
rename to assets/hdom/hdom.xml
diff --git a/assets/idgen/idgen.drawio b/assets/idgen/idgen.drawio
new file mode 100644
index 0000000000..cfa12e4cb6
--- /dev/null
+++ b/assets/idgen/idgen.drawio
@@ -0,0 +1 @@
+7ZZdb5swFIZ/DZeRAIc0u1xo6CY1UqdMinrpwilYNT6RcQLZr9+hGBLqfmxSl120uUjs19/PYyI8FpfNlebbYoUZSC/0s8Zjl14YRsyn7zY4dMF0HnZBrkXWRcExWItfYEM7Lt+JDKpRR4MojdiOwxSVgtSMMq411uNu9yjHq255Dk6wTrl0043ITNGl88g/5t9A5EW/cuDblpL3nW1QFTzD+iRiS4/FGtF0pbKJQbbsei7duOSF1mFjGpT5kwG3m8lhn0/Svblkm5+3s7urH3JiZ9lzubMH3oOuBCq7Z3PoQWjcqQzauXyPLepCGFhvedq21mSessKUkmoBFe9RmYSXQrbWvy9WNNWNhIZ+Vqiw7SCkjFGifpycJfSJY8rtdkAbaF48ZzDQo1sHWILRB+piB0wtb3vhgp5/faLPRsWJuX4YtxcmHyY+MqWCxfoXiEMHMXU/K904TpLl7H3oDjhfwTuwPAtf5vCdU/VOmMqhTMc2Y5SV0fgAPSuFCp7gsxGXIldUTQkTUL5oIQr6m/hqG0qRZe0yz7ob231T3ztoip5YunAtzZ6RFP4rSVNHUjj9tBT60ZuaLs6pKXI0Xa8XH1gQC8bP0Zf/7Gfm+Fl9aD/hufRQ9fim9th28rrLlr8B
\ No newline at end of file
diff --git a/assets/ksuid/ksuid.drawio b/assets/ksuid/ksuid.drawio
new file mode 100644
index 0000000000..1853ff7c49
--- /dev/null
+++ b/assets/ksuid/ksuid.drawio
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/ksuid/ksuid.png b/assets/ksuid/ksuid.png
new file mode 100644
index 0000000000..e5ec002279
Binary files /dev/null and b/assets/ksuid/ksuid.png differ
diff --git a/assets/malloc/malloc.drawio b/assets/malloc/malloc.drawio
new file mode 100644
index 0000000000..564481357f
--- /dev/null
+++ b/assets/malloc/malloc.drawio
@@ -0,0 +1 @@
+7V1bc9o4FP41mck+JOMbjnlsyKWd3c5kN7Oz7VPHYAHe2hY1oiH99SvZljE+h0sbkGSWPBAsy8Z8Ouc7R58uXLiDdPmYh7PpRxqR5MKxouWFe3fhOH3P56+i4LUs8AOrLJjkcVQW2auC5/gHqQpltUUckflaRUZpwuLZeuGIZhkZsbWyMM/py3q1MU3WP3UWTggoeB6FCSz9J47YtCwNetaq/D2JJ1P5ybZVnUlDWbkqmE/DiL40itz7C3eQU8rKd+lyQBKBncSlvO5hw9n6wXKSsX0u+PLh78X8z4d08X70b/Rt+OPbB/J05farh2Ov8huTiANQHdKcTemEZmFyvyq9zekii4i4rcWPVnX+oHTGC21e+C9h7LVqzXDBKC+asjSpzpJlzD5Vl4v3n8X76151dLdsnLp7lQcZy18/NQ8aV4nD1WXFkbxuTDP2EKZxIgo+3H7kX/YpIUv+7yPNaFE9eicMhZ8eJnT0tSx6iBP5tHMW5kxWyWhGZFlVR3wKbIyqfeZ0kY8qZNPbp9tv6R+Pf/716L/r/Z69fxzGV9Kow3xC2JaWcipHEs3T+ISqrR8JTQn/2rxCTpKQxd/X7Tes3GBS16su5d8rfG1UmNE4Y/PGnZ9EAa9QObS05lfppi2j21XdX6vP35QPII8a32RVVBgybtTbIP0eJosKBcYN0/HDlJvnbTacz+oWa9j9ulW/TGNGnmdh0XYvnNrWLXinVY25bQxoQvPi5m6//8D/thnKd5IzstzastXZYB1TefiyoidHktC0QU2etdkUGu3x83A7AG7uPycLt+0oxBvn7JszZ+vlbBdyNlqvf2jKfpOfusBPxzkhah1zMHh4uPcP65j6HNE/O6JeR+zt6Yi2Z0Ty5K2HEn977tSu7ShInXqAIxZzbqxKOUKE7sHgKMHb050r+QDfMIkn2elkR75uhG9glEvCyfxkEK7R1IZwHyA8F7Gq83lEBbCrMsHHo5UFEM7IkqlF+O6OI3x/HIS1k4QNJYIifbHVYixoooh04kKZNiLC3tvD3p6A1/R9eMQ9A1jjiJmFr5KW8d5ID4B57o2olXKR7gjaVHaVpBgiDNgw61cfb47pm9rTfhvm/YWBOuox7vePH2/8faWZ4FhkCOP7ZeHnFyK54yZmWUsr+I3/vxKfHkU5mfMugkXH/KW0ff7vhb+WPCKeOoxIDpqLibo/1yYHgNttSQNBD8BtY3C7x4IbBncI90jCXYwOtEFPwyycCKWBc94kprBHbAbStoNA7aqEGnI1hNqSUBeClDBbi8dtxxrH+VxULHXfbti2DalELeCQuiHg3g7ASxGtG4B7ui0cKjgAcLu2cAlpIaOlpNBPRzQbxxND4bV93fgGe+BbG/SQTMPvMRUWXelo1jBmaTgXoF+OaMqTk/LKB4H2LInZb4Yi71i6kYfKWWG2AH6Hx9OBiIwzNr8uqrTNPQpZaCjMHmLgdWatBGZEP7uU8k6BYjP5k4iWaoR1GWej5LrB0VY9k6F8LeCKojibmGrnrvYcBZHXQAPUDJMVgXKRs2kBdzM3EWwTZyKYTmPxnix5GyRQNDIEd8TwXaVpuO1sIJga/JJhysPr0uQB0RgJ7g1C3opZBc6fuJSdeGDUrTyw6lJ2KQ30teeBiGQMABc0vj7RbB9Ob09N6xjB+9oTGRvm6Cel5gfa1XwbZul6NNkjjQEGKjVZHGGYjRe84arHWIUmG+yrydYTXA+OuLMpLXT/54QeIITu9lUSugMzR9A0Hto0rfS9meJ0K30PtCc8DswwG+m7ONNI351Ope99pE+qNn13oI5bm3MiECLpjL3WRRNWA3G0SHB4krct7WHVQeTbqvsjWbxB9UYaK0dRNxXIGzdQTOPsWciratOTY85k1G6r7h7DxHatFPIGuIa5yLjQxgvhm/EUw1CTVjqq8/kdGT5f2U9frfvl4Pfl8kuWBpg2BbBC5u+szdiRhc35R3B+T+O4/ITWNBsEWohjA6ceApMs+7n1AmCKfy0PAv6W9ygnHVWXrZpg553qHqy8UTkpCdzoFxYO4M0LcxeYlrd8Z0PWvmnFIPSknPAbhcOiguC+av0Fr927vejdiR5AMbvevRuRQo5zb4ULxaMweVedSOMoKmbCJeGQJLfh6Ouk4NMGBY6LP/FxlPHGpuKyq/5eE9I2uG29XL169ot6nWzTMre40Ua/t66twHXXLMF9m6XKKnQ8npPjmA7U+c7MwP35urfdo3+VGnzV1ACnrJyp4RjU4J0eNWCdtjM17PDnXyUGt638HZsYYFfxTAzHIAb/5IgBkZLnP0Drqxx+QhpsD8bAl/ra2DJKTC07RM8YxVfzvkD1ApLPjTO7FpOs1o/UV21ZTLLPUpCd60n2dObdsWR9dQlu8lXoa64uwStuyAMOvphk62M2By41ryV5k2u2FVbtromMEqCzAdWMWh4A4XrAcRvEdSU1GCOrFTscXtx9EFZqxPLG5/hiTnxBVi/iuUFPa3xBFit2Ob7Ui+GN8U1kpLTbAcZrq+xKdynBMYZdX2tpjwMA8i8PHx22P+IiEVnp8JED58NZy7rNtAMGcxj9iMH5bbMwOrIXHwDKvTrDgUpnRQbjxRodU5wVZnfabQ8ZWOeI9UzxVhgQ9CMGu82d8FZ/n9iqVrqC/WNue6Ep3uqbF1td2NvliA1N8dYbA/kNdkK6rA9Am9TuxLAPoqWX11j98DaEjZMRXdgD6XYvD9KEdhnRhZ2WTgT1wDg+8PSP97W2nDxo/9q50Yyv7wAwz3qsXj3WQ3aZRyv2bnBbU6PHejDdVh6pD+ma4OcedLumB7Nz9fv21zuVHgBhoJVhEKuVY73TyueBIqTfiGG22el8Hoza6EcY5prdzueBSGcATUBJ3eRRG2yBlVqdRCq+XRm1MQAxB0PM3LEGAxBD9V5zxxoMQAxmlJ2QJcBYg/ag24N5o9FjDQbYHhR2jR5rMAAxZK+lDktf0Ca1OzGy1ZLmX1s57FiDfoRh3txtCQPSBAJxLZqrUXBhGtRlmmizRL0dkjaF3IB5p4dkiTZJ6AcYZgbdJgnQu8QgvlFKEpKlOiJgYD8Upjb5ukEnspkrYOhHLICx/pTiUA/5dUClNNmHFnlScUg/wM6pxyEM4p7SiTF9TAUwNw55SOBWy6p9bL2IwXFIP2K2hYZuc7U5EyCD1Ge0OGcCZJDJujxzAFil9nBsWyc2dQDIcwZAfGpzBwBTYBirnQtsWx1djwcmA+u3V+QHnrrcxwT5JvaDtYoRPrFeJuhmGgDxqfUzwdwQDGNXLeki29J2OT0zjygcvb86f144gBl9Nb9n58oBe5O5qVk6YCM7/3Z6LxcDgwwctex2Zg+UJgxjpbtD2MgmtSaLmb7KX9TegFjH1EwTIEP3v3FNMTIjrQybrV8/qHbIYLqsHzL5SF3TKJz2zGD9kdeBPegu9zyAMGwAwrADfVrCsAEQn9pes0AYxjBWLAwjm812gnSBMGyAvaKrC8wd8zUh5KO5uLljvseEjB/mlLLGuUfuWdOPNCKixn8=
\ No newline at end of file
diff --git a/assets/diagrams/rle-layout.dot b/assets/rle/rle-layout.dot
similarity index 100%
rename from assets/diagrams/rle-layout.dot
rename to assets/rle/rle-layout.dot
diff --git a/assets/diagrams/rs-dot-example.dot b/assets/rstream-dot/rs-dot-example.dot
similarity index 100%
rename from assets/diagrams/rs-dot-example.dot
rename to assets/rstream-dot/rs-dot-example.dot
diff --git a/assets/diagrams/q1.dot b/assets/rstream-query/q1.dot
similarity index 100%
rename from assets/diagrams/q1.dot
rename to assets/rstream-query/q1.dot
diff --git a/assets/diagrams/q2.dot b/assets/rstream-query/q2.dot
similarity index 100%
rename from assets/diagrams/q2.dot
rename to assets/rstream-query/q2.dot
diff --git a/assets/diagrams/rs-query1.dot b/assets/rstream-query/rs-query1.dot
similarity index 100%
rename from assets/diagrams/rs-query1.dot
rename to assets/rstream-query/rs-query1.dot
diff --git a/assets/rstream/event-proc.drawio b/assets/rstream/event-proc.drawio
new file mode 100644
index 0000000000..5194d0fa72
--- /dev/null
+++ b/assets/rstream/event-proc.drawio
@@ -0,0 +1 @@
+7VtZc+I4EP41VO0+kPINPHKYmVRNjgqZ2s3TlMAy9o6wWFlOYH79yEbypXCEI4Jk8hKr1bJlfd2fulumYfZniy8EzIMb7EHUMDRv0TAHDcPQWx2H/UslSyFpayvJlIQelxWCUfgLcqFQS0IPxhVFijGi4bwqnOAoghNakQFC8EtVzceo+tQ5mEJJMJoAJEv/CT0arKRtWyvkX2E4DcSTdY33zIBQ5oI4AB5+KYlMt2H2CcZ0dTVb9CFKV0+sy2rccE1vPjECI7rLgEcU2XP8ze664MnB97oPe37T5HOjS/HC0GPvz5uY0ABPcQSQW0h7BCeRB9O7aqxV6HzDeM6EOhP+ByldcjBBQjETBXSGeC9chPTfdPiVzVtPpZ7Bgt85ayxFI6JkWRqUNp/KfcWwrCXGrd4vfam1y8ZFMU7IBG5YK2F+gEwh3aBn5OAyt4B4Btl82DgCEaDhc3UegJvnNNcrEGQXHMQ3AMrv+wxQwp80ogSCWcNwwIzB00Ns6j33OX17IZrSfKFKhlCF+SUIKRzNQbZCL8zZq5D6OKJDMAtRuu7XvRt2q3sEF+zfDY5S+P0QoT5GmGQ3NweD4dB188c+Q0LhYjNC8oryAYagFM4xTYu3XwqH1YUXBiVnFXpHB8Ew1LqVsZdfGW9yrK2IQzTO6C7FNmSEykSThDxnb6gf1zONHT3TVumZxofn2q0moQByfQ13vBPmllrMW2cAumqn15Xux4a0H98n41EyPvF2e4JtVfmuajkXSKBH3lSP6D/2rv5jHeg/2dAuIWBZUpjjMKJx6c73qaCwPr1mfYZTy27q+tph+s0t+lZroz67WL1hYd75Uu1v8bZEHixmzwL41FDSdBZwiJ3/kzSP7Mk2k3exqyzQf7j7/uj+6H/t3n5xB+J+YyK6V+nCaBlN5D4hYS+zmoBzjNShmhl0OkP2dxwKy/lJGIWmnMPsC+Sws6UwfdeUXA2HmVbN/NqbOcapc9gb9Ztb9O3N+qfhMF2uSFzf9n/0777fProPm/nnPSsSx+Sdeuh0BryjOBHZi3da50s8OycfSoin7ujbgiH7jcFWXX9b8GSbCoIngVGJeAbuByceq77jKCceY5+Ap1IyUF4XPWMasnakIbWFz33y9lOZwGe1AMV10NYZmcB+RdGPYANKK6HmxZx/KCtp74ykqRRJMc0th8wjCij8KIfM9chK/SGz2TkjTv1YdSVz1/TOPDS9O8wC5AyH+5w2TnwfkhO72xHcyqllkrkLqauU6NKq/XGrI7nVrtubpb1uNO/kVvL2FniYbW5aMvcy97o0r1JfBjD/JAAn9Ktdj3LVho1mW/KrOPTS3WoSgDCSDITZP61CSGAc/gLjTCFdZF4HZdp2r2EPmASgcBoxwYQtItv/zJ74+qzLO2ah52XGhcAYoh6Y/JxmllUKG/3s7yBX5V8j86k28m+Ay+hu8JO1jt3UrnTHaVWcm6dVb6soFyVaoYJ9P2bGUwf5CIVYUz7G9gmePXSHf/19eVyqPvC3LiaRvoSgRMC0vXpyIHfudZLTqqWd4kh57ZHwgfpN8V3MugH1M+36gNOc5YiHls9y7lKzgKsP2TUUxozvI0jiy2OU/LRYHaO0pOW9juYJlQ/J4qzOIy9yHIB5ehlhCrev8jjfdu8SisIIcrkHyM87NiqkGRNcabZc1EkPy/r9d4JKHFTm1m6/ApX1ClT2yaCSg6gBRHDKOAjLIdQngcVUjkpHQkX8xKbmQAGIPLa0088Kld5RjZUtf5DU49UyLYloiGTQojQTMTQWsX4W2Nq1bV7XbRm29rvCJhc7MzxYrpVkud4nRSb/pPQEyLBm8fvUVSxX/MzXdH8D
\ No newline at end of file
diff --git a/assets/rstream/event-proc.png b/assets/rstream/event-proc.png
new file mode 100644
index 0000000000..650a19e1f3
Binary files /dev/null and b/assets/rstream/event-proc.png differ
diff --git a/assets/diagrams/rstream-constructs.xml b/assets/rstream/rstream-constructs.xml
similarity index 100%
rename from assets/diagrams/rstream-constructs.xml
rename to assets/rstream/rstream-constructs.xml
diff --git a/assets/soa/aos.png b/assets/soa/aos.png
new file mode 100644
index 0000000000..9459a71883
Binary files /dev/null and b/assets/soa/aos.png differ
diff --git a/assets/soa/aossoa.drawio b/assets/soa/aossoa.drawio
new file mode 100644
index 0000000000..f32fd4537d
--- /dev/null
+++ b/assets/soa/aossoa.drawio
@@ -0,0 +1 @@
+7Zvfj6IwEMf/Gh/XAC2Ijyund5uct3fxkntmpQrZQg3WX/fXX1mLSouJ5ty0meCDoQMU+My00++IPRTl+69lvEqnLCG05znJvoe+9Dxv4GLxXRkORwMOvaNhWWbJ0eSeDbPsL5FGR1o3WULWjQM5Y5Rnq6ZxzoqCzHnDFpcl2zUPWzDavOoqXhLNMJvHVLf+yRKeHq2h75zt30i2TOsru47ck8f1wdKwTuOE7S5MaNxDUckYP27l+4jQil3N5Xje5Mre042VpOC3nPBK3vDL+vev7+F7Grg/Zq/rp+1T7Z5tTDfyiVds3d/LW+aHmkPJNkVCqq6cHhrt0oyT2SqeV3t3wvHClvKcipYrNhes4JM4z2jl9JfRVHT1kxLRqTNlBZMHSF+7VX+LjNKIUVZ+XAwNh5NJFAm7vDlScrK/+tjuCaYIQsJywsuDOESegCV+GX9eINu7szdrU3rhyPq0WMbP8tTxGbHYkJTvIe63Ej+YJR44E+c5fAzx0xCwBnmgId8SajrIg2AiPg9CHtiGfNCK3HCU+6MxGqPHID/N69YgDzXkVW4zCryK8EdN5F5oG/Ah9NyJbEue9ZiDmzyxbcmzfgS4yRPbljw9D3ry9G1Lnh6CnTx925KnpwvPfr+vARdPzJtU17xk76TGVLCCKOSkKabZshDNuSBEhH1U8cuEsH+WO/IsSarLtLqx6ej7PVm15VO4D3BfoCbige4+3OI+79Pc165iAa19FOIYmx4wuogFtvRR6wbmkesiFliQq3UD88h1EQssytW6gXnkuoztMvHNVQjsG87ESJfEwPQZsm3EoHZJDEifITXKjSNvl8SAohzbtuBEuiQGFuW+bQtO1Inie9ynLl6Np2JdFIMqIgXWjRddE8MCbps8Q+AVsZKFkek6KWoXxICIq2Uf88g7QfwfJSRkujRdXwxwCcm2EYN1QQwNuRrlxpHrgribpG4uIZmfpNrFNaB6BrJuxOjiGhhyrEa5ceS6IO4mqevuC22bpNrfm4ZUAbRuxIB/b1p9E8k8cl1hd5PUzW8imZ+kdLUOqwZo23ipq+xQgQ9sKwH6urruJqir7gvV4ojpCcrvlPo9o0992ePzftQTzfO/bz/2XfyFGY3/AQ==
\ No newline at end of file
diff --git a/assets/soa/hybrid.png b/assets/soa/hybrid.png
new file mode 100644
index 0000000000..38f490de85
Binary files /dev/null and b/assets/soa/hybrid.png differ
diff --git a/assets/soa/soa.png b/assets/soa/soa.png
new file mode 100644
index 0000000000..feb3893ea0
Binary files /dev/null and b/assets/soa/soa.png differ
diff --git a/assets/text-canvas/text-canvas.drawio b/assets/text-canvas/text-canvas.drawio
new file mode 100644
index 0000000000..aeb5f9a94c
--- /dev/null
+++ b/assets/text-canvas/text-canvas.drawio
@@ -0,0 +1 @@
+7Zpbj6IwGIZ/jZeTcFYvBUFNRtfVMXPNSpVmC3WxLrq/fosUOdTJuomSktQLAy898T608H3Q053oPEn8QzjHAUA9TQnOPX3c07ShYdH/TLjkgjVQcmGfwCCX1FJYwz+AiUWxEwzAsVaQYIwIPNTFLY5jsCU1zU8SnNaL7TCq93rw94AT1lsf8eonDEiYqwNTKfUpgPuw6FlV2JHILwoz4Rj6AU4rku72dCfBmORb0dkBKPOu8CWv531x9DawBMTkkQqpMfq1VD2SLn9c4MJZfj+OP95YK799dGInzAZLLoUDCT7FAcgaUXq6nYaQgPXB32ZHU4qcaiGJEN1T6eYOIuRghJNrXd2jP8ehOusGJAScvxy/enOFXk0AR4AkF1qEVdAsZiS7ktTC2LTChUlhBYnBNJ9dCftby6VZdIP59R/ead3xThfNO71D3hn/9k5r0zujO95ponlndsg7TTDvrA55pwjmXb873qkDwbwbcN55E849er6kbtGRJPgnKEyKcQwavjHJR3Af090kPxU7Mw/SB8AR0yMYBFkvd5HUoe1wTDw/giizbmbP6RCXiILQlDmO8bU48QnEWbNvQ+VJ96cmrwHPy7jDS3sVr+FdXoq9mk2mHxJcCU416+CGJgeu3ya4IuaqkLPlTKvcVUSbaSofvtlyqt0jJ9xU44NH+9v7WCKrIBNtsvEx63g2l8TKB8ehaMT4SHmzGLur99nCldxKbn3RuL04Snccz3Ot55hnPJDh0FsNl9Rnx+nPuMQeyGVYrZrEB+SbxWbtyjtwBZou2rrAZwKc6Wglkd2QmcJFKHwyIFufFHv2ivAEgV0nqfXr0UmfD07MNqEVDVegGZJZI3kjGjM+FaBKZg1mmmDM+CSAZMa9BROMGZ8FkGtjk5loayOfB5DzjHtjKhgzPgcgmXFvagVjxmceJLMmM0swZnwiRJfMmtmrtpjR3fKD0Ouxyle1uvsX
\ No newline at end of file
diff --git a/examples/README.md b/examples/README.md
index 2a979f8ed6..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 98) 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,50 +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 | | [todo-list](./todo-list/) | Obligatory to-do list example with undo/redo |
-| 088 | | [transducers-hdom](./transducers-hdom/) | Transducer & rstream based hdom UI updates |
-| 089 | | [triple-query](./triple-query/) | Triple store query results & sortable table |
-| 090 | | [webgl-cube](./webgl-cube/) | WebGL multi-colored cube mesh |
-| 091 | | [webgl-cubemap](./webgl-cubemap/) | WebGL cube maps with async texture loading |
-| 092 | | [webgl-grid](./webgl-grid/) | WebGL instancing, animated grid |
-| 093 | | [webgl-msdf](./webgl-msdf/) | WebGL MSDF text rendering & particle system |
-| 094 | | [webgl-multipass](./webgl-multipass/) | Minimal multi-pass / GPGPU example |
-| 095 | | [webgl-shadertoy](./webgl-shadertoy/) | Shadertoy-like WebGL setup |
-| 096 | | [webgl-ssao](./webgl-ssao/) | WebGL screenspace ambient occlusion |
-| 097 | | [wolfram](./wolfram/) | 1D Wolfram automata with OBJ point cloud export |
-| 098 | | [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 88a1afb473..ede714e3de 100644
--- a/packages/adjacency/CHANGELOG.md
+++ b/packages/adjacency/CHANGELOG.md
@@ -3,25 +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.3](https://github.com/thi-ng/umbrella/compare/@thi.ng/adjacency@0.2.2...@thi.ng/adjacency@0.2.3) (2021-01-10)
+# [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.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 74ecc10af6..45b5dc0ebd 100644
--- a/packages/adjacency/package.json
+++ b/packages/adjacency/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/adjacency",
- "version": "0.2.3",
+ "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.8.5",
+ "@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.29",
- "@thi.ng/checks": "^2.8.0",
- "@thi.ng/dcons": "^2.3.6",
- "@thi.ng/sparse": "^0.1.61"
+ "@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 34925c665a..94782b3f4b 100644
--- a/packages/args/CHANGELOG.md
+++ b/packages/args/CHANGELOG.md
@@ -3,6 +3,25 @@
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)
+
+
+### Features
+
+* **args:** add defaultHint opt, update usage() ([f8a4146](https://github.com/thi-ng/umbrella/commit/f8a414605a0d5c93fcef83ab931911c6c2f39f7d))
+
+
+
+
+
# 0.1.0 (2021-01-10)
diff --git a/packages/args/README.md b/packages/args/README.md
index fd28ef4ca2..fed01f672e 100644
--- a/packages/args/README.md
+++ b/packages/args/README.md
@@ -61,7 +61,7 @@ yarn add @thi.ng/args
```
-Package sizes (gzipped, pre-treeshake): ESM: 1.79 KB / CJS: 1.92 KB / UMD: 1.92 KB
+Package sizes (gzipped, pre-treeshake): ESM: 2.03 KB / CJS: 2.16 KB / UMD: 2.10 KB
## Dependencies
diff --git a/packages/args/package.json b/packages/args/package.json
index da312c2098..bffd4493ea 100644
--- a/packages/args/package.json
+++ b/packages/args/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/args",
- "version": "0.1.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.13.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",
@@ -61,9 +61,11 @@
],
"keywords": [
"argument",
+ "ansi",
"cli",
"coerce",
- "convert",
+ "color",
+ "conversion",
"declarative",
"functional",
"hex",
diff --git a/packages/args/src/api.ts b/packages/args/src/api.ts
index 12f7e9137c..228615a227 100644
--- a/packages/args/src/api.ts
+++ b/packages/args/src/api.ts
@@ -4,6 +4,7 @@ export interface ArgSpecBase {
alias?: string;
desc?: string;
hint?: string;
+ defaultHint?: string;
fn?: Fn;
}
@@ -92,9 +93,21 @@ export interface UsageOpts {
* @defaultValue true
*/
color: Partial | false;
+ /**
+ * If true (default), display argument default values.
+ *
+ * @defaultValue true
+ */
+ showDefaults: boolean;
}
+/**
+ * Color theme for {@link usage}. Each item is an ANSI color code:
+ *
+ * https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit
+ */
export interface ColorTheme {
+ default: number;
hint: number;
multi: number;
param: number;
@@ -102,6 +115,7 @@ export interface ColorTheme {
}
export const DEFAULT_THEME: ColorTheme = {
+ default: 95,
hint: 90,
multi: 90,
param: 96,
diff --git a/packages/args/src/parse.ts b/packages/args/src/parse.ts
index 385562bb46..99265d00ab 100644
--- a/packages/args/src/parse.ts
+++ b/packages/args/src/parse.ts
@@ -5,97 +5,140 @@ import { camel } from "@thi.ng/strings";
import type { Args, ArgSpecExt, ParseOpts, ParseResult } from "./api";
import { usage } from "./usage";
+const HELP = "--help";
+
export const parse = >(
specs: Args,
argv: string[],
opts?: Partial
): ParseResult | undefined => {
opts = { start: 2, showUsage: true, ...opts };
+ try {
+ return parseOpts(specs, argv, opts);
+ } catch (e) {
+ if (opts.showUsage) {
+ console.log(e.message + "\n\n" + usage(specs, opts.usageOpts));
+ }
+ throw e;
+ }
+};
+
+const parseOpts = >(
+ specs: Args,
+ argv: string[],
+ opts: Partial
+): ParseResult | undefined => {
+ const aliases = aliasIndex(specs);
const acc: any = {};
- const aliases = Object.entries(specs).reduce(
- (acc, [k, v]) => (v.alias ? ((acc[v.alias] = k), acc) : acc),
- >{}
- );
let id: Nullable;
let spec: Nullable;
let i = opts.start!;
- try {
- for (; i < argv.length; ) {
- const a = argv[i];
- if (!id) {
- if (a[0] === "-") {
- if (a[1] === "-") {
- if (a === "--") {
- i++;
- break;
- }
- id = camel(a.substr(2));
- } else {
- id = aliases[a[1]];
- !id && illegalArgs(`unknown alias: ${a}`);
- }
- if (id === "help") {
- console.log(usage(specs, opts.usageOpts));
- return;
- }
- spec = specs[id];
- !spec && illegalArgs(id);
- i++;
- if (spec.flag) {
- acc[id] = true;
- id = null;
- if (spec.fn && !spec.fn("true")) break;
- }
- } else break;
- } else {
- /^-[a-z]/i.test(a) && illegalArgs(`missing value for: --${id}`);
- if (spec!.multi) {
- isArray(acc[id]) ? acc[id].push(a) : (acc[id] = [a]);
- } else {
- acc[id] = a;
- }
- id = null;
- i++;
- if (spec!.fn && !spec!.fn(a)) break;
+ for (; i < argv.length; ) {
+ const a = argv[i];
+ if (!id) {
+ if (a === HELP) {
+ console.log(usage(specs, opts.usageOpts));
+ return;
}
+ const state = parseKey(specs, aliases, acc, a);
+ id = state.id;
+ spec = state.spec;
+ i = i + ~~(state.state < 2);
+ if (state.state) break;
+ } else {
+ if (parseValue(spec!, acc, id, a)) break;
+ id = null;
+ i++;
+ }
+ }
+ id && illegalArgs(`missing value for: --${id}`);
+ return {
+ result: processResults(specs, acc),
+ index: i,
+ rest: argv.slice(i),
+ done: i >= argv.length,
+ };
+};
+
+const aliasIndex = >(specs: Args) =>
+ Object.entries(specs).reduce(
+ (acc, [k, v]) => (v.alias ? ((acc[v.alias] = k), acc) : acc),
+ >{}
+ );
+
+interface ParseKeyResult {
+ state: number;
+ id?: string;
+ spec?: ArgSpecExt;
+}
+
+const parseKey = >(
+ specs: Args,
+ aliases: IObjectOf,
+ acc: any,
+ a: string
+): ParseKeyResult => {
+ if (a[0] === "-") {
+ let id: string | undefined;
+ if (a[1] === "-") {
+ // terminator arg, stop parsing
+ if (a === "--") return { state: 1 };
+ id = camel(a.substr(2));
+ } else {
+ id = aliases[a[1]];
+ !id && illegalArgs(`unknown option: ${a}`);
+ }
+ const spec: ArgSpecExt = specs[id];
+ !spec && illegalArgs(id);
+ if (spec.flag) {
+ acc[id] = true;
+ id = undefined;
+ // stop parsing if fn returns false
+ if (spec.fn && !spec.fn("true")) return { state: 1, spec };
}
- id && illegalArgs(`missing value for: --${id}`);
- for (id in specs) {
- spec = specs[id];
- if (acc[id] === undefined) {
- if (spec.default !== undefined) {
- acc[id] = spec.default;
- } else if (spec.optional === false) {
- illegalArgs(`missing arg: --${id}`);
- }
- } else {
- if (spec.coerce) {
- try {
- if (spec.multi && spec.delim) {
- acc[id] = (acc[id]).reduce(
- (acc, x) => (
- acc.push(...x.split(spec!.delim!)), acc
- ),
- []
- );
- }
- acc[id] = spec.coerce(acc[id]);
- } catch (e) {
- throw new Error(`arg --${id}: ${e.message}`);
- }
- }
+ return { state: 0, id, spec };
+ }
+ // no option arg, stop parsing
+ return { state: 2 };
+};
+
+const parseValue = (spec: ArgSpecExt, acc: any, id: string, a: string) => {
+ /^-[a-z]/i.test(a) && illegalArgs(`missing value for: --${id}`);
+ if (spec!.multi) {
+ isArray(acc[id!]) ? acc[id!].push(a) : (acc[id!] = [a]);
+ } else {
+ acc[id!] = a;
+ }
+ return spec!.fn && !spec!.fn(a);
+};
+
+const processResults = >(specs: Args, acc: any) => {
+ let spec: Nullable;
+ for (let id in specs) {
+ spec = specs[id];
+ if (acc[id] === undefined) {
+ if (spec.default !== undefined) {
+ acc[id] = spec.default;
+ } else if (spec.optional === false) {
+ illegalArgs(`missing arg: --${id}`);
}
+ } else if (spec.coerce) {
+ coerceValue(spec, acc, id);
}
- return {
- result: acc,
- index: i,
- rest: argv.slice(i),
- done: i >= argv.length,
- };
- } catch (e) {
- if (opts.showUsage) {
- console.log(e.message + "\n\n" + usage(specs, opts.usageOpts));
+ }
+ return acc;
+};
+
+const coerceValue = (spec: ArgSpecExt, acc: any, id: string) => {
+ try {
+ if (spec.multi && spec.delim) {
+ acc[id] = (acc[id]).reduce(
+ (acc, x) => (acc.push(...x.split(spec!.delim!)), acc),
+ []
+ );
}
- throw e;
+ acc[id] = spec.coerce!(acc[id]);
+ } catch (e) {
+ throw new Error(`arg --${id}: ${e.message}`);
}
};
diff --git a/packages/args/src/usage.ts b/packages/args/src/usage.ts
index c78737dbe0..d12442ffc1 100644
--- a/packages/args/src/usage.ts
+++ b/packages/args/src/usage.ts
@@ -3,6 +3,7 @@ import {
kebab,
padRight,
repeat,
+ stringify,
stripAnsi,
wordWrapLines,
} from "@thi.ng/strings";
@@ -15,6 +16,7 @@ export const usage = >(
opts = {
lineWidth: 80,
paramWidth: 32,
+ showDefaults: true,
...opts,
};
const theme =
@@ -45,10 +47,21 @@ export const usage = >(
isRequired ? theme.required! : theme.multi!
)
: "";
+ const defaults =
+ opts.showDefaults && spec.default
+ ? ansi(
+ ` (default: ${stringify()(
+ spec.defaultHint != undefined
+ ? spec.defaultHint
+ : spec.default
+ )})`,
+ theme.default
+ )
+ : "";
return (
padRight(opts.paramWidth!)(params, stripAnsi(params).length) +
wordWrapLines(
- prefix + (spec.desc || ""),
+ prefix + (spec.desc || "") + defaults,
opts.lineWidth! - opts.paramWidth!
)
.map((l, i) => (i > 0 ? indent : "") + l)
diff --git a/packages/arrays/CHANGELOG.md b/packages/arrays/CHANGELOG.md
index 3ef4e4b0d6..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.9.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/arrays@0.9.0...@thi.ng/arrays@0.9.1) (2021-01-10)
+## [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
@@ -11,22 +11,30 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
-# [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)
+# [0.10.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/arrays@0.9.2...@thi.ng/arrays@0.10.0) (2021-01-21)
+
+
+### Bug Fixes
+
+* **arrays:** fixed-length binarySearch2/4/8/16/32 ([39e5c37](https://github.com/thi-ng/umbrella/commit/39e5c3736135f9a49daceee1fe4da9fbdbb96eab))
### Features
-* **arrays:** add bisect(), bisectWith() ([17d06a4](https://github.com/thi-ng/umbrella/commit/17d06a43e338aca5f2dc61110382363639daecc5))
-* **arrays:** add into(), sortByCachedKey() ([b94f64c](https://github.com/thi-ng/umbrella/commit/b94f64c2c351cfed5ea9ade5e42ad0b7076ef9e9))
-* **arrays:** update sortByCachedKey(), add tests ([64e8f6e](https://github.com/thi-ng/umbrella/commit/64e8f6e4e83c26c73e23a4831483bd328b78bc49))
+* **arrays:** add insert/insertUnsafe() ([2a78598](https://github.com/thi-ng/umbrella/commit/2a7859823d2fb56eef4ee7a6919fe70072475f42))
-## [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)
+# [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)
-**Note:** Version bump only for package @thi.ng/arrays
+
+### Features
+
+* **arrays:** add bisect(), bisectWith() ([17d06a4](https://github.com/thi-ng/umbrella/commit/17d06a43e338aca5f2dc61110382363639daecc5))
+* **arrays:** add into(), sortByCachedKey() ([b94f64c](https://github.com/thi-ng/umbrella/commit/b94f64c2c351cfed5ea9ade5e42ad0b7076ef9e9))
+* **arrays:** update sortByCachedKey(), add tests ([64e8f6e](https://github.com/thi-ng/umbrella/commit/64e8f6e4e83c26c73e23a4831483bd328b78bc49))
diff --git a/packages/arrays/README.md b/packages/arrays/README.md
index e6ecd729ed..2b4a05e865 100644
--- a/packages/arrays/README.md
+++ b/packages/arrays/README.md
@@ -42,7 +42,7 @@ yarn add @thi.ng/arrays
```
-Package sizes (gzipped, pre-treeshake): ESM: 2.00 KB / CJS: 2.18 KB / UMD: 2.15 KB
+Package sizes (gzipped, pre-treeshake): ESM: 2.08 KB / CJS: 2.27 KB / UMD: 2.23 KB
## Dependencies
@@ -57,17 +57,25 @@ Package sizes (gzipped, pre-treeshake): ESM: 2.00 KB / CJS: 2.18 KB / UMD: 2.15
[Generated API docs](https://docs.thi.ng/umbrella/arrays/)
+- [arrayIterator()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/iterator.ts)
- [binarySearch()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/binary-search.ts)
+- [bisect()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/bisect.ts)
- [endsWith()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/ends-with.ts)
- [ensureArray()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/ensure-array.ts)
- [ensureIterable()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/ensure-iterable.ts)
+- [fillRange()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/fill-range.ts)
+- [find()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/find.ts)
- [fuzzyMatch()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/fuzzy-match.ts)
+- [insert()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/insert.ts)
+- [into()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/into.ts)
- [isSorted()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/is-sorted.ts)
+- [levenshtein()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/levenshtein.ts)
- [multiSwap()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/swap.ts)
- [peek()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/peek.ts)
- [quickSort()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/quicksort.ts)
- [shuffle()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/shuffle.ts) (w/ custom PRNG support)
- [shuffleRange()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/shuffle.ts) (w/ custom PRNG support)
+- [sortByCachedKey()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/sort-cached.ts)
- [startsWith()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/starts-with.ts)
- [swap()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/swap.ts)
- [swizzle()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/swizzle.ts)
diff --git a/packages/arrays/bench/insert.ts b/packages/arrays/bench/insert.ts
new file mode 100644
index 0000000000..fc0b4265c1
--- /dev/null
+++ b/packages/arrays/bench/insert.ts
@@ -0,0 +1,38 @@
+import { assert } from "@thi.ng/api";
+import { benchmark } from "@thi.ng/bench";
+import { SYSTEM } from "@thi.ng/random";
+import { insert, insertUnsafe } from "../src";
+
+const opts = { iter: 1000, warmup: 100 };
+
+const insertCopyWithin = (buf: any[], x: any, i: number, k = Infinity) => {
+ buf.length < k && buf.length++;
+ buf.copyWithin(i + 1, i);
+ buf[i] = x;
+ return buf;
+};
+
+const splice = (buf: any[], x: any, i: number, k = Infinity) => {
+ buf.splice(i, 0, x);
+ buf.length > k && buf.pop();
+ return buf;
+};
+
+const run = (
+ fn: typeof insert,
+ k: 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 = 8,
+ n = 1e4
+) => {
+ const buf: any[] = [];
+ const m = k - 1;
+ for (; --n >= 0; ) fn(buf, 1, SYSTEM.int() & m, k);
+ assert(buf.length === k, `len=${buf.length}`);
+};
+
+// prettier-ignore
+for (let k of [4, 8, 16, 32, 64]) {
+ benchmark(() => run(splice, k), { title: `splice${k}`, ...opts });
+ benchmark(() => run(insert, k), { title: `insert${k}`, ...opts });
+ benchmark(() => run(insertUnsafe, k), { title: `insertUnsafe${k}`, ...opts });
+ benchmark(() => run(insertCopyWithin, k), { title: `insertCopyWithin${k}`, ...opts });
+}
diff --git a/packages/arrays/bench/tsconfig.json b/packages/arrays/bench/tsconfig.json
new file mode 100644
index 0000000000..9655cbea10
--- /dev/null
+++ b/packages/arrays/bench/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "../../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../build",
+ "module": "commonjs",
+ "noUnusedLocals": false,
+ "noUnusedParameters": false
+ },
+ "include": ["./**/*.ts", "../src/**/*.ts"]
+}
diff --git a/packages/arrays/package.json b/packages/arrays/package.json
index d5f638fb1f..05f08a75a2 100644
--- a/packages/arrays/package.json
+++ b/packages/arrays/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/arrays",
- "version": "0.9.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.1.5"
+ "@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/arrays/src/binary-search.ts b/packages/arrays/src/binary-search.ts
index 5ee840af47..bda59bb75d 100644
--- a/packages/arrays/src/binary-search.ts
+++ b/packages/arrays/src/binary-search.ts
@@ -86,6 +86,11 @@ export const binarySearchNumeric = (
return -low - 1;
};
+export const binarySearch2 = (buf: ArrayLike, x: number) => {
+ let idx = buf[1] <= x ? 1 : 0;
+ return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
+};
+
/**
* Non-recursive, optimized binary search for fixed size numeric arrays of 4
* values. Returns index of `x` or `-index-1` if not found.
@@ -96,7 +101,7 @@ export const binarySearchNumeric = (
export const binarySearch4 = (buf: ArrayLike, x: number) => {
let idx = buf[2] <= x ? 2 : 0;
idx |= buf[idx + 1] <= x ? 1 : 0;
- return buf[idx] === x ? idx : -idx - 1;
+ return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
};
/**
@@ -110,7 +115,7 @@ export const binarySearch8 = (buf: ArrayLike, x: number) => {
let idx = buf[4] <= x ? 4 : 0;
idx |= buf[idx + 2] <= x ? 2 : 0;
idx |= buf[idx + 1] <= x ? 1 : 0;
- return buf[idx] === x ? idx : -idx - 1;
+ return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
};
/**
@@ -125,7 +130,7 @@ export const binarySearch16 = (buf: ArrayLike, x: number) => {
idx |= buf[idx + 4] <= x ? 4 : 0;
idx |= buf[idx + 2] <= x ? 2 : 0;
idx |= buf[idx + 1] <= x ? 1 : 0;
- return buf[idx] === x ? idx : -idx - 1;
+ return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
};
/**
@@ -141,7 +146,7 @@ export const binarySearch32 = (buf: ArrayLike, x: number) => {
idx |= buf[idx + 4] <= x ? 4 : 0;
idx |= buf[idx + 2] <= x ? 2 : 0;
idx |= buf[idx + 1] <= x ? 1 : 0;
- return buf[idx] === x ? idx : -idx - 1;
+ return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
};
/**
diff --git a/packages/arrays/src/index.ts b/packages/arrays/src/index.ts
index ffa20f967b..739c4ed3a2 100644
--- a/packages/arrays/src/index.ts
+++ b/packages/arrays/src/index.ts
@@ -8,6 +8,7 @@ export * from "./find";
export * from "./fill-range";
export * from "./fuzzy-match";
export * from "./is-sorted";
+export * from "./insert";
export * from "./into";
export * from "./iterator";
export * from "./levenshtein";
diff --git a/packages/arrays/src/insert.ts b/packages/arrays/src/insert.ts
new file mode 100644
index 0000000000..b7fbeadbbd
--- /dev/null
+++ b/packages/arrays/src/insert.ts
@@ -0,0 +1,36 @@
+/**
+ * Inserts `x` into `buf` at index `i` and ensures that array length doesn't
+ * grow beyond max `k` items (default: unbounded).
+ *
+ * @remarks
+ * The function will have no effect iff `i<0` or `i>=k` or `k<1`. If
+ * `buf.length` is larger than `k`, only the index range [i..k) will be
+ * modified.
+ *
+ * In benchmarking with 4, 8, 16, 32, 64 element arrays, this function is
+ * consistently 7-16x faster than `Array.prototype.copyWithin()` and 1.5-2x
+ * faster than `Array.prototype.splice()` (for sizes < ~32). See
+ * `/bench/insert.ts`
+ *
+ * @param buf
+ * @param x
+ * @param i
+ * @param k
+ */
+export const insert = (buf: T[], x: T, i: number, k = Infinity) =>
+ i < 0 || i >= k || k < 1 ? buf : insertUnsafe(buf, x, i, k);
+
+/**
+ * Same as {@link insert} but without any bounds/index checks.
+ *
+ * @param buf
+ * @param x
+ * @param i
+ * @param k
+ */
+export const insertUnsafe = (buf: T[], x: T, i: number, k = Infinity) => {
+ let j = buf.length < k ? buf.length + 1 : k;
+ for (; --j > i; ) buf[j] = buf[j - 1];
+ buf[i] = x;
+ return buf;
+};
diff --git a/packages/arrays/tpl.readme.md b/packages/arrays/tpl.readme.md
index 14384563c6..1244017d8a 100644
--- a/packages/arrays/tpl.readme.md
+++ b/packages/arrays/tpl.readme.md
@@ -37,17 +37,25 @@ ${examples}
${docLink}
+- [arrayIterator()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/iterator.ts)
- [binarySearch()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/binary-search.ts)
+- [bisect()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/bisect.ts)
- [endsWith()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/ends-with.ts)
- [ensureArray()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/ensure-array.ts)
- [ensureIterable()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/ensure-iterable.ts)
+- [fillRange()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/fill-range.ts)
+- [find()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/find.ts)
- [fuzzyMatch()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/fuzzy-match.ts)
+- [insert()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/insert.ts)
+- [into()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/into.ts)
- [isSorted()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/is-sorted.ts)
+- [levenshtein()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/levenshtein.ts)
- [multiSwap()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/swap.ts)
- [peek()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/peek.ts)
- [quickSort()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/quicksort.ts)
- [shuffle()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/shuffle.ts) (w/ custom PRNG support)
- [shuffleRange()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/shuffle.ts) (w/ custom PRNG support)
+- [sortByCachedKey()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/sort-cached.ts)
- [startsWith()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/starts-with.ts)
- [swap()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/swap.ts)
- [swizzle()](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays/src/swizzle.ts)
diff --git a/packages/associative/CHANGELOG.md b/packages/associative/CHANGELOG.md
index 99d680f8ad..a9589b6b79 100644
--- a/packages/associative/CHANGELOG.md
+++ b/packages/associative/CHANGELOG.md
@@ -3,25 +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.14](https://github.com/thi-ng/umbrella/compare/@thi.ng/associative@5.0.13...@thi.ng/associative@5.0.14) (2021-01-10)
+# [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.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 8d65019428..3475f3cbb8 100644
--- a/packages/associative/package.json
+++ b/packages/associative/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/associative",
- "version": "5.0.14",
+ "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.6",
- "@thi.ng/equiv": "^1.0.35",
- "@thi.ng/errors": "^1.2.26",
- "@thi.ng/transducers": "^7.5.5",
+ "@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
new file mode 100644
index 0000000000..d98b56ccf8
--- /dev/null
+++ b/packages/base-n/CHANGELOG.md
@@ -0,0 +1,20 @@
+# Change Log
+
+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)
+
+
+### Features
+
+* **base-n:** add en/decodeBytes(), add BASE16_XX ([d6205d7](https://github.com/thi-ng/umbrella/commit/d6205d72331bf038ebdc95c221763e2f794c10a9))
+* **base-n:** import as new pkg (MBP2010) ([f5763b3](https://github.com/thi-ng/umbrella/commit/f5763b3c6be87eb0e27a9239527283323c3e774c))
diff --git a/packages/base-n/LICENSE b/packages/base-n/LICENSE
new file mode 100644
index 0000000000..8dada3edaf
--- /dev/null
+++ b/packages/base-n/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/packages/base-n/README.md b/packages/base-n/README.md
new file mode 100644
index 0000000000..865f85c0f6
--- /dev/null
+++ b/packages/base-n/README.md
@@ -0,0 +1,90 @@
+
+
+# ![base-n](https://media.thi.ng/umbrella/banners/thing-base-n.svg?4cffdce7)
+
+[![npm version](https://img.shields.io/npm/v/@thi.ng/base-n.svg)](https://www.npmjs.com/package/@thi.ng/base-n)
+![npm downloads](https://img.shields.io/npm/dm/@thi.ng/base-n.svg)
+[![Twitter Follow](https://img.shields.io/twitter/follow/thing_umbrella.svg?style=flat-square&label=twitter)](https://twitter.com/thing_umbrella)
+
+This project is part of the
+[@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo.
+
+- [About](#about)
+ - [Status](#status)
+- [Installation](#installation)
+- [Dependencies](#dependencies)
+- [API](#api)
+- [Authors](#authors)
+- [License](#license)
+
+## About
+
+Arbitrary base-n conversions w/ presets for base16/32/36/58/62/64/85, support for arrays & bigints.
+
+### Status
+
+**BETA** - possibly breaking changes forthcoming
+
+[Search or submit any issues for this package](https://github.com/thi-ng/umbrella/issues?q=%5Bbase-n%5D+in%3Atitle)
+
+## Installation
+
+```bash
+yarn add @thi.ng/base-n
+```
+
+```html
+// ES module
+
+
+// UMD
+
+```
+
+Package sizes (gzipped, pre-treeshake): ESM: 789 bytes / CJS: 892 bytes / UMD: 970 bytes
+
+## Dependencies
+
+- [@thi.ng/hex](https://github.com/thi-ng/umbrella/tree/develop/packages/hex)
+
+## API
+
+[Generated API docs](https://docs.thi.ng/umbrella/base-n/)
+
+```ts
+import { BASE85, defBase } from "@thi.ng/base-n";
+
+BASE85.encodeBigInt(2n ** 128n - 1);
+// '=r54lj&NUUO~Hi%c2ym0'
+
+BASE85.decodeBigInt("=r54lj&NUUO~Hi%c2ym0").toString(16);
+// 'ffffffffffffffffffffffffffffffff'
+
+// define a custom base impl
+const ternary = defBase("012");
+
+ternary.encode(12345678)
+// '212020020002100'
+
+ternary.decode("212020020002100");
+// 12345678
+```
+
+## Authors
+
+Karsten Schmidt
+
+If this project contributes to an academic publication, please cite it as:
+
+```bibtex
+@misc{thing-base-n,
+ title = "@thi.ng/base-n",
+ author = "Karsten Schmidt",
+ note = "https://thi.ng/base-n",
+ year = 2017
+}
+```
+
+## License
+
+© 2017 - 2021 Karsten Schmidt // Apache Software License 2.0
diff --git a/packages/base-n/api-extractor.json b/packages/base-n/api-extractor.json
new file mode 100644
index 0000000000..94972e6bed
--- /dev/null
+++ b/packages/base-n/api-extractor.json
@@ -0,0 +1,3 @@
+{
+ "extends": "../../api-extractor.json"
+}
diff --git a/packages/base-n/package.json b/packages/base-n/package.json
new file mode 100644
index 0000000000..b4cccb437a
--- /dev/null
+++ b/packages/base-n/package.json
@@ -0,0 +1,84 @@
+{
+ "name": "@thi.ng/base-n",
+ "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",
+ "umd:main": "./lib/index.umd.js",
+ "typings": "./index.d.ts",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/thi-ng/umbrella.git"
+ },
+ "homepage": "https://github.com/thi-ng/umbrella/tree/master/packages/base-n#readme",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/postspectacular"
+ },
+ {
+ "type": "patreon",
+ "url": "https://patreon.com/thing_umbrella"
+ }
+ ],
+ "author": "Karsten Schmidt ",
+ "license": "Apache-2.0",
+ "scripts": {
+ "build": "yarn clean && yarn build:es6 && node ../../scripts/bundle-module",
+ "build:release": "yarn clean && yarn build:es6 && node ../../scripts/bundle-module all",
+ "build:es6": "tsc --declaration",
+ "build:test": "rimraf build && tsc -p test/tsconfig.json",
+ "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",
+ "doc:readme": "ts-node -P ../../tools/tsconfig.json ../../tools/src/readme.ts",
+ "doc:ae": "mkdir -p .ae/doc .ae/temp && node_modules/.bin/api-extractor run --local --verbose",
+ "doc": "node_modules/.bin/typedoc --out doc --theme ../../tools/doc/typedoc-theme src/index.ts",
+ "pub": "yarn build:release && yarn publish --access public"
+ },
+ "devDependencies": {
+ "@istanbuljs/nyc-config-typescript": "^1.0.1",
+ "@microsoft/api-extractor": "^7.12.1",
+ "@types/mocha": "^8.2.0",
+ "@types/node": "^14.14.14",
+ "mocha": "^8.3.0",
+ "nyc": "^15.1.0",
+ "ts-node": "^9.1.1",
+ "typedoc": "^0.20.26",
+ "typescript": "^4.1.5"
+ },
+ "dependencies": {
+ "@thi.ng/hex": "^0.2.0"
+ },
+ "files": [
+ "*.js",
+ "*.d.ts",
+ "lib"
+ ],
+ "keywords": [
+ "array",
+ "base16",
+ "base32",
+ "base36",
+ "base58",
+ "base62",
+ "base64",
+ "base85",
+ "bigint",
+ "binary",
+ "conversion",
+ "encode",
+ "decode",
+ "string",
+ "typescript"
+ ],
+ "publishConfig": {
+ "access": "public"
+ },
+ "sideEffects": false,
+ "thi.ng": {
+ "status": "beta",
+ "year": 2017
+ }
+}
diff --git a/packages/base-n/src/16.ts b/packages/base-n/src/16.ts
new file mode 100644
index 0000000000..bedfd6fb0c
--- /dev/null
+++ b/packages/base-n/src/16.ts
@@ -0,0 +1,11 @@
+import { defBase } from "./base";
+
+/**
+ * Digits: 0-9 A-F
+ */
+export const BASE16_UC = defBase("0123456789ABCDEF");
+
+/**
+ * Digits: 0-9 a-f
+ */
+export const BASE16_LC = defBase("0123456789abcdef");
diff --git a/packages/base-n/src/32.ts b/packages/base-n/src/32.ts
new file mode 100644
index 0000000000..0a2e131451
--- /dev/null
+++ b/packages/base-n/src/32.ts
@@ -0,0 +1,17 @@
+import { defBase } from "./base";
+
+/**
+ * Digits: A-Z 2-7
+ *
+ * @remarks
+ * Reference: https://tools.ietf.org/html/rfc4648
+ */
+export const BASE32_RFC4648 = defBase("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567");
+
+/**
+ * Digits: 0-9 A-V
+ *
+ * @remarks
+ * Reference: https://en.wikipedia.org/wiki/Base32#base32hex
+ */
+export const BASE32_HEX = defBase("0123456789ABCDEFGHIJKLMNOPQRSTUV");
diff --git a/packages/base-n/src/36.ts b/packages/base-n/src/36.ts
new file mode 100644
index 0000000000..99f02821ae
--- /dev/null
+++ b/packages/base-n/src/36.ts
@@ -0,0 +1,11 @@
+import { defBase } from "./base";
+
+export const B36_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+/**
+ * Digits: 0-9 A-Z
+ *
+ * @remarks
+ * Reference: https://en.wikipedia.org/wiki/Base36
+ */
+export const BASE36 = defBase(B36_CHARS);
diff --git a/packages/base-n/src/58.ts b/packages/base-n/src/58.ts
new file mode 100644
index 0000000000..70ae485c16
--- /dev/null
+++ b/packages/base-n/src/58.ts
@@ -0,0 +1,9 @@
+import { defBase } from "./base";
+
+export const B58_CHARS =
+ "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
+
+/**
+ * Reference: https://en.wikipedia.org/wiki/Binary-to-text_encoding
+ */
+export const BASE58 = defBase(B58_CHARS);
diff --git a/packages/base-n/src/62.ts b/packages/base-n/src/62.ts
new file mode 100644
index 0000000000..e88f53535f
--- /dev/null
+++ b/packages/base-n/src/62.ts
@@ -0,0 +1,12 @@
+import { B36_CHARS } from "./36";
+import { defBase } from "./base";
+
+export const B62_CHARS = B36_CHARS + "abcdefghijklmnopqrstuvwxyz";
+
+/**
+ * Digits: 0-9 A-Z a-z
+ *
+ * @remarks
+ * Reference: https://en.wikipedia.org/wiki/Base62
+ */
+export const BASE62 = defBase(B62_CHARS);
diff --git a/packages/base-n/src/64.ts b/packages/base-n/src/64.ts
new file mode 100644
index 0000000000..4a55b453a2
--- /dev/null
+++ b/packages/base-n/src/64.ts
@@ -0,0 +1,12 @@
+import { B62_CHARS } from "./62";
+import { defBase } from "./base";
+
+export const B64_CHARS = B62_CHARS + "+/";
+
+/**
+ * Digits: 0-9 A-Z a-z + /
+ *
+ * @remarks
+ * Reference: https://en.wikipedia.org/wiki/Base64
+ */
+export const BASE64 = defBase(B64_CHARS);
diff --git a/packages/base-n/src/85.ts b/packages/base-n/src/85.ts
new file mode 100644
index 0000000000..64f0ab28b2
--- /dev/null
+++ b/packages/base-n/src/85.ts
@@ -0,0 +1,9 @@
+import { B62_CHARS } from "./62";
+import { defBase } from "./base";
+
+const B85_CHARS = B62_CHARS + "!#$%&()*+-;<=>?@^_`{|}~";
+
+/**
+ * Reference: https://en.wikipedia.org/wiki/Ascii85
+ */
+export const BASE85 = defBase(B85_CHARS);
diff --git a/packages/base-n/src/api.ts b/packages/base-n/src/api.ts
new file mode 100644
index 0000000000..fd3b64b489
--- /dev/null
+++ b/packages/base-n/src/api.ts
@@ -0,0 +1,48 @@
+export interface IBase {
+ readonly N: number;
+ readonly base: string;
+
+ /**
+ * Encodes `x` into a baseN encoded string. `x` MUST be < 2^53. Use
+ * `encodeBigInt()` for arbitrary values.
+ *
+ * @param x
+ */
+ encode(x: number): string;
+ /**
+ * Encodes bigint `x` into a baseN encoded string.
+ *
+ * @param x
+ */
+ encodeBigInt(x: bigint): string;
+
+ /**
+ * Encodes given byte array into a bigint and then baseN encodes it.
+ *
+ * @param buf
+ */
+ encodeBytes(buf: Uint8Array): string;
+
+ /**
+ * Decodes baseN encoded string `x` into a numeric value. Assumes the
+ * resulting `x` will be < 2^53. Use `decodeBigInt()` for arbitrary values.
+ *
+ * @param x
+ */
+ decode(x: string): number;
+ /**
+ * Decodes baseN encoded string `x` into a bigint value.
+ *
+ * @param x
+ */
+ decodeBigInt(x: string): bigint;
+ /**
+ * Decodes given string in a byte array. The byte values will be big endian
+ * order, with the LSB aligned to end of the given array. If `buf` is
+ * shorter than the space required by the encoded source string, the most
+ * significant bytes will be ignored.
+ *
+ * @param buf
+ */
+ decodeBytes(x: string, buf: Uint8Array): Uint8Array;
+}
diff --git a/packages/base-n/src/base.ts b/packages/base-n/src/base.ts
new file mode 100644
index 0000000000..b13886cc45
--- /dev/null
+++ b/packages/base-n/src/base.ts
@@ -0,0 +1,85 @@
+import { U8 } from "@thi.ng/hex";
+import type { IBase } from "./api";
+
+export const defBase = (chars: string) => new BaseN(chars);
+
+export class BaseN implements IBase {
+ readonly N: number;
+ readonly index: Record;
+
+ constructor(public readonly base: string) {
+ this.N = base.length;
+ this.index = [...base].reduce(
+ (acc, x, i) => ((acc[x] = i), acc),
+ >{}
+ );
+ }
+
+ encode(x: number) {
+ const { base, N } = this;
+ if (x === 0) return base[0];
+ let res = "";
+ while (x > 0) {
+ res = base[x % N] + res;
+ x = (x / N) | 0;
+ }
+ return res;
+ }
+
+ encodeBigInt(x: bigint) {
+ if (x < BigInt(2 ** 53)) return this.encode(Number(x));
+ const { base, N } = this;
+ if (x === BigInt(0)) return base[0];
+ const NN = BigInt(N);
+ let res = "";
+ while (x > 0) {
+ res = base[Number(x % NN)] + res;
+ x /= NN;
+ }
+ return res;
+ }
+
+ encodeBytes(buf: Uint8Array) {
+ let hex = "";
+ for (let i = 0, n = buf.length; i < n; i++) hex += U8(buf[i]);
+ return this.encodeBigInt(BigInt(`0x${hex}`));
+ }
+
+ decode(x: string) {
+ const { index, N } = this;
+ let res = 0;
+ for (let n = x.length - 1, i = 0; i <= n; i++) {
+ res += index[x[i]] * N ** (n - i);
+ }
+ return res;
+ }
+
+ decodeBigInt(x: string): bigint {
+ const { index, N } = this;
+ const NN = BigInt(N);
+ let res = BigInt(0);
+ for (let n = x.length - 1, i = 0; i <= n; i++) {
+ res += BigInt(index[x[i]]) * NN ** BigInt(n - i);
+ }
+ return res;
+ }
+
+ decodeBytes(x: string, buf: Uint8Array): Uint8Array {
+ let y = this.decodeBigInt(x);
+ const M = BigInt(255);
+ const SHIFT = BigInt(8);
+ for (let i = buf.length; --i >= 0; ) {
+ buf[i] = Number(y & M);
+ y >>= SHIFT;
+ }
+ return buf;
+ }
+
+ validate(x: string) {
+ return new RegExp(`^[${this.base}]+$`).test(x);
+ }
+
+ size(x: number) {
+ return Math.ceil(Math.log(x) / Math.log(this.N));
+ }
+}
diff --git a/packages/base-n/src/index.ts b/packages/base-n/src/index.ts
new file mode 100644
index 0000000000..a58466b41d
--- /dev/null
+++ b/packages/base-n/src/index.ts
@@ -0,0 +1,10 @@
+export * from "./api";
+export * from "./base";
+
+export * from "./16";
+export * from "./32";
+export * from "./36";
+export * from "./58";
+export * from "./62";
+export * from "./64";
+export * from "./85";
diff --git a/packages/base-n/test/index.ts b/packages/base-n/test/index.ts
new file mode 100644
index 0000000000..a9234eccfb
--- /dev/null
+++ b/packages/base-n/test/index.ts
@@ -0,0 +1,34 @@
+import * as assert from "assert";
+import {
+ BASE32_HEX,
+ BASE32_RFC4648,
+ BASE36,
+ BASE58,
+ BASE62,
+ BASE64,
+ BASE85,
+ IBase,
+} from "../src";
+
+describe("base-n", () => {
+ it("roundtrip", () => {
+ const X = BigInt(2) ** BigInt(128) - BigInt(1);
+
+ const check = (
+ base: IBase,
+ expected: string,
+ id: string | number = base.N
+ ) => {
+ assert.strictEqual(base.encodeBigInt(X), expected, `encode: ${id}`);
+ assert.strictEqual(base.decodeBigInt(expected), X, `decode: ${id}`);
+ };
+
+ check(BASE32_RFC4648, "H7777777777777777777777777", "32rfc");
+ check(BASE32_HEX, "7VVVVVVVVVVVVVVVVVVVVVVVVV", "32hex");
+ check(BASE36, "F5LXX1ZZ5PNORYNQGLHZMSP33");
+ check(BASE58, "YcVfxkQb6JRzqk5kF2tNLv");
+ check(BASE62, "7n42DGM5Tflk9n8mt7Fhc7");
+ check(BASE64, "3/////////////////////");
+ check(BASE85, "=r54lj&NUUO~Hi%c2ym0");
+ });
+});
diff --git a/packages/base-n/test/tsconfig.json b/packages/base-n/test/tsconfig.json
new file mode 100644
index 0000000000..f6e63560dd
--- /dev/null
+++ b/packages/base-n/test/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "extends": "../../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../build",
+ "module": "commonjs"
+ },
+ "include": [
+ "./**/*.ts",
+ "../src/**/*.ts"
+ ]
+}
diff --git a/packages/base-n/tpl.readme.md b/packages/base-n/tpl.readme.md
new file mode 100644
index 0000000000..4319daa09e
--- /dev/null
+++ b/packages/base-n/tpl.readme.md
@@ -0,0 +1,67 @@
+# ${pkg.banner}
+
+[![npm version](https://img.shields.io/npm/v/${pkg.name}.svg)](https://www.npmjs.com/package/${pkg.name})
+![npm downloads](https://img.shields.io/npm/dm/${pkg.name}.svg)
+[![Twitter Follow](https://img.shields.io/twitter/follow/thing_umbrella.svg?style=flat-square&label=twitter)](https://twitter.com/thing_umbrella)
+
+This project is part of the
+[@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo.
+
+
+
+## About
+
+${pkg.description}
+
+${status}
+
+${supportPackages}
+
+${relatedPackages}
+
+${blogPosts}
+
+## Installation
+
+${pkg.install}
+
+${pkg.size}
+
+## Dependencies
+
+${pkg.deps}
+
+${examples}
+
+## API
+
+${docLink}
+
+```ts
+import { BASE85, defBase } from "@thi.ng/base-n";
+
+BASE85.encodeBigInt(2n ** 128n - 1);
+// '=r54lj&NUUO~Hi%c2ym0'
+
+BASE85.decodeBigInt("=r54lj&NUUO~Hi%c2ym0").toString(16);
+// 'ffffffffffffffffffffffffffffffff'
+
+// define a custom base impl
+const ternary = defBase("012");
+
+ternary.encode(12345678)
+// '212020020002100'
+
+ternary.decode("212020020002100");
+// 12345678
+```
+
+## Authors
+
+${authors}
+
+${pkg.cite}
+
+## License
+
+© ${copyright} // ${license}
diff --git a/packages/base-n/tsconfig.json b/packages/base-n/tsconfig.json
new file mode 100644
index 0000000000..bd6481a5a6
--- /dev/null
+++ b/packages/base-n/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "."
+ },
+ "include": [
+ "./src/**/*.ts"
+ ]
+}
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 c6542261a1..66589e34a9 100644
--- a/packages/bencode/CHANGELOG.md
+++ b/packages/bencode/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.
-## [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 c9c70015e1..546a5b410a 100644
--- a/packages/bencode/package.json
+++ b/packages/bencode/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/bencode",
- "version": "0.3.46",
+ "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.9.1",
- "@thi.ng/checks": "^2.8.0",
- "@thi.ng/defmulti": "^1.3.4",
- "@thi.ng/errors": "^1.2.26",
- "@thi.ng/transducers": "^7.5.5",
- "@thi.ng/transducers-binary": "^0.6.2"
+ "@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 b95c109aad..fdbb2aed7f 100644
--- a/packages/bitfield/CHANGELOG.md
+++ b/packages/bitfield/CHANGELOG.md
@@ -3,33 +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.29](https://github.com/thi-ng/umbrella/compare/@thi.ng/bitfield@0.3.28...@thi.ng/bitfield@0.3.29) (2021-01-10)
+# [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.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 2bd623d26f..71ac461a08 100644
--- a/packages/bitfield/package.json
+++ b/packages/bitfield/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/bitfield",
- "version": "0.3.29",
+ "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.13.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 b0898534c8..eed647b270 100644
--- a/packages/cache/CHANGELOG.md
+++ b/packages/cache/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.
-## [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 19279d4f67..27b20f1091 100644
--- a/packages/cache/package.json
+++ b/packages/cache/package.json
@@ -1,6 +1,6 @@
{
"name": "@thi.ng/cache",
- "version": "1.0.66",
+ "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.6",
- "@thi.ng/transducers": "^7.5.5"
+ "@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 a4993877c2..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.47 KB / CJS: 1.73 KB / UMD: 1.46 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 f5c674a912..ae63f04978 100644
--- a/packages/color/CHANGELOG.md
+++ b/packages/color/CHANGELOG.md
@@ -3,17 +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.2](https://github.com/thi-ng/umbrella/compare/@thi.ng/color@2.1.1...@thi.ng/color@2.1.2) (2021-01-10)
+# [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
+
+* **color:** major update/rename all types/conversions ([4143c8f](https://github.com/thi-ng/umbrella/commit/4143c8fe746a692e61be7696053c883eef7ab326))
+
+
+### Features
+* **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))
-## [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)
-**Note:** Version bump only for package @thi.ng/color
+### Performance Improvements
+
+* **color:** make defColor() fixed for 4 channels ([4ea77ef](https://github.com/thi-ng/umbrella/commit/4ea77eff4ef89b771268c6244628b71ec869ab8b))
+
+
+### BREAKING CHANGES
+
+* **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 47351d12d9..2f2a4ac099 100644
--- a/packages/color/package.json
+++ b/packages/color/package.json
@@ -1,7 +1,7 @@
{
"name": "@thi.ng/color",
- "version": "2.1.2",
- "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.9.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.1.5",
- "@thi.ng/strings": "^1.13.0",
- "@thi.ng/transducers": "^7.5.5",
- "@thi.ng/vectors": "^4.8.5"
+ "@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, (