Yes, that's essentially what I've done here:
The emulator is written in C++ and the emulator framebuffer is rendered via OpenGL calls through emscripten's GL-to-WebGL wrapper.
The buttons on the left border are done via regular handwritten HTML5+CSS, and there's also file drag'n'drop implemented in Javascript via the HTML5 drag'n'drop API. The C++ emulator code exposes a few C functions to the Javascript side to "remote-control" the C++ side from the JS side.
For instance: you can open the browser's devtools JS console and type "yakc_toggle_crt()", this is a C function which is made visible to JS via EMSCRIPTEN_KEEPALIVE, and which toggles the CRT shader effect on and off (all implemented on the C/C++ side), and the HTML5 "CRT" button in the bottom calls this function in its onclick handler.
The starting points in the emscripten docs for this type of stuff are:
- EMSCRIPTEN_KEEPALIVE (make a C function visible from the Javascript side)
- EM_JS and EM_ASM ("magic" C macros to embed Javascript code into C code)
...but in general, all of this is also possible to do yourself via EMSCRIPTEN_KEEPALIVE and EM_JS, the emscripten-provided functions just also handle a lot more edge cases. But understanding the low-level "do-it-yourself" approach is important for HTML5 APIs that are not covered by emscripten (for instance drag'n'drop).
Cheers,
-Floh.