[Reactor] Passing Data Deeply (without Context)

This is HOW-TO implement functionality similar to ReactJS::Context, see Passing Data Deeply with Context.

Just to refresh, there are two types of components in Sciter’s Reactor,

functional components:

function FunctionComponent(props, kids ,parent) {}

class components:

class ClassComponent extends Element {

  this(props, kids, parent) {}
  render(props, kids, parent) {}
}

Note that parent parameter in these functions, that is real DOM element – parent element where this function or class component will appear or exists already.

All this gives us everything we need to implement that Passing Data Deeply with Context functionality with Sciter’s Reactor.

Let’s define this simple function:

function getContext(element, propName, defaultValue) {
   if(!element) return defaultValue;
   let v = element[propName];
   return v ?? getContext(element.parentElement, propName, defaultValue);
}

As you see that function tries to get property propName on nearest DOM element in parent/child chain.

Having it we can define that Header component as:

export default function Heading(props, kids , parent) {
  const level = getContext(parent,"level",1);
  switch (level) {
    case 1:
      return <h1>{children}</h1>;
    case 2:
      return <h2>{children}</h2>;
    case 3:
      return <h3>{children}</h3>;
    case 4:
      return <h4>{children}</h4>;
    case 5:
      return <h5>{children}</h5>;
    case 6:
      return <h6>{children}</h6>;
    default:
      throw Error('Unknown level: ' + level);
  }
}

And <Section> component will simply be this:

export default class Section extends Element {

  level = 1; // serves as context variable

  this(props, kids, parent) {
    // get the level either from props.level or compute it in context 
    this.level = props.level ?? (getContext(parent,"level",0) + 1);
  }

  render(props, kids, parent) {
    return <section>{kids}</section>;
  }
}

As you see that is pretty simple to do with Reactor and does not require any additional functionality other than that getContext() helper function.

See full demo here.

UPDATE: if you need explicit <Context> component then check this discussion.

no responses

It will never die

Sciter (scapp.exe) on WindowsXP (circa 2001).

Sciter/XP binaries are located in sdk/bin/windows.xp/x32/. These binaries support only RASTER backend. In principle they can be used on all Windows versions when “do not use system video drivers” requirement is in effect (e.g. video drivers install applications, etc.). But no GPU acceleration in these binaries.

no responses

Support of display:flex and display:grid in Sciter.

Main purpose of display:flex and display:grid introduction in Sciter is to support cases when you need some pages to be laid out in the same way in Sciter and in web browser – to minimize maintenance efforts when same designs are shared between desktop and the web.

This is NOT about something like “I’ll design web site and run it as is in desktop application”. That is simply impossible – too different execution models (media types in terms of CSS). And this applies to any user agent in CSS terms (Sciter, browsers, Electron, etc.).  But to share design of some fragments (panels, views, components, elements) is feasible and practical.

Tab in web browser where your design is loaded is usually treated as an endless scrollable tape. Such tape is usually shown in maximized browser window.  And that is not so for desktop HTML application – its window usually covers part of desktop screen.

Also, almost all web applications / sites are vertically scrollable – endless tapes indeed. While this OK for web applications but desktop usability guidelines usually consider scrollable elements as exceptions rather than the norm.  But even on the Web:

Display all important information above the fold. Users often decide whether to stay or leave based on what they can see without scrolling. Plus they allocate only 20% of their attention below the fold.

OK, back to to those two beasts…

display:flex

display:flex W3C specification is quite a complex (and controversial in many aspects, IMO) thing and I doubt that 99% of web design and designers  use it at full extent.

Most of the time it is used for just tow cases:

  • to laid out blocks horizontally in predictable manner replacing old CSS tricks with float:left/right;
  • to achieve flexibility : “make this element to span all available space left from other elements”;

And so is the limited implementation of display:flex in Sciter – it is aimed to support most popular layout cases by using already existing Sciter’s flow:horizontal |  horizontal-wrap | vertical | vertical-wrap. Below are details of how it is made:

section { 
   display: flex;
   flex-direction: row;
   flex-wrap: nowrap;
}

gets translated into

section {
  display: block;
  flow: horizontal; 
}

and

section { 
   display: flex;
   flex-direction: column;
   flex-wrap: wrap;
}

is translated into

section {
  display: block;
  flow: horizontal-wrap; 
}

Same thing is for  flex-direction: column  / flex-wrap – they translated into flow: vertical and flow: vertical-wrap .

Flexibility

Flexibility in display:flex is defined by special flex:N property where N number defines portion of free space the element will take inside its container.

In Sciter flex:N gets translated into flex units applied to width or height of the element : width: N*; for flex-direction: row and height: N*; for  flex-direction: column; containers.

display:grid

As a specification, display:grid is significantly better than display:flow and so Sciter contains near the full implementation of display:grid specification. To get the idea of display:grid read this.

Afterword

I’d like to highlight again: main goal of display:flex/grid in Sciter is not to implement those specs in full but rather to support most popular cases to share designs between Sciter and Web platforms. Original Sciter’s Flows and Flexes are more ergonomic and flexible I would say. Use them if you design stuff solely for Sciter.

no responses

C modules in Sciter landed in 6.0.1.0

CModules – modules defined in pure C language. C sources are translated to native code before running.

CModules are using TinyCC that supports ANSI C, but also most of the new ISO C99 standard and many GNUC extensions including inline assembly.

Sciter adds just these three features to TinyCC:

    • #import "file.c" – similar to #include "file.c" but file.c gets compiled as a separate compilation unit. This allows to break cmodule into several C files.
    • export “keyword” that marks functions exported from C module to JS.
    • jsvalue type that encapsulates direct reference to JS values. There are also several built-in functions serving jsvalues.

See sdk/samples.c

Exporting functions from CModules

Function to be exported from C (and so to be called from JS) is an ordinary C function that is marked by export keyword and having JS compatible parameters and return value. List of JS compatible types:

  • all built-in integer types are supported: variants int (a.k.a. int32), int8 , int16, int32, int64, long (a.k.a. int32) and their unsigned variants
  • reals: float and double
  • Pointers to the above types.
  • Special jsvalue type – handle to JS objects – strings, arrays, objects, etc.

CModules are optional in Sciter.

In order to enable CModules in Sciter sources you shall add --CMODULES in premake5.lua project generating script.

At runtime to add ALLOW_CMODULES in SciterSetOption call:

 SciterSetOption(NULL, SCITER_SET_SCRIPT_RUNTIME_FEATURES,
                         ALLOW_FILE_IO |
                         ALLOW_SOCKET_IO |
                         ALLOW_EVAL |
                         ALLOW_SYSINFO | 
                         ALLOW_CMODULES // <<<<<<<<<<<<<<<
                 );
2 responses
no responses

C modules in Sciter

Here is practical example of using C modules – Sciter’s JS/C port of demo three.js webgl – buffergeometry – lines drawrange

That demo in Sciter (on the left) and MS Edge (60 FPS both ):

That is a mesh that contains 500 3d dots (particles). On each animation step (60 FPS) it computes distances between points, so 500×500/2 times (125,000) to calculate sqrt((x1 - x2)2 + (y1 - y2)2 + (z1 - z2)2) and renders them. That’s typical number crunching task of O(N2) complexity. JS is not that good at such tasks, it is flexible but not that performant. That’s why C modules are here.

 

2 responses

Here we go

Experiment: C modules in Sciter.

C modules here are like JS modules but their C source is compiled on the fly to native code. So these are native modules that do not require separate C compiler as Sciter includes tinycc engine.

Example:

<html>
    <head>
        <script|module>

import * as cmod from "./cmod.c"; // C module
import * as jsmod from "./jsmod.js"; // JS module

const floats = new Float32Array(3000);
for(let i = 0; i < floats.length; ++i)
  floats[i] = Math.random();

function time(f) {
  let a = new Date().getTime();
  f();
  let b = new Date().getTime();
  return b - a;
}

let d1, d2;

// JS version
let t1 = time(() => d1 = jsmod.closestDistance(floats));
// native C version
let t2 = time(() => d2 = cmod.closestDistance(floats));

document.body.append(<ul>
    <li>JS res=<var>{printf("%f",d1)}</var> exectime=<var>{t1}ms</var></li>
    <li>C res=<var>{printf("%f",d2)}</var> exectime=<var>{t2}ms</var></li>
</ul>);
        </script>
    </head>
    <body>
    </body>
</html>

And here is source code of that cmod.c file:

#include <math.h>
#include <jsbridge.h>

export float closestDistance(floats dots) {
  float m = 3.0;
  for( int i = 0; i < dots.length; i += 3 ) {
    for( int j = 0; j < dots.length; j += 3 ) {
      if( i == j) continue;
      float x = dots.data[i] - dots.data[j];
      float y = dots.data[i+1] - dots.data[j+1];
      float z = dots.data[i+2] - dots.data[j+2];
      float d = sqrtf(x*x + y*y + z*z);
      if( d < m ) m = d;
    }
  }
  return m;
}

and for the completeness jsmod.js that does and expose the same:

export function closestDistance(dots) {
  let m = 3.0;
  for( let i = 0; i < dots.length; i += 3 ) {
    for( let j = 0; j < dots.length; j += 3 ) {
      if( i == j) continue;
      let x = dots[i] - dots[j];
      let y = dots[i+1] - dots[j+1];
      let z = dots[i+2] - dots[j+2];
      let d = Math.sqrt(x*x + y*y + z*z);
      if( d < m ) m = d;
    }
  }
  return m;
}

Result of running that test document is:

c modules running results

As you see C (native) code in this example runs 45 times faster than JS code.

Also C modules may load and use other .dll/.so – dlopen() in C modules work on all platforms.

Main use case of C modules is a “number crunching” functionality where you would need maximum performance. They play pretty much the same role as shaders in OpenGL, Vulkan, etc.

This is an experiment so far. C modules make sense in context of scapp.exe but I am not so sure about sciter.dll use cases. I am not so sure do we need this feature or not.

6 responses

cage + scapp = Sciter in kiosk mode

In order to run scapp in kiosk mode (single app spanning whole screen) we can use Cage wayland compositor

Just run this on Linux:

  sudo apt-get install cage

Then press CTRL+ALT+F3 to switch to new screen space and type there

  cage path/to/scapp

and it will run scapp as a full screen app.

Additional parameters that can be passed to the scapp are provided in the form of environment variables, type these before invoking cage (in v 6.0.0.4):

  export SCAPP_DOC="/path/of/the/doc/to/load.htm"
  export SCITER_FULL_SCREEN=on
  export SCITER_DPI=192

Here is the real test of cage/scapp running on 3840×2160 monitor @ 60 FPS on Raspberry Pi 5

The movie itself is 720p.

I tried 4K movie – that appeared too heavy for such setup. In principle it should be possible to make layered output using specialized wayland compositor – one layer with the video and UI layer on top of it.

6 responses

Sciter + libVLC on Raspberry Pi

Here are results of another <video> behavior implementation. This time libVLC is used.

Main goal is to check performance and Sciter/libVLC integration.

And here is the real test on Raspberry Pi 5:

As in previous test it renders as video as element with backdrop-filter: blur(10px); (at the bottom).

libVLC has convenient API that is exposed by single libvlc.so/dll/dylib. ffmpeg is quite difficult in this regard – multiple dlls of different versions and origins.

Yet libVLC works slightly better – Sciter takes 27% of single core with libVLC versus 32% of ffmpeg.

Sciter does not include libVLC, it loads libvlc.so/dll/dylib on demand instead – only when needed.

In order to use video with Sciter either VLC player needs to be installed on target machine or libvlc library needs to be placed aside sciter(.dll|so|dylib).

7 responses

Sciter + FFmpeg on Raspberry Pi

I’ve moved [sciter-ffmpeg](https://gitlab.com/sciter-engine/sciter-ffmpeg) as an internal behavior behind `video` on Linux.

Main goal is to check how Sciter and FFmpeg libraries behave together, especially on relatively low-grade devices and video chips as Raspberry Pi.

And here is the real test on Raspberry Pi 5:

It renders as video as element with backdrop-filter: blur(10px); (at the bottom). Having video and such elements rendered on the same canvas enables effects like backdrop-filter to work. On each vide frame rendered `backdrop-filter: blur` runs shader that blurs underground video content in real time.

As you see it takes 30% of one core (from 4 cores in total) to render such DOM tree. And that percentage is not dependent on Sciter’s window size – image rendering with scaling is done by GPU.

2 responses