SDK for building apps for our FiveM laptop resource.
npm install @ravenstudiosio/laptop-sdkbash
npm install @ravenstudiosio/laptop-sdk
`
Quick Start
$3
`tsx
import {
createApp,
RavenStudiosSDKProvider,
useFileSystemAPI,
useNotificationAPI,
} from "@ravenstudiosio/laptop-sdk";
import type { AppComponentProps } from "@ravenstudiosio/laptop-sdk";
import { Calculator } from "lucide-react";
// Child component can use hooks
const CalculatorContent = () => {
const fileSystemApi = useFileSystemAPI();
const notificationApi = useNotificationAPI();
const handleCalculate = () => {
fileSystemApi.createFile("/Home", "result.txt", "2 + 2 = 4");
notificationApi.notify({
title: "Calculation Complete",
message: "Result saved to file",
});
};
return (
Calculator
);
};
// Wrap with provider to enable hooks
const component = (props: AppComponentProps) => {
return (
);
};
export default createApp(
{
id: "my-calculator",
name: "Calculator",
icon: Calculator,
category: "Utilities",
description: "A simple calculator app",
version: "1.0.0",
isSystem: false,
isDownloadable: true,
downloadSize: 2.5,
publisher: "Your Name",
defaultWidth: 400,
defaultHeight: 500,
},
component
);
`
$3
`tsx
import { createApp } from "@ravenstudiosio/laptop-sdk";
import type { AppComponentProps } from "@ravenstudiosio/laptop-sdk";
import { Calculator } from "lucide-react";
const MyCalculatorApp = ({
windowApi,
fileSystemApi,
notificationApi,
}: AppComponentProps) => {
const handleCalculate = () => {
notificationApi.notify({
title: "Calculation Complete",
message: "2 + 2 = 4",
});
};
return (
Calculator
);
};
export default createApp(
{
id: "my-calculator",
name: "Calculator",
icon: Calculator,
category: "Utilities",
description: "A simple calculator app",
version: "1.0.0",
isSystem: false,
isDownloadable: true,
downloadSize: 2.5,
publisher: "Your Name",
defaultWidth: 400,
defaultHeight: 500,
},
MyCalculatorApp
);
`
$3
`tsx
import type { AppComponentProps } from "@ravenstudiosio/laptop-sdk";
import { FileText } from "lucide-react";
const MyTextEditor = (props: AppComponentProps) => {
return Text Editor Content;
};
const metadata = {
id: "text-editor",
name: "Text Editor",
icon: FileText,
category: "Productivity" as const,
description: "Simple text editor",
version: "1.0.0",
isSystem: false,
isDownloadable: true,
};
const component = (props: AppComponentProps) => {
return ;
};
export default {
metadata,
component,
};
`
React Hooks API
The SDK provides React hooks for a modern, ergonomic developer experience. Use these hooks to access SDK APIs anywhere in your component tree without prop drilling.
$3
- useSDK() - Access all SDK APIs at once
- useWindowAPI() - Window management
- useFileSystemAPI() - File system operations
- useStorageAPI() - App-scoped storage
- useDialogAPI() - System dialogs
- useClipboardAPI() - Clipboard operations
- useMenuAPI() - Context menus
- useShortcutAPI() - Keyboard shortcuts
- useIPCAPI() - Inter-process communication
- useNotificationAPI() - Toast notifications
- useSystemAPI() - System information
- useCommandAPI() - Command palette
- useProcessAPI() - Process management
- useAppInfo() - App metadata
$3
`tsx
import {
RavenStudiosSDKProvider,
useFileSystemAPI,
useNotificationAPI,
useWindowAPI,
} from "@ravenstudiosio/laptop-sdk";
// Deeply nested component
const SaveButton = () => {
const fileSystemApi = useFileSystemAPI();
const notificationApi = useNotificationAPI();
const handleSave = () => {
fileSystemApi.createFile("/Home", "data.txt", "My data");
notificationApi.notify({
title: "Saved",
message: "File saved successfully",
});
};
return ;
};
const Toolbar = () => {
const windowApi = useWindowAPI();
return (
);
};
// Root component wraps with provider
const component = (props: AppComponentProps) => {
return (
My App
);
};
`
$3
useSDK - Get all APIs:
`tsx
const MyComponent = () => {
const { windowApi, fileSystemApi, notificationApi } = useSDK();
// Use any API you need
};
`
useSystemAPI - React to theme changes:
`tsx
const ThemeDisplay = () => {
const systemApi = useSystemAPI();
const [theme, setTheme] = useState(systemApi.getTheme());
useEffect(() => {
return systemApi.onThemeChange(setTheme);
}, [systemApi]);
return Current theme: {theme};
};
`
useShortcutAPI - Register keyboard shortcuts:
`tsx
const ShortcutExample = () => {
const shortcutApi = useShortcutAPI();
const notificationApi = useNotificationAPI();
useEffect(() => {
const unregister = shortcutApi.register(
"Ctrl+S",
() =>
notificationApi.notify({ title: "Save", message: "Ctrl+S pressed!" }),
{ description: "Save file", global: true }
);
return unregister;
}, [shortcutApi, notificationApi]);
return Press Ctrl+S;
};
`
useIPCAPI - Inter-app communication:
`tsx
const IPCExample = () => {
const ipcApi = useIPCAPI();
const [messages, setMessages] = useState([]);
useEffect(() => {
return ipcApi.on("chat", (data, senderAppId) => {
setMessages((prev) => [...prev, ${senderAppId}: ${data}]);
});
}, [ipcApi]);
const sendMessage = () => {
ipcApi.broadcast("chat", "Hello from my app!");
};
return (
{messages.map((m, i) => (
- {m}
))}
);
};
`
Available APIs
The SDK provides 13 powerful APIs to interact with the laptop system:
$3
Manage windows, dialogs, and file pickers.
`tsx
const MyApp = ({ windowApi }: AppComponentProps) => {
const openNewWindow = () => {
windowApi.openWindow("New Window", Content, 800, 600);
};
const closeApp = () => {
windowApi.close();
};
const maximizeWindow = () => {
windowApi.maximize();
};
return (
);
};
`
$3
Read, write, and manage files and folders.
`tsx
const MyApp = ({ fileSystemApi, notificationApi }: AppComponentProps) => {
const createFile = () => {
fileSystemApi.createFile("/Home", "document.txt", "Hello World");
notificationApi.notify({
title: "File Created",
message: "document.txt created successfully",
});
};
const readFile = () => {
const file = fileSystemApi.getItemByPath("/Home/document.txt");
if (file && file.type === "file") {
console.log("Content:", file.content);
}
};
const searchFiles = () => {
const results = fileSystemApi.searchItems("document");
console.log("Found:", results);
};
return (
);
};
`
$3
App-scoped persistent storage (in-memory).
`tsx
const MyApp = ({ storageApi }: AppComponentProps) => {
const saveData = () => {
storageApi.set("user-preference", { theme: "dark", fontSize: 14 });
};
const loadData = () => {
const prefs = storageApi.get("user-preference", { theme: "light" });
console.log("Preferences:", prefs);
};
const clearData = () => {
storageApi.clear();
};
return (
);
};
`
$3
System dialogs for user interaction.
`tsx
const MyApp = ({ dialogApi, notificationApi }: AppComponentProps) => {
const showAlert = async () => {
await dialogApi.alert({
title: "Information",
message: "This is an informational message",
});
};
const showConfirm = async () => {
const confirmed = await dialogApi.confirm({
title: "Delete File?",
message: "This action cannot be undone.",
});
if (confirmed) {
console.log("User confirmed");
}
};
const showPrompt = async () => {
const name = await dialogApi.prompt({
title: "Enter your name:",
defaultValue: "John Doe",
});
if (name) {
notificationApi.notify({
title: "Hello",
message: Welcome, ${name}!,
});
}
};
return (
);
};
`
$3
Copy and paste functionality.
`tsx
const MyApp = ({ clipboardApi, notificationApi }: AppComponentProps) => {
const copyText = () => {
clipboardApi.writeText("Hello from Virtual OS!");
notificationApi.notify({
title: "Copied",
message: "Text copied to clipboard",
});
};
const pasteText = () => {
const text = clipboardApi.readText();
console.log("Pasted:", text);
};
return (
);
};
`
$3
Toast notifications.
`tsx
const MyApp = ({ notificationApi }: AppComponentProps) => {
const showNotification = () => {
notificationApi.notify({
title: "Success",
message: "Operation completed successfully",
});
};
return ;
};
`
$3
Context menus.
`tsx
const MyApp = ({ menuApi }: AppComponentProps) => {
const showMenu = (e: React.MouseEvent) => {
menuApi.showContextMenu(
[
{ id: "cut", label: "Cut", onClick: () => console.log("Cut") },
{ id: "copy", label: "Copy", onClick: () => console.log("Copy") },
{ id: "sep", label: "", type: "separator" },
{ id: "paste", label: "Paste", onClick: () => console.log("Paste") },
],
{ x: e.clientX, y: e.clientY }
);
};
return Right-click me;
};
`
$3
Global keyboard shortcuts.
`tsx
const MyApp = ({ shortcutApi, notificationApi }: AppComponentProps) => {
useEffect(() => {
const unregister = shortcutApi.register(
"Ctrl+S",
() => {
notificationApi.notify({
title: "Save",
message: "File saved!",
});
},
{ description: "Save file", global: true }
);
return unregister;
}, [shortcutApi, notificationApi]);
return Press Ctrl+S to save;
};
`
$3
Inter-process communication between apps.
`tsx
const MyApp = ({ ipcApi, notificationApi }: AppComponentProps) => {
useEffect(() => {
// Listen for messages
const unsubscribe = ipcApi.on("my-channel", (data, senderAppId) => {
console.log("Received from", senderAppId, ":", data);
});
return unsubscribe;
}, [ipcApi]);
const sendMessage = () => {
ipcApi.broadcast("my-channel", {
message: "Hello from my app!",
timestamp: Date.now(),
});
};
return ;
};
`
$3
System information and theme.
`tsx
const MyApp = ({ systemApi }: AppComponentProps) => {
const [theme, setTheme] = useState(systemApi.getTheme());
useEffect(() => {
const unsubscribe = systemApi.onThemeChange((newTheme) => {
setTheme(newTheme);
});
return unsubscribe;
}, [systemApi]);
const launchApp = () => {
systemApi.launchApp("file-explorer");
};
return (
Current theme: {theme}
);
};
`
$3
Register commands in the command palette.
`tsx
const MyApp = ({ commandApi }: AppComponentProps) => {
useEffect(() => {
commandApi.registerCommands([
{
id: "my-app-action",
label: "Do Something Cool",
description: "Performs a cool action",
execute: () => {
console.log("Command executed!");
},
},
]);
return () => {
commandApi.unregisterCommands(["my-app-action"]);
};
}, [commandApi]);
return Press Ctrl+K and search for "Do Something Cool";
};
`
$3
Process and instance management.
`tsx
const MyApp = ({ processApi }: AppComponentProps) => {
const info = processApi.getInfo();
return (
Instance ID: {info.instanceId}
App ID: {info.appId}
Started: {new Date(info.startTime).toLocaleString()}
);
};
`
TypeScript Support
The SDK is fully typed with TypeScript. All APIs have complete type definitions:
`tsx
import type {
AppComponentProps,
FileSystemItem,
WindowState,
SystemTheme,
// ... and many more
} from "@ravenstudiosio/laptop-sdk";
`
Building Your App
$3
1. Create a new React project with Vite:
`bash
npm create vite@latest my-virtual-os-app -- --template react-ts
cd my-virtual-os-app
npm install
`
2. Install the SDK and dependencies:
`bash
npm install @ravenstudiosio/laptop-sdk
npm install lucide-react
`
3. Configure Module Federation in vite.config.ts:
`typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { federation } from "@module-federation/vite";
export default defineConfig({
server: {
port: 5001,
strictPort: true,
origin: "http://localhost:5001",
},
base: "http://localhost:5001",
plugins: [
react(),
federation({
name: "my-app",
filename: "remoteEntry.js",
manifest: true,
exposes: {
"./app": "./src/AppModule.tsx",
},
shared: {
react: { singleton: true, requiredVersion: "^19.0.0" },
"react-dom": { singleton: true, requiredVersion: "^19.0.0" },
"lucide-react": { singleton: true },
},
}),
],
build: {
modulePreload: false,
target: "chrome89",
minify: false,
cssCodeSplit: false,
},
});
`
4. Create your app in src/AppModule.tsx:
`tsx
import { createApp } from "@ravenstudiosio/laptop-sdk";
import type { AppComponentProps } from "@ravenstudiosio/laptop-sdk";
import { AppWindow } from "lucide-react";
const MyApp = (props: AppComponentProps) => {
return (
My Laptop App
);
};
export default createApp(
{
id: "my-app",
name: "My App",
icon: AppWindow,
category: "Utilities",
description: "My awesome app",
version: "1.0.0",
isSystem: false,
isDownloadable: true,
},
MyApp
);
``