VSTDOCSv0.0.17

DOCS / GETTING STARTED

Your plugin, in React

Integrating VSReacT into an existing plugin takes one component: construct a vsreact::RootView in your editor, point it at your bundle, and add it like any juce::Component.

The editor side

PluginEditor.cpp
vsreact::RootOptions options;
options.bundleFile = juce::File ("path/to/ui/build/main.js"); // dev: watched
options.watchForChanges = true;                               // hot reload
options.onNativeCall = [this] (const juce::String& name,
                               const juce::var& args) -> juce::var
{
    if (auto handled = bridge.handleNativeCall (name, args)) // APVTS binding
        return *handled;

    if (name == "app:version")
        return juce::var (ProjectInfo::versionString);        // your own calls

    return {};
};

root = std::make_unique<vsreact::RootView> (std::move (options),
                                            std::move (registry));
bridge.attach (*root);   // pushes DAW-side param changes to useParameter
addAndMakeVisible (*root);
setSize (520, 340);

Every field of RootOptions is documented in the C++ API reference. Resizing the editor relayouts the whole Yoga tree — a resizable plugin needs nothing extra.

The React side

render(<App />) mounts your tree into the RootView. There is no HTML and no DOM — the primitives are View, Text, Image, TextInput, and NativeView, laid out by Yoga and painted by C++.

ui/src/main.tsx
import { render, View, Text } from "@vsreact/core";

function App() {
  return (
    <View className="flex-1 items-center justify-center bg-zinc-950">
      <Text className="text-2xl font-bold">Hello, host.</Text>
    </View>
  );
}

render(<App />);

Bundling with Bun

QuickJS runs ES2023, so no transpilation gymnastics are needed — one flat IIFE bundle:

ui/package.json (scripts)
{
  "scripts": {
    "build": "bun build src/main.tsx --outfile build/main.js --format iife",
    "watch": "bun build src/main.tsx --outfile build/main.js --format iife --watch"
  }
}
Pure-JS npm packages that target ES2023 bundle right in. Anything expecting the DOM, Node APIs, or the network will not — by design, a plugin UI should be deterministic and offline.

When the bundle throws

If your bundle throws — at load or later inside an effect — the plugin does not die silently: VSReacT renders a red error overlay with the message and stack trace right inside the plugin window. console.log routes to the native logger, so your debugger’s output window shows JS logs alongside C++ ones.