├── makefile ├── .gitignore ├── declarative ├── .gitignore ├── blogcache.txt ├── makefile ├── mono.css ├── anim.hs ├── minanim.js ├── ANIMGENERATED.js └── anim.cpp ├── observablehq-stdlib ├── .eslintignore ├── .prettierrc ├── 1-COMMIT ├── src │ ├── that.js │ ├── dom │ │ ├── text.js │ │ ├── input.js │ │ ├── canvas.js │ │ ├── svg.js │ │ ├── select.js │ │ ├── uid.js │ │ ├── range.js │ │ ├── context2d.js │ │ ├── index.js │ │ ├── download.js │ │ └── element.js │ ├── constant.js │ ├── now.js │ ├── index.js │ ├── promises │ │ ├── tick.js │ │ ├── delay.js │ │ ├── index.js │ │ └── when.js │ ├── require.js │ ├── generators │ │ ├── map.js │ │ ├── filter.js │ │ ├── valueAt.js │ │ ├── range.js │ │ ├── worker.js │ │ ├── disposable.js │ │ ├── index.js │ │ ├── queue.js │ │ ├── observe.js │ │ └── input.js │ ├── files │ │ ├── index.js │ │ ├── text.js │ │ ├── url.js │ │ └── buffer.js │ ├── html.js │ ├── svg.js │ ├── resolve.js │ ├── mutable.js │ ├── width.js │ ├── tex.js │ ├── fileAttachment.js │ ├── md.js │ ├── library.js │ └── template.js ├── .gitignore ├── test │ ├── fileAttachments-test.js │ ├── DOM │ │ └── uid-test.js │ ├── index-test.js │ ├── generators │ │ ├── disposable-test.js │ │ └── generators-test.js │ └── promises │ │ └── delay-test.js ├── .eslintrc.json ├── stdlib.sublime-project ├── .github │ └── workflows │ │ └── nodejs.yml ├── rollup.config.js ├── LICENSE └── package.json ├── static ├── Symbola.ttf ├── Exo2-Bold.ttf ├── Exo2-Medium.ttf ├── Exo2-Regular.ttf ├── FiraMono-Bold.ttf ├── Bellefair-Regular.ttf ├── FiraMono-Medium.ttf ├── FiraMono-Regular.ttf ├── FiraSans-Regular.ttf ├── NotoSerif-Regular.ttf ├── SourceSerifPro-Bold.ttf ├── UbuntuMono-Regular.ttf ├── iosevka-etoile-thin.ttf ├── SourceSerifPro-Regular.ttf ├── iosevka-etoile-regular.ttf ├── iosevka-fixed-extended.ttf ├── SourceSerifPro-SemiBold.ttf └── iosevka-fixed-extendedmedium.ttf ├── mathemagic.sublime-project ├── jacobian ├── transform-terms.png ├── et-book │ ├── et-book-bold-line-figures │ │ ├── et-book-bold-line-figures.eot │ │ ├── et-book-bold-line-figures.ttf │ │ └── et-book-bold-line-figures.woff │ ├── et-book-roman-line-figures │ │ ├── et-book-roman-line-figures.eot │ │ ├── et-book-roman-line-figures.ttf │ │ └── et-book-roman-line-figures.woff │ ├── et-book-roman-old-style-figures │ │ ├── et-book-roman-old-style-figures.eot │ │ ├── et-book-roman-old-style-figures.ttf │ │ └── et-book-roman-old-style-figures.woff │ ├── et-book-semi-bold-old-style-figures │ │ ├── et-book-semi-bold-old-style-figures.eot │ │ ├── et-book-semi-bold-old-style-figures.ttf │ │ └── et-book-semi-bold-old-style-figures.woff │ └── et-book-display-italic-old-style-figures │ │ ├── et-book-display-italic-old-style-figures.eot │ │ ├── et-book-display-italic-old-style-figures.ttf │ │ └── et-book-display-italic-old-style-figures.woff ├── tufte.css ├── index.html └── sketch.js ├── whalesong ├── whalesong-picture.jpg ├── makefile ├── index.md └── index.html ├── ddg-laplace-operator ├── fonts │ ├── KaTeX_AMS-Regular.ttf │ ├── KaTeX_Main-Bold.ttf │ ├── KaTeX_Main-Bold.woff │ ├── KaTeX_Main-Bold.woff2 │ ├── KaTeX_Main-Italic.ttf │ ├── KaTeX_Math-Italic.ttf │ ├── KaTeX_AMS-Regular.woff │ ├── KaTeX_AMS-Regular.woff2 │ ├── KaTeX_Fraktur-Bold.ttf │ ├── KaTeX_Fraktur-Bold.woff │ ├── KaTeX_Main-Italic.woff │ ├── KaTeX_Main-Italic.woff2 │ ├── KaTeX_Main-Regular.ttf │ ├── KaTeX_Main-Regular.woff │ ├── KaTeX_Math-Italic.woff │ ├── KaTeX_Math-Italic.woff2 │ ├── KaTeX_Size1-Regular.ttf │ ├── KaTeX_Size2-Regular.ttf │ ├── KaTeX_Size3-Regular.ttf │ ├── KaTeX_Size4-Regular.ttf │ ├── KaTeX_Caligraphic-Bold.ttf │ ├── KaTeX_Fraktur-Bold.woff2 │ ├── KaTeX_Fraktur-Regular.ttf │ ├── KaTeX_Fraktur-Regular.woff │ ├── KaTeX_Main-BoldItalic.ttf │ ├── KaTeX_Main-BoldItalic.woff │ ├── KaTeX_Main-Regular.woff2 │ ├── KaTeX_Math-BoldItalic.ttf │ ├── KaTeX_Math-BoldItalic.woff │ ├── KaTeX_SansSerif-Bold.ttf │ ├── KaTeX_SansSerif-Bold.woff │ ├── KaTeX_SansSerif-Bold.woff2 │ ├── KaTeX_SansSerif-Italic.ttf │ ├── KaTeX_Script-Regular.ttf │ ├── KaTeX_Script-Regular.woff │ ├── KaTeX_Script-Regular.woff2 │ ├── KaTeX_Size1-Regular.woff │ ├── KaTeX_Size1-Regular.woff2 │ ├── KaTeX_Size2-Regular.woff │ ├── KaTeX_Size2-Regular.woff2 │ ├── KaTeX_Size3-Regular.woff │ ├── KaTeX_Size3-Regular.woff2 │ ├── KaTeX_Size4-Regular.woff │ ├── KaTeX_Size4-Regular.woff2 │ ├── KaTeX_Caligraphic-Bold.woff │ ├── KaTeX_Caligraphic-Bold.woff2 │ ├── KaTeX_Fraktur-Regular.woff2 │ ├── KaTeX_Main-BoldItalic.woff2 │ ├── KaTeX_Math-BoldItalic.woff2 │ ├── KaTeX_SansSerif-Italic.woff │ ├── KaTeX_SansSerif-Italic.woff2 │ ├── KaTeX_SansSerif-Regular.ttf │ ├── KaTeX_SansSerif-Regular.woff │ ├── KaTeX_Typewriter-Regular.ttf │ ├── KaTeX_Caligraphic-Regular.ttf │ ├── KaTeX_Caligraphic-Regular.woff │ ├── KaTeX_Caligraphic-Regular.woff2 │ ├── KaTeX_SansSerif-Regular.woff2 │ ├── KaTeX_Typewriter-Regular.woff │ └── KaTeX_Typewriter-Regular.woff2 ├── auto-render.min.js └── index.html ├── README.md ├── three.html ├── index.html └── observablehq.html /makefile: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.sublime-workspace 2 | -------------------------------------------------------------------------------- /declarative/.gitignore: -------------------------------------------------------------------------------- 1 | anim.out 2 | -------------------------------------------------------------------------------- /observablehq-stdlib/.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /observablehq-stdlib/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": false 3 | } 4 | -------------------------------------------------------------------------------- /observablehq-stdlib/1-COMMIT: -------------------------------------------------------------------------------- 1 | e9e9a6f322002fdc55a145342e393a52f6811f54 2 | -------------------------------------------------------------------------------- /static/Symbola.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/Symbola.ttf -------------------------------------------------------------------------------- /observablehq-stdlib/src/that.js: -------------------------------------------------------------------------------- 1 | export default function that() { 2 | return this; 3 | } 4 | -------------------------------------------------------------------------------- /static/Exo2-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/Exo2-Bold.ttf -------------------------------------------------------------------------------- /static/Exo2-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/Exo2-Medium.ttf -------------------------------------------------------------------------------- /static/Exo2-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/Exo2-Regular.ttf -------------------------------------------------------------------------------- /declarative/blogcache.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/declarative/blogcache.txt -------------------------------------------------------------------------------- /mathemagic.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": 3 | [ 4 | { 5 | "path": "." 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /static/FiraMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/FiraMono-Bold.ttf -------------------------------------------------------------------------------- /jacobian/transform-terms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/transform-terms.png -------------------------------------------------------------------------------- /static/Bellefair-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/Bellefair-Regular.ttf -------------------------------------------------------------------------------- /static/FiraMono-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/FiraMono-Medium.ttf -------------------------------------------------------------------------------- /static/FiraMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/FiraMono-Regular.ttf -------------------------------------------------------------------------------- /static/FiraSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/FiraSans-Regular.ttf -------------------------------------------------------------------------------- /static/NotoSerif-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/NotoSerif-Regular.ttf -------------------------------------------------------------------------------- /static/SourceSerifPro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/SourceSerifPro-Bold.ttf -------------------------------------------------------------------------------- /static/UbuntuMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/UbuntuMono-Regular.ttf -------------------------------------------------------------------------------- /static/iosevka-etoile-thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/iosevka-etoile-thin.ttf -------------------------------------------------------------------------------- /static/SourceSerifPro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/SourceSerifPro-Regular.ttf -------------------------------------------------------------------------------- /static/iosevka-etoile-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/iosevka-etoile-regular.ttf -------------------------------------------------------------------------------- /static/iosevka-fixed-extended.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/iosevka-fixed-extended.ttf -------------------------------------------------------------------------------- /whalesong/whalesong-picture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/whalesong/whalesong-picture.jpg -------------------------------------------------------------------------------- /observablehq-stdlib/src/dom/text.js: -------------------------------------------------------------------------------- 1 | export default function(value) { 2 | return document.createTextNode(value); 3 | } 4 | -------------------------------------------------------------------------------- /static/SourceSerifPro-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/SourceSerifPro-SemiBold.ttf -------------------------------------------------------------------------------- /observablehq-stdlib/src/constant.js: -------------------------------------------------------------------------------- 1 | export default function(x) { 2 | return function() { 3 | return x; 4 | }; 5 | } 6 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/now.js: -------------------------------------------------------------------------------- 1 | export default function*() { 2 | while (true) { 3 | yield Date.now(); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /static/iosevka-fixed-extendedmedium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/static/iosevka-fixed-extendedmedium.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_AMS-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_AMS-Regular.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Main-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Main-Bold.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Main-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Main-Bold.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Main-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Main-Bold.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Main-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Main-Italic.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Math-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Math-Italic.ttf -------------------------------------------------------------------------------- /observablehq-stdlib/.gitignore: -------------------------------------------------------------------------------- 1 | *.sublime-workspace 2 | .DS_Store 3 | .esm-cache/ 4 | dist/ 5 | node_modules 6 | npm-debug.log 7 | .nyc_output 8 | -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_AMS-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_AMS-Regular.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_AMS-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_AMS-Regular.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Fraktur-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Fraktur-Bold.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Fraktur-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Fraktur-Bold.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Main-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Main-Italic.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Main-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Main-Italic.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Main-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Main-Regular.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Main-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Main-Regular.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Math-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Math-Italic.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Math-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Math-Italic.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Size1-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Size1-Regular.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Size2-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Size2-Regular.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Size3-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Size3-Regular.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Size4-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Size4-Regular.ttf -------------------------------------------------------------------------------- /observablehq-stdlib/src/index.js: -------------------------------------------------------------------------------- 1 | export {default as FileAttachments} from "./fileAttachment.js"; 2 | export {default as Library} from "./library.js"; 3 | -------------------------------------------------------------------------------- /whalesong/makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | all: index.html 3 | 4 | index.html: index.md 5 | ASAN_OPTIONS="detect_leaks=0" builder index.md index.html 6 | -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Caligraphic-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Caligraphic-Bold.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Fraktur-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Fraktur-Bold.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Fraktur-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Fraktur-Regular.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Fraktur-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Fraktur-Regular.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Main-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Main-BoldItalic.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Main-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Main-BoldItalic.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Main-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Main-Regular.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Math-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Math-BoldItalic.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Math-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Math-BoldItalic.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_SansSerif-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_SansSerif-Bold.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_SansSerif-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_SansSerif-Bold.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_SansSerif-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_SansSerif-Bold.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_SansSerif-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_SansSerif-Italic.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Script-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Script-Regular.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Script-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Script-Regular.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Script-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Script-Regular.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Size1-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Size1-Regular.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Size1-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Size1-Regular.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Size2-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Size2-Regular.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Size2-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Size2-Regular.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Size3-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Size3-Regular.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Size3-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Size3-Regular.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Size4-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Size4-Regular.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Size4-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Size4-Regular.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Caligraphic-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Caligraphic-Bold.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Caligraphic-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Caligraphic-Bold.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Fraktur-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Fraktur-Regular.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Main-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Main-BoldItalic.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Math-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Math-BoldItalic.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_SansSerif-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_SansSerif-Italic.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_SansSerif-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_SansSerif-Italic.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_SansSerif-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_SansSerif-Regular.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_SansSerif-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_SansSerif-Regular.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Typewriter-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Typewriter-Regular.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Caligraphic-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Caligraphic-Regular.ttf -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Caligraphic-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Caligraphic-Regular.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Caligraphic-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Caligraphic-Regular.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_SansSerif-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_SansSerif-Regular.woff2 -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Typewriter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Typewriter-Regular.woff -------------------------------------------------------------------------------- /ddg-laplace-operator/fonts/KaTeX_Typewriter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/ddg-laplace-operator/fonts/KaTeX_Typewriter-Regular.woff2 -------------------------------------------------------------------------------- /observablehq-stdlib/src/dom/input.js: -------------------------------------------------------------------------------- 1 | export default function(type) { 2 | var input = document.createElement("input"); 3 | if (type != null) input.type = type; 4 | return input; 5 | } 6 | -------------------------------------------------------------------------------- /jacobian/et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot -------------------------------------------------------------------------------- /jacobian/et-book/et-book-bold-line-figures/et-book-bold-line-figures.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-bold-line-figures/et-book-bold-line-figures.ttf -------------------------------------------------------------------------------- /jacobian/et-book/et-book-bold-line-figures/et-book-bold-line-figures.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-bold-line-figures/et-book-bold-line-figures.woff -------------------------------------------------------------------------------- /jacobian/et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot -------------------------------------------------------------------------------- /jacobian/et-book/et-book-roman-line-figures/et-book-roman-line-figures.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-roman-line-figures/et-book-roman-line-figures.ttf -------------------------------------------------------------------------------- /jacobian/et-book/et-book-roman-line-figures/et-book-roman-line-figures.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-roman-line-figures/et-book-roman-line-figures.woff -------------------------------------------------------------------------------- /observablehq-stdlib/src/promises/tick.js: -------------------------------------------------------------------------------- 1 | import when from "./when.js"; 2 | 3 | export default function(duration, value) { 4 | return when(Math.ceil((Date.now() + 1) / duration) * duration, value); 5 | } 6 | -------------------------------------------------------------------------------- /jacobian/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot -------------------------------------------------------------------------------- /jacobian/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.ttf -------------------------------------------------------------------------------- /jacobian/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.woff -------------------------------------------------------------------------------- /observablehq-stdlib/src/dom/canvas.js: -------------------------------------------------------------------------------- 1 | export default function(width, height) { 2 | var canvas = document.createElement("canvas"); 3 | canvas.width = width; 4 | canvas.height = height; 5 | return canvas; 6 | } 7 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/require.js: -------------------------------------------------------------------------------- 1 | import {require as requireDefault, requireFrom} from "d3-require"; 2 | 3 | export default function(resolve) { 4 | return resolve == null ? requireDefault : requireFrom(resolve); 5 | } 6 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/promises/delay.js: -------------------------------------------------------------------------------- 1 | export default function(duration, value) { 2 | return new Promise(function(resolve) { 3 | setTimeout(function() { 4 | resolve(value); 5 | }, duration); 6 | }); 7 | } 8 | -------------------------------------------------------------------------------- /jacobian/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.eot -------------------------------------------------------------------------------- /jacobian/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.ttf -------------------------------------------------------------------------------- /jacobian/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.woff -------------------------------------------------------------------------------- /observablehq-stdlib/src/generators/map.js: -------------------------------------------------------------------------------- 1 | export default function*(iterator, transform) { 2 | var result, index = -1; 3 | while (!(result = iterator.next()).done) { 4 | yield transform(result.value, ++index); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/files/index.js: -------------------------------------------------------------------------------- 1 | import buffer from "./buffer.js"; 2 | import text from "./text.js"; 3 | import url from "./url.js"; 4 | 5 | export default { 6 | buffer: buffer, 7 | text: text, 8 | url: url 9 | }; 10 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/promises/index.js: -------------------------------------------------------------------------------- 1 | import delay from "./delay.js"; 2 | import tick from "./tick.js"; 3 | import when from "./when.js"; 4 | 5 | export default { 6 | delay: delay, 7 | tick: tick, 8 | when: when 9 | }; 10 | -------------------------------------------------------------------------------- /jacobian/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot -------------------------------------------------------------------------------- /jacobian/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.ttf -------------------------------------------------------------------------------- /jacobian/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bollu/mathemagic/HEAD/jacobian/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.woff -------------------------------------------------------------------------------- /observablehq-stdlib/src/generators/filter.js: -------------------------------------------------------------------------------- 1 | export default function*(iterator, test) { 2 | var result, index = -1; 3 | while (!(result = iterator.next()).done) { 4 | if (test(result.value, ++index)) { 5 | yield result.value; 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/files/text.js: -------------------------------------------------------------------------------- 1 | export default function(file) { 2 | return new Promise(function(resolve, reject) { 3 | var reader = new FileReader; 4 | reader.onload = function() { resolve(reader.result); }; 5 | reader.onerror = reject; 6 | reader.readAsText(file); 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/files/url.js: -------------------------------------------------------------------------------- 1 | export default function(file) { 2 | return new Promise(function(resolve, reject) { 3 | var reader = new FileReader; 4 | reader.onload = function() { resolve(reader.result); }; 5 | reader.onerror = reject; 6 | reader.readAsDataURL(file); 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/files/buffer.js: -------------------------------------------------------------------------------- 1 | export default function(file) { 2 | return new Promise(function(resolve, reject) { 3 | var reader = new FileReader; 4 | reader.onload = function() { resolve(reader.result); }; 5 | reader.onerror = reject; 6 | reader.readAsArrayBuffer(file); 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/dom/svg.js: -------------------------------------------------------------------------------- 1 | export default function(width, height) { 2 | var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); 3 | svg.setAttribute("viewBox", [0, 0, width, height]); 4 | svg.setAttribute("width", width); 5 | svg.setAttribute("height", height); 6 | return svg; 7 | } 8 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/generators/valueAt.js: -------------------------------------------------------------------------------- 1 | export default function(iterator, i) { 2 | if (!isFinite(i = +i) || i < 0 || i !== i | 0) return; 3 | var result, index = -1; 4 | while (!(result = iterator.next()).done) { 5 | if (++index === i) { 6 | return result.value; 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /observablehq-stdlib/test/fileAttachments-test.js: -------------------------------------------------------------------------------- 1 | import {test} from "tap"; 2 | import {FileAttachments} from "../src/index.js"; 3 | 4 | test("FileAttachments is exported by stdlib", t => { 5 | t.equal(typeof FileAttachments, "function"); 6 | t.equal(FileAttachments.name, "FileAttachments"); 7 | t.end(); 8 | }); 9 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/html.js: -------------------------------------------------------------------------------- 1 | import template from "./template.js"; 2 | 3 | export default template(function(string) { 4 | var template = document.createElement("template"); 5 | template.innerHTML = string.trim(); 6 | return document.importNode(template.content, true); 7 | }, function() { 8 | return document.createElement("span"); 9 | }); 10 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/svg.js: -------------------------------------------------------------------------------- 1 | import template from "./template.js"; 2 | 3 | export default template(function(string) { 4 | var root = document.createElementNS("http://www.w3.org/2000/svg", "g"); 5 | root.innerHTML = string.trim(); 6 | return root; 7 | }, function() { 8 | return document.createElementNS("http://www.w3.org/2000/svg", "g"); 9 | }); 10 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/dom/select.js: -------------------------------------------------------------------------------- 1 | export default function(values) { 2 | var select = document.createElement("select"); 3 | Array.prototype.forEach.call(values, function(value) { 4 | var option = document.createElement("option"); 5 | option.value = option.textContent = value; 6 | select.appendChild(option); 7 | }); 8 | return select; 9 | } 10 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/generators/range.js: -------------------------------------------------------------------------------- 1 | export default function*(start, stop, step) { 2 | start = +start; 3 | stop = +stop; 4 | step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step; 5 | var i = -1, n = Math.max(0, Math.ceil((stop - start) / step)) | 0; 6 | while (++i < n) { 7 | yield start + i * step; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/resolve.js: -------------------------------------------------------------------------------- 1 | export default function resolve(name, base) { 2 | if (/^(\w+:)|\/\//i.test(name)) return name; 3 | if (/^[.]{0,2}\//i.test(name)) return new URL(name, base == null ? location : base).href; 4 | if (!name.length || /^[\s._]/.test(name) || /\s$/.test(name)) throw new Error("illegal name"); 5 | return "https://unpkg.com/" + name; 6 | } 7 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/dom/uid.js: -------------------------------------------------------------------------------- 1 | var count = 0; 2 | 3 | export default function(name) { 4 | return new Id("O-" + (name == null ? "" : name + "-") + ++count); 5 | } 6 | 7 | function Id(id) { 8 | this.id = id; 9 | this.href = new URL(`#${id}`, location) + ""; 10 | } 11 | 12 | Id.prototype.toString = function() { 13 | return "url(" + this.href + ")"; 14 | }; 15 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/mutable.js: -------------------------------------------------------------------------------- 1 | import observe from "./generators/observe.js"; 2 | 3 | export default function Mutable(value) { 4 | let change; 5 | Object.defineProperties(this, { 6 | generator: {value: observe(_ => void (change = _))}, 7 | value: {get: () => value, set: x => change(value = x)} 8 | }); 9 | if (value !== undefined) change(value); 10 | } 11 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/generators/worker.js: -------------------------------------------------------------------------------- 1 | import disposable from "./disposable.js"; 2 | 3 | export default function worker(source) { 4 | const url = URL.createObjectURL(new Blob([source], {type: "text/javascript"})); 5 | const worker = new Worker(url); 6 | return disposable(worker, () => { 7 | worker.terminate(); 8 | URL.revokeObjectURL(url); 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/dom/range.js: -------------------------------------------------------------------------------- 1 | export default function(min, max, step) { 2 | if (arguments.length === 1) max = min, min = null; 3 | var input = document.createElement("input"); 4 | input.min = min = min == null ? 0 : +min; 5 | input.max = max = max == null ? 1 : +max; 6 | input.step = step == null ? "any" : step = +step; 7 | input.type = "range"; 8 | return input; 9 | } 10 | -------------------------------------------------------------------------------- /observablehq-stdlib/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "parserOptions": { 4 | "sourceType": "module", 5 | "ecmaVersion": 8 6 | }, 7 | "env": { 8 | "browser": true, 9 | "es6": true, 10 | "node": true 11 | }, 12 | "rules": { 13 | "semi": 2, 14 | "no-process-env": 2, 15 | "no-cond-assign": 0, 16 | "no-redeclare": 0 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/dom/context2d.js: -------------------------------------------------------------------------------- 1 | export default function(width, height, dpi) { 2 | if (dpi == null) dpi = devicePixelRatio; 3 | var canvas = document.createElement("canvas"); 4 | canvas.width = width * dpi; 5 | canvas.height = height * dpi; 6 | canvas.style.width = width + "px"; 7 | var context = canvas.getContext("2d"); 8 | context.scale(dpi, dpi); 9 | return context; 10 | } 11 | -------------------------------------------------------------------------------- /declarative/makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all server 2 | all: index.html server 3 | 4 | server: 5 | python3 -m http.server 6 | 7 | index.html: index.md anim.out minanim.js script.js 8 | ASAN_OPTIONS="detect_leaks=0" ./anim.out > ANIMGENERATED.js 9 | ASAN_OPTIONS="detect_leaks=0" builder index.md index.html 10 | 11 | anim.out: anim.cpp 12 | g++ -g -O1 -std=c++11 -fsanitize=address -fsanitize=undefined anim.cpp -o anim.out 13 | 14 | -------------------------------------------------------------------------------- /observablehq-stdlib/stdlib.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": ".", 5 | "file_exclude_patterns": ["*.sublime-workspace"], 6 | "folder_exclude_patterns": [".esm-cache", "dist"] 7 | } 8 | ], 9 | "build_systems": [ 10 | { 11 | "name": "yarn test", 12 | "cmd": ["yarn", "test"], 13 | "file_regex": "\\((...*?):([0-9]*):([0-9]*)\\)", 14 | "working_dir": "$project_path" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /observablehq-stdlib/test/DOM/uid-test.js: -------------------------------------------------------------------------------- 1 | import {test} from "tap"; 2 | import UID from "../../src/dom/uid.js"; 3 | 4 | test("UID", t => { 5 | global.location = "https://test.com/"; 6 | const hi = UID("hi"); 7 | t.deepEqual(hi, { 8 | id: "O-hi-1", 9 | href: "https://test.com/#O-hi-1" 10 | }); 11 | t.equal(hi.toString(), "url(https://test.com/#O-hi-1)"); 12 | const anon = UID(); 13 | t.equal(anon.toString(), "url(https://test.com/#O-2)"); 14 | t.end(); 15 | }); 16 | -------------------------------------------------------------------------------- /declarative/mono.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-weight: normal; 3 | background-color: white; 4 | } 5 | 6 | .linenum { color: #000000; } 7 | 8 | .keyword { 9 | color: black; 10 | font-weight: bold; 11 | text-decoration: underline; 12 | } 13 | 14 | .type { 15 | color: black; 16 | font-weight: bold; 17 | } 18 | 19 | .string { 20 | color: gray; 21 | } 22 | 23 | .comment { 24 | color: #222222; 25 | font-style: italic; 26 | } 27 | 28 | .number { 29 | color: black; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/width.js: -------------------------------------------------------------------------------- 1 | import observe from "./generators/observe.js"; 2 | 3 | export default function() { 4 | return observe(function(change) { 5 | var width = change(document.body.clientWidth); 6 | function resized() { 7 | var w = document.body.clientWidth; 8 | if (w !== width) change(width = w); 9 | } 10 | window.addEventListener("resize", resized); 11 | return function() { 12 | window.removeEventListener("resize", resized); 13 | }; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/generators/disposable.js: -------------------------------------------------------------------------------- 1 | import that from "../that.js"; 2 | 3 | export default function disposable(value, dispose) { 4 | let done = false; 5 | if (typeof dispose !== "function") { 6 | throw new Error("dispose is not a function"); 7 | } 8 | return { 9 | [Symbol.iterator]: that, 10 | next: () => done ? {done: true} : (done = true, {done: false, value}), 11 | return: () => (done = true, dispose(value), {done: true}), 12 | throw: () => ({done: done = true}) 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /observablehq-stdlib/test/index-test.js: -------------------------------------------------------------------------------- 1 | import {test} from "tap"; 2 | import {Library} from "../src/index.js"; 3 | 4 | test("new Library returns a library with the expected keys", async t => { 5 | t.deepEqual(Object.keys(new Library()).sort(), [ 6 | "DOM", 7 | "FileAttachment", 8 | "Files", 9 | "Generators", 10 | "Mutable", 11 | "Promises", 12 | "html", 13 | "md", 14 | "now", 15 | "require", 16 | "resolve", 17 | "svg", 18 | "tex", 19 | "width" 20 | ]); 21 | t.end(); 22 | }); 23 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/generators/index.js: -------------------------------------------------------------------------------- 1 | import disposable from "./disposable.js"; 2 | import filter from "./filter.js"; 3 | import input from "./input.js"; 4 | import map from "./map.js"; 5 | import observe from "./observe.js"; 6 | import queue from "./queue.js"; 7 | import range from "./range.js"; 8 | import valueAt from "./valueAt.js"; 9 | import worker from "./worker.js"; 10 | 11 | export default { 12 | disposable: disposable, 13 | filter: filter, 14 | input: input, 15 | map: map, 16 | observe: observe, 17 | queue: queue, 18 | range: range, 19 | valueAt: valueAt, 20 | worker: worker 21 | }; 22 | -------------------------------------------------------------------------------- /observablehq-stdlib/.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | strategy: 9 | matrix: 10 | os: [ubuntu-latest] 11 | node-version: [10.x, 12.x] 12 | 13 | runs-on: ${{ matrix.os }} 14 | 15 | steps: 16 | - uses: actions/checkout@v1 17 | - name: Use Node.js ${{ matrix.node-version }} 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: ${{ matrix.node-version }} 21 | - name: yarn install and test 22 | run: | 23 | yarn install --frozen-lockfile 24 | yarn test 25 | env: 26 | CI: true 27 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/dom/index.js: -------------------------------------------------------------------------------- 1 | import canvas from "./canvas.js"; 2 | import context2d from "./context2d.js"; 3 | import download from "./download.js"; 4 | import element from "./element.js"; 5 | import input from "./input.js"; 6 | import range from "./range.js"; 7 | import select from "./select.js"; 8 | import svg from "./svg.js"; 9 | import text from "./text.js"; 10 | import uid from "./uid.js"; 11 | 12 | export default { 13 | canvas: canvas, 14 | context2d: context2d, 15 | download: download, 16 | element: element, 17 | input: input, 18 | range: range, 19 | select: select, 20 | svg: svg, 21 | text: text, 22 | uid: uid 23 | }; 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Mathemagic](https://bollu.github.io/mathemagic/) 2 | - [Link to the website](https://bollu.github.io/mathemagic/) 3 | 4 | 5 | The goal of this side project is to create beautiful rendering of ideas 6 | in differential geometry which enchant me. So I hope to have renderings 7 | of homology, cohomology, exterior calculus, the laplace operator, the heat 8 | equation, the wave equation, curvature, and holonomy. 9 | 10 | While I'm at it, I plan to steal ideas and javascript from 11 | [observableHQ](https://observablehq.com/), whom I deeply admire. 12 | 13 | - [`selectAll` semantics of d3](https://github.com/d3/d3-selection/blob/v1.4.1/README.md#selectAll) 14 | -------------------------------------------------------------------------------- /observablehq-stdlib/rollup.config.js: -------------------------------------------------------------------------------- 1 | import node from "rollup-plugin-node-resolve"; 2 | import {terser} from "rollup-plugin-terser"; 3 | import * as meta from "./package.json"; 4 | 5 | const copyright = `// @observablehq/stdlib v${meta.version} Copyright ${(new Date).getFullYear()} Observable, Inc.`; 6 | 7 | export default [ 8 | { 9 | input: "src/index.js", 10 | plugins: [ 11 | node(), 12 | terser({ 13 | output: {preamble: copyright}, 14 | mangle: {reserved: ["RequireError"]} 15 | }) 16 | ], 17 | output: { 18 | format: "umd", 19 | extend: true, 20 | name: "observablehq", 21 | file: "dist/stdlib.js" 22 | } 23 | } 24 | ]; 25 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/promises/when.js: -------------------------------------------------------------------------------- 1 | import constant from "../constant.js"; 2 | 3 | var timeouts = new Map; 4 | 5 | function timeout(now, time) { 6 | var t = new Promise(function(resolve) { 7 | timeouts.delete(time); 8 | var delay = time - now; 9 | if (!(delay > 0)) throw new Error("invalid time"); 10 | if (delay > 0x7fffffff) throw new Error("too long to wait"); 11 | setTimeout(resolve, delay); 12 | }); 13 | timeouts.set(time, t); 14 | return t; 15 | } 16 | 17 | export default function when(time, value) { 18 | var now; 19 | return (now = timeouts.get(time = +time)) ? now.then(constant(value)) 20 | : (now = Date.now()) >= time ? Promise.resolve(value) 21 | : timeout(now, time).then(constant(value)); 22 | } 23 | -------------------------------------------------------------------------------- /observablehq-stdlib/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Observable, Inc. 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose 4 | with or without fee is hereby granted, provided that the above copyright notice 5 | and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 8 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 9 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 10 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 11 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 12 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 13 | THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/generators/queue.js: -------------------------------------------------------------------------------- 1 | import that from "../that.js"; 2 | 3 | export default function(initialize) { 4 | let resolve; 5 | const queue = []; 6 | const dispose = initialize(push); 7 | 8 | if (dispose != null && typeof dispose !== "function") { 9 | throw new Error(typeof dispose.then === "function" 10 | ? "async initializers are not supported" 11 | : "initializer returned something, but not a dispose function"); 12 | } 13 | 14 | function push(x) { 15 | queue.push(x); 16 | if (resolve) resolve(queue.shift()), resolve = null; 17 | return x; 18 | } 19 | 20 | function next() { 21 | return {done: false, value: queue.length 22 | ? Promise.resolve(queue.shift()) 23 | : new Promise(_ => (resolve = _))}; 24 | } 25 | 26 | return { 27 | [Symbol.iterator]: that, 28 | throw: () => ({done: true}), 29 | return: () => (dispose != null && dispose(), {done: true}), 30 | next 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/generators/observe.js: -------------------------------------------------------------------------------- 1 | import that from "../that.js"; 2 | 3 | export default function(initialize) { 4 | let stale = false; 5 | let value; 6 | let resolve; 7 | const dispose = initialize(change); 8 | 9 | if (dispose != null && typeof dispose !== "function") { 10 | throw new Error(typeof dispose.then === "function" 11 | ? "async initializers are not supported" 12 | : "initializer returned something, but not a dispose function"); 13 | } 14 | 15 | function change(x) { 16 | if (resolve) resolve(x), resolve = null; 17 | else stale = true; 18 | return value = x; 19 | } 20 | 21 | function next() { 22 | return {done: false, value: stale 23 | ? (stale = false, Promise.resolve(value)) 24 | : new Promise(_ => (resolve = _))}; 25 | } 26 | 27 | return { 28 | [Symbol.iterator]: that, 29 | throw: () => ({done: true}), 30 | return: () => (dispose != null && dispose(), {done: true}), 31 | next 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /observablehq-stdlib/test/generators/disposable-test.js: -------------------------------------------------------------------------------- 1 | import {test} from "tap"; 2 | import disposable from "../../src/generators/disposable.js"; 3 | 4 | test("disposable(value, dispose) yields the specified value", async t => { 5 | const foo = {}; 6 | const generator = disposable(foo, () => {}); 7 | t.deepEqual(generator.next(), {done: false, value: foo}); 8 | t.deepEqual(generator.next(), {done: true}); 9 | t.end(); 10 | }); 11 | 12 | test("disposable(value, dispose) defines generator.return", async t => { 13 | let passedFoo; 14 | const foo = {}; 15 | const generator = disposable(foo, _ => (passedFoo = _)); 16 | t.deepEqual(generator.return(), {done: true}); 17 | t.equal(passedFoo, foo); 18 | t.deepEqual(generator.next(), {done: true}); 19 | t.end(); 20 | }); 21 | 22 | test("disposable(value, dispose) defines generator.throw", async t => { 23 | const generator = disposable(42, () => {}); 24 | t.deepEqual(generator.throw(new Error()), {done: true}); 25 | t.deepEqual(generator.next(), {done: true}); 26 | t.end(); 27 | }); 28 | -------------------------------------------------------------------------------- /observablehq-stdlib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@observablehq/stdlib", 3 | "version": "3.3.1", 4 | "license": "ISC", 5 | "main": "dist/stdlib.js", 6 | "module": "src/index.js", 7 | "author": { 8 | "name": "Observable, Inc.", 9 | "url": "https://observablehq.com" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/observablehq/stdlib.git" 14 | }, 15 | "scripts": { 16 | "test": "tap 'test/**/*-test.js'", 17 | "prepublishOnly": "rollup -c", 18 | "postpublish": "git push && git push --tags" 19 | }, 20 | "husky": { 21 | "hooks": { 22 | "pre-commit": "eslint . && yarn test" 23 | } 24 | }, 25 | "files": [ 26 | "src/**/*.js", 27 | "dist/**/*.js" 28 | ], 29 | "dependencies": { 30 | "d3-require": "^1.2.4" 31 | }, 32 | "devDependencies": { 33 | "eslint": "^6.7.2", 34 | "husky": "^3.1.0", 35 | "rollup": "^1.27.8", 36 | "rollup-plugin-node-resolve": "^5.0.0", 37 | "rollup-plugin-terser": "^5.2.0", 38 | "tap": "^14.10.2" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/dom/download.js: -------------------------------------------------------------------------------- 1 | export default function(value, name = "untitled", label = "Save") { 2 | const a = document.createElement("a"); 3 | const b = a.appendChild(document.createElement("button")); 4 | b.textContent = label; 5 | a.download = name; 6 | 7 | async function reset() { 8 | await new Promise(requestAnimationFrame); 9 | URL.revokeObjectURL(a.href); 10 | a.removeAttribute("href"); 11 | b.textContent = label; 12 | b.disabled = false; 13 | } 14 | 15 | a.onclick = async event => { 16 | b.disabled = true; 17 | if (a.href) return reset(); // Already saved. 18 | b.textContent = "Saving…"; 19 | try { 20 | const object = await (typeof value === "function" ? value() : value); 21 | b.textContent = "Download"; 22 | a.href = URL.createObjectURL(object); // eslint-disable-line require-atomic-updates 23 | } catch (ignore) { 24 | b.textContent = label; 25 | } 26 | if (event.eventPhase) return reset(); // Already downloaded. 27 | b.disabled = false; 28 | }; 29 | 30 | return a; 31 | } 32 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/tex.js: -------------------------------------------------------------------------------- 1 | var raw = String.raw; 2 | 3 | function style(href) { 4 | return new Promise(function(resolve, reject) { 5 | var link = document.createElement("link"); 6 | link.rel = "stylesheet"; 7 | link.href = href; 8 | link.onerror = reject; 9 | link.onload = resolve; 10 | document.head.appendChild(link); 11 | }); 12 | } 13 | 14 | export default function(require) { 15 | return function() { 16 | return Promise.all([ 17 | require("@observablehq/katex@0.11.1/dist/katex.min.js"), 18 | require.resolve("@observablehq/katex@0.11.1/dist/katex.min.css").then(style) 19 | ]).then(function(values) { 20 | var katex = values[0], tex = renderer(); 21 | 22 | function renderer(options) { 23 | return function() { 24 | var root = document.createElement("div"); 25 | katex.render(raw.apply(String, arguments), root, options); 26 | return root.removeChild(root.firstChild); 27 | }; 28 | } 29 | 30 | tex.options = renderer; 31 | tex.block = renderer({displayMode: true}); 32 | return tex; 33 | }); 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/generators/input.js: -------------------------------------------------------------------------------- 1 | import observe from "./observe.js"; 2 | 3 | export default function(input) { 4 | return observe(function(change) { 5 | var event = eventof(input), value = valueof(input); 6 | function inputted() { change(valueof(input)); } 7 | input.addEventListener(event, inputted); 8 | if (value !== undefined) change(value); 9 | return function() { input.removeEventListener(event, inputted); }; 10 | }); 11 | } 12 | 13 | function valueof(input) { 14 | switch (input.type) { 15 | case "range": 16 | case "number": return input.valueAsNumber; 17 | case "date": return input.valueAsDate; 18 | case "checkbox": return input.checked; 19 | case "file": return input.multiple ? input.files : input.files[0]; 20 | case "select-multiple": return Array.from(input.selectedOptions, o => o.value); 21 | default: return input.value; 22 | } 23 | } 24 | 25 | function eventof(input) { 26 | switch (input.type) { 27 | case "button": 28 | case "submit": 29 | case "checkbox": return "click"; 30 | case "file": return "change"; 31 | default: return "input"; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/dom/element.js: -------------------------------------------------------------------------------- 1 | var namespaces = { 2 | math: "http://www.w3.org/1998/Math/MathML", 3 | svg: "http://www.w3.org/2000/svg", 4 | xhtml: "http://www.w3.org/1999/xhtml", 5 | xlink: "http://www.w3.org/1999/xlink", 6 | xml: "http://www.w3.org/XML/1998/namespace", 7 | xmlns: "http://www.w3.org/2000/xmlns/" 8 | }; 9 | 10 | export default function(name, attributes) { 11 | var prefix = name += "", i = prefix.indexOf(":"), value; 12 | if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1); 13 | var element = namespaces.hasOwnProperty(prefix) // eslint-disable-line no-prototype-builtins 14 | ? document.createElementNS(namespaces[prefix], name) 15 | : document.createElement(name); 16 | if (attributes) for (var key in attributes) { 17 | prefix = key, i = prefix.indexOf(":"), value = attributes[key]; 18 | if (i >= 0 && (prefix = key.slice(0, i)) !== "xmlns") key = key.slice(i + 1); 19 | if (namespaces.hasOwnProperty(prefix)) element.setAttributeNS(namespaces[prefix], key, value); // eslint-disable-line no-prototype-builtins 20 | else element.setAttribute(key, value); 21 | } 22 | return element; 23 | } 24 | -------------------------------------------------------------------------------- /observablehq-stdlib/test/promises/delay-test.js: -------------------------------------------------------------------------------- 1 | import {test} from "tap"; 2 | import delay from "../../src/promises/delay.js"; 3 | import tick from "../../src/promises/tick.js"; 4 | 5 | test("delay(duration) resolves with undefined", async t => { 6 | t.equal(await delay(50), undefined); 7 | t.end(); 8 | }); 9 | 10 | test("delay(duration) resolves after the specified duration", async t => { 11 | const then = Date.now(); 12 | await delay(150); 13 | const delta = Date.now() - then; 14 | t.ok(130 <= delta && delta <= 170); 15 | t.end(); 16 | }); 17 | 18 | test("delay(duration, value) resolves with the specified value", async t => { 19 | t.equal(await delay(50, "foo"), "foo"); 20 | t.end(); 21 | }); 22 | 23 | test("delay(duration, value) resolves with the specified value after the specified duration", async t => { 24 | const then = Date.now(); 25 | t.equal(await delay(150, "foo"), "foo"); 26 | const delta = Date.now() - then; 27 | t.ok(130 <= delta && delta <= 170); 28 | t.end(); 29 | }); 30 | 31 | test("tick(1000) resolves near the second boundary", async t => { 32 | await tick(1000); 33 | const now = Date.now(); 34 | t.ok(now % 1000 < 10, `${now % 1000} deviation from the second`); 35 | t.end(); 36 | }); 37 | -------------------------------------------------------------------------------- /observablehq-stdlib/test/generators/generators-test.js: -------------------------------------------------------------------------------- 1 | import {test} from "tap"; 2 | import filter from "../../src/generators/filter"; 3 | import map from "../../src/generators/map"; 4 | import range from "../../src/generators/range"; 5 | import valueAt from "../../src/generators/valueAt"; 6 | import observe from "../../src/generators/observe"; 7 | import queue from "../../src/generators/queue"; 8 | 9 | test("filter(value, fn) filters", t => { 10 | function* input() { 11 | yield* [1, 2, 3, 4]; 12 | } 13 | t.deepEqual(Array.from(filter(input(), i => i % 2 === 0)), [2, 4]); 14 | t.end(); 15 | }); 16 | 17 | test("map(value, fn) maps", t => { 18 | function* input() { 19 | yield* [1, 2, 3, 4]; 20 | } 21 | t.deepEqual(Array.from(map(input(), i => i * 2)), [2, 4, 6, 8]); 22 | t.end(); 23 | }); 24 | 25 | test("range(start, stop) generates a range", t => { 26 | t.deepEqual(Array.from(range(1, 4)), [1, 2, 3]); 27 | t.deepEqual(Array.from(range(1, 5, 2)), [1, 3]); 28 | t.deepEqual(Array.from(range(3)), [0, 1, 2]); 29 | t.end(); 30 | }); 31 | 32 | test("valueAt(generator, i) picks a value", t => { 33 | function* input() { 34 | yield* [1, 2, 3, 4]; 35 | } 36 | t.equal(valueAt(input(), 2), 3); 37 | t.equal(valueAt(input()), undefined); 38 | t.end(); 39 | }); 40 | 41 | test("observe only yields the most recent value", async t => { 42 | let o = observe(change => { 43 | change(1); 44 | change(2); 45 | }); 46 | t.equal(await o.next().value, 2); 47 | t.end(); 48 | }); 49 | 50 | test("queue yields all values", async t => { 51 | let q = queue(change => { 52 | change(1); 53 | change(2); 54 | }); 55 | t.equal(await q.next().value, 1); 56 | t.equal(await q.next().value, 2); 57 | t.end(); 58 | }); 59 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/fileAttachment.js: -------------------------------------------------------------------------------- 1 | async function remote_fetch(file) { 2 | const response = await fetch(await file.url()); 3 | if (!response.ok) throw new Error(`Unable to load file: ${file.name}`); 4 | return response; 5 | } 6 | 7 | class FileAttachment { 8 | constructor(url, name) { 9 | Object.defineProperties(this, { 10 | _url: {value: url}, 11 | name: {value: name, enumerable: true} 12 | }); 13 | } 14 | async url() { 15 | return this._url; 16 | } 17 | async blob() { 18 | return (await remote_fetch(this)).blob(); 19 | } 20 | async arrayBuffer() { 21 | return (await remote_fetch(this)).arrayBuffer(); 22 | } 23 | async text() { 24 | return (await remote_fetch(this)).text(); 25 | } 26 | async json() { 27 | return (await remote_fetch(this)).json(); 28 | } 29 | async stream() { 30 | return (await remote_fetch(this)).body; 31 | } 32 | async image() { 33 | const url = await this.url(); 34 | return new Promise((resolve, reject) => { 35 | const i = new Image; 36 | if (new URL(url, document.baseURI).origin !== new URL(location).origin) { 37 | i.crossOrigin = "anonymous"; 38 | } 39 | i.onload = () => resolve(i); 40 | i.onerror = () => reject(new Error(`Unable to load file: ${this.name}`)); 41 | i.src = url; 42 | }); 43 | } 44 | } 45 | 46 | export function NoFileAttachments(name) { 47 | throw new Error(`File not found: ${name}`); 48 | } 49 | 50 | export default function FileAttachments(resolve) { 51 | return name => { 52 | const url = resolve(name += ""); // Returns a Promise, string, or null. 53 | if (url == null) throw new Error(`File not found: ${name}`); 54 | return new FileAttachment(url, name); 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/md.js: -------------------------------------------------------------------------------- 1 | import template from "./template.js"; 2 | 3 | const HL_ROOT = 4 | "https://cdn.jsdelivr.net/npm/@observablehq/highlight.js@2.0.0/"; 5 | 6 | export default function(require) { 7 | return function() { 8 | return require("marked@0.3.12/marked.min.js").then(function(marked) { 9 | return template( 10 | function(string) { 11 | var root = document.createElement("div"); 12 | root.innerHTML = marked(string, {langPrefix: ""}).trim(); 13 | var code = root.querySelectorAll("pre code[class]"); 14 | if (code.length > 0) { 15 | require(HL_ROOT + "highlight.min.js").then(function(hl) { 16 | code.forEach(function(block) { 17 | function done() { 18 | hl.highlightBlock(block); 19 | block.parentNode.classList.add("observablehq--md-pre"); 20 | } 21 | if (hl.getLanguage(block.className)) { 22 | done(); 23 | } else { 24 | require(HL_ROOT + "async-languages/index.js") 25 | .then(index => { 26 | if (index.has(block.className)) { 27 | return require(HL_ROOT + 28 | "async-languages/" + 29 | index.get(block.className)).then(language => { 30 | hl.registerLanguage(block.className, language); 31 | }); 32 | } 33 | }) 34 | .then(done, done); 35 | } 36 | }); 37 | }); 38 | } 39 | return root; 40 | }, 41 | function() { 42 | return document.createElement("div"); 43 | } 44 | ); 45 | }); 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/library.js: -------------------------------------------------------------------------------- 1 | import {require as requireDefault} from "d3-require"; 2 | import constant from "./constant.js"; 3 | import DOM from "./dom/index.js"; 4 | import Files from "./files/index.js"; 5 | import {NoFileAttachments} from "./fileAttachment.js"; 6 | import Generators from "./generators/index.js"; 7 | import html from "./html.js"; 8 | import md from "./md.js"; 9 | import Mutable from "./mutable.js"; 10 | import now from "./now.js"; 11 | import Promises from "./promises/index.js"; 12 | import resolve from "./resolve.js"; 13 | import requirer from "./require.js"; 14 | import svg from "./svg.js"; 15 | import tex from "./tex.js"; 16 | import width from "./width.js"; 17 | 18 | export default Object.assign(function Library(resolver) { 19 | const require = requirer(resolver); 20 | Object.defineProperties(this, { 21 | DOM: {value: DOM, writable: true, enumerable: true}, 22 | FileAttachment: {value: constant(NoFileAttachments), writable: true, enumerable: true}, 23 | Files: {value: Files, writable: true, enumerable: true}, 24 | Generators: {value: Generators, writable: true, enumerable: true}, 25 | html: {value: constant(html), writable: true, enumerable: true}, 26 | md: {value: md(require), writable: true, enumerable: true}, 27 | Mutable: {value: constant(Mutable), writable: true, enumerable: true}, 28 | now: {value: now, writable: true, enumerable: true}, 29 | Promises: {value: Promises, writable: true, enumerable: true}, 30 | require: {value: constant(require), writable: true, enumerable: true}, 31 | resolve: {value: constant(resolve), writable: true, enumerable: true}, 32 | svg: {value: constant(svg), writable: true, enumerable: true}, 33 | tex: {value: tex(require), writable: true, enumerable: true}, 34 | width: {value: width, writable: true, enumerable: true} 35 | }); 36 | }, {resolve: requireDefault.resolve}); 37 | -------------------------------------------------------------------------------- /three.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | My first three.js app 6 | 10 | 11 | 12 | 13 | 14 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /observablehq-stdlib/src/template.js: -------------------------------------------------------------------------------- 1 | export default function template(render, wrapper) { 2 | return function(strings) { 3 | var string = strings[0], 4 | parts = [], part, 5 | root = null, 6 | node, nodes, 7 | walker, 8 | i, n, j, m, k = -1; 9 | 10 | // Concatenate the text using comments as placeholders. 11 | for (i = 1, n = arguments.length; i < n; ++i) { 12 | part = arguments[i]; 13 | if (part instanceof Node) { 14 | parts[++k] = part; 15 | string += ""; 16 | } else if (Array.isArray(part)) { 17 | for (j = 0, m = part.length; j < m; ++j) { 18 | node = part[j]; 19 | if (node instanceof Node) { 20 | if (root === null) { 21 | parts[++k] = root = document.createDocumentFragment(); 22 | string += ""; 23 | } 24 | root.appendChild(node); 25 | } else { 26 | root = null; 27 | string += node; 28 | } 29 | } 30 | root = null; 31 | } else { 32 | string += part; 33 | } 34 | string += strings[i]; 35 | } 36 | 37 | // Render the text. 38 | root = render(string); 39 | 40 | // Walk the rendered content to replace comment placeholders. 41 | if (++k > 0) { 42 | nodes = new Array(k); 43 | walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT, null, false); 44 | while (walker.nextNode()) { 45 | node = walker.currentNode; 46 | if (/^o:/.test(node.nodeValue)) { 47 | nodes[+node.nodeValue.slice(2)] = node; 48 | } 49 | } 50 | for (i = 0; i < k; ++i) { 51 | if (node = nodes[i]) { 52 | node.parentNode.replaceChild(parts[i], node); 53 | } 54 | } 55 | } 56 | 57 | // Is the rendered content 58 | // … a parent of a single child? Detach and return the child. 59 | // … a document fragment? Replace the fragment with an element. 60 | // … some other node? Return it. 61 | return root.childNodes.length === 1 ? root.removeChild(root.firstChild) 62 | : root.nodeType === 11 ? ((node = wrapper()).appendChild(root), node) 63 | : root; 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /ddg-laplace-operator/auto-render.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("katex")):"function"==typeof define&&define.amd?define(["katex"],t):"object"==typeof exports?exports.renderMathInElement=t(require("katex")):e.renderMathInElement=t(e.katex)}("undefined"!=typeof self?self:this,function(e){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=1)}([function(t,r){t.exports=e},function(e,t,r){"use strict";r.r(t);var n=r(0),o=r.n(n),a=function(e,t,r){for(var n=r,o=0,a=e.length;n M Guid; create = undefined 38 | -- start :: Transition a -> M (); start = undefined 39 | -- waitforall :: M (); waitforall = undefined 40 | 41 | 42 | -- growLineFromTo :: Guid -> Transition a 43 | -- growLineFromTo l = undefined 44 | 45 | -- APPLICATION 46 | -- gridpts_ :: [Renderable] 47 | -- gridpts_ = [Circle (Point cx cy) (Radius 0) | cx <- [0,10..100], cy <- [0,10..100]] 48 | -- 49 | -- polypts_ :: [Point] 50 | -- polypts_ = [Point 100 200, Point 200 300, Point 100 200] 51 | -- 52 | -- centroid :: [Point] -> Point 53 | -- centroid ps = sum ps -- todo fix 54 | -- 55 | -- barrier :: Point -> Float; barrier = undefined 56 | -- 57 | -- stepInteriorPt = undefined 58 | -- 59 | -- iterates :: (a -> Bool) -> (a -> a) -> a -> [a] 60 | -- iterates p f a = case p a of False -> []; True -> a:iterates p f (f a) 61 | 62 | {- 63 | data M a = M { mval :: a, mstagenum :: Int } 64 | instance Functor M where 65 | instance Applicative M where 66 | instance Monad M where 67 | anim :: M () 68 | anim = do 69 | gridpts <- forM gridpts_ create 70 | lines <- forM (zipWith Line polypts_ (tail polypts_)) create 71 | potentialpt <- create (Circle (centroid polypts_) (Radius 0)) 72 | 73 | start $ Stagger (Sec 0.2) [SlowEnd (Sec 0.5) CircleRadius (Radius 1) pt | pt <- gridpts] 74 | waitforall 75 | 76 | start $ Onebyone (map growLineFromTo lines) 77 | waitforall 78 | 79 | start $ SlowEnd (Sec 0.5) CircleRadius (Radius 1) potentialpt 80 | waitforall 81 | 82 | let locs = iterates (\x -> barrier x > 100) stepInteriorPt (centroid polypts_) 83 | start (Onebyone [SlowEnd (Sec 0.5) CircleCenter loc potentialpt | loc <- locs]) 84 | -} 85 | 86 | onebyone :: [Transition] -> Transition; 87 | onebyone [x] = x 88 | onebyone (x:xs) = Sequence x (onebyone xs) 89 | 90 | animpingpong = 91 | let left = Point 50 100; right = Point 300 100; 92 | circ = Circle (Guid "c") left (Radius 0) 93 | grow = SlowEnd (Sec 0.5) CircleRadius (ValRadius . Radius $ 1) circ 94 | shrink = SlowEnd (Sec 0.5) CircleRadius (ValRadius . Radius $ 0) circ 95 | goleft = SlowEnd (Sec 0.5) CircleCenter (ValPoint left) circ 96 | wait = Wait (Sec 0.5) 97 | goright = SlowEnd (Sec 0.5) CircleCenter (ValPoint right) circ 98 | in onebyone [grow, goleft, wait, goright, shrink] 99 | 100 | 101 | 102 | main :: IO () 103 | main = putStrLn "foo" 104 | -------------------------------------------------------------------------------- /declarative/minanim.js: -------------------------------------------------------------------------------- 1 | function assert_precondition(t, out = {}, tstart = 0) { 2 | console.assert(typeof(t) === "number"); 3 | console.assert(typeof(out) === "object"); 4 | console.assert(typeof(tstart) === "number"); 5 | console.assert(t >= tstart); 6 | return [out, tstart]; 7 | } 8 | 9 | function anim_delay(duration) { 10 | console.assert(typeof(duration) === "number"); 11 | let f = function(t, out, tstart) { 12 | [out, tstart] = assert_precondition(t, out, tstart); return out; 13 | } 14 | f.duration = duration; 15 | f.par = ((g) => anim_parallel(f, g)); 16 | f.seq = ((g) => anim_sequence(f, g)); 17 | return f; 18 | } 19 | 20 | function anim_const(field, v) { 21 | let f = function(t, out, tstart) { 22 | [out, tstart] = assert_precondition(t, out, tstart); out[field] = v; return out; 23 | }; 24 | f.duration = 0; 25 | f.par = ((g) => anim_parallel(f, g)); 26 | f.seq = ((g) => anim_sequence(f, g)); 27 | return f; 28 | } 29 | 30 | function ease_linear(vstart, tlin, vend) { return (1.0 - tlin) * vstart + tlin * vend; } 31 | 32 | function ease_cubic(vstart, tlin, vend) { 33 | const cube = (1 - tlin)**3; return cube * vstart + (1 - cube) * vend; 34 | } 35 | function ease_out_back(vstart, tlin, vend) { 36 | const c1 = 1.70158; const c3 = c1 + 1; const t = 1 + c3 * Math.pow(tlin - 1, 3) + c1 * Math.pow(tlin - 1, 2); 37 | return (1-t) * vstart + t*vend; 38 | } 39 | 40 | 41 | function anim_interpolated(fease, field, vend, duration) { 42 | let f = function(t, out, tstart) { 43 | [out, tstart] = assert_precondition(t, out, tstart); 44 | if (t < tstart + duration && duration !== 0) { 45 | const tlin = (t - tstart) /duration; 46 | console.assert(tlin >= 0); 47 | console.assert(tlin <= 1); 48 | const vstart = out[field]; 49 | out[field] = fease(vstart, tlin, vend); 50 | } else { out[field] = vend; } 51 | return out; 52 | }; 53 | f.duration = duration; 54 | f.par = ((g) => anim_parallel(f, g)); 55 | f.seq = ((g) => anim_sequence(f, g)); 56 | return f; 57 | 58 | } 59 | 60 | function anim_sequence(anim1, anim2) { 61 | const duration = anim1.duration + anim2.duration; 62 | let f = function(t, out, tstart) { 63 | [out, tstart] = assert_precondition(t, out, tstart); 64 | anim1(t, out, tstart); 65 | if (t >= tstart + anim1.duration) { anim2(t, out, tstart + anim1.duration); } 66 | return out; 67 | } 68 | f.duration = duration; 69 | f.par = ((g) => anim_parallel(f, g)); 70 | f.seq = ((g) => anim_sequence(f, g)); 71 | return f; 72 | } 73 | 74 | function anim_parallel(anim1, anim2) { 75 | const duration = Math.max(anim1.duration, anim2.duration); 76 | let f = function(t, out, tstart) { 77 | [out, tstart] = assert_precondition(t, out, tstart); 78 | if (t >= tstart) { anim1(t, out, tstart); anim2(t, out, tstart); } 79 | return out; 80 | } 81 | f.duration = duration; 82 | f.par = ((g) => anim_parallel(f, g)); 83 | f.seq = ((g) => anim_sequence(f, g)); 84 | return f; 85 | } 86 | 87 | function anim_parallel_list(xs) { var x = xs[0]; for(var i = 1; i < xs.length; ++i) { x = x.par(xs[i]); } return x; } 88 | function anim_sequence_list(xs) { var x = xs[0]; for(var i = 1; i < xs.length; ++i) { x = x.seq(xs[i]); } return x; } 89 | 90 | function anim_stagger(xs, delta) { 91 | console.assert(typeof(delta) == "number"); 92 | var ys = []; 93 | for(var i = 0; i < xs.length; ++i) { 94 | ys.push(anim_delay(delta*i).seq(xs[i])); 95 | } 96 | var y = ys[0]; 97 | for(var i = 1; i < ys.length; ++i) { 98 | y = y.par(ys[i]); 99 | } 100 | return y; 101 | } 102 | -------------------------------------------------------------------------------- /declarative/ANIMGENERATED.js: -------------------------------------------------------------------------------- 1 | function anim_circle(inp, t01) { 2 | inp.t = t01 * 720.000000; 3 | if (inp.t > 720.000000) { inp.t = 720.000000; } 4 | if (inp.t >= 0.000000 && inp.t <= 720.000000) { // start toplevel 5 | if (inp.t >= 0.000000 && inp.t <= 0.000000) { // start begin_cx 6 | inp.cx = 100.000000; 7 | } else if (inp.t >= 0.000000 && inp.t <= 720.000000) { // elseif begin_cx 8 | inp.cx = 100.000000; 9 | } // end begin_cx 10 | if (inp.t >= 0.000000 && inp.t <= 0.000000) { // start begin_rad 11 | inp.cr = 0.000000; 12 | } else if (inp.t >= 0.000000 && inp.t <= 720.000000) { // elseif begin_rad 13 | inp.cr = 0.000000; 14 | } // end begin_rad 15 | if (inp.t >= 0.000000 && inp.t <= 200.000000) { // start grow 16 | inp.cr = ((0.000000)*((1.000000)-((1.000000)-((((1.000000)-((0.005000)*((inp.t)-(0.000000))))*((1.000000)-((0.005000)*((inp.t)-(0.000000)))))*((1.000000)-((0.005000)*((inp.t)-(0.000000))))))))+((20.000000)*((1.000000)-((((1.000000)-((0.005000)*((inp.t)-(0.000000))))*((1.000000)-((0.005000)*((inp.t)-(0.000000)))))*((1.000000)-((0.005000)*((inp.t)-(0.000000))))))); 17 | } else if (inp.t >= 0.000000 && inp.t <= 720.000000) { // elseif grow 18 | inp.cr = 20.000000; 19 | } // end grow 20 | if (inp.t >= 200.000000 && inp.t <= 400.000000) { // start right_cx 21 | inp.cx = ((100.000000)*((1.000000)-((1.000000)-((((1.000000)-((0.005000)*((inp.t)-(200.000000))))*((1.000000)-((0.005000)*((inp.t)-(200.000000)))))*((1.000000)-((0.005000)*((inp.t)-(200.000000))))))))+((300.000000)*((1.000000)-((((1.000000)-((0.005000)*((inp.t)-(200.000000))))*((1.000000)-((0.005000)*((inp.t)-(200.000000)))))*((1.000000)-((0.005000)*((inp.t)-(200.000000))))))); 22 | } else if (inp.t >= 200.000000 && inp.t <= 720.000000) { // elseif right_cx 23 | inp.cx = 300.000000; 24 | } // end right_cx 25 | if (inp.t >= 400.000000 && inp.t <= 500.000000) { // start wait 26 | } // end wait 27 | if (inp.t >= 500.000000 && inp.t <= 700.000000) { // start left_cx 28 | inp.cx = ((300.000000)*((1.000000)-((1.000000)-((((1.000000)-((0.005000)*((inp.t)-(500.000000))))*((1.000000)-((0.005000)*((inp.t)-(500.000000)))))*((1.000000)-((0.005000)*((inp.t)-(500.000000))))))))+((100.000000)*((1.000000)-((((1.000000)-((0.005000)*((inp.t)-(500.000000))))*((1.000000)-((0.005000)*((inp.t)-(500.000000)))))*((1.000000)-((0.005000)*((inp.t)-(500.000000))))))); 29 | } else if (inp.t >= 500.000000 && inp.t <= 720.000000) { // elseif left_cx 30 | inp.cx = 100.000000; 31 | } // end left_cx 32 | if (inp.t >= 700.000000 && inp.t <= 720.000000) { // start disappear 33 | if (inp.t >= 700.000000 && inp.t <= 720.000000) { // start left_disappear_cx 34 | inp.cx = ((100.000000)*((1.000000)-((1.000000)-((((1.000000)-((0.050000)*((inp.t)-(700.000000))))*((1.000000)-((0.050000)*((inp.t)-(700.000000)))))*((1.000000)-((0.050000)*((inp.t)-(700.000000))))))))+((80.000000)*((1.000000)-((((1.000000)-((0.050000)*((inp.t)-(700.000000))))*((1.000000)-((0.050000)*((inp.t)-(700.000000)))))*((1.000000)-((0.050000)*((inp.t)-(700.000000))))))); 35 | } else if (inp.t >= 700.000000 && inp.t <= 720.000000) { // elseif left_disappear_cx 36 | inp.cx = 80.000000; 37 | } // end left_disappear_cx 38 | if (inp.t >= 700.000000 && inp.t <= 720.000000) { // start left_disappear_cr 39 | inp.cr = ((20.000000)*((1.000000)-((1.000000)-((((1.000000)-((0.050000)*((inp.t)-(700.000000))))*((1.000000)-((0.050000)*((inp.t)-(700.000000)))))*((1.000000)-((0.050000)*((inp.t)-(700.000000))))))))+((0.000000)*((1.000000)-((((1.000000)-((0.050000)*((inp.t)-(700.000000))))*((1.000000)-((0.050000)*((inp.t)-(700.000000)))))*((1.000000)-((0.050000)*((inp.t)-(700.000000))))))); 40 | } else if (inp.t >= 700.000000 && inp.t <= 720.000000) { // elseif left_disappear_cr 41 | inp.cr = 0.000000; 42 | } // end left_disappear_cr 43 | } // end disappear 44 | } // end toplevel 45 | return inp; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mathemagic 5 | 6 | 7 | 19 | 20 | 21 |
22 |

Mathemagic

23 |

A whimsical toybox of mathematical visualization

24 |
25 |

26 | The goal of this side project is to create beautiful rendering of ideas 27 | in differential geometry which enchant me. So I hope to have renderings 28 | of homology, cohomology, exterior calculus, the laplace operator, the heat 29 | equation, the wave equation, curvature, and holonomy. 30 |

31 | 32 | 47 |
48 | 49 | 50 | 175 | 176 | -------------------------------------------------------------------------------- /declarative/anim.cpp: -------------------------------------------------------------------------------- 1 | // Inspired by anime.js 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define TAB " " 8 | 9 | using ll = long long; 10 | 11 | using accessor = const char *; 12 | 13 | enum class valtype { tfloat, tvar, tmul, tadd, tsub, tundefined }; 14 | struct val { 15 | valtype type; 16 | float f_; 17 | const char *var_; 18 | val *inner[2]; 19 | 20 | static val binop(valtype t, val *l, val *r) { 21 | val v; v.type = t; v.inner[0] = l; v.inner[1] = r; return v; 22 | } 23 | 24 | val() : f_(-42), var_("UNDEFINED"), type(valtype::tundefined) { } 25 | 26 | public: 27 | val(const val &other) = default; 28 | val(int i) : f_(i), var_(nullptr), type(valtype::tfloat) {} 29 | val(float f) : f_(f), var_(nullptr), type(valtype::tfloat) {} 30 | val(double d) : f_(d), var_(nullptr), type(valtype::tfloat) {} 31 | val(const char *var) : var_(var), type(valtype::tvar) {} 32 | static val add(val *l, val *r) { return binop(valtype::tadd, l, r); } 33 | static val sub(val *l, val *r) { return binop(valtype::tsub, l, r); } 34 | static val mul(val *l, val *r) { return binop(valtype::tmul, l, r); } 35 | }; 36 | 37 | val operator +(val l, val r) { return val::add(new val(l), new val(r)); } 38 | val operator -(val l, val r) { return val::sub(new val(l), new val(r)); } 39 | val operator *(val l, val r) { return val::mul(new val(l), new val(r)); } 40 | 41 | struct anim { 42 | const char *name; float duration; 43 | anim(const char *name, float duration) : name(name), duration(duration) {} 44 | virtual ~anim() {} 45 | }; 46 | 47 | struct anim_const : public anim { 48 | val v; accessor acc; 49 | anim_const(const char *name, accessor acc, val v): 50 | anim(name, 0), v(v), acc(acc) {} 51 | }; 52 | 53 | struct anim_slowend : public anim { 54 | accessor acc; 55 | val end; 56 | anim_slowend(const char *name, accessor acc, float duration, val end) : 57 | anim(name, duration), acc(acc), end(end) {}; 58 | }; 59 | 60 | struct anim_wait : public anim { 61 | anim_wait(const char *name, float duration) : anim(name, duration) {} 62 | }; 63 | 64 | struct anim_sequence : public anim { 65 | static const int MAX_ANIMS_SEQUENCE = 100; 66 | anim *anims[MAX_ANIMS_SEQUENCE]; 67 | int len; 68 | anim_sequence(const char *name) : anim(name, 0.0), len(0) {} 69 | 70 | void seq(anim *a) { assert(a); anims[len++] = a; duration += a->duration; } 71 | 72 | }; 73 | 74 | struct anim_parallel : public anim { 75 | static const int MAX_ANIMS_PARALLEL = 100; 76 | anim *anims[MAX_ANIMS_PARALLEL]; 77 | int len; 78 | anim_parallel(const char *name) : anim(name, 0), len(0) {} 79 | void par(anim *a) { 80 | assert(a); 81 | anims[len++] = a; 82 | duration = std::max (duration, a->duration); 83 | } 84 | }; 85 | 86 | 87 | int indent(char *s, const int depth) { 88 | int oix = 0; 89 | for(int i = 0; i < depth; ++i) { oix += sprintf(s + oix, "%s", TAB); } 90 | return oix; 91 | } 92 | 93 | int compile_accessor(const accessor acc, char *os) { 94 | return sprintf(os, "%s", acc); 95 | } 96 | 97 | int compile_val(const val v, char *os) { 98 | switch(v.type) { 99 | case valtype::tfloat: return sprintf(os, "%f", v.f_); 100 | case valtype::tvar: return sprintf(os, "inp.%s", v.var_); 101 | case valtype::tmul: 102 | case valtype::tadd: 103 | case valtype::tsub: { 104 | ll oix = 0; 105 | oix += sprintf(os + oix, "("); 106 | oix += compile_val(*v.inner[0], os + oix); 107 | oix += sprintf(os + oix, ")"); 108 | oix += sprintf(os + oix, "%c", 109 | v.type == valtype::tmul ? '*' : 110 | v.type == valtype::tadd ? '+' : 111 | v.type == valtype::tsub ? '-' : '#'); 112 | oix += sprintf(os + oix, "("); 113 | oix += compile_val(*v.inner[1], os + oix); 114 | oix += sprintf(os + oix, ")"); 115 | return oix; 116 | } 117 | case valtype::tundefined: { 118 | assert(false && "uninitialized value!"); 119 | exit(1); 120 | } 121 | 122 | } 123 | } 124 | 125 | 126 | int write_set_accessor_to_val(char *os, const accessor acc, const val v) { 127 | ll oix = 0; 128 | // in. = val;\n 129 | oix += sprintf(os + oix, TAB "inp."); 130 | oix += compile_accessor(acc, os + oix); 131 | oix += sprintf(os + oix, " = "); 132 | oix += compile_val(v, os + oix); 133 | oix += sprintf(os + oix, ";\n"); 134 | return oix; 135 | } 136 | 137 | // unk = unknown 138 | void compile_anim_cases(const float time_start, const float parent_time_end, const anim *aunk, const int depth, char *os, ll &oix, 139 | std::map &finalvals) { 140 | 141 | oix += indent(os + oix, depth); 142 | oix += sprintf(os + oix, "if (inp.t >= %f && inp.t <= %f) { // start %s\n", 143 | time_start, time_start + aunk->duration, aunk->name); 144 | 145 | if (const anim_sequence *aseq = dynamic_cast(aunk)) { 146 | float seq_time_start = time_start; 147 | for(int i = 0; i < aseq->len; ++i) { 148 | const anim *acur = aseq->anims[i]; 149 | compile_anim_cases(seq_time_start, time_start + aseq->duration, acur, depth+1, os, oix, finalvals); 150 | seq_time_start += acur->duration; 151 | } 152 | } else if (const anim_parallel *apar = dynamic_cast(aunk)) { 153 | for(int i = 0; i < apar->len; ++i) { 154 | const anim *acur = apar->anims[i]; 155 | compile_anim_cases(time_start, time_start + apar->duration, acur, depth+1,os, oix, finalvals); 156 | } 157 | } else if (const anim_const *aconst = dynamic_cast(aunk)) { 158 | // in. = val;\n 159 | oix += indent(os + oix, depth); 160 | oix += write_set_accessor_to_val(os + oix, aconst->acc, aconst->v); 161 | finalvals[aconst->acc] = aconst->v; 162 | } else if (const anim_wait *_ = dynamic_cast(aunk)) { 163 | // do nothing 164 | } else if (const anim_slowend *aslowend = dynamic_cast(aunk)) { 165 | // need start value which is implicitly defined. 166 | auto it = finalvals.find(aslowend->acc); 167 | if (it == finalvals.end()) { 168 | char accname[1024]; 169 | (void) compile_accessor(aslowend->acc, accname); 170 | fprintf(stderr, "ERROR: unable to find value |%s| required by animation |%s|\n", 171 | accname, aslowend->name); 172 | exit(1); 173 | } 174 | 175 | const val prev_final = it->second; 176 | const val t = val("t") - val(time_start); 177 | const val t01lin = aslowend->duration == 0 ? 1 : (1.0 / aslowend->duration) * t; 178 | // https://easings.net/ 179 | const val t01 = 1 - (1 - t01lin) * (1 - t01lin) * (1 - t01lin); 180 | const val v = prev_final * (1 - t01) + aslowend->end * t01; 181 | 182 | // in. = val;\n 183 | oix += indent(os + oix, depth); 184 | oix += write_set_accessor_to_val(os + oix, aslowend->acc, v); 185 | // oix += sprintf(os + oix, TAB "inp."); 186 | // oix += compile_accessor(aslowend->acc, os + oix); 187 | // oix += sprintf(os + oix, " = "); 188 | // oix += compile_val(v, os + oix); 189 | // oix += sprintf(os + oix, ";\n"); 190 | 191 | finalvals[aslowend->acc] = aslowend->end; 192 | } else { 193 | assert(false && "unhandled animation."); 194 | } 195 | 196 | // write else part. 197 | if (const anim_slowend *aslowend = dynamic_cast(aunk)) { 198 | oix += indent(os + oix, depth); 199 | oix += sprintf(os + oix, "} else if (inp.t >= %f && inp.t <= %f) { // elseif %s\n", time_start, parent_time_end, aunk->name); 200 | oix += indent(os + oix, depth); 201 | oix += write_set_accessor_to_val(os + oix, aslowend->acc, aslowend->end); 202 | 203 | } else if (const anim_const *aconst = dynamic_cast(aunk)) { 204 | oix += indent(os + oix, depth); 205 | oix += sprintf(os + oix, "} else if (inp.t >= %f && inp.t <= %f) { // elseif %s\n", time_start, parent_time_end, aunk->name); 206 | oix += indent(os + oix, depth); 207 | oix += write_set_accessor_to_val(os + oix, aconst->acc, aconst->v); 208 | } 209 | 210 | oix += indent(os + oix, depth); 211 | oix += sprintf(os + oix, "} // end %s\n", aunk->name); 212 | } 213 | 214 | 215 | void compile_anim(anim *a, const char *fnname, char *os) { 216 | ll oix = 0; 217 | const float totaltime = a->duration; 218 | 219 | oix += sprintf(os + oix, "function %s(inp, t01) {\n", fnname); 220 | // oix += sprintf(os + oix, TAB "let out = {}\n"); 221 | oix += sprintf(os + oix, TAB "inp.t = t01 * %f;\n", a->duration); 222 | oix += sprintf(os + oix, TAB "if (inp.t > %f) { inp.t = %f; }\n", 223 | a->duration, a->duration); 224 | 225 | std::map finalvals; 226 | std::map lasttime; 227 | compile_anim_cases(0, totaltime, a, 1, os, oix, finalvals); 228 | oix += sprintf(os + oix, TAB "return inp;\n"); 229 | oix += sprintf(os + oix, "}\n"); 230 | } 231 | 232 | int main() { 233 | anim *cx_begin = new anim_const("begin_cx", "cx", 100); 234 | anim *rad_begin = new anim_const("begin_rad", "cr", 0); 235 | 236 | anim_sequence *toplevel = new anim_sequence("toplevel"); 237 | toplevel->seq(cx_begin); 238 | toplevel->seq(rad_begin); 239 | toplevel->seq(new anim_slowend("grow", "cr", /*duration=*/200, 20)); 240 | toplevel->seq(new anim_slowend("right_cx", "cx", /*duration=*/200, 300)); 241 | toplevel->seq(new anim_wait("wait", 100)); 242 | toplevel->seq(new anim_slowend("left_cx", "cx", /*duration=*/200, 100)); 243 | 244 | anim_parallel *disappear = new anim_parallel("disappear"); 245 | disappear->par(new anim_slowend("left_disappear_cx", "cx", /*duration=*/ 20, 80)); 246 | disappear->par(new anim_slowend("left_disappear_cr", "cr", /*duration=*/ 20, 0)); 247 | toplevel->seq(disappear); 248 | 249 | char buf[4096]; 250 | compile_anim(toplevel, "anim_circle", buf); 251 | fprintf(stdout, "%s\n", buf); 252 | fflush(stdout); 253 | return 0; 254 | } 255 | -------------------------------------------------------------------------------- /jacobian/tufte.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /* Import ET Book styles 4 | adapted from https://github.com/edwardtufte/et-book/blob/gh-pages/et-book.css */ 5 | 6 | @font-face { 7 | font-family: "et-book"; 8 | src: url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot"); 9 | src: url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.woff") format("woff"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.ttf") format("truetype"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.svg#etbookromanosf") format("svg"); 10 | font-weight: normal; 11 | font-style: normal; 12 | font-display: swap; 13 | } 14 | 15 | @font-face { 16 | font-family: "et-book"; 17 | src: url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot"); 18 | src: url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.woff") format("woff"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.ttf") format("truetype"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.svg#etbookromanosf") format("svg"); 19 | font-weight: normal; 20 | font-style: italic; 21 | font-display: swap; 22 | } 23 | 24 | @font-face { 25 | font-family: "et-book"; 26 | src: url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot"); 27 | src: url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.woff") format("woff"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.ttf") format("truetype"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.svg#etbookromanosf") format("svg"); 28 | font-weight: bold; 29 | font-style: normal; 30 | font-display: swap; 31 | } 32 | 33 | @font-face { 34 | font-family: "et-book-roman-old-style"; 35 | src: url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot"); 36 | src: url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.woff") format("woff"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.ttf") format("truetype"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.svg#etbookromanosf") format("svg"); 37 | font-weight: normal; 38 | font-style: normal; 39 | font-display: swap; 40 | } 41 | 42 | /* Tufte CSS styles */ 43 | html { 44 | font-size: 15px; 45 | } 46 | 47 | body { 48 | width: 87.5%; 49 | margin-left: auto; 50 | margin-right: auto; 51 | padding-left: 12.5%; 52 | font-family: et-book, Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif; 53 | background-color: #fffff8; 54 | color: #111; 55 | max-width: 1400px; 56 | counter-reset: sidenote-counter; 57 | } 58 | 59 | h1 { 60 | font-weight: 400; 61 | margin-top: 4rem; 62 | margin-bottom: 1.5rem; 63 | font-size: 3.2rem; 64 | line-height: 1; 65 | } 66 | 67 | h2 { 68 | font-style: italic; 69 | font-weight: 400; 70 | margin-top: 2.1rem; 71 | margin-bottom: 1.4rem; 72 | font-size: 2.2rem; 73 | line-height: 1; 74 | } 75 | 76 | h3 { 77 | font-style: italic; 78 | font-weight: 400; 79 | font-size: 1.7rem; 80 | margin-top: 2rem; 81 | margin-bottom: 1.4rem; 82 | line-height: 1; 83 | } 84 | 85 | hr { 86 | display: block; 87 | height: 1px; 88 | width: 55%; 89 | border: 0; 90 | border-top: 1px solid #ccc; 91 | margin: 1em 0; 92 | padding: 0; 93 | } 94 | 95 | p.subtitle { 96 | font-style: italic; 97 | margin-top: 1rem; 98 | margin-bottom: 1rem; 99 | font-size: 1.8rem; 100 | display: block; 101 | line-height: 1; 102 | } 103 | 104 | .numeral { 105 | font-family: et-book-roman-old-style; 106 | } 107 | 108 | .danger { 109 | color: red; 110 | } 111 | 112 | article { 113 | padding: 5rem 0rem; 114 | } 115 | 116 | section { 117 | padding-top: 1rem; 118 | padding-bottom: 1rem; 119 | } 120 | 121 | p, 122 | dl, 123 | ol, 124 | ul { 125 | font-size: 1.4rem; 126 | line-height: 2rem; 127 | } 128 | 129 | p { 130 | margin-top: 1.4rem; 131 | margin-bottom: 1.4rem; 132 | padding-right: 0; 133 | vertical-align: baseline; 134 | } 135 | 136 | /* Chapter Epigraphs */ 137 | div.epigraph { 138 | margin: 5em 0; 139 | } 140 | 141 | div.epigraph > blockquote { 142 | margin-top: 3em; 143 | margin-bottom: 3em; 144 | } 145 | 146 | div.epigraph > blockquote, 147 | div.epigraph > blockquote > p { 148 | font-style: italic; 149 | } 150 | 151 | div.epigraph > blockquote > footer { 152 | font-style: normal; 153 | } 154 | 155 | div.epigraph > blockquote > footer > cite { 156 | font-style: italic; 157 | } 158 | /* end chapter epigraphs styles */ 159 | 160 | blockquote { 161 | font-size: 1.4rem; 162 | } 163 | 164 | blockquote p { 165 | width: 55%; 166 | margin-right: 40px; 167 | } 168 | 169 | blockquote footer { 170 | width: 55%; 171 | font-size: 1.1rem; 172 | text-align: right; 173 | } 174 | 175 | section > p, 176 | section > footer, 177 | section > table { 178 | width: 55%; 179 | } 180 | 181 | /* 50 + 5 == 55, to be the same width as paragraph */ 182 | section > dl, 183 | section > ol, 184 | section > ul { 185 | width: 50%; 186 | -webkit-padding-start: 5%; 187 | } 188 | 189 | dt:not(:first-child), 190 | li:not(:first-child) { 191 | margin-top: 0.25rem; 192 | } 193 | 194 | figure { 195 | padding: 0; 196 | border: 0; 197 | font-size: 100%; 198 | font: inherit; 199 | vertical-align: baseline; 200 | max-width: 55%; 201 | -webkit-margin-start: 0; 202 | -webkit-margin-end: 0; 203 | margin: 0 0 3em 0; 204 | } 205 | 206 | figcaption { 207 | float: right; 208 | clear: right; 209 | margin-top: 0; 210 | margin-bottom: 0; 211 | font-size: 1.1rem; 212 | line-height: 1.6; 213 | vertical-align: baseline; 214 | position: relative; 215 | max-width: 40%; 216 | } 217 | 218 | figure.fullwidth figcaption { 219 | margin-right: 24%; 220 | } 221 | 222 | /* Links: replicate underline that clears descenders */ 223 | a:link, 224 | a:visited { 225 | color: inherit; 226 | } 227 | 228 | .no-tufte-underline:link { 229 | background: unset; 230 | text-shadow: unset; 231 | } 232 | 233 | a:link, .tufte-underline, .hover-tufte-underline:hover { 234 | text-decoration: none; 235 | background: -webkit-linear-gradient(#fffff8, #fffff8), -webkit-linear-gradient(#fffff8, #fffff8), -webkit-linear-gradient(currentColor, currentColor); 236 | background: linear-gradient(#fffff8, #fffff8), linear-gradient(#fffff8, #fffff8), linear-gradient(currentColor, currentColor); 237 | -webkit-background-size: 0.05em 1px, 0.05em 1px, 1px 1px; 238 | -moz-background-size: 0.05em 1px, 0.05em 1px, 1px 1px; 239 | background-size: 0.05em 1px, 0.05em 1px, 1px 1px; 240 | background-repeat: no-repeat, no-repeat, repeat-x; 241 | text-shadow: 0.03em 0 #fffff8, -0.03em 0 #fffff8, 0 0.03em #fffff8, 0 -0.03em #fffff8, 0.06em 0 #fffff8, -0.06em 0 #fffff8, 0.09em 0 #fffff8, -0.09em 0 #fffff8, 0.12em 0 #fffff8, -0.12em 0 #fffff8, 0.15em 0 #fffff8, -0.15em 0 #fffff8; 242 | background-position: 0% 93%, 100% 93%, 0% 93%; 243 | } 244 | 245 | @media screen and (-webkit-min-device-pixel-ratio: 0) { 246 | a:link, .tufte-underline, .hover-tufte-underline:hover { 247 | background-position-y: 87%, 87%, 87%; 248 | } 249 | } 250 | 251 | a:link::selection, 252 | a:link::-moz-selection { 253 | text-shadow: 0.03em 0 #b4d5fe, -0.03em 0 #b4d5fe, 0 0.03em #b4d5fe, 0 -0.03em #b4d5fe, 0.06em 0 #b4d5fe, -0.06em 0 #b4d5fe, 0.09em 0 #b4d5fe, -0.09em 0 #b4d5fe, 0.12em 0 #b4d5fe, -0.12em 0 #b4d5fe, 0.15em 0 #b4d5fe, -0.15em 0 #b4d5fe; 254 | background: #b4d5fe; 255 | } 256 | 257 | /* Sidenotes, margin notes, figures, captions */ 258 | img { 259 | max-width: 100%; 260 | } 261 | 262 | .sidenote, 263 | .marginnote { 264 | float: right; 265 | clear: right; 266 | margin-right: -60%; 267 | width: 50%; 268 | margin-top: 0.3rem; 269 | margin-bottom: 0; 270 | font-size: 1.1rem; 271 | line-height: 1.3; 272 | vertical-align: baseline; 273 | position: relative; 274 | } 275 | 276 | .sidenote-number { 277 | counter-increment: sidenote-counter; 278 | } 279 | 280 | .sidenote-number:after, 281 | .sidenote:before { 282 | font-family: et-book-roman-old-style; 283 | position: relative; 284 | vertical-align: baseline; 285 | } 286 | 287 | .sidenote-number:after { 288 | content: counter(sidenote-counter); 289 | font-size: 1rem; 290 | top: -0.5rem; 291 | left: 0.1rem; 292 | } 293 | 294 | .sidenote:before { 295 | content: counter(sidenote-counter) " "; 296 | font-size: 1rem; 297 | top: -0.5rem; 298 | } 299 | 300 | blockquote .sidenote, 301 | blockquote .marginnote { 302 | margin-right: -82%; 303 | min-width: 59%; 304 | text-align: left; 305 | } 306 | 307 | div.fullwidth, 308 | table.fullwidth { 309 | width: 100%; 310 | } 311 | 312 | div.table-wrapper { 313 | overflow-x: auto; 314 | font-family: "Trebuchet MS", "Gill Sans", "Gill Sans MT", sans-serif; 315 | } 316 | 317 | .sans { 318 | font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif; 319 | letter-spacing: .03em; 320 | } 321 | 322 | code, pre > code { 323 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; 324 | font-size: 1.0rem; 325 | line-height: 1.42; 326 | -webkit-text-size-adjust: 100%; /* Prevent adjustments of font size after orientation changes in iOS. See https://github.com/edwardtufte/tufte-css/issues/81#issuecomment-261953409 */ 327 | } 328 | 329 | .sans > code { 330 | font-size: 1.2rem; 331 | } 332 | 333 | h1 > code, 334 | h2 > code, 335 | h3 > code { 336 | font-size: 0.80em; 337 | } 338 | 339 | .marginnote > code, 340 | .sidenote > code { 341 | font-size: 1rem; 342 | } 343 | 344 | pre > code { 345 | font-size: 0.9rem; 346 | width: 52.5%; 347 | margin-left: 2.5%; 348 | overflow-x: auto; 349 | display: block; 350 | } 351 | 352 | pre.fullwidth > code { 353 | width: 90%; 354 | } 355 | 356 | .fullwidth { 357 | max-width: 90%; 358 | clear:both; 359 | } 360 | 361 | span.newthought { 362 | font-variant: small-caps; 363 | font-size: 1.2em; 364 | } 365 | 366 | input.margin-toggle { 367 | display: none; 368 | } 369 | 370 | label.sidenote-number { 371 | display: inline; 372 | } 373 | 374 | label.margin-toggle:not(.sidenote-number) { 375 | display: none; 376 | } 377 | 378 | .iframe-wrapper { 379 | position: relative; 380 | padding-bottom: 56.25%; /* 16:9 */ 381 | padding-top: 25px; 382 | height: 0; 383 | } 384 | 385 | .iframe-wrapper iframe { 386 | position: absolute; 387 | top: 0; 388 | left: 0; 389 | width: 100%; 390 | height: 100%; 391 | } 392 | 393 | @media (max-width: 760px) { 394 | body { 395 | width: 84%; 396 | padding-left: 8%; 397 | padding-right: 8%; 398 | } 399 | 400 | hr, 401 | section > p, 402 | section > footer, 403 | section > table { 404 | width: 100%; 405 | } 406 | 407 | pre > code { 408 | width: 97%; 409 | } 410 | 411 | section > dl, 412 | section > ol, 413 | section > ul { 414 | width: 90%; 415 | } 416 | 417 | figure { 418 | max-width: 90%; 419 | } 420 | 421 | figcaption, 422 | figure.fullwidth figcaption { 423 | margin-right: 0%; 424 | max-width: none; 425 | } 426 | 427 | blockquote { 428 | margin-left: 1.5em; 429 | margin-right: 0em; 430 | } 431 | 432 | blockquote p, 433 | blockquote footer { 434 | width: 100%; 435 | } 436 | 437 | label.margin-toggle:not(.sidenote-number) { 438 | display: inline; 439 | } 440 | 441 | .sidenote, 442 | .marginnote { 443 | display: none; 444 | } 445 | 446 | .margin-toggle:checked + .sidenote, 447 | .margin-toggle:checked + .marginnote { 448 | display: block; 449 | float: left; 450 | left: 1rem; 451 | clear: both; 452 | width: 95%; 453 | margin: 1rem 2.5%; 454 | vertical-align: baseline; 455 | position: relative; 456 | } 457 | 458 | label { 459 | cursor: pointer; 460 | } 461 | 462 | div.table-wrapper, 463 | table { 464 | width: 85%; 465 | } 466 | 467 | img { 468 | width: 100%; 469 | } 470 | } 471 | -------------------------------------------------------------------------------- /whalesong/index.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | # Whalesong 8 | 9 | 10 | 11 | I first heard that whales experience non-euclidian geometry at the splendid 12 | ['The non-Euclidian geometry of whales and ants'](https://static01.nyt.com/images/blogs/wordplay/Universe_in_Zero_Words_Copyright.pdf). 13 | It set of a cascade of thoughts, along the lines of ['what is it like to be a bat'](https://warwick.ac.uk/fac/cross_fac/iatl/study/ugmodules/humananimalstudies/lectures/32/nagel_bat.pdf). 14 | I find it pleasurable to attempt to perceive the world as these beings might, 15 | whose perception of the world is so non-Euclidian. So I set off to learn 16 | more, and hopefully try and simulate this phenomena to get a better 17 | intuition for it. 18 | 19 | It's djikstras on a graph, where the edge lengths are obtained by discretizing 20 | hyperbolic space so the single-source shortest paths discovered by djikstras is 21 | a reasonable approximation of the real shortest paths in hyperbolic space Ah, 22 | so the physics is that due to (i) snells law, (ii) changing refractive index 23 | due to depth, sound "bends" inside water, leading to the shortest paths of 24 | sound inside water to be those circular arcs plotted above. So you can consider 25 | the paths that sound travels in space as hyperbolic space. If this is the only 26 | sense organ whales have, then whales perceive the world as hyperbolic space. 27 | 28 | 29 | 30 | 31 |
32 | 33 | 34 | 303 | 304 | -------------------------------------------------------------------------------- /jacobian/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | The Jacobian, geometrically 8 | 14 | 15 | 16 | 17 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
34 |

The Jacobian

35 | 36 |
37 |

38 | In this article, I'm going to motivate a geometric quantity known as the 39 | Jacobian you may have seen in multivariable calculus. It shows up without 40 | explanation when one solves multiple integrals; little explanation is given 41 | to what it means . At the end of reading this, if you knew what 42 | a Jacobian is, you'll have a sense of what it really means. If you didn't, 43 | even better --- you'll learn what the Jacobian is! 44 |

45 |

46 | Let's dive in. To discuss the Jacobian, we first need a transformation. A prototypical 47 | example the transformation that squeezes the entire plane into the unit circle. This is given by 48 | \( f(v) \equiv v/|v| \) where \( v \) is a 2D vector, or a point on a plane. Written 49 | in terms of coordinates, we make the substitution \( v \mapsto (x, y) \), and the length 50 | of the vector \( |v| \mapsto \sqrt{x^2 + y^2} \). This yields the expression 51 | \( f(x, y) \equiv (x/\sqrt{x^2 + y^2}, y/\sqrt{x^2 + y^2}) \). To get a very visceral sense 52 | of what this function does, let's think about it this way: distribute pink-colored points randomly, and then 53 | transform using \( f\). This gives a sense of how \( f \) crumples the unit plane 54 | onto the unit circle. 55 |

56 |
57 |

58 | However, there's another way to view this transform, which will be slightly more fruitful for us in the future; We're going 59 | to look at how this function $f$ transforms curves, because a curve is the most primitive object 60 | that has notions of continuity, smoothness, and all other nice geometic properties we know and love from 61 | calculus. We have a pink curve that moves around. This curve is mapped by \( f \) 62 | to the blue curve that lies entirely on the unit circle. Watching this 63 | transformation gives us a sense of what geometry the mapping \( f \) preserves and destroys 64 |

65 |
66 | 67 |

68 | To watch more closely, let's consider two extreme cases. First, where the pink 69 | curve is perpendicular to the circle. Here, we see below that that the projection in blue 70 | vanishes. Regardless of however long our pink curve is, the projection is always just a single 71 | point. A curve that is perpendicular to the circle will have zero projection. 72 | 73 |

74 |

75 | 76 | 77 |

78 | The other case we consider is where the curve is tangent or parallel to the circle. Here, 79 | we find the projection of the pink curve to be very long, as the pink curve is able to cast 80 | a long shadow onto the circle. 81 |

82 | 83 |
84 |

85 | 86 | 87 |

88 | Finally, if you wish to play with the transform, I've left 89 | 90 | 91 | Best viewed on the desktop 92 | where you can draw a curve with your mouse. The curve after $f$ is applied, 93 | is displayed in blue. 94 |

95 |
96 |
97 | 98 | 99 | 100 |
101 |

Transformation of derivatives along a curve

102 | 103 |

104 | We now have a handle on how continuity is transformed. Let's now try to understand 105 | how tangents or derivatives are transformed, since differentiability comes right after 106 | continuity in Differential calculus. To explore this, let's draw the simplest curve possible: a straight line. 107 | Let's see where this curve is mapped to by \( f \), and then draw the mapped curve's tangents. 108 | 109 | 110 |

111 | But, what even is 112 | a tangent? Calculus tells us that it's a straight line that just touches our curve. So we'll draw 113 | the tangent as a straight line to our curve, then push the tangent onto the circle using \( f \) 114 | to see what it looks like after the transformation. 115 |

116 | 117 |

118 | We represent the straight line as function $c: [0, 1] \rightarrow \mathbb 119 | R^2$; $c(t) \equiv (t, 0)$. That is, it's a curve with a point that moves 120 | along the $x$ axis as $t$ goes from $0$ to $1$. Let's plot the point that 121 | moves, along with a straight line at that point, and see how this gets 122 | mapped: 123 |

124 | 125 |
126 | 127 |

128 | We see that the length of the orange tangent on the circle is not constant, 129 | even though the length of the purple tangent is constant! As the blue point 130 | comes closer to the circle, the orange tangent attached to the pink point is 131 | longer, since the pink point moves faster on the circle. As the blue point 132 | goes farther away from the circle, the length of the orange tangent grows 133 | ever shorter, while the speed of the pink point on the circle crawls to a 134 | halt. Can we calculate this somehow? 135 |

136 |
137 | 138 |
139 |

Calculating the tangent on the circle

140 | 141 |

142 | We started with the blue point on the curve curve $c(t) \equiv (t, 0)$. 143 | We then drew a blue tangent, $c'(t) = (1, 0)$. This was the blue line of constant length. 144 | Next, we drew the analogous pink point on the curve. This was computed as $d(t) \equiv f(c(t))$, 145 | since we took a point on the curve $c$ and saw where it lands due to $f$'s action. Next, we differentiated 146 | this curve $d(t)$ to get the pink line $d'(t)$. We wish to relate $c'(t)$ and $d'(t)$. 147 |

148 | 149 | 150 |

151 | 152 | In the concrete case, we find: 153 | 154 | $$ 155 | \begin{align*} 156 | & d'(t) = \\ 157 | & \text{(defn of $d$)}\\ 158 | & = (f(c(t))' \\ 159 | &= \frac{d f(c(t))}{dt} \\ 160 | & \text{(substitute $c(t) = (t, 0)$)}\\ 161 | &= \frac{d f(t, 0)}{dt} \\ 162 | & \text{(substitute $f$)} \\ 163 | &= \frac{d ((t/\sqrt{t^2 + 0^2}, 0/\sqrt{t^2 + 0^2}))}{dt} \\ 164 | & \text{(simplify)} \\ 165 | &= \frac{d ((\sqrt{t}, 0))}{dt} \\ 166 | & \text{(push derivative inside)}\\ 167 | &= \bigg( \frac{d\sqrt{t}}{dt}, \frac{d0}{dt} \bigg) \\ 168 | &d'(t) = \bigg (\frac{1}{2\sqrt{t}}, 0 \bigg) \quad 169 | \end{align*} 170 | $$ 171 | 172 | Thus, we find that the derivative of the curve $d(t)$ is $d'(t) = (1/2\sqrt{t}, 0)$. This grows smaller 173 | as $t$ grows larger in size, mimicking what we saw. As we grow farther away from the center, the pink line 174 | on the circle grew smaller and smaller. 175 |

176 |
177 | 178 |
179 |

Transformation of derivative with fixed basepoint

180 |

181 | The math tells us that at each point, the derivative is $d'(t) = (1/2\sqrt{t}, 0)$. 182 | This means that for a chosen point , say $t = 1$, the derivative is going to be 183 | 184 | $$d'(t=1) = (1/2\sqrt 1, 0) = (1/2, 0).$$ 185 | 186 | The derivative of the original curve at the same point is $c'(1) = d/dt(t, 0)|_{t=1} = (1, 0)|_{t=1} = (1, 0)$. 187 | That's curious, the new derivative $d'(t)$ seems to be a scaled proportionally 188 | from the old derivative: 189 | 190 | $$ 191 | d'(t) = (1/2, 0) = 1/2(1, 0) = 1/2 c'(t). 192 | $$ 193 | 194 | This means that the tangents on the straight line are 195 | proportionally related to tangents on the circle. Is this 196 | true? Let's watch. 197 |

198 | 199 | 200 |
201 | 202 |

203 | It does seem to be true; as we vary the length of the purple tangent line on the line segment, 204 | the length of the orange tangent line on the circle grows proportionally! Is there something special 205 | about the straight line? Let's try to see what happens in general. 206 |

207 |
208 | 209 |
210 |

Generalizing our computation

211 | 212 |

213 | Previously, we used the concrete definition of $f(x, y)$ and $c(t)$ that we knew to compute the derivative 214 | $d'(t)$. What happens if we perform the same derivation in the abstract? This should tell us how to compute $d'(t)$ 215 | in terms of $f(x, y)$ and $c(t)$. We begin by thinking about 216 | $c(t) : [0, 1] \rightarrow \mathbb R^2$. It's a little awkward to deal with, because it produces two outputs . 217 | Let's break $c(t)$ into two functions, $c_x(t)$ and $c_y(t)$, so that $c(t) = (c_x(t), c_y(t))$. 218 |

219 | 220 |

221 | Similarly, we had 222 | $f: \mathbb R^2 \rightarrow \mathbb R^2$. Let's break this into $f_x(x, y): \mathbb R^2 \rightarrow \mathbb R$ 223 | and $f_y(x, y): \mathbb R^2 \rightarrow \mathbb R$ such that $f(x, y) = (f_x(x, y), f_y(x, y))$. This gives us two 224 | functions $f_x, f_y: \mathbb R^2 \rightarrow \mathbb R$ which takes two inputs and produces a single output. 225 |

226 | 227 |

228 | We now have the simplifications we need to carry out our "concrete proof", completely abstractly. Instead of substituting 229 | $c(t) = (t, 0)$, we will substitute $c(t) = (c_x(t), c_y(t))$. Similarly, instead of substituting 230 | $f(x, y) = (x/\sqrt{x^2 + y^2}, y/\sqrt{x^2 + y^2})$, we will substitute $f(x, y) = (f_x(x, y), f_y(x, y))$ and carry out the proof. 231 | This yields: 232 | 233 | $$ 234 | \begin{align*} 235 | & d'(t) = \\ 236 | & \text{(defn of $d$)}\\ 237 | & = (f(c(t))' = \frac{d f(c(t))}{dt} \\ 238 | & \text{(substitute $c(t) = (c_x(t), c_y(t))$)}\\ 239 | &= \frac{d f(c_x(t), c_y(t))}{dt} \\ 240 | & \text{(substitute $f(x, y) = (f_x(x, y), f_y(x, y)))$} \\ 241 | &= \frac{d((f_x(c_x(t), c_y(t)), f_y(c_x(t), c_y(t))))}{dt} \\ 242 | & \text{(push derivative inside)}\\ 243 | &= \bigg(\frac{df_x(c_x(t), c_y(t))}{dt}, \frac{df_y(c_x(t), c_y(t))}{dt} \bigg) \\ 244 | \end{align*} 245 | $$ 246 |

247 | 248 |

249 | At this stage, we're going to whack the expression with the only hammer we have in calculus: the chain rule! 250 | This gives us: 251 | 252 | $$ 253 | \begin{align*} 254 | &= \bigg(\frac{df_x(c_x(t), c_y(t))}{dt}, \frac{df_y(c_x(t), c_y(t))}{dt} \bigg) \\ 255 | &d'(t) = \bigg (\frac{df_x}{dx}\frac{dc_x(t)}{dt} + \frac{df_x}{dy} \frac{dc_y(t)}{dt}, \frac{df_y}{dx} \frac{dc_x(t)}{dt} + \frac{df_y}{dy}\frac{dc_y(t)}{dt} \bigg) \\ 256 | \end{align*} 257 | $$ 258 | 259 | We see that this splits into two "kinds" of derivatives: terms of the form $(dc_x/dt, dc_y/dt)$, and 260 | of the form $\{ df_{x, y}/d_{x, y} \}$. 261 | We can write the above as: 262 | 263 | $$ 264 | \begin{align*} 265 | &d'(t) = \bigg (\frac{df_x}{dx}\frac{dc_x(t)}{dt} + \frac{df_x}{dy} \frac{dc_y(t)}{dt}, \frac{df_y}{dx} \frac{dc_x(t)}{dt} + \frac{df_y}{dy}\frac{dc_y(t)}{dt} \bigg) \\ 266 | &d'(t) = 267 | \begin{bmatrix} 268 | df_x/dx & df_x/dy \\ 269 | dg_x/dx & dg_x/dy \\ 270 | \end{bmatrix} 271 | \begin{bmatrix} 272 | dc_x/dt \\ dc_y/dt 273 | \end{bmatrix} 274 | \end{align*} 275 | $$ 276 | 277 | So we see that we can write $d'(t)$ as a matrix multiplication (linear transformation) of $(dc_x/dt, dc_y/dt)$ 278 | with the Jacobian of $f$, $J \equiv \begin{bmatrix} df_x/dx & df_x/dy \\ dg_x/dx & dg_x/dy \\ \end{bmatrix}$. 279 | This philosophically means that the new tangent is a linear transform of the old tangent. 280 |

281 | 282 |
283 | 284 |
285 |

Wrapping Up

286 | 287 |

288 | We began exploring what it means to have a complicated transformation and how to visualize it. 289 | We then thought about curves, and how curves are transformed under this relationship. This naturally 290 | got us thinking about derivatives, where we noticed that the relationship between the derivatives 291 | of the original curve and the transformed curve appear to be linear. This culminated in us computing 292 | the Jacobian, which precisely quantified the linear relationship in the tangents to the curve. 293 | 294 |

301 | 302 |

303 | 304 |

305 | Finally, I end with an interactive toy; Click to select a base point. Move the cursor 306 | to draw blue line segments. See the prediction by the Jacobian (in purple) and the real 307 | projection (in orange), and revel in the fact that the pink Jacobian prediction 308 | and the real orange projection do indeed overlap for small approximations! 309 |

310 |

311 |
312 |
313 | 314 | 315 | -------------------------------------------------------------------------------- /whalesong/index.html: -------------------------------------------------------------------------------- 1 | A Universe of Sorts
11 | 12 | 13 | 14 | 15 | 16 |

§ Whalesong

17 | 18 | I first heard that whales experience non-euclidian geometry at the splendid 19 | 'The non-Euclidian geometry of whales and ants'. 20 | It set of a cascade of thoughts, along the lines of 'what is it like to be a bat'. 21 | I find it pleasurable to attempt to perceive the world as these beings might, 22 | whose perception of the world is so non-Euclidian. So I set off to learn 23 | more, and hopefully try and simulate this phenomena to get a better 24 | intuition for it. 25 | It's djikstras on a graph, where the edge lengths are obtained by discretizing 26 | hyperbolic space so the single-source shortest paths discovered by djikstras is 27 | a reasonable approximation of the real shortest paths in hyperbolic space Ah, 28 | so the physics is that due to (i) snells law, (ii) changing refractive index 29 | due to depth, sound "bends" inside water, leading to the shortest paths of 30 | sound inside water to be those circular arcs plotted above. So you can consider 31 | the paths that sound travels in space as hyperbolic space. If this is the only 32 | sense organ whales have, then whales perceive the world as hyperbolic space. 33 |
34 | 303 | 304 | -------------------------------------------------------------------------------- /jacobian/sketch.js: -------------------------------------------------------------------------------- 1 | W = 300; 2 | H = 150; 3 | R = 20; 4 | 5 | function easeInOutQuad(x) { 6 | return x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2; 7 | } 8 | 9 | 10 | function easeOutQuart(x) { 11 | return 1 - Math.pow(1 - x, 4); 12 | } 13 | 14 | function easeInQuart(x) { 15 | return x * x * x * x; 16 | } 17 | 18 | function halton (index, base) { 19 | let fraction = 1; 20 | let result = 0; 21 | while (index > 0) { 22 | fraction /= base; 23 | result += fraction * (index % base); 24 | index = Math.floor(index / base); // floor division 25 | } 26 | return result; 27 | } 28 | 29 | 30 | // f(x, y) = (u: x (x^2+y^2)^{-1/2}, v: y(x^2 + y^2)^{-1/2}) 31 | // du/dx = 1. (x^2+y^2)^{-1/2} + x(-1/2)(x^2+y^2){-3/2}(2x) = (x^2 + y^2)^{-1/2} - x^2(x^2 + y^2)^{-3/2} 32 | // du/dy = 1. x(-1/2)(x^2+y^2){-3/2}(2y) = - xy(x^2 + y^2)^{-3/2} 33 | function jac(x, y, tx, ty) { 34 | let xsqysq = x*x+y*y; 35 | let dudx = Math.pow(xsqysq, -1/2) - x*x*Math.pow(xsqysq, -3/2); 36 | let dudy = -x*y*Math.pow(xsqysq, -3/2); 37 | let dvdx = dudy; 38 | let dvdy = Math.pow(xsqysq, -1/2) - y*y*Math.pow(xsqysq, -3/2); 39 | 40 | 41 | let ox = tx*dudx + ty*dudy; 42 | let oy = tx*dvdx + ty*dvdy; 43 | // console.log("dudx: ", dudx, "dudy: ", dudy, "dvdx: ", dvdx, "dvdy: ", dvdy, "ox: ", ox, "oy: ", oy); 44 | return [ox, oy]; 45 | } 46 | 47 | 48 | const interactive_derivative = ( s ) => { 49 | let pX = R*3; 50 | let pY = 0; 51 | 52 | s.setup = () => { 53 | let myCanvas = s.createCanvas(W, H); 54 | // myCanvas.parent(document.getElementById('myContainer')); 55 | myCanvas.parent('interactive-derivative'); 56 | }; 57 | 58 | s.draw = () => { 59 | s.background(255,253,231); 60 | 61 | if (s.mouseIsPressed) { 62 | pX = s.mouseX - W/2; 63 | pY = s.mouseY - H/2; 64 | } 65 | 66 | let vecX = (s.mouseX -W/2) - pX; 67 | let vecY = (s.mouseY - H/2) - pY; 68 | 69 | 70 | 71 | s.stroke(30,136,229); 72 | s.strokeWeight(6); 73 | s.strokeCap(s.SQUARE); 74 | s.line(pX+W/2, pY+H/2, s.mouseX, s.mouseY); 75 | 76 | 77 | const TGTWT = 6; 78 | const len = Math.sqrt(pX*pX + pY*pY); 79 | let sX = (TGTWT+R)*pX/len; 80 | let sY = (TGTWT+R)*pY/len; 81 | 82 | let stv = jac(pX, pY, vecX, vecY); 83 | s.strokeWeight(0); 84 | s.fill(69,90,100); 85 | s.ellipse(W/2, H/2, 2*R, 2*R); 86 | 87 | 88 | s.stroke(255,111,0) 89 | s.strokeWeight(6); 90 | s.strokeCap(s.SQUARE); 91 | s.noFill(); 92 | s.beginShape(); 93 | for(let i = 0; i <= len; ++i) { 94 | let t = i / len; 95 | const x0 = pX; const y0 = pY; 96 | const x1 = s.mouseX - W/2; const y1 = s.mouseY - H/2; 97 | 98 | const xt = (1 - t)*x0 + t*x1; 99 | const yt = (1 - t)*y0 + t*y1; 100 | const tlen = Math.sqrt(xt*xt + yt*yt); 101 | 102 | s.curveVertex(W/2 + R*xt/tlen, H/2 + R*yt/tlen); 103 | } 104 | s.endShape(); 105 | 106 | 107 | s.strokeWeight(6); 108 | s.strokeCap(s.SQUARE); 109 | s.stroke(216,27,96);; 110 | s.line(W/2 + sX, 111 | H/2 + sY, 112 | W/2 + sX+ 10*stv[0], 113 | H/2 + sY+ 10*stv[1]); 114 | 115 | s.strokeWeight(0);; 116 | 117 | }; 118 | }; 119 | 120 | 121 | 122 | const transform_anim_normal = ( s ) => { 123 | let pts = []; 124 | s.setup = () => { 125 | let myCanvas = s.createCanvas(W, H); 126 | myCanvas.parent('transform-anim-normal'); 127 | }; 128 | 129 | let t = 0; 130 | 131 | s.draw = () => { 132 | 133 | 134 | const V = 0.02; 135 | t = (t + V) % (4); 136 | const NUM_POINTS = 40; 137 | if (pts.length > NUM_POINTS) { 138 | pts.shift(); 139 | } 140 | 141 | const RMOVE = R*3; 142 | if (t <= 1) { // 0-1 143 | pts.push([R*2 + RMOVE * easeInOutQuad(t), 0]); 144 | } else if (t <= 2) { // 1-2 145 | pts.push([R*2 + RMOVE * easeInOutQuad(1), 0]); 146 | } else if (t <= 3) { 147 | let tcur = t - 2; 148 | let trev = 1 - tcur; // 1 - (t - 1) = 1 - t + 1 = 2 - t 149 | pts.push([R*2 + RMOVE * easeInOutQuad(trev), 0]); 150 | } else if (t <= 4) { 151 | pts.push([R*2 + RMOVE * easeInOutQuad(0), 0]); 152 | } 153 | 154 | 155 | s.background(238,238,238); 156 | s.background(255,253,231); 157 | s.noFill(); 158 | s.stroke(216,27,96); 159 | s.strokeWeight(6); 160 | s.beginShape(); 161 | for (let i = 0; i < pts.length; ++i) { 162 | s.stroke(216,27,96); 163 | s.curveVertex(pts[i][0] + W/2, pts[i][1] +H/2); 164 | } 165 | s.endShape(); 166 | 167 | s.strokeWeight(0); 168 | s.fill(69,90,100); 169 | s.ellipse(W/2, H/2, 2*R, 2*R); 170 | 171 | 172 | s.stroke(33,150,243); 173 | s.strokeWeight(6); 174 | s.beginShape(); 175 | for (let i = 0; i < pts.length; ++i) { 176 | const len = Math.sqrt(pts[i][0] * pts[i][0] + pts[i][1] * pts[i][1]); 177 | s.curveVertex(W/2 + R*pts[i][0]/len, H/2 + R*pts[i][1]/len); 178 | } 179 | s.endShape(); 180 | 181 | 182 | }; 183 | }; 184 | 185 | const transform_anim_tangential = ( s ) => { 186 | let pts = []; 187 | s.setup = () => { 188 | let myCanvas = s.createCanvas(W, H); 189 | myCanvas.parent('transform-anim-tangential'); 190 | }; 191 | 192 | let t = 0; 193 | 194 | s.draw = () => { 195 | 196 | 197 | const V = 0.02; 198 | t = (t + V) % (4); 199 | const NUM_POINTS = 40; 200 | if (pts.length > NUM_POINTS) { 201 | pts.shift(); 202 | } 203 | 204 | const RMOVE = R*4; 205 | if (t <= 1) { // 0-1 206 | pts.push([R*2, -R*2 + RMOVE * easeInOutQuad(t)]); 207 | } else if (t <= 2) { // 1-2 208 | pts.push([R*2, -R*2 + RMOVE * easeInOutQuad(1)]); 209 | } else if (t <= 3) { 210 | let tcur = t - 2; 211 | let trev = 1 - tcur; // 1 - (t - 1) = 1 - t + 1 = 2 - t 212 | pts.push([R*2, -R*2 + RMOVE * easeInOutQuad(trev)]); 213 | } else if (t <= 4) { 214 | pts.push([R*2, -R*2 + RMOVE * easeInOutQuad(0)]); 215 | } 216 | 217 | 218 | s.background(238,238,238); 219 | s.background(255,253,231); 220 | s.noFill(); 221 | s.stroke(216,27,96); 222 | s.strokeWeight(6); 223 | s.beginShape(); 224 | for (let i = 0; i < pts.length; ++i) { 225 | s.stroke(216,27,96); 226 | s.curveVertex(pts[i][0] + W/2, pts[i][1] +H/2); 227 | } 228 | s.endShape(); 229 | 230 | s.strokeWeight(0); 231 | s.fill(69,90,100); 232 | s.ellipse(W/2, H/2, 2*R, 2*R); 233 | 234 | 235 | s.stroke(33,150,243); 236 | s.strokeWeight(6); 237 | s.beginShape(); 238 | for (let i = 0; i < pts.length; ++i) { 239 | const len = Math.sqrt(pts[i][0] * pts[i][0] + pts[i][1] * pts[i][1]); 240 | s.curveVertex(W/2 + R*pts[i][0]/len, H/2 + R*pts[i][1]/len); 241 | } 242 | s.endShape(); 243 | 244 | 245 | }; 246 | }; 247 | 248 | 249 | 250 | const transform_anim = ( s ) => { 251 | let pts = []; 252 | s.setup = () => { 253 | let myCanvas = s.createCanvas(W, H); 254 | myCanvas.parent('transform-anim'); 255 | }; 256 | 257 | let t1 = 0; let t2 = 0; 258 | 259 | s.draw = () => { 260 | 261 | const R1 = R*2; const R2 = R/2; const V1 = 0.01; V2 = 0.05; 262 | pts.push([R1 * Math.cos(t1) + R2 * Math.cos(t2), R1 * Math.sin(t1) + R2 * Math.sin(t2)]); 263 | t1 = (t1 + V1) % (2*Math.PI); 264 | t2 = (t2 + V2) % (2*Math.PI); 265 | 266 | const NUM_POINTS = 40; 267 | if (pts.length > NUM_POINTS) { 268 | pts.shift(); 269 | } 270 | 271 | s.background(238,238,238); 272 | s.background(255,253,231); 273 | s.noFill(); 274 | s.stroke(216,27,96); 275 | s.strokeWeight(6); 276 | s.beginShape(); 277 | for (let i = 0; i < pts.length; ++i) { 278 | s.stroke(216,27,96); 279 | s.curveVertex(pts[i][0] + W/2, pts[i][1] +H/2); 280 | } 281 | s.endShape(); 282 | 283 | s.strokeWeight(0); 284 | s.fill(69,90,100); 285 | s.ellipse(W/2, H/2, 2*R, 2*R); 286 | 287 | 288 | s.stroke(33,150,243); 289 | s.strokeWeight(6); 290 | s.beginShape(); 291 | for (let i = 0; i < pts.length; ++i) { 292 | const len = Math.sqrt(pts[i][0] * pts[i][0] + pts[i][1] * pts[i][1]); 293 | s.curveVertex(W/2 + R*pts[i][0]/len, H/2 + R*pts[i][1]/len); 294 | } 295 | s.endShape(); 296 | 297 | 298 | }; 299 | }; 300 | 301 | 302 | const transform = ( s ) => { 303 | let pts = []; 304 | s.setup = () => { 305 | let myCanvas = s.createCanvas(W, H); 306 | myCanvas.parent('transform'); 307 | }; 308 | 309 | s.draw = () => { 310 | 311 | pts.push([s.mouseX - W/2, s.mouseY -H/2]); 312 | const NUM_POINTS = 10; 313 | if (pts.length > NUM_POINTS) { 314 | pts.shift(); 315 | } 316 | 317 | s.background(238,238,238); 318 | s.background(255,253,231); 319 | s.noFill(); 320 | s.stroke(216,27,96); 321 | s.strokeWeight(6); 322 | s.beginShape(); 323 | for (let i = 0; i < pts.length; ++i) { 324 | s.stroke(216,27,96); 325 | s.curveVertex(pts[i][0] + W/2, pts[i][1] +H/2); 326 | } 327 | s.endShape(); 328 | 329 | s.strokeWeight(0); 330 | s.fill(69,90,100); 331 | s.ellipse(W/2, H/2, 2*R, 2*R); 332 | 333 | 334 | s.stroke(33,150,243); 335 | s.strokeWeight(6); 336 | s.beginShape(); 337 | for (let i = 0; i < pts.length; ++i) { 338 | const len = Math.sqrt(pts[i][0] * pts[i][0] + pts[i][1] * pts[i][1]); 339 | s.curveVertex(W/2 + R*pts[i][0]/len, H/2 + R*pts[i][1]/len); 340 | } 341 | s.endShape(); 342 | 343 | 344 | }; 345 | }; 346 | const crumple = ( s ) => { 347 | const fn = 100; // total # of frames 348 | let fi = 0; // current frame. 349 | let pts = [] 350 | s.setup = () => { 351 | let myCanvas = s.createCanvas(W, H); 352 | myCanvas.parent(document.getElementById('crumple')); 353 | } 354 | 355 | s.draw = () => { 356 | s.background(255,253,231); 357 | s.noFill(); 358 | 359 | s.strokeWeight(0); 360 | s.fill(69,90,100); 361 | s.ellipse(W/2, H/2, 2*R, 2*R); 362 | 363 | // generate points using halton sequence? 364 | // homotope points. 365 | const NFRAME_POINTS = 100; 366 | const NFRAME_TRANSFORM = 40; 367 | const NFRAME_STAY = 20; 368 | const NFRAME_HIDE = 20; 369 | 370 | 371 | let c0 = s.color(216,27,96, 255); 372 | let c1 = s.color(30,136,229, 128); 373 | const BORDER = 60; 374 | 375 | fi++; 376 | let fcur = fi; 377 | 378 | s.strokeWeight(6); 379 | 380 | if (fcur < NFRAME_POINTS) { 381 | if (fcur == 0) { 382 | pts = []; 383 | } else { 384 | let rRand = 2*R + halton(fcur, 2) * 6*R; 385 | let thetaRand = halton(fcur, 3) * 2 * Math.PI 386 | 387 | pts.push([rRand * Math.cos(thetaRand), rRand * Math.sin(thetaRand)]); 388 | } 389 | for(let i = 0; i < pts.length; ++i) { 390 | let x0 = pts[i][0]; 391 | let y0 = pts[i][1]; 392 | 393 | let t = Math.min(1, (fcur - i)/5); 394 | let ct = s.color(c0); 395 | ct.setAlpha(255*t); 396 | s.stroke(ct); 397 | s.point(W/2 + x0, H/2 + y0); 398 | } 399 | return; 400 | } else { 401 | fcur -= NFRAME_POINTS; 402 | } 403 | 404 | if (fcur < NFRAME_STAY) { 405 | let t = fcur /NFRAME_STAY; 406 | for(let i = 0; i < pts.length; ++i) { 407 | let x0 = pts[i][0]; 408 | let y0 = pts[i][1]; 409 | let x1 = R*x0/Math.sqrt(x0*x0 + y0*y0); 410 | let y1 = R*y0/Math.sqrt(x0*x0 + y0*y0); 411 | s.stroke(c0); 412 | s.point(W/2 + x0, H/2 + y0); 413 | } 414 | return; 415 | } else { fcur -= NFRAME_STAY }; 416 | 417 | 418 | if (fcur < NFRAME_TRANSFORM) { 419 | let t = fcur/NFRAME_TRANSFORM; 420 | t = easeOutQuart(t); 421 | for(let i = 0; i < pts.length; ++i) { 422 | let x0 = pts[i][0]; 423 | let y0 = pts[i][1]; 424 | let x1 = R*x0/Math.sqrt(x0*x0 + y0*y0); 425 | let y1 = R*y0/Math.sqrt(x0*x0 + y0*y0); 426 | 427 | s.stroke(s.lerpColor(c0, c1, t)); 428 | s.point(W/2 + (1-t)*x0 + t*x1, H/2 + (1-t)*y0 + t*y1); 429 | } 430 | return; 431 | 432 | } else { 433 | fcur -= NFRAME_TRANSFORM; 434 | } 435 | 436 | if (fcur < NFRAME_STAY) { 437 | for(let i = 0; i < pts.length; ++i) { 438 | let x0 = pts[i][0]; 439 | let y0 = pts[i][1]; 440 | let x1 = R*x0/Math.sqrt(x0*x0 + y0*y0); 441 | let y1 = R*y0/Math.sqrt(x0*x0 + y0*y0); 442 | s.stroke(c1); 443 | s.point(W/2 + x1, H/2 + y1); 444 | } 445 | return; 446 | } else { 447 | fcur -= NFRAME_STAY; 448 | } 449 | 450 | if (fcur < NFRAME_HIDE) { 451 | let t = fcur /NFRAME_HIDE; 452 | t = easeInQuart(t); 453 | for(let i = 0; i < pts.length; ++i) { 454 | let x0 = pts[i][0]; 455 | let y0 = pts[i][1]; 456 | let x1 = R*x0/Math.sqrt(x0*x0 + y0*y0); 457 | let y1 = R*y0/Math.sqrt(x0*x0 + y0*y0); 458 | let ct = s.color(c1); 459 | ct.setAlpha(128*(1.0 - t)); 460 | s.stroke(ct); 461 | s.point(W/2 + x1, H/2 + y1); 462 | } 463 | return; 464 | } 465 | 466 | // pause. 467 | if (fcur < 50) { return; } 468 | 469 | // ran no animation. exhausted. 470 | fi = 0; 471 | pts = []; 472 | return; 473 | }; 474 | }; 475 | 476 | const static_derivative = ( s ) => { 477 | 478 | let pts = []; 479 | 480 | let fi = 0; 481 | let fv = 1; 482 | 483 | s.setup = () => { 484 | let myCanvas = s.createCanvas(W, H); 485 | // myCanvas.parent(document.getElementById('myContainer')); 486 | myCanvas.parent('static-derivative'); 487 | 488 | for (let i = -50; i < 50; ++i) { 489 | let x = i*2; 490 | let y = 1.5*R; 491 | pts.push([i, x, y]); 492 | } 493 | }; 494 | 495 | s.draw = () => { 496 | s.background(255,253,231); 497 | 498 | s.strokeWeight(0); 499 | s.fill(69,90,100); 500 | s.ellipse(W/2, H/2, 2*R, 2*R); 501 | 502 | 503 | s.stroke(66,66,66); 504 | s.strokeWeight(4); 505 | s.strokeCap(s.SQUARE); 506 | s.noFill(); 507 | s.beginShape(); 508 | for (let i = 0; i < pts.length; ++i) { 509 | let x = pts[i][1]; 510 | let y = pts[i][2]; 511 | s.curveVertex(W/2 + x, H/2 + y); 512 | } 513 | s.endShape(); 514 | 515 | 516 | 517 | const LEN = 30; 518 | if (fv == 1 && fi == pts.length - LEN - 1) { fv = -1; } 519 | if (fv == -1 && fi == 1 ) { fv = 1; } 520 | fi += fv; 521 | 522 | // purple 523 | s.strokeWeight(6); 524 | s.stroke(106,27,154); 525 | s.noFill(); 526 | s.beginShape(); 527 | for (let i = fi; i < fi + LEN; ++i) { 528 | let x = pts[i][1]; 529 | let y = pts[i][2]; 530 | s.curveVertex(W/2 + x, H/2 + y); 531 | } 532 | s.endShape(); 533 | 534 | const xmid = pts[fi+LEN/2][1]; 535 | const ymid = pts[fi+LEN/2][2]; 536 | 537 | // blue 538 | s.strokeWeight(0); 539 | s.fill(33,150,243); 540 | s.ellipse(W/2 + xmid, H/2 + ymid, 10, 10); 541 | 542 | 543 | // orange 544 | s.stroke(255,111,0) 545 | s.strokeWeight(6); 546 | s.strokeCap(s.SQUARE); 547 | s.noFill(); 548 | s.beginShape(); 549 | for (let i = fi; i < fi + LEN; ++i) { 550 | let x = pts[i][1]; 551 | let y = pts[i][2]; 552 | let px = R*x/Math.sqrt(x*x+y*y); 553 | let py = R*y/Math.sqrt(x*x+y*y); 554 | s.curveVertex(W/2 + px, H/2 + py); 555 | } 556 | s.endShape(); 557 | 558 | 559 | 560 | // pink 561 | const pxmid = R*xmid/Math.sqrt(xmid*xmid+ymid*ymid); 562 | const pymid = R*ymid/Math.sqrt(xmid*xmid+ymid*ymid); 563 | s.strokeWeight(0); 564 | s.fill(233,30,99); 565 | s.ellipse(W/2 + pxmid, H/2 + pymid, 10, 10); 566 | 567 | }; 568 | }; 569 | 570 | 571 | const linear_derivative = ( s ) => { 572 | let pts = []; 573 | 574 | let fi = 0; 575 | 576 | s.setup = () => { 577 | let myCanvas = s.createCanvas(W, H); 578 | // myCanvas.parent(document.getElementById('myContainer')); 579 | myCanvas.parent('linear-derivative'); 580 | 581 | for (let i = -50; i < 50; ++i) { 582 | let x = i*2; 583 | let y = 1.5*R; 584 | pts.push([i, x, y]); 585 | } 586 | }; 587 | 588 | s.draw = () => { 589 | s.background(255,253,231); 590 | 591 | s.strokeWeight(0); 592 | s.fill(69,90,100); 593 | s.ellipse(W/2, H/2, 2*R, 2*R); 594 | 595 | 596 | s.stroke(66,66,66); 597 | s.strokeWeight(4); 598 | s.strokeCap(s.SQUARE); 599 | s.noFill(); 600 | s.beginShape(); 601 | for (let i = 0; i < pts.length; ++i) { 602 | let x = pts[i][1]; 603 | let y = pts[i][2]; 604 | s.curveVertex(W/2 + x, H/2 + y); 605 | } 606 | s.endShape(); 607 | 608 | 609 | fi = (fi + 0.01) % (2*Math.PI); 610 | const LEN = Math.cos(fi) * Math.cos(fi)*40; 611 | const MID = 50; 612 | 613 | // purple 614 | s.strokeWeight(6); 615 | s.stroke(106,27,154); 616 | s.noFill(); 617 | s.beginShape(); 618 | for (let i = Math.floor(MID-LEN); i < Math.ceil(MID + LEN); ++i) { 619 | let x = pts[i][1]; 620 | let y = pts[i][2]; 621 | s.curveVertex(W/2 + x, H/2 + y); 622 | } 623 | s.endShape(); 624 | 625 | const xmid = pts[MID][1]; 626 | const ymid = pts[MID][2]; 627 | 628 | // blue 629 | s.strokeWeight(0); 630 | s.fill(33,150,243); 631 | s.ellipse(W/2 + xmid, H/2 + ymid, 10, 10); 632 | 633 | 634 | // orange 635 | s.stroke(255,111,0) 636 | s.strokeWeight(6); 637 | s.strokeCap(s.SQUARE); 638 | s.noFill(); 639 | s.beginShape(); 640 | for (let i = Math.floor(MID-LEN); i < Math.ceil(MID + LEN); ++i) { 641 | let x = pts[i][1]; 642 | let y = pts[i][2]; 643 | let px = R*x/Math.sqrt(x*x+y*y); 644 | let py = R*y/Math.sqrt(x*x+y*y); 645 | s.curveVertex(W/2 + px, H/2 + py); 646 | } 647 | s.endShape(); 648 | 649 | 650 | 651 | // pink 652 | const pxmid = R*xmid/Math.sqrt(xmid*xmid+ymid*ymid); 653 | const pymid = R*ymid/Math.sqrt(xmid*xmid+ymid*ymid); 654 | s.strokeWeight(0); 655 | s.fill(233,30,99); 656 | s.ellipse(W/2 + pxmid, H/2 + pymid, 10, 10); 657 | 658 | }; 659 | }; 660 | 661 | 662 | let p5_crumple = new p5(crumple); 663 | let p5_transform = new p5(transform); 664 | let p5_transform_anim = new p5(transform_anim); 665 | let p5_transform_anim_normal = new p5(transform_anim_normal); 666 | let p5_transform_anim_tangential = new p5(transform_anim_tangential); 667 | let p5_interactive_derivative = new p5(interactive_derivative); 668 | let p5_static_derivative = new p5(static_derivative); 669 | let p5_linear_derivative = new p5(linear_derivative); 670 | 671 | 672 | -------------------------------------------------------------------------------- /observablehq.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mathemagic 5 | 6 | 7 | 19 | 20 | 21 |
22 |

Staged Animations as a Generator of Promises

23 |
24 |

25 | I explain the amazingly slick animation 26 | library from observablehq, its 27 | philosophy, and how to get their examples running on a page that's outside 28 | of their garden. 29 |

30 | 31 |

D3js

32 |

33 | The big idea is this: we use `d3.js` to animate what I'll term a _scene_. 34 | A _scene_ consists of some objects `enter`ing, some objects `exit`ing, 35 | and some objects `update`ing. To setup control flow _between_ scenes, 36 | we will use `async/await` in ES6. 37 | 38 | In the text above, a scene is one sentence that's shown. The objects 39 | that are entering are the new letters in green. The objects that are 40 | exiting are the letters that drop out in red. The objects that 41 | are updated are predictably the letters that rearrange in black. 42 |

43 |
44 |
45 | 46 |
47 | 48 | 49 | 381 | 382 | -------------------------------------------------------------------------------- /ddg-laplace-operator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 18 | 19 | 33 | 34 | 35 | 36 | 40 | 41 | 42 | 80 | 81 |

The Laplacian

82 | 83 | # The laplace operator and its generalization to curved spaces: Laplace Beltrami

84 | It's a generalization of the ordinaly laplacian to curved domains. 85 | We will write \(\Delta\). (We will reserve \(\nabla^2\) for the Hessian, which is related to the laplacian) 86 | Discrete laplacians reduce problems to linear algebra. 87 | 88 |

Laplacian in physics

89 |
    90 |
  • Heat equation: \( \frac{d}{dt} u = \Delta u \): Heat at the boundary is fixed. 91 | What is heat at time \( t \)
  • 92 |
  • Wave equation: \(\frac{d^2u}{dt^2} = -\Delta u\): Initial values are fixed of 93 | particle locations. Simulates how waves evolve over time.
  • 94 |
  • Laplace equation: \(\Delta u = 0\).
  • 95 |
96 | 97 |

Laplacian in \(\mathbb R^n\)

98 | 99 | If \(u: \mathbb R^n \rightarrow \mathbb R\), then \(\Delta u = \sum_{i=1}^n \frac{\partial^2}{\partial x_i^2} u\) 100 | 101 |

In 2-D

102 | If \( u: \mathbb R^2 \rightarrow \mathbb R \), then 103 | \[ \Delta u = \frac{\partial^2u}{\partial x^2}(x, y) + \frac{\partial^2 u}{\partial y^2}(x, y) \]. 104 | 105 |

Examples of computing Laplacians in 2D

106 |

\( u_1(x, y) \equiv -x^2 - 2y^2 \)

107 | \[ 108 | \begin{aligned} 109 | \Delta u_1 &= \frac{\partial^2}{\partial x^2}(-x^2 - 2y^2) + 110 | \frac{\partial^2}{\partial y^2}(-x^2 - 2y^2) \\ 111 | & = -2 - 4 = -6 112 | \end{aligned} 113 | \] 114 | 115 |

\( u_2(x, y) \equiv -3x^3 - 3xy^2 \)

116 | \[ 117 | 118 | \begin{aligned} 119 | \Delta u_2 &= \frac{\partial^2}{\partial x^2}(x^3 - 3xy^2) + 120 | \frac{\partial^2}{\partial y^2}(x^3 - 3xy^2) \\ 121 | & = 6x - 6x = 0 122 | \end{aligned} 123 | \] 124 | 125 |

Second Derivative: Convexity

126 | \( u(x) = \frac{d^2u}{dx^2} \) 127 | 128 | Magnitude of second derivative has to do about curvature. One way to talk 129 | about curvature is to build the osculating circle. 130 | 131 | It is not as simple as \( \kappa = u'' \): It's \( \kappa = u'' / (1 + (u')^2)^{3/2} \) 132 | 133 | But if the first derivative is zero, then \( \kappa = u'' \) 134 | 135 | 136 | 137 |

Graph laplacian

138 | 139 | \(G = (V, E) \). Store a value \( u_i \) at each vertex \( i \). 140 | \[ 141 | (Lu)_i \equiv (\frac{1}{deg(i)} \sum_{(i, j) \in E} u_j) - u_i 142 | \] 143 | 144 | If the values in the nodes is the heat of each vertex, then the value of 145 | the laplacian tells us if we are hotter or colder than the _average_ of 146 | our neighbours. 147 | 148 | Key idea: Laplacian is deviation from the local average. 149 |

Second derivative: Deviation from average

150 | 151 | Great animation! 152 | \(u(x_0 - \epsilon)), \u(x_0), \u(x_0 + \epsilon) 153 | 154 |

Laplacian: Deviation from average

155 | 156 | difference between value at point $x_0$ and the average 157 | value in a small ball around $x_0. 158 | 159 | \[ 160 | \delta (x_0) \sim \lim_{r \rightarrow 0} 1/r^2 (\frac{1}{|B_r(x_0)|}) \int_{B_r{x_0}} u(x) dx - u(x_0) 161 | \] 162 | 163 |

Heat equation

164 | 165 | Change in the function value is equal to the laplacian of the function: \(du/dt = \delta u\). 166 | Values move to the average of nearby values, till it becomes completely constant. 167 | Bumps above the surface get pushed down. Bumps below the surface get pushed up. 168 | 169 |

Laplace equation

170 | 171 | If we run the heat equation for a very long time \( du/dt = \Delta u; \quad u|_{\partial \Omega} = g \), 172 | eventually the value at any point will be equal to the average of the neighbouring values. It 173 | will satisfy $\Delta u = 0$. 174 | 175 | Such a function is called as a harmonic function. Such a function will be 176 | a solution to the laplace equation. 177 | 178 | It's a very "harmonious" situation. 179 | 180 |

Wave equation

181 | 182 | \[ d^u/dt^2 = \Delta u \]. The force is equal to the laplacian of the 183 | displacement. If a point is above the local average, it experiences 184 | a downward force. If a point is below the local average, it experiences 185 | an upward force. 186 | 187 | 195 | 196 | 197 |

Random walks and the laplacian

198 | Connects to heat kernel. 199 | 200 |

Laplacian via Dirichlet energy

201 | 202 | Define \( \int_\Omega |\Delta u|^2 dV \). A notion of smoothness. 203 | 204 | We can use the laplacian to express Dirichlet energy as a quadratic form. 205 | 206 | \( \langle \delta u, u \rangle = \int_\Omega u \delta u dV \) 207 | 208 | 209 |

Properties of the laplace operator

210 | 211 | All constant functions have 0 laplacian. Linear functions also, because 212 | linear functions don't have second derivativtes. It is invariant to rigid 213 | motions and isometries, because it only depends on the average geometry. 214 | It's self adjoint (symmetric) and elliptic (positive definite). 215 | So we have \( - \langle \Delta u, u \rangle > 0 \) [positive definite upto sign], 216 | and has a unique minimizer, upto constants. 217 | 218 | Key idea: Laplacian behaves like an almost-invertible positive definite 219 | matrix. 220 | 221 |

Spectral properties

222 | 223 | A real symmetric operator \(A\) has real eigenvalues \(\lambda_i\), orthogonal 224 | eigenvectors \(e_i\). 225 | 226 | Similarly, self-adjoint elliptic operator \(L\) on a compact domain has: 227 | 228 | a discrete set of eigenvalues \(\lambda_i\), orthogonal eigenfunctions \)\phi_i\). 229 | 230 | Example, second derivative on the circle \(S^1\). The eigenfunctions 231 | will be sines and cosines. These provide a basis for functions on the circle 232 | [Fourier basis]. 233 | 234 | 235 | This works for the Laplacian on any surface. Eigenfunctions of the sphere 236 | are spherical harmonics! We can do the same on any surface. 237 |

Dirichlet energy and harmonic functions

238 | 239 | There are many choices of how to interpolate. We have a region \( \Omega \). 240 | We know the boundary values \( g: \partial \Omega \rightarrow \mathbb R \). 241 | The best choice is a constant function, but constant functions are not smooth. 242 | So we can try to look for functions that are "as constant as possible". 243 | 244 |

Dirichlet energy

245 | 246 | Measures the failure of a function to be constant. It's the integrate of the 247 | norm of the gradient. So if the function does not change all that much, 248 | then the integral of the norms will be small. 249 | 250 | \[ 251 | E_D(u) \equiv \frac{1}{2} \int_\Omega | \nabla u |^2 dA 252 | \] 253 | 254 | It's zero for constant functions. 255 | Large where the function changes rapidly. 256 | 257 |

Dirichlet Principle

258 | 259 | How do we minimize Dirichlet energy? We can set the gradient of the dirichlet 260 | energy to 0 and solve. Because Dirichlet energy is convex, we can show that 261 | we have a unique minimizer. 262 | 263 | We can show that 264 | 265 | \[ 266 | E_D(u) = \int_\Omega u \nabla u dA 267 | \] 268 | 269 | Setting it to 0 gives us: 270 | 271 | \[ 272 | \nabla u = 0 \text{on $\Omega$} \\ 273 | u = g \text{on $\partial \Omega$} 274 | \] 275 | 276 | A function \( u\) minimizes dirichlet energy iff it is a solution to the laplace equation 277 | 278 |

Conformal maps, complex functions

279 | 280 | Functions that minimize geometry are harmonic functions. 281 | They exhibit a mean value property: value at any point \( x \) is equal 282 | to the average over **any** ball (not just small balls) 283 | 284 | Maximum principle: we can have no extrema for interior points. The value 285 | inside the ball cannot be larger than the values on the boundary of the ball. 286 | Thus, the maxima or minima have to be on the boundary of the domain. 287 | 288 | 289 | 290 | 293 | 294 |

Poisson equation

295 | Laplace equation is a stationary solution to the heat equation. What if 296 | we have a heat source? \( \frac{du}{dt} = \nabla u + f \). We have some 297 | boundary values (we may think of this as a heat sink), \(u = g \) on the boundary 298 | \( \partial \Omega \). 299 | 300 |

Harmonic green's function

301 | 302 | What happens to the dirac delta? We get green's function 303 | 304 | We can convolve any function with the green's function to solve them. 305 | 306 | Key idea: Solving a linear PDE is equivalent to convolving with the fundamental solution. 307 | 308 |

Poisson Equation: Variational perspective

309 | 310 | Given a vector field $X$, find the potential whose gradient is $X$. 311 | 312 | \[ 313 | \min_u \int_\Omega | \nabla u - X|^2 314 | \] 315 | 316 | Key idea: Use poisson equation to integrate a vector field. 317 | 318 |

Boundary conditions

319 | Tricky, easy to get wrong. What kind can we have? 320 | - Dirichlet boundary conditions: Values at the endpoints are fixed. 321 | - Neumann boundary conditions: Boundary derivatives are fixed 322 | - Mixture of data, we also have stuff that can satisfy them. 323 | 324 |

One dimensional laplace equation

325 | 326 | Dirichlet conditions? Yes, just draw a straight line. 327 | 328 | Neumann conditions? No, we cannot control the derivative at both ends 329 | 330 |

2D: Laplace equation

331 | 332 |

Dirichlet conditions

333 | \[ 334 | \nabla u = 0 \text{ on } \Omega \\ 335 | u = g \text{ on } \partial \Omega 336 | \] 337 | 338 | Can we satisfy these conditions? Yes, just let the heat equation run. 339 | 340 |

Neumann conditions

341 | 342 | Use laplace equation. 343 | 344 | PDE may not have solutions for given boundary conditions. 345 | 346 |
347 |
348 |
349 |
350 |
351 | 352 | 353 |

FOOBAR

354 |

FOOBAR

355 |

FOOBAR

356 |

FOOBAR

357 |

FOOBAR

358 |

FOOBAR

359 | 360 |
361 |
362 | 363 | 520 | 521 | 522 | --------------------------------------------------------------------------------