Contributing to the Docs

Thank you for wanting to help us make the docs better. Every contribution is appreciated.

Goals

The Viam documentation aims to:

  • Educate users (explain concepts, provide an overview of what is possible)
  • Help users accomplish tasks (performing an action, building a thing)

We do that by providing concise and well-structured documentation to users. When users stumble, we provide avenues for feedback, so we can take action and prevent other users from running into similar issues.

Voice

We aim to be friendly but not colloquial, direct, and concise.

Here are a few additional pointers:

SubjectJudgment
Emoji ✨No
Exclamation marksUse sparingly
Rhetorical questionsNo

Audience

We write for a technical audience that spans from entry-level to expert. However, common tools and concepts such as version control, moving files with ssh, JSON are beyond the scope of our docs. To make the content as accessible as possible we will, where possible, include actions to be taken and text that guides the user as to what they are achieving when performing these actions.

For example, when copying a file to another machine with ssh, we would describe the action with words like “Use ssh to move the file onto the other machine” alongside the command to move the file. Explaining ssh goes beyond the scope of our docs. Where needed, we will link to supporting documentation but not provide supporting documentation ourselves where it would duplicate existing external documentation. Use your judgment to determine when we need to explain more and when we need to link to supporting content. When in doubt, ask during review.

Project structure

All documentation is in the docs folder. For information about Hugo and how to develop locally, see the README.

Content types

When creating a new piece of content, decide which one of the four content types the content should be. Note this in a comment in the front matter of the file.

The docs use the Diátaxis Framework as the basis of the content structure with the following four content types:

  • Explanation (conceptual): An understanding-oriented piece of content. This content provides background knowledge on a topic and tends to be referenced in how-to guides and tutorials. For example the viam-server page or the Registry page. It’s useful to have a real or imagined “Why?” question to serve as a prompt.

    Click to view template
    # Concept
    
    Introductory paragraph.
    Possibly containing further subsections or links to relevant conceptual information.
    
    ## Subconcept
    
    Paragraphs containing explanation. Add imagery as needed.
    
    - Provide context and address potential points of confusion. - Add real or hypothetical examples.
    
    Possibly more Subconcept sections.
    
    ### Do x with subconcept (optional)
    
    Information on potential ways to apply the concept (possibly linking to how-tos or containing how-tos).
    
    ## Next steps
    
    Links to related content.
    
  • How-to Guide (procedural): A task-oriented piece of content that directs a reader to perform actions step by step to complete a task, like instructions to sauté onions. Generally starts with a description of the task and things to consider, and then provides a set of numbered steps to follow. For example, the Installation page or the Find module page.

    Click to view template
    # Do This Task
    
    Description of task and considerations. Possibly containing further subsections.
    
    ## Do x
    
    1. Ordered list of actions to perform. Written in imperative form. Add imagery as needed.
    
    (possibly more Do X sections)
    
    ## Next steps
    
    Links to related content.
    
  • Tutorial: A learning-oriented piece of content that functions as a lesson for the reader. A tutorial helps readers to learn and apply skills by doing something meaningful and attainable, like a recipe to cook a full meal.

    Click to view template
    # Do X with Y
    
    Outline the why.
    Tell the story of the machine.
    Explain the machine's use and origin.
    
    ## Requirements
    
    What does the reader need to already know.
    What will you be using (hardware/software).
    
    ## Build X
    
    Build steps.
    
    ## Configure your X
    
    Configuration steps.
    
    ## Program your X
    
    Code and directions.
    
    ## Next steps
    
    Link to other tutorials with cards or text.
    
    
    

    For the full template see template.md.

  • Reference: A concise, information-oriented piece of content that generally starts with an overview/introduction and then a list of some kind (configuration options, API methods, etc.). Examples include the API pages as well as component and service pages.

    Example template: Component template.

    Click to view template
    # Product, Feature or API Name
    
    Description or introduction.
    Possibly containing further subsections.
    
    ## List or table of items (heading optional as needed)
    
    - Unordered list of options
    
    (possibly more information for each option)
    
    ## Next steps
    
    Links to related content.
    

Style guide

All docs are written in Hugo Markdown. Most Markdown formatting is supported. For a brief introduction to Markdown, check out this Markdown Cheatsheet. Some additional formatting options are supported with Hugo Shortcodes.

We follow the Rackspace Style Guide with many rules encoded in Vale rules.

Additional we enforce the following substitutions:

Do not sayInstead say
web app, cloud appViam app or Viam platform
viam app, Viam AppViam app
Viam-server, Viam server, Viam-Serverviam-server
Config Tab, Config tab, Configure TabCONFIGURE tab
Vision service, Vision Servicevision service
Motion service, Motion Servicemotion service
slam service, Slam service, SLAM ServiceSLAM service
Data Management Service, Data Management servicedata management service
in the websiteon the website
on the appin the app
user of an orgmember of an org
main part and child part, main part and non-main partmain part and sub-part
subpartsub-part
drop downdropdown
drop-downdropdown
RPLIDAR, RplidarRPlidar
compute partscomputer
microprocessorRaspberry Pi or Jetson or another specific term

Vale linting

When you open a PR, your changes will be checked against a few style rules. To run this check locally, follow the instructions in the Vale Readme.

markdownlint

We recommend you work in Visual Studio Code and install the markdownlint extension.

UI elements

Use bold text for UI elements, such as tabs and buttons.

Example values

Use examples that resemble real data. For emails this could be amanda@viam.com.

When using placeholders in code examples, follow the Google developer documentation style guide’s rules for formatting placeholders.

Images and screenshots

Use screenshots in introductory materials and where the surrounding text is not enough to direct the reader. Be aware that screenshots tend to get outdated quickly and come with a maintenance burden.

Rules for images:

  • Place images in the assets folder. The folder uses the same content structure as the docs. Your images should be in the folder the page that uses it is in. However, there is no need to duplicate an image into multiple places if you use it in multiple pages.
  • All images require alt text.
  • All images should be smaller than 1MB. Hugo throws a warning during local builds (such as make serve-prod) if an image exceeds this size. Use an image compressor like TinyPNG. This is to reduce the overall page and repo size.

Remove EXIF data automatically

Image markup

If the image is supposed to take up the full width of the page use the regular markdown syntax: ![alt text](path).

![Raspberry Pi](/installation/thumbnails/raspberry-pi-4-b-2gb.png)

If the image is smaller use the imgproc shortcode with an appropriate resize value.

<!-- Remove space between curly braces -->

{ {<imgproc src="PATH/TO/IMAGE.png" resize="300x" declaredimensions=true alt="ALT">} }

{ {<imgproc src="/installation/thumbnails/raspberry-pi-4-b-2gb.png" resize="x60" declaredimensions=true alt="Raspberry Pi">} }

{ {<imgproc src="/installation/thumbnails/raspberry-pi-4-b-2gb.png" resize="x200" declaredimensions=true alt="Raspberry Pi">} }

Raspberry Pi

Raspberry Pi Raspberry Pi

The imgproc shortcode will:

  • convert the image into the webp format (which is more efficient) and resize the image
  • resize the image in the current format and set that image as a backup in case webp is not supported. This does reduce file size when the website is being served. However, the source file should still be smaller than 1MB to minimize overall page and repo size. For more information on the resize options see Image Processing.

Only specify declaredimensions if the image is not responsive (if it doesn’t resize). The only images that you’d want to use declaredimensions on are the ones that take up the same space on mobile as on desktop.

An example of this are the small board icons on the front page which should never be a different size than they are. The pictures in cards, however, need to resize because they change size based on the available screen space.

Screenshot should most often be added with normal markdown syntax. Then they’ll take up the max size they can on a big screen but be smaller on mobile. If you want to resize a large image, use the largest size the image can take up as the image to resize the image to.

GIFs and videos

We encourage the use of GIFs and Videos. Our docs have two kinds of videos:

  • Regular videos with video controls and audio
  • GIF-like videos that do not have video controls or audio and function like GIFs

Regular videos

For regular videos that should use the video shortcode as follows:

<!-- remove space -->

{ {<video webm_src="/heart.webm" mp4_src="/heart.mp4" alt="A robot drawing a heart" poster="/general/heart.jpg">} }

We use webm and mp4 source files for videos because they are generally smaller. The poster is an image that gets loaded as a preview.

Click to see the commands for converting videos to these formats

To create the webm and mp4 files use these commands:

ffmpeg -i PATH_TO_GIF_OR_VID -vcodec libx264 -vf "format=yuv420p,scale=720:-2" -b:v 300k PATH_TO_GIF_OR_VID.mp4
ffmpeg -i PATH_TO_GIF_OR_VID -c:v libvpx-vp9 -b:v 0 -crf 41 my-animation.webm
ffmpeg -i PATH_TO_GIF_OR_VID -vcodec libx264 -vf "format=yuv420p,scale=720:-2" -b:v 300k PATH_TO_GIF_OR_VID.mp4
ffmpeg -i PATH_TO_GIF_OR_VID -c:v libvpx-vp9 -b:v 0 -crf 41 my-animation.webm

The first command:

  • uses the libx264 codec
  • uses the yuv420p pixel format
  • scales the video to 720px width
  • changes the bitrate to 300k - you can change this value but check that the result is usable and reasonably small

The second command:

  • uses the libvpx-vp9 codec
  • -crf 41 sets the quality level. Valid values are 0-63. Lower numbers are higher quality

To create a preview image use this command:

ffmpeg -ss 00:00:05 -i PATH_TO_GIF_OR_VID.mp4 -frames:v 1 PATH_TO_GIF_OR_VID.jpg
ffmpeg -ss 00:00:05 -i PATH_TO_GIF_OR_VID.mp4 -frames:v 1 PATH_TO_GIF_OR_VID.jpg

The command takes a screenshot at 00:00:05.

GIF-like videos

GIF-like videos on our pages are generally used to show robot actions. We do not use the GIF file format within our docs because it uses a lot of bandwidth - more than videos - and the best practice is to not use them.

Instead, we use a video div with two sources:

<!-- remove space -->

{ {<gif webm_src="/heart.webm" mp4_src="/heart.mp4" alt="A robot drawing a heart">}}

Place the files into the static directory.

Click to see instructions for creating the video files

To create the webm and mp4 source files, you need to convert the video/gif you have. The resulting webm and mp4 file should always be less than 1MB. A good first thing to do is to upload the video to Ezgif and reduce the file size by:

  • cutting the video
  • cropping the video
  • changing the size
  • (on GIFs) changing the quality
  • (on GIFs) using the optimize function to remove every second frame and then adjusting the speed
  • (on GIFs) using the frames editor to remove frames that are similar and holding the previous frame longer instead

Once you have a gif that is reasonably small, run these commands:

ffmpeg -i PATH_TO_GIF_OR_VID -vcodec libx264 -vf "format=yuv420p,scale=400:-2" -b:v 300k -an PATH_TO_GIF_OR_VID.mp4
ffmpeg -i PATH_TO_GIF_OR_VID -c:v libvpx-vp9 -b:v 0 -crf 41 my-animation.webm
ffmpeg -i PATH_TO_GIF_OR_VID -vcodec libx264 -vf "format=yuv420p,scale=400:-2" -b:v 300k -an PATH_TO_GIF_OR_VID.mp4
ffmpeg -i PATH_TO_GIF_OR_VID -c:v libvpx-vp9 -b:v 0 -crf 41 my-animation.webm

The first command:

  • uses the libx264 codec
  • uses the yuv420p pixel format
  • scales the video to 400px width - if you are working with screenshots that need to be bigger, adjust this number.
  • changes the bitrate to 300k - you can change this value but check that the result is usable
  • removes the audiotrack with -an

The second command:

  • uses the libvpx-vp9 codec
  • -crf 41 sets the quality level. Valid values are 0-63. Lower numbers are higher quality
Click to see instructions for creating video commands for your terminal

If you’d like to use commands like webm2mp4 add this to your .zshrc:

function webm2gif() {
vid=$1
ext=${vid##*.}
vdirname=`dirname $vid`
vfname=`basename $vid $ext`
ffmpeg -t 8 -i ${vdirname}/${vfname}webm -vf "fps=5,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 ${vdirname}/${vfname}gif
}

function mp42gif() {
vid=$1
ext=${vid##*.}
vdirname=`dirname $vid`
vfname=`basename $vid $ext`
ffmpeg -t 8 -i ${vdirname}/${vfname}mp4 -vf "fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 ${vdirname}/${vfname}gif
}

function gif2webm() {
vid=$1
ext=${vid##*.}
vdirname=`dirname $vid`
vfname=`basename $vid $ext`
ffmpeg -i ${vdirname}/${vfname}gif -c vp9 -b:v 0 -crf 41 -an ${vdirname}/${vfname}webm
}

function gif2mp4() {
vid=$1
ext=${vid##*.}
vdirname=`dirname $vid`
vfname=`basename $vid $ext`
ffmpeg -i ${vdirname}/${vfname}gif -vcodec libx264 -vf "format=yuv420p,scale=400:-2" -b:v 300k -an ${vdirname}/${vfname}mp4
}

function gif2mp4-withsound() {
vid=$1
ext=${vid##*.}
vdirname=`dirname $vid`
vfname=`basename $vid $ext`
ffmpeg -i ${vdirname}/${vfname}gif -vcodec libx264 -vf "format=yuv420p,scale=-2:720" -b:v 300k ${vdirname}/${vfname}mp4
}

function mp42webm() {
vid=$1
ext=${vid##*.}
vdirname=`dirname $vid`
vfname=`basename $vid $ext`
ffmpeg -i ${vdirname}/${vfname}mp4 -c vp9 -b:v 0 -crf 41 -an ${vdirname}/${vfname}webm
}

function mp42webm-withsound() {
vid=$1
ext=${vid##*.}
vdirname=`dirname $vid`
vfname=`basename $vid $ext`
ffmpeg -i ${vdirname}/${vfname}mp4 -c vp9 -b:v 0 -crf 41 ${vdirname}/${vfname}webm
}

function webm2mp4() {
vid=$1
ext=${vid##*.}
vdirname=`dirname $vid`
vfname=`basename $vid $ext`
ffmpeg -i ${vdirname}/${vfname}webm -vcodec libx264 -vf "format=yuv420p,scale=400:-2" -b:v 300k -an ${vdirname}/${vfname}mp4
}

function webm2mp4-withsound() {
vid=$1
ext=${vid##*.}
vdirname=`dirname $vid`
vfname=`basename $vid $ext`
ffmpeg -i ${vdirname}/${vfname}webm -vcodec libx264 -vf "format=yuv420p,scale=-2:720" -b:v 300k ${vdirname}/${vfname}mp4
}

function mp42jpg {
vid=$1
ext=${vid##*.}
vdirname=`dirname $vid`
vfname=`basename $vid $ext`
ffmpeg -ss 00:00:05 -i ${vdirname}/${vfname}mp4 -frames:v 1 ${vdirname}/${vfname}jpg
}

Formatting guide

Front matter

Each file that generates a page in Hugo starts with front matter that looks like this:

---
title: "Build a line-following robot with only a rover and a webcam"
linkTitle: "Line Follower"
weight: 90
type: "docs"
description: "Instructions for building a line-following robot that uses a webcam to track lines."
# SME: "SME Name"
---
  • The description gets used for previews.
  • The weight determines the ordering of pages in the side navigation bar.

Prod/Draft/Future pages

Add draft: true to the Front Matter to set a page to Draft. You can commit and push the page and it won’t display in production. Add future: true to the Front Matter to begin building a page to production on a certain date (for example, a release date).

File names

File names are kebab-case, with hyphens, such as upload-model.md.

One sentence per line

To make reviews easier, each new sentence should begin on a new line.

Where related resources would be helpful to a reader, link them. However:

  • Links are an opportunity for a reader to get lost or get distracted. If that happens, a link is not helpful. Placing links near the end of a section/page can help avoid this.
  • Avoid a page becoming a sea of blue hyperlinks. Excessive linking can make a page harder to view and read.

When linking to an image or another page within the docs please use relative links (appendix/contributing/) or (/appendix/contributing/).

Glossary

We have built a glossary into our docs. Jargon and product-specific concepts should have an entry in the appendix/glossary folder. You can use a glossary entry on any page like this:

<!-- Remove spaces between curly braces -->

This text will have additional information on hover for the
word { {< glossary_tooltip term_id="smart-machine" text="smart machine" >} }.

Reusable text snippets

If you need to use the same text in multiple locations, for example when cautioning users to disconnect power before changing connections or providing a commonly used instruction set or procedure, you can use reusable snippets.

The following is an example of the secret-share.md alert added using the snippet shortcode:

Figure: Snippet Shortcode Usage
Snippet shortcode usage.

Including another file

This is a Heading in the Sample File

This entire section was added to the current topic using the readfile shortcode.

Heading 2

  • bullet 1
  • bullet 2

Heading 3

This Markdown code:

Markdown Table
| id | name    |
|----|---------|
| 1  | Roberta |
| 2  | Oliver  |
| 3  | Shayna  |
| 4  | Fechin  |

Renders like so:

Markdown Table

idname
1Roberta
2Oliver
3Shayna
4Fechin

This HTML code:

<h3>HTML Table</h3>

<table>
  <tr>
    <th>id</th>
    <th>name</th>
  </tr>
  <tr>
    <td>1</td>
    <td>Roberta</td>
  </tr>
  <tr>
    <td>2</td>
    <td>Oliver</td>
  </tr>
  <tr>
    <td>3</td>
    <td>Shayna</td>
  </tr>
  <tr>
    <td>4</td>
    <td>Fechin</td>
  </tr>
</table>

Renders like so:

HTML Table

idname
1Roberta
2Oliver
3Shayna
4Fechin

This is the last line of the included file.

Section content before this line is contained in an included file: /static/include/sample.md

Tab Panels

Supported

  • Markdown and HTML images
    • Images should be included with the imgproc shortcode. You cannot directly use the <img> html tag for images in the assets folder because the images, once built, are renamed. If you really need to use html directly, place the image in the static folder.
  • Alert Shortcode
  • PRISM syntax highlighting (the three backticks)
  • “codelang” highlighting (add codelang=“language” to tab element). It’s very ugly, needs css work, and is not recommended at this time.

Not supported

  • Footnotes
  • Expanders

Example usage

# remove spaces

{ {<imgproc src="/general/tabbed-panel-markdown.png" resize="300x" declaredimensions=true alt="Screen capture of Tab/Tabs Shortcode Usage" style="border:solid 1px black">} }
Screen capture of Tab/Tabs Shortcode Usage

What is Rendered?

It renders vanilla HTML and markdown, Alerts, and images. For example, these two images:

  • Markdown Image Example
    expand example

  • HTML Image Example (with border)

    Screen capture of Tab/Tabs Shortcode Usage

Code with syntax highlighting

Line numbering is off by default.

{
  "word": "Three backticks and the language name enables Prism syntax highlighting."
}

With just line 6 highlighted. See the prism line highlight extension for more info:

while (True):
    # When True, sets the LED pin to high or on.
    await led.set(True)
    print('LED is on')

    await asyncio.sleep(1)

    # When False, sets the pin to low or off.
    await led.set(False)
    print('LED is off')

    await asyncio.sleep(1)

With linked lines and lines 8-10 highlighted.

while (True):
    # When True, sets the LED pin to high or on.
    await led.set(True)
    print('LED is on')

    await asyncio.sleep(1)

    # When False, sets the pin to low or off.
    await led.set(False)
    print('LED is off')

    await asyncio.sleep(1)

Alert shortcodes

How to use notes, cautions, and warnings

Info/Tip: Use to convey helpful information or clarification. They both use the same color.

Note/Important/Stability Notice: These call attention to something important. When creating alerts about important messages, set the title attribute as title="Important". If you want to include a more detailed title or message, use title="Important: $message" to provide additional context.

Caution: Provide notice that a certain action or event could damage hardware or cause data loss.

Warning: Use to notify the reader of an issue to avoid loss of life, personal injury, and health hazards. Electrical and physical safety fall into this category.

Figure: Shortcodes for Alerts
The shortcodes used to display Alerts.

Using expanders

Expanders allow to you add long sections of code to your topic and hide them until the reader decides to view it.

Within the expander, you can still use most other shortcodes and syntax highlighting from Prism functions properly. The shortcode displays your expander’s title in a light blue bar to make it noticeable.

Screen Capture of an Expander Screen capture of the expander control rendered on a documentation page

Usage

  1. Add the shortcode tags. Make sure that the title is suitable for your use.
  2. Drop in the material you want to hide until the reader wants it.
ALT
Click to view the source

Add the text to hide here.

Prism syntax highlighting works in expanders, as do most other shortcodes.

print("Code snippets work")

Figures

The figure shortcode enhances the existing figure and figurecaption html tags. Figure supports the standard html attributes associated with the html img and figure tags, as well as an attr element for attribution text and attrlink if you wish to add a link to the attribution text.

Figure: Figure Shortcode
The shortcode used to display an image, its caption, and its attribution.

This shortcode places the caption (that is the “title”) above the table. The title is set in 12pt italic with a green underline.

Figure styles the Attribution text as body text.

Footnotes

To add a footnote:

"Some completely[^f] random text."

[^f]: this is the text for the footnote

You can place the footnote text immediately beneath the paragraph where you put the marker. Hugo will place it at the bottom of the page.

Pull requests

If you are making a small change, like fixing a typo or editing a few lines of text, you do not need to create an issue. However, if you plan to make bigger changes, we ask that you create an issue and discuss the change with us in advance.

To get started:

  1. Fork the official repo into your personal GitHub.
  2. Clone the forked repo to your local system.
  3. Add the remote path for the ‘official’ repository: git remote add upstream git@github.com:viamrobotics/docs.git

When you are ready to contribute changes to the docs:

  1. Make sure you are on the main branch: git switch main
  2. Sync your forked main branch with the official repo: git pull upstream main
  3. Create a new branch for your changes: git switch -c my-new-feature
  4. Edit some docs…
  5. Commit your changes: git commit -am 'Add some feature'
  6. Make sure your local branch is still up-to-date with the official repo: git pull upstream main
  7. Push to the branch: git push origin my-new-feature
  8. Submit a pull request

Questions

If you have questions or would like to chat, please find us on the Community Discord.

Have questions, or want to meet other people working on robots? Join our Community Discord.

If you notice any issues with the documentation, feel free to file an issue or edit this file.