FullStacked

Getting started

Install

The app, on any device:

Beta builds, to try what’s next (see Releases for the channels):

The app opens on the shell, a terminal where your projects live. Its commands include git, npm, bundle, run, fullstacked, ls, cd, vi, ssh, curl and config. Run help for the full list.

The CLI, on a desktop with Node.js:

npm install -g fullstacked

Safe mode

If a project takes over the app and you can’t get back to the shell, restart in safe mode. It closes the open projects and reopens the shell, ignoring the initialDirectory setting.

Platform Keyboard Touch
macOS Cmd+Shift+T  
iOS, iPadOS Cmd+Shift+T Hold three fingers on the screen for 1.5s
Android, ChromeOS Ctrl+Shift+T Hold three fingers on the screen for 1.5s
Windows Ctrl+Shift+T  
Linux Ctrl+Shift+T, or start with --safe  
CLI fullstacked --safe  

The shortcut is caught by the app before the page, so a project can’t take it over.

A first project

In the shell or a terminal:

mkdir hello
cd hello

Create index.ts:

import fs from "node:fs";
import os from "node:os";

// Node's APIs...
fs.writeFileSync(
    "/visits.txt",
    String(
        Number(
            fs.existsSync("/visits.txt")
                ? fs.readFileSync("/visits.txt", "utf8")
                : 0
        ) + 1
    )
);
const visits = fs.readFileSync("/visits.txt", "utf8");

// ...and the DOM, in the same file
const h1 = document.createElement("h1");
h1.innerText = `Hello from ${os.platform()}, visit #${visits}`;
document.body.append(h1);

Run it:

fullstacked

The project is bundled into out/ and opens in a window: a new window in the app, or your browser at http://localhost:9000 with the CLI. /visits.txt is a file in the project directory, which is the root of the project’s sandbox.

With npm packages and React

npm install react react-dom

Add a tsconfig.json so JSX uses the automatic runtime:

{ "compilerOptions": { "jsx": "react-jsx" } }
// index.tsx
import { createRoot } from "react-dom/client";
import { useState } from "react";
import { readdir } from "node:fs/promises";

function App() {
    const [files, setFiles] = useState<string[]>([]);
    return (
        <>
            <button onClick={async () => setFiles(await readdir("/"))}>
                List files
            </button>
            <ul>
                {files.map((f) => (
                    <li key={f}>{f}</li>
                ))}
            </ul>
        </>
    );
}

const root = document.createElement("div");
document.body.append(root);
createRoot(root).render(<App />);

In the app’s shell, npm install runs the core’s installer, so no Node is needed on the device. On a desktop, plain npm works too.

Clone and run an existing project

git clone https://github.com/<owner>/<repo>.git
cd <repo>
npm install
fullstacked

Next