Show HN: An eBook reader webapp I created. http://magicscroll.net
Reader runs from http://magicscroll.net

This is my first post to HN. Since this is a Hacker Community I thought you all might be interested in some stats and info about the project:

---

I think MagicScroll's doing pretty well in terms of uptake but I don't have any kind of tracking implemented yet so I'm a bit blind.

I've got just over 6000 users from the Chrome Web Store.

https://chrome.google.com/webstore/detail/ghgnmgfdoiplfmhgghbmlphanpfmjble

On my server logs I get between 700 and 900 hits to my cache manifest file every 24 hours with more over the weekend. As near as I can tell users turn a books page an average of just less than 400 times an hour. (Each page turn involves a round trip to the server for syncing purposes). More than 95% of the hits are coming from Chrome so I think there's a lot of room to expand.

---

I didn't build MagicScroll as a commercial venture but based on its limited popularity I do think it has the potential to create revenue, and I now hope to build a business around it. In the next month or so I plan to create a paid extension similar to Readability that will allow websites to be read using MagicScroll. I also intend to build an API for booksellers to allow MagicScroll to be integrated into their stores. If MagicScroll does gain a significant number of users I hope to integrate my own ebook store into it but I think that will be in a year or twos time at the earliest.

---

For those of you interested in the programming side. It is built in GWT and runs on the Google App Engine. I'm embarrassed to say that I don't have any real knowledge of javascript though I'm trying to rectify that. There are about 30 lines of native javascript in the project most of which facilates communication between the frame that holds the book and the UI.

The entire project is heavily cached and apart from unzipping the ePUB and some security logic everything happens clientside. There are obviously a lot of advantages to this and it was quite easy to do because I was working in GWT. In fact I found that the same logic on the client often runs significantly faster than it does on the App Engine server.

To do page rendering I'm using a very simple binary search. I draw a page with a certain number of characters and if it overflows I draw it half the size and then half between that and so on. It's quick but I have no idea how Google has managed to get their pages in Google Books to render so fast, or to change the font size without redrawing.

One thing I've perhaps overrelyed on is AsyncCallbacks here's part of the code that draws the book:

LoadDialog.get().show("Loading Book. Stage 2 of 3");
init(eacKey, new DelayedCallback<Void>(new SimpleCallback<Void>(){

@Override
public void onSuccess(Void result) {
resize();
LoadDialog.get().show("Loading Book. Stage 3 of 3");
PageRendererFrame.addEPubStyleSheets(new DelayedCallback<Void>(new SimpleCallback<Void>(){

@Override
public void onSuccess(Void result) {
SettingsWidget.get(new SimpleCallback<SettingsWidget>() {

@Override
public void onSuccess(final SettingsWidget settingsWidget) {
PageRendererFrame.addStyleSheet(settingsWidget.getCurrentValueStore().getCurrentColors().getLocation(), new DelayedCallback<Void>(new SimpleCallback<Void>() {

@Override
public void onSuccess(Void result) {
PageRendererFrame.addStyleSheet(settingsWidget.getCurrentValueStore().getCurrentFont().getLocation(), new DelayedCallback<Void>(new SimpleCallback<Void>() {

@Override
public void onSuccess(Void result) {
PageRendererFrame.showPage(new DelayedCallback<Void>(new SimpleCallback<Void>() {

@Override
public void onSuccess(Void result) {
hider.removeFromParent();
preventDraw = false;
callback.onSuccess(null);
}

}));

}

}));

}

}));

}

});

}

}));

}

}));

The DelayedCallback works like a normal callback but introduces a 1 millisecond delay to avoid the browser from thinking the code has frozen. SimpleCallback is just like AsyncCallback but without the onFailure method. If an exception occurs the program halts instead of recovering.

I made it so that whenever an uncaught exception occurs I get emailed about it. This has massively increased my stress levels but I think its contributed to the stability of the code so I'll probably do the same in the future. I now get less than 20 errors a day. Mostly if someone tries to use MagicScroll with IE7 or if they try to read an encrypted book.

Anyway thanks for letting me ramble, I'm interested to know what HN thinks.