diff --git a/.gitignore b/.gitignore
index e985324..d3f8ca1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@ node_modules
.venv
dist
images
+docs/build
# Python
__pycache__
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..d0c3cbf
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?=
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = source
+BUILDDIR = build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 0000000..dc1312a
--- /dev/null
+++ b/docs/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=source
+set BUILDDIR=build
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.https://www.sphinx-doc.org/
+ exit /b 1
+)
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/docs/source/conf.py b/docs/source/conf.py
new file mode 100644
index 0000000..37ac532
--- /dev/null
+++ b/docs/source/conf.py
@@ -0,0 +1,26 @@
+"""Configuration file for the Sphinx documentation builder."""
+
+
+# -- Project information -----------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
+
+project = "IPyNiiVue"
+author = "Jan-Hendrik Müller, Trevor Manz, Bradley Alford, Anthony Androulakis, "
+author += "Taylor Hanayik, Christian O'Reilly"
+project_copyright = "2024, " + author
+release = "2.1.0"
+
+# -- General configuration ---------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
+
+extensions = []
+
+templates_path = ["_templates"]
+exclude_patterns = []
+
+
+# -- Options for HTML output -------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
+
+html_theme = "pyramid"
+html_static_path = ["_static"]
diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst
new file mode 100644
index 0000000..d374d19
--- /dev/null
+++ b/docs/source/contributing.rst
@@ -0,0 +1,69 @@
+Contributing
+============
+
+We are glad you are here! Contributions to this package are always welcome.
+Read on to learn more about the contribution process and package design.
+
+ipyniivue uses `the reccomended `__ hatchling build-system, which is convenient to use via the `hatch CLI `__. We recommend installing hatch globally (e.g., via pipx) and running the various commands defined within pyproject.toml. hatch will take care of creating and synchronizing a virtual environment with all dependencies defined in pyproject.toml.
+
+Install Pre-Commit hooks
+^^^^^^^^^^^^^^^^^^^^^^^^
+We use `pre-commit `__ to run code checks and clear
+notebook outputs before committing changes. To install the pre-commit hooks,
+run the following command:
+
+.. code-block:: console
+
+ $ pre-commit install
+
+As a result, the hooks will automatically check and fix some issues before
+pushing with git. If changes are made after committing with git, you will need
+to commit again afterwords. Alternatively, you can just run the following
+command beforehand:
+
+.. code-block:: console
+
+ $ nb-clean clean --remove-empty-cells
+
+Command Cheatsheat
+^^^^^^^^^^^^^^^^^^
+All commands are run from the root of the project, from a terminal:
+
++--------------------+-----------------------------------+
+| Command | Action |
++====================+===================================+
+| $ hatch run format | Format project with ruff format . |
+| | and apply linting with ruff --fix |
++--------------------+-----------------------------------+
+| $ hatch run lint | Lint project with ruff check . |
++--------------------+-----------------------------------+
+| $ hatch run test | Run unit tests with pytest |
++--------------------+-----------------------------------+
+
+Alternatively, you can develop ipyniivue by manually creating a virtual environment and managing installation and dependencies with pip.
+
+.. code-block:: console
+
+ python3 -m venv .venv && source .venv/bin/activate
+ pip install -e ".[dev]"
+
+Making Changes to the JavaScript Code
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This is an `anywidget `__ project, which means the code base is hybrid Python and JavaScript. The JavaScript part is developed under js/ and uses `esbuild `__ to bundle the code. Any time you make changes to the JavaScript code, you need to rebuild the files under src/ipyniivue/static. This can be done in two ways:
+
+.. code-block:: console
+
+ $ npm run build
+
+which will build the JavaScript code once, or you can start a development server:
+
+.. code-block:: console
+
+ $ npm run dev
+
+which will start a development server that will automatically rebuild the code as you make changes. We recommend the latter approach, as it is more convenient.
+
+Once you have the development server running, you can start the JupyterLab or VS Code to develop the widget. When finished, you can stop the development server with Ctrl+C.
+
+NOTE: In order to have anywidget automatically apply changes as you work, make sure to export ANYWIDGET_HMR=1 environment variable. This can be set directly in a notebook with %env ANYWIDGET_HMR=1 in a cell.
\ No newline at end of file
diff --git a/docs/source/index.rst b/docs/source/index.rst
new file mode 100644
index 0000000..9108d73
--- /dev/null
+++ b/docs/source/index.rst
@@ -0,0 +1,12 @@
+IPyNiiVue Documentation
+=======================
+
+A Jupyter Widget for Niivue based on anywidget.
+
+
+.. toctree::
+ :maxdepth: 4
+ :caption: Contents:
+
+ install
+ contributing
\ No newline at end of file
diff --git a/docs/source/install.rst b/docs/source/install.rst
new file mode 100644
index 0000000..b46b9e8
--- /dev/null
+++ b/docs/source/install.rst
@@ -0,0 +1,23 @@
+Installation
+============
+
+To first install IPyNiiVue and its dependencies, simply run:
+
+.. code-block:: console
+
+ $ pip install ipyniivue
+
+Usage
+^^^^^^
+
+In a Jupyter environment:
+
+.. code-block:: console
+
+ from ipyniivue import NiiVue
+
+ nv = NiiVue()
+ nv.load_volumes([{"path": "images/mni152.nii.gz"}])
+ nv
+
+See the `basic demo `__ to learn more.
\ No newline at end of file