Web Specific Notes

Supported Features

With “OpenSiv3D for Web,” you can use the almost features which is supported in OpenSiv3D for Linux. For details, check out Implementation Status

File Systems

Your WebGL apps cannot access any files on users’ file system.

Those files required on running your WebGL apps, can be bundled on building with emcc’s --preload option. These bundled files are loaded into a virtual file system; then you can access these files on ordinal way.

Features that Differs Other Platforms

Network

Only connecting to external websocket server is supported. Make sure to use secured websocket server in secured (https://) pages.

  const IPv4Address ip = IPv4Address::Localhost();
  constexpr uint16 port = 50000;

  TCPClient client;

  client.connect(ip, port);

  Point serverPlayerPos{ 0, 0 };
  const Point clientPlayerPos = Cursor::Pos();
  
  // send
  client.send(clientPlayerPos);

  //
  // Not Supported that polling with `client.read`.
  // Polling will freeze the browser. 
  //
  // while (client.read(serverPlayerPos));
  //

  // recv
  client.read(serverPlayerPos);

Multi-Threading

Unsupported Texture Format

In mobile browsers, generating textures of format TextureFormat::R32_Float will be failed due to the mobile hardware limitation. Consider using TextureFormat::R16G16_Float formatted textures instead.

Features that Requires User Actions

Some features are required to use on user actions.

  • Dialog::*
  • ClipBoard::ReadText, SetText
  • Window::SetFullscreen
  • VideoReader (on Safari)
  • System::LaunchBrowser
//
// will enter fullscreen on first user action after invoking `Window::SetFullscreen`
// Window::SetFullscreen(true);
//

if (SimpleGUI::Button(U"Full Screen", Point{ 20, 20 }))
{
  //
  // SimpleGUI::Button()` will be true on user `click` actions,
  // invocation of `Window::SetFullscreen` will work expectedly.
  //
  Window::SetFullscreen(true);
}

Features that can be Written Differently from Other Platforms

GameLoop

With emscripten Asyncify, we can let a browser handle JavaScript events in the infinite game loop.

# include <Siv3D.hpp>

void Main()
{
  // initializations here...

  while (System::Update())
  {
    // more tasks on each frames..
  }
}

Another strategy is to register the function as a callback with s3d::Platform::Web::System::SetMainLoop, which is called at the start of an animation frame.

# include <Siv3D.hpp>

void Main()
{
  // initializations here...

  Platform::Web::System::SetMainLoop([&]()
  {
    System::Update();
    // more tasks on each frames..
  });
}

File Save Dialog

s3d::Dialog::Save will always return “/dev/save” pseudo device, which means that you cannot query users which file format they want to download.

Features that uses AsyncTask

Some features, such as AudioDecoding or Clipboard, blocks the main loop for several seconds.

Audio Decoding

s3d::Platforms::Web::AudioProcessing::DecodeAudioFromFile returns AsyncTask<Audio>.

  // 
  // Maybe blocks for several seconds
  //
  // Audio audio { "/example/test.mp3" };
  Audio audio;
  AsyncTask<Audio> audioTask = s3d::Platforms::Web::AudioDecoder::DecodeFromFile("/example/test.mp3");

  // check if audio decoding has been finished
  if (audioTask.isReady())
  {
    audio = audioTask.get();
  }

File Open Dialog

s3d::Platforms::Web::Dialog::Open** returns AsyncTask<**>.

  // 
  // Maybe blocks for several seconds
  //
  // Audio audio = Dialog::OpenAudio();
  Audio audio;
  AsyncTask<Audio> audioTask = s3d::Platforms::Web::Dialog::OpenAudio();

  // check if user has been selected file and decoding audio is finished
  if (audioTask.isReady())
  {
    audio = audioTask.get();
  }

Clipboard

Only test copying and pasting are supported. (and in FireFox, this feature is disallowed.)

s3d::Platforms::Web::Clipboard::GetText returns AsyncTask<String>. (You can use s3d::Clipboard::SetText in ordinal way.)

  // 
  // Maybe blocks for several seconds
  //
  // String text;
  // 
  // if (Clibboard::GetText(text))
  // {
  //
  // }
  AsyncTask<String> textTask;
  String text;

  textTask = Platforms::Web::Clipboard::GetText();

  // check if text has been pasted from clipboard
  if (textTask.isReady())
  {
    text = textTask.get();
  }