Manual Setup
Learn how to convert an existing web project into a Cosmo widget.
While the create-cosmo-widget scaffolding tool is the easiest way to start, you can also manually configure an existing web project to work with Cosmo.
1. Install Dependencies
Install the Widget SDK for runtime type safety and utilities.
npm install @buildcosmo/widgetpnpm add @buildcosmo/widgetyarn add @buildcosmo/widgetIf you're using Vite, you can optionally install the Cosmo Vite plugin for on-desktop dev widget testing:
npm install -D @buildcosmo/vite-pluginpnpm add -D @buildcosmo/vite-pluginyarn add -D @buildcosmo/vite-plugin2. Configure Vite (Optional)
If you're using Vite, add the Cosmo plugin to your vite.config.js or vite.config.ts. This plugin handles configuration validation, asset packaging, and dev server communication for on-desktop testing.
import { defineConfig } from "vite";
import { cosmo } from "@buildcosmo/vite-plugin";
export default defineConfig({
plugins: [
// ... other plugins (e.g., react(), vue())
cosmo(),
],
});Without the Vite plugin, you can still build and test your widget, but you won't have automatic on-desktop dev widget testing integration.
3. Add Widget Configuration
Create a widget.config.json file in the root of your project. This file is required for Cosmo to recognize and load your widget.
{
"minCosmoVersion": "0.4.0",
"defaultWidth": 320,
"defaultHeight": 200,
"minWidth": 200,
"minHeight": 120,
"allowResize": true,
"keepAspectRatio": false,
"allowLockScreen": true,
"allowInternet": false
}See Widget Configuration for a full list of options.
4. Create Entry Point
Cosmo expects your widget to expose a global window.widget function. This function is called when the widget is initialized.
Modify your main entry file (e.g., src/main.jsx, src/main.ts, or src/main.js) to export this function.
function widget(preferences, widgetData) {
const app = document.querySelector('#app');
app.innerHTML = `<h1>Hello Cosmo!</h1>`;
}
window.widget = widget;
// Dev fallback: Simulate first load (widgetData is undefined)
if (import.meta.env.DEV && !window.webkit) {
widget({ theme: "Default", hideBackground: false });
}import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
let root = null;
function widget(preferences, widgetData) {
const container = document.getElementById('root');
if (!root) {
root = createRoot(container);
}
root.render(
<StrictMode>
<App preferences={preferences} initialData={widgetData} />
</StrictMode>
);
}
window.widget = widget;
// Dev fallback: Simulate first load (widgetData is undefined)
if (import.meta.env.DEV && !window.webkit) {
widget({ theme: "Default", hideBackground: false });
}import { createApp } from 'vue';
import App from './App.vue';
function widget(preferences: Record<string, any>, widgetData?: Record<string, any>) {
const app = createApp(App, {
preferences,
widgetData
});
app.mount('#app');
}
(window as any).widget = widget;
// Dev fallback: Simulate first load (widgetData is undefined)
if (import.meta.env.DEV && !(window as any).webkit) {
widget({ theme: "Default", hideBackground: false });
}Cosmo looks for window.widget. If this is not defined, your
widget will display a blank screen.
5. Run Development Server
Start your development server as usual.
npm run devIf you're using Vite with the Cosmo plugin and Cosmo's Developer Mode is enabled, it will automatically detect your local server and prompt you to open the widget on the desktop. Without the Vite plugin, you'll need to build your widget and load it manually for testing.