Objo Studio Can Now Build Web Apps!

Objo Studio now has a new project type: Web.

Web Projects let you build responsive applications for the web in the same IDE and language you already use for Desktop and Command Line apps. You design pages visually, write ordinary Objo code, run the project in your browser and debug its server-side events with breakpoints, stepping, variables and watches.

That’s the short version and if that’s enough to get you excited by all means download Objo Studio now and play around for free.

The more interesting version is that Web Projects were designed as part of Objo Studio rather than grafted onto later. Objo was always going to support web apps from its very inception.

For the time being, Web Projects are being released as a public beta. Objo Studio itself remains a shipping product; the beta label applies specifically to web apps whilst the community tests the tool and we iron out any wrinkles.

Web projects are not desktop windows shoe-horned into a browser

A Web project is a server-hosted Objo application. Your interface runs in the browser, while your application code normally runs on the server. Objo does not translate your source into JavaScript. It does not copy your server code into the page. The browser runs a small, fixed client supplied by Objo Studio and communicates with the application through a strictly typed protocol.

Each browser tab receives its own isolated logical session, including its own:

  • App instance
  • Pages and controls
  • Properties and local state
  • Tasks
  • Output
  • Authentication identity and roles

Opening a second tab therefore creates a genuinely separate application session. If a temporary network interruption occurs, the original tab will reconnect to its existing session without running the application’s startup code again.

This is deliberately similar to the mental model used by Desktop apps: you create controls, handle their events and update their properties. The substantial difference is that the framework understands there is a network and a browser between the code and the interface.

That distinction sounds obvious. Web development has nevertheless spent a surprising amount of time pretending it is not important.

Responsive web apps

Web pages are designed at three explicit visual breakpoints:

Breakpoint Grid
Compact 4 columns
Medium 8 columns
Wide 12 columns

Every control has a placement at each visual breakpoint and the IDE helps visualise this and copy the arrangement to different visual breakpoints.

A web page’s layout uses a responsive grid rather than absolute pixel coordinates. Studio prevents controls from overlapping and validates every layout before the project can run or be published. This is one of the areas where I think Objo is substantially better designed than competitors like Xojo.

Xojo’s current Web layout API still exposes control geometry primarily through pixel-based Left, Top, Width and Height properties combined with edge-locking flags. Its Flex layout applies only to WebContainer controls added at runtime. That is an understandable evolution from a desktop layout editor, but it is not any sane person would design a responsive web app today.

Objo starts with the browser’s layout problem instead. Compact, Medium and Wide are not previews of one fixed arrangement being stretched hopefully across different screens. They are first-class layouts, edited visually and validated together.

The result is far more predictable. You can make a form become a single column on a phone, use more horizontal space on a tablet and present a proper dashboard on a large display without writing resize handlers or calculating coordinates.

Your browser should not need a degree in archaeology to discover where a button was intended to go.

Controls that behave like they should in the browser

The initial Web catalogue contains 22 controls:

  • Button
  • Canvas
  • Chart
  • CheckBox
  • ColourPicker
  • ComboBox
  • DateTimePicker
  • GroupBox
  • ImageViewer
  • Label
  • ListBox
  • NumericTextField
  • PopupMenu
  • ProgressBar
  • RadioButtonGroup
  • SearchField
  • Separator
  • Slider
  • TabPanel
  • TextArea
  • TextField
  • TimePicker

The browser client uses native elements and established accessibility patterns wherever possible.

For instance, labels can be associated with inputs. GroupBox uses fieldset and legend semantics. TabPanel supports proper keyboard navigation. ProgressBar respects reduced-motion preferences. Charts include an accessible View data table rather than assuming that everybody can obtain information from coloured lines and slices. These controls have been thoroughly thought out.

Web Projects support System, Light and Dark themes with a project accent colour. The visual designer can preview both light and dark appearances without changing the saved project setting.

Serious data controls

I didn’t want the Web controls to become toys that worked for a five-row demonstration and collapsed as soon as somebody connected a real database.

ListBox can own stored rows or operate as a virtual, database-backed view. In virtual mode the browser requests bounded ranges while the full dataset remains in SQLite, PostgreSQL or another server-side store. Sorting, editing and selection use stable row identities rather than requiring every record to be copied into the page.

ComboBox similarly keeps its complete item catalogue on the server. The browser receives a bounded window of relevant suggestions as the user types, allowing a catalogue to grow well beyond the old “send every choice to the browser and hope” approach.

Chart keeps its data on the server while resize, HiDPI painting, hover, tooltips and keyboard navigation happen locally after a validated snapshot arrives. Bar, horizontal bar, line, scatter, pie and doughnut charts are included.

A Canvas control without a round-trip

Canvas is the deliberate exception to the usual server-side execution model.

You still drag a Canvas onto a WebPage and write familiar handlers such as:

Sub BadgeCanvas_Paint(g As Graphics)
    g.Clear(Colour.White)
    g.DrawingColour = Colour.Blue
    g.FillCircle(Me.Width / 2, Me.Height / 2, 32)
End Sub

Studio privately compiles the Canvas handlers and the safe helper code they use into a bounded client image. That image runs inside a first-party WebAssembly Worker in the browser.

Painting, presses, double-presses, focus changes and scale-factor updates can therefore execute beside the Canvas. Drawing frames and raw input do not make a round trip through the application server.

This is another architectural difference from Xojo. Xojo’s WebCanvas documentation exposes a DiffEngineDisabled property which determines whether all graphics commands or only their differences are sent to the browser. Objo instead moves the relevant Objo event code into an isolated browser worker.

It remains Objo code. There is no separate JavaScript canvas project and no hidden collection of callbacks to maintain.

One Solution, Several Applications

Web Projects make much more sense when considered alongside the rest of Objo Studio.

An Objo solution can contain several projects:

Acme Tools
├── Shared
│   ├── Customer
│   ├── CustomerValidator
│   ├── Invoice
│   └── ReportFormatter
├── Acme Desktop
├── Acme Web
└── Acme Importer

Acme Desktop can provide a rich native interface for staff. Acme Web can expose a responsive portal to customers. Acme Importer can be a Command Line app used by scheduled jobs or an administrator.

The Customer, Invoice and validation code lives once under Shared. Studio compiles it into each application alongside that project’s own source.

Shared Code can contain classes, interfaces, enumerations, modules, business rules, parsers, data models and utility functions. Shared images and resource files are supported too, with individual projects able to replace a shared asset when they need a target-specific version.

Naturally, shared code must use APIs available to every target that consumes it. A shared invoice calculator can be used everywhere. A method that opens a Desktop window cannot magically become meaningful inside a Web application.

The important point is that sharing is part of the solution model. It does not depend on duplicate source files, symbolic links or remembering which project contains the authoritative copy.

Run, Debug and Publish

Choose Run and Studio starts a private development host on your computer, selects an available loopback port and opens the configured browser.

Choose Debug and you can put breakpoints in server-side Web events, step through code, inspect variables and use watches just as you would in a Desktop or Command Line project. Application output appears in Studio’s Output panel without filling it with routine Web server and WebAssembly machinery.

During a normal Run, the host can serve several logical sessions. Debug deliberately admits one session so the debugger has an unambiguous application state.

For deployment, Studio’s normal workflow goes directly to Publish. It creates one self-contained native executable for the selected platform. The destination computer does not need Objo Studio or a separate .NET installation.

The published application is a real server process. You can choose its default port and network access, override those settings from the command line and place it behind the reverse proxy, TLS, monitoring and restart policy appropriate to your deployment.

Objo Studio does not claim that making an executable removes the need to operate a server. That would be convenient, but it would also be nonsense.

Why Beta?

The foundation is substantial but this is a huge addition to Objo Studio and I acknowledge it probably still needs a little refinement before we can say it is completely ready.

The beta does not currently include arbitrary HTML, CSS or JavaScript or custom Web controls. Remote debugging and Web project unit-test targets are not yet available. Debugging is limited to one browser session, and Canvas is an immediate-mode 2D surface rather than a complete game framework.

Another way to build with Objo

Web Projects do not replace Desktop or Command Line development.

Sometimes the right application is a native desktop tool with menus, multiple windows and direct access to the computer. Sometimes it is a small Command Line utility that can be scripted and scheduled. Sometimes it needs to be available from any machine with a browser.

Quite often, a useful product contains all three.

Objo Studio can now keep those applications in one solution, build them with one language and let them share the code that actually defines the product.

That is the larger point of Web Projects. They are not a separate Web edition of Objo and they are not an attempt to disguise a JavaScript framework as a visual BASIC.

They are another first-class application target inside the same development environment.

A responsive designer that understands breakpoints. Controls that respect the browser. Server sessions with clear isolation. Local Canvas execution where latency matters. Shared Code that is genuinely shared. One executable when it is time to deploy.

Web development still contains plenty of unavoidable complexity. I would simply prefer that putting a button on a page was not part of it.

Pricing / licensing

Creating web projects in Objo Studio does not require a special license. Just like for desktop, you can build and test your web projects in your local browser for free. When you’re ready to deploy the web app to an actual web server you will need an Objo Studio license. This is the same license that is required to deploy desktop and command line apps - one license covers all platforms. You get 12 months of updates including and your license will continue to work with all Objo Studio versions released during your license period.

From 1st October 2026, the price of a license will be £129 (plus applicable taxes). This is a modest increase from the current £99 to reflect the additional value Studio is now provided. If you were on the fence about buying a license - now is the time to do so and save yourself a little money.

Anyone with an existing license that is valid will be able to publish web apps immediately.

Visit the Pricing page or Buy Now.

Download Objo Studio and try Web Projects during the public beta. The Web Projects documentation includes a from-blank walkthrough, deployment guidance and the complete Web API.

This is a really giid decision as I know how important Web applications are. We have customers running our Web Server system for 2000 concurrent users. This is for enterprise applications absolutely needed. As your competitor I can only say: congratulations.

Thanks for the support. I welcome healthy competition - it does tend to make everyone’s product better. What a wonderful world to live in where there are actually some really good BASIC-like visual languages available once again :slight_smile:

@Garry you caught me. I was not expecting Web Support. What a great contribution… looking forward…

Thank you Garry for this important update. Web applications are a very important part of the development landscape nowadays.

I also agree with you, healthy competition is very good for customer and developer.

Kind regards,

Chris

Garry, i’m curious. In the WebCanvas, with all if the drawing code compiled and running as WebAssembly, how do you deal with a drawing that relies on data with a changing source, like animation or from a database?

Hey Greg. Good question. There are two different cases.

For self-contained animation, the state can live in the browser-side page instance. A Paint handler can update that state and call Me.Refresh(). Objo schedules a coalesced repaint for the next browser animation frame, with only one Paint in flight, so no drawing traffic crosses the network. V1 does not provide an Update event, timer or deterministic game loop, though, so this is intended for relatively simple animation rather than games. It is something on the roadmap.

Database-backed drawing is different. Database work remains on the server and the Canvas worker has no database or network access. The server can call Canvas.Refresh(), but that requests a repaint; it does not transfer application data. The compiler also prevents mutable page state from being used by both server and Canvas code, because those are separate VMs and the two copies would otherwise silently diverge.

So the honest answer is that arbitrary server-fed Canvas data is not supported in the current beta. It needs an explicit, typed and bounded server-to-Canvas snapshot mechanism, rather than silently copying application state or risking secrets reaching the browser. That is post-V1 work.

For database visualisation today, Chart is the better fit where possible: the server sends it a validated immutable data snapshot, after which resizing, painting, hover and keyboard interaction all happen locally in the browser. A completely custom database-backed Canvas drawing is currently a limitation.

Since I wrote the javascript diff engine you spoke about (all in xojo btw) i can tell you that getting it right for the best performance is tricky. Xojo literally writes the jscanvas code on the server, makes a diff between the previous state and the current state, sends the diff to the browser, and reapplies it to the state that’s in the browser. Even with all those steps, it’s way faster than sending all of the drawing code over and over. I had looked into making a mechanism where users could define the “variables” up front and only send those, but we found it to be too restrictive for what users wanted the canvas to do (which was “behave just like the desktop canvas”).

That is extremely useful context, especially since you wrote the original engine. I understood the broad approach, but I didn’t know you had already experimented with transferring predefined variables and rejected it for exactly that reason.

Objo currently starts from the opposite end: the Paint code and its local state live in the browser, eliminating the drawing-command transfer entirely. That is excellent for animation and low-latency interaction, but it makes the boundary obvious whenever drawing depends upon server-side state.

I wasn’t considering a fixed collection of designer-defined scalar variables. My first thought was an explicitly published, immutable value tree which the browser would replace atomically. That could handle database-fed charts, maps and similar visualisations without transferring graphics commands.

However, you’re right that even a flexible snapshot does not make the Canvas behave exactly like its desktop counterpart. If Paint expects to call arbitrary methods or consume wider application state, the developer still has to design around the server/browser boundary.

The phrase “behave just like the desktop Canvas” is the important part for me. I’ve tried to keep the Desktop and Web programming models conceptually close, and requiring developers to reshape their application state specifically for Canvas might expose too much of the underlying architecture.

The WebAssembly approach still has significant advantages, but I need to rethink how server-side state can participate while keeping Canvas natural to use. I don’t yet know whether the best answer is a richer data-transfer mechanism, some form of hybrid execution or something else.

You could also implement a server side JavaScript renderer so the web UI is rendered directly to vectors which you grab on the screen site and text objects. So you could have both. That’s a bit like the XoJo way.
I am rendering also direct to vectors with my own vector engine, images we are rendering also partially when changes are only partially. This way grants me a good connectivity. Text rendering and vector rendering is done browser side, mouse action and keyboard action is grabbed by javascript and transferred back. As I can grab the vector renderer from the Javaclass directly I have the control and the performance. It is - at the end - a bit similar to the XoJo way of handling that but many times faster and less memory consuming. It has nice parts depending what you want. If you have your target in enterprise applications like me, it is the right way. If you want to deliver extreme render-rich graphical web applications your entire client side rendering approach is the right one.

My impulse would be to step back from Canvas and expose a more general purpose standard API first for client/server communication because there will surely be other use cases that Objo’s framework and its users will need. Canvas support could build atop that. In other words I wonder if thinking of it in terms of Canvas is premature specialization. But that is just my spider sense tingling – it’s not always accurate, and of course I lack insight into all the balls you currently have in the air, as well as the years of thought you have doubtless already put into this, at least back-of-mind.

That’ll be far too slow for a very complex drawing. You’ll maybe get up to 100 elements but then network latency becomes the problem… and don’t get me started on things like

g.drawpicture anyArbitraryPicture, 50, 50

For a canvas on the browser to render a picture, it needs to already be cached in the browser before the drawing code runs. Ever notice that when you draw a picture in Xojo, it draws once without and then a second time with the pictures? That’s the reason.

Don’t forget about handling conditional code too.

if objState = true then
   // draw the blue pill
else
  // draw the red pill
end if

Those are the ones that get you into a lot of trouble and the diff engine was very good at handling.

Yes, you’re right. That’s always a problem and explains the XoJo way related problems really good.

I think the last few replies have helped clarify the problem quite a bit.

bgrommes point about this perhaps being a more general client/server communication mechanism rather than something invented specifically for Canvas is a good one.

Greg’s conditional example also gets to the heart of the difficulty. Simply transferring a handful of variables isn’t really enough. If Paint does:

If SomeObject.State Then
   # Draw one thing
Else
    # Draw something else
End If

then SomeObject.State has become part of the client-side Paint dependency graph. And Paint might call another method which reads another property, and so on. Trying to make arbitrary server-side application state transparently available to that code starts looking very much like distributed shared memory, which I definitely don’t want to deal with!

I’m increasingly thinking the cleanest model is:

  • Canvas code continues to execute locally in the browser, as it does now.
  • The server can explicitly publish an immutable, typed snapshot of data to the browser.
  • A Paint invocation sees one coherent version of that snapshot for its entire duration.
  • Updates replace the snapshot atomically rather than trying to synchronise individual variables.

Pictures are another useful wrinkle. A snapshot can’t simply contain a reference to a server-side Picture and hope for the best. Any referenced image or resource would need a stable client-side handle, with the browser ensuring it’s cached before a snapshot requiring it becomes active. Otherwise you get the horrible class of bugs where the first Paint is missing an image and the second Paint mysteriously works.

There are still cases where arbitrary desktop Canvas code simply cannot be moved to the browser because its dependency graph eventually reaches something inherently server-side, such as a database. I think I’d rather have the compiler tell you exactly where that boundary is than silently turn the Canvas into a remote renderer and introduce unpredictable latency.

So I don’t think I’ve solved it yet, but the discussion is definitely narrowing the problem so thanks!