Quartex is now a company

It is with great pleasure that I can inform everyone that Quartex Pascal is now a company with a fully funded three year runway. This means that Quartex Pascal as well as the desktop project will see full-time development the next three years.

As of such, the Patreon project will shut down mid December. Don’t remove your backing just yet, i need time to register each name and the tires so that backers can receive appropriate licenses for having backed the project. I will inform everyone in good time.

Having sacrificed more or less every weekend for the past four years, it feels good to have arrived at a place where i can focus more deeply on the tasks, rather than jumping in and out with a full work-week between sessions. I can barely remember a weekend I did not work on QTX in some capacity. I must admit I had hoped the Patreon model would have seen stronger backing, but at least I gave the alternative routes a fair chance.

I think products like this can only be realized through traditional, commercial mechanisms. That is ultimately the lesson I have learned after four years of alternative paths. C# and Miguel de Icaza’s story is somewhat similar. He barely made any money on donations and backing (and that was in California, at the heart of Silicone Valley) and it was ultimately thanks to Novell investing in C# and asp.net for Linux that Xamarin Studio (commercial mono, much better than VS) came into existence. Xamarin Studio was later bought by Microsoft, and the mobile development framework and compiler in VS is ultimately Xamarin. Without commercial investment, Xamarin would never have been a success.

Anyways, updates will appear on Patreon for December, and after that everything will happen via the official website here. The Facebook group will remain active, and it will become an open user-group like Delphi developer, FPC Developer and C++Builder Developer – which are the developer groups I manage on Facebook.

Salud Compadres!

There will no doubt be some pause in January as I implement the license server so updates etc. can be automated, but news will be posted here starting with the release of version 1.0 of Quartex Pascal.

So there is a lot to be happy for right now! Finally I can work full weeks on QTX and have normal weekends again ❤️

Now for the third chapter in a very exciting journey 🙏🔱

Filesystem over Websocket

With the desktop application model in development we are finally nearing the stage where we can bring out the big guns and tie the web-desktop infrastructure together. If you are new to QTX you might be wondering what that means? Well, let’s do a little recap of what we are building here and why!

The QTX Desktop is already capable of running 68k Amiga software courtesy of vAmiga (webassembly). x86 support is coming, as is DOSBox support. But those are just for fun and love of retro coding. The actual desktop services and API for making full and large HTML5 based web applications is what this is all about. Being able to have a desktop ecosystem that you can deploy to and host anywhere.

Before QTX existed I had a similar product called Smart Mobile Studio, and I used that to create a prototype of a web based desktop system. Sadly my work on Smart Mobile Studio came to a halt in late 2018, and it became clear that if we finished the desktop system using that compiler, anyone interested in the web desktop would have to buy Smart Pascal in order to work with the codebase I was creating. That made little sense since I had left the company and held no stocks there (I would effectively be doing their work for free, lining their pockets by proxy). At the same time the Smart Pascal RTL would need so many changes to cope, that it would practically be a full re-implementation.

After much consideration we (the backers and myself) decided it would be better to implement a whole new development tool-chain from scratch, and then continue on the desktop project once QTX had matured.

But why a web desktop you might ask? Why would that even be remotely interesting? Well if you have a NAS (network active storage) or a router in your home (chances are you have at least a router) and look at how those devices are controlled, you will find they are both accessed purely through a browser. It also turns out that writing applications for an established NAS brand, such as Synology, is both costly for the developer (absurd developer license fees) and extremely esoteric.

What does such a NAS consist of? Is it black-magic? Does these devices have some secret sauce that separates it from a run-of-the-mill desktop PC? Turns out there is no secret sauce except for their web desktop system, which allows users to manage and work with their NAS from any webbrowser. What you are paying for in blood when you buy a NAS, is ultimately this web desktop system and the work that has gone into that aspect of the product. Most NAS systems are extremely over-priced considering the hardware you get, and you have ZERO control beyond what Synology (or any of the other vendors) gives you.

The Synology web desktop. It works really well and makes it easy to install programs for your NAS. Everybody knows how to use a desktop so it’s a lot more intuitive than the typical website approach. Just sad it costs a ton of money

This is where the Quartex Media Desktop (codename Amibian.js) comes in. A system written 100% in Quartex Pascal and that needs only node.js and a browser to deliver the goods. The entire system is 100% node.js / HTML5, and can thus be moved between architectures ( x86, ARM, Risc-V, PPC ) without needing to re-compile anything.

$800 for a NAS? The hardware is maybe worth $100

This work stopped in late 2019 when we had more or less exhausted the old development system (SMS was designed for mobile apps, not a full desktop environment and back-end services). Sadly, COVID took center stage for a couple of years and took a huge bite out of our TTM. I have kept on working on QTX, even though the tasks seemed endless sometimes. But finally, finally we are reaching that sweet spot where the underlying code is evolved enough that we can continue.

Which is where we are now!

Let’s get the filesystem going

People often ask me why I mention the Commodore Amiga in the same breath as QTX, and you would be forgiven for thinking that it’s just a bad case of nostalgia. And while I have many fond memories of learning to code on Commodore machines way back in the early 1980s, this is ultimately not why I find that machine and OS so inspiring.

Commodore was way ahead of it’s time, and many of the ideas that went into their operating system, were quite frankly too complex for the hardware to fully realize. You have to keep in mind that a stock Amiga 1200 had a 68020 CPU running at 14 MHz with 2 megabytes of ram. Your wristwatch (if you have a modern smart-watch like Samsung Galaxy or Apple Watch) has 100 times more processing power than that old machine. However, the ideas and solutions they came up with is where my focus is.

Take something simple, like the filesystem. Amiga OS had a driver based filesystem long before Windows was capable of displaying more than 16 colors. They also organized that filesystem and path structure, so that creating virtual drives was intrinsic to the system. You could in fact mount a folder as a drive by assigning a drive identifier to it, using a simple shell command, such as:

Assign MyDrive: MyFiles/MoreFiles

The above would register a “fake” disk called “MyDrive” that would simply be mapped to the local folder MyFiles/MoreFiles. In today’s jargon this would be called a symbolic link, and you can do this with Windows, MacOS and Linux. But out of those three systems, only Linux comes close to the same ease of use and elegance of the original Amiga OS.

An early version of the desktop prototype, with filesystem running for both Dropbox, Server (local) and Ram-disk, used seamlessly between running applications. Each application runs in it’s own frame context and communicate with the desktop API through messages. This is where Ragnarok comes in for those that are wondering about that.

If we take that concept and refactor it to 2023, taking account for cloud storage and the various storage mechanisms popular vendors (such as Amazon, Dropbox or Azure) provide, the path-syntax that Amiga OS operated with makes much more sense than it did running on slow and bulky 1980’s consumer hardware:

Assign MyPictures: Dropbox:pictures
Assign MyMovies: Azure:Movies

The path syntax that Amiga OS operated with is brilliant in it’s simplicity, and the fact that it was driver based both for the physical-media-filesystem and networking filesystems, is one of the reasons Amiga OS is still being used today by thousands of people around the world. Whenever there is a new storage media or protocol, someone writes a driver for it, and the core OS can instantly use the new technology. The path syntax the OS follows is:

[drive|assign|pipe|rexx|samba channel]:folder/folder/file

As you can see from above, the same syntax covers not just files and folders, but also pipes, samba shares (network shared folders) and rexx. While I don’t see any point of rexx in 2023, the syntax is malleable enough to cover local storage devices, yet it can stretch to also cover networking and IPC mechanisms. Commodore took the best from Unix and DOS when they designed this. They also applied some ideas from an earlier system called Minix. The takeaway here should be, that it’s a formula that has stood the test of time (almost 40 years of continuous use).

In order for us to use this system for our desktop, the same path syntax must be understood by both back-end (services) and front-end (web desktop client). Which means we need a path parser that is able to read, parse and translate an Amiga path, into a Windows, Unix or Linux path. Since Linux is my goto OS for embedded hardware I have focused on that first. With the exception of the drive-moniker (e.g “MyDrive:”), the paths are compatible with Linux and Unix out of the box.

If you have a peek in qtx.fileapi.core.pas you will find that we have both path parsing and a abstract storage device system in place already. It must just be deployed and initialized properly. It even has an in-memory storage device, called ram-disk, which is typical for Amiga OS, but which a lot of people also use on Windows and Linux. Puppy Linux actually boots out of RAM-DISK

So right now I am implementing the missing pieces so that we can start using and writing node.js back-end services that makes full use of the filesystem drivers. The old system used a hybrid websocket server, which is a normal HTTP/S server that can also deal with websocket connections. This was something I implemented especially for our desktop using Smart Pascal first, but it needs to be refactored for QTX. Which is what I’m looking at now.

The filesystem service and drivers is also something you can use in your applications. In order for it to work properly it requires a second service, the authentication service. Both use the same hybrid node.js server class – so once that is in place, both these node.js services can be used by your programs. Regardless of you using the desktop ecosystem or not.

I made some kick-ass clusters for the desktop system, QTX is excellent for getting into IOT and hardware

This is what I love about OOP, namely that we focus on widgets (components), packages and classes. And if you write the classes to be as system agnostic as possible – you can recycle the technology in a myriad of different scenarios.

Deploying large web applications

Another use case for the desktop system, is to simplify how you deploy your large web applications written in QTX. How would you go about implementing a full accounting system for web? You would need windowing (preferably), you will need file-access, you will need database access, you will need strong authentication — in short, you would end up creating the exact same technology!

The web desktop does all of this for you. Once complete you will be able to fork the entire desktop, mold it as you see fit, and use it as a ramp for that large, 60 form application that would otherwise be a mess if you implemented it as a vanilla website.

Writing Client & Server software should be fun!

Major RTL update available

It’s been 3 weeks since the last update, but rest assured that those weeks have not been wasted. In fact, I have worked on QTX every single day in from afternoon to bedtime. The changes and fixes in this update are in their hundreds. I will only list those that are of immediate interest for users to know about.

Above: The new desktop application model is coming along nicely. Still a few bugs to iron out before we create application templates for it, but getting there!

Please be advised that this update is very much work in progress, meaning that if you experience any issues then please report those issues so I can get them fixed. The ZIndex support especially is borderline experimental, since it’s one of those absolutely bizarre aspects of HTML that makes no sense from an architecture point of view.

Above: For those of you that grew up in the 80s, the Webassembly Amiga emulator will no doubt bring back memories. If you download some ADF games from the internet, you can click the file-flot and boot up the game or demo. This is just a tiny taste of what is to come, we also have x86 emulation and roughly 3000 90s games to play with (I will not provide the DOXBOX games, those can be found on torrent sites here and there).

To underline: This update contains no new .exe file, purely RTL changes! It is the same exefile as was in the last update (I have to do the RTL changes before I go in and make changes to the exe). For those of you that are waiting for IDE fixes, sit tight, they will be out very soon.

Partial changelog

  • Completely overhauled the theme.css file so it takes height for mobile platforms, make sure you copy this into your existing projects! Also replace the old default.theme.css in the themes folder with the new one!
  • SetLeft, SetTop, SetWidth and SetHeight optimized
  • MoveTo, SetSize, SetBounds, BoundsRect adjusted to call the above methods when doing changes, rather than ad-hoc setting the values
  • GetClientRect fixed, it now uses GetClientWidth() and GetClientHeight() which adjusts for the any border-padding and margins
  •  Added support for Shadow DOM, calling TQTXWidget.AttachShadow() creates a shadow-dom on an element, which can be accessed via the property ShadowRoot: TQTXWidget, or direct access to the shadow handle via ShadowHandle
  • Introduced the concept of “Synchronized widgets”. By setting the Synchronized: boolean property on a widget inside the constructor callback, the widget will wait until all it’s children are created and in the DOM (as well as itself) before invoking ObjectReady(). This is important for widgets that wrap external JS frameworks, or that needs to be 100% sure that the widget is indeed “ready” before it’s manipulated further.
  • Added a new CreateOptions flag, wmSynchronized, which developers can set if they dont want to set the Synchronized property. The function GetCreateOptions() can be overriden and you can add the wmSynchronized flag to the result (datatype is a set)
  • Introduced stacking-context functions to TQTXWidget: GetStackContextFor() and an overloaded version that also takes a filter parameter. This will return an array of each child element on a widget, sorted by their element-index. This can be used to determine how widgets are overlapping
  • Optimized BringToFront() and SendToBack(), there was no need for the RemoveChild() call prior to re-insert or re-append of the element
  • Implemented Tooltips (!) This is now in the unit qtx.dom.tooltip.pas
  • Expanded TQTXWidget with a Hint property, as well as a ShowHint property
  • TQTXDomApplication makes a reference to TQTXTooltipManager, which brings in that part of the RTL automatically. You will need to reference qtx.dom.tooltip.pas in your units if you wish to access the tooltip system directly
  • Added a InstallWindowClass() method to TQTXToolTipManager, you can use this to install your own tooltip widget if you want to style it differently
  • Changed the “body” proxy component property for TQTXDOMApplication from a component, to a full blown widget. If you want to create widgets directly on the HTML body, you can use this as a parent. Changing this to a TQTXWidget also means you can easily access things like background, styles, check the width and height etc.
  • Added a new FormContainer: TQTXWidget property to TQTXDOMApplication, this is a proxy widget that will always represent the container where forms are housed. Different application models represents forms differently, and will have different layout rules for forms. This property simplifies access to the “viewport”, regardless of application model.
  • Added Touch delegates, these delegates can be found in qtx.dom.events.touch.pas (Please note that you dont need to use these unless you explicitly need multi-touch support. Instead use the pointer-events and check the pointerType property to know if a user is operating with a mouse, pen or touch, and then implement your handling code thereafter).
  • Added the Touch delegates to the widgets in the RTL, these now show up the “add delegate” dialog for the form-designer
  • Added touch helper functions to TQTXDOMApplication, as well as the partial TQTXWidget class in various units
  • The qtx.dom.widgets.pas unit was getting rather big. Exported things like borders into it’s own unit (qtx.dom.border.pas)
  • To speed up widget creation, borders and font objects are now created “on demand”, meaning they are created when you first reference them. No point wasting CPU time creating a background object when it’s not used
  • Refactored TQTXToolbar so that it supports vertical layout (!)
  • Rewrote the CSS for the toolbar so it takes height for both horizontal and vertical orientation
  • Added support for ZOrder! Exposing the property ZOrder to TQTXWidget. ZOrder under HTML is a bit strange, since elements initially follow their elementIndex (a new widget is always topmost since it’s appended to the parent, and thus ends up at the end of the child collection). ZOrder overrides this, which to be frank is quite confusing for Delphi developers (myself included). Default value is “auto”, which in QTX means -1. So if no zindex has been assigned to a widget, it will return -1, which simply means “automatic”.
  • Implemented ZOrder functions which simplifies sorting and working with ZIndex: GetZOrderHighestFrom(), GetZOrderBoundsFor(), GetZOrderStackFor(). These are used by the RTL to deal with ZOrder.
  • Re-implemented (experimental) BringToFront() and SendToBack() so they now use ZIndex rather than elementIndex. Please note that this is experimental at this point. I have tested this with the various example apps and it works fine, but there are bounds to be edge-cases where you might have to call BringToFront() in order to remap the zindex of child widgets. Consider this work in progress! You can turn this off by disabling the $IFDEF in qtx.dom.pas, EXP_ZINDEX
  • Added a new InstallViewPort() method to TQTXDisplay, so that an application model can use a different TQTXViewport class if needed
  • Disabled older system to detect resize, which caused excessive calls to Invalidate() and Moved(). If you need automatic Resize() and Moved() calls, simply activate the ResizeObserver or MoveObserver, by calling their Observe() methods. When writing widgets you would call ResizeObserver.Observe() in ObjectReady(). This will then listen for mutation events in the DOM and call Resize() automatically whenever your widget has it’s size changed. The MoveObserver works the exact same way.
  • Expanded TQTXDisplay with methods that performs the layout, StdLayout(). TQTXDisplay will organize it’s children vertically, subtracting the height of any widgets you might have created there directly, and resize the viewport to cover the reminder. By isolating this logic in it’s own procedure, different TQTXViewport than the default class (see InstallViewPort() above) can perform changes to the default layout regime if needed.
  • Implemented a new widget, TQTXDOMIFrame, which creates an IFrame element. Please note that this widget still needs work. When finished it will also expose a message channel for communication between “apps” or third party websites.
  • TQTXWindowElement, the baseclass for all TQTXWindow parts, now inherits from TQTXSyncWidgetContainer
  • TQTXWindow is now synchronized, since that works better when hosting external websites as the content
  • Added a new Window type, TQTXFrameWindow, which contains a TQTXDOMIFrame widget
  • Implemented a new application model, this is still being worked on, but you can find it in the test project “Windowing app”, which is ultimately the desktop project I have been showing lately. This project also has an Amiga webassembly emulator — make sure you open this project in the browser, as miniblink does not support WASM.
  • .. And much, much more!

I could literally continue for at least 2 more A4 pages of changes and fixes, but the above list represents the biggest changes to the RTL so far.

What to look out for?

Since I have disabled the old resize system, which ultimately tied into BeginUpdate(), EndUpdate() and logging of changes between those two methods, some of your existing projects might be affected by this. The solution is to activate the ResizeObserver object in your widget ( a simple ResizeObserver.Observe(); will do).

The ZIndex change is quite huge, in that our codebase has so far only dealt with ElementIndex (creation index) with regards to BringToFront() and SendToBack(). But so far I have not seen any dire consequences for this change. If your project is affected, you can turn off the ZOrder support by disabling the EXP_ZINDEX $IFDEF on top of the qtx.dom.widgets.pas unit.

I have completely overhauled the theme.css file so it takes height for mobile platforms, make sure you copy this into your existing projects! Also replace the old default.theme.css in the themes folder with the new one!


You can download the RTL update from http://www.patreon.com/quartexNow as usual!

How to use TQTXColumnPanel

Besides the TQTXGrid widget, the column panel is probably the control I am asked the most about how to use. I fully understand that when coming from Delphi or Lazarus, some of the widgets in the QTX runtime-library can seem difficult or confusing. We are used to dragging & dropping controls onto a form, and get instant visual feedback.

Sadly, this is not how HTML5 works all the time. We have to keep in mind that HTML is ultimately a document format, where web developers are expected to provide content according to a specification within that medium. In many cases child elements have to conform to a specific displaymode and positionmode in order to render correctly.

This does not always translate well to a form designer approach.

TQTXColumnPanel is one such widget, where you really are expected to provide content by code rather than dropping child widgets at design-time.

What does TQTXColumnPanel do?

The widget exposes and wraps the fancy new column CSS attributes, most notably the “column-count” attribute which divides the content into X number of columns, dividing the width between them. The result can look somewhat like traditional newspaper columns.

The CSS attributes that defines and affects column layout in HTML are (here listed in their JavaScript prototype format (more about that further down):

  • columnCount
  • columnFill
  • columnGap
  • columnRule
  • columnRuleColor
  • columnRuleStyle
  • columnRuleWidth
  • columnSpan
  • columnWidth
  • columns

I should underline that TQTXColumnPanel does not expose all of these via the inspector. It exposes the bare-bones of what is needed to set a panel into column mode. You can access the other attributes through the widget’s Style property, or directly through the widget handle (more about that towards the end of this post).

To get to grips with the widget I suggest you drag & drop a few TQTXDomDiv widget instances onto the column-panel. TQTXDomDiv is a clean, thin wrapper over the HTML DIV element – which works really well with column layout.

As the name says (div is from the Latin diversus, meaning miscellaneous) the DIV element is a generic element that developers can use for anything (basically just a rectangular region). This is the element type that most other HTML5 elements inherits from behind the scenes of the document object model. If you know Delphi, this can be seen as a parallel to TWinControl.

Above: A TQTXColumnPanel with 3 TQTXDOMDiv widgets, each with a displaymode of cdBlock and positionmode set to cpInitial

In HTML, different element types (read: tags) have different rules associated with them. In this case you want child widgets to have a displaymode of cdBlock, and positionmode set to cpInitial.

Run in a full browser

The Quartex IDE uses a small and fast embedded browser called Miniblink to preview applications. This is a tiny footprint browser that is barely 30 megabytes in size, and it’s capable of rendering HTML4 and a fair subset of HTML5 – which is quite impressive considering the footprint.

As amazing as Miniblink is, it only supports a subset of HTML5. It is an embedded browser after all and not really intended to rival desktop browsers. I included it purely because I found it useful when developing RTL code designed for mobile applications. You should ignore it if you need to work with cutting edge HTML5.

Miniblink gave me a sort of lowest common denominator to aim for with regards to element and feature support. But Miniblink is not a replacement for a full modern browser. I strongly urge developers to run and test their applications in their system browsers.

Above: Miniblink does not support the column attributes. Run the code in the system browser instead.

Column support is sadly one the features Miniblink lacks, so make sure you click the “Open in browser” button (on the toolbar, next to the Execute button) to run your project in the system default browser.

Above: If you have multiple browsers installed you can tell the IDE which one to use in the preferences dialog

I presume you have installed a modern browser such as Chrome, Firefox or Edge? If not, make sure you install one of these first. Once installed, go into the IDE’s preferences dialog and select the browser for use (this can be found under the Network tab).

Remember to save any changes to your form before clicking the Build button, and then click the “Execute in browser” button to open the project in your system browser of choice.

Above: Running your project that uses TQTXColumnPanel in a full browser renders the output correctly

Populating the panel

Personally I prefer to do things from code as much as possible. The so-called “code first” approach where you try to write classes and units in code (since that is more easily made portable), and only use the form designer for the most complex or time consuming of tasks. I realize that this is not how most people work, but working with HTML5 will force you to approach the DOM from a code-first perspective in some cases.

In the case above, we could have edited the InnerHTML property of each panel by clicking on the [..] button in the inspector (on the same row as the InnerHTML property). That is perfectly valid and the data will be baked into your code and assigned to the property during construction.

However, for this example I have set the content via code, like this:

Above: Sometimes it’s just easier to work with HTML from code, although it does mean a bit more typing

You could also have simplified the whole process even further and dropped the TQTXDOMDiv widget’s completely, by writing this:

Above: You can insert raw HTML into any widget and the browser will create the elements for you. However, this approach means you wont have pascal widgets to play with that easily. But for static content, this is by far the easiest way

In terms of speed the above method is the fastest, since there is no widget creation cycle involved.

While a bit outside the scope of this article you can access the div’s by code by using the standard JavaScript functions. Once you have the handle for these elements, you can pass that handle in the constructor of TQTXWidget, and it will adopt the handle as it’s own. But for static content like this, a TQTXWidget really is overkill and meaningless unless you need to work with one of the columns directly.

Dealing with widget height

One thing you will notice when populating a TQTXColumnPanel with widgets via the form designer, is that their height will always be whatever you designed them as at design-time. This is the because the inspector values are written to the instance during construction -and in this particular instance it would actually be better if it didn’t.

This can be solved by accessing the raw HTML style of the widgets directly from code and setting the height to 100%. The inspector cannot do this since it only works with intrinsic, typed datatypes – so it is not possible to assign “100%” to the height of an element from the inspector (it expects an integer value).

We can solve this by adding the following code to the form initialization:

Widget1.Style.height := "100%";
Widget2.Style.height := "100%";
Widget3.Style.height := "100%";

This is true for all widgets by the way, you can access CSS directly for every widget directly, and override whatever was set in the inspector at design-time. The Style property in Pascal of a widget is just a helper object which maps the most common CSS styles by name, just to make it easy to work with from your object pascal code.

If you need to access a style that is not exposed via the Style property, you can go the immediate route through the widget (read: element) handle:

Widget1.Handle.style["some-name"] := Value;
Widget1.Handle.style.someName := Value;

The above two lines does the exact same thing, except the first accesses the style attribute through the CSS collection (hence the hyphen in the name which all such names use), while the other accesses the attribute directly via the JavaScript prototype property (read: object property).

If you look at JavaScript code and how people operate with CSS values, you will notice this distinction. It is faster to access it directly via the prototype, but traditionally it has been safer to use the named CSS collection. This is because different browsers use slightly different names for things, usually just prefixes.

A bit of context: Firefox uses the “-moz-” prefix, while Safari and Chrome use the “-webkit-” prefix. But in the past few years all the browsers have agreed to support non-prefixed named properties. So instead of for example “-moz-transition” or “-webkit-transition”, you can simply write “transition” and all browsers will understand it.

Hope this helps

I hope this little post have helped clear up how to use TQTXColumnPanel. Keep in mind that the knowledge we have talked about here, such as accessing the underlying element’s styles through the handle property, is universal within QTX. It applies not just to this widget, but all of them.

Theme styling: A primer

One of the major benefits HTML5 / JavaScript holds over native applications is the power of CSS (cascading style-sheets). CSS is a simple way of describing the visual attributes of something, from the size and color of the font to the thickness of borders and even animations. You can even position elements in 3D space if you like using nothing but CSS.

The TQTXWindow class is a highly complex, multi composite widget. Since it’s styling is quite complex, I am considering moving it’s CSS to a separate file. This way we can support multiple visual styles that are not dictated by the application theme.

A CSS file contains the definitions of such styles called style-rules, and once defined you can change everything about your UI with barely any effort. A style rule simply defines a list of attributes and the values you want them to have. Here is an example of a style-rule:

margin: 2px;
padding: 4px;
font-color: red;

Note: While the technical term for such a definition is style-rule, most people simply say style. So when I refer to a style in this article, unless otherwise stated I am referring to a single style-rule definition.

A HTML application can load and use any number of CSS files, which makes it easier for developers to organize and manage styling for their applications. You can have animations in one file, widget styles in another and color definitions in a third. There are some very good CSS visual editors online as well, that you can use to generate complex CSS. Then you can copy and paste the result into a CSS file and use it in your QTX projects.

CSS is vast and covers a plethora of attributes, but for sake of brevity we group the attributes involved into four distinct categories:

  • Visual attributes: border, background, shadows, visibility, opacity; anything visual
  • Behavioral attributes: width, height, padding, margin, clipping and layout
  • Animation attributes: rotating, flipping or moving an element using hardware acceleration, or moving an element in 3D space
  • Typeface attributes: font names, families, their weight and orientation (note that I did not list color, since that is a visual attribute)

There is much more to CSS than these four categories, but if you are unfamiliar with CSS – these four gives you a rough overview of the terrain. Every inch of a HTML element can be altered in some way through CSS, the question really comes down to how do we organize this in a system that makes sense.

This is where the QTX theme ( or scheme ) comes in.

The theme file might look very complex if you are unfamiliar with CSS, but the takeaway is that borders, backgrounds etc are all defined as separate styles with a known name. New theme files must provide the same names, but with different content if you like.

QTX Style Guidelines

In order to bring uniformity and structure to how component writers work, the IDE operates with a few basic laws or guidelines for using or creating your own themes. These laws are simple and non-intrusive.

If you want to deal with the styling yourself and ignore how QTX does things, that is not a problem! It is very important that QTX don’t get in the way of whatever styling developers write themselves, or collide with existing JavaScript frameworks and their styling schemes. But let’s look at how the RTL is rigged to work with theme-files, which is just a normal CSS file with a set of pre-defined, named style-rules.

As long as you follow the “laws” of how the theme file operates, your application will look good should you apply a different theme. As of writing only a single theme is provided (Ubuntu Blue) but more will be written in the near future

First, these are the guidelines for those that wish to create their own theme files. These guidelines must be followed since the RTL and IDE expects this scheme to be in place.

The theme-files divides the styling of a widget into 4 parts: border, background, font and behavior. We dont have styles that mix the attribute groups I mentioned earlier. A border style should just affect the border, a background style should just affect the background. In the RTL we apply multiple styles to a single widget, this is how you can change the border without affecting anything else (!).

  • Border styles must only affect how a border is visually represented
  • Background styles must only affect the background
  • Font styles only affect the font size, weight and pitch. You can set the name of the font if you wish, but the theme-file defines a font for the entire theme, which the rules inherit from. But you are free to override this if you wish.
  • Behavior, size and layout should exclusively be defined in a style that match the Pascal class-name of a widget. TQTXToolbar, TQTXButton and so on all have corresponding style-rules in the themefile.
  • All TQTXWidget based controls will add their own pascal class name to the style-collection of it’s HTML element (all widgets create and maintain a HTML element, in most cases this is a DIV) during initialization of the widget.
  • Widget writers should provide a CSS file in their package that contains style-rules for their Pascal widget class-names. This ensures that element + basic behavior is established instantaneously on creation.

The last 3 items of these guidelines will be confusing to anyone unfamiliar with CSS, they mostly affect advanced developers that write their own packages

Ad-Hoc example

Let us have a look at a direct example of the style mapping mentioned above. First, let us write the smallest possible TQTXWidget we can think of:

You can ignore the [RegisterWidget] and [RegisterInfo] pascal attributes, those just ensure that the IDE registers the widget on the component palette in the IDE when the package loads. Just focus on the class definition for now. And yes, this is a fully working widget, albeit a bit useless.

With the pascal code in place, we need a matching CSS style-rule. Like mentioned already, the widget will add it’s own Pascal name to the list of styles it uses – so all we need now is to have a CSS rule with the same name (note: user styles are prefixed by a dot [.], this is not custom for QTX but a part of the CSS standard).

The above CSS is a fair starting point, and like the guidelines explains, automatically mapped styles should only define behavior essential to the widget. Attributes like padding, margin, minimum size, anything that helps setup the structure of the widget rather than it’s visual attributes.

With our pascal widget and CSS setup, let’s provide a default border and background for the widget. This is done by overriding the StyleObject() method and setting the ThemeBorder and ThemeBackground properties there:

Putting it all together, our new widget is now ready to be registered with the widget palette and be placed in a package file for easier deployment and re-use by other QTX developers. Pretty damn cool if I say so myself!

Widget writers who deliver packages with new and cool widgets for developers to use, just have to provide a CSS file inside the package. When a project using that package compiles, the data-files are copied into the current project automatically by the IDE. The user just have to add the styles to his index.html document. This is literally a one liner operation.

This is the beauty of the QTX scheme. The extreme ease of use, letting the browser deal with as much composing as possible, and try to match things up through logic rather than brute force.

The new qtx.dom.theme unit

The theme system operates with a set of named styles that all widgets must follow. Sure, you can roll your own and ignore the system, that is perfectly fine, but the RTL based widgets are all rigged to use the QTX scheme.

A fair bit of thought has gone into this system, and the borders, backgrounds and colors are made to compliment each other. Developers making their own CSS theme files obviously should ensure they pick colors that go well with each other. For example, the border TThemeBorder.tbButton is made to work well with TThemeBackground.bgButton background type.

In the upcoming release a new unit has been added to the QTX.DOM namespace, namely qtx.dom.theme.pas, which contains the enum types used by the theme files and IDE scheme.

Most importantly is that TQTXWidget has been expanded with two new properties:

  • ThemeBorder: TThemeBorder
  • ThemeBackground: TThemeBackground

These enum types are straight forward in what they represent, and they are simply used as keys into a series of lookup tables in the unit dealing with name-to-type conversion.

You don’t really have to deal with this unit directly unless you want to. The new TQTXWidget properties are available from the form designer and widget inspector.

The enums are used as keys into various lookup tables for quickly setting a theme style

From the form designer and widget inspector, it’s straight forward. You can change the border and background of any widget.

Each widget will set the default border and background they use as a part of their creation, but you can override this and select whatever border or background you wish. Some times it can look good to mix things up a bit.

Windowing is special

The windowing UI that QTX ships with requires a bit more than just border and background styling, so that is somewhat bolted into the theme-file. However, a window is clearly defined in parts (header, footer, content region etc.) so new theme files will definitively contain new look and feel moving windows too.

I am considering separating the window styling into a separate file, so that it’s not subject to whatever color preferences has been set by a single theme. This will require a bit of contemplation before I change it since the window structure is far more complex than a simple, composite widget.

Well, I hope this was informative! More info will be available shortly!

An IoT scenario: Looking at hardware

This article was published on our Patreon site and was available to backers in May of 2022. It is re-published here as part of the drip from what backers have access to and what non-backers have access to.

I dont often write about hardware on this page, but as we near code-freeze to the IDE and development tools- my thoughts return back to our original project, namely the Quartex Media Desktop (codename: Amibian.js).

Just to underline: You dont need a SBC (single board computer) to work with Quartex Pascal. JavaScript runs anywhere, which is the point of making a development toolchain like this to begin with. This article is about working with IoT and embedded devices, which is completely optional.

Since I have written about Quartex Media Desktop before, hopefully everyone understands the value and power that brings. So instead of going into a pitch about that, let’s instead define a use-case where getting a dedicated IoT board makes sense. (Note: If you are not familiar with the Quartex Media Desktop, below is a video that demonstrates the prototype).

The ticket booth scenario

Let us for sake of argument say that you get hired by a large company to deliver a ticket system. The company provides you with a touch display and casing (booth) to house whatever hardware you request to finish this project. Your job is to sort out operating system, back-end technology, commercial dependencies like software licenses -and further, to implement the ecosystem that the customer will see and interact with.

This is where things start to get interesting, because such a ticket system has to scale. There wont just be one such device in use, but rather hundreds – if not thousands nation wide. As a growing business the company hopes to take the product internationally, which could result in hundreds of thousands of devices being deployed around the world.

Above: Amibian.js provides the infrastructure for your JS applications. Things like filesystem, security, IPC, and above all – a windowed environment and process isolation. For Kiosk style applications, your application is run in fullscreen (no windowing borders).

There are many factors to take into account here. In a distributed system that needs to scale, most of the pressure will be on the back-end (server) side of things. I would not attempt to simply “roll my own” back-end for a project of this magnitude, but instead make full use of Docker and Kubernetes to deal with the scaling aspect, while I would write the QTX server to make full use of available CPU cores and process clustering.

Define your products life-cycle

While the back-end will by far be the most complex piece to engineer, it ultimately holds less surprises. Like i mentioned above, technologies like Docker and Kubernetes pretty much solves everything with regards to scaling and meeting demand. What is more important for our ticket booth system, is to make sure we pick an SBC that performs well, and that will continue to perform well as our software grows in complexity.

This period of time is simply called the a products life cycle, with the EOL (end of life) marking the date where a company must upgrade their hardware. What duration we end up with ultimately boils down to growth in complexity, the amount of data that must be represented, and underlying non-visual complexity. For sake of argument, let us define a lifecycle of 3 years. Personally I would try to find devices that can deliver 5 years, but the difference in cost can be very high between the two.

Right out of the gates the Raspberry PI falls short. The first thing on my mind would be to find an SBC that can handle temperatures well, especially cold weather. If you plan to deploy the device to a region with cold winters then you can forget about the Raspberry Pi. You will need insulation in your booth, but for devices not designed for -30 degrees celsius, you also need an expensive regulator and heating elements. It will be more affordable to pick an SBC that can operate at -35c degrees celsius, and instead make sure you have good insulation. With active cooling the board will make sure the insulation doesn’t cause over heating in warm weather.

But for performance, which is ultimately where your code comes in, the Raspberry Pi is not quite up for the job. Sure, it will run Amibian.js just fine, but the performance will always lack “bite” to deal with demanding tasks, especially graphics intensive applications. A ticket booth system will obviously not be “intensive” compared to say, running Quake in the browser – but you dont want something as simple as a few video elements to potentially ruin the customer experience.

Define your low-end mark

Running Quartex Media Desktop (read: amibian.js) doesn’t require that much CPU power for the core system. The system is based on 5 node.js services where only 3 of them are critical for operation, the other 2 are optional. These services can either be installed separately on their own SBC (hardware cluster) or collectively on a single SBC. The node.js services use exceptionally little memory and they are just as fast as any service written in native languages like Delphi (or .Net C# for that matter).

When running a kiosk system with Amibian.js, you adapt the Linux setup to only run your software. You dont actually boot into the Linux desktop, instead you boot into Chrome in it’s own X-window session. Chrome will then run fullscreen in Kiosk mode and load the desktop from localhost. Once loaded into the browser the desktop connects back to localhost via websocket, and use Ragnarok messages to invoke API functions, perform file operations and run programs.

So the boot sequence for our SBC will look something like this:

  • Bootstrap loads kernel
  • Kernel loads Linux drivers, services and initialize
  • PM2 loads our node.js services and starts them
  • Our Node.js services use ZConfig to find each other
  • Each of our services register with the Amibian.js core service
  • Chrome is started in Kiosk mode with URL set to localhost where the Amibian.js core service hosts a webserver supporting websocket
  • Desktop connects back via websocket. All API calls happens via Ragnarok messages over websocket. The core service automatically routes API messages to whatever service is registered to deal with them, and likewise routes the response back to the desktop instance that issues them. In many ways the services act as distributed library files.

So if you install Amibian.js on a single SBC, the experience is indistinguishable from booting a normal, native Linux desktop.

The thing you want to factor in, is the graphical performance of the SBC. While you can run the services on any cheap board, the one hosting the desktop display must by necessity have enough muscle to render the display without issues. This means first and foremost a beefy GPU, but also a processor and RAM enough to delegate everything. A browser is perhaps the single most demanding piece of software in existence today.

As a bare minimum I would recommend:

  • 4 GB of memory
  • ARM v7 (Quad core A73 at 2.4 GHz)
  • SATA interface and boot support
  • eMMc boot support
  • RF / Bluetooth support

The Raspberry PI v4 does hit these marks, or at least it can easily be expanded to cover this list. But keep in mind that this defines our lowest point. This is the absolute minimum that I would recommend for using Amibian.js as your software delivery platform.

As of writing the prices for SBC’s have gone through the roof, and even a Raspberry PI v4 with 4Gb of ram retails for over $100. Which is ridiculous, it’s not worth that by any means unless you have some very narrow educational criteria hanging over you.

A much better buy, one that I picked out two years ago, is the ODroid N2. Not only does it check all the criteria, it actually has 2 extra CPU cores (based on the little-big architecture, where you have 4 powerful CPU cores, and 2 weaker cores). Not long ago the ODroid N2 was replaced with the ODroid N2+ which is roughly 30% faster than the original N2 yet retails at the same price. You can pick up this device for $83 at Hardkernel. And it’s worth every penny for general purpose development. It also acts as one hell of a games system if you want to give your kids a system to play Playstation 1, Sega Saturn and Gameboy Advance type retro games on.

But would I pick the N2+ for a ticket booth with a 5 year lifecycle?

The new breed of SBC’s

Most SBC’s are based on tech created for the mobile phone marked. Meaning that mobile phones drive the development of these SoC’s (system on a chip). The companies that deliver these SoCs want to capitalize on the production infrastructure they have setup, so after the contract for a phone expires, they usually offer the same SoC to embedded and IoT companies – which builds an SBC around them.

There is usually a 5 year delay between a SoC being used in a phone, and the time it becomes available as a fancy new SBC in the IoT sphere. A good example of this is the Snapdragon 880 series which powers expensive phones like Samsung Galaxy Note 9. The 880 series delivers performance comparable to an Intel i5 (first generation), which is incredible value for money.

The coolest board right now is the newly released Firefly SBC. This is not based on the Snapdragon, but rather a brand new RockChip CPU design – but it delivers performance better than Snapdragon 880. It is fitted with a powerful GPU that can handle 8k video and display modes, and you can buy a model with up to 32Gb of RAM (!) – which is a first for SBC’s I believe. I have never seen an IoT SBC with more than 8Gb.

Since manufacturing parts are scarce right now, I was not surprised to see that it retails at well over $200. But when you consider that a Snapdragon 880 development board sells for $2000 – I wouldn’t think twice about giving the Firefly a testdrive. And yes, it ticks all the boxes in our list (it’s way ahead of our minimum). First of all It’s based on ARM v8 (a whole generation ahead of our lowest mark), it has NPU chip which is used to run A.I models, it’s data transfer speeds is astronomical compared to our lowest specs – and you can fit it to an ATX motherboard and use standard PC cases if needed.

So if I was to pick a board right now for our 5 year lifecycle, I would go for the Firefly. If we lower the lifecycle to 3 years, the ODroid N2+ is just impossible to beat. I should underline that GPU support for X has been an issue for the ODroid N2, but that was solved via the Bifrost driver update a while back. But I would make absolutely sure and test it early if you plan on using it.

An alternative to the Firefly board, is Radxa: Rock 5b. This is based on the same RockChip RK3588 SoC that the Firefly uses. Price is significantly lower, especially if you pre-order, but to stay below the $200 mark you are limited to the 16Gb model.

So right now we are in that sweet 5 year spot where the previous generation of SoC’s are being repurposed for IoT devices. Although the RockChip 3588 is the exception rather than the rule. It is either way miles ahead of all the other board out there – and I would not buy anything below this is performance, unless your menu system will only see moderate improvements in the years to come.

Never buy boards for today, always try to think 5 years into the future.

Why not use X86?

You are probably wondering why ARM is the preferred platform in my articles, why not opt for a cheap and affordable x86 board? Intel in particular has dropped it’s prices and there is a lot of good SBC’s that are powered by overclocked Atom CPU’s out there.

Well, there is nothing in the way of using x86, at least at first glance.

A while back there was a movement in the US called “the right to repair” movement. They actually took Apple to court because Apple has consistently gone out of their way to stop people repairing their own machines. Apple even went as far as to fill machines with glue, just to make absolutely sure that nobody could repair, optimize or alter their own devices.

During that trial, which Apple lost, a lot of information was presented about ordinary x86 hardware, information that shocked a lot of people (myself included). Where everything from the firmware to the actual, physical hardware is rigged in in their favor. Microsoft especially has made it damn near impossible to buy a PC without Windows. There are some that allow you to install Ubuntu and pick between the two, but the whole marked is so heavily dominated by third parties that I dont see this changing any time soon.

When you add to this the facts that surfaced about Intel’s SoC’s, namely that they have several back-doors in the SoC design, bolted into the very hardware, that allows them to access your computer remotely – typically in concert with government agencies, suddenly x86 becomes a security risk because these back-doors were first discovered by hackers.

My reluctance for x86 has nothing to do with my personal activities, my digital life hardly warrants interest enough for any remote system incursion, be it the government or Intel. The point here is the principle of the matter, what people do with their computers is nobody’s business. And companies using “financial incentives” to dominate a marked that should be based on fair competition, is not something I will support of condone. Tese tech giants have even gone so far as to have legislation changed to suit their criteria. You dont have to be a rocket scientist to see where this is going, and what that means for consumers.

I should add, this is the real reason why Apple decided to create their own hardware. They have sold their new SoC as being about performance, but it’s actually about getting away from the legislation surrounding x86, parts and repair laws (especially here in Europe). By bolting as much as possible into a single part (SoC) they can ensure that customers are 100% dependent on them, and have to buy a new device. After all, If there are no parts to buy, you cant argue for any rights to repair either.

That’s the kind of people you are helping to fund when you buy their products. I haven’t bought an Apple device in over a decade, and I never will. Nor will i ever buy an Intel PC.

Bricked x86 SBCs

A good example of how controlled the the x86 marked has become – is to have a look at the x86 based UP board. Out of the box this is a good value for money board with the same form-factor and ports as a Raspberry PI. It used to sell for around $120 and is more than capable or running Amibian.js and tick all our boxes. It even has an on-board eMMc drive.

The problem is that their Firmware is bricked to only run two operating systems, namely Windows 10 or Ubuntu. When I asked them how I could boot other operating systems, such as Aros, Android or Haiku (a modern, open source re-implementation of BeOS), they simply dismissed me and referred to their documentation. There is nothing in the way technically for the board to run these alternatives, they would even run exceptionally well – but it boils down to financial incentives: they get paid by Microsoft for each license installed.

So to be perfectly honest: Companies dictating what type of OS you are “allowed” to run on your own device are persona non grata in my book. I simply ignore them and never buy anything from them.

Besides, with so much power and freedom in ARM these days – why on earth would you want to use an x86? The power consumption alone should be enough to say no thank you!

Next article

In this article we went through some of the boards available out there, and had a peek at thinking in life-cycles. I am going to continue writing about this scenario, and in my next article we will have a look at PM2, the process manager we use to run our node.js services in the background when your device starts!

Quartex Pascal version 0.17.2 released

This build contains fixes for bugs that has been lurking around the RTL and IDE for some time. Each revision unveils less and less items to fix, and I believe we are only a couple of builds away to mark the binary as a release candidate! It was a bit sad that the latest DWScript that was going to ship with this build was unstable, but rest assured that we will fork the latest and greatest once the DWScript codebase has been stabilized again. Eric is not one to leave bugs hanging for long.

Quartex IDE now has an RSS feed view to the forum on this website (top-right in the welcome tab)

Fixes for this build

  • Rolled back to previous DWScript which is stable
  • IDE now fetches the RSS feed from our forum (here at quartexdeveloper.com)
  • Fixed a problem with TQTXDynamicApplication model where the ShowForm() failed due to mistaken reintroduction
  • Fixed a problem with TQTXBoxedApplication model where a similar reintroduce caused issue. Both of these further affected the “ShowForm” method, so it was very fortunate that we fixed these now
  • The codegen omitted width when emitting code for TQTXBoxedApplication forms, which it should — this has now been fixed
  • Gave all widgets in the RTL icons. The default green puzzle piece is now reserved for clean HTML definition components (e.g 1:1 wrappers over direct HTML tags, like <Table> or <option> style elements). It also remains as a default glyph in case someone register a widget without a glyph
  • All widgets have been given a [DefaultName(‘<name here>’)] attribute, so that when you add a widget it is not named “widget1” or “Widget2” but rather “button1” or “listbox1” — which is what you expect and have in both Delphi and Lazarus.
  • Added a clean TQTXLeafletMap example, which demonstrates RT’s leaflet map package. Also gave that widget a google maps glyph (not sure it actually uses Google maps, that that is easy to fix).
  • Fixed a problem where WWR (web worker units) was not properly parsed and thus had no unit overview
  • Went over the code that resolves unit-file names, so it’s faster and more maintainable
  • .. and much, much more!

Future changes

With the TQTXBoxedApplicationModel finished, it is time to add that model to the projects menu. So in the next build I hope to have the new project template in place. With that however, the application object’s constructor (which is currently exposed in app.entrypoint.pas) will be consumed by the {$I “app::form.init”} code generator insertion point. Why? Because the application model for a project should not be changed by code, but rather in the build-config. If you change from say, a boxed model to a dynamic model, the only way the IDE can alter the constructor of the application object – is if it controls that snippet of code.

This means that examples have to be gone over, and I also need to adjust the project templates. It is an annoying thing to do in the 11th hour but will do a lot to the user-friendliness of the product, and also leave less confusion as to how to switch model in an already existing project.


Backers can download the latest binary from Patreon

Update to latest DWS in the works

Like I mentioned in the previous posts in Patreon (backers only), we have precious little tickets left! And I have started on the last big change, which is to update DWS (Delphi Web Script) to the absolute latest, bleeding edge version.

This brings us a number of advantages, most notable is the fancy new async and await keywords. So you will be able to define a procedure as purely async, and further define code that waits for that particular condition to finish or fail. The mechanism behind this is called a promise, which is a common JavaScript technology by now – implemented at the lowest levels of JSVM both for the browser and Node.js.

This will have a profound effect on how we write wrapper code for external libraries. At the moment we have to use a bit of inline javascript in ASM sections to pascalify these mechanisms — so it will be a great to finally be able to work directly with promises as a part of the pascal language.

A pseudo example is when downloading a file via the fetch() browser method:

await fetch(url, procedure (data: JByteArray)
// Success code here, bytes in the data param
procedure (error: JError)
// Error handling here


Since we forked DWS some 3 years ago, there have been a lot of internal changes to the compiler and infrastructure. This includes name changes that, while superficial, affects more or less every inch of the IDE code. I cant just do a mass-rename inside the source-code either, since there have been subtle changes in a few public elements that are now protected.

In short, this will take a week more to get to grips with — but it will be worth the wait!

Website, forum and gearing up for RC1

As we are nearing RC1 with only a handful of tickets left, there are about to be some serious changes to our infrastructure.

So far we have operated with Patreon as our means to finance the development, and Facebook as our daily driver for live status, quick feedback and general community talk. This model has served the project well, except that Facebook really is a terrible place to run a group that is 100% dependent on a single person.

Facebook supports multiple account, and you would imagine that you could establish a business account and a personal account – and that these would be completely separate from each other. Sadly that is not the case, and should my personal account be blocked for whatever reason the Facebook A.I decides that day, the business account becomes locked as well.

It was never a long term plan to stick with Facebook, so it was time to bite the bullet and purchase a professional installation of WordPress with a forum plugin. And this is exactly what I have done. I was aiming to wait with that step until after version 1.0 was out the door, but Facebook has made it difficult to have both a personal life and professional life (which I consider separate) on the same platform. I have outlined at length how absurd the Facebook A.I operates, how it mistakes Norwegian words for English (with disastrous results) and so fourth. You can read that article here.

New model

Before x-mas I did a couple of polls in our Facebook group regarding how we should proceed. Regardless of the above mentioned debacle, Facebook as a platform is really only suited for user-groups and keeping track of friends. There is also the financial aspect of the product to consider. We need a stable income to ensure stable development of future versions. If we manage to secure enough, I would be able to work full time on this rather than just weekends. That would be much more effective for everyone and I would be able to expand the range and power of the product a thousand fold compared to what we have today.

The result of the polls were quite simple:

  1. We continue to use Patreon for handling backing and donations
  2. The Facebook group will become public (read: anyone can join, not just backers) much like Delphi Developer, FPC Developer and the other groups I run in the same family.
  3. New binaries will exclusively be issued via Patreon
  4. Community edition will be available on this website, but that will only be major releases (LTS). Those that wish to have running updates, patches and cutting edge documentation must subscribe to a Patreon tier. This is what everyone else is doing and it makes more sense. There has to be an incentive to get the cutting edge stuff (and yes, the tiers will be adjusted to better suit this model).

To give you some idea of cost, a year worth of $25 a month backing, which gets you binary updates (including docs) and articles is exactly $300. Keep in mind that this also includes the cluster environment, a ton of new components I will write, and all the fancy stuff that is lined up for version 1.1 and 1.2 (like database components, filesystem over WebSocket and so on). The hard work with the IDE is done, and we can polish and make sure the details get better – but all in all the IDE infrastructure is ready to rock. Focus after version 1.0 will be more on content, demos, articles, ready to use project templates, new packages, utility features and drop-in protocols (yes you read that right). This is where the fun begins.

This is a product that we can aggressively expand to consume pretty much whatever we want of the JSVM / React / Node.js world. We don’t have to wait for Idera or Embarcadero or anyone else. QTX is a free agent and answers to nobody but the backers. Once we agree on a tech, I get to work and make it a part of the IDE and RTL. And this also includes exciting stuff like bytecode assembly, WASM and baking native executables via Phonegap and React directly from the IDE.

In plain English: We can’t keep going like we have up to now, because we are financially nowhere near where I can jump over full time (or 50% for that matter). The only way to get anywhere close to a 50% position, is to get everyone over on Patreon. Even if it’s just the lowest Tier (I will adjust the tiers) that would radically change things. It’s a long term goal, but it’s there.

There is also something to be said about simplicity. Having to re-post the same news in 3 places is a bit much. At least now we have this website as the main focal point and Patreon for backers and “subscriptions”. So feel free to post to the forums here on this website (you probably need to register first).