Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions assets/readme/manipulation.mp4
Git LFS file not shown
3 changes: 3 additions & 0 deletions assets/readme/teleop.mp4
Git LFS file not shown
85 changes: 85 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Welcome to dimOS

**dimOS** is an open source operating system for generalist robotics, built by Dimensional. Write one Python program and run it on a quadruped, a humanoid, a drone, or an arm.

dimOS is also agent native. Every skill a robot exposes is also an MCP tool. An LLM coding agent can discover those tools and call them directly.

## The problem

Every robot ships its own SDK and the code written for one rarely survives the move to another. ROS is the usual way out, but you take on its build system and its runtime whole, before writing any behaviour of your own. Most of it also needs the hardware, so your work waits on a robot that is shared, remote, or still in a box.

## How dimOS solves it

- **Behaviour lives in modules, not in an SDK.** A module does one job. It declares the streams it needs as typed fields, so a module written for a quadruped runs on an arm once something publishes what it asked for.

- **No workspace to build.** dimOS installs with pip on your laptop and reaches the robot over the network. Streams travel over LCM, shared memory, DDS, Zenoh, or ROS 2. You pick the transport per stream, and ROS is one option rather than the foundation.

- **Nothing waits on hardware.** The same blueprint runs against a recorded session or in MuJoCo before it runs on a robot. The behaviour you debug is the behaviour that ships.

- **Agents are modules too.** An LLM subscribes to the same streams your control loops use. It calls the same skills, and it takes its instructions in plain language.

<div class="grid cards dim-cta" markdown>

- :material-rocket-launch: **[Quickstart](/docs/quickstart.md)**

Install dimOS and replay a real robot session on your laptop in a few minutes. No robot needed.

</div>

## Capabilities

Real robots, running dimOS.

<div class="grid cards dim-media" markdown>

- [![Navigation and mapping](/assets/readme/navigation.gif)](https://x.com/stash_pomichter/status/2010471593806545367)

**[Navigation and mapping](/docs/capabilities/navigation/index.md)**

SLAM, dynamic obstacle avoidance, route planning, and autonomous exploration.

- [![Agentic control](/assets/readme/agentic_control.gif)](https://x.com/stash_pomichter/status/2015912688854200322)

**[Agentic control and MCP](/docs/capabilities/agents/index.md)**

Talk to the robot. Every skill is also exposed as an MCP tool.

- [![Spatial memory](/assets/readme/spatial_memory.gif)](https://x.com/stash_pomichter/status/1980741077205414328)

**[Spatial memory](/docs/capabilities/memory/index.md)**

Spatio-temporal RAG, object localization, and permanence. Navigate back to what the robot saw.

- <a href="https://x.com/dimensionalos/status/2077476353960722507"><video src="/assets/readme/teleop.mp4" autoplay loop muted playsinline preload="metadata" aria-label="dimTELE: remote control any robot from anywhere in the world"></video></a>

**[Remote teleoperation](/docs/capabilities/teleoperation/hosted.md)**

**dimTELE** gives you remote control of any robot, from anywhere in the world, at ultra-low latency.

- [![Perception](/assets/readme/perception.png)](/docs/capabilities/perception/index.md)

**[Perception](/docs/capabilities/perception/index.md)**

Detect objects in camera, place them in 3D, with VLMs and audio built in.

- <a href="https://x.com/swstica/status/2092438167618261161"><video src="/assets/readme/manipulation.mp4" autoplay loop muted playsinline preload="metadata" aria-label="A robot arm scanning a scene, planning a grasp, and dropping a bottle into a container on spoken instruction"></video></a>

**[Manipulation](/docs/capabilities/manipulation/index.md)**

Scan the scene, generate grasp candidates, plan, and execute from a spoken instruction.

</div>

## Start here

<div class="grid cards dim-tiles" markdown>

- :material-rocket-launch: **[Quickstart](/docs/quickstart.md)**

Replay a real robot session on your laptop. No robot needed.

- :material-chip: **[Platforms](/docs/platforms/quadruped/go2/index.md)**

Unitree Go2 and G1 setup, in simulation and on real hardware.

</div>
69 changes: 4 additions & 65 deletions misc/mkdocs/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

THEME_CSS = Path(__file__).with_name("theme.css")
REPO_ROOT = Path(__file__).resolve().parents[2]
README = REPO_ROOT / "README.md"
# The home page's demo gifs, shared with the readme rather than copied.
README_ASSETS = REPO_ROOT / "assets" / "readme"

GITHUB_BLOB = "https://github.com/dimensionalOS/dimos/blob/main"
Expand Down Expand Up @@ -143,75 +143,14 @@ def _rewrite_link(match: re.Match[str], src_uri: str) -> str:
return match.group(0)


def _page_url(path: str) -> str:
"""docs/usage/modules.md -> usage/modules/, the url mkdocs actually builds.

Only needed for raw html attributes: mkdocs rewrites markdown links itself,
but never looks inside an <a href> or an <img src>.
"""
page = re.sub(r"^docs/", "", path).removesuffix(".md")
page = re.sub(r"(^|/)index$", r"\1", page)
return page.rstrip("/") + "/" if page else "."


def _readme_as_home() -> str:
"""The repo README, with its links pointed at the site instead of github."""
text = README.read_text(encoding="utf-8")

# Badges, star counts and the trendshift ribbon are furniture for a repo
# landing page. Here they are a wall of images above the first sentence.
text = re.sub(r"^\[!\[.*img\.shields\.io.*$", "", text, flags=re.M)
text = re.sub(r"^!\[.*img\.shields\.io.*$", "", text, flags=re.M)
text = re.sub(r"^<a href=\"https://trendshift\.io.*$", "", text, flags=re.M)

# A 1px transparent gif forcing a minimum column width is a github table
# hack. Here the cells already carry width="20%", and the spacer only adds
# a line box, plus a lightbox anchor around a blank image.
text = re.sub(r"\s*<img[^>]*spacer\.png[^>]*>", "", text)

# <big> is deprecated, and being an inline tag it re-blocks markdown even
# inside a div that asked for it. Material sizes the banner text anyway.
text = text.replace("<big>", "").replace("</big>", "")

# Github renders markdown inside a raw html block; python-markdown only
# does so when the tag asks for it, which is what md_in_html reads.
# Only on <div>: md_in_html does not treat a <td> as a markdown block, so
# the attribute would survive into the output as a stray one.
text = re.sub(r"<div\b(?![^>]*\bmarkdown=)([^>]*)>", r'<div\1 markdown="1">', text)

# Raw html links into the docs tree, which mkdocs leaves alone.
text = re.sub(
r'(href=")docs/([^"]+\.md)"', lambda m: f'{m.group(1)}{_page_url(m.group(2))}"', text
)
# Raw html links to source, which have no page on the site at all.
text = re.sub(
r'(href=")((?:' + "|".join(SOURCE_ROOTS) + r')/[^"]*)"',
lambda m: f'{m.group(1)}{GITHUB_BLOB}/{m.group(2)}"',
text,
)

# docs/usage/modules.md -> usage/modules.md, since the site root is docs/.
text = re.sub(r"\]\(docs/", "](", text)
# Anything else in the repo is source, and lives on github.
text = re.sub(
r"\]\((AGENTS\.md|CONTRIBUTING\.md|LICENSE|(?:dimos|examples|bin|native|misc|scripts)/[^)#]*)",
lambda m: f"]({GITHUB_BLOB}/{m.group(1)}",
text,
)
# The readme opens with a centred banner rather than a heading, so give the
# page a title for the nav and the browser tab.
return f'---\ntitle: "Welcome to dimOS"\n---\n\n{text}'


def on_files(files, config):
"""Ship the theme and the readme-as-home without adding files to docs/."""
"""Ship the theme and the shared demo assets without adding files to docs/."""
from mkdocs.structure.files import File

files.append(File.generated(config, "assets/mkdocs-theme.css", content=THEME_CSS.read_text()))
files.append(File.generated(config, "index.md", content=_readme_as_home()))

# The readme's screenshots live outside docs/, so pull them in by path
# rather than copying 43MB into the docs tree.
# The home page's screenshots live outside docs/, beside the readme's, so
# pull them in by path rather than copying 43MB into the docs tree.
for asset in sorted(README_ASSETS.glob("*")):
if asset.is_file():
files.append(
Expand Down
140 changes: 137 additions & 3 deletions misc/mkdocs/theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
--dim-radius-sm: 0.375rem;
--dim-radius-lg: 1rem;
--dim-radius-pill: 9999px;
--dim-hairline: color-mix(in srgb, var(--md-default-fg-color) 12%, transparent);
--dim-nav-title: #ffffff;
}

Expand All @@ -36,6 +35,13 @@
--md-code-bg-color: #131923;
--md-footer-bg-color: #0a0e14;
--md-footer-bg-color--dark: #080b10;

/* Hairlines, applied consistently to every raised surface. Declared here
* rather than at :root: material puts the scheme on <body>, so a custom
* property that reads --md-default-fg-color from :root resolves against
* material's light-mode default and freezes to black — invisible on this
* background, and inherited that way by every border on the site. */
--dim-hairline: color-mix(in srgb, var(--md-default-fg-color) 12%, transparent);
}

/* ---------------------------------------------------------------- layout */
Expand All @@ -44,7 +50,7 @@
* nobody can track back from. Sidebars are fixed, so the middle column takes
* every pixel this cap frees up. */
.md-grid {
max-width: min(84rem, 100%);
max-width: min(72rem, 100%);
}

/* Reading measure only applies to prose. Code, tables, and figures keep the
Expand All @@ -53,7 +59,21 @@
.md-typeset > ul,
.md-typeset > ol,
.md-typeset > blockquote {
max-width: 52rem;
max-width: 44rem;
}

/* Once the table of contents is showing there is room to inset the article
* from both sidebars, so the text sits in the middle rather than running up
* against the nav. The rule runs down the article rather than the sidebar,
* because the sidebar is sticky and only as tall as its own scrollwrap. */
@media screen and (min-width: 76.25em) {
.md-content {
border-left: 1px solid var(--dim-hairline);
}

.md-content__inner {
padding-inline: 2.4rem;
}
}

/* A little more room for the nav tree; deep paths like
Expand Down Expand Up @@ -324,6 +344,120 @@
transform: translateY(-2px);
}

/* Six capability cards, three to a row so the grid stays two tidy rows. The
* columns belong on the wrapper: material gives `.grid` the tracks and sets
* the inner ul to display:contents, so a rule on the ul would do nothing. */
.md-typeset .dim-media {
grid-template-columns: repeat(2, 1fr);
}

@media screen and (min-width: 60em) {
.md-typeset .dim-media {
grid-template-columns: repeat(3, 1fr);
}
Comment thread
swstica marked this conversation as resolved.
Comment thread
swstica marked this conversation as resolved.
}

/* Narrower cards want less air and smaller supporting text than material's
* default, or three across turns into three columns of wrapped fragments. */
.md-typeset .grid.cards.dim-media > ul > li {
--dim-card-pad: 0.6rem;
padding: var(--dim-card-pad);
}

.md-typeset .dim-media > ul > li > p + p {
font-size: 0.72rem;
color: var(--md-default-fg-color--light);
}

/* A card that leads with a demo clip: the clip is the card's top edge, so it
* cancels material's card padding and takes the card's own corners. */
.md-typeset .grid.cards > ul > li {
--dim-card-pad: 0.8rem;
}

.md-typeset .grid.cards > ul > li > p:first-child:has(> a > :is(img, video)) {
margin: calc(-1 * var(--dim-card-pad)) calc(-1 * var(--dim-card-pad)) 0.7rem;
}

/* The clips are captured at whatever the source window was — 1:1, 16:10, 16:9 —
* so crop to one ratio rather than let each card set its own height. */
.md-typeset .grid.cards > ul > li > p:first-child > a > :is(img, video) {
display: block;
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
border-radius: var(--dim-radius) var(--dim-radius) 0 0;
}

/* ----------------------------------------------------------------- home */

/* One wide signpost rather than a row of them: a single full-width card with
* the icon floated beside the link and the line under it. */
.md-typeset .dim-cta {
grid-template-columns: 1fr;
}

.md-typeset .grid.cards.dim-cta > ul > li {
padding: 1.1rem 1.3rem;
}

/* Floated so the summary wraps beside the icon too, not just the title. */
.md-typeset .dim-cta .twemoji {
float: left;
width: 1.7em;
height: 1.7em;
margin: 0.1rem 0.9rem 0 0;
color: var(--md-accent-fg-color);
}

.md-typeset .dim-cta .twemoji svg {
width: 100%;
height: 100%;
}

.md-typeset .dim-cta > ul > li > p + p {
margin-top: 0.1rem;
color: var(--md-default-fg-color--light);
}

/* The capability grid above carries a clip per card, so the two calls to
* action need to read as a different kind of card rather than a third row of
* the same one: filled surface, no outline, icon promoted above the link. */
/* These two are the end of the page, so they get room rather than being the
* tightest cards on it: a floor on the height, and the content centred in
* whatever height wins. */
.md-typeset .grid.cards.dim-tiles > ul > li {
display: flex;
flex-direction: column;
justify-content: center;
min-height: 9rem;
background: var(--md-default-bg-color--light);
border-color: transparent;
padding: 1.6rem;
}

.md-typeset .grid.cards.dim-tiles > ul > li:hover {
border-color: transparent;
background: color-mix(in srgb, var(--md-accent-fg-color) 8%, var(--md-default-bg-color--light));
}

.md-typeset .dim-tiles .twemoji {
display: block;
margin-bottom: 0.5rem;
color: var(--md-accent-fg-color);
}

.md-typeset .dim-tiles .twemoji svg {
width: 1.4em;
height: 1.4em;
}

/* The summary is supporting text here, not body copy. */
.md-typeset .dim-tiles > ul > li > p + p {
font-size: 0.72rem;
color: var(--md-default-fg-color--light);
}

/* --------------------------------------------------------------- footer */

.md-footer {
Expand Down
Loading