anchor.diff:            print('action: $offset $action');
             action.perform(_palette[action.inkType]);
   
  -
  +          // TODO: should this check be here?
  +          if (!ff.isFastForwarding) {
  +            _offsetActions.add(OffsetAction(offset, action));
  +          }
           });
   
  -        _script(_palette);
  -
  -        // TODO: could publish a "loading" event here so UI can react to all the
  -        // rapid-fire events accordingly
  -        var record = _version.actions;
  -        var lastOffset = Duration.zero;
  -
  -        for (var recorded in record) {
  -          Future.delayed(lastOffset = recorded.offset, () {
  -            var action =
  -                _palette.serializers.deserialize(recorded.action) as Action;
  -            replayedActions.add(action);
  -          });
  -        }
  -
  -        Future.delayed(lastOffset, () => replayedActions.close());
  +        _stopwatch.start();
  +        script(_palette);
  +        var lastOffset = load();
   
           ff.fastForward(lastOffset);
         });
       });
     }
  +
  +  Stream<OffsetAction> get offsetActions => _offsetActions.stream;
   
     void pause() {
       _pausableZone.pause();
  
positive.code:   }
  
    List<String> saves() {}
  }
  
  class Story {
    final String storyId;
    final Script _script;
    final PausableZone _pausableZone;
    final Palette _palette;
    final Stream<Action> _actions;
    final Stopwatch _stopwatch;
  
    StreamSubscription _actionsSubscription;
    Version _version;
  
    Story(this.storyId, this._script, this._palette, this._stopwatch,
        this._actions, Stream<RecordedAction> record)
        : _pausableZone = PausableZone(() => _stopwatch.elapsed) {
      _stopwatch.start();
      _start(record);
    }
  
    void _start(Stream<RecordedAction> record) {
      var fastForwarder = FastForwarder(() => _pausableZone.offset);
      var replayedActions = StreamController<Action>(sync: true);
  
      // TODO: move this?
      _palette.events.listen(
          (event) => print('event: ${fastForwarder.currentOffset} $event'));
  
      var actions = Rx.concat([replayedActions.stream, _actions]);
  
      _pausableZone.run((c) {
        fastForwarder.runFastForwardable((ff) {
  
negative.code:   void run(Narrator n) {}
  }
  
  class OffsetAction {
    final Duration offset;
    final Action action;
  
    OffsetAction(this.offset, this.action);
  }
  