I wrote a "web OS" based on the Apple Lisa's UI, with 1-bit graphics
This is a web OS I wrote in vanilla JS that looks like the Apple Lisa Office System (1983-85), with other contemporaneous influences and additional improvements and features. It's currently in alpha and isn't remotely bug free. I had been holding off on posting this here until it was somewhat presentable and useful. Please note; the Lisa conforms more literally to the desktop metaphor than most modern GUIs - some of the important differences are mentioned in the readme.
This is a complete recreation of the UI in JS; it all renders to a single canvas element. It's not a CSS theme, and not an emulator ported to JS. None of the code is written by Apple. I'll be happy to elaborate more in the comments, but the short version is the entire UI is defined outside the DOM using JS objects. Thus, every interface element - menus, windows, controls, and even typefaces - was recreated from scratch. There are no font files - I wrote my own typesetting system, which supports combining multiple text styles and generates new glyph variants on the fly.
Many of the technical decisions I made were motivated by a desire to have this look the same in every browser. That's harder to do with the DOM and CSS, and why I moved as much logic as I could to JS. Also, the only part of the project outside of vanilla JS and standard web APIs is the Gulp toolkit, which I'm using as a minification/build tool. No vibe coding was used to make this!
This is based on a UI from the 80s, and won't work well on your phone. If you insist on running it that way, turn on trackpad mode in the touchscreen settings panel of the preferences app. For best results, install it as a PWA (add it to your home screen). Also there are some odd Android bugs; the native touchscreen keyboard is currently broken, and there's an issue with the cursor when dragging windows.
I realize there's not a whole lot to do within LisaGUI right now; I've got a big list of additional features and apps I'll be adding in the future. I've been working on this project for a while, and I'm eager to hear people's feedback and answer questions about it.
The good news is, if you have a large enough low-dpi display, and you make the window big enough, the automatic integer scaling settings will kick in, and the pixels themselves will be displayed larger. This can be forced via the preferences app (under the display options). If you screw this up, then restart LisaGUI while holding the shift key to reset the scaling settings.
EDIT: Unrelated to this, there are a couple minor bugs with PWAs on iOS relating to the positioning of the canvas. These can be resolved by rotating your device to a different orientation and then rotating it back to the original position... but this is annoying.
EDIT 2: To close windows, just double click the icon in the titlebar! This "collapses the window back into an icon."
If we're talking about pixel perfect rendering there are various issues in the Web APIs that conspire against you.
devicePixelRatio (dpr) - This is supposed to tell you how many CSS pixels = one device pixel. This particular demo ignores it. On my Windows PC my dpr is 1.25 and the site looks horrendous with every other pixel 4th pixel of a font being double wide (or something along those lines). Not dissing the demo, it's cool. It's uncommon for Web devs to be aware of these issues as like 99.99% are on a Mac and never set zoom to anything other then 100%
The idea was supposed to be, you could take the CSS size and multiply by devicePixelRatio to get the display size. Unfortunately that does not work for various reasons.
There's zoom. Firefox and Chrome change the devicePixelRatio in response to zooming. Safari does not. Even if Safari supported this it's not enough. You can maybe repo how bad the site looks on my Windows PC on a Mac by zooming in on any browser (pick zoom from the menus, not pinch to zoom - see below)
Next there is pixel snapping. The short version is, imagine your window is 3 pixels wide and you ask the browser to make 2 elements side by side each 50% wide. If you check the CSS width both elements will say they are 1.5 pixels wide (getContentBoundingRect().width). But the browser won't display a 1.5 pixel element. I will snap one element 2 pixels and the other 1 pixel. To find out which is which you're supposed to use ResizeObserver with devicePixelContentBoxSize, but again Safari doesn't support this. It's not just with splits, that just the easiest way to demo the issue. Get this wrong and your checkerboard background will have a stripe somewhere where the checkerboard is missing a row or column.
Next there is pinch to zoom. It's separate and reported no where in the Web API AFAICT. The browsers will re-render text/svg to a higher resolution when you pinch to zoom but they don't pass that info to the page so it can not re-render canvases in response.
So: tl;dr, you can't - partly because of Safari. Partly because the Web is missing functionality
To get the canvas to be consistently smooth, I had to apply a lot of contrast using a CSS filter, and I set image-rendering to pixelated, IIRC.
I do something similar when dealing with raw screenshots from DOS games, which are typically 320x200, but intended for 4:3 display, so pixels are 5:6. In this case, upscaling to 1600x1200 (the smallest possible integer upscale to achieve the correct aspect ratio) with nearest-neighbor, then downscaling with bilinear to the target res (e.g. 1440x1080, 960x720, etc.) works really well.
The most common mistake is to reinterpret sRGB as if it is a linear color space, and assume that half of RGB 255,255,255 is RGB 128,128,128. But that's wrong. sRGB is a gamma-compressed color space that does not respond linearly.
First you treat all sRGB values as if they are between 0 and 1. To convert into linear RGB, take all values to the power of 2.2 (like squaring them). Then you do any math on color values in Linear RGB. For example, half of linear 1 is indeed 0.5. To convert back into sRGB, take all values to the power of 1/2.2 (like a square root).'
This means that 0.5 in linear RGB corresponds to 0.73 in sRGB. You can confirm this by placing a black and white checkerboard next to a square of RGB 186,186,186. They will match in apparent intensity (provided you have an sRGB display that doesn't have viewing angle problems).
Some graphics APIs can do the sRGB to Linear RGB conversion for you automatically, but you need to request the API to do that. This makes the pixel shader only see Linear RGB, but the pixels are coming from an sRGB texture, and are being written to an sRGB buffer as output.
Author's note: I pronounce the letters in GUI separately. Why would you ever pronounce it "gooey?" Please don't do that. Just don't.
Solidarity!
vi versus emacs, vi versus vim, (guh sound)IF versus (j sound)IF, m68k versus x86, Mac versus Amiga, BSD versus Linux, et cetera.
TUI = tooey
CLI = clee
TCP/IP = tickipip
GPT = gipity
DNS = dunce
HTTP = Hittup
USB = Oosbuh
USB-C = Oosbuhc
GPT = gipity
I'm calling foul on that one. It's "Jay pay tay". Which sounds the same as the French phrase "J'ai pété" or "I farted."
That makes me laugh more than gipity.
Also checked with an online solver and it verified that there was no solution.
Incidentally, I'm planning on adding solitaire as the next game!
Half of the random states created are solvable, and the other half are unsolvable.
My solution was not checking if the puzzle is solvable (the mathematics of this seem complicated), but starting with a solved one and then do a fixed number of random movements.
Also, I was just checking around to see if there were any good methods for telling if a puzzle is solvable without solving it. Seems geeks for geeks have some code for it.
https://www.geeksforgeeks.org/dsa/check-instance-15-puzzle-s... The only other solution I can think of is detecting both configurations (blank in bottom right or top left) and displaying something when either is reached.
IIRC, Windows 95 briefly had this in the form of a Templates folder. You added files to that folder and then you could create new copies of those files from the context menu. I don't remember it persisting into other versions of Windows.
if you want to create a document, double click on its corresponding stationery stack and a new document is created. No need to find open Excel (or LisaCalc
This is a cool idea, but not really as practical, at least, not in the way it's presented here. To create a document, you first have to have an existing template of that type. What happens if you delete all of your templates? Even in our small demo environment here, it's such an obvious flaw that the author keeps templates on a RAMdisk. But even without that problem, you have to know where your templates are saved. I was surprised to find a drawing app.
One way to potentially fix this is to just allow document creation from the global File menu. File > New > LisaType Paper. Of course, if Lisa had been successful, this would break down, too. Imagine a menu with LisaType Paper, LisaCalc Spreadsheet, Lotus Spreadsheet, Lotus Document, etc, etc.
But it is a very elegant system, and I wish we could have seen a world where this desktop metaphor survived, so we could see how those problems would have been solved.
Windows support for this survived I think until XP at least, but generally it runs the "New ..." context sub menu in Explorer.
Just Get Info on any file in the Finder, then check the "Stationary pad" box.
I just looked it up and here's an official help page about it: https://support.apple.com/en-tm/guide/mac-help/mchlp1341/mac
Something I recommend doing for the mouse cursor on mobile is to make it work like Microsoft’s Remote Desktop on iOS (possibly Android too, but I’m an iPhone user so don’t know for sure) where the cursor isn’t where you tap on the screen, but you kind of pan anywhere on the screen which proportionally moves the cursor which is somewhere not under your finger. It’s a bit hard to explain, you just need to try using RDP on Microsoft’s free Windows App on your mobile device.
If this is causing any confusion I might put a priority on saving this setting in a way where it can be applied immediately as the page is loaded.
What I'll probably do is serialize the setting data to localstorage so it's available before the system starts up and loads from IndexedDB.
Edit: doing nothing will do the autoselect. Odd
But if rotation lock is off, it's fine. Maybe there's something in the way the resolution is read that is different if the lock is on? Nothing appears in the menu bar at the top so there was no way to do anything.
Amazing efforts here though, now I can actually use it! Truly impressive.
I'm balancing historical accuracy with modern constraints with my own self-imposed technical debts, so there's bound to be compromises!
(Edit: Menus staying open after one click was a welcome improvement that I think came much later.)
There's at least one Mac extension I know of that lets you use sticky menus on earlier versions of Mac OS, like System 6. I figured I'd backport that feature a little further, so to speak...
EDIT: Also, forgot to mention it in this reply, but you double click the titlebar icon to close the window.
Setting aside specifically places something on the desktop. Save-able documents have a "save and put away" option which "refiles" it back in its folder without putting it on the desktop.
You made me realize I still need to add a separate "put away" option on all windows regardless, so there's always a menu command that can be used to refile something.
The desktop isn't a normal directory - I discuss this in the readme a bit.
Here's a picture of how far I got: https://imgur.com/a/QhnnC4X
https://datawookie.dev/blog/2019/04/sliding-puzzle-solvable/
So I appreciate when things look really cool, reminds of me Think-Pascal.
I would love to see a breakout style game or something in the demo/examples but that is my inner child speaking.
That's a good game idea. The next game I'm going to do will be solitaire. I was also thinking of trying to eventually make something like the mazewar game from the Xerox Alto to pay my respects to Xerox, although I know that will be an undertaking, especially adding in networking...
If things appear uneven, these issues may be due to viewing the screen at 1x scale on a lower-DPI display, as I mentioned in another comment. The only way for me to debug these issues is with a screenshot. You can press Windows + PrintScreen to take a screenshot on Windows, or press Command + Shift + 3 on a Mac. You can send them to me using the email link at the bottom of https://yaros.ae/ or by messaging me on Bluesky (https://bsky.app/profile/lisagui.com).
Also, I've been posting project updates to the Bluesky account, and I'll continue to do so in the future for anyone interested in keeping up with the project. There's also an RSS link on my website for anyone who's old-school and doesn't want to make a Bluesky account.
(Tested in Firefox and Chrome on desktop.)
EDIT: I'm honestly not sure what this issue might be... If you're up for sending me a screenshot, there's an email link at the bottom of https://yaros.ae/.
When you select text in a textbox, the keyboard should input text. Also, individual menu items have their own keyboard shortcuts. If you're on a PC, it defaults to using the Control key as the "Apple" key. If your on a Mac, it defaults to using the Command key. This option can be changed in the preferences app in the "Set Conveniences" pane.
One thing, though, is that it "stutters" every 15 seconds or so. Like, it pauses for a noticeable time, like hundreds of ms. The UI shows a consistent 119-120 FPS, even when this is happening.
It's possible the fault is Firefox, and not your page. I do have 64 GB of RAM, but also a zillion tabs open.
minor bugs with PWAs on iOS
There are major bugs with PWA's, and I suspect most of them stem from the tens of billions of dollars per year of app store revenue that would be undermined if PWA's actually became useful...
People asking for “I just want to have fully featured apps coming from wherever” are aplenty. Apple has pushed app snippets and in-AppStore one shot apps for a long time. These would be much better as PWAs.
Not because PWAs are inherently better. I believe native programs are superior. However history has shown that vast majority of apps are just poorly wrapped websites.
As an aside, iOS PWA support is really phoned in. For example they introduced environmental css variables for safe insets. And then provided no way to test them outside of real device or a simulator.