Skip to content

Iframe integration

A space (URL provided by Fast4) can be displayed in two ways:

  • "as it is" meaning the URL is directly loaded in the browser
  • in an iframe to be integrated in another web site

iframe

The space URL can be integrated in another web site by adding this element:

<iframe id="spacePage" title="Space page" src="http://demo.simspace.fr" frameborder="0"></iframe>

Here is a basic example to integrate the iframe:

index.html
<html>
  <head>
    <title>Space page sample</title>
    <meta http-equiv="content-type" content="text/html;charset=utf-8" />
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css"
      rel="stylesheet"
    />
    <link
      href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css"
      rel="stylesheet"
    />
    <script src="https://code.jquery.com/jquery-3.6.1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
    <script src="space.js"></script>
  </head>
  <body>
    <h1>Space page sample</h1>
    <button onclick="logout()">Logout</button>
    <div class="container">
      <iframe
        class="w-100 h-100"
        frameborder="0"
        id="spacePage"
        title="Space page"
        src="https://demo.simspace.fr"
      >
      </iframe>
    </div>
  </body>
</html>
space.js
window.onmessage = function (event) {
  // Ensure the event comes from the Simspace iframe
  if (event.origin === 'https://demo.simspace.fr') {
    if (event.data.type === 'CHAT_SCROLL') {
      window.scrollTo(0, document.body.scrollHeight)
    } else {
      toastr.info('New message received: ' + JSON.stringify(event.data))
    }
  }
}

function logout() {
  const iframe = document.querySelector('iframe')
  iframe.contentWindow.postMessage({ type: 'LOGOUT' }, 'https://demo.simspace.fr')
}

The javascript file is used to intercept the events sent by the iframe. Please refer to the details here-below.

Please ensure that the events come from the Simspace iframe by checking the origin property.

Events published by the iframe

The iframe send events to parent page through the postMessage API.

These events can be intercepted in the parent page by using the window.onmessage = function (event) {} method (see sample above).

Each event data got the type property to identify the event type (see all supported types below).

Other fields can be added depending on the event type.

Warning

Some new events can be added on futures deliveries, so you should consider not to be too strict on events types. For instance, enum are too strict, and if a new event type is added, your code will crash!

Here is the message structure in Typescript:

export type SimspacePMEvent =
  | {
      type: 'LOGIN' | 'LOGOUT'
      player: PlayerPMInfo
    }
  | {
      type: 'GAME_START' | 'GAME_ABANDON' | 'GAME_COMPLETE'
      player: PlayerPMInfo
      simulation: SimulationPMInfo
      game: GamePMInfo
    }
  | {
      type: 'SIMULATION_NOT_PLAYABLE'
      player: PlayerPMInfo
      simulation: SimulationPMInfo
    }
  | {
      type: 'GAME_PLAYER_INPUT'
      player: PlayerPMInfo
      simulation: SimulationPMInfo
      game: GamePMInfo
      step: { id: number; name: string }
      playerInput: IPlayerInput
    }
  | {
      type: 'CHAT_SCROLL'
    }

export type SimulationPMInfo = {
  id: number
  code: string
  name: string
}

export type PlayerPMInfo = {
  id: number
  identifier: string
}

export type GamePMInfo = {
  id: number
}

export type IPlayerInput =
  | {
      type: 'multiple'
      answers: IPlayerAnswer[]
    }
  | {
      type: 'single'
      answer: IPlayerAnswer
    }
  | {
      type: 'free-text'
      text: string
    }
  | {
      type: 'action'
      action: 'RESET' | 'EXIT'
    }

export interface IPlayerAnswer {
  id: number
  label: string
}

Login event

The type of this event is LOGIN.

It is sent after the player just logged in into the space. Only the player is provided for this event.

{
  "type": "LOGIN",
  "player": { "id": 10, "identifier": "user-123" }
}

Logout event

The type of this event is LOGOUT.

It is sent after the player logged out or when his session has expired. Only the player is provided for this event. You might want to listen to this event if you are responsible for logging the player programmatically through the access token mechanism.

{
  "type": "LOGOUT",
  "player": { "id": 10, "identifier": "user-123" }
}

Game start event

The type of this event is GAME_START.

It is sent when a player just start a new game.

{
  "type": "GAME_START",
  "player": { "id": 10, "identifier": "user-123" },
  "simulation": { "id": 12, "code": "my-simulation", "name": "My Simulation" },
  "game": { "id": 15 }
}

Game complete event

The type of this event is GAME_COMPLETE.

It is sent when a player just complete a game.

{
  "type": "GAME_COMPLETE",
  "player": { "id": 10, "identifier": "user-123" },
  "simulation": { "id": 12, "code": "my-simulation", "name": "My Simulation" },
  "game": { "id": 15 }
}

Game abandon event

The type of this event is GAME_ABANDON.

It is sent when a player just abandon a game.

{
  "type": "GAME_ABANDON",
  "player": { "id": 10, "identifier": "user-123" },
  "simulation": { "id": 12, "code": "my-simulation", "name": "My Simulation" },
  "game": { "id": 15 }
}

Player input in chat

The type of this event is GAME_PLAYER_INPUT.

It is sent when a player just type an input in the chat.

{
  "type": "GAME_PLAYER_INPUT",
  "player": { "id": 10, "identifier": "user-123" },
  "simulation": { "id": 12, "code": "my-simulation", "name": "My Simulation" },
  "game": { "id": 15 },
  "step": { "id": 5, "name": "my step" },
  "playerInput": {
    "type": "MULTIPLE",
    "answers": [
      { "id": 3, "label": "Lorem ipsum dolor sit amet" },
      { "id": 5, "label": "Donec sit amet mollis nibh" }
    ]
  }
}

This event has additional fields:

  • step the step in the simulation using the input (identified by its id and name)
  • playerInput the answers of the step

Simulation not playable

This event use the SIMULATION_NOT_PLAYABLE type.

This event is sent only if:

  • you use the simulation standalone mode
  • the simulations cannot be replayed

So it happens:

  • if the simulation replay option is disabled and you try to replay a simulation
  • or if the sequential simulations option is enabled and you try to start a simulation in the wrong order
{
  "type": "SIMULATION_NOT_PLAYABLE",
  "player": { "id": 10, "identifier": "user-123" },
  "simulation": { "id": 12, "code": "my-simulation", "name": "My Simulation" }
}

Chat scroll event

The type of this event is CHAT_SCROLL.

{
  "type": "CHAT_SCROLL"
}

This event is sent every time the chat automatically scrolls.

It may be used by the iframe container to adjust its own scroll, for e.g.:

window.onmessage = function (event) {
  // [...]

  if (event.data.type === 'CHAT_SCROLL') {
    window.scrollTo(0, document.body.scrollHeight)
  }
}

Events published by the parent page

The parent page mainly receive events from the iframe, but it can also send some.

The implementation is easy:

function logout() {
  const iframe = document.querySelector('iframe')
  const message = { type: 'LOGOUT' }
  iframe.contentWindow.postMessage(message, 'https://demo.simspace.fr')
}

In this example we select the unique iframe in the web page and we send it the message.

Warning

It is highly recommended to set the target parameter in postMessage. In our case, this is the iframe host.

Player logout

If you use a space with credentials, if the player is logged out from your web site you probably want to log him out from the iframe. To do so, you have to send the message { type: 'LOGOUT }.

iframe.contentWindow.postMessage({ type: 'LOGOUT' }, 'https://demo.simspace.fr')

Standalone simulation

The iframe can be used in "standalone mode", meaning the navigation buttons on game page are not displayed. This is useful if you want to only display a game without showing the simulations page.

To use this mode, you must add the query parameter standaloneSimulation=true.

https://demo.simspace.fr/player/simulations/simu-1/game?standaloneSimulation=true

The simu-1 is the unique code to identify the simulation.

This mode only works for the game page.

If the space is secured by credentials, you can use both "access-token" and "standalone mode".

https://demo.simspace.fr/player/simulations/simu-1/game?standaloneSimulation=true&accessToken=f38bbdfc-5f4f-11ed-a962-0f7cc96827e1