Osy#betaa language · its runtime Osyrin · a hosted platform
Why Osy#Built for agentsAgents as declarationsWorkflows that waitRuns exactly onceSecure by defaultNothing to mockThe editor is the compilerUI in the languageDocuments are dataOne program

Reference / UI

The barcode kit — a QR and barcode scanner you opt into

BarcodeScanner(scanned: Found, formats: qr)

A live camera scanner for QR codes and barcodes, shipped as an optional KIT you depend on with one line. It owns the camera and the decode loop and raises `scanned(text, format)`; your app supplies a box to draw in and an action to run. It is also the platform's proof that a control may ship a WebAssembly module.

preview1 example compiled by CIuicontrolscamerabarcode

Summary#

The platform ships mechanism, never components. Osysharp.Barcode is a complete barcode and QR scanner built on that mechanism, distributed as an ordinary kit — you depend on it in one line and nothing is copied into your project:

app Warehouse {
  use Osysharp.Barcode@1;
  model "model/**/*.osy";
}

It opens the camera, watches the picture, and raises scanned(text, format) when it reads a code. Everything about reading a symbol — the camera, the frame loop, the decoder — is inside the control.

⚠️ This is not the same thing as camera and microphone. Camera.Start() / Camera.Capture() are for taking a photograph or a recording and keeping the file. This is for reading what a picture says and keeping the text. An app can use both; they do not interfere.

Signature#

BarcodeScanner(scanned: Found)                       // everything, back camera, four looks a second
BarcodeScanner(scanned: Found, formats: qr)          // QR only — materially faster on a phone
BarcodeScanner(scanned: Found, active: armed)        // false releases the camera

scanned is an event, so it binds to an action taking (string text, string format). The control has no default size: put it in a box that has one.

Description#

The whole thing, at a call site#

// ⚠ This example DECLARES the control inline, because a documentation example compiles on its own with no manifest
// to carry a `use`. In your app you write `use Osysharp.Barcode@1;` instead and delete this block — the declaration
// arrives with the kit. What follows is `scan.osy`, trimmed to what this page uses.
control BarcodeScanner {
  contractVersion "1.1"
  participation headless
  props {
    bool active = true;
    [Values(any, qr, linear)] string formats = "any";
    [Values(back, front)] string facing = "back";
    int intervalMs = 250;
    int repeatAfterMs = 2000;
  }
  events {
    scanned(string text, string format);
    failed(string reason);
  }
  chunks { Core; Wasm; }
  probe { bool scanning; int scans; string? last; string? failure; }
}

[Page("/scan")] [AllowAnonymous]
component ScanPage() {
  string code = "";
  string problem = "";
  bool armed = true;

  action Found(string text, string format) { code = text; armed = false; }
  action Broke(string reason) { problem = reason; }
  action Again() { code = ""; problem = ""; armed = true; }

  render {
    Stack(gap: 3, p: 4) {
      Stack(h: "16rem") {
        BarcodeScanner(scanned: Found, failed: Broke, active: armed, formats: qr);
      }
      if (problem != "") { Text(problem); }
      if (code != "") {
        Text(code);
        Button("Scan another", onPress: Again);
      }
    }
  }
}

Note active: armed. A scanner that cannot be switched off is a camera that is always on — turning it off after a read is both the polite thing and the thing that puts the browser's recording indicator out.

repeatAfterMs is the prop that makes it usable#

A label held in front of the camera is read on every pass — four times a second at the default interval. So the same text is reported once and then suppressed for repeatAfterMs (2 seconds by default). Without that, one label held for ten seconds produces forty events, and an app that appends a row per scan collects forty rows.

Set it to 0 if you genuinely want every read — a counter, or a diagnostic.

Narrowing formats is a real speed-up#

valuewhat it looks for
anyevery format the decoder knows
qrQR and Micro QR
linearthe retail and logistics 1-D family — EAN, UPC, Code 39/93/128, ITF, Codabar, DataBar

The decoder spends time proportional to how many families it must try, so qr on a phone is noticeably faster than any. format on the scanned event names the exact symbology it found (QRCode, EAN-13, …), not the family you asked for.

When it cannot run, it says so#

failed(reason) carries words meant for a person: the camera was refused, there is no camera, another app holds it, the decoder would not load. It is raised once per cause, not once per frame — so an app can show it as a message without four of them arriving a second.

Like camera and microphone, this needs a secure page: browsers give no camera to plain http:// beyond localhost.

What it costs, and when#

SizeWhen it loads
the control3 KBon mount
the decoder glue37 KBthe first time a scanner is activated
the decoder itself1.07 MBthe same moment, as WebAssembly

A page that mounts a scanner with active: false and never arms it downloads neither chunk. An app that never writes the use carries nothing at all.

It is also the proof that a control may ship WebAssembly#

The decoder is ZXing's C++ library compiled to WebAssembly, and it reaches the browser through nothing special: a .wasm is an ordinary control asset, pinned by content address, served same-origin, and reached through the ordinary chunks — assets a control loads on demand mechanism. If you are shipping a control of your own around a native library, this kit is the worked example — see its README.md for the one function everything turns on.

See also#

Related

camera and microphone

Take a photograph, record a video, or record audio. `Camera.Start()` asks for the device and `Camera()` shows the…

control — foreign UI controls (charts, grids, maps)

A `control` block declares the contract of a foreign UI widget — a chart, a data grid, a map — that a small JavaScript…

chunks — assets a control loads on demand

A `chunks { }` block declares assets a control ships but does not need at mount — a maths renderer, a diagram engine, a…

The markdown editor kit — a rich editor you opt into

A full rich-text markdown editor — sections, partial saves, a block menu, tables, find and replace, maths and diagrams…

upload

`Upload(onUploaded: Ingest) { … }` is a file picker wearing whatever you put inside it. When someone chooses a file its…