Introduction: Your First Steps into the Web OS
Welcome to Chapter 3, future Puter.js developer! In the previous chapter, we successfully set up our development environment, ensuring all the tools are ready for action. Now, it’s time to take that crucial first step: building your very own “Hello World” application within the Puter.js Web OS.
While “Hello World” might seem basic, it’s a rite of passage for every programmer. For Puter.js, it’s more than just printing text; it’s about understanding how a simple web application transforms into a full-fledged program running inside a distributed operating system. We’ll learn how your code interacts with the Puter OS to manage windows, display content, and declare itself to the system. This chapter will lay the foundational knowledge for developing truly interactive and powerful Web OS applications.
Ready to bring your first Puter.js app to life? Let’s dive in!
Core Concepts: What Makes a Puter.js App?
Before we write any code, let’s understand the fundamental building blocks and how they fit into the Puter.js Web OS ecosystem.
The Anatomy of a Puter.js Application
Unlike a traditional website that simply loads in a browser tab, a Puter.js application is designed to run as an independent “program” within the Puter OS. Think of it like a desktop application, but built entirely with web technologies (HTML, CSS, JavaScript).
Every Puter.js app typically consists of:
index.html: The main entry point for your application’s user interface. This is where your visual elements live.app.js(or similar): Your application’s brain. This JavaScript file contains the logic, handles user interactions, and crucially, communicates with the Puter OS through thePuterglobal object.style.css(optional but recommended): For styling your app and making it look beautiful.manifest.json: This is a critical file. It’s like your app’s passport and instruction manual for the Puter OS. It tells the OS essential information about your app, such as its name, version, icon, and where to find its main entry point.
The Puter Global Object: Your Gateway to the OS
When your Puter.js app runs, the Puter OS injects a special global object, simply named Puter, into your application’s JavaScript context. This Puter object is your application’s direct line of communication with the underlying operating system.
Through Puter, your application can:
- Manage its own window (size, position, title).
- Interact with the Puter file system.
- Access user information and preferences.
- Utilize OS-level UI components.
- Handle permissions and security.
We’ll be using Puter extensively, starting with simple window management.
The Application Lifecycle: Puter.app.onReady()
Just like a traditional operating system needs to prepare before launching an application, the Puter OS also has an initialization phase. Your application needs to know when the Puter OS is fully ready for it to start interacting. This is where Puter.app.onReady() comes in.
Puter.app.onReady() is a function that takes a callback. The code inside this callback will only execute after the Puter OS has finished setting up your app’s environment. This ensures that any Puter API calls you make will succeed, preventing errors and ensuring a smooth launch. It’s the equivalent of document.addEventListener('DOMContentLoaded') or window.onload for a traditional web page, but specifically for the Puter OS context.
Let’s visualize this basic structure:
Why a manifest.json is Essential
The manifest.json file is a standard JSON file that provides metadata about your application. For Puter.js, it’s crucial because:
- Identification: It gives your app a unique name and version.
- Entry Point: It tells the Puter OS which HTML file to load as the main interface for your app.
- Permissions (Future): It will eventually define what resources your app needs access to (e.g., file system, camera, network).
- Appearance: It can specify the app’s icon and other visual cues for the Puter OS desktop.
Without a valid manifest.json, the Puter OS wouldn’t know how to launch or even recognize your application!
Step-by-Step Implementation: Building “Hello, Puter.js!”
Let’s create our first Puter.js application, step by step.
Step 1: Create Your Project Folder
First, create a new directory for your app. Open your terminal or command prompt and run:
mkdir my-first-puter-app
cd my-first-puter-app
Step 2: Craft the manifest.json
Inside your my-first-puter-app folder, create a new file named manifest.json.
// my-first-puter-app/manifest.json
{
"name": "Hello Puter",
"version": "1.0.0",
"description": "My first Puter.js application!",
"main": "index.html",
"icon": "/icons/app-icon.svg",
"permissions": []
}
Explanation:
"name": The name of your application as it will appear in the Puter OS."version": The current version of your application. Always follow semantic versioning (e.g.,1.0.0)."description": A brief explanation of what your app does."main": This is the most important field for now. It tells the Puter OS which HTML file to load when your app starts."icon": Path to your app’s icon. We’ll create a placeholder for this."permissions": An array to declare necessary permissions. For now, it’s empty, as our app doesn’t need special access.
Step 3: Design the index.html
Next, create index.html in the same folder. This will be the visual canvas for our “Hello World” message.
<!-- my-first-puter-app/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello Puter App</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="app-root">
<h1>Loading...</h1>
</div>
<script src="app.js"></script>
</body>
</html>
Explanation:
- Standard HTML5 boilerplate.
- We’ve included a
<title>tag, but the actual window title will be set by the Puter OS (which we’ll control viaPuter.app). <link rel="stylesheet" href="style.css">: Links to our styling file (we’ll create it next).<div id="app-root">: A container where our JavaScript will inject content.<h1>Loading...</h1>: A temporary message until our app fully initializes.<script src="app.js"></script>: Crucially, this loads our application’s JavaScript logic. Notice it’s at the end of<body>to ensure the DOM is ready before our script tries to manipulate it.
Step 4: Add Some Style with style.css
Create style.css in the same directory. This will add some basic styling.
/* my-first-puter-app/style.css */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #282c34; /* Dark background for a Web OS feel */
color: #e0e0e0; /* Light text color */
}
h1 {
font-size: 2.5em;
text-align: center;
}
Explanation:
- Sets a modern font, centers content, and applies a dark theme, giving our app a sleek, OS-like appearance.
height: 100vh;ensures the body takes up the full viewport height, allowing for perfect centering.
Step 5: Implement the app.js Logic
Now for the core logic. Create app.js in the same folder.
// my-first-puter-app/app.js
// This function will run once the Puter OS has fully prepared our app environment.
Puter.app.onReady(() => {
// Let's greet the user!
const appRoot = document.getElementById('app-root');
if (appRoot) {
appRoot.innerHTML = '<h1>Hello, Puter.js!</h1>';
}
// Set the window title for our app.
// This will appear in the Puter OS window bar.
Puter.app.setToolbar({
title: 'My First Puter App'
});
// Optionally, set initial window properties like size.
// The Puter OS will try to honor these, but might adjust based on screen.
Puter.app.setWindowProperties({
width: 600,
height: 400,
resizable: true
});
console.log("Puter.js app is ready and running!");
});
// Any code outside of Puter.app.onReady() might run before the OS is fully initialized,
// so it's best to put all Puter API interactions inside the ready callback.
Explanation:
Puter.app.onReady(() => { ... });: This is where our application’s main logic resides. It ensures that thePuterobject and its APIs are available before we try to use them.const appRoot = document.getElementById('app-root');: We get a reference to ourdivelement fromindex.html.appRoot.innerHTML = '<h1>Hello, Puter.js!</h1>';: We dynamically update the content of our app to display our greeting.Puter.app.setToolbar({ title: 'My First Puter App' });: This important line tells the Puter OS what title to display in the window’s toolbar. This is how your app customizes its OS-level window.Puter.app.setWindowProperties({ ... });: Here, we suggest an initialwidth,height, and whether the window should beresizableto the Puter OS. The OS will then manage the actual window based on these preferences.console.log(...): A simple log to confirm our app is running.
Step 6: Create an Icon Placeholder
Our manifest.json references an icon. Let’s create a placeholder folder and a dummy file to avoid errors.
mkdir icons
touch icons/app-icon.svg
You can leave app-icon.svg empty for now, or put a simple SVG content like:
<!-- my-first-puter-app/icons/app-icon.svg -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<rect width="100" height="100" fill="#007bff"/>
<text x="50" y="60" font-family="Arial" font-size="50" fill="#fff" text-anchor="middle">P</text>
</svg>
Step 7: Run Your Puter.js App!
Now, with all files in place, it’s time to launch your masterpiece using the Puter CLI (which you installed in Chapter 2).
Navigate to the my-first-puter-app directory in your terminal and run:
puter dev .
Explanation:
puter dev: This command tells the Puter CLI to run an application in development mode..: The dot specifies that the current directory (my-first-puter-app) contains the application we want to run. The CLI will look formanifest.jsonin this directory.
Upon running this command, a new window (managed by the Puter OS emulator or local Puter runtime) should appear, displaying “Hello, Puter.js!” and having “My First Puter App” in its title bar. Congratulations! You’ve just launched your first Puter.js application!
Mini-Challenge: Personalize Your Greeting
Let’s make our “Hello World” a bit more personal and dynamic.
Challenge: Modify your app.js to greet the user by their Puter OS username. The Puter object also provides access to user information via Puter.user. The current (as of 2026-01-12) API for accessing the logged-in user’s data is Puter.user.getProfile(), which returns a Promise that resolves with user details, including a username property.
Hint:
- You’ll need to use
Puter.user.getProfile(). - Since
getProfile()returns a Promise, you’ll need to useasync/awaitor.then()to handle the asynchronous operation. - Remember to update the
appRoot.innerHTMLwith the personalized greeting.
What to observe/learn: This challenge introduces you to asynchronous operations within Puter.js and how to access user-specific data, which is fundamental for building personalized applications.
Common Pitfalls & Troubleshooting
Even simple apps can encounter issues. Here are a few common problems and how to fix them:
“Puter.js CLI command not found”:
- Cause: The Puter CLI might not be installed correctly or its path isn’t in your system’s PATH environment variable.
- Fix: Revisit Chapter 2’s installation steps. Ensure
npm install -g @puterjs/cli(or equivalent) completed successfully. You might need to restart your terminal.
“App doesn’t launch, or a blank window appears”:
- Cause A: Error in
manifest.json. The Puter CLI might fail to parse it or can’t find themainentry point. - Fix A: Double-check
manifest.jsonfor syntax errors (e.g., missing commas, unclosed quotes) and ensure"main": "index.html"correctly points to your HTML file. Theputer devcommand usually provides helpful error messages in the terminal if the manifest is malformed. - Cause B: JavaScript error in
app.jsbeforePuter.app.onReady()fires or within the callback. - Fix B: Open the browser’s developer console (usually F12 or Ctrl+Shift+I/Cmd+Option+I) when the Puter.js app window is focused. Look for red error messages. These will point to specific lines in your
app.jsorindex.html.
- Cause A: Error in
“Puter is not defined” error in
app.js:- Cause: You might be trying to access
PuterAPIs outside of thePuter.app.onReady()callback, or before the Puter OS has fully injected thePuterobject. - Fix: Ensure all interactions with
Puter(likePuter.app.setToolbarorPuter.user.getProfile) are enclosed within thePuter.app.onReady(() => { ... });block.
- Cause: You might be trying to access
Summary
You’ve successfully built and launched your very first Puter.js application! Let’s recap what you’ve learned:
- Puter.js App Structure: An app is composed of
index.html,app.js,style.css, and the vitalmanifest.json. manifest.json: Acts as the app’s metadata and configuration for the Puter OS, defining its name, version, and main entry point.- The
PuterGlobal Object: Your primary interface for interacting with the Puter OS, providing access to app, UI, user, and other system-level functionalities. Puter.app.onReady(): The essential entry point for your app’s logic, ensuring that the Puter OS environment is fully initialized before your code runs.- Window Management: You used
Puter.app.setToolbar()to customize your app’s window title andPuter.app.setWindowProperties()to suggest its size and behavior to the OS. - Puter CLI
devcommand: How to run your Puter.js application in development mode.
In the next chapter, we’ll dive deeper into core Puter.js APIs, exploring how to manage multiple windows, interact with dynamic data, and build more complex user interfaces.
References
- HeyPuter/puter GitHub Repository
- Puter Developer Documentation (Conceptual)
- MDN Web Docs: Introduction to Web APIs
- MDN Web Docs: Using promises
This page is AI-assisted and reviewed. It references official documentation and recognized resources where relevant.