# Introduction

Windows XP in JavaScript, with a File System, programs, custom file picker and saver dialogs, 3rd-party program, etc.

*Microsoft and Windows XP trademarks & logos definitely belong to Microsoft Corporation. All the programs' names and logos (Foxit, Word, WinRar, Internet Explorer, etc.) are of their rightful copyright holders. **win32.run** is purely for the purpose of nostalgia. I have no intent and no right to monetize **win32.run**, but you may occasionally see ads when playing third-party games.*

\
**WIN32.RUN** runs solely on the client-side (the user's browser). All files are processed right in the user's browser. There is no file uploading, no server-side processing (cause I'm broke, can't afford it). Each user has his own OS session (just like the good old Windows XP)

Files (and Folders) in win32.run are stored locally in IndexedDB. Apps (and 3rd-party apps) can interact with files through win32.run homemade file picker and saver dialog (with Windows XP appearance).

{% embed url="<https://static.win32.run/video/win32_2x.mp4>" %}


# Acknowledgements

win32.run is built on [Svelte](https://github.com/sveltejs/svelte)/[SvelteKit](https://github.com/sveltejs/kit) and [Tailwindcss](https://github.com/tailwindlabs/tailwindcss). All the Windows XP icons were recreated in high resolution by [March Mountain](https://www.deviantart.com/marchmountain/art/Windows-XP-High-Resolution-Icon-Pack-916042853)

Other open-source libraries, code snippets used in this project:

* [dragselect](https://github.com/ThibaultJanBeyer/DragSelect) An easy JavaScript library for selecting and moving elements. With no dependencies.
* [idb-keyval](https://github.com/jakearchibald/idb-keyval) A super-simple-small promise-based keyval store implemented with IndexedDB
* [jszip](https://github.com/Stuk/jszip) Create, read and edit .zip files with Javascript
* [short-uuid](https://github.com/oculus42/short-uuid) Translate standard UUIDs into shorter formats and back.
* [libarchivejs](https://github.com/nika-begiashvili/libarchivejs) Archive library for browsers
* [tui.image-editor](https://github.com/nhn/tui.image-editor) Full-featured photo image editor using canvas.
* [docx](https://github.com/dolanmiu/docx) Easily generate .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.
* [Koodo Reader](https://github.com/troyeguo/koodo-reader) A modern ebook manager and reader
* [jspaint](https://github.com/1j01/jspaint) Classic MS Paint
* [ruffle](https://github.com/ruffle-rs/ruffle) A Flash Player emulator written in Rust
* [tinymce](https://github.com/tinymce/tinymce) (the MS Word UI part) JavaScript library for rich text editing.
* [svelte-sortablejs](https://github.com/jhubbardsf/svelte-sortablejs) Svelte wrapper for SortableJS
* [svelte-range-slider-pips](https://github.com/simeydotme/svelte-range-slider-pips) Multi-Thumb, Accessible, Beautiful Range Slider with Pips
* [minesweeper](https://github.com/amyngyn/minesweeper) A JavaScript implementation of the Minesweeper game.&#x20;
* Visualizations (used in Media Player Classic): [Spheres on a noisy sphere](https://codepen.io/prisoner849/pen/KKRONqp), [Points](https://codepen.io/prisoner849/pen/RwyzrVj), [Harmonic](https://codepen.io/TomHinton/pen/MWGqqMN), [Hyperbolic](https://codepen.io/TomHinton/pen/GRdBVZm), [Threejs Particle](https://codepen.io/alvalau/pen/ExLEEeK), [Smoke Filled Room](https://codepen.io/TomHinton/pen/xxjpJMp), [We kissed as the sky fell in](https://codepen.io/TomHinton/pen/VwxMvGJ), [Your actual body](<https://codepen.io/foretoo/pen/WNzPjgo >), [I still walk the same street at night](https://codepen.io/TomHinton/pen/BardWZj), [Misjudged your limits](https://codepen.io/TomHinton/pen/abqvjgZ), [Meet me there](https://codepen.io/TomHinton/pen/vYdOdrL), [Tender](<https://codepen.io/toshiya-marukubo/pen/JjOYmxG >)
* Pens (in `some stuff.zip`)  [3D Room](https://codepen.io/ricardoolivaalonso/pen/mdPzrpe), [Glassmorphism Creative Cloud App Redesign](https://codepen.io/TurkAysenur/pen/ZEpxeYm), [Neumorphic Elements](https://codepen.io/myacode/pen/PoqQQNM), [Portal scene](https://codepen.io/aderaaij/pen/BapYONL), [TinyPolyWorld.](https://codepen.io/Zultan/pen/mwGZBP)

## License

win32.run published under MIT License. This applies only to the portion of code that I wrote. Libraries, code snippets, artworks, photos, icons and sounds from others are still under their respective licenses.

## Contact

For general inquiries, bug reports or feature requests, please open an issue on win32.run [Github page](https://github.com/ducbao414/win32.run.cf)


# Files Transfer

## From host computer to win32.run

As stated in the Introduction section, each user has their own session and all the files are stored in their browser, there's no data uploading involved.

To transfer files from your computer to win32, drag & drop them to a folder or the desktop (win32's desktop).&#x20;

{% embed url="<https://static.win32.run/video/file_copying.mp4>" %}

## From win32 back to host

To download files back to your computer, right click on the file -> Send to -> Local Computer (Download)

Download is a misnomer since files are never uploaded to the server. They are always stored in your browser through IndexedDB


# Developers

This section is intended for developers


# Run, build & deploy

```
git clone https://github.com/ducbao414/win32.run.cf.git
cd win32.run.cf
npm install
```

#### Dev server

```
npm run dev
```

Runs at `http://localhost:3000`.

#### Build

```
npm run build
```

#### Preview production build

```
npm run preview
```

#### Deploy to Cloudflare Pages

The easiest way is directly through the Cloudflare dashboard — no CLI needed:

1. Push your fork to GitHub
2. Go to [Cloudflare Dashboard](https://dash.cloudflare.com/) → **Workers & Pages** → **Create** → **Pages** → **Connect to Git**
3. Select your repository
4. Under **Build settings**, choose **SvelteKit** as the framework preset — it will fill in the build command and output directory automatically
5. Click **Save and Deploy**

Cloudflare will build and deploy on every push to your main branch from that point on.


# Spaghetti Code

Though I do use JS in automating part of my workflow, I'm not really a developer. Since win32.run doesn't conform to any architectural pattern (I honestly don't know about this stuff), its codebase is a mess.&#x20;

\**One quick disturbing spoile*r: sometimes you see camelCase, the other times it's snake\_case. I don't know what I was thinking. Truely sorry for that.

In case you already have an up & running webapp (website) and want to run it on win32.run, please read [3rd-party apps](/developers/3rd-party-apps) section for integration, so you don't have to deal with this dirty codebase.

But if you're interested in expanding or customizing win32.run, this section will try to explain some parts of my spaghetti code.


# Code Structure

UI components, utility functions, shared data structures and configurations reside in `src/lib`

Assets and static content (embedded html page used in some programs) reside in `static`

Application starting point: `src/routes/index.svelte`, this page handles the general load/unload of the UI.&#x20;

Upon its boot, `src/routes/index.svelte` will load `src/routes/boot_manager.svelte`, which is the boot options scene.&#x20;

At this point, if you select `Start Windows Normally`, the `src/routes/xp/starting.svelte` will be loaded into the scene.

## starting.svelte

`src/routes/xp/starting.svelte`

If this is the first time use, it will bootstrap the user's *hard drive* with hard\_drive.json. It also preloads static assets (wallpapers, icons, audios, etc.) and some components like context menus.

Then it loads `src/routes/xp/desktop.svelte`

## desktop.svelte

`src/routes/xp/desktop.svelte`

The desktop environment. It's the container for the workspace, taskbar, start menu, etc.

`desktop.svelte` also listens for system-wide commands (at the moment: shutdown, restart) and handles writing changes made by users and programs to the disk (IndexedDB)

## work\_space.svelte

`src/routes/xp/work_space.svelte`

The screen -  (taskbar + startmenu) in terms of screen estate.

It launches programs into the workspace on request.

## /programs

`src/routes/xp/programs`

This folder contains all the *native* programs (apps, like Foxit Reader, MS Word). It's just my code organizing, if you write a new program, you don't necessarily put your `your_program.svelte` in this folder.

In case you already have an up & running webapp (website), please read [3rd-party apps](/developers/3rd-party-apps) section for integration, so you don't have to deal with win32.run codebase.


# System Variables

System-wide configurations (file types icons, list of default desktop wallpapers, open with menu, etc.) are set in `src/lib/system.js`

For data that need to be communicated across the system, win32.run uses [Svelte Stores](https://svelte.dev/tutorial/writable-stores). (`src/lib/store.js`). These data structures allow any page to subscribe and listen to their changes.

**Example 1:** any page can request to launch a program with

```javascript
import { queueProgram } from '$lib/store.js'
queueProgram.set(program_details);
```

`src/routes/xp/work_space.svelte` listens to these requests and launches the requested program

```javascript
import { queueProgram } from '$lib/store.js'

queueProgram.subscribe(program_details => {
    if(program_details == null){
        return;
    }
    launch(program_details);
})
```

**Example 2:** the hard drive `hardDrive` (in src/lib/store.js) is also a Svelte Store (actually it's just the inventory of files and folders, the real files' contents are saved in IndexedDB).

Any *native* program can make updates to win32 hard drive with `hardDrive.update(...)` or `hardDrive.set(...).` (Though you should use utilities functions in `$lib/fs.js` like `fs.save_file, fs.del_fs, fs.new_fs_item`)

`src/routes/xp/programs/my_computer.svelte` subscribes to its changes and updates its UI accordingly


# Working with Files

## Structure

Files & folders in win32.run shared the same structure. I'm not good at naming, let's call them `fs_item`

To get a fs\_item from id

```javascript
import { hardDrive } from '$lib/store.js';

let id = '1Ggc8cPyxmAqp5tqKdo3s9';
let fs_item = $hardDrive[id];
```

Each fs\_item is identified with an id. Here's the general structure of a fs\_item

```javascript
{
    id: String,
    //used to identify a fs_item
    
    basename: String,
    //name of the item without extension
    
    ext: String,
    //extension. e.g. .jpg, .png
    
    name: String,
    // = basename + ext. :) now I'm ashamed at this redundancy
    
    size: Number,
    //item size, in Kilobytes
    
    date_created: Number,
    //timestamp of the Date when item was first created,
    
    date_modified: Number,
    //timestamp of the Date when item was last modified,
    
    storage_type: String,
    //possible values include 'local' and 'remote'
    //local: the content of the file is stored locally in IndexedDB as File
    //remote: the content is on a web address (https or http)
    
    url: String,
    //if the storage_type is local, url is a id point to a File object
    //in IndexedDB
    //if the storage_type is remote, url is the web address of the file
    
    parent: String,
    //id of the parent folder (the folder that contains this fs_item)
    
    children: [String],
    //list of its children fs_items' ids
    //if it's a file, then children is a empty array
}
```

## Operations

It's recommended that you use `$lib/fs.js` instead of working with files manually.

When I wrote this fs.js file, I didn't intend for its functions to be used by another human being, so it's pretty messed up there, without any code comments. Shame on me.

```javascript
import * as fs from '$lib/fs.js';
```

### Create

This function creates a new fs\_item (can create both file and folder), returns a promise that resolves with the newly created fs\_item id.

```javascript
let fs_item_id = await fs.new_fs_item(type, ext, seedname, parent_id, file);
```

* `type: String`: can be '`file`' to create a new file, or '`folder`' to create a new folder
* `ext: String:` the `fs_item` extension, start with a dot. e.g: .jpg, .png. Leave an empty string `''` if `type == 'folder'`
* `seedname: String:` suggested file name. e.g: '`nevada desert'.`
* `parent_id: String:` id of the parent folder where the newly created item will be located.
* `file: File:` the actually file content. See [Mozilla Docs](https://developer.mozilla.org/en-US/docs/Web/API/File)

### Copy

To actually copy a fs\_item, use `fs.clone_fs()`

```javascript
fs.clone_fs(item_id, new_parent_id, new_item_id)
```

* `item_id: String`: the fs\_item id that you want to copy
* `new_parent_id: String`: id of the destination directory (folder)
* `new_item_id: String`: provide the newly created item an id so you can refer to it later. Sorry for this inconvenience.

To generate an id:

```javascript
import short from 'short-uuid';
let id = short.generate();
```

Note: The `fs.copy`, `fs.cut` functions are used to put an item into the clipboard. These functions don't actually copy or cut an item.

### Delete

To permanently delete a fs\_item

```javascript
fs.del_fs(item_id)
```

### Save

To save content to a fs\_item

```javascript
await fs.save_file(fs_item_id, file)
```

In which `file` is the new content as a File object. See [Mozilla Docs](https://developer.mozilla.org/en-US/docs/Web/API/File)

Example:

```javascript
let text = '<h1>Hello World</h1>';
let file = new File([text], 'any_name.html', {type: 'text/html'});

let fs_item_id = '1Ggc8cPyxmAqp5tqKdo3s9';

await fs.save_file(fs_item_id, file); 
```

### Read

To read content of a fs\_item, use `fs.get_file(item_id)`. This function returns a promise that resolves with a File object. See [Mozilla Docs](https://developer.mozilla.org/en-US/docs/Web/API/File).

```javascript
let file = await fs.get_file(item_id);
//file is a File object

let text_content = await file.text();//read file as text
```

### fs\_item's id to human-readable path

If you have a fs\_item's id (e.g. `1Ggc8cPyxmAqp5tqKdo3s9`) and want to convert it into a human-readable path like what is being displayed in My Computer `D:\webpages\any_name.html`&#x20;

```javascript
import * as finder from '$lib/finder.js';

let fs_item_id = '1Ggc8cPyxmAqp5tqKdo3s9';
let path_str = finder.to_url(fs_item_id);
//return value is D:\webpages\any_name.html
```

### human-readable path to fs\_item id

If you have path (for example `D:\webpages\any_name.html` ) and want to get the fs\_item id out of it

```javascript
import * as finder from '$lib/finder.js';

let path_str = 'D:\\webpages\\any_name.html';
//the double backslash \\ is for escaping \
//the actual path_str is D:\webpages\any_name.html

let fs_item_id = finder.to_id(path_str);
//returns 1Ggc8cPyxmAqp5tqKdo3s9

//then you can use this id to save, copy or delete the file
```


# Open a program with a file

As mentioned in the [System Variables](/developers/spaghetti-code/system-variables) section, work\_space.svelte is the one that handles all the requests to launch programs. To open a file with a program:

```javascript
import {hardDrive, queueProgram} from '$lib/store.js'

let fs_item_id = '';
let fs_item = $hardDrive[fs_item_id];//get the fs_item 

queueProgram.set({
    path: './programs/notepad.svelte',
    fs_item: fs_item
}) 
//request work_space.svelte to open the above fs_item with notepad
//by setting queueProgram
```

In the above example, the `path` './programs/notepad.svelte' is not the actual path of notepad.svelte file.

It's just a unique string for `work_space.svelte` to identifies the requested program, in this case, notepad. Please see `launch` function in work\_space.svelte for all registered programs. You can add your own too.

As long as it's being registered in `launch` function of `work_space.svelte`, any unique string can be used as `path` for launching a program


# 3rd-party apps

Users can install 3rd-party webapp via the Installer (it's on the desktop)

Developers who want their existing webapps to interact with win32 filesystem can do it with ease. It's simple, just adding a few lines of code to your existing webapps to pick, read & and write files.

Internally, 3rd-party webapps on win32.run are embedded inside [iframe](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe). In order to render your webapp, the `X-Frame-Options` header should not to be set.

Just open the Installer on win32.run desktop, fetch and install your webapp. If it works, then you're good to go.

*If you can't locate the Installer on the desktop, you might find it in the Start Menu.*

### Installation

### NPM

```sh
npm i win32-run-api
```

### Or Script Tag

```html
<script src="https://win32.run/js/api/0.js"></script>
```

### Initialization

3rd-party webapps communicate with win32 through [window.postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage), therefore you should instantiate Win32 class when the window object is available. i.e. `onMount` in Svelte, `componentDidMount` in React.

But for whatever reason you can't, just put the initialization where you see fit. The communication channel will be setup later when it can.

```javascript
let win32 = new Win32();
```

## Check if your webapp is running on win32.run

To check if your webapp is running on win32.run (as compared to running in its own browser tab)

```javascript
win32.is_it() //returns a Boolean
```

You can use it to update the UI and logic of your webapp accordingly. Of course this method can't be run during server side rendering.


# Pick Files

Let the user pick files through win32.run Files Picker dialog.

```javascript
await win32.pick_files(desc, exts, multiple);
```

### Params

#### desc

`String`

Description of the files you want to pick. It will be displayed to the user.

```javascript
let desc = 'Whatever, any files';
```

#### exts

`[String]`

Acceptable file extensions, case-insensitive. Each extension starts with a dot character.

```javascript
let exts = ['.txt', '.html', '.md'];
```

Specify an empty array \[] to accept any extension

#### multiple

`Boolean`

Default to `true`

Whether to allow the user to select multiple or single file.

### Returns

`Promise<[Object]>`

A promise that resolves with an array of objects. Each object has the following structure.

```javascript
{
    id: String, 
    //id of the file on win32.run
    //which can be used to retrieve the file later 
    //without invoking the Files Picker dialog. See Get File section

    win32_name: String, 
    //display name of the file on win32.run. 
    //could be different to name in file.name

    win32_path: String, 
    //path of the file on win32.run. 
    //it just for display purpose (like in My Computer). 
    //GET request to win32_path will not return the file content

    file: File
    //a File object, 
    //see https://developer.mozilla.org/en-US/docs/Web/API/File
}
```

This method will always return a promise of an array, regardless of the `multiple` value

### Example

```javascript
let results = await win32.pick_files('Any plain text files', ['.txt', '.html', '.md'], true);

//read text content of the first file using File.text()
let content = await results[0].file.text();
```

<figure><img src="/files/8bxrBRJJE7CSeXCj3qrJ" alt=""><figcaption></figcaption></figure>


# Save File As

Save a file to win32.run through File Saving Dialog

```javascript
await win32.save_file_as(file, types)
```

### Params

#### file

`File`

Content of the file you want to save to win32. A File object. See [Mozilla Docs](https://developer.mozilla.org/en-US/docs/Web/API/File)

#### types

`[Object]`

win32.run allows users to save a file as different mimetypes. For example: text can be save as regular .txt plain text (text/plain) or .html webpage (text/html)

<pre class="language-javascript"><code class="lang-javascript"><strong>types = [
</strong>     {desc: 'Plain Text', mime: 'text/plain', ext: '.txt'},
     {desc: 'Webpage', mime: 'text/html', ext: '.html'}
]
</code></pre>

### Return

`Promise<String>`

Promise that resolves with id of the saved file, which can be used to retrieve the file later without invoking the Files Picker dialog.

### Example

```javascript
let text_content = '<h1>This is a heading of a webpage</h1>';
let file = new File([text_content], '_'); 
let types = [
     {desc: 'Plain Text', mime: 'text/plain', ext: '.txt'},
     {desc: 'Webpage', mime: 'text/html', ext: '.html'}
];
let id = await win32.save_file_as(file, types);
```

<figure><img src="/files/qO0o2ZYVkHM7bf8zl5M4" alt=""><figcaption></figcaption></figure>


# Get File

Get a file on win32.run by its id without invoking Files Picker dialog

```javascript
await win32.get_file(id);
```

### Params

#### id

`String`

id of the file. Refer to [Pick Files](/developers/3rd-party-apps/pick-files#returns)

### Return

`Promise<Object>`

A win32 file object, as described in [Pick Files](/developers/3rd-party-apps/pick-files#returns)


# Save File

Save a file without invoking File Saving Dialog.

Similar to `win32.get_file` method, you have to have a win32 file id first, which could obtain when you first save the file using or `win32.pick_files` or `win32.save_file_as`

```javascript
await win32.save_file(file, id)
```

### Params

#### file

`File`

Content of the file you want to save to win32. A File object. See [Mozilla Docs](https://developer.mozilla.org/en-US/docs/Web/API/File)

#### id

`String`

id of the file. Refer to [Pick Files](/developers/3rd-party-apps/pick-files#returns)

### Return

`Promise<Void>`


