diff --git a/.gitignore b/.gitignore
index f7812b6dd26..0686354bc83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -252,6 +252,7 @@ paket-files/
# JetBrains Rider
.idea/
*.sln.iml
+.editorconfig
# CodeRush
.cr/
@@ -295,3 +296,8 @@ desktop.ini
# Images generated using the MapRenderer
Resources/MapImages
+
+## Docfx stuff
+/Content.Docfx/api/
+/Content.Docfx/*site
+
diff --git a/Content.Docfx/articles/example-article.md b/Content.Docfx/articles/example-article.md
new file mode 100644
index 00000000000..c0478cedea0
--- /dev/null
+++ b/Content.Docfx/articles/example-article.md
@@ -0,0 +1 @@
+# Add your introductions here!
diff --git a/Content.Docfx/articles/toc.yml b/Content.Docfx/articles/toc.yml
new file mode 100644
index 00000000000..d37668b95ad
--- /dev/null
+++ b/Content.Docfx/articles/toc.yml
@@ -0,0 +1,2 @@
+- name: Example-article
+ href: example-article.md
diff --git a/Content.Docfx/docfx.json b/Content.Docfx/docfx.json
new file mode 100644
index 00000000000..b5ca8035ee2
--- /dev/null
+++ b/Content.Docfx/docfx.json
@@ -0,0 +1,134 @@
+{
+ "metadata": [
+ {
+ "src":
+ [
+ {
+ "files": [
+ "**.csproj"
+ ],
+ "exclude": [
+ "**/bin/**",
+ "**/obj/**",
+ "_site/**",
+ "**.xaml"
+ ],
+ "src": "../Content.Client"
+ }
+ ],
+ "disableGitFeatures": false,
+ "disableDefaultFilter": false,
+ "dest": "api/Content.Client"
+ },
+ {
+ "src":
+ [
+ {
+ "files": [
+ "**.csproj"
+ ],
+ "exclude": [
+ "**/bin/**",
+ "**/obj/**",
+ "_site/**",
+ "**.xaml"
+ ],
+ "src": "../Content.Server"
+ }
+ ],
+ "disableGitFeatures": false,
+ "disableDefaultFilter": false,
+ "dest": "api/Content.Server"
+ },
+ {
+ "src":
+ [
+ {
+ "files": [
+ "**.csproj"
+ ],
+ "exclude": [
+ "**/bin/**",
+ "**/obj/**",
+ "_site/**",
+ "**.xaml"
+ ],
+ "src": "../Content.Shared"
+ }
+ ],
+ "disableGitFeatures": false,
+ "disableDefaultFilter": false,
+ "dest": "api/Content.Shared"
+ },
+ {
+ "src":
+ [
+ {
+ "files": [
+ "**.csproj"
+ ],
+ "exclude": [
+ "**/bin/**",
+ "**/obj/**",
+ "_site/**",
+ "**.xaml"
+ ],
+ "src": "../Content.Tests"
+ }
+ ],
+ "disableGitFeatures": false,
+ "disableDefaultFilter": false,
+ "dest": "api/Content.Tests"
+ }
+ ],
+ "build": {
+ "content": [
+ {
+ "files": [
+ "api/**/**.yml"
+ ]
+ },
+ {
+ "files": [
+ "articles/**.md",
+ "articles/**/toc.yml",
+ "toc.yml",
+ "*.md"
+ ]
+ }
+ ],
+ "resource": [
+ {
+ "files": [
+ "images/**",
+ "favicon.ico",
+ "icon.svg"
+ ]
+ }
+ ],
+ "overwrite": [
+ {
+ "files": [
+ "apidoc/**.md"
+ ],
+ "exclude": [
+ "obj/**",
+ "_site/**"
+ ]
+ }
+ ],
+ "dest": "_content-site",
+ "globalMetadataFiles": [],
+ "fileMetadataFiles": [],
+ "template": [
+ "default",
+ "templates/darkfx"
+ ],
+ "postProcessors": [],
+ "markdownEngineName": "markdig",
+ "noLangKeyword": false,
+ "keepFileLink": false,
+ "cleanupCacheHistory": false,
+ "disableGitFeatures": false
+ }
+}
\ No newline at end of file
diff --git a/Content.Docfx/index.md b/Content.Docfx/index.md
new file mode 100644
index 00000000000..7291f49e258
--- /dev/null
+++ b/Content.Docfx/index.md
@@ -0,0 +1,9 @@
+# Space Station 14 DocFX
+
+
+## Welcome to the Space Station 14 DocFX instance.
+### Click one of the tabs above to see documentation for that particular project/namespace
+
+## Links
+
+[Website](https://spacestation14.io/) | [Discord](https://discord.gg/t2jac3p) | [Forum](https://forum.spacestation14.io/) | [Steam](https://store.steampowered.com/app/1255460/Space_Station_14/) | [Standalone Download](https://spacestation14.io/about/nightlies/)
\ No newline at end of file
diff --git a/Content.Docfx/templates/darkfx/LICENSE.txt b/Content.Docfx/templates/darkfx/LICENSE.txt
new file mode 100644
index 00000000000..f6e12fca04f
--- /dev/null
+++ b/Content.Docfx/templates/darkfx/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Steffen Wilke
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/Content.Docfx/templates/darkfx/partials/affix.tmpl.partial b/Content.Docfx/templates/darkfx/partials/affix.tmpl.partial
new file mode 100644
index 00000000000..11caeb3d05d
--- /dev/null
+++ b/Content.Docfx/templates/darkfx/partials/affix.tmpl.partial
@@ -0,0 +1,40 @@
+{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
+
+
+
+ {{^_disableContribution}}
+
+ {{/_disableContribution}}
+
+
+ ☀
+
+
+
+ ☾
+
+
+
+
+
+
diff --git a/Content.Docfx/templates/darkfx/partials/footer.tmpl.partial b/Content.Docfx/templates/darkfx/partials/footer.tmpl.partial
new file mode 100644
index 00000000000..a9da7c3bb48
--- /dev/null
+++ b/Content.Docfx/templates/darkfx/partials/footer.tmpl.partial
@@ -0,0 +1,29 @@
+{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
+
+
\ No newline at end of file
diff --git a/Content.Docfx/templates/darkfx/partials/head.tmpl.partial b/Content.Docfx/templates/darkfx/partials/head.tmpl.partial
new file mode 100644
index 00000000000..83fc5f91a8e
--- /dev/null
+++ b/Content.Docfx/templates/darkfx/partials/head.tmpl.partial
@@ -0,0 +1,20 @@
+{{!Copyright (c) Oscar Vasquez. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
+
+
+
+
+ {{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}
+
+
+
+ {{#_description}}{{/_description}}
+
+
+
+
+
+
+ {{#_noindex}}{{/_noindex}}
+ {{#_enableSearch}}{{/_enableSearch}}
+ {{#_enableNewTab}}{{/_enableNewTab}}
+
\ No newline at end of file
diff --git a/Content.Docfx/templates/darkfx/styles/main.css b/Content.Docfx/templates/darkfx/styles/main.css
new file mode 100644
index 00000000000..078adc776a7
--- /dev/null
+++ b/Content.Docfx/templates/darkfx/styles/main.css
@@ -0,0 +1,470 @@
+:root, body.dark-theme {
+ --color-foreground: #ccd5dc;
+ --color-navbar: #66666d;
+ --color-breadcrumb: #999;
+ --color-underline: #ddd;
+ --color-toc-hover: #fff;
+ --color-background: #2d2d30;
+ --color-background-subnav: #333337;
+ --color-background-dark: #1e1e1e;
+ --color-background-table-alt: #212123;
+ --color-background-quote: #69696e;
+}
+
+body.light-theme {
+ --color-foreground: #171717;
+ --color-breadcrumb: #4a4a4a;
+ --color-toc-hover: #4c4c4c;
+ --color-background: #ffffff;
+ --color-background-subnav: #f5f5f5;
+ --color-background-dark: #ddd;
+ --color-background-table-alt: #f9f9f9;
+}
+
+body {
+ color: var(--color-foreground);
+ line-height: 1.5;
+ font-size: 14px;
+ -ms-text-size-adjust: 100%;
+ -webkit-text-size-adjust: 100%;
+ word-wrap: break-word;
+ background-color: var(--color-background);
+}
+
+.btn.focus, .btn:focus, .btn:hover {
+ color: var(--color-foreground);
+}
+
+h1 {
+ font-weight: 600;
+ font-size: 32px;
+}
+
+h2 {
+ font-weight: 600;
+ font-size: 24px;
+ line-height: 1.8;
+}
+
+h3 {
+ font-weight: 600;
+ font-size: 20px;
+ line-height: 1.8;
+}
+
+h5 {
+ font-size: 14px;
+ padding: 10px 0px;
+}
+
+article h1, article h2, article h3, article h4 {
+ margin-top: 35px;
+ margin-bottom: 15px;
+}
+
+article h4 {
+ padding-bottom: 8px;
+ border-bottom: 2px solid var(--color-underline);
+}
+
+.navbar-brand>img {
+ color: var(--color-background);
+}
+
+.navbar {
+ border: none;
+}
+
+.subnav {
+ border-top: 1px solid var(--color-underline);
+ background-color: var(--color-background-subnav);
+}
+
+.sidenav, .fixed_header, .toc {
+ background-color: var(--color-background);
+}
+
+.navbar-inverse {
+ background-color: var(--color-background-dark);
+ z-index: 100;
+}
+
+.navbar-inverse .navbar-nav>li>a, .navbar-inverse .navbar-text {
+ color: var(--color-navbar);
+ background-color: var(--color-background-dark);
+ border-bottom: 3px solid transparent;
+ padding-bottom: 12px;
+}
+
+.navbar-inverse .navbar-nav>li>a:focus, .navbar-inverse .navbar-nav>li>a:hover {
+ color: var(--color-foreground);
+ background-color: var(--color-background-dark);
+ border-bottom: 3px solid var(--color-background-subnav);
+ transition: all ease 0.25s;
+}
+
+.navbar-inverse .navbar-nav>.active>a, .navbar-inverse .navbar-nav>.active>a:focus, .navbar-inverse .navbar-nav>.active>a:hover {
+ color: var(--color-foreground);
+ background-color: var(--color-background-dark);
+ border-bottom: 3px solid var(--color-foreground);
+ transition: all ease 0.25s;
+}
+
+.navbar-form .form-control {
+ border: none;
+ border-radius: 0;
+}
+
+.light-theme .navbar-brand svg {
+ filter: brightness(20%);
+}
+
+.toc .level1>li {
+ font-weight: 400;
+}
+
+.toc .nav>li>a {
+ color: var(--color-foreground);
+}
+
+.sidefilter {
+ background-color: var(--color-background);
+ border-left: none;
+ border-right: none;
+}
+
+.sidefilter {
+ background-color: var(--color-background);
+ border-left: none;
+ border-right: none;
+}
+
+.toc-filter {
+ padding: 10px;
+ margin: 0;
+ background-color: var(--color-background);
+}
+
+.toc-filter>input {
+ border: none;
+ border-radius: unset;
+ background-color: var(--color-background-subnav);
+ padding: 5px 0 5px 20px;
+ font-size: 90%
+}
+
+.toc-filter>.clear-icon {
+ position: absolute;
+ top: 17px;
+ right: 15px;
+}
+
+.toc-filter>input:focus {
+ color: var(--color-foreground);
+ transition: all ease 0.25s;
+}
+
+.toc-filter>.filter-icon {
+ display: none;
+}
+
+.sidetoc>.toc {
+ background-color: var(--color-background);
+ overflow-x: hidden;
+}
+
+.sidetoc {
+ background-color: var(--color-background);
+ border: none;
+}
+
+.alert {
+ background-color: inherit;
+ border: none;
+ padding: 10px 0;
+ border-radius: 0;
+}
+
+.alert>p {
+ margin-bottom: 0;
+ padding: 5px 10px;
+ border-bottom: 1px solid;
+ background-color: var(--color-background-dark);
+}
+
+.alert>h5 {
+ padding: 10px 15px;
+ margin-top: 0;
+ margin-bottom: 0;
+ text-transform: uppercase;
+ font-weight: bold;
+ border-top: 2px solid;
+ background-color: var(--color-background-dark);
+ border-radius: none;
+}
+
+.alert>ul {
+ margin-bottom: 0;
+ padding: 5px 40px;
+}
+
+.alert-info {
+ color: #1976d2;
+}
+
+.alert-warning {
+ color: #f57f17;
+}
+
+.alert-danger {
+ color: #d32f2f;
+}
+
+pre {
+ padding: 9.5px;
+ margin: 0 0 10px;
+ font-size: 13px;
+ word-break: break-all;
+ word-wrap: break-word;
+ background-color: var(--color-background-dark);
+ border-radius: 0;
+ border: none;
+}
+
+code {
+ background: var(--color-background-dark) !important;
+ border-radius: 2px;
+}
+
+.hljs {
+ color: var(--color-foreground);
+}
+
+.toc .nav>li.active>.expand-stub::before, .toc .nav>li.in>.expand-stub::before, .toc .nav>li.in.active>.expand-stub::before, .toc .nav>li.filtered>.expand-stub::before {
+ content: "▾";
+}
+
+.toc .nav>li>.expand-stub::before, .toc .nav>li.active>.expand-stub::before {
+ content: "▸";
+}
+
+.affix ul ul>li>a:before {
+ content: "|";
+}
+
+.breadcrumb {
+ background-color: var(--color-background-subnav);
+}
+
+.breadcrumb .label.label-primary {
+ background: #444;
+ border-radius: 0;
+ font-weight: normal;
+ font-size: 100%;
+}
+
+#breadcrumb .breadcrumb>li a {
+ border-radius: 0;
+ font-weight: normal;
+ font-size: 85%;
+ display: inline;
+ padding: 0 .6em 0;
+ line-height: 1;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ color: var(--color-breadcrumb);
+}
+
+#breadcrumb .breadcrumb>li a:hover {
+ color: var(--color-foreground);
+ transition: all ease 0.25s;
+}
+
+.breadcrumb>li+li:before {
+ content: "⯈";
+ font-size: 75%;
+ color: var(--color-background-dark);
+ padding: 0;
+}
+
+.light-theme .breadcrumb>li+li:before {
+ color: var(--color-foreground)
+ }
+
+.toc .level1>li {
+ font-weight: 600;
+ font-size: 130%;
+ padding-left: 5px;
+}
+
+.footer {
+ border-top: none;
+ background-color: var(--color-background-dark);
+ padding: 15px 0;
+ font-size: 90%;
+}
+
+.toc .nav>li>a:hover, .toc .nav>li>a:focus {
+ color: var(--color-toc-hover);
+ transition: all ease 0.1s;
+}
+
+.form-control {
+ background-color: var(--color-background-subnav);
+ border: none;
+ border-radius: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+.form-control:focus {
+ border-color: #66afe9;
+ outline: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+input#search-query:focus {
+ color: var(--color-foreground);
+}
+
+.table-bordered, .table-bordered>tbody>tr>td, .table-bordered>tbody>tr>th, .table-bordered>tfoot>tr>td, .table-bordered>tfoot>tr>th, .table-bordered>thead>tr>td, .table-bordered>thead>tr>th {
+ border: 1px solid var(--color-background-dark);
+}
+
+.table-striped>tbody>tr:nth-of-type(odd) {
+ background-color: var(--color-background-table-alt);
+}
+
+blockquote {
+ padding: 10px 20px;
+ margin: 0 0 10px;
+ font-size: 110%;
+ border-left: 5px solid var(--color-background-quote);
+ color: var(--color-background-quote);
+}
+
+.pagination>.disabled>a, .pagination>.disabled>a:focus, .pagination>.disabled>a:hover, .pagination>.disabled>span, .pagination>.disabled>span:focus, .pagination>.disabled>span:hover {
+ background-color: var(--color-background-subnav);
+ border-color: var(--color-background-subnav);
+}
+
+.breadcrumb>li, .pagination {
+ display: inline;
+}
+
+.tabGroup a[role="tab"] {
+ border-bottom: 2px solid var(--color-background-dark);
+}
+
+.tabGroup a[role="tab"][aria-selected="true"] {
+ color: var(--color-foreground);
+}
+
+.tabGroup section[role="tabpanel"] {
+ border: 1px solid var(--color-background-dark);
+}
+
+.sideaffix > div.contribution > ul > li > a.contribution-link:hover {
+ background-color: var(--color-background);
+}
+
+.switch {
+ position: relative;
+ display: inline-block;
+ width: 40px;
+ height: 20px;
+}
+
+.switch input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+
+.slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #ccc;
+ -webkit-transition: .4s;
+ transition: .4s;
+}
+
+.slider:before {
+ position: absolute;
+ content: "";
+ height: 14px;
+ width: 14px;
+ left: 4px;
+ bottom: 3px;
+ background-color: white;
+ -webkit-transition: .4s;
+ transition: .4s;
+}
+
+input:checked + .slider {
+ background-color: #337ab7;
+}
+
+input:focus + .slider {
+ box-shadow: 0 0 1px #337ab7;
+}
+
+input:checked + .slider:before {
+ -webkit-transform: translateX(19px);
+ -ms-transform: translateX(19px);
+ transform: translateX(19px);
+}
+
+/* Rounded sliders */
+.slider.round {
+ border-radius: 20px;
+}
+
+.slider.round:before {
+ border-radius: 50%;
+}
+.toggle-mode .icon {
+ display: inline-block;
+}
+
+.toggle-mode .icon i {
+ font-style: normal;
+ font-size: 17px;
+ display: inline-block;
+ padding-right: 7px;
+ padding-left: 7px;
+ vertical-align: middle;
+}
+
+@media (min-width: 1600px) {
+ .container {
+ width: 100%;
+ }
+ .sidefilter {
+ width: 18%;
+ }
+ .sidetoc {
+ width: 18%;
+ }
+ .article.grid-right {
+ margin-left: 19%;
+ }
+ .sideaffix {
+ width: 11.5%;
+ }
+ .affix ul>li.active>a {
+ white-space: initial;
+ }
+ .affix ul>li>a {
+ width: 99%;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+}
\ No newline at end of file
diff --git a/Content.Docfx/templates/darkfx/styles/toggle-theme.js b/Content.Docfx/templates/darkfx/styles/toggle-theme.js
new file mode 100644
index 00000000000..f2ea5f5fd71
--- /dev/null
+++ b/Content.Docfx/templates/darkfx/styles/toggle-theme.js
@@ -0,0 +1,35 @@
+const sw = document.getElementById("switch-style"), sw_mobile = document.getElementById("switch-style-m"), b = document.body;
+if (b) {
+ function toggleTheme(target, dark) {
+ target.classList.toggle("dark-theme", dark)
+ target.classList.toggle("light-theme", !dark)
+ }
+
+ function switchEventListener() {
+ toggleTheme(b, this.checked);
+ if (window.localStorage) {
+ this.checked ? localStorage.setItem("theme", "dark-theme") : localStorage.setItem("theme", "light-theme")
+ }
+ }
+
+ var isDarkTheme = !window.localStorage || !window.localStorage.getItem("theme") || window.localStorage && localStorage.getItem("theme") === "dark-theme";
+
+ if(sw && sw_mobile){
+ sw.checked = isDarkTheme;
+ sw_mobile.checked = isDarkTheme;
+
+ sw.addEventListener("change", switchEventListener);
+ sw_mobile.addEventListener("change", switchEventListener);
+
+ // sync state between switches
+ sw.addEventListener("change", function() {
+ sw_mobile.checked = this.checked;
+ });
+
+ sw_mobile.addEventListener("change", function() {
+ sw.checked = this.checked;
+ });
+ }
+
+ toggleTheme(b, isDarkTheme);
+}
\ No newline at end of file
diff --git a/Content.Docfx/toc.yml b/Content.Docfx/toc.yml
new file mode 100644
index 00000000000..2e1b1d638a5
--- /dev/null
+++ b/Content.Docfx/toc.yml
@@ -0,0 +1,18 @@
+- name: Articles
+ href: articles/
+
+# Client
+- name: Content.Client
+ href: api/Robust.Client/
+
+# Server
+- name: Content.Server
+ href: api/Content.Server/
+
+# Shared
+- name: Content.Shared
+ href: api/Content.Shared/
+
+# Unit testing
+- name: Content.Tests
+ href: api/Content.Tests/
\ No newline at end of file