21 ms·
Show HN: Starboard – Fully in-browser literate notebooks like Jupyter Notebook
- protoduction 6y agoHi HN, I developed Starboard over the past months. Cell-by-cell notebooks like Jupyter are great for prototyping, explaining and exploration, but their dependence on a Python server (with often undocumented dependencies) limits their ability to be shared and remixed. Now that browsers support dynamic imports, it has become possible to create a similar workflow entirely in the browser. That motivated me to build Starboard Notebook, a tool I wished existed. It's: * Run entirely in the browser, there is no server or setup, it's all static files. * Web-native, so no widget system is necessary. There is nearly no magic, it's all web tech (HTML, CSS, JS). * Stores as a plaintext file, it will play nicely with version control systems. * Hackable: the sandbox that your code gets run in contains the editor itself, so you can metaprogram the editor itself (e.g. adding support for other languages such as Python through WASM). * Open source (https://github.com/gzuidhof/starboard-notebook https://github.com/gzuidhof/starboard-notebook). You can import any code that targets the browser directly (e.g. puts stuff on the window object), or that has exports in ES module format. I'm happy to answer any questions!
- jarmitage 6y agoGreat stuff! Congrats on launching. Can it be combined with https://svelte.dev https://svelte.dev? Would be great for reactivity and cheaply creating visualisations.
- benrbray 6y agoThere's also SolidJS which is a promising alternative to Svelte! [1] https://github.com/ryansolid/solid https://github.com/ryansolid/solid [2] https://indepth.dev/exploring-the-state-of-reactivity-patterns-in-2020/ https://indepth.dev/exploring-the-state-of-reactivity-patter...
- rguiscard 6y agoIt is indeed a good work. The barebone demo is an empty notebook. How could I loaded a locally saved notebook ? Should I loaded it through javascript API or embed it in the index.html ? Thanks.
- rguiscard 6y agoTo answer my own question, just set window.initialNotebookContent before calling starboard-notebook.js.
- protoduction 6y agoCorrect, or you can set it as a property on the starboard-notebook web component HTML element.
- angleofrepose 6y agoThanks for sharing, this is a cool project. I've been working on something similar on and off for a while, and I've found the space to be fascinating and somewhat puzzling. Most of the first questions I try to ask about these in browser notebooks don't have clean answers. In no particular order: - Do you have any ideas about solving logic errors? As it stands right now a while(true) loop crashes the page and consecutive re-openings of the page for a short while (in chrome). What about things like document.body.innerHTML = "" (you actually seem to handle this pretty gracefully, I'll see if I can poke more holes in this another time). For what it's worth none of the online notebooks I've seen have a satisfactory solution to infinite loops, loop timeouts are too blunt an instrument and crashing the tab can take the browser minutes to recover. - Is there a particular reason you use eval rather than the new Function constructor? From what I've read using new Function is much more performant, and other than different scoping a better choice than eval. Can't find the link at the moment, but it was wrapped up in the mdn[1] design docs for their codebox examples. - I see you're using the first codemirror 6[2] beta release, how are you liking it? I really enjoy the interface so far. - Do you have any favorite resources or inspirations about why you went about building a hackable offline local first notebook environment? I particularly like the experiments at Ink and Switch[3]. (many related hn submissions). As well as webstrates[4]. My attempt at this game is to break out of the notebook style single column layout and embrace an art board style canvas, which is a rather radical idea in that it is not obvious what that should look like or how basic interactions like hierarchies or execution order should look, but fun to explore. I also desperately want to prevent crashing as a result of logic errors and workflow footguns(like deleting DOM elements or overwriting storage), to that end I have a separate storage of scripts to rebuild a "safe boot" interface, but there is more thinking to be done here. I look forward to poking around your code some more soon. Thanks for posting. [1]: https://developer.mozilla.org/en-US/ https://developer.mozilla.org/en-US/ [2]: https://codemirror.net/6/ https://codemirror.net/6/ [3]: https://www.inkandswitch.com/ https://www.inkandswitch.com/ [4]: https://www.webstrates.net/ https://www.webstrates.net/ Edited out a question about your motivations. I reread your comment and the about page and I realized my motivations are similar to yours. While observable doesn't have a few of your key points, it is a fantastic product. The reason I don't settle on it is that I'm interested in experimenting with the environment outside of a notebook-with-cells interface.
- spankalee 6y agoI see you're using lit-html, LitElement/web components, and you've exposed lit-html to users. That's awesome! I'm one of the authors. Observable's html templates were inspired by lit-html, but they ended up implementing their own library. I'm glad the lit-* stuff is useful to you, and really excited to see it available in cells. I'll have to try this out!
- benrbray 6y agoThis is the first I'm hearing of lit-html, but it looks great! Is it still an active project? I'd be curious to hear your thoughts about lit-html in comparison to newer tools like svelte, solidjs, etc., which, like lit-html, abandon VDOM in favor of "surgical updates" to the DOM. Also, have tried PureScript? e.g. [1] [1]: https://github.com/paf31/purescript-sdom https://github.com/paf31/purescript-sdom
- spankalee 6y agoIt's very, very much active. It's used heavily at Google in apps, Chrome, YouTube, Waymo, etc., and by companies like Microsoft, GitHub, Netflix, IBM, Adobe, Maersk, SAP, Apple... One big difference to the projects you listed is that lit-html doesn't require a compiler. It's plain JS, and is fast because it uses template literals and built-in HTML parsing/cloning to associate expressions with DOM.
- protoduction 6y agoA late response, but I can add a bit more motivation. Without lit-html Starboard would be nowhere near as flexible or elegant. Starboard has to be completely customizable at runtime, that would probably be difficult to achieve with anything that has a build step, with lit-html it's "just Javascript" all the way down. If you usually use a framework like React, Vue or Svelte it is still worth trying out lit-html, they are not mutually exclusive, it's simple to learn and deceptively powerful. It's great to have it on your toolbelt.
- mujina93 6y agoVery cool project! 3 questions: - did I understand correctly that notebooks would be hosted (at least stored and served) on the Starboard website? (you mention it's kind of a github, in the About section) What does this imply for private notebooks? Are they possible? - any example on how to run python there with pyodide? I didn't understand by quickly looking if that integration is part of future plans or it's already a possibility. - I read that not all features are ready at the moment, for example exporting to a proper website. Any forecast on when will features like this one ready? Thanks!
- protoduction 6y agoThanks! Answering your questions: - If you log in and create a public notebook, it's stored on Starboard's server, then you can just share it by link. If you create an offline notebook it's stored in your browser's LocalStorage. Right now you can't create a notebook yet that only you can see or can be shared with a private link, to do! But of course you don't have to use the Starboard website, you can just save it as a text file on your disk. In the future I want there to be a CLI tool that serves that notebook for you on localhost. - No examples yet, it's future plans for now (but I hope to land that in a week or two!) - No forecast.. It's just myself working on it, so you'll have to bear with me. I am working full-time on this.
- tanepiper 6y agoHi, I have had a look and I think it look great - it really fits the format of a set of notes I'd like to share. One thing is I can't really find docs - I want to add RxJS on the page - is this possible? Edit: Oh nevermind, I see it in the screenshot on the Github page with the import Edit 2: Oh actually it's not working: TypeError: Cannot set property 'rxjs' of undefined If I try import { interval } from '...' I get: SyntaxError: 'import' and 'export' may only appear at the top level (1:14)
- Gehinnn 6y agoIf you are looking for a rxjs playground + visualizer, you might like this tool: https://blog.hediet.de/post/a_typescript_playground_for_rx_js https://blog.hediet.de/post/a_typescript_playground_for_rx_j...
- tanepiper 6y agoThat's pretty cool, although I liked Starboard's block UI and ability to add other content (actually it works very like EditorJS, which I built an Angular component around: https://medium.com/@tanepiper/ngx-editorjs-angular-module-to-use-editorjs-in-your-application-8c1873c09b6c https://medium.com/@tanepiper/ngx-editorjs-angular-module-to...)
- thekaleb 6y agoHave you tried the import expression as opposed to the import statement? E.G. const foo = await import('foo.js');
- tanepiper 6y agoSame - I wonder if it's because it's some sandbox context and it's trying to bind to window (it's the UMD version)
- protoduction 6y agoI've had a look and wasn't able to get it to work yet, imports can be bit iffy: usually anything that exposes ES modules or puts variables on the window object work fine. It looks like the reason it doesn't work here is because it relies on "this" being the window object. To make top-level await possible your code gets wrapped into a function, and in there "this" no longer points to the window. I am sure a workaround is possible, I'll make a ticket on github. https://github.com/gzuidhof/starboard-notebook/issues/1 https://github.com/gzuidhof/starboard-notebook/issues/1
- K2L8M11N2 6y agoI was working on an (unrelated) thing also called Starboard, I guess I have to rebrand :/
- jv22222 6y agoIMHO As an indie founder you never really have to worry about your brand being the same as another until something is internet owned. Which means that it is undeniably #1 on all search engines for that word. For example you couldn’t really start an indie project called “gap” because it’s just so dominated and there’s no room for you to ever overtake it. But “wide”, for example, is not internet owned so you could start something scrappy called “wide” with the hope that one day you can internet own it. Starboard is definitely not internet owned so if you do decide to drop it at least know that there is no reason to do so because of external optics. Also note, there is Probably no other brand that you could choose that didn’t already have a lot of folks using that brand already. In the end the market will choose the winner! All that said, this version of starboard here does look pretty cool. I don’t mean to upset anyone. But I did want to explain this point of view on brands for indie founders. BTW What’s your product all about?
- K2L8M11N2 6y agoElevator pitch: a Pinboard-like bookmarking website with an emphasis on good UX (while preserving the information density and without a sluggish JS SPA).
- jv22222 6y agoCool, thanks for letting me know! Sounds useful! That does sound like a good brand idea for that. Of course I have lot's of other questions like "How you gonna make money?" but this is probably not the time or the place ;)
- cheez 6y agoVery cool. I'm not sure I will use it in place of Jupyter notebooks but I love the fact that it can be a simple file.
- Jugurtha 6y ago> Cell-by-cell notebooks like Jupyter are great for prototyping, explaining and exploration, but their dependence on a Python server (with often undocumented dependencies) limits their ability to be shared and remixed. Now that browsers support dynamic imports, it has become possible to create a similar workflow entirely in the browser. Pretty cool. As someone involved in building a machine learning platform which also allows users to leverage Jupyter notebooks, I feel your pain. We had to add many features to make working on non trivial projects more feasible. For example near-real-time collaboration so people could pair-program on one notebook. One other problem you mention is the kernel in the backend. The problem with that is often found in issues where a user launches a long-running notebook, closes their tab/browser. The computation happens but the results don't find their way, which means users must have code for side effects and artifacts in the notebook. We've added a functionality to run notebooks asynchronously to address that problem, which also addresses the problem of multiple users competing for limited resources (tragedy of the commons) and kernels dying. Now users can run their notebooks asynchronously: they're scheduled, run, and saved seamlessly. Jupyter is a useful tool which has these problems that aren't trivial to solve. For example, for the near-real-time collaboration, the Jupyter team is revamping their API with Lumino (https://github.com/jupyterlab/lumino https://github.com/jupyterlab/lumino), which was PhosphorJS but the development stopped when the main contributor had retired.
- mujina93 6y agoHey! I'm using jupyter notebooks on a daily basis, and I would be really interested in the 2 features that you mentioned: enabling real time pair programming (a la google doc) and resuming running notebooks whose frontend was closed. Are you building a product that you plan to release? Or are these contributions that are available as open source components? In any case, I'd like to know more, or to have some information on relevant topics that might be useful to understand and find workarounds for these issues!
- Jugurtha 6y agoHi... >and resuming running notebooks whose frontend was closed. The platform schedules the notebooks, runs them, and saves the results with the output[0]. You can still check the progress, status, and position in the queue of the notebook if you wish. You still get the results after it's done even if you had closed the browser. >Are you building a product that you plan to release? Or are these contributions that are available as open source components? Well... We're a machine learning shop, present in Algiers, Algeria and Paris, France, that's been building custom turn-key products for large organizations for quite some time. As you know, non-trivial projects with real stakes are a bit more "challenging" than portfolio projects. Tracking rationale of projects, tracking metrics/params/models, shared access to data, deploying and managing models, challenges in collaboration, setting an environment and keeping things from breaking, or needing a beefy machine. We started building the platform to allow our teammates to remotely work on projects involving machine learning, as commuting is hard and having contributors in different countries can be challenging. We also wanted to simplify access to a larger talent pool from other countries, which means we had to have a way to work together. We also wanted self-service: our data scientists had to sollicit the help of other engineers to either use some language specific feature, or to deploy their notebooks. We wanted to allow them to do so themselves in one click so they don't wait, and other engineers can work on other things. We wanted the results to get as soon as possible to the domain expert, and allo that domain expert to be able to train models themselves with no code experience, by exposing parameters that are relevant to some sector, and allow them too to deploy a model. In many cases, a domain expert would chime in to tell us that some variable that was dismissed was actually critical at some point in a decision-making process. So we wanted that, too. We also wanted developers to interact with the models with HTTP requests period. We kind of suffered from having too many simultaneous projects with different stacks. We needed a way to execute projects efficiently and effectively, but we didn't like other products. We also wanted extensibility. As I said, we built whole products, not just the models, so we needed a way to plug functionality in. We're actively developing this. >In any case, I'd like to know more, or to have some information on relevant topics that might be useful to understand and find workarounds for these issues! Sure, shoot us an email at the site below or using the info in my bio. [0]: https://iko.ai/docs/notebook/#long-running-notebooks https://iko.ai/docs/notebook/#long-running-notebooks
- jrott 6y agoawesome work, I love that it's plaintext. The easy sharing can definitely make a difference.
- billconan 6y agoI worked on a similar project: https://epiphany.pub/post?refId=2684bc94f9fcb9ffe637ebfbeba2af8c797c6ad9a66181026ee4bd3806b6f211 https://epiphany.pub/post?refId=2684bc94f9fcb9ffe637ebfbeba2... It's half abandoned now. one issue of js based notebook is the missing of a file system. data scientists load huge data into notebooks, this is hard to do on the web. There is the new web filesystem api, but that only helps load local files.
- anderspitman 6y agoMy vision is for this to be handled by things like remoteStorage, Solid, or (if you must) Google Drive. I find having control over your data and delegating access to various apps to be a nice flow when implemented well (see for example https://app.diagrams.net/ https://app.diagrams.net/). It's not a silver bullet. For larger data you can't afford to download it every time. That tends to balance itself out though, because you don't really want to store huge data on your laptop anyway, so you're going to have to find a different solution for that anyway (such as using Jupyter). You can accomplish quite a bit with streaming + sampling, which is the crux of how all our apps work in iobio.
- amadeuspagel 6y agoI guess the web first way of dealing with this would be to have the data online also, maybe even on the same platform. Then you could have things like: Look at visualizations of this dataset, at what people have done with this dataset etc.. And you could immidiately verify the results, assuming you trust the data.
- billconan 6y agoit's gonna be slow and expensive.
- westurner 6y agoNeat! There's a project called Jyve that compiles Jupyter Lab to WASM (using iodide). https://github.com/deathbeds/jyve https://github.com/deathbeds/jyve There are kernels for JS, CoffeeScript, Brython, TypeScript, and P5. FWIU, the kernels are marked as unsafe because, unfortunately, there seems to be no good way to sandbox user-supplied notebook code from the application instance. The README describes some of the vulnerabilities that this entails. The jyve project issues discuss various ideas for repacking Python packages beyond the set already included with Pyodide and supporting loading modules from remote sources. https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity https://developer.mozilla.org/en-US/docs/Web/Security/Subres... : "Subresource Integrity (SRI) is a security feature that enables browsers to verify that resources they fetch (for example, from a CDN) are delivered without unexpected manipulation. It works by allowing you to provide a cryptographic hash that a fetched resource must match." There's a new Native Filesystem API: "The new Native File System API allows web apps to read or save changes directly to files and folders on the user's device." https://web.dev/native-file-system/ https://web.dev/native-file-system/ We'll need a way to grant specific URLs specific, limited amounts of storage. https://github.com/iodide-project/pyodide https://github.com/iodide-project/pyodide : > The Python scientific stack, compiled to WebAssembly > [...] Pyodide brings the Python 3.8 runtime to the browser via WebAssembly, along with the Python scientific stack including NumPy, Pandas, Matplotlib, parts of SciPy, and NetworkX. The packages directory lists over 35 packages which are currently available. > Pyodide provides transparent conversion of objects between Javascript and Python. When used inside a browser, Python has full access to the Web APIs. https://github.com/deathbeds/jyve/issues/46 https://github.com/deathbeds/jyve/issues/46 : > Would miniforge and conda-forge build a WASM architecture target? > Emscripten or WASI?
- roywiggins 6y agoThis is really cool, and I've wanted something like this to hack on for ages. I'm a big fan of being able to present concepts along with code that you can run, and I'm also a huge fan of not having to rely on a server backend. I have a static blog where I try to talk about various math concepts which I illustrate with code. I hacked together a pseudo-literate html sort of presentation, and it works just fine, but it's inflexible.
- jvanvugt 6y agoCool project! Using Monaco for the editor makes it much more pleasant for writing code than Jupyter notebooks
- kbouck 6y agoHow does this compare with Observable? https://observablehq.com/ https://observablehq.com/
- fzaninotto 6y agoObservable is not JavaScript https://observablehq.com/@observablehq/observables-not-javascript https://observablehq.com/@observablehq/observables-not-javas...
- j-pb 6y agoYeah but it's close enough (in the sense that it's like JSX, syntactic sugar over a JS runtime), so an in depth comparison would still be usefull.
- jacobolus 6y agoIt’s misleading to take this headline and not actually read the document and notice how few these differences are. Observable cells are basically Javascript, with a small handful of additional conveniences (most importantly: they can reference other cells reactively) which make a huge improvement in the notebook context, and make Observable significantly more pleasant than any other notebook environment (Jupyter, Mathematica, etc.). Javascript libraries and code snippets can be used as-is in an Observable notebook, and anything in Observable cells can be straightforwardly ported to vanilla JS at the expense of a bit of effort and slightly uglier code. (Or the Observable runtime and standard library can be used directly externally.)
- TeMPOraL 6y agoIt's still JavaScript, just implicitly transformed to execute in a different way than it would if you put all the cells you've written in a single file. If I write a macro in Common Lisp that packages my code in a lambda, establishes a bit of dynamic context around its execution, and perhaps walks the code itself to modify some of its contents, this doesn't make uses of that macro "not Lisp". Yet that's what's happening here, just with less elegant machinery as JS doesn't have proper macros.
- an4rchy 6y agoNeat idea. I was checking out the roadmap and was curious, do you have any plans to monetize in the future? Also, I hadn't realized there was a category of 'Open Startups', that's pretty cool.
- ipsum2 6y agoIt's awesome that they publish their analytics openly: https://plausible.io/starboard.gg https://plausible.io/starboard.gg
- solidasparagus 6y agoBut the data is kind of crappy. The same user coming back in two different days is considered two unique users.
- protoduction 6y agoIn a way that's an important feature. I don't want to (be able to) track individual users, and I don't think I have to. I don't have to tailor ads to the visitor or something, I just want accurate enough stats in aggregate.
- Hitton 6y agoGreat find. Best statistic on HN userbase and "HN hug" I've ever seen.
- deleted 6y ago[deleted]
- Equiet 6y agoGreat work! I'm the founder of Deepnote (https://deepnote.com/ https://deepnote.com/). We're working on a data science notebook (primarily focused on Python), happy to share what we've learned. I couldn't find any contact info on the website, feel free to message me at jakub@deepnote.com.
- haneefmubarak 6y agoHow does this compare to RunKit? https://runkit.com/ https://runkit.com/
- rewq4321 6y agoStarboard is all client-side, whereas runkit is all server-side (node.js). A closer comparison would probably be Observable[0]. I love the "just HTML and CSS" philosophy of Starboard, but I'm not really qualified to have an opinion here because my work doesn't involve notebooks that much. [0] https://observablehq.com https://observablehq.com
- smashah 6y agoThe concept of Jupiter notebook for python was always kinda wild to me. Great that now there's an option for JS. Looking forward to using it! Great work!
- conradludgate 6y agoJupyter notebooks exist for way more than python. You can run any language kernel for it. Js, rust, go, c etc all have kernels
- faebi 6y agoI even used a ruby kernel once and had a pretty neat data science experience with it.
- mrweasel 6y agoI still don't what a Jupiter notebook, and at this point I'm afraid to ask.
- indigochill 6y agoJupyter is a Python environment built around IPython (Interactive Python). A notebook is a series of "cells" which are snippets of Python code. You execute these cells and see results in another pane much like if you were just noodling around in the console (except there's one unified place where output appears). Where it's seeing a lot of traction is in data science where someone can explore the data with code, save their exploration, and share it with others. The advantage over a standard paper is that when someone opens a notebook, they see all the code and can run and mess with it independently.
- wokwokwok 6y agoHm. So, without a kernel that can do heavily lifting, you're limited to basically what you get when have the browser console open; ie. html + js. Is that the idea? A better / structured browser console? Or am I missing something? I mean, I completely appreciate the benefit of notebooks; but if you're limited to running code inside your browser window sandbox... how do you do anything useful with it? How do you import a dataset? > const data = await fetch(`https://api.exchangerate.host/timeseries?start_date=2020-01-01&end_date=${today}`); https://api.exchangerate.host/timeseries?start_date=2020-01-... Is great for trivial public datasets, but CORS is going to forbid you from loading any personal/private data right? unpkg can give you public packages, but if you have any personal code, how do you use it? It seems like you basically end up with an empty sandbox.
- brainless 6y agoI somehow felt very similarly. In that this is a very cool project, but what does it really solve. People who work with data also actually need Python, do you really expect me to recreate all the Py libs in JS now? I am really curious what was the author's thinking process here with regards to solving the problem, what in fact was even the problem. Perhaps the author could share their thoughts. Edit: grammar
- brainless 6y agoAfter looking at https://starboard.gg/about https://starboard.gg/about things are clearer now. The use-cases are clear and I can see the audience it targets.
- SiempreViernes 6y agoCan you explain it, because even after reading the about page I think your objections in the first post stand unchallanged.
- oarsinsync 6y agoTo me it looks like while Jupyter is good with Big Data, this may be good with Small Data that doesn't need the overhead that is Jupyter, but saves the need to reinvent all the wheels yourself manually. I'm looking at this and comparing it to the situation I find myself in with looking for a syslog collector. I want something that can collect all my syslog and present them in a web UI in a sensible way. My options appear to be limited to commercial solutions, ELK (Elastic, Logsearch, Kibana), or text files. There's no middle ground. I have ~20 VMs + containers, and no way to view all of their logs in a central sensible manner unless I roll my own (or buy more hardware to be able to run the ELK cluster).
- yetanotheruser8 6y agoThis is actually useful. I like this better than Codesandbox for just messing around with some data cleanup or something hacky and quick. I'm sure it's on the list, but I wouldn't be opposed to some Dark-mode.
- tetris11 6y agoI'm not going to mention org-mode, because Im bigger than that but really I'm not and org-mode org-mode org-mode
- bloopernova 6y agoThis is more org-babel, though. Which is org-mode. Hm. I'm honestly just happy that Literate Programming is being hacked on, shared, discussed, and criticized. Living documents just seem so much closer to the promise of hypertext and the original web than what we have now.
- LeonidBugaev 6y agoCombine it with https://github.com/iodide-project/pyodide https://github.com/iodide-project/pyodide (Python and bunch of scientific libs compiled to webasm), and you will get really nice lite Jupiter alternative which can cover 90% of use cases.
- znt 6y agoThis has great potential. You planning to seek funding to work on this full time?
- protoduction 6y agoI am not sure yet. I am working on this full-time, but it's my own savings that keep me fed so that's not very sustainable. I am not sure what makes the most sense in terms of monetization in the longer term. I think it's a difficult for many open source projects.
- fomojola 6y agoI really like it! Have you given any thought to server-side execution? One of the things I think is missing from Jupyter is a clean, standard way of doing timed execution of a notebook: there are a number of paid solutions, but nothing out of the box (that I could find; spent a few days searching). Conceivably one could string together puppeteer or something similar, but it would be great to be able to run "node starboard_runner.js <notebook file>" and have the results output to stdout or saved to a file.
- paulgb 6y ago> One of the things I think is missing from Jupyter is a clean, standard way of doing timed execution of a notebook Have you looked at nbconvert with the ExecutePreprocessor? I use it (with a light wrapper) from cron for sending automatic email reports and generating static dashboards. It might do what you're looking for.
- chrisweekly 6y agoAwesome! Created free acct, looking fwd to building stuff with this!
- spicyramen 6y agoI didn't get if you can run Python code? I use TensorFlow quite often and would be interested in trying it
- protoduction 6y agoNot yet, but it's near the top of my to-do list
- deleted 6y ago[deleted]
- fghhfg 6y ago> static files + Stores as a plaintext file check TiddlyWiki
- MR4D 6y agoThe fact that this runs in my iPhone is impressive. That feature alone makes it worth spending more time on. Good job!