# ProcessNode

Represent a step in a workflow with an explicit idle, running, success, or error state.

Page: https://20cuts.com/docs/components/process-node

## Installation

Run from your product repository:

```sh
npx -y https://20cuts.com/releases/v0.3.0/20cuts-create-0.3.0.tgz video/20cuts
cd video/20cuts
npm ci
npm run studio
```

The installer includes this component, its source dependencies, runnable examples,
and skills for Codex and Claude Code. If 20cuts is already installed, import the
component from its existing source directory.

## Usage

```tsx
import { ProcessNode } from "./system/motion";

export default function VideoScene() {
  return (
    <ProcessNode title="Render" rows={["Frames complete", "Ready to share"]} state="success" width={340} />
  );
}
```


## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| title (required) | string | None | Name of the workflow step. |
| rows | readonly string[] | [] | Supporting rows below the title. |
| state | "idle" \| "running" \| "success" \| "error" | "idle" | Visible workflow status. |
| accent | string | "#62972d" | CSS color for running and successful states. |
| width | number | 300 | Width in pixels. |
| style | CSSProperties | None | Styles applied to the component wrapper. |

The state prop controls the display. Derive changes from the Remotion frame in the parent composition.

## Complete example

This is the source of the fictional component demonstration. Replace its content
with supported behavior and assets from your product.

```tsx
import React, { type CSSProperties, type ReactNode } from "react";

import { AbsoluteFill, useCurrentFrame, useVideoConfig } from "remotion";

import { ProcessNode } from "./system";

const ink = "#141414", lime = "#b6f36b";

const center: CSSProperties = { display: "flex", alignItems: "center", justifyContent: "center" };

function Stage({ children, dark = false, style }: {
    children: ReactNode;
    dark?: boolean;
    style?: CSSProperties;
}) {
    return <AbsoluteFill style={{ fontFamily: "Arial, Helvetica, sans-serif", color: dark ? "#fff" : ink, background: dark ? ink : "#f7f7f5", ...center, ...style }}>{children}</AbsoluteFill>;
}

export function ProcessNodeExample() { const t = useCurrentFrame() / useVideoConfig().fps; return <Stage><div style={{ display: "flex", gap: 26 }}><ProcessNode title="Source" rows={["Screens captured", "Assets ready"]} state="success"/><ProcessNode title="Render" rows={["Sequence assembled", t > 2 ? "Frames complete" : "Frames processing"]} state={t > 2 ? "success" : "running"}/><ProcessNode title="Publish" rows={[t > 3 ? "Review complete" : "Waiting for render", t > 3 ? "Ready to share" : "Not published"]} state={t > 3 ? "success" : "idle"}/></div></Stage>; }
```

Save it as src/ProcessNodeExample.tsx. This demonstration uses
1280×720, 30fps and 180 frames.
For a separate entry point, replace src/index.tsx with this registration, then
run npm run studio:

```tsx
import { Composition, registerRoot } from "remotion";
import { ProcessNodeExample } from "./ProcessNodeExample";

registerRoot(() => (
  <Composition
    id="ProcessNodeExample"
    component={ProcessNodeExample}
    width={1280}
    height={720}
    fps={30}
    durationInFrames={180}
  />
));
```

## Source

- https://20cuts.com/animation-system/library/source/motion/surfaces.tsx
- https://20cuts.com/animation-system/library/source/motion/core.ts

## Agent instructions

Use the 20cuts ProcessNode component in this project's Remotion composition. Represent one real workflow stage as a node and derive its visible state from the scene's timeline; use concise rows. Keep motion frame-driven and put timing in seconds relative to the current Sequence. Use the product's actual copy and assets. Preview the composition before rendering.
