diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d67351e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -sudo: required - -services: - - docker - - postgresql - -language: ruby - -rvm: - - 2.7.1 - -before_script: - - cp config/database.yml.travis config/database.yml - - bundle exec rake db:create db:migrate - diff --git a/Gemfile b/Gemfile index b8cd5c5..e87f78e 100644 --- a/Gemfile +++ b/Gemfile @@ -15,7 +15,7 @@ end gem 'pg', '>= 0.18', '< 2.0' gem 'rack', '~> 2.2' gem 'puma', '~> 8.0' -gem 'sass-rails' +gem 'sprockets-rails' gem 'ostruct' group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 336165e..58f4632 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -205,16 +205,6 @@ GEM tsort reline (0.7.0) io-console (~> 0.5) - sass-rails (6.0.0) - sassc-rails (~> 2.1, >= 2.1.1) - sassc (2.4.0) - ffi (~> 1.9) - sassc-rails (2.1.2) - railties (>= 4.0.0) - sassc (>= 2.0) - sprockets (> 3.0) - sprockets-rails - tilt securerandom (0.4.1) sprockets (4.4.0) concurrent-ruby (~> 1.1) @@ -225,7 +215,6 @@ GEM activesupport (>= 6.1) sprockets (>= 3.0.0) thor (1.5.0) - tilt (2.9.0) timeout (0.6.1) tsort (0.2.0) tzinfo (2.0.6) @@ -256,7 +245,7 @@ DEPENDENCIES puma (~> 8.0) rack (~> 2.2) rails (~> 7.1.0) - sass-rails + sprockets-rails tzinfo-data web-console (>= 3.3.0) diff --git a/Gemfile.next.lock b/Gemfile.next.lock index e531565..ca0acf2 100644 --- a/Gemfile.next.lock +++ b/Gemfile.next.lock @@ -198,16 +198,6 @@ GEM tsort reline (0.7.0) io-console (~> 0.5) - sass-rails (6.0.0) - sassc-rails (~> 2.1, >= 2.1.1) - sassc (2.4.0) - ffi (~> 1.9) - sassc-rails (2.1.2) - railties (>= 4.0.0) - sassc (>= 2.0) - sprockets (> 3.0) - sprockets-rails - tilt securerandom (0.4.1) sprockets (4.4.0) concurrent-ruby (~> 1.1) @@ -218,7 +208,6 @@ GEM activesupport (>= 6.1) sprockets (>= 3.0.0) thor (1.5.0) - tilt (2.9.0) timeout (0.6.1) tsort (0.2.0) tzinfo (2.0.6) @@ -250,7 +239,7 @@ DEPENDENCIES puma (~> 8.0) rack (~> 2.2) rails (~> 7.2.0) - sass-rails + sprockets-rails tzinfo-data web-console (>= 3.3.0) diff --git a/README.md b/README.md index 93d8272..8962af6 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,17 @@ one. Visit http://localhost:3000 and share a benchmark at it using the `SHARE_URL` example above. +To look at a report page without running a benchmark first, load the samples: + +```bash +bin/rails db:seed +``` + +That creates three reports covering the variations the page has to handle: a +comparison report with a noisy entry, one without `compare!`, and one from an +older client that sent no ruby/os/arch fields. It prints their paths and does +nothing if reports already exist, so pass `FORCE=1` to add them anyway. + ## Verifying a change end to end The suite uses Rack::Test, so it never exercises the real server or a real diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js index 5918193..1493c37 100644 --- a/app/assets/config/manifest.js +++ b/app/assets/config/manifest.js @@ -1,2 +1,3 @@ //= link_tree ../images //= link_directory ../stylesheets .css +//= link_tree ../fonts diff --git a/app/assets/fonts/README.md b/app/assets/fonts/README.md new file mode 100644 index 0000000..f57a406 --- /dev/null +++ b/app/assets/fonts/README.md @@ -0,0 +1,12 @@ +Self-hosted so the app makes no third-party request for fonts. + +Latin subsets pulled from Google Fonts. Source Code Pro is a variable font, so +one file covers every weight the app uses. + + oxygen-400.woff2 Oxygen Regular + oxygen-700.woff2 Oxygen Bold + source-code-pro.woff2 Source Code Pro, variable 200..900 + +Both families are licensed under the SIL Open Font License 1.1: +https://fonts.google.com/specimen/Oxygen/license +https://fonts.google.com/specimen/Source+Code+Pro/license diff --git a/app/assets/fonts/oxygen-400.woff2 b/app/assets/fonts/oxygen-400.woff2 new file mode 100644 index 0000000..45fca4e Binary files /dev/null and b/app/assets/fonts/oxygen-400.woff2 differ diff --git a/app/assets/fonts/oxygen-700.woff2 b/app/assets/fonts/oxygen-700.woff2 new file mode 100644 index 0000000..50d99f6 Binary files /dev/null and b/app/assets/fonts/oxygen-700.woff2 differ diff --git a/app/assets/fonts/source-code-pro.woff2 b/app/assets/fonts/source-code-pro.woff2 new file mode 100644 index 0000000..eff3376 Binary files /dev/null and b/app/assets/fonts/source-code-pro.woff2 differ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js deleted file mode 100644 index e07c5a8..0000000 --- a/app/assets/javascripts/application.js +++ /dev/null @@ -1,16 +0,0 @@ -// This is a manifest file that'll be compiled into application.js, which will include all the files -// listed below. -// -// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, -// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. -// -// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the -// compiled file. -// -// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details -// about supported directives. -// -//= require jquery -//= require jquery_ujs -//= require turbolinks -//= require_tree . diff --git a/app/assets/javascripts/docs.coffee b/app/assets/javascripts/docs.coffee deleted file mode 100644 index 24f83d1..0000000 --- a/app/assets/javascripts/docs.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/reports.coffee b/app/assets/javascripts/reports.coffee deleted file mode 100644 index 24f83d1..0000000 --- a/app/assets/javascripts/reports.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index d784ea8..5ff2143 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -1,21 +1,171 @@ /* - * This is a manifest file that'll be compiled into application.css, which will include all the files - * listed below. + * Base styles and page furniture. Per-page styles live in their own files and + * are pulled in by require_tree below. * - * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's - * vendor/assets/stylesheets directory can be referenced here using a relative path. - * - * You're free to add application-wide styles to this file and they'll appear at the bottom of the - * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS - * files in this directory. Styles in this file should be added after the last require_* statement. - * It is generally better to create a new file per style scope. + * Colors and type follow fastruby.io: Oxygen for text, Source Code Pro for + * anything numeric, and square corners throughout. * *= require_tree . *= require_self */ +:root { + --ink: #262320; + --muted: #57514a; + --page: #f8f8f8; + --surface: #fff; + --cream: #f1ebe1; + --line: #dadada; + --faint: #6b6b6b; + --green: #00d242; + --green-pale: #b5e0c3; + --yellow: #fdca31; + --warn-ink: #8a6d3b; + --mono: "Source Code Pro", ui-monospace, SFMono-Regular, Menlo, monospace; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + body { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", - Roboto, Oxygen-Sans, Ubuntu, Cantarell, - "Helvetica Neue", sans-serif; + margin: 0; + min-height: 100vh; + display: flex; + flex-direction: column; + background: var(--page); + color: var(--ink); + font-family: Oxygen, Helvetica, Arial, sans-serif; + font-size: 17px; + line-height: 1.45; + letter-spacing: 0.36px; +} + +a { + color: var(--ink); + text-decoration: none; + border-bottom: 1px solid var(--line); +} + +a:hover { + color: var(--green); + border-bottom-color: var(--green); +} + +code { + font-family: var(--mono); + font-size: 0.925em; +} + +/* Masthead */ + +.masthead { + display: flex; + justify-content: space-between; + align-items: center; + gap: 24px; + padding: 22px 20px; + background: var(--surface); + border-bottom: 1px solid var(--line); +} + +.masthead__wordmark { + font-weight: 700; + font-size: 20px; + letter-spacing: 1.18px; + border-bottom: 0; +} + +.masthead__wordmark span { + color: var(--green); +} + +.masthead__wordmark:hover { + color: var(--ink); +} + +.masthead__link { + font-size: 14px; + color: var(--muted); +} + +/* Page shell */ + +.shell { + flex: 1; + width: 100%; + max-width: 940px; + margin: 0 auto; + padding: 28px 20px 40px; +} + +/* Colophon */ + +.colophon { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + gap: 12px; + padding: 24px 20px; + background: var(--surface); + border-top: 1px solid var(--line); + font-size: 14px; + color: var(--muted); +} + +/* Shared bits */ + +.eyebrow { + margin: 0; + font-family: var(--mono); + font-size: 11px; + font-weight: 500; + letter-spacing: 1.4px; + text-transform: uppercase; + color: var(--muted); +} + +/* Lines are separate elements rather than one
, so the markup can be
+ indented normally without leading whitespace reaching the page. */
+
+.terminal {
+ display: flex;
+ flex-direction: column;
+ background: var(--ink);
+ padding: 22px 24px;
+ overflow-x: auto;
+}
+
+.terminal__line {
+ font-family: var(--mono);
+ font-size: 14px;
+ line-height: 1.85;
+ color: var(--page);
+ white-space: nowrap;
+}
+
+.terminal__result {
+ margin-top: 1.85em;
+ color: var(--green-pale);
+}
+
+.terminal .prompt {
+ color: var(--green);
+}
+
+/* Wider screens opt into more generous spacing. Everything above is the
+ small-screen baseline. */
+
+@media screen and (min-width: 40em) {
+ .masthead,
+ .colophon {
+ padding-left: 32px;
+ padding-right: 32px;
+ }
+
+ .shell {
+ padding: 44px 32px 56px;
+ }
}
diff --git a/app/assets/stylesheets/docs.css b/app/assets/stylesheets/docs.css
new file mode 100644
index 0000000..ebd0b86
--- /dev/null
+++ b/app/assets/stylesheets/docs.css
@@ -0,0 +1,89 @@
+/* Home page: hero, usage block, and the FAQ list. Flat selectors, no nesting. */
+
+.docs {
+ display: flex;
+ flex-direction: column;
+ gap: 32px;
+}
+
+.docs__hero {
+ display: flex;
+ flex-direction: column;
+ gap: 18px;
+ max-width: 62ch;
+}
+
+.docs__hero h1 {
+ margin: 0;
+ font-weight: 700;
+ font-size: 1.75rem;
+ line-height: 1.08;
+ letter-spacing: 1.18px;
+}
+
+.docs__hero p {
+ margin: 0;
+ font-size: 18px;
+ line-height: 1.55;
+ color: var(--muted);
+}
+
+.docs__usage {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ max-width: 74ch;
+}
+
+.docs__note {
+ margin: 0;
+ font-size: 14.5px;
+ color: var(--muted);
+}
+
+.docs__faq {
+ display: flex;
+ flex-direction: column;
+ border-top: 1px solid var(--line);
+ max-width: 78ch;
+}
+
+.docs__faq-item {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 8px;
+ padding: 22px 0;
+ border-bottom: 1px solid var(--line);
+}
+
+.docs__faq-item h2 {
+ margin: 0;
+ font-weight: 700;
+ font-size: 16px;
+ line-height: 1.35;
+ letter-spacing: normal;
+}
+
+.docs__faq-item p {
+ margin: 0;
+ font-size: 16px;
+ line-height: 1.55;
+ color: var(--muted);
+}
+
+/* Wider screens opt into the two-column FAQ and the larger heading. */
+
+@media screen and (min-width: 40em) {
+ .docs {
+ gap: 44px;
+ }
+
+ .docs__hero h1 {
+ font-size: 2.1rem;
+ }
+
+ .docs__faq-item {
+ grid-template-columns: 240px 1fr;
+ gap: 28px;
+ }
+}
diff --git a/app/assets/stylesheets/fonts.css.erb b/app/assets/stylesheets/fonts.css.erb
new file mode 100644
index 0000000..265e221
--- /dev/null
+++ b/app/assets/stylesheets/fonts.css.erb
@@ -0,0 +1,30 @@
+/*
+ * Self-hosted webfonts, so no third-party request is made on first load.
+ * .css.erb rather than .scss so the asset paths do not depend on the sass
+ * engine, which is on its way out.
+ */
+
+@font-face {
+ font-family: "Oxygen";
+ font-style: normal;
+ font-weight: 400;
+ font-display: swap;
+ src: url("<%= font_path "oxygen-400.woff2" %>") format("woff2");
+}
+
+@font-face {
+ font-family: "Oxygen";
+ font-style: normal;
+ font-weight: 700;
+ font-display: swap;
+ src: url("<%= font_path "oxygen-700.woff2" %>") format("woff2");
+}
+
+/* Variable font: one file serves every weight between 200 and 900. */
+@font-face {
+ font-family: "Source Code Pro";
+ font-style: normal;
+ font-weight: 200 900;
+ font-display: swap;
+ src: url("<%= font_path "source-code-pro.woff2" %>") format("woff2");
+}
diff --git a/app/assets/stylesheets/reports.css b/app/assets/stylesheets/reports.css
new file mode 100644
index 0000000..68b1153
--- /dev/null
+++ b/app/assets/stylesheets/reports.css
@@ -0,0 +1,257 @@
+/* Report page: the results table, the deviation notice, and the share block. */
+
+.report {
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+}
+
+.report__head {
+ display: flex;
+ flex-direction: column;
+ gap: 14px;
+}
+
+.report__meta {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.report__meta li {
+ font-family: var(--mono);
+ font-size: 12.5px;
+ padding: 7px 12px;
+ background: var(--cream);
+ color: var(--muted);
+}
+
+/* The numeric columns do not wrap, so the table gets its own horizontal scroll
+ rather than pushing the page wide. */
+
+.results-wrap {
+ overflow-x: auto;
+ border: 1px solid var(--line);
+ background: var(--surface);
+}
+
+.results-wrap:focus-visible {
+ outline: 2px solid var(--green);
+ outline-offset: 2px;
+}
+
+.results {
+ width: 100%;
+ border-collapse: collapse;
+ background: var(--surface);
+}
+
+.results th {
+ font-family: var(--mono);
+ font-size: 11px;
+ font-weight: 500;
+ letter-spacing: 1.2px;
+ text-transform: uppercase;
+ color: var(--muted);
+ text-align: left;
+ padding: 12px 8px;
+ border-bottom: 2px solid var(--line);
+}
+
+.results td {
+ padding: 12px 8px;
+ border-top: 1px solid var(--line);
+ vertical-align: middle;
+}
+
+.results th:first-child,
+.results td:first-child {
+ padding-left: 14px;
+}
+
+.results th:last-child,
+.results td:last-child {
+ padding-right: 14px;
+}
+
+.results th.results__rail,
+.results td.results__rail {
+ width: 4px;
+ padding-left: 12px;
+ padding-right: 0;
+}
+
+.results__slower,
+.results__ips {
+ text-align: right;
+ font-family: var(--mono);
+ font-variant-numeric: tabular-nums;
+ white-space: nowrap;
+}
+
+.results__slower {
+ font-size: 14px;
+}
+
+.results__name {
+ min-width: 0;
+}
+
+.results__label {
+ font-family: var(--mono);
+ font-size: 15px;
+ font-weight: 300;
+}
+
+.results__tag {
+ font-family: var(--mono);
+ font-size: 10px;
+ font-weight: 500;
+ letter-spacing: 1.2px;
+ text-transform: uppercase;
+ color: var(--ink);
+ background: var(--green-pale);
+ padding: 3px 6px;
+ margin-left: 8px;
+ white-space: nowrap;
+}
+
+.results__value {
+ font-size: 16px;
+ font-weight: 300;
+}
+
+.results__dev {
+ font-size: 12.5px;
+ color: var(--faint);
+}
+
+.results__dev.is-noisy {
+ color: var(--warn-ink);
+}
+
+.results tr.is-fastest {
+ background: #f8fdf9;
+}
+
+.results tr.is-fastest td.results__rail {
+ background: var(--green);
+ background-clip: content-box;
+}
+
+.results tr.is-fastest .results__label,
+.results tr.is-fastest .results__value {
+ font-weight: 900;
+}
+
+.results tr.is-fastest .results__slower {
+ color: var(--faint);
+}
+
+.notice {
+ display: flex;
+ flex-direction: column;
+ gap: 5px;
+ padding: 18px 22px;
+ background: var(--surface);
+ border: 1px solid var(--line);
+ border-left: 4px solid var(--yellow);
+}
+
+.notice p {
+ margin: 0;
+ font-size: 15.5px;
+ line-height: 1.5;
+ color: var(--muted);
+ max-width: 66ch;
+}
+
+.share {
+ display: flex;
+ flex-direction: column;
+ gap: 14px;
+}
+
+.share__link {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 18px;
+}
+
+.share__url {
+ font-family: var(--mono);
+ font-size: 13.5px;
+ padding: 14px 16px;
+ background: var(--surface);
+ border: 1px solid var(--line);
+ user-select: all;
+ word-break: break-all;
+}
+
+.share__hint {
+ font-size: 13.5px;
+ color: var(--muted);
+}
+
+.share__snippet {
+ background: var(--surface);
+ border: 1px solid var(--line);
+}
+
+.share__snippet-head {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ align-items: center;
+ gap: 12px;
+ padding: 12px 16px;
+ background: var(--page);
+ border-bottom: 1px solid var(--line);
+}
+
+.share__snippet pre {
+ margin: 0;
+ padding: 18px 16px;
+ background: var(--ink);
+ color: var(--page);
+ font-family: var(--mono);
+ font-size: 13.5px;
+ line-height: 1.8;
+ overflow-x: auto;
+ user-select: all;
+}
+
+/* Wider screens opt into roomier cells. */
+
+@media screen and (min-width: 40em) {
+ .report {
+ gap: 30px;
+ }
+
+ .results th {
+ padding: 15px 10px;
+ }
+
+ .results td {
+ padding: 16px 10px;
+ }
+
+ .results th:first-child,
+ .results td:first-child {
+ padding-left: 22px;
+ }
+
+ .results th:last-child,
+ .results td:last-child {
+ padding-right: 22px;
+ }
+
+ .results th.results__rail,
+ .results td.results__rail {
+ padding-left: 18px;
+ }
+}
diff --git a/app/assets/stylesheets/reports.scss b/app/assets/stylesheets/reports.scss
deleted file mode 100644
index 4c50ea4..0000000
--- a/app/assets/stylesheets/reports.scss
+++ /dev/null
@@ -1,21 +0,0 @@
-// Place all the styles related to the reports controller here.
-// They will automatically be included in application.css.
-// You can use Sass (SCSS) here: http://sass-lang.com/
-
-.report {
- .results {
- font-family: Monaco, Consolas, 'Liberation Mono', Courier, monospace;
- }
- width: 600px;
-
- @media screen and (max-width: 600px) {
- width: 100%;
- padding-right: 5px;
- font-size: 13px;
-
- .results {
- font-size: 13px;
- }
-
- }
-}
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
deleted file mode 100644
index de6be79..0000000
--- a/app/helpers/application_helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module ApplicationHelper
-end
diff --git a/app/helpers/docs_helper.rb b/app/helpers/docs_helper.rb
deleted file mode 100644
index 611f68b..0000000
--- a/app/helpers/docs_helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module DocsHelper
-end
diff --git a/app/helpers/reports_helper.rb b/app/helpers/reports_helper.rb
index 741e2d3..d2a59d1 100644
--- a/app/helpers/reports_helper.rb
+++ b/app/helpers/reports_helper.rb
@@ -18,7 +18,7 @@ def format_ips(value)
def times_slower(best, cur)
best_low = best["ips"] - best["stddev"]
report_high = cur["ips"] + cur["stddev"]
- overlaps = report_high > best_low
+ overlaps = report_high > best_low
if overlaps
return "-"
@@ -34,4 +34,58 @@ def stddev_percentage(part)
def format_stddev(part)
"%4.1f%%" % stddev_percentage(part)
end
+
+ # The report rendered as a markdown table, for pasting into an issue or a
+ # pull request. Mirrors what the page shows: the fastest entry is bolded and
+ # the slower column only appears for comparison reports.
+ def report_markdown(report, fastest, url)
+ columns = ["name", "iterations/second"]
+ columns << "slower" if report.compare
+
+ lines = []
+ lines << "| #{columns.join(" | ")} |"
+ lines << "| #{columns.map { "---" }.join(" | ")} |"
+
+ report.entries.each do |entry|
+ name = markdown_cell(entry["name"])
+ name = "**#{name}**" if fastest && entry["name"] == fastest["name"]
+
+ cells = [name, "#{format_ips(entry["ips"]).strip} \u00b1 #{format_stddev(entry).strip}"]
+ cells << times_slower(fastest, entry) if report.compare
+
+ lines << "| #{cells.join(" | ")} |"
+ end
+
+ environment = report_environment(report)
+ lines << ""
+ lines << [environment, "Full report: #{url}"].compact.join(". ")
+
+ lines.join("\n")
+ end
+
+ # "interpolation and 3 others - benchmark.fyi". A single-entry report gets just
+ # the name, since "and 0 others" reads like a bug.
+ def report_title(report, fastest)
+ name = fastest ? fastest["name"] : "Report"
+ others = report.entries.size - 1
+ name = "#{name} and #{pluralize(others, "other")}" if others.positive?
+
+ "#{name} - benchmark.fyi"
+ end
+
+ # Benchmark names are arbitrary strings. An unescaped pipe would add a column
+ # to the markdown table and break the row for everyone who pastes it.
+ def markdown_cell(value)
+ value.to_s.gsub("|") { "\\|" }
+ end
+
+ # "ruby 4.0.6, darwin/arm64" from whichever of those fields the client sent.
+ # Older reports predate them entirely, so this can be nil.
+ def report_environment(report)
+ ruby = "ruby #{report.ruby}" if report.ruby.present?
+ machine = [report.os, report.arch].reject(&:blank?).join("/")
+
+ parts = [ruby, machine.presence].compact
+ parts.any? ? parts.join(", ") : nil
+ end
end
diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb
deleted file mode 100644
index 286b223..0000000
--- a/app/mailers/application_mailer.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-class ApplicationMailer < ActionMailer::Base
- default from: 'from@example.com'
- layout 'mailer'
-end
diff --git a/app/views/docs/index.html.erb b/app/views/docs/index.html.erb
index 8dd8f47..6b9bbee 100644
--- a/app/views/docs/index.html.erb
+++ b/app/views/docs/index.html.erb
@@ -1,21 +1,58 @@
-benchmark-ips version 2.6.0 or greater and run your benchmark with SHARE=1. I.e.: SHARE=1 ruby my_benchmark.rb
- + Run your benchmark-ips + benchmark with one extra environment variable and get a URL you can paste + into an issue, a pull request, or a blog post. +
+
+ Requires benchmark-ips 2.6.0 or greater. Add x.compare! to your
+ benchmark for the times-slower column.
+
+ The URL is printed in your terminal after the run. Share it with friends, + enemies, whoever. +
+
+ Yes. Point benchmark-ips at it with SHARE_URL instead of
+ SHARE, and it posts there rather than here.
+
+ Send a pull request to + github.com/fastruby/benchmark.fyi + with your changes. +
++ Excellent. Open an issue or send a pull request to + github.com/fastruby/benchmark.fyi. +
+