zui 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Desktop.qml CHANGED
@@ -64,11 +64,14 @@ QQC.ApplicationWindow {
64
64
  }
65
65
  Text {
66
66
  anchors.horizontalCenter: parent.horizontalCenter
67
+ width: Math.max(0, Math.min(680, window.width - 48))
67
68
  text: service.lastError !== "" ? service.lastError
68
69
  : (Fonts.failed ? "Zui could not load its bundled fonts" : "Starting Zui…")
69
70
  color: Color.foreground
70
71
  font.family: Style.font.family
71
72
  font.pixelSize: Style.font.body
73
+ horizontalAlignment: Text.AlignHCenter
74
+ wrapMode: Text.Wrap
72
75
  }
73
76
  }
74
77
 
data/README.md CHANGED
@@ -1,24 +1,80 @@
1
- # Zui
1
+ <p align="center">
2
+ <img src="docs/assets/readme-hero.svg" width="100%" alt="Zui — native desktop applications in pure Ruby">
3
+ </p>
2
4
 
3
- Zui builds beautiful native desktop applications in pure Ruby, with first-class UI, state,
4
- events, bindings, animation, media, GPU effects, 3D, and application logic. Applications are
5
- Ruby and assets—there is no application UI language to learn alongside Ruby.
5
+ <h1 align="center">Native desktop applications in pure Ruby</h1>
6
6
 
7
- Zui is desktop-only. Its native client intentionally excludes browser-engine payloads while
8
- retaining the complete desktop component catalog.
7
+ <p align="center">
8
+ Build reactive Linux, macOS, and Windows interfaces with one Ruby API, a native Qt renderer,
9
+ and no application-owned QML or browser runtime.
10
+ </p>
9
11
 
10
- This repository is the reusable core. Distribution integrations live at its edges:
12
+ <p align="center">
13
+ <a href="https://rubygems.org/gems/zui"><img alt="RubyGem" src="https://img.shields.io/gem/v/zui?style=flat-square&color=9cff57&labelColor=111711"></a>
14
+ <a href="https://github.com/AdamMusa/zui/actions/workflows/platforms.yml"><img alt="Native platforms" src="https://github.com/AdamMusa/zui/actions/workflows/platforms.yml/badge.svg"></a>
15
+ <img alt="Ruby 3.1 or newer" src="https://img.shields.io/badge/Ruby-%E2%89%A5%203.1-cc342d?style=flat-square&labelColor=111711">
16
+ <img alt="241 components" src="https://img.shields.io/badge/components-241-46e8ff?style=flat-square&labelColor=111711">
17
+ <a href="LICENSE"><img alt="MIT license" src="https://img.shields.io/badge/license-MIT-a79cff?style=flat-square&labelColor=111711"></a>
18
+ </p>
11
19
 
12
- - Linux and Windows desktop applications use the standalone Qt host.
13
- - macOS applications use the same host inside a standard application bundle.
14
- - Omarchy plugins and applications use the separate
15
- [`omarchy-ui`](https://github.com/AdamMusa/omarchy-ui) adapter.
20
+ <p align="center">
21
+ <a href="#quick-start">Start</a> ·
22
+ <a href="#platform-support">Platforms</a> ·
23
+ <a href="#component-catalog">Components</a> ·
24
+ <a href="#reactive-by-design">Reactivity</a> ·
25
+ <a href="#how-zui-runs">Architecture</a> ·
26
+ <a href="#ship-an-application">Distribution</a> ·
27
+ <a href="#showcase-applications">Examples</a> ·
28
+ <a href="https://zui.alkimist.dev">Documentation</a>
29
+ </p>
16
30
 
17
- Zui ships a standard Qt `ApplicationWindow`, a bidirectional `QProcess` bridge, its own neutral
18
- theme and controls, and the full built-in component catalog. It has no runtime dependency on
19
- Quickshell or an Omarchy installation.
31
+ ---
20
32
 
21
- ## Core API
33
+ Zui is a desktop UI framework for Ruby. Application code owns the interface, state, behavior,
34
+ and assets; Zui owns the rendering protocol, native host, platform-neutral QML implementation,
35
+ and complete component catalog. The result is a normal desktop application—not a web page inside
36
+ a window.
37
+
38
+ <table>
39
+ <tr>
40
+ <td width="33%"><strong>One application language</strong><br>Compose UI, state, bindings, events, commands, timers, and application logic in Ruby.</td>
41
+ <td width="33%"><strong>Native desktop renderer</strong><br>Render through Qt Quick, Controls, Multimedia, GPU effects, Shapes, and optional 3D modules.</td>
42
+ <td width="33%"><strong>Private verified runtime</strong><br>Install a checksummed native client without changing system Qt or shell configuration.</td>
43
+ </tr>
44
+ <tr>
45
+ <td><strong>241 named components</strong><br>Use specific controls with validated properties and events instead of a generic markup escape hatch.</td>
46
+ <td><strong>Reactive by default</strong><br>Update only changed properties and publish multi-value transactions as atomic patch batches.</td>
47
+ <td><strong>Portable source</strong><br>Run the same application on Linux, macOS, Windows, or through an environment adapter such as Omarchy UI.</td>
48
+ </tr>
49
+ </table>
50
+
51
+ <p align="center">
52
+ <img src="examples/nova_pour/preview.png" width="880" alt="Nova Pour, a complete pure-Ruby Zui desktop application">
53
+ </p>
54
+
55
+ <p align="center"><sub>Nova Pour is one of the complete applications included in the showcase catalog.</sub></p>
56
+
57
+ ## Quick start
58
+
59
+ Install Ruby 3.1 or newer and the gem. Zui downloads its version-matched native client and small
60
+ mruby bundle runtime only when you explicitly configure it:
61
+
62
+ ```bash
63
+ gem install zui
64
+ zui doctor --fix
65
+ zui new telemetry-console
66
+ cd telemetry-console
67
+ zui run main.rb
68
+ ```
69
+
70
+ That is the complete development setup. You do not need a Qt SDK, CMake, a C++ compiler, or a
71
+ system-wide Qt installation.
72
+
73
+ `zui doctor --fix` downloads the native client and lite mruby runtime for the installed Zui
74
+ version, verifies their SHA-256 checksums and manifests, and activates them atomically in the user
75
+ cache. It does not modify shell startup files or global Qt environment variables.
76
+
77
+ ## Your first application
22
78
 
23
79
  ```ruby
24
80
  require "zui"
@@ -46,51 +102,52 @@ end
46
102
  Counter.run
47
103
  ```
48
104
 
49
- ## Developer workflow
50
-
51
- ```bash
52
- gem install zui
53
- zui doctor --fix
54
- zui new telemetry-console
55
- cd telemetry-console
56
- zui run main.rb
57
- zui bundle
58
- ```
105
+ The source is ordinary Ruby. Zui validates the declared tree, sends it through a versioned JSON
106
+ protocol, and renders it with native Qt components. Application QML is neither required nor
107
+ accepted through the runtime protocol.
59
108
 
60
- Build and install the gem directly from a checkout:
109
+ ## Reactive by design
61
110
 
62
- ```bash
63
- gem build zui.gemspec
64
- gem install ./zui-0.0.6.gem
65
- ```
111
+ State, bindings, animation, scheduled work, and events live in the same builder context:
66
112
 
67
- `zui doctor --fix` is the one-time setup for each Zui version and platform. It downloads the
68
- matching versioned client from GitHub Releases, verifies its SHA-256 checksum and manifest, and
69
- installs it in the native user cache. `zui configure` performs the same explicit setup operation.
70
- The prebuilt client is never packaged in or downloaded from the RubyGem. It contains the native
71
- host and its Qt/QML engine libraries—not the developer's application, Ruby source, or the Zui
72
- Ruby/QML framework. Setup never changes the global shell environment; `zui run` supplies the
73
- client paths only to the child application.
113
+ ```ruby
114
+ Zui.app do
115
+ state :status, "online"
116
+ state :uptime, 0
74
117
 
75
- Developers install Ruby and the `zui` gem. They do not install CMake, a C++ compiler, or Qt. Those
76
- tools are used only by Zui's release CI to produce the platform clients.
118
+ app :main, title: "Service Monitor", width: 720, height: 480 do
119
+ card padding: 24 do
120
+ column spacing: 12 do
121
+ indicator = badge state.status
122
+ bind(indicator, :value) { state.status.upcase }
123
+ bind(indicator, :foreground) { state.status == "online" ? "#9cff57" : "#ff6f7d" }
77
124
 
78
- `zui bundle` uses a platform template to produce an application directory on Linux and Windows or
79
- a standard `.app` on macOS. The package combines the application's Ruby/assets, the Zui framework
80
- runtime and catalog, and a private copy of the configured native Qt/QML client. No system Qt
81
- installation is used by the finished bundle. The current bundle format expects Ruby 3.1 or newer
82
- on the destination and supports `ZUI_RUBY` when an installer provides a private Ruby executable.
125
+ text { "Uptime: #{state.uptime}s" }
83
126
 
84
- See [Platform support](docs/platforms.md) for host requirements and bundle layouts.
127
+ button "Reconnect" do
128
+ transaction do
129
+ state.status = "online"
130
+ state.uptime = 0
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
85
136
 
86
- `zui doctor` is read-only: it reports platform, Ruby, client, run, and bundle readiness. Add
87
- `--fix` to download and install the missing client from GitHub Releases. Zui has no separate
88
- validation command; Ruby, DSL, protocol, resource, and QML errors are reported by the operation
89
- that encounters them.
137
+ every(1) { state.uptime += 1 }
138
+ end
139
+ ```
90
140
 
91
- ## Reusable application UI
141
+ - `state` defines application-owned values.
142
+ - Value components can take a block for their primary reactive property.
143
+ - `bind` connects any declared property to application state.
144
+ - `transaction` publishes related changes together.
145
+ - `after`, `every`, and `async` schedule application work.
146
+ - `animate` and animation components use native render-side transitions.
147
+ - `dynamic` rebuilds data-dependent child structures without rebuilding the whole application.
92
148
 
93
- Application UI modules are scoped to one builder instead of being mixed into Zui globally:
149
+ Reusable UI modules are scoped to one application builder, so domain components do not leak into
150
+ other applications:
94
151
 
95
152
  ```ruby
96
153
  module TelemetryConsole
@@ -105,30 +162,298 @@ module TelemetryConsole
105
162
  app(:main, title: "Telemetry Console") { dashboard }
106
163
  end
107
164
  end
108
-
109
- def self.run = build.run
110
165
  end
166
+ ```
167
+
168
+ ## Platform support
169
+
170
+ Zui uses the same Ruby API, protocol, renderer, catalog, and application source on every supported
171
+ desktop target. Each release is gated by CI that builds, packages, installs, and launches the
172
+ matching native client.
173
+
174
+ | Operating system | Architecture | Native client | `zui bundle` output | Release status |
175
+ | --- | --- | --- | --- | --- |
176
+ | Linux | x86-64 | `zui-client-linux-x86_64` | Portable application directory | Supported and CI verified |
177
+ | macOS | Apple Silicon | `zui-client-macos-arm64` | Standard `.app` bundle | Supported and CI verified |
178
+ | macOS | Intel x86-64 | `zui-client-macos-x86_64` | Standard `.app` bundle | Supported and CI verified |
179
+ | Windows | x86-64 | `zui-client-windows-x86_64` | Portable application directory | Supported and CI verified |
180
+
181
+ Application bundles do not require Ruby on the destination. The default `--lite` mode embeds Zui's
182
+ versioned mruby runtime. `--full` embeds a private CRuby plus only the non-Zui gems resolved by the
183
+ project's `Gemfile.lock`.
111
184
 
112
- TelemetryConsole.run
185
+ Unsupported architectures fail explicitly during configuration. Zui never silently compiles Qt,
186
+ uses a system Qt installation, or downloads an asset for a different platform. See the complete
187
+ [platform and bundle layouts](docs/platforms.md).
188
+
189
+ ## Component catalog
190
+
191
+ Zui 0.0.8 registers **241 built-in components**. Every entry has a named Ruby builder method,
192
+ property and event schema, native QML renderer, reactive patch support, and contract tests.
193
+
194
+ | Category | Count | Representative components |
195
+ | --- | ---: | --- |
196
+ | Foundation and layout | 28 | `container`, `grid_layout`, `scroll`, `split_view`, `application_window` |
197
+ | Display, content, and media | 24 | `text`, `image`, `markdown`, `video`, `model_view_3d` |
198
+ | Buttons and input | 36 | `button`, `text_field`, `slider`, `date_picker`, `multi_select` |
199
+ | Navigation and structure | 20 | `tabs`, `drawer`, `stack_view`, `breadcrumb`, `key_catcher` |
200
+ | Menus, dialogs, and feedback | 19 | `dialog`, `popup`, `toast`, `progress_ring`, `bottom_sheet` |
201
+ | Data and collections | 22 | `list_view`, `grid_view`, `table_view`, `tree_view`, `calendar` |
202
+ | Charts and visualization | 16 | `line_chart`, `candlestick_chart`, `heatmap`, `gauge`, `legend` |
203
+ | Drawing and interaction | 16 | `canvas`, `shape`, `shader_effect`, `drag_area`, `particle_system` |
204
+ | Animation, state, and timing | 32 | `animation`, `transition`, `timer`, `state_group`, `spring_animation` |
205
+ | Effects | 7 | `multi_effect`, `blur`, `drop_shadow`, `colorize`, `glow` |
206
+ | Multimedia and capture | 12 | `media_player`, `camera`, `audio_input`, `video_output`, `screen_capture` |
207
+ | Models and utilities | 9 | `list_model`, `settings`, `clipboard`, `standard_paths` |
208
+
209
+ Zui does not silently replace unavailable components with screenshots, generic controls, or
210
+ application-specific fallbacks. A declared component either renders as that component or reports
211
+ an explicit error.
212
+
213
+ - Browse the [complete source-backed component reference](https://zui.alkimist.dev/components).
214
+ - Review the [component coverage matrix](docs/component-coverage.md).
215
+
216
+ ## Command-line workflow
217
+
218
+ | Command | Purpose |
219
+ | --- | --- |
220
+ | `zui new NAME` | Generate a pure-Ruby application, `Gemfile`, distribution config, and reusable UI module |
221
+ | `zui doctor` | Report Ruby, platform, native-client, run, and bundle readiness without changing anything |
222
+ | `zui doctor --fix` | Download, verify, and install the missing native client and lite mruby runtime |
223
+ | `zui configure` | Perform the same explicit runtime installation directly |
224
+ | `zui run FILE` | Launch a Ruby entry point through the private native client |
225
+ | `zui bundle [DIRECTORY]` | Build the default standalone `--lite` bundle with embedded mruby |
226
+ | `zui bundle --full [DIRECTORY]` | Embed private CRuby and only the gems locked by the project |
227
+ | `zui bundle --name NAME --output PATH` | Override the generated product name and destination |
228
+ | `zui bundle --no-tree-shake` | Retain the complete component and Qt feature catalog for metaprogrammed applications |
229
+ | `zui bundle --dist [DIRECTORY]` | Build release installers from the required project-root `config.rb` |
230
+ | `zui version` | Print the installed framework version |
231
+
232
+ Zui has no separate validation command. Ruby, DSL, schema, resource, protocol, and renderer errors
233
+ are reported by the operation that encounters them.
234
+
235
+ ## How Zui runs
236
+
237
+ ```text
238
+ ┌─────────────────────────────────────────────────────────────────────┐
239
+ │ Ruby application │
240
+ │ UI modules · state · bindings · events · commands · assets │
241
+ └──────────────────────────────┬──────────────────────────────────────┘
242
+ │ versioned JSON protocol
243
+ ┌──────────────────────────────▼──────────────────────────────────────┐
244
+ │ Zui native client │
245
+ │ process transport · schema validation · lifecycle · error boundary │
246
+ └──────────────────────────────┬──────────────────────────────────────┘
247
+ │ declared component tree + patches
248
+ ┌──────────────────────────────▼──────────────────────────────────────┐
249
+ │ Platform-neutral renderer │
250
+ │ ControlNode · theme · controls · 241-component QML catalog │
251
+ └──────────────────────────────┬──────────────────────────────────────┘
252
+
253
+ Qt Quick · Controls · Multimedia · GPU · 3D
113
254
  ```
114
255
 
115
- This keeps `main.rb` at one domain-level call and prevents components from one application leaking
116
- into another application's DSL.
256
+ The Ruby process owns application logic. The native client owns the Qt event loop and graphics
257
+ runtime. The renderer applies validated trees and bounded reactive patch batches across the
258
+ process boundary.
259
+
260
+ The client intentionally excludes browser-engine payloads. Zui is desktop-only and does not use
261
+ HTML, CSS, JavaScript, WebView, Electron, or Qt WebEngine to render application interfaces.
262
+
263
+ ## Native client integrity
117
264
 
118
- ## Architecture
265
+ The RubyGem contains the Ruby framework and QML catalog, but not a platform client. Native clients
266
+ are built by the release matrix and attached to the matching GitHub tag.
267
+
268
+ During setup, Zui verifies:
269
+
270
+ 1. The release asset name matches the detected platform and architecture.
271
+ 2. The downloaded archive matches its published SHA-256 checksum.
272
+ 3. Every archive path is safe before extraction.
273
+ 4. `client.json` has the expected format, Zui version, platform, executable, and bundle capability.
274
+ 5. Activation completes atomically in the versioned user cache.
275
+
276
+ The private client includes the host executable, linked Qt libraries, QML modules, plugins, and
277
+ translations required by the catalog. `zui run` exposes those paths only to its child process.
278
+
279
+ ## Ship an application
280
+
281
+ ```bash
282
+ zui bundle
283
+ # or
284
+ zui bundle path/to/application --name "Telemetry Console"
285
+ ```
286
+
287
+ Every distribution combines four deliberately separate payloads:
119
288
 
120
289
  ```text
121
- Ruby application
122
- Zui DSL/state/events
123
- versioned JSON protocol
124
- native Qt host and process transport
125
- → platform-neutral QML renderer
126
- → Qt Quick / Controls / Multimedia / optional modules
290
+ application Ruby source and assets
291
+ + Zui Ruby/QML framework runtime
292
+ + selected private Ruby runtime (`mruby` or `cruby`)
293
+ + configured native Qt/QML client
294
+ ```
295
+
296
+ | Platform | Generated shape | Suitable next step |
297
+ | --- | --- | --- |
298
+ | Linux | Self-contained directory with `run` and desktop entry | AppImage, Flatpak, Snap, `.deb`, `.rpm`, or Arch package |
299
+ | macOS | Standard `.app` directory | Sign, notarize, and distribute with the application's release identity |
300
+ | Windows | Self-contained directory with `run.cmd` | MSIX, MSI, WiX, Inno Setup, or another installer |
301
+
302
+ No system Ruby or Qt installation is used by the finished bundle. Signing, notarization, installer
303
+ format, store submission, and application identity remain the release owner's responsibility.
304
+
305
+ `--lite` is the default. It compiles the project's local Ruby source into one mruby-compatible
306
+ program and rejects external gem `require` calls with a `--full` hint. Use `--full` for ordinary
307
+ CRuby behavior or third-party gems. Full bundles require a locked project `Gemfile`; run
308
+ `bundle install` after changing dependencies. Both modes are built for the current target OS and
309
+ architecture, and both use the same project-specific QML/native tree-shaking pass.
310
+
311
+ `zui bundle` statically analyzes every production Ruby source file, including code in conditional
312
+ branches, and retains only the referenced Zui adapters, QML modules, plugins, and native library
313
+ dependency closure. Test, spec, vendor, temporary, and previous distribution directories do not
314
+ affect the result. The selected components and byte savings are recorded in `zui-bundle.json`.
315
+
316
+ Ruby can compute method names at runtime, so applications that invoke components through
317
+ metaprogramming must declare those possible types in `.zui-bundle.json`:
318
+
319
+ ```json
320
+ {
321
+ "components": ["camera", "video_output"]
322
+ }
323
+ ```
324
+
325
+ Use `--no-tree-shake` only when the possible component set cannot be declared.
326
+
327
+ ### Native installers
328
+
329
+ `zui bundle --dist` creates the same tree-shaken application bundle and then packages it for the
330
+ current operating system:
331
+
332
+ | Host platform | Distribution artifacts |
333
+ |---|---|
334
+ | Linux | `.deb` and `.rpm` |
335
+ | macOS | `.dmg` containing the `.app` and an Applications shortcut |
336
+ | Windows | Inno Setup `.exe` installer |
337
+
338
+ Release packaging requires a `config.rb` file in the project root. It is executable Ruby using a
339
+ validated Zui DSL:
340
+
341
+ ```ruby
342
+ Zui::Dist.configure do
343
+ name "Telemetry Console"
344
+ identifier "com.example.telemetry-console"
345
+ version "1.0.0"
346
+ publisher "Example Company <dev@example.com>"
347
+ description "A native telemetry dashboard."
348
+ license "MIT"
349
+ homepage "https://example.com/telemetry-console"
350
+
351
+ icon linux: "assets/icon.png",
352
+ macos: "assets/icon.icns",
353
+ windows: "assets/icon.ico"
354
+ categories "Utility", "Development"
355
+ end
127
356
  ```
128
357
 
129
- Every declared component renders as that component or reports an explicit component error. Zui
130
- does not silently substitute images, alternate controls, or application-specific fallbacks.
358
+ Only the current platform's icon is required when packaging: PNG or SVG on Linux, ICNS on macOS,
359
+ and ICO on Windows. Paths must remain inside the project. `--output DIRECTORY` selects the artifact
360
+ directory, and existing artifacts are never overwritten. Linux RPM creation requires `rpmbuild`
361
+ (`rpm-build` or `rpm-tools`), macOS uses the system `hdiutil`, and Windows requires Inno Setup 6's
362
+ `ISCC.exe` on `PATH`.
363
+
364
+ The installers carry the application, selected Ruby runtime, Zui, Qt, and selected native
365
+ dependencies. They do not declare or require system Ruby. Code signing, Apple notarization, and
366
+ Windows Authenticode signing remain release-owner steps.
367
+
368
+ ## Showcase applications
369
+
370
+ The repository includes complete Ruby applications rather than isolated visual snippets:
371
+
372
+ | Application | What it demonstrates |
373
+ | --- | --- |
374
+ | [Avatar Runner](examples/avatar_runner/) | Keyboard focus, pointer input, timed physics, Canvas drawing, and atomic state patches |
375
+ | [Nova Pour](examples/nova_pour/) | Image loading, filtering, cart state, dialogs, bindings, and order simulation |
376
+ | [Tesla Drive Dashboard](examples/tesla_drive_dashboard/) | Vehicle simulation, image stacks, Canvas maps, local audio, telemetry, and animation |
377
+ | [Lumen Forge](examples/lumen_forge/) | Compiled shaders, pointer uniforms, GPU effects, charts, and timers |
378
+ | [Cardiac Health Monitor](examples/cardiac_health_monitor/) | Medical imagery, ECG visualization, gauges, heatmaps, particles, and live state |
379
+ | [Orbital Weather Console](examples/orbital_weather_console/) | Image-backed weather scenes, forecasts, gauges, charts, and simulation |
380
+ | [Quantum Market Terminal](examples/quantum_market_terminal/) | Portfolio state, trading simulation, charts, allocation controls, and transactions |
381
+ | [Smart Home Energy](examples/smart_home_energy/) | Room imagery, lighting, device state, energy telemetry, and home simulation |
382
+ | [Cinematic Music Studio](examples/cinematic_music_studio/) | Local and remote media, playback state, seeking, playlists, and audio controls |
383
+
384
+ Run any showcase through the normal client:
385
+
386
+ ```bash
387
+ zui run examples/avatar_runner/main.rb
388
+ zui run examples/tesla_drive_dashboard/main.rb
389
+ zui bundle examples/nova_pour
390
+ ```
391
+
392
+ See the [complete showcase index](examples/).
393
+
394
+ ## Omarchy integration
395
+
396
+ Zui is platform-neutral and has no runtime dependency on Quickshell or Omarchy. The separate
397
+ [`omarchy-ui`](https://github.com/AdamMusa/omarchy-ui) adapter adds shell applications, bar widgets,
398
+ panels, plugin lifecycle, theme integration, and Omarchy packaging while reusing the same Ruby DSL,
399
+ protocol, and component catalog.
400
+
401
+ The dependency direction remains one-way: desktop-environment adapters depend on Zui; Zui never
402
+ contains environment-specific branches.
403
+
404
+ ## Develop Zui itself
405
+
406
+ Clone the repository and run the complete local suite:
407
+
408
+ ```bash
409
+ git clone https://github.com/AdamMusa/zui.git
410
+ cd zui
411
+ scripts/test
412
+ ```
413
+
414
+ The suite covers the Ruby API, state engine, protocol, CLI, distributions, examples, QML contracts,
415
+ QML linting when available, the C++ host build, and an offscreen runtime smoke test.
416
+
417
+ Build and install the gem directly:
418
+
419
+ ```bash
420
+ gem build zui.gemspec
421
+ gem install ./zui-*.gem
422
+ ```
423
+
424
+ Release CI additionally builds the pinned mruby runtime, audits both release archives, installs the
425
+ built gem, repairs a fresh cache, and launches real `--lite` and `--full` bundles on every supported
426
+ target.
427
+
428
+ ## Troubleshooting
429
+
430
+ | Symptom | Resolution |
431
+ | --- | --- |
432
+ | `Client: not configured` | Run `zui doctor --fix` once for the installed Zui version |
433
+ | `Lite runtime: not configured` | Run `zui doctor --fix` to install the checksummed mruby archive |
434
+ | Platform or architecture is unsupported | Use one of the release-gated targets above or add a verified native-client runner and artifact |
435
+ | `--lite` rejects a gem `require` | Use `--full` and lock the gem in the project `Gemfile.lock` |
436
+ | A component reports a resource or module error | Check the declared asset path and run `zui doctor`; Zui will not substitute another component |
437
+ | Audio, camera, or capture is unavailable | Confirm OS permissions, devices, codecs, and platform media services |
438
+ | The native client looks stale after a framework update | Run `zui doctor --fix`; client caches are isolated by Zui version |
439
+
440
+ ## Documentation and support
441
+
442
+ | Resource | Purpose |
443
+ | --- | --- |
444
+ | [Official documentation](https://zui.alkimist.dev) | Guides, concepts, and searchable API documentation |
445
+ | [Component reference](https://zui.alkimist.dev/components) | Properties, events, container behavior, and validated Ruby examples for all 241 components |
446
+ | [Platform support](docs/platforms.md) | Native-client setup, target matrix, and OS-specific bundle layouts |
447
+ | [Component coverage](docs/component-coverage.md) | Complete built-in catalog checklist |
448
+ | [GitHub Releases](https://github.com/AdamMusa/zui/releases) | Versioned native clients and SHA-256 checksums |
449
+ | [RubyGems](https://rubygems.org/gems/zui) | Published framework versions |
450
+ | [Issue tracker](https://github.com/AdamMusa/zui/issues) | Focused bug reports and feature proposals |
131
451
 
132
452
  ## License
133
453
 
134
- MIT
454
+ Zui is available under the [MIT License](LICENSE). Bundled third-party fonts and runtime
455
+ dependencies retain their respective licenses; see [third-party notices](THIRD_PARTY_NOTICES.md).
456
+
457
+ <p align="center">
458
+ <strong>Build the interface in Ruby. Let Zui carry it to the desktop.</strong>
459
+ </p>
data/Service.qml CHANGED
@@ -13,6 +13,7 @@ Item {
13
13
  property bool ready: false
14
14
  property bool stopping: false
15
15
  property string lastError: ""
16
+ property string runtimeDiagnostics: ""
16
17
  property var surfaces: ({})
17
18
  property var surfaceOptions: ({})
18
19
  property var nodeIndex: ({})
@@ -411,6 +412,7 @@ Item {
411
412
 
412
413
  function startRuby() {
413
414
  if (stopping || projectDir === "" || program === "" || transport.running) return
415
+ runtimeDiagnostics = ""
414
416
  transport.start(runtimeExecutable, program, projectDir, rubyLoadPath)
415
417
  }
416
418
 
@@ -429,14 +431,24 @@ Item {
429
431
  function onLineReceived(line) { root.handleLine(line) }
430
432
  function onErrorLineReceived(line) {
431
433
  var message = String(line || "").trim()
432
- if (message !== "") console.warn("zui ruby:", message)
434
+ if (message === "") return
435
+ console.warn("zui ruby:", message)
436
+ var separator = root.runtimeDiagnostics === "" ? "" : "\n"
437
+ root.runtimeDiagnostics = (root.runtimeDiagnostics + separator + message).slice(0, 512)
438
+ Qt.callLater(function() {
439
+ if (!root.ready && !root.transport.running && root.runtimeDiagnostics !== "")
440
+ root.lastError = root.runtimeDiagnostics
441
+ })
433
442
  }
434
443
  function onExited(exitCode) {
435
444
  root.ready = false
436
445
  if (root.stopping || root.projectDir === "") return
437
- root.lastError = exitCode === 0
446
+ var summary = exitCode === 0
438
447
  ? "Zui runtime stopped"
439
448
  : "Zui runtime crashed (exit " + exitCode + ")"
449
+ root.lastError = root.runtimeDiagnostics === ""
450
+ ? summary
451
+ : summary + "\n\n" + root.runtimeDiagnostics
440
452
  restartTimer.interval = root.restartDelayMs
441
453
  restartTimer.start()
442
454
  root.restartDelayMs = Math.min(30000, root.restartDelayMs * 2)
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Zui
6
+ class ApplicationRuntime
7
+ FORMAT = 1
8
+
9
+ attr_reader :engine, :version, :executable, :environment, :gems, :program, :load_path
10
+
11
+ def initialize(engine:, version:, executable:, environment: {}, gems: [], program: nil, load_path: nil)
12
+ @engine = engine.to_s
13
+ @version = version.to_s
14
+ @executable = executable.to_s
15
+ @environment = environment.transform_keys(&:to_s).transform_values do |paths|
16
+ Array(paths).map(&:to_s).freeze
17
+ end.freeze
18
+ @gems = Array(gems).map(&:to_s).sort.freeze
19
+ @program = program&.to_s
20
+ @load_path = load_path&.to_s
21
+ freeze
22
+ end
23
+
24
+ def write(directory)
25
+ File.write(File.join(directory, "runtime.json"), "#{JSON.pretty_generate(to_h)}\n")
26
+ self
27
+ end
28
+
29
+ def to_h
30
+ result = {
31
+ "format" => FORMAT,
32
+ "engine" => engine,
33
+ "version" => version,
34
+ "executable" => executable,
35
+ "environment" => environment,
36
+ "gems" => gems
37
+ }
38
+ result["program"] = program unless program.nil?
39
+ result["load_path"] = load_path unless load_path.nil?
40
+ result
41
+ end
42
+ end
43
+ end