Create web-and-mobile.md

This commit is contained in:
Bane Stojkovic
2026-10-12 13:50:48 +02:00
parent 505f06d26c
commit 9e4ce7da81
+170
View File
@@ -0,0 +1,170 @@
# 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`, through
`IPlugInPort`, 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, and `DrawingManager.drawProject`
accepts any `Graphics2D`. A canvas, SVG or Android-Canvas `Graphics2D` plugs
in at the same point.
- **Rendering already works without a window.** `RegressionTestRunner` exports
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.geom` is everywhere.** `Point2D` is imported ~250 times,
`AffineTransform` ~160, `Shape` ~175. `Area` boolean 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 using `FontMetrics`, `GlyphVector` or `FontRenderContext`.
- **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:
1. **A replacement `java.awt.geom`** — port OpenJDK's pure-Java geometry
classes, including `Area`. Check license compatibility of OpenJDK's
GPLv2 + Classpath Exception sources with DIYLC's GPLv3 before copying.
2. **A canvas-backed `Graphics2D`** — strokes, transforms, composites, clips,
gradients; text measured through canvas `measureText`. `ShadedPaint`
reimplemented as canvas gradients.
3. **A build-time component list** replacing the Reflections scan (an
annotation processor emitting the list of `@ComponentDescriptor` classes).
4. **A `.diy` reader/writer without XStream** — hand-written, or a small
server-side conversion step. The serialized shape is a public contract, so
validate against `diylc-regression-data/input`.
5. **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
1. **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.
2. **Remove Swing from core (4.1).**
3. **Build-time component discovery (4.2).**
4. **Headless viewer / export service (C).** Mobile viewing and sharing
cheaply, building on the cloud features.
5. **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?