0?B(u.type,u.props,u.key,u.ref?u.ref:null,u.__v):u).__=t,u.__b=t.__b+1,c=null,(s=u.__i=ut(u,n,l,i))!==-1&&(i--,(c=n[s])&&(c.__u|=2)),c==null||c.__v===null?(s==-1&&f--,typeof u.type!="function"&&(u.__u|=4)):s!=l&&(s==l-1?f--:s==l+1?f++:(s>l?f--:f++,u.__u|=4))):t.__k[r]=null;if(i)for(r=0;r(l!=null&&!(2&l.__u)?1:0))for(o=n-1,r=n+1;o>=0||r=0){if((l=e[o])&&!(2&l.__u)&&u==l.key&&c===l.type)return o;o--}if(r2&&(c.children=arguments.length>3?q.call(arguments,2):n),B(t.type,c,_||t.key,o||t.ref,null)}function fe(t,e){var n={__c:e="__cC"+Le++,__:t,Consumer:function(_,o){return _.children(o)},Provider:function(_){var o,r;return this.getChildContext||(o=new Set,(r={})[e]=this,this.getChildContext=function(){return r},this.componentWillUnmount=function(){o=null},this.shouldComponentUpdate=function(u){this.props.value!==u.value&&o.forEach(function(c){c.__e=!0,re(c)})},this.sub=function(u){o.add(u);var c=u.componentWillUnmount;u.componentWillUnmount=function(){o&&o.delete(u),c&&c.call(u)}}),_.children}};return n.Provider.__=n.Consumer.contextType=n}var q,m,Se,rt,U,Ee,He,te,Re,oe,ne,_e,Le,N,De,ot,J,T=_t(()=>{N={},De=[],ot=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,J=Array.isArray;q=De.slice,m={__e:function(t,e,n,_){for(var o,r,u;e=e.__;)if((o=e.__c)&&!o.__)try{if((r=o.constructor)&&r.getDerivedStateFromError!=null&&(o.setState(r.getDerivedStateFromError(t)),u=o.__d),o.componentDidCatch!=null&&(o.componentDidCatch(t,_||{}),u=o.__d),u)return o.__E=o}catch(c){t=c}throw t}},Se=0,rt=function(t){return t!=null&&t.constructor==null},K.prototype.setState=function(t,e){var n;n=this.__s!=null&&this.__s!==this.state?this.__s:this.__s=R({},this.state),typeof t=="function"&&(t=t(R({},n),this.props)),t&&R(n,t),t!=null&&this.__v&&(e&&this._sb.push(e),re(this))},K.prototype.forceUpdate=function(t){this.__v&&(this.__e=!0,t&&this.__h.push(t),re(this))},K.prototype.render=Y,U=[],He=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,te=function(t,e){return t.__v.__b-e.__v.__b},G.__r=0,Re=/(PointerCapture)$|Capture$/i,oe=0,ne=we(!1),_e=we(!0),Le=0});T();T();T();T();var I,y,pe,Ie,he=0,je=[],b=m,We=b.__b,Be=b.__r,Ne=b.diffed,qe=b.__c,$e=b.unmount,Oe=b.__;function X(t,e){b.__h&&b.__h(y,t,he||e),he=0;var n=y.__H||(y.__H={__:[],__h:[]});return t>=n.__.length&&n.__.push({}),n.__[t]}function me(t,e,n){var _=X(I++,2);if(_.t=t,!_.__c&&(_.__=[n?n(e):ft(void 0,e),function(c){var l=_.__N?_.__N[0]:_.__[0],s=_.t(l,c);l!==s&&(_.__N=[s,_.__[1]],_.__c.setState({}))}],_.__c=y,!y.u)){var o=function(c,l,s){if(!_.__c.__H)return!0;var p=_.__c.__H.__.filter(function(f){return!!f.__c});if(p.every(function(f){return!f.__N}))return!r||r.call(this,c,l,s);var i=_.__c.props!==c;return p.forEach(function(f){if(f.__N){var a=f.__[0];f.__=f.__N,f.__N=void 0,a!==f.__[0]&&(i=!0)}}),r&&r.call(this,c,l,s)||i};y.u=!0;var r=y.shouldComponentUpdate,u=y.componentWillUpdate;y.componentWillUpdate=function(c,l,s){if(this.__e){var p=r;r=void 0,o(c,l,s),r=p}u&&u.call(this,c,l,s)},y.shouldComponentUpdate=o}return _.__N||_.__}function ve(t,e){var n=X(I++,4);!b.__s&&Ke(n.__H,e)&&(n.__=t,n.i=e,y.__h.push(n))}function w(t){return he=5,Z(function(){return{current:t}},[])}function Z(t,e){var n=X(I++,7);return Ke(n.__H,e)&&(n.__=t(),n.__H=e,n.__h=t),n.__}function ye(t){var e=y.context[t.__c],n=X(I++,9);return n.c=t,e?(n.__==null&&(n.__=!0,e.sub(y)),e.props.value):t.__}function lt(){for(var t;t=je.shift();)if(t.__P&&t.__H)try{t.__H.__h.forEach(Q),t.__H.__h.forEach(de),t.__H.__h=[]}catch(e){t.__H.__h=[],b.__e(e,t.__v)}}b.__b=function(t){y=null,We&&We(t)},b.__=function(t,e){t&&e.__k&&e.__k.__m&&(t.__m=e.__k.__m),Oe&&Oe(t,e)},b.__r=function(t){Be&&Be(t),I=0;var e=(y=t.__c).__H;e&&(pe===y?(e.__h=[],y.__h=[],e.__.forEach(function(n){n.__N&&(n.__=n.__N),n.i=n.__N=void 0})):(e.__h.forEach(Q),e.__h.forEach(de),e.__h=[],I=0)),pe=y},b.diffed=function(t){Ne&&Ne(t);var e=t.__c;e&&e.__H&&(e.__H.__h.length&&(je.push(e)!==1&&Ie===b.requestAnimationFrame||((Ie=b.requestAnimationFrame)||at)(lt)),e.__H.__.forEach(function(n){n.i&&(n.__H=n.i),n.i=void 0})),pe=y=null},b.__c=function(t,e){e.some(function(n){try{n.__h.forEach(Q),n.__h=n.__h.filter(function(_){return!_.__||de(_)})}catch(_){e.some(function(o){o.__h&&(o.__h=[])}),e=[],b.__e(_,n.__v)}}),qe&&qe(t,e)},b.unmount=function(t){$e&&$e(t);var e,n=t.__c;n&&n.__H&&(n.__H.__.forEach(function(_){try{Q(_)}catch(o){e=o}}),n.__H=void 0,e&&b.__e(e,n.__v))};var ze=typeof requestAnimationFrame=="function";function at(t){var e,n=function(){clearTimeout(_),ze&&cancelAnimationFrame(e),setTimeout(t)},_=setTimeout(n,100);ze&&(e=requestAnimationFrame(n))}function Q(t){var e=y,n=t.__c;typeof n=="function"&&(t.__c=void 0,n()),y=e}function de(t){var e=y;t.__c=t.__(),y=e}function Ke(t,e){return!t||t.length!==e.length||e.some(function(n,_){return n!==t[_]})}function ft(t,e){return typeof e=="function"?e(t):e}var A,$,pt=(t,e)=>{if(A=void 0,e&&e.type==="click"){if(e.ctrlKey||e.metaKey||e.altKey||e.shiftKey||e.button!==0)return t;let n=e.target.closest("a[href]"),_=n&&n.getAttribute("href");if(!n||n.origin!=location.origin||/^#/.test(_)||!/^(_?self)?$/i.test(n.target)||$&&(typeof $=="string"?!_.startsWith($):!$.test(_)))return t;A=!0,e.preventDefault(),e=n.href.replace(location.origin,"")}else typeof e=="string"?A=!0:e&&e.url?(A=!e.replace,e=e.url):e=location.pathname+location.search;return A===!0?history.pushState(null,"",e):A===!1&&history.replaceState(null,"",e),e},ht=(t,e,n)=>{t=t.split("/").filter(Boolean),e=(e||"").split("/").filter(Boolean);for(let _=0,o,r;_{let r=new URL(e,location.origin),u=r.pathname.replace(/\/+$/g,"")||"/";return{url:e,path:u,query:Object.fromEntries(r.searchParams),route:(c,l)=>n({url:c,replace:l}),wasPush:_}},[e]);return ve(()=>(addEventListener("click",n),addEventListener("popstate",n),()=>{removeEventListener("click",n),removeEventListener("popstate",n)}),[]),E(O.ctx.Provider,{value:o},t.children)}var dt=Promise.resolve();function Je(t){let[e,n]=me(k=>k+1,0),{url:_,query:o,wasPush:r,path:u}=Ye(),{rest:c=u,params:l={}}=ye(Ge),s=w(!1),p=w(u),i=w(0),f=w(),a=w(),v=w(),x=w(!1),g=w();g.current=!1;let h=w(!1),d,L,C;ue(t.children).some(k=>{if(ht(c,k.props.path,C=Ce(xe({},k.props),{path:c,query:o,params:l,rest:""})))return d=ae(k,C);k.props.default&&(L=ae(k,C))});let S=d||L;Z(()=>{a.current=f.current;let k=a.current&&a.current.props.children;!k||!S||S.type!==k.type||S.props.component!==k.props.component?(this.__v&&this.__v.__k&&this.__v.__k.reverse(),i.current++,h.current=!0):h.current=!1},[_]);let D=f.current&&f.current.__u&V&&f.current.__u&ee,z=f.current&&f.current.__h;f.current=E(Ge.Provider,{value:C},S),D?(f.current.__u|=V,f.current.__u|=ee):z&&(f.current.__h=!0);let M=a.current;return a.current=null,this.__c=(k,H)=>{g.current=!0,a.current=M,t.onLoadStart&&t.onLoadStart(_),s.current=!0;let P=i.current;k.then(()=>{P===i.current&&(a.current=null,f.current&&(H.__h&&(f.current.__h=H.__h),H.__u&ee&&(f.current.__u|=ee),H.__u&V&&(f.current.__u|=V)),dt.then(n))})},ve(()=>{let k=this.__v&&this.__v.__e;if(g.current){!x.current&&!v.current&&(v.current=k);return}!x.current&&v.current&&(v.current!==k&&v.current.remove(),v.current=null),x.current=!0,p.current!==u&&(r&&scrollTo(0,0),t.onRouteChange&&t.onRouteChange(_),p.current=u),t.onLoadEnd&&s.current&&t.onLoadEnd(_),s.current=!1},[u,r,e]),h.current?[E(ge,{r:f}),E(ge,{r:a})]:E(ge,{r:f})}var V=32,ee=128,ge=({r:t})=>t.current;Je.Provider=O;O.ctx=fe({});var Ge=fe({});var Ye=()=>ye(O.ctx);T();var Qe=m.__e;m.__e=(t,e,n)=>{if(t&&t.then){let _=e;for(;_=_.__;)if(_.__c&&_.__c.__c)return e.__e==null&&(e.__e=n.__e,e.__k=n.__k),e.__k||(e.__k=[]),_.__c.__c(t,e)}Qe&&Qe(t,e,n)};T();function mt(){return E("div",null,E("h1",null,"Lorem ipsum dolor sit amet, consectetur adipisicing elit."))}var Xe=mt;le(E(Xe,null),document.getElementById("root"));})();
+/**
+* @license Apache-2.0
+*
+* Copyright (c) 2025 The Stdlib Authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
diff --git a/server/index.js b/server/index.js
new file mode 100644
index 0000000000..c260a1baa1
--- /dev/null
+++ b/server/index.js
@@ -0,0 +1,21 @@
+/**
+* @license Apache-2.0
+*
+* Copyright (c) 2025 The Stdlib Authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+// MAIN //
+
+require( './server.js' );
\ No newline at end of file
diff --git a/server/server.js b/server/server.js
new file mode 100644
index 0000000000..4ab4e130e9
--- /dev/null
+++ b/server/server.js
@@ -0,0 +1,67 @@
+/**
+* @license Apache-2.0
+*
+* Copyright (c) 2025 The Stdlib Authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+'use strict';
+
+// MODULES //
+
+var path = require( 'path' );
+var httpServer = require( './../lib/server' );
+
+
+// VARIABLES //
+
+var PUBLIC_DIR = path.resolve( __dirname, '..', 'public' );
+var PORT = 3000;
+
+
+// FUNCTIONS //
+
+/**
+* Callback invoked upon starting a server.
+*
+* @private
+* @param {(Error|null)} error - error object
+* @param {Object} fastify - fastify instance
+*/
+function done( error ) {
+ if ( error ) {
+ throw error;
+ }
+ console.log( 'Server is running...' );
+}
+
+
+// MAIN //
+
+/**
+* Main execution sequence.
+*
+* @private
+*/
+function main() {
+ var opts = {
+ 'logger': 'info',
+ 'port': PORT,
+ 'prefix': '/',
+ 'root': PUBLIC_DIR
+ };
+ httpServer( opts )( done );
+}
+
+main();
diff --git a/src/app.jsx b/src/app.jsx
new file mode 100644
index 0000000000..472eae3035
--- /dev/null
+++ b/src/app.jsx
@@ -0,0 +1,45 @@
+/**
+* @license Apache-2.0
+*
+* Copyright (c) 2025 The Stdlib Authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+'use strict';
+
+// MODULES //
+
+import { h } from 'preact'
+import { Router } from 'preact-iso'
+
+
+// MAIN //
+
+/**
+* Main application component.
+*
+* @returns {PreactComponent} preact component
+*/
+function App() {
+ return(
+
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
+
+ )
+}
+
+
+// EXPORTS //
+
+export default App;
diff --git a/src/index.jsx b/src/index.jsx
new file mode 100644
index 0000000000..ba3acf112a
--- /dev/null
+++ b/src/index.jsx
@@ -0,0 +1,29 @@
+/**
+* @license Apache-2.0
+*
+* Copyright (c) 2025 The Stdlib Authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+'use strict';
+
+// MODULES //
+
+import { render } from 'preact';
+import App from './app.jsx';
+
+
+// MAIN //
+
+render( , document.getElementById( 'root' ) );
diff --git a/tools/README.md b/tools/README.md
new file mode 100644
index 0000000000..1dfae75f62
--- /dev/null
+++ b/tools/README.md
@@ -0,0 +1,49 @@
+
+
+# Tools
+
+> Development tools.
+
+
+
+
+
+This directory contains development utilities for building and managing the website.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/make/Makefile b/tools/make/Makefile
new file mode 100644
index 0000000000..005d80944c
--- /dev/null
+++ b/tools/make/Makefile
@@ -0,0 +1,65 @@
+#/
+# @license Apache-2.0
+#
+# Copyright (c) 2025 The Stdlib Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#/
+
+# DEPENDENCIES #
+
+# Order is important:
+include $(TOOLS_MAKE_DIR)/common.mk
+include $(TOOLS_MAKE_LIB_DIR)/help/Makefile
+
+# Please keep sorted in alphabetical order:
+include $(TOOLS_MAKE_LIB_DIR)/css/Makefile
+include $(TOOLS_MAKE_LIB_DIR)/install/Makefile
+include $(TOOLS_MAKE_LIB_DIR)/js/Makefile
+
+
+# RULES #
+
+#/
+# Default target.
+#
+# @example
+# make
+#
+# @example
+# make all
+#/
+all: help
+
+.PHONY: all
+
+#/
+# Runs the project's cleanup sequence.
+#
+# @example
+# make clean
+#/
+clean: clean-node clean-js-bundle
+ $(QUIET) $(DELETE) $(DELETE_FLAGS)
+
+.PHONY: clean
+
+#/
+# Runs the project's build sequence.
+#
+# @example
+# make build
+#/
+build: $(NODE_MODULES) build-js css-minify
+
+.PHONY: build
diff --git a/tools/make/README.md b/tools/make/README.md
new file mode 100644
index 0000000000..b0fa75f1c0
--- /dev/null
+++ b/tools/make/README.md
@@ -0,0 +1,43 @@
+
+
+# Makefile
+
+> Development utility.
+
+This project uses [`make`][make] as its development utility. For an overview of `make`, see the `make` [manual][make].
+
+## Usage
+
+#### Help
+
+To view a list of available `Makefile` targets,
+
+```bash
+$ make help
+```
+
+
+
+[make]: https://www.gnu.org/software/make/manual/make.html#Introduction
+
+
+
+
diff --git a/tools/make/common.mk b/tools/make/common.mk
new file mode 100644
index 0000000000..95b0c839e6
--- /dev/null
+++ b/tools/make/common.mk
@@ -0,0 +1,127 @@
+#/
+# @license Apache-2.0
+#
+# Copyright (c) 2025 The Stdlib Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#/
+
+# VERBOSITY #
+
+ifndef VERBOSE
+ QUIET := @
+endif
+
+
+# ENVIRONMENTS #
+
+# Determine the OS:
+#
+# [1]: https://en.wikipedia.org/wiki/Uname#Examples
+# [2]: http://stackoverflow.com/a/27776822/2225624
+OS ?= $(shell uname)
+ifneq (, $(findstring MINGW,$(OS)))
+ OS := WINNT
+else
+ifneq (, $(findstring MSYS,$(OS)))
+ OS := WINNT
+else
+ifneq (, $(findstring CYGWIN,$(OS)))
+ OS := WINNT
+else
+ifneq (, $(findstring Windows_NT,$(OS)))
+ OS := WINNT
+endif
+endif
+endif
+endif
+
+# Define whether the make commands are running on a hosted continuous integration service:
+TRAVIS ?=
+APPVEYOR ?=
+CIRCLECI ?=
+GITHUB ?=
+ifeq ($(TRAVIS), true)
+ CI_SERVICE ?= travis
+else
+ifeq ($(APPVEYOR), true)
+ CI_SERVICE ?= appveyor
+else
+ifeq ($(CIRCLECI), true)
+ CI_SERVICE ?= circle
+else
+ifeq ($(GITHUB), true)
+ CI_SERVICE ?= github
+else
+ CI_SERVICE ?= none
+endif
+endif
+endif
+endif
+
+
+# COMMANDS #
+
+# Define whether delete operations should be safe (i.e., deleted items are sent to trash, rather than permanently deleted):
+SAFE_DELETE ?= false
+
+# Define the delete command:
+ifeq ($(SAFE_DELETE), true)
+ # FIXME: -rm -rf
+ DELETE := -rm
+ DELETE_FLAGS := -rf
+else
+ DELETE ?= -rm
+ DELETE_FLAGS ?= -rf
+endif
+
+# Define the command for setting executable permissions:
+MAKE_EXECUTABLE ?= chmod +x
+
+# Define the command for recursively creating directories (WARNING: portability issues on some systems!):
+MKDIR_RECURSIVE ?= mkdir -p
+
+# Define the command for extracting tarfiles:
+TAR ?= tar
+
+# Define the command to `cat` a file:
+CAT ?= cat
+
+# Define the command to copy files:
+CP ?= cp
+
+# Define the command to recursively sync directories:
+RSYNC_RECURSIVE ?= rsync -r
+
+# Define the `git` command:
+GIT ?= git
+
+# Define the command for staging files:
+GIT_ADD ?= $(GIT) add
+
+# Define the command for committing files:
+GIT_COMMIT ?= $(GIT) commit
+
+# Determine the `open` command:
+ifeq ($(OS), Darwin)
+ OPEN ?= open
+else
+ OPEN ?= xdg-open
+endif
+# TODO: add Windows command
+
+# Define the command for `node`:
+NODE ?= node
+
+# Define the command for `npm`:
+NPM ?= npm
diff --git a/tools/make/lib/css/Makefile b/tools/make/lib/css/Makefile
new file mode 100644
index 0000000000..c2b9cb20cf
--- /dev/null
+++ b/tools/make/lib/css/Makefile
@@ -0,0 +1,36 @@
+#/
+# @license Apache-2.0
+#
+# Copyright (c) 2025 The Stdlib Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#/
+
+# VARIABLES #
+
+# Define the path to the script for generating minified CSS bundles:
+css_minifier ?= $(TOOLS_DIR)/scripts/minify_css.js
+
+
+# RULES #
+
+#/
+# Minifies CSS source files.
+#
+# @example
+# make css-minify
+#/
+css-minify: $(NODE_MODULES) $(css_minifier)
+ $(QUIET) NODE_PATH="$(NODE_PATH)" $(NODE) "$(css_minifier)"
+
+.PHONY: css-minify
diff --git a/tools/make/lib/css/README.md b/tools/make/lib/css/README.md
new file mode 100644
index 0000000000..ce14bd217b
--- /dev/null
+++ b/tools/make/lib/css/README.md
@@ -0,0 +1,51 @@
+
+
+# CSS
+
+> CSS recipes.
+
+
+
+
+
+This directory contains [`make`][make] recipes for managing CSS files.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[make]: https://www.gnu.org/software/make/
+
+
+
+
diff --git a/tools/make/lib/help/Makefile b/tools/make/lib/help/Makefile
new file mode 100644
index 0000000000..e06e026275
--- /dev/null
+++ b/tools/make/lib/help/Makefile
@@ -0,0 +1,60 @@
+#/
+# @license Apache-2.0
+#
+# Copyright (c) 2025 The Stdlib Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#/
+
+# VARIABLES #
+
+# Define the path to the Makefile usage text file for displaying help information:
+MAKE_USAGE ?= $(TOOLS_MAKE_DIR)/usage.txt
+
+# Define command flags:
+FIND_MAKEFILES_FLAGS ?= \
+ -name 'Makefile' \
+ -o \
+ -name '*.mk'
+
+
+# RULES #
+
+#/
+# Prints a help message and lists available targets.
+#
+# @example
+# make help
+#/
+help:
+ $(QUIET) $(CAT) $(MAKE_USAGE)
+
+.PHONY: help
+
+#/
+# Lists all Makefile targets.
+#
+# ## Notes
+#
+# - The list of targets is NOT exhaustive, as it does not include targets which have not been explicitly declared PHONY targets and does not include targets declared via variables. These targets could be included by dumping the Makefile database `make -qp`, but not seen as necessary due to predominant use of PHONY.
+#
+# @example
+# make list-targets
+#/
+list-targets:
+ $(QUIET) find $(TOOLS_MAKE_DIR) $(FIND_MAKEFILES_FLAGS) \
+ | xargs grep '^.PHONY: ' \
+ | awk '{print $$2}' \
+ | sort
+
+.PHONY: list-targets
diff --git a/tools/make/lib/help/README.md b/tools/make/lib/help/README.md
new file mode 100644
index 0000000000..f272ba0650
--- /dev/null
+++ b/tools/make/lib/help/README.md
@@ -0,0 +1,51 @@
+
+
+# Help
+
+> Help recipes.
+
+
+
+
+
+This directory contains [`make`][make] recipes for printing help information when using [`make`][make], such as the project [`make`][make] usage text, targets, and more.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[make]: https://www.gnu.org/software/make/
+
+
+
+
diff --git a/tools/make/lib/install/Makefile b/tools/make/lib/install/Makefile
new file mode 100644
index 0000000000..cd8ceda0a3
--- /dev/null
+++ b/tools/make/lib/install/Makefile
@@ -0,0 +1,34 @@
+#/
+# @license Apache-2.0
+#
+# Copyright (c) 2025 The Stdlib Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#/
+
+# DEPENDENCIES #
+
+include $(TOOLS_MAKE_LIB_DIR)/install/node.mk
+
+
+# RULES #
+
+#/
+# Runs the project's install process.
+#
+# @example
+# make install
+#/
+install: install-node
+
+.PHONY: install
diff --git a/tools/make/lib/install/README.md b/tools/make/lib/install/README.md
new file mode 100644
index 0000000000..3088c575fb
--- /dev/null
+++ b/tools/make/lib/install/README.md
@@ -0,0 +1,51 @@
+
+
+# Install
+
+> Install recipes.
+
+
+
+
+
+This directory contains [`make`][make] recipes for running the project's installation process.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[make]: https://www.gnu.org/software/make/
+
+
+
+
diff --git a/tools/make/lib/install/node.mk b/tools/make/lib/install/node.mk
new file mode 100644
index 0000000000..0aecf81470
--- /dev/null
+++ b/tools/make/lib/install/node.mk
@@ -0,0 +1,53 @@
+#/
+# @license Apache-2.0
+#
+# Copyright (c) 2025 The Stdlib Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#/
+
+# VARIABLES #
+
+# Define the path to the root `package.json`:
+ROOT_PACKAGE_JSON ?= $(ROOT_DIR)/package.json
+
+
+# VARIABLES #
+
+#/
+# Installs package dependencies by executing [`npm install`][1].
+#
+# ## Notes
+#
+# - Packages will be installed in a local `node_modules` directory relative to the project's `package.json` file.
+#
+# [1]: https://docs.npmjs.com/cli/install
+#
+# @example
+# make install-node
+#/
+install-node: $(ROOT_PACKAGE_JSON)
+ $(QUIET) $(NPM) install
+
+.PHONY: install-node
+
+#/
+# Cleans the `node_modules` directory by removing it entirely.
+#
+# @example
+# make clean-node
+#/
+clean-node:
+ $(QUIET) $(DELETE) $(DELETE_FLAGS) $(NODE_MODULES)
+
+.PHONY: clean-node
diff --git a/tools/make/lib/js/Makefile b/tools/make/lib/js/Makefile
new file mode 100644
index 0000000000..f8a6c428c0
--- /dev/null
+++ b/tools/make/lib/js/Makefile
@@ -0,0 +1,43 @@
+#/
+# @license Apache-2.0
+#
+# Copyright (c) 2025 The Stdlib Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#/
+
+
+# RULES #
+
+#/
+# Builds JavaScript.
+#
+# @example
+# make build-js
+#/
+build-js: $(NODE_MODULES)
+ $(QUIET) NODE_PATH="$(NODE_PATH)" $(NODE) "$(ROOT_DIR)/etc/esbuild/build.js"
+
+.PHONY: build-js
+
+#/
+# Removes JavaScript bundle.
+#
+# @example
+# make clean-js
+#/
+clean-js-bundle:
+ $(QUIET) $(DELETE) $(BUILD_DIR)/js/bundle.js
+
+.PHONY: clean-js-bundle
+
diff --git a/tools/make/usage.txt b/tools/make/usage.txt
new file mode 100644
index 0000000000..aecad7e54a
--- /dev/null
+++ b/tools/make/usage.txt
@@ -0,0 +1,11 @@
+
+Usage: make
+
+ make help Print this message.
+ make notes Search for code annotations.
+ make list-files List files.
+ make install Run install sequence.
+ make clean Run all cleanup tasks.
+ make clean-node Remove Node dependencies.
+ make inspect.VARIABLE Print the runtime value of a VARIABLE.
+ make assert.VARIABLE Assert that a VARIABLE is set.
diff --git a/tools/scripts/README.md b/tools/scripts/README.md
new file mode 100644
index 0000000000..2d81c25553
--- /dev/null
+++ b/tools/scripts/README.md
@@ -0,0 +1,49 @@
+
+
+# Scripts
+
+> Generic scripts.
+
+
+
+
+
+This directory contains generic project scripts.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tools/scripts/minify_css.js b/tools/scripts/minify_css.js
new file mode 100644
index 0000000000..c851389b0e
--- /dev/null
+++ b/tools/scripts/minify_css.js
@@ -0,0 +1,126 @@
+#!/usr/bin/env node
+
+/**
+* @license Apache-2.0
+*
+* Copyright (c) 2025 The Stdlib Authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+'use strict';
+
+// MODULES //
+
+var fs = require( 'fs' );
+var path = require( 'path' );
+var CleanCSS = require( 'clean-css' );
+
+
+// VARIABLES //
+
+// Parent directory containing source CSS files:
+var dirpath = path.join( __dirname, '../../public/css' );
+
+// Child directories containing source CSS files to bundle and minify:
+var dirs = [
+ path.join( dirpath, 'main' )
+];
+
+// CSS processor options:
+var copts = {
+ 'returnPromise': false,
+ 'compatibility': 'ie9',
+ 'level': 1
+};
+
+
+// FUNCTIONS //
+
+/**
+* Synchronously reads a list of CSS files.
+*
+* @private
+* @param {Array} list - list of files
+* @returns {Array} array of file contents
+*/
+function readFiles( list ) {
+ var opts;
+ var out;
+ var i;
+
+ opts = {
+ 'encoding': 'utf8'
+ };
+ out = [];
+ for ( i = 0; i < list.length; i++ ) {
+ out.push( fs.readFileSync( list[ i ], opts ) );
+ }
+ return out;
+}
+
+
+// MAIN //
+
+/**
+* Main execution sequence.
+*
+* @private
+*/
+function main() {
+ var minifier;
+ var fpath;
+ var fopts;
+ var tmp;
+ var i;
+ var j;
+
+ minifier = new CleanCSS( copts );
+ fopts = {
+ 'encoding': 'utf8'
+ };
+
+ // Process each CSS directory...
+ for ( i = 0; i < dirs.length; i++ ) {
+ // Read the bundle list:
+ tmp = require( path.join( dirs[ i ], 'bundle.json' ) );
+
+ // Resolve each file in the list to an absolute path:
+ for ( j = 0; j < tmp.length; j++ ) {
+ tmp[ j ] = path.resolve( dirs[ i ], tmp[ j ] );
+ }
+ // Read each CSS file:
+ tmp = readFiles( tmp );
+
+ // Concatenate file contents into a single string:
+ tmp = tmp.join( '\n' );
+
+ // Minify the CSS:
+ tmp = minifier.minify( tmp );
+ if ( tmp.errors.length ) {
+ console.error( 'Directory: %s\n', dirs[ i ] );
+ console.error( 'Errors:\n' );
+ console.error( tmp.errors.join( '\n' ) );
+ }
+ if ( tmp.warnings.length ) {
+ console.error( 'Directory: %s\n', dirs[ i ] );
+ console.error( 'Warnings:\n' );
+ console.error( tmp.warnings.join( '\n' ) );
+ }
+ // Write the minified CSS to file:
+ fpath = path.join( dirs[ i ], 'bundle.min.css' );
+ fs.writeFileSync( fpath, tmp.styles, fopts );
+ }
+}
+
+main();