@ravenstudiosio/laptop-sdk
v1.0.0
Published
SDK for building apps for our FiveM laptop resource.
Downloads
6
Maintainers
Readme
Laptop SDK
Official SDK for building apps for our FiveM laptop resource.
Installation
npm install @ravenstudiosio/laptop-sdkQuick Start
Method 1: Using Hooks with Context Provider (Recommended)
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 (
<div className="p-4">
<h1>Calculator</h1>
<button onClick={handleCalculate}>Calculate & Save</button>
</div>
);
};
// Wrap with provider to enable hooks
const component = (props: AppComponentProps) => {
return (
<RavenStudiosSDKProvider value={props}>
<CalculatorContent />
</RavenStudiosSDKProvider>
);
};
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
);Method 2: Using Props (Traditional)
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 (
<div className="p-4">
<h1>Calculator</h1>
<button onClick={handleCalculate}>Calculate</button>
</div>
);
};
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
);Method 3: Using Classic Export Pattern
import type { AppComponentProps } from "@ravenstudiosio/laptop-sdk";
import { FileText } from "lucide-react";
const MyTextEditor = (props: AppComponentProps) => {
return <div>Text Editor Content</div>;
};
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 <MyTextEditor {...props} />;
};
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.
Available Hooks
useSDK()- Access all SDK APIs at onceuseWindowAPI()- Window managementuseFileSystemAPI()- File system operationsuseStorageAPI()- App-scoped storageuseDialogAPI()- System dialogsuseClipboardAPI()- Clipboard operationsuseMenuAPI()- Context menususeShortcutAPI()- Keyboard shortcutsuseIPCAPI()- Inter-process communicationuseNotificationAPI()- Toast notificationsuseSystemAPI()- System informationuseCommandAPI()- Command paletteuseProcessAPI()- Process managementuseAppInfo()- App metadata
Using Hooks
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 <button onClick={handleSave}>Save</button>;
};
const Toolbar = () => {
const windowApi = useWindowAPI();
return (
<div>
<SaveButton />
<button onClick={() => windowApi.maximize()}>Maximize</button>
</div>
);
};
// Root component wraps with provider
const component = (props: AppComponentProps) => {
return (
<RavenStudiosSDKProvider value={props}>
<div>
<h1>My App</h1>
<Toolbar />
</div>
</RavenStudiosSDKProvider>
);
};Hook Usage Examples
useSDK - Get all APIs:
const MyComponent = () => {
const { windowApi, fileSystemApi, notificationApi } = useSDK();
// Use any API you need
};useSystemAPI - React to theme changes:
const ThemeDisplay = () => {
const systemApi = useSystemAPI();
const [theme, setTheme] = useState(systemApi.getTheme());
useEffect(() => {
return systemApi.onThemeChange(setTheme);
}, [systemApi]);
return <div>Current theme: {theme}</div>;
};useShortcutAPI - Register keyboard shortcuts:
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 <div>Press Ctrl+S</div>;
};useIPCAPI - Inter-app communication:
const IPCExample = () => {
const ipcApi = useIPCAPI();
const [messages, setMessages] = useState<string[]>([]);
useEffect(() => {
return ipcApi.on("chat", (data, senderAppId) => {
setMessages((prev) => [...prev, `${senderAppId}: ${data}`]);
});
}, [ipcApi]);
const sendMessage = () => {
ipcApi.broadcast("chat", "Hello from my app!");
};
return (
<div>
<button onClick={sendMessage}>Send Message</button>
<ul>
{messages.map((m, i) => (
<li key={i}>{m}</li>
))}
</ul>
</div>
);
};Available APIs
The SDK provides 13 powerful APIs to interact with the laptop system:
1. Window API
Manage windows, dialogs, and file pickers.
const MyApp = ({ windowApi }: AppComponentProps) => {
const openNewWindow = () => {
windowApi.openWindow("New Window", <div>Content</div>, 800, 600);
};
const closeApp = () => {
windowApi.close();
};
const maximizeWindow = () => {
windowApi.maximize();
};
return (
<div>
<button onClick={openNewWindow}>Open Window</button>
<button onClick={maximizeWindow}>Maximize</button>
<button onClick={closeApp}>Close</button>
</div>
);
};2. File System API
Read, write, and manage files and folders.
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 (
<div>
<button onClick={createFile}>Create File</button>
<button onClick={readFile}>Read File</button>
<button onClick={searchFiles}>Search</button>
</div>
);
};3. Storage API
App-scoped persistent storage (in-memory).
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 (
<div>
<button onClick={saveData}>Save</button>
<button onClick={loadData}>Load</button>
<button onClick={clearData}>Clear All</button>
</div>
);
};4. Dialog API
System dialogs for user interaction.
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 (
<div>
<button onClick={showAlert}>Alert</button>
<button onClick={showConfirm}>Confirm</button>
<button onClick={showPrompt}>Prompt</button>
</div>
);
};5. Clipboard API
Copy and paste functionality.
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 (
<div>
<button onClick={copyText}>Copy</button>
<button onClick={pasteText}>Paste</button>
</div>
);
};6. Notification API
Toast notifications.
const MyApp = ({ notificationApi }: AppComponentProps) => {
const showNotification = () => {
notificationApi.notify({
title: "Success",
message: "Operation completed successfully",
});
};
return <button onClick={showNotification}>Notify</button>;
};7. Menu API
Context menus.
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 <div onContextMenu={showMenu}>Right-click me</div>;
};8. Shortcut API
Global keyboard shortcuts.
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 <div>Press Ctrl+S to save</div>;
};9. IPC API
Inter-process communication between apps.
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 <button onClick={sendMessage}>Send Message</button>;
};10. System API
System information and theme.
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 (
<div>
<p>Current theme: {theme}</p>
<button onClick={launchApp}>Open File Explorer</button>
</div>
);
};11. Command API
Register commands in the command palette.
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 <div>Press Ctrl+K and search for "Do Something Cool"</div>;
};12. Process API
Process and instance management.
const MyApp = ({ processApi }: AppComponentProps) => {
const info = processApi.getInfo();
return (
<div>
<p>Instance ID: {info.instanceId}</p>
<p>App ID: {info.appId}</p>
<p>Started: {new Date(info.startTime).toLocaleString()}</p>
</div>
);
};TypeScript Support
The SDK is fully typed with TypeScript. All APIs have complete type definitions:
import type {
AppComponentProps,
FileSystemItem,
WindowState,
SystemTheme,
// ... and many more
} from "@ravenstudiosio/laptop-sdk";Building Your App
Project Setup
- Create a new React project with Vite:
npm create vite@latest my-virtual-os-app -- --template react-ts
cd my-virtual-os-app
npm install- Install the SDK and dependencies:
npm install @ravenstudiosio/laptop-sdk
npm install lucide-react- Configure Module Federation in
vite.config.ts:
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,
},
});- Create your app in
src/AppModule.tsx:
import { createApp } from "@ravenstudiosio/laptop-sdk";
import type { AppComponentProps } from "@ravenstudiosio/laptop-sdk";
import { AppWindow } from "lucide-react";
const MyApp = (props: AppComponentProps) => {
return (
<div className="p-4">
<h1>My Laptop App</h1>
</div>
);
};
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
);