{"id":35688,"date":"2022-04-26T16:04:21","date_gmt":"2022-04-26T20:04:21","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=35688"},"modified":"2022-04-27T14:37:41","modified_gmt":"2022-04-27T18:37:41","slug":"infinite-mac","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2022\/04\/26\/infinite-mac\/","title":{"rendered":"Infinite Mac"},"content":{"rendered":"<p><a href=\"https:\/\/blog.persistent.info\/2022\/03\/blog-post.html\">Mihai Parparita<\/a> (<a href=\"https:\/\/twitter.com\/mihai\/status\/1509718311403241474\">tweet<\/a>, <a href=\"https:\/\/news.ycombinator.com\/item?id=30875259\">Hacker<\/a> <a href=\"https:\/\/news.ycombinator.com\/item?id=31168646\">News<\/a>):<\/p>\n<blockquote cite=\"https:\/\/blog.persistent.info\/2022\/03\/blog-post.html\">\n<p>I&rsquo;ve extended James Friend&rsquo;s in-browser Basilisk II port to create a full-featured classic 68K Mac in your browser. You can see it in action at <a href=\"https:\/\/system7.app\/\">system7.app<\/a> or <a href=\"https:\/\/macos8.app\">macos8.app<\/a>.<\/p>\n<p>[&#8230;]<\/p>\n<p>At this point I switched my approach to downloading pieces of the disk image on demand, instead of all upfront. After some <a href=\"https:\/\/github.com\/mihaip\/infinite-mac\/commit\/7ea4f6e6bf762ec59f53ff76b239d5adb0ae3cbd\">false<\/a> <a href=\"https:\/\/github.com\/mihaip\/infinite-mac\/commit\/a304dab9bb330d84d56c7b9f595fa5b962dceff2\">starts<\/a>, I settled on <a href=\"https:\/\/github.com\/mihaip\/infinite-mac\/commit\/2992609ac3e86f595796759fb8aec6c1c354b298\">an approach<\/a> where the disk image is broken up into fixed-size content-addressed 256K chunks. Filesystem requests from Emscripten are intercepted, and when they involve a chunk that has not been loaded yet, they are sent off to a service worker who will load the chunk over the network. Manually chunking (as opposed to <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Range_requests\">HTTP range requests<\/a>) allows each chunk to be Brotli-compressed (ranges technically support compression too, but it&rsquo;s <a href=\"https:\/\/stackoverflow.com\/a\/53135659\/343108\">lacking<\/a> in the real world). Using content addressing makes the large number of identical chunks from the empty portion of the disk map to the same URL. There is also basic <a href=\"https:\/\/github.com\/mihaip\/infinite-mac\/commit\/d537786c9916182b7bd578448a061674ae9ba84c\">prefetching support<\/a>, so that sequential reads are less likely to be blocked on the network.<\/p>\n<p>Along with some <a href=\"https:\/\/github.com\/mihaip\/infinite-mac\/commit\/01a78bf70b6a14d969036f0a72bb67289a88bf80\">old fashioned web optimizations<\/a>, this makes the emulator show the Mac&rsquo;s boot screen in a second, and be fully booted in 3 seconds, even with a cold HTTP cache.<\/p>\n<p>[&#8230;]<\/p>\n<p>While Emscripten has an <a href=\"https:\/\/emscripten.org\/docs\/api_reference\/Filesystem-API.html#filesystem-api-idbfs\">IDBFS mode<\/a> where changes to the filesystem are persisted via IndexedDB, it&rsquo;s not a good fit for the emulator, since it relies on there being an event loop, which is not the case in the emulator worker. Instead I used an approach <a href=\"https:\/\/github.com\/mihaip\/infinite-mac\/commit\/0899205dba8fc3104f6a4f65a1714816720fe67b\">similar to uploading<\/a> to send the contents of a third ExtFS &ldquo;Saved&rdquo; directory, which can then be persisted using IndexedDB on the browser side.<\/p>\n<\/blockquote>\n<p>It includes BBEdit 2, CodeWarrior 4, GraphicConverter, Hotline, KPT Bryce, Netscape, and lots of games.<\/p>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2022\/04\/14\/bbedit-turns-30\/\">BBEdit Turns 30<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2020\/07\/30\/macintosh-js\/\">macintosh.js<\/a><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Mihai Parparita (tweet, Hacker News): I&rsquo;ve extended James Friend&rsquo;s in-browser Basilisk II port to create a full-featured classic 68K Mac in your browser. You can see it in action at system7.app or macos8.app. [&#8230;] At this point I switched my approach to downloading pieces of the disk image on demand, instead of all upfront. After [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2022-04-26T20:04:31Z","apple_news_api_id":"ae918298-68ad-432c-afae-2db28fb4e67f","apple_news_api_modified_at":"2022-04-27T18:37:45Z","apple_news_api_revision":"AAAAAAAAAAAAAAAAAAAAAA==","apple_news_api_share_url":"https:\/\/apple.news\/ArpGCmGitQyyvri2yj7Tmfw","apple_news_coverimage":0,"apple_news_coverimage_caption":"","apple_news_is_hidden":false,"apple_news_is_paid":false,"apple_news_is_preview":false,"apple_news_is_sponsored":false,"apple_news_maturity_rating":"","apple_news_metadata":"\"\"","apple_news_pullquote":"","apple_news_pullquote_position":"","apple_news_slug":"","apple_news_sections":"\"\"","apple_news_suppress_video_url":false,"apple_news_use_image_component":false,"footnotes":""},"categories":[2],"tags":[154,1404,1396,733,1340,598,295,400,346,30,923,854,74,138,1184,96],"class_list":["post-35688","post","type-post","status-publish","format-standard","hentry","category-technology","tag-bbedit","tag-codewarrior","tag-disk-image","tag-emulator","tag-glider-pro","tag-graphicconverter","tag-history","tag-hotline","tag-javascript","tag-mac","tag-mac-os-8","tag-netscape","tag-opensource","tag-optimization","tag-the-oregon-trail","tag-web"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/35688","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/comments?post=35688"}],"version-history":[{"count":2,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/35688\/revisions"}],"predecessor-version":[{"id":35711,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/35688\/revisions\/35711"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=35688"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=35688"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=35688"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}