Agent skill

React Joyride

by cadence-workflow in cadence-workflow/cadence-web

Guide for implementing, configuring, and debugging React Joyride v3 guided tours.

MITAuto-check passedDevelopment

Install React Joyride

skills CLI
$ npx skills add cadence-workflow/cadence-web --skill react-joyride -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install cadence-workflow/cadence-web react-joyride --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/cadence-workflow/cadence-web.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/react-joyride .claude/skills/react-joyride && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
react-joyride
GitHub stars
435
Token cost
~3.9k tokens
SKILL.md length
1,224 words
Files
5 (incl. references)
Skills in repo
2
Repo updated
First seen
Licence
MIT

At a glance

Guide for implementing, configuring, and debugging React Joyride v3 guided tours.

  • Works in 3 steps: Color options (simplest) → Styles override → Custom components (full control)
  • The user mentions joyride
  • SKILL.md covers Quick Start, Core Concepts, Step Configuration and Uncontrolled vs Controlled, plus 6 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

React Joyride is an agent skill from cadence-workflow/cadence-web. Guide for implementing, configuring, and debugging React Joyride v3 guided tours. Use this skill whenever the user mentions joyride, guided tour, onboarding tour, walkthrough, tooltip tour, step-by-step guide, product tour, or wants to highlight UI elements sequentially. Also use when debugging tour issues like tooltips not appearing, targets not found, or controlled mode problems. This skill covers the useJoyride hook, Joyride component, step configuration, events, controls, custom components, and styling.

Its SKILL.md is about 3.9k tokens, which your agent loads only when the skill is triggered. The skill folder holds 5 other files, including reference files (for example `references/api-events-components.md`, `references/api-props-options.md` and `references/api-step-state-controls.md`).

It sits in Development, covering Debugging. It works with React and webpack. The repository describes itself as: Web UI for visualizing workflows on Cadence. The licence is MIT.

When your agent uses it

  • The user mentions joyride
  • Onboarding tour
  • Step-by-step guide
  • Wants to highlight UI elements sequentially

Example prompts

  • “/react-joyride”

Workflow steps

3 steps, taken from the step headings in SKILL.md.

  1. Color options (simplest)
  2. Styles override
  3. Custom components (full control)

What it can do on your machine

Read from SKILL.md and the folder at commit 5e06d86. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are typescript).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Links to these hosts (documentation or services it may open):

    • v3.react-joyride.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

React Joyride loads about 3.9k tokens when it runs, and up to ~9.6k if it reads all its reference files. Until then it costs about 132 tokens; SKILL.md has 1,224 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~132
When it runs · the whole SKILL.md, loaded when a task matches
~3.9k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~9.6k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from cadence-workflow/cadence-web at commit 5e06d86, republished under its MIT licence (© cadence-workflow). 1,224 words, ~3,937 tokens.

Download SKILL.mdSave it as .claude/skills/react-joyride/SKILL.md (or your agent's skills folder). This skill also uses 4 other files; get the full folder from GitHub.
name
react-joyride
description
Guide for implementing, configuring, and debugging React Joyride v3 guided tours. Use this skill whenever the user mentions joyride, guided tour, onboarding tour, walkthrough, tooltip tour, step-by-step guide, product tour, or wants to highlight UI elements sequentially. Also use when debugging tour issues like tooltips not appearing, targets not found, or controlled mode problems. This skill covers the useJoyride hook, Joyride component, step configuration, events, controls, custom components, and styling.
license
MIT
metadata.author
gilbarbara
metadata.version
3.0.0

React Joyride v3

Create guided tours in React apps. Two public APIs: the useJoyride() hook (recommended) and the <Joyride> component.

Online docs: https://v3.react-joyride.com

Quick Start

tsx
import { useJoyride, STATUS, Status } from 'react-joyride';

function App() {
  const { Tour } = useJoyride({
    continuous: true,
    run: true,
    steps: [
      { target: '.my-element', content: 'This is the first step', title: 'Welcome' },
      { target: '#sidebar', content: 'Navigate here', placement: 'right' },
    ],
    onEvent: (data) => {
      if (([STATUS.FINISHED, STATUS.SKIPPED] as Status).includes(data.status)) {
        // Tour ended
      }
    },
  });

  return <div>{Tour}{/* rest of app */}</div>;
}
Using the component
tsx
import { Joyride, STATUS, Status } from 'react-joyride';

function App() {
  return (
    <Joyride
      continuous
      run={true}
      steps={[
        { target: '.my-element', content: 'First step' },
        { target: '#sidebar', content: 'Second step' },
      ]}
      onEvent={(data) => {
        if (([STATUS.FINISHED, STATUS.SKIPPED] as Status).includes(data.status)) {
          // Tour ended
        }
      }}
    />
  );
}

The hook returns { controls, failures, on, state, step, Tour }. Render Tour in your JSX.

Docs: https://v3.react-joyride.com/docs/getting-started

Core Concepts

The tour has two state dimensions:

Tour Status: idle -> ready -> waiting -> running <-> paused -> finished | skipped

  • idle: No steps loaded
  • ready: Steps loaded, waiting for run: true
  • waiting: run=true but steps loading async (transitions to running when steps arrive)
  • running: Tour active
  • paused: Tour paused (controlled mode at COMPLETE, or stop() called)
  • finished / skipped: Tour ended

Step Lifecycle (per step): init -> ready -> beacon_before -> beacon -> tooltip_before -> tooltip -> complete

  • *_before phases: scrolling and positioning happen here
  • beacon: Pulsing indicator shown (skipped when continuous + navigating, skipBeacon, or placement: 'center')
  • tooltip: The tooltip is visible and interactive

Docs: https://v3.react-joyride.com/docs/how-it-works

Step Configuration

Each step requires target and content. All other fields are optional.

tsx
{
  target: '.my-element',       // CSS selector, HTMLElement, React ref, or () => HTMLElement
  content: 'Step body text',   // ReactNode
  title: 'Optional title',    // ReactNode
  placement: 'bottom',        // Default. Also: top, left, right, *-start, *-end, auto, center
  id: 'unique-id',            // Optional identifier
  data: { custom: 'data' },   // Attached to event callbacks
}
Target types
tsx
// CSS selector
{ target: '.sidebar-nav' }
// HTMLElement
{ target: document.getElementById('my-el') }
// React ref
const ref = useRef(null);
{ target: ref }
// Function (evaluated each lifecycle)
{ target: () => document.querySelector('.dynamic-element') }
Common step options (override per-step)
OptionDefaultDescription
placement'bottom'Tooltip position. Use 'center' for modal-style (requires target: 'body')
skipBeaconfalseSkip beacon, show tooltip directly
buttons['back','close','primary']Buttons in tooltip. Add 'skip' for skip button
hideOverlayfalseDon't show dark overlay
blockTargetInteractionfalseBlock clicks on highlighted element
before-(data) => Promise<void> — async hook before step shows
after-(data) => void — fire-and-forget hook after step completes
skipScrollfalseDon't scroll to target
scrollTarget-Scroll to this element instead of target
spotlightTarget-Highlight this element instead of target
spotlightPadding10Padding around spotlight. Number or { top, right, bottom, left }
targetWaitTimeout1000ms to wait for target to appear. 0 = no waiting
beforeTimeout5000ms to wait for before hook. 0 = no timeout

All Options fields can be set globally via options prop or per-step. Per-step values override global.

Docs: https://v3.react-joyride.com/docs/step | https://v3.react-joyride.com/docs/props/options

Uncontrolled vs Controlled

Uncontrolled (default — strongly preferred)

The tour manages step navigation internally. This is the right choice for most use cases.

The library handles async transitions for you. If a step needs to wait for a UI change (dropdown opening, data loading, animation), use before hooks — the tour waits for the promise to resolve before showing the step. If a target element isn't in the DOM yet, targetWaitTimeout (default: 1000ms) handles polling for it. You do NOT need controlled mode for these cases.

tsx
const { Tour } = useJoyride({
  continuous: true,
  run: isRunning,
  steps: [
    { target: '.nav', content: 'Navigation' },
    {
      target: '.dropdown-item',
      content: 'Inside the dropdown',
      before: () => {
        // Open dropdown and wait for animation — tour waits automatically
        openDropdown();
        return new Promise(resolve => setTimeout(resolve, 300));
      },
      after: () => closeDropdown(), // Clean up after step (fire-and-forget)
    },
    { target: '.main-content', content: 'Main content' },
  ],
  onEvent: (data) => {
    if (([STATUS.FINISHED, STATUS.SKIPPED] as Status).includes(data.status)) {
      setIsRunning(false);
    }
  },
});
Controlled (with stepIndex) — use sparingly

Only use controlled mode when the parent genuinely needs to manage the step index externally (e.g., syncing with URL params, external state machines, or complex multi-component coordination that before/after hooks can't handle).

tsx
const [stepIndex, setStepIndex] = useState(0);
const [run, setRun] = useState(true);

const { Tour } = useJoyride({
  continuous: true,
  run,
  stepIndex,  // This makes it controlled
  steps,
  onEvent: (data) => {
    const { action, index, status, type } = data;

    if (([STATUS.FINISHED, STATUS.SKIPPED] as Status).includes(status)) {
      setRun(false);
      return;
    }

    if (type === 'step:after' || type === 'error:target_not_found') {
      setStepIndex(index + (action === 'prev' ? -1 : 1));
    }
  },
});

Controlled mode rules:

  • go() and reset() are disabled (logged warning)
  • You must update stepIndex in response to events
  • The tour pauses at COMPLETE — you must advance it
  • Prefer uncontrolled mode with before/after hooks unless you have a strong reason for external index management

Event System

onEvent callback
tsx
onEvent: (data: EventData, controls: Controls) => void

The data object contains the full tour state plus event-specific fields. The controls object lets you programmatically control the tour.

Event types (in order per step)
EventWhen
tour:startTour begins
step:before_hookbefore hook is called
step:beforeTarget found, step about to render
scroll:startScrolling to target
scroll:endScroll complete
beaconBeacon shown
tooltipTooltip shown
step:afterUser navigated (next/prev/close/skip)
step:after_hookafter hook called
tour:endTour finished or skipped
tour:statusStatus changed (on stop/reset)
error:target_not_foundTarget element not found
errorGeneric error
Event subscription with on()
tsx
const { on, Tour } = useJoyride({ ... });

useEffect(() => {
  const unsubscribe = on('tooltip', (data, controls) => {
    analytics.track('tour_step_viewed', { step: data.index });
  });
  return unsubscribe;
}, [on]);

Docs: https://v3.react-joyride.com/docs/events

Controls

Available via useJoyride() return value or onEvent second argument:

MethodDescription
next()Advance to next step
prev()Go to previous step
close(origin?)Close current step, advance
skip(origin?)Skip the tour entirely
start(index?)Start the tour
stop(advance?)Stop (pause) the tour
go(index)Jump to step (uncontrolled only)
reset(restart?)Reset tour (uncontrolled only)
open()Open tooltip for current step
info()Get current state

Docs: https://v3.react-joyride.com/docs/hook

Styling & Theming

Three layers of customization (from simple to full control):

1. Color options (simplest)
tsx
options: {
  primaryColor: '#1976d2',      // Buttons and beacon
  backgroundColor: '#1a1a2e',   // Tooltip background
  textColor: '#ffffff',         // Tooltip text
  overlayColor: 'rgba(0,0,0,0.7)', // Overlay backdrop
  arrowColor: '#1a1a2e',        // Arrow (match background)
}
2. Styles override
tsx
styles: {
  tooltip: { borderRadius: 12 },
  buttonPrimary: { backgroundColor: '#1976d2' },
  buttonBack: { color: '#666' },
  spotlight: { borderRadius: 8 },
}

Style keys: arrow, beacon, beaconInner, beaconOuter, beaconWrapper, buttonBack, buttonClose, buttonPrimary, buttonSkip, floater, loader, overlay, tooltip, tooltipContainer, tooltipContent, tooltipFooter, tooltipFooterSpacer, tooltipTitle

3. Custom components (full control)

See next section.

Docs: https://v3.react-joyride.com/docs/props/styles

Custom Components

Replace any UI component via props. Each receives render props with step data and button handlers.

Custom Tooltip
tsx
import type { TooltipRenderProps } from 'react-joyride';

function MyTooltip({ backProps, index, primaryProps, size, skipProps, step, tooltipProps }: TooltipRenderProps) {
  return (
    <div {...tooltipProps} style={{ background: '#fff', padding: 16, borderRadius: 8, width: step.width }}>
      {step.title && <h3>{step.title}</h3>}
      <div>{step.content}</div>
      <div>
        {index > 0 && <button {...backProps}>Back</button>}
        <button {...primaryProps}>Next</button>
      </div>
    </div>
  );
}

// Usage
<Joyride tooltipComponent={MyTooltip} ... />

Important: Spread tooltipProps on the container (sets role="dialog" and aria-modal). Spread button props (backProps, primaryProps, closeProps, skipProps) on buttons for correct action handling.

Custom Beacon

Must render a <span> (placed inside a <button> wrapper). Receives BeaconRenderProps: { continuous, index, isLastStep, size, step }.

Custom Arrow

Receives ArrowRenderProps: { base, placement, size }.

Show full SKILL.md (490 more words)Show less
Custom Loader

Receives LoaderRenderProps: { step }. Set to null to disable the loader.

Docs: https://v3.react-joyride.com/docs/custom-components

Problem → Solution Guide

I need to...Use
Wait for async UI changes between steps (dropdown, animation, data load)before hook returning a Promise — not controlled mode
Control step navigation externally (URL sync, external state machine)Controlled mode with stepIndex — but try before/after hooks first
Track which steps failed (target missing, hook error)failures array from useJoyride() return
Listen to specific events without onEvent switchon('event:type', handler) from useJoyride() return
Show a centered modal-style steptarget: 'body' + placement: 'center'

Common Gotchas & Debugging

Use debug: true first

The debug prop is the most powerful troubleshooting tool. It logs detailed lifecycle transitions, state changes, and event emissions to the console. Always start here when something isn't working.

tsx
<Joyride debug={true} ... />
// or
useJoyride({ debug: true, ... })

The console output shows exactly which lifecycle phase the tour reaches, what actions are firing, and where it gets stuck.

Tour not starting
  • Check run={true} is set
  • Verify steps array is not empty and steps have valid target + content
  • For SSR: use <Joyride> component (auto-guards DOM access) or check typeof window !== 'undefined'
Target not found
  • Test selector in console: document.querySelector('.your-selector')
  • Element must be visible (not display: none, visibility: hidden, or zero dimensions)
  • If element mounts later, increase targetWaitTimeout (default: 1000ms)
  • Set targetWaitTimeout: 0 to skip waiting entirely
  • In uncontrolled mode, missing targets auto-advance; in controlled mode, handle error:target_not_found event
Tooltip never appears / overlay flashes
  • Add debug: true and check the console to see which lifecycle phase is reached
  • Verify the target element is in the viewport or scrollable
  • Check for CSS overflow: hidden on ancestors clipping the target
  • If using portals or modals, the target may not be accessible
Controlled mode stuck
  • First question: do you actually need controlled mode? Most async needs are solved with before/after hooks in uncontrolled mode
  • If controlled: you MUST update stepIndex in your onEvent handler when type === 'step:after'
  • Handle both forward (action !== 'prev') and backward (action === 'prev') navigation
  • Also handle error:target_not_found to skip broken steps
  • go() and reset() don't work in controlled mode
Before hook timeout
  • Default beforeTimeout is 5000ms — increase if your async operation takes longer
  • Set beforeTimeout: 0 for no timeout
  • The loader appears after loaderDelay (300ms) while waiting
Scroll issues
  • Use scrollTarget to scroll to a different element than the tooltip target
  • Adjust scrollOffset (default: 20px) for headers or fixed elements
  • Set skipScroll: true to disable auto-scrolling for a step
  • scrollToFirstStep: false by default — set to true if first step is off-screen
Center placement
  • Use placement: 'center' with target: 'body' for modal-style centered tooltips
  • Center placement automatically hides the beacon and arrow
Imports
tsx
// Named exports only (no default export in v3)
import { Joyride, useJoyride } from 'react-joyride';

// Constants for type-safe comparisons
import { ACTIONS, EVENTS, LIFECYCLE, ORIGIN, STATUS } from 'react-joyride';

// Types
import type { Step, Props, EventData, Controls, TooltipRenderProps } from 'react-joyride';

Docs: https://v3.react-joyride.com/docs/exports

Reference Files

Read these for complete API details:

  • references/api-props-options.md — Full Props, Options (all 30+ fields with defaults), Locale, FloatingOptions, Styles types
  • references/api-step-state-controls.md — Step, StepMerged, StepTarget, State, Controls (all 10 methods), UseJoyrideReturn, StepFailure
  • references/api-events-components.md — All 13 event types, ACTIONS/LIFECYCLE/STATUS/ORIGIN constants, EventData, custom component render props
  • references/patterns.md — Complete working examples: controlled mode, before/after hooks, custom tooltip, event subscription, dynamic steps

© cadence-workflow, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 4 other files (references) in .agents/skills/react-joyride of cadence-workflow/cadence-web.

  • SKILL.md
  • references/api-events-components.md
  • references/api-props-options.md
  • references/api-step-state-controls.md
  • references/patterns.md

Open the folder on GitHubat commit 5e06d86

Compare with similar skills

React Joyride next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

React Joyride compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
React Joyride this skillcadence-workflow/cadence-web435—~3.9kAutomated safety check: PassMIT
Electron Heap Snapshot Analysiskeybase/client9.3k—~875Automated safety check: PassBSD-3-Clause
Electron DevTools Trace Analysiskeybase/client9.3k—~809Automated safety check: PassBSD-3-Clause
React DevTools Profile Analyzerkeybase/client9.3k—~978Automated safety check: PassBSD-3-Clause
Jazz UI Developmentgarden-co/classic-jazz2.5k—~1.7kAutomated safety check: PassMIT
Implement GitHub FeatureAgnosticUI/agnosticui826—~1.6kAutomated safety check: PassApache-2.0

Similar skills

  • Analyzes V8, Chrome and Electron .heapsnapshot files with Node scripts to find memory leaks, detached DOM nodes and the retainer paths that keep objects alive.

    9.3k GitHub stars~875 tokensUpdated today
    DevelopmentAuto-check passed
  • Analyzes Chrome or Electron DevTools Performance trace exports with Python scripts to find where render time actually goes, without opening DevTools.

    9.3k GitHub stars~809 tokensUpdated today
    DevelopmentAuto-check passed
  • Parses a React DevTools Profiler JSON export with Python scripts to find re-render storms, commit fan-out and why a component rendered, without opening the DevTools UI.

    9.3k GitHub stars~978 tokensUpdated today
    DevelopmentAuto-check passed
  • Jazz UI Development

    garden-co/classic-jazz

    A skill your agent uses when building, debugging, or optimizing Jazz applications.

    2.5k GitHub stars~1.7k tokensUpdated 1 mo ago
    DevelopmentAuto-check passed
  • Implement GitHub Feature

    AgnosticUI/agnosticui

    Design and implement a new feature or component from a GitHub issue.

    826 GitHub stars~1.6k tokensUpdated 3 mo ago
    DevelopmentAuto-check passed
  • Renderdoc GPU Debug

    rudybear/renderdoc-skill

    GPU frame debugging with RenderDoc via rdc-cli. An agent skill from rudybear/renderdoc-skill.

    211 GitHub stars~4k tokensUpdated 7 mo ago
    DevelopmentAuto-check passed

More from cadence-workflow/cadence-web

  • Add Feature Flag

    cadence-workflow/cadence-web

    Add a new boolean feature flag (dynamic config key) to cadence-web.

    435 GitHub stars~1.1k tokensUpdated today
    Auto-check: notes

Works with

Categories

Questions about React Joyride

What does React Joyride do?

Guide for implementing, configuring, and debugging React Joyride v3 guided tours. React Joyride is an agent skill from cadence-workflow/cadence-web. Guide for implementing, configuring, and debugging React Joyride v3 guided tours.

When should I use React Joyride?

React Joyride fits situations like: the user mentions joyride; onboarding tour; step-by-step guide; wants to highlight UI elements sequentially.

How do I install React Joyride in Claude Code?

Run `npx skills add cadence-workflow/cadence-web --skill react-joyride -a claude-code`. Or copy the skill folder (.agents/skills/react-joyride in cadence-workflow/cadence-web) into .claude/skills/react-joyride in your project. Claude Code loads it when a task matches its description.

How do I install React Joyride in Codex?

Run `npx skills add cadence-workflow/cadence-web --skill react-joyride -a codex`. Or copy the skill folder (.agents/skills/react-joyride in cadence-workflow/cadence-web) into .agents/skills/react-joyride in your project. Codex loads it when a task matches its description.

Can I use React Joyride in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add cadence-workflow/cadence-web --skill react-joyride -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/react-joyride, .gemini/skills/react-joyride, .github/skills/react-joyride and .opencode/skills/react-joyride in your project.

What does React Joyride need to run?

SKILL.md names no scripts, command-line tools or credentials: React Joyride is instructions for the agent only.

Does React Joyride access the network?

SKILL.md names 1 domain. As links in the text: v3.react-joyride.com. This is read from the text; nothing was executed.

Is React Joyride safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does React Joyride use?

React Joyride is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does React Joyride use?

About 3.9k tokens (SKILL.md is roughly 16k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 5.7k tokens, read only when the agent opens those files.

What are the alternatives to React Joyride?

Skills that share tags, products or a category with React Joyride: Electron Heap Snapshot Analysis (keybase/client, 9.3k stars), Electron DevTools Trace Analysis (keybase/client, 9.3k stars), React DevTools Profile Analyzer (keybase/client, 9.3k stars) and Jazz UI Development (garden-co/classic-jazz, 2.5k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains React Joyride?

cadence-workflow (a GitHub organization) maintains it in cadence-workflow/cadence-web, which has 435 GitHub stars. The repository holds 2 skills in this directory. The repository was last updated on October 6, 2026.

Source: cadence-workflow/cadence-web on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.