Skip to content

Commit

Permalink
Snaps design guidelines (MetaMask#713)
Browse files Browse the repository at this point in the history
* add design guidelines for snaps

* formatting

* added images

* added images locally

* Formatting

* eslint

* Update snaps/concepts/design-guidelines.md

Co-authored-by: Alexandra Tran Carrillo <[email protected]>

* Update snaps/concepts/design-guidelines.md

Co-authored-by: Alexandra Tran Carrillo <[email protected]>

* Update snaps/concepts/design-guidelines.md

Co-authored-by: Alexandra Tran Carrillo <[email protected]>

* Update snaps/concepts/design-guidelines.md

Co-authored-by: Alexandra Tran Carrillo <[email protected]>

* Update snaps/concepts/design-guidelines.md

Co-authored-by: Alexandra Tran Carrillo <[email protected]>

* Update snaps/concepts/design-guidelines.md

Co-authored-by: Alexandra Tran Carrillo <[email protected]>

* Update snaps/concepts/design-guidelines.md

Co-authored-by: Alexandra Tran Carrillo <[email protected]>

* Reviewed input

* updated images

---------

Co-authored-by: Alexandra Tran Carrillo <[email protected]>
  • Loading branch information
eriknson and alexandratran authored May 4, 2023
1 parent 724b693 commit 5fa2d7e
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 55 deletions.
46 changes: 18 additions & 28 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
"commonjs": true,
"es6": true
},
"settings": {
"react": {
"version": "detect"
}
},
"overrides": [
{
"files": "**/*.js",
Expand All @@ -27,30 +32,15 @@
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
"ecmaVersion": "latest",
"sourceType": "module"
},
"rules": {
"indent": [
"error",
2
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"double"
],
"jsx-quotes": [
"error",
"prefer-double"
],
"semi": [
"error",
"always"
],
"indent": ["error", 2],
"linebreak-style": ["error", "unix"],
"quotes": ["error", "double"],
"jsx-quotes": ["error", "prefer-double"],
"semi": ["error", "always"],
"react/react-in-jsx-scope": 0,
"object-curly-spacing": ["error", "always"],
"comma-dangle": ["error", "always-multiline"],
Expand All @@ -59,12 +49,12 @@
"unused-imports/no-unused-vars": [
"error",
{
"vars": "all",
"varsIgnorePattern": "^_",
"args": "after-used",
"argsIgnorePattern": "^_"
}
"vars": "all",
"varsIgnorePattern": "^_",
"args": "after-used",
"argsIgnorePattern": "^_"
}
],
"object-shorthand": ["error", "properties"]
}
}
}
13 changes: 4 additions & 9 deletions snaps-sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,14 @@ const sidebar = {
"concepts/lifecycle",
"concepts/user-interface",
"concepts/execution-environment",
"concepts/design-guidelines",
],
},
{
type: "category",
label: "Tutorials",
link: { type: "generated-index" },
items: [
"tutorials/gas-estimation",
"tutorials/transaction-insights",
],
items: ["tutorials/gas-estimation", "tutorials/transaction-insights"],
},
{
type: "category",
Expand All @@ -74,15 +72,12 @@ const sidebar = {
type: "doc",
id: "reference/cli/index",
},
items: [
"reference/cli/options",
"reference/cli/subcommands",
],
items: ["reference/cli/options", "reference/cli/subcommands"],
},
"reference/permissions",
],
},
],
};

module.exports = sidebar;
module.exports = sidebar;
Binary file added snaps/assets/dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added snaps/assets/insights.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added snaps/assets/install-modal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added snaps/assets/install.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added snaps/assets/picker.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 13 additions & 12 deletions snaps/concepts/anatomy.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
---
title: Snaps anatomy
description: Learn about the anatomy of a snap project.
---

# Snap anatomy
# Snaps anatomy

If you look at the directory structure of the
[Snaps template repository](https://github.com/MetaMask/template-snap-monorepo) used in the
Expand Down Expand Up @@ -53,11 +54,11 @@ Consider this simple snap, `hello-snap`:
module.exports.onRpcRequest = async ({ origin, request }) => {
switch (request.method) {
// Expose a "hello" RPC method to dapps
case 'hello':
return 'world!';
case "hello":
return "world!";

default:
throw new Error('Method not found.');
throw new Error("Method not found.");
}
};
```
Expand All @@ -75,12 +76,12 @@ If a dapp wants to use `hello-snap`, it can implement something like this:
```javascript
// Connect to the snap, enabling its usage inside the dapp
await window.ethereum.request({
method: 'wallet_enable',
method: "wallet_enable",
params: [
{
wallet_snap: {
'npm:hello-snap': {
version: '^1.0.0',
"npm:hello-snap": {
version: "^1.0.0",
},
},
},
Expand All @@ -89,8 +90,8 @@ await window.ethereum.request({

// Invoke the "hello" RPC method exposed by the snap
const hello = await window.ethereum.request({
method: 'wallet_invokeSnap',
params: { snapId: 'npm:hello-snap', request: { method: 'hello' } },
method: "wallet_invokeSnap",
params: { snapId: "npm:hello-snap", request: { method: "hello" } },
});

console.log(hello); // 'world!'
Expand Down Expand Up @@ -171,8 +172,8 @@ For example:
```javascript
module.exports = {
cliOptions: {
src: 'lib/index.js',
dist: 'out',
src: "lib/index.js",
dist: "out",
port: 9000,
},
};
Expand All @@ -186,7 +187,7 @@ You can transform it in any way you want, for example, adding plugins.
The `bundleCustomizer` function looks something like this:

```javascript
const brfs = require('brfs');
const brfs = require("brfs");

module.exports = {
cliOptions: {
Expand Down
159 changes: 159 additions & 0 deletions snaps/concepts/design-guidelines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
---
title: Snaps design guidelines
description: Guiding principles for designers, developers, builders, and writers to create snap install flows that are accessible for all types of users.
---

# Snaps design guidelines

This page outlines guiding principles for designers, developers, builders, and writers to create snap install flows that are accessible for all users. Use these guidelines when introducing your snap within a dapp or website.

## Why this matters

The snap installation process contains critical info about your snap, including what it does, how it enhances your application, and why it’s beneficial for users. It's important to provide this information on your website or dapp to help users understand the purpose and benefits of the snap before installing it. Without this information, users may drop out during installation or install the snap without fully understanding its purpose.

## Guidelines at a glance

**Metadata must-haves**

- Keep your name to **21 characters or less** (including spaces).
- Never use “snap” in your snap’s name. Use the space for something more descriptive.
- Your avatar should fit in a **32px circular frame, SVG format**.
- Always aim for short and simple copy.

**Before** asking for permission to install, provide users with **clear and concise information** about:

- _What_ the snap does and _how_ it meets their needs.
- _How_ the snap works.
- Any _security precautions_ they may need to know about.

Write in active voice and use sentence case. Avoid jargon—write in plain language that can be understood at a glance.

## Think like your users, write like a human

Consider whether the details that interest you as a developer are relevant to the user’s experience. Often times, content can be drastically reduced by cutting jargon and run-on sentences. Read your content out loud to hear what stands out most in your messaging. If something is hard to say, it’s probably hard to read.

- **Be clear.**

When labeling buttons or actions, use descriptive action verbs instead of vague phrases. _Install_ is more clear than _Complete_, for example.

- **Be concise.**

Use short, simple words. Make every word earn its place on the screen.

- **Be consistent.**

Identify synonyms and eliminate them. Each important object and action should have a single word to represent it. Inconsistency can blur the lines for users, creating uncertainty and confusion.

## Introducing your snap

Use conversational language when explaining the snap. If you need to use a technical term, briefly define it so everyone can understand. Avoid jargon whenever possible, and keep your words short and simple. Introduce your snap in the context of your application to make it clear what the user gets if they install.

![Introducing your snap's features via a modal](../assets/install-modal.png)

:::note How to (not) describe what your snap does

**Don'ts**

_Allow the snap to perform actions that run periodically at fixed times, dates, or intervals. This can be used to trigger time-sensitive interactions or notifications._

_Allow this snap to display notifications regarding your Ethereum Name Service expiration._

**Do's**

_Let this snap schedule and run recurring tasks or notifications._

_Let this snap notify you when your ENS is about to expire._

:::

### Details to include when introducing your snap

This is your chance to share the benefits of your snap to the intended user. If it isn’t clear what a user stands to gain from your snap, chances are they won’t even install it. So don’t be afraid to think like a marketer and emphasize the benefits of your snap.

Consider introducing your snap on your website with a modal, tooltip, or card. This introduction can happen before or alongside the installation prompt, but should always be clear and descriptive.

#### Important details include:

- What your snap does, why someone would use it, and how it works.
- Security precautions in plain, basic language that anyone can understand.
- Descriptions of the features that make your snap appealing to the intended users.

:::tip Tip
Some studies estimate users read only 20-28% of text on any screen, so write about your snap with language that’s impactful, clear, and direct.
:::

## Embedded in existing flows

Introduce the snap as a natural extension of existing elements on your screen, and suggest installation when the time is right. This can be a make or break moment for your snap, so put yourself in the shoes of the intended user.

At what point does it make the most sense to prompt an install? Don’t ask the user to install your snap before they do anything in the dapp or website, as they will probably decline. Instead, **wait to prompt installation** **until a point where the snap is required**.

In the following example, a key management snap is suggested in the context of a network picker screen.

![Installation and connection to your snap embedded in existing flows](../assets/picker.png)

## Making the most of your metadata

Your snap’s avatar and name will be among the first things a user sees when deciding whether to install your snap. These are also a key part of your identity, so it’s worth spending a bit of time on this step.

**Avatar**

Your snap’s avatar should be suitable for a **32 px circular frame in SVG format**. Avoid using images with small details, as they won't be impactful in the allotted space. Aim for something bold, simple, and easily understood.

**Name**

Your snap's name should be short and easy to remember. It should be **21 characters maximum**, **including spaces**, to ensure that it is easy to read and fits comfortably on small screens.

Using a descriptive name can help users understand how they will benefit from installing your snap, and may increase the likelihood that they will install and use it. **Never** use the word **“snap”** in your name — your name should be specific and memorable, and which will differentiate your snap from others.

:::note How to (not) name your snap

**Don'ts**

_Solana Snap_

_Snap for Filecoin_

_Best manager for Bitcoin_

**Do's**

_Solana Manager_

_Bitcoin Helper_

_Filecoin Wallet_

:::

![How your snap’s avatar and name is displayed during installation](../assets/install.png)
![How your snap’s name is displayed during transaction insights](../assets/insights.png)
![How your snap’s avatar and name is displayed during a custom dialog screen](../assets/dialog.png)

## Upleveling your copy

At MetaMask, we use an in-depth style guide to inform our writing decisions. Here are a couple of ways to easily uplevel your own copy so it feels more at home in the MetaMask ecosystem.


### Capitalization

With few exceptions, use **sentence case as a default**. Sentence case is capitalizing only the first word of a line of copy. Not only is sentence case is more casual and conversational, it’s also easier to scan than title case. Keep in mind, there are a handful of times that title case is the way to go.

### Active voice

Write your copy in active voice. There are certain situations where passive voice is the better option, but it’s more likely that active voice will suit your situation.

:::tip How to write in active voice
_Subject_ (person/thing acting) _verb_ (the action) _object_ (receives the action).
:::

:::note How to (not) write in active voice

_The problem is being investigated_

_We’re investigating the problem_

:::



6 changes: 3 additions & 3 deletions snaps/concepts/execution-environment.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Snap execution environment
title: Snaps execution environment
description: Learn about the Snaps execution environment.
---

Expand Down Expand Up @@ -32,8 +32,8 @@ The following globals are also available:
The execution environment is instrumented in this way to:

1. Prevent snaps from influencing any other running code, including MetaMask itself.
That is, prevent all snaps from polluting the global environment and malicious snaps from
stealing the user's stuff.
That is, prevent all snaps from polluting the global environment and malicious snaps from
stealing the user's stuff.
1. Prevent snaps from accessing sensitive JavaScript APIs (such as `fetch`) without permission.
1. Ensure that the execution environment is "fully virtualizable," that is, platform-independent.

Expand Down
5 changes: 3 additions & 2 deletions snaps/concepts/lifecycle.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
---
title: Snaps lifecycle
description: Learn about the lifecycle of a snap.
---

# Snap lifecycle
# Snaps lifecycle

Just like [service workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) or
AWS lambda functions, snaps are designed to wake up in response to messages/events, and shut down
Expand All @@ -18,4 +19,4 @@ A snap is considered unresponsive if:
1. It takes more than 60 seconds to process a JSON-RPC request.

Stopped snaps start whenever they receive a JSON-RPC request, unless they're disabled.
If a snap is disabled, the user must re-enable it before it can start again.
If a snap is disabled, the user must re-enable it before it can start again.
3 changes: 2 additions & 1 deletion snaps/concepts/user-interface.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
---
title: Snaps user interface
description: Learn about the user interface of a snap.
---

# Snap user interface
# Snaps user interface

Any snap must represent itself and what it does to the end user.
Using the MetaMask settings page, the user can see their installed snaps.
Expand Down

0 comments on commit 5fa2d7e

Please sign in to comment.