7.8 KiB
Web and Mobile
Options for running DIYLC in a browser or on a phone, given that every
component draws through AWT Graphics2D and the shell is Swing.
1. Goal
Decide how DIYLC could reach the web and mobile without giving up the
component library, the .diy file format, or rendering parity with the
desktop build. This document records where the codebase stands, what each
route would cost, and the order in which to explore them.
2. Where the codebase stands
| core | library | swing | |
|---|---|---|---|
| Lines of Java | ~28k | ~81k | ~24k |
Files importing java.awt |
63 / 241 | 278 / 317 | 151 / 168 |
Files importing javax.swing |
7 | 3 | 148 |
2.1 What makes a port easier
- Editing logic does not depend on Swing.
Presenter, throughIPlugInPort, takes model-level events:mouseClicked(Point, button, ctrl, shift, alt, clickCount),mouseMoved,dragStarted,dragActionChanged,dragEnded,keyPressed. Selection, dragging, snapping, undo and netlists live in core, so a non-Swing front end could drive them. - All drawing goes through one
Graphics2D.G2DWrapper extends Graphics2D(diylc-core/.../presenter/G2DWrapper.java) already sits between the components and the real renderer, andDrawingManager.drawProjectaccepts anyGraphics2D. A canvas, SVG or Android-CanvasGraphics2Dplugs in at the same point. - Rendering already works without a window.
RegressionTestRunnerexports PNGs and netlists for ~700 projects with no UI. - Swing has leaked into core in only a few places (see 4.1).
2.2 What makes a port hard
java.awt.geomis everywhere.Point2Dis imported ~250 times,AffineTransform~160,Shape~175.Areaboolean operations appear about 745 times in core and library, and continuity, the netlist and hit-testing all depend on them. No JS/WASM Java runtime except CheerpJ ships these classes.- Text is measured through AWT. 38
new Font(...)calls in the library and 38 files usingFontMetrics,GlyphVectororFontRenderContext. - A custom AWT paint:
org.diylc.awt.ShadedPaint/ShadedPaintContext. - Heavy runtime reflection. XStream reads and writes the file format and
Reflections discovers components at startup (
ComponentProcessor). Both work badly or not at all under ahead-of-time compilers such as TeaVM or GraalVM's web image. - Mobile has no AWT. Android has no
java.awt, and Gluon's JavaFX-on-mobile stack does not support Swing or AWT drawing. A mobile build needs either a web build or an AWT replacement layer. - Build targets Java 21. Only a handful of Java-21-only calls were found, so retargeting to 17 for a runtime that needs it looks feasible.
3. Options
| # | Route | Effort | Result | Mobile |
|---|---|---|---|---|
| A | Existing JAR in the browser via CheerpJ | days | Full desktop app in a tab | Loads, unusable |
| B | Stream the Swing app via Webswing | days | Full app, no download | Poor |
| C | Headless Java service + thin web client | weeks | Viewer / exporter | Good for viewing |
| D | Engine compiled to JS/WASM + new web UI | months | Touch-capable editor | Good (PWA / Capacitor) |
| E | Rewrite in TypeScript or Kotlin Multiplatform | very large | Anything | Good |
A. CheerpJ
A JVM compiled to WebAssembly that runs the current JAR client-side. Swing, AWT, XStream and reflection all work. Costs: large download, slow first load, a desktop UI on touch screens, and possibly a commercial license.
Unverified: which Java versions the current CheerpJ release supports (may
require a --release 17 build) and its license terms for an open-source
project.
B. Webswing
Runs the Swing app in a server-side JVM and paints it into a browser canvas. Costs: one JVM per user, ongoing hosting, drag latency, commercial license.
C. Headless service with thin client
Core and library run as a service that renders PNG or SVG and accepts
IPlugInPort calls. Strong as a viewer and exporter: open a .diy, get
images, BOM and netlist. Fits beside the existing cloud and sharing features,
though diylc-server-api is PHP, so this would be a separate Java service.
Too much latency for smooth drag editing.
D. Engine to JS/WASM with a new UI
Compile core and library with TeaVM (or GraalVM's web image) and supply:
- A replacement
java.awt.geom— port OpenJDK's pure-Java geometry classes, includingArea. Check license compatibility of OpenJDK's GPLv2 + Classpath Exception sources with DIYLC's GPLv3 before copying. - A canvas-backed
Graphics2D— strokes, transforms, composites, clips, gradients; text measured through canvasmeasureText.ShadedPaintreimplemented as canvas gradients. - A build-time component list replacing the Reflections scan (an
annotation processor emitting the list of
@ComponentDescriptorclasses). - A
.diyreader/writer without XStream — hand-written, or a small server-side conversion step. The serialized shape is a public contract, so validate againstdiylc-regression-data/input. - A new TypeScript UI replacing the ~24k lines of Swing, driving
IPlugInPort.
Shipped as a PWA, or wrapped with Capacitor for the app stores, this covers
iOS and Android. The same geometry layer plus an Android-Canvas Graphics2D
would also allow a native Android build. Expect text-metric differences to
show up as regression-suite diffs.
E. Rewrite
About 130k lines and a file format to keep compatible. Not worth it compared with D, which keeps the library intact.
4. Groundwork that pays off on every route
4.1 Remove Swing from diylc-core
| File | Swing / desktop use |
|---|---|
presenter/Presenter.java |
JOptionPane error dialog |
presenter/ComponentProcessor.java |
Icon, ImageIcon |
common/ComponentType.java |
Icon |
core/images/IconLoader.java |
javax.swing.* |
plugins/cloud/service/CloudService.java |
Swing import |
plugins/compare/util/CompareResultsHtmlReport.java |
Swing import |
plugins/chatbot/service/JsonToHtmlConverter.java |
Swing import |
utils/Constants.java |
Toolkit screen resolution |
Move dialogs behind an interface implemented in diylc-swing, and represent
icons as image data rather than Icon. The three Swing imports in
diylc-library (MultimeterAnalyzer, GuitarDiagramAnalyzer,
components/misc/Image) need the same review.
4.2 Build-time component discovery
Replace the runtime Reflections scan with a generated list. Speeds up desktop
startup and removes a blocker for routes C and D. Discovery must still find
every @ComponentDescriptor class with no registry to maintain by hand.
4.3 Measure the AWT surface precisely
Before committing to D, list every AWT class and method actually called from
core and library (e.g. with jdeps or a bytecode scan). That inventory sizes
the replacement layer and shows which Graphics2D operations the canvas
backend must support.
5. Next steps
- CheerpJ proof of concept (days). Run the current JAR in a browser, confirm the Java version and license questions in A. Tells you whether "DIYLC in a browser" is wanted with almost no code change.
- Remove Swing from core (4.1).
- Build-time component discovery (4.2).
- Headless viewer / export service (C). Mobile viewing and sharing cheaply, building on the cloud features.
- Only if a real web or mobile editor is the goal: do 4.3, then start D
with the geometry layer and the canvas
Graphics2D. Use the regression suite's ~700 reference PNGs to check that browser and desktop render the same.
6. Open questions
- Is the target a full editor, or is viewing and sharing on mobile enough? This alone decides between C and D.
- Should the web build be offline-capable (PWA), or may it require a server?
- Is a commercial runtime (CheerpJ, Webswing) acceptable for a GPLv3 project?