Lifecycle and saves

A calm experience is also a well-behaved one. It starts quickly, rests when nobody is looking, never loses a save and never writes one twice.

The handshake

  1. The platform loads your entry with #zc_parent=…&zc_instance=… in the hash.
  2. connect() sends zc.ready with your id and version every 250 milliseconds until it is answered.
  3. The platform checks your id, version and protocol against the approval and answers zc.connected with the context and a private port, or rejects you.
  4. From then on, every call goes through that port. If your page reloads, the session ends and the visitor starts again from the platform.

Be ready within 15 seconds

Call loading.start() first and loading.ready() as soon as the visitor can begin. Load heavy assets after that. If you are not ready after 15 seconds, the platform tells the visitor something is wrong. If you cannot start, call loading.fail(message).

Lifecycle commands

CommandWhat to do
pauseStop sound, animation and input. Report paused.
resumeContinue where the visitor left off. Report running.
visibilitySent once after connecting and then on every change. When visible is false, rest as if paused.
disposeStop timers and let the SDK flush your saves. The frame is removed as soon as you answer, or after one second at most.

Report the session, don't count time

Call session.report({state, mode}) whenever the state changes, and repeat it every few seconds while it runs. The platform measures time from these reports on the server. It stops counting when it hears paused, or when it hears nothing for 12 seconds.

Revisions protect every save

Each save has a revision that grows by one with every write. You pass the revision you last saw. If someone else wrote in the meantime, such as another tab or another device, the write fails with CONFLICT instead of overwriting their progress.

Retry with the same request id

A TIMEOUT or INTERNAL error doesn't mean the write failed, only that you don't know. Send the same data again with the same requestId. The server returns the first result instead of writing twice. Reusing an id with different data fails with IDEMPOTENCY_CONFLICT.

Let autosave set the pace

storage.createAutosave(save) calls your function at most once per interval: 10 seconds by default, anywhere from 10 seconds to 5 minutes. Call schedule() whenever something changes. On pause, hide and dispose, and before a run is finished or the visitor leaves, the SDK flushes right away. After three failed attempts it reports SAVE_UNCONFIRMED through onError. Return false from your function if newer changes still need a save.

When the channel closes

onDisconnect fires once. Keep what the visitor sees, stop saving and say gently that they can reopen the experience to continue. Never try to reconnect on your own.