DEV Community

Cover image for From C++ to WASM via WebCC/Coi
artydev
artydev

Posted on

From C++ to WASM via WebCC/Coi

If, like me, you are intrigued by WASM and you don't how to step in, then give an eye to Coi

Coil let's you code you web app in a declarative way like React and compile it through C++ to WASM with the help of WebCC

I have installed the toolchain in WSL and the compilation is very fast.

There is also a VSCode extention :

import "../components/Button.coi";

component AudioPlayer {
  mut Audio audio;
  mut bool playing = false;
  mut float currentTime = 0;
  mut float duration = 0;
  mut float progress = 0;
  mut int volume = 80;

  mount {
    // Replace with your own audio file URL
    audio = Audio.createAudio(
      "https://cdn.pixabay.com/audio/2025/06/23/audio_e6a00ad257.mp3"
    );
    audio.setVolume(0.8);
    System.log("test" + duration);
  }

  tick(float dt) {
    if (playing) {
      currentTime = audio.getCurrentTime();
      duration = audio.getDuration();

      if (duration > 0) {
        progress = (currentTime / duration) * 100;
      }
    }
  }

  def togglePlay(): void {
    if (playing) {
      audio.pause();
      playing = false;
    } else {
      audio.play();
      playing = true;
      duration = audio.getDuration();
    }
  }

  def volumeUp(): void {
    if (volume < 100) {
      volume = volume + 10;

      if (volume > 100) {
        volume = 100;
      }

      float vol = volume / 100.0;
      audio.setVolume(vol);
    }
  }

  def volumeDown(): void {
    if (volume > 0) {
      volume = volume - 10;

      if (volume < 0) {
        volume = 0;
      }

      float vol = volume / 100.0;
      audio.setVolume(vol);
    }
  }

  style {
    .audio-player {
      display: flex;
      flex-direction: column;
      gap: 20px;
      padding: 40px;
      background: #fff;
      border: 1px solid #eee;
      border-radius: 12px;
      width: 280px;
    }

    .label {
      font-size: 12px;
      text-transform: uppercase;
      letter-spacing: 1px;
      color: #999;
      text-align: center;
    }

    .track-info {
      text-align: center;
    }

    .track-title {
      font-size: 18px;
      font-weight: 600;
      color: #1a1a1a;
      margin-bottom: 4px;
    }

    .track-artist {
      font-size: 13px;
      color: #666;
    }

    .album-art {
      width: 160px;
      height: 160px;
      background: linear-gradient(135deg, #9477ff 0%, #6b5ce7 100%);
      border-radius: 12px;
      margin: 0 auto;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 60px;
      box-shadow: 0 4px 15px rgba(148, 119, 255, 0.3);
    }

    .progress-container {
      display: flex;
      flex-direction: column;
      gap: 8px;
    }

    .progress-bar {
      width: 100%;
      height: 6px;
      background: #eee;
      border-radius: 3px;
      overflow: hidden;
    }

    .progress-fill {
      height: 100%;
      background: linear-gradient(90deg, #9477ff, #b19fff);
      border-radius: 3px;
      transition: width 0.1s linear;
    }

    .time-info {
      display: flex;
      justify-content: space-between;
      font-size: 12px;
      color: #666;
    }

    .controls {
      display: flex;
      justify-content: center;
      align-items: center;
      gap: 20px;
    }

    .play-btn {
      width: 56px;
      height: 56px;
      border-radius: 50%;
      background: #9477ff;
      border: none;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 20px;
      color: #fff;
      transition: all 0.2s ease;
      box-shadow: 0 4px 15px rgba(148, 119, 255, 0.4);
    }

    .play-btn:hover {
      transform: scale(1.05);
      background: #a388ff;
    }

    .volume-container {
      display: flex;
      align-items: center;
      gap: 8px;
    }

    .volume-icon {
      font-size: 16px;
      color: #666;
    }

    .volume-bar {
      flex: 1;
      height: 6px;
      background: #eee;
      border-radius: 3px;
      overflow: hidden;
    }

    .volume-fill {
      height: 100%;
      background: #9477ff;
      border-radius: 3px;
      transition: width 0.1s ease;
    }

    .volume-btn {
      width: 28px;
      height: 28px;
      border-radius: 50%;
      background: #f5f5f5;
      border: 1px solid #eee;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 14px;
      color: #666;
      transition: all 0.2s ease;
    }

    .volume-btn:hover {
      background: #9477ff;
      color: #fff;
      border-color: #9477ff;
    }

    .volume-text {
      font-size: 12px;
      color: #666;
      width: 35px;
      text-align: right;
    }
  }

  view {
    <div class="audio-player">
      <div class="label">Audio Player</div>

      <div class="album-art">🎵</div>

      <div class="track-info">
        <div class="track-title">Coify</div>
        <div class="track-artist">Demo Track</div>
      </div>

      <div class="progress-container">
        <div class="progress-bar">
          <div
            class="progress-fill"
            style="width: {progress}%;"
          ></div>
        </div>

        <div class="time-info">
          <span>{currentTime}s</span>
          <span>{duration}s</span>
        </div>
      </div>

      <div class="controls">
        <button class="play-btn" onclick={togglePlay}>
          <if playing>
            <span></span>
          <else>
            <span></span>
          </else>
          </if>
        </button>
      </div>

      <div class="volume-container">
        <span class="volume-icon">🔊</span>

        <button class="volume-btn" onclick={volumeDown}></button>

        <div class="volume-bar">
          <div
            class="volume-fill"
            style="width: {volume}%;"
          ></div>
        </div>

        <button class="volume-btn" onclick={volumeUp}>+</button>

        <span class="volume-text">{volume}%</span>
      </div>
    </div>
  }
}


app { root = AudioPlayer; }
Enter fullscreen mode Exit fullscreen mode

Then compile the code (very fast:

python:~/coi/example/src/demos$ coi AudioPlayer.coi  --out ./dist
Processing /home/python/coi/example/src/demos/AudioPlayer.coi...
Processing /home/python/coi/example/src/components/Button.coi...
All files processed. Total components: 2
Generated ./dist/app.css
Running: webcc /tmp/coi_build/app.cc --out /home/python/coi/example/src/demos/./dist --cache-dir /tmp/coi_build/webcc_cache --template /tmp/coi_build/index.template.html
[WebCC] Loading definitions from compiled-in schema...
[WebCC] Loaded 130 commands and 17 events.
[WebCC] Scanning source files for features...
  -> Found get_body (dom), embedding JS support.
  -> Found create_element (dom), embedding JS support.
  -> Found set_attribute (dom), embedding JS support.
  -> Found append_child (dom), embedding JS support.
  -> Found remove_element (dom), embedding JS support.
  -> Found set_inner_text (dom), embedding JS support.
  -> Found add_click_listener (dom), embedding JS support.
  -> Found log (system), embedding JS support.
  -> Found set_main_loop (system), embedding JS support.
  -> Found open_url (system), embedding JS support.
  -> Found create_audio (audio), embedding JS support.
  -> Found play (audio), embedding JS support.
  -> Found pause (audio), embedding JS support.
  -> Found set_volume (audio), embedding JS support.
  -> Found get_current_time (audio), embedding JS support.
  -> Found get_duration (audio), embedding JS support.
[WebCC] Generated /home/python/coi/example/src/demos/./dist/app.js
[WebCC] Using template: /tmp/coi_build/index.template.html
[WebCC] Generated /home/python/coi/example/src/demos/./dist/index.html
[WebCC] Compiling...
  [CC] /tmp/coi_build/app.cc
  [CC] /home/python/webcc/src/core/command_buffer.cc
  [CC] /home/python/webcc/src/core/event_buffer.cc
  [CC] /home/python/webcc/src/core/scratch_buffer.cc
  [CC] /home/python/webcc/src/core/libc.cc
[WebCC] Linking...
[WebCC] Success! Run 'python3 -m http.server' in /home/python/coi/example/src/demos/./dist to view.
Enter fullscreen mode Exit fullscreen mode

Here is the output, magic!!! :

python@:~/coi/example/src/demos/dist$ ls -rtl
total 64
-rw-r--r-- 1 python python  4460 Jan 11 14:05 app.css
-rw-r--r-- 1 python python   298 Jan 11 14:05 index.html
-rw-r--r-- 1 python python 13789 Jan 11 14:05 app.js
-rwxr-xr-x 1 python python 34063 Jan 11 14:05 app.wasm
Enter fullscreen mode Exit fullscreen mode

Note the size of the wasm file.

Click below to experiment the demo:

Top comments (0)