# How to Use Time Travel in Loro

In Loro, you can call `doc.checkout(frontiers)` to jump to the version specified
by the
frontiers([Learn more about frontiers](/docs/advanced/version_deep_dive#frontiers)).

Note that using `doc.checkout(frontiers)` to jump to a specific version places
the document in a detached state, preventing further edits. To learn more, see
[_Attached/Detached Status_](/docs/advanced/doc_state_and_oplog#attacheddetached-status).
To continue editing, reattach the document to the latest version using
`doc.attach()`. This design is temporary and will be phased out once we have a
more refined version control API in place.

## Read-only Time Travel

Below we demonstrate how to implement simple, read-only time-travel. You could,
for example, combine this with a slider in a UI to allow users to view the document
over time.

### Enable Timestamps

Before this example will work, it is important that the edits made to the document
have had [timestamp storage](/docs/advanced/timestamp) enabled:

```ts no_run
doc.setRecordTimestamp(true);
```

This makes sure that all changes to the document will have a timestamp added to it.
We will use this timestamp to sort changes so that the ordering will match user
intuition.

### Implementing Time Travel

The first step is to load our document. Here we assume that you have a snapshot from your database
or API.

```ts no_run
// Get the snapshot for your doc from your database / API
let snapshot = fetchSnapshot();

// Import into a new document
const doc = new LoroDoc();
doc.import(snapshot);
```

Next we must collect and sort the timestamps for every change in the document. We want uesrs to be
able to drag a slider to select a timestamp out of this list.

```ts no_run
// Collect all changes from the document
const changes = doc.getAllChanges();

// Get the timestamps for all changes
const timestamps = Array.from(
  new Set(
    [...changes.values()]
      .flat() // Flatten changes from all peers into one list
      .map((x) => x.timestamp) // Get the timestamp from each peer
      .filter((x) => !!x),
  ),
);

// Sort the timestamps
timestamps.sort((a, b) => a - b);
```

Next we need to make a helper function that will return a list of
[Frontiers](/docs/advanced/version_deep_dive#frontiers) for any timestamp.

For each peer that has edited a document, there is a list of changes by that peer. Each change has a
`counter`, and a `length`. That `counter` is like an always incrementing version number for the
changes made by that peer.

A change's `counter` is the starting point of the change, and the `length` indicates how much the
change incremented the counter before the end of the change.

The frontiers are the list of counters that we want to checkout from each peer. Since we are going
for a timeline view, we want to get the highest counter that we know happned before our timestamp
for each peer.

Here we make a helper function to do that.

```ts
const getFrontiersForTimestamp = (
  changes: Map<string, Change[]>,
  ts: number,
): { peer: string; counter: number }[] => {
  const frontiers = [] as { peer: string; counter: number }[];

  // Record the highest counter for each peer where it's change is not later than
  // our target timestamp.
  changes.forEach((changes, peer) => {
    let counter = -1;
    for (const change of changes) {
      if (change.timestamp <= ts) {
        counter = Math.max(counter, change.counter + change.length - 1);
      }
    }
    if (counter > -1) {
      frontiers.push({ counter, peer });
    }
  });
  return frontiers;
};
```

Finally, all we can get the index from our slider, get the timestamp from our list, and then
checkout the calculated frontiers.

```ts no_run
let sliderIdx = 3;
const timestamp = timestamps[sliderIdx - 1];
const frontiers = getFrontiersForTimestamp(changes, timestamp);

doc.checkout(frontiers);
```

## Time Travel With Editing

Below is a more complete example demonstrating Time Travel functionality with a node editor.

<iframe
  src="https://loro-react-flow-example.vercel.app/"
  onClick={() => {
    window.clarity?.("event", "play-time-travel");
  }}
  style={{
    width: "100%",
    height: 500,
    border: 0,
    borderRadius: 8,
    marginTop: 16,
    overflow: "hidden",
    filter: "invert(1) hue-rotate(180deg)",
  }}
  title="https://twitter.com/zx_loro/loro-react-flow-example/main"
  allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
  sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>