diff --git a/ivette/api/server_tsc.ml b/ivette/api/server_tsc.ml
index 8f5eb6e829b7992c706487f59d1b23b226f80421..62324078a05818e35a5c0802eaa4e2c07006d566 100644
--- a/ivette/api/server_tsc.ml
+++ b/ivette/api/server_tsc.ml
@@ -76,7 +76,7 @@ let makeJtype ?self ~names =
     | Jstring | Jalpha -> Format.pp_print_string fmt "string"
     | Jkey kd -> Format.fprintf fmt "Json.key<'#%s'>" kd
     | Jindex kd -> Format.fprintf fmt "Json.index<'#%s'>" kd
-    | Jdict(kd,js) -> Format.fprintf fmt "Json.Dict<'#%s',%a>" kd pp js
+    | Jdict(kd,js) -> Format.fprintf fmt "Json.Dictionary<'#%s',%a>" kd pp js
     | Jdata id | Jenum id -> pp_ident fmt id
     | Joption js -> Format.fprintf fmt "%a |@ undefined" pp js
     | Jtuple js ->
diff --git a/ivette/src/dome/doc/guides/application.md b/ivette/src/dome/doc/guides/application.md
index 8abb0b0ebdce327a8a1cf2d20d71f4b28bc69a02..ae191b062b31701c1d63c0ba49e4ad50526d7761 100644
--- a/ivette/src/dome/doc/guides/application.md
+++ b/ivette/src/dome/doc/guides/application.md
@@ -85,15 +85,10 @@ your data flow.
 - **Global States** are necessary to implement the unidirectional data-flow. These
   data are stored in the renderer process, but outside of the view hierarchy of
   **React** components actually mounted in the DOM. Hence, it remains consistent whatever
-  the evolution of the view. See `Dome.State` class and the associated custom **React** hooks
+  the evolution of the view. See `dome/state` module and the associated custom **React** hooks
   to implement global states. You may also use global JavaScript variables and emit events
   on your own.
 
-- **Local States** are necessary to maintain local states associated
-  to views.  We strongly encourage the use of the `Dome.useState()` hook for this
-  purpose, since it generalizes `React.useState()` with persistent window settings
-  (see below).
-
 - **View Updates** to make your views listening for updates of the various data
   sources, we encourage to use the **React** hooks we provide, since they
   transparently make your components to re-render when required. However,
@@ -110,12 +105,12 @@ your data flow.
   **Dome** components with presentation options can be assigned a `settings` key
   to make their state persistent. Contrary to Global Settings, however, they are
   not shared across several windows. You may also access these data by using
-  `Dome.setWindowSetting()` and `Dome.getWindowSetting()`, or the **React** hook
-  `Dome.useWindowSetting()`.
+  `Settings.setWindowSetting()` and `Settings.getWindowSetting()`, or the **React** hook
+  `Settings.useWindowSetting()`. See also helpers `Dome.useXxxSettings()`.
 
 - **Global Settings** are stored in the user's home directory and automatically
   saved and load with your application; they are typically modified _via_ the
   Settings Window, which is accessible from the application menubar. In **Dome**,
-  you access these data by using `Dome.setGlobalSetting()` and
-  `Dome.getGlobalSetting()`, or the **React** hook `Dome.useGlobalSetting()`.
-  Settings must be JSON serializable JavaScript values.
+  you can shall define a global settings by creating an instance of
+  `Settings.GlobalSettings` class and use it with
+  the `Settings.useGlobalSettings()` hook.
diff --git a/ivette/src/dome/src/renderer/data/json.ts b/ivette/src/dome/src/renderer/data/json.ts
index 2e2ebe87b2de5fc4ad4c8ced72592c3aa2ce7a04..1f5b2163ed92e12a322c8d950f4805abd2f73a68 100644
--- a/ivette/src/dome/src/renderer/data/json.ts
+++ b/ivette/src/dome/src/renderer/data/json.ts
@@ -429,32 +429,55 @@ export function jIndex<K>(kd: K): Loose<index<K>> {
   return (js: json) => typeof js === 'number' ? forge(kd, js) : undefined;
 }
 
+/** Dictionaries with « untyped » keys. */
+export type dict<A> = { [key: string]: A };
+
+/**
+   Decode a JSON dictionary, discarding all inconsistent entries.
+   If the JSON contains no valid entry, still returns `{}`.
+*/
+export function jDict<A>(fn: Loose<A>): Safe<dict<A>> {
+  return (js: json) => {
+    const buffer: dict<A> = {}
+    if (js !== null && typeof js === 'object' && !Array.isArray(js)) {
+      for (var key of Object.keys(js)) {
+        const fd = js[key];
+        if (fd !== undefined) {
+          const fv = fn(fd);
+          if (fv !== undefined) buffer[key] = fv;
+        }
+      }
+    }
+    return buffer;
+  };
+}
+
 /** Dictionaries with « typed » keys. */
-export type dict<K, A> = phantom<K, { [key: string]: A }>
+export type dictionary<K, A> = phantom<K, { [key: string]: A }>
 
 /** Lookup into dictionary.
     Better than a direct access to `d[k]` for undefined values. */
-export function lookup<K, A>(d: dict<K, A>, k: key<K>): A | undefined {
+export function lookup<K, A>(d: dictionary<K, A>, k: key<K>): A | undefined {
   return d[k];
 }
 
 /** Empty dictionary. */
-export function empty<K, A>(kd: K): dict<K, A> {
+export function empty<K, A>(kd: K): dictionary<K, A> {
   return forge(kd, {} as any);
 }
 
 /** Dictionary extension. */
-export function index<K, A>(d: dict<K, A>, key: key<K>, value: A) {
+export function index<K, A>(d: dictionary<K, A>, key: key<K>, value: A) {
   d[key] = value;
 }
 
 /**
-   Decode a JSON dictionary, discarding all inconsistent entries.
+   Decode a JSON dictionary with typed keys, discarding all inconsistent entries.
    If the JSON contains no valid entry, still returns `{}`.
 */
-export function jDictionary<K, A>(kd: K, fn: Loose<A>): Safe<dict<K, A>> {
+export function jDictionary<K, A>(kd: K, fn: Loose<A>): Safe<dictionary<K, A>> {
   return (js: json) => {
-    const buffer: dict<K, A> = empty(kd);
+    const buffer: dictionary<K, A> = empty(kd);
     if (js !== null && typeof js === 'object' && !Array.isArray(js)) {
       for (var key of Object.keys(js)) {
         const fd = js[key];
@@ -472,8 +495,8 @@ export function jDictionary<K, A>(kd: K, fn: Loose<A>): Safe<dict<K, A>> {
    Encode a dictionary into JSON, discarding all inconsistent entries.
    If the dictionary contains no valid entry, still returns `{}`.
 */
-export function eDictionary<K, A>(fn: Encoder<A>): Encoder<dict<K, A>> {
-  return (d: dict<K, A>) => {
+export function eDictionary<K, A>(fn: Encoder<A>): Encoder<dictionary<K, A>> {
+  return (d: dictionary<K, A>) => {
     const js: json = {};
     for (var k of Object.keys(d)) {
       const fv = d[k];
diff --git a/ivette/src/dome/src/renderer/dome.js b/ivette/src/dome/src/renderer/dome.js
deleted file mode 100644
index face33d62a13c994b370e894f179d2c9c5a23f16..0000000000000000000000000000000000000000
--- a/ivette/src/dome/src/renderer/dome.js
+++ /dev/null
@@ -1,827 +0,0 @@
-/**
-   @packageDocumentation
-   @module dome(renderer)
-   @description
-
-   ## Dome Application (Renderer Process)
-
-   This modules manages your main application window
-   and its interaction with the main process.
-
-   Example:
-
-   ```typescript
-   // File 'src/renderer/index.js':
-   import Application from './Application.js' ;
-   Dome.setContent( Application );
-   ```
- */
-
-import _ from 'lodash' ;
-import React from 'react';
-import ReactDOM from 'react-dom';
-import { AppContainer } from 'react-hot-loader' ;
-import { remote , ipcRenderer } from 'electron';
-import { EventEmitter } from 'events' ;
-import SYS , * as System from 'dome/system' ;
-import './style.css' ;
-
-// --------------------------------------------------------------------------
-// --- Context
-// --------------------------------------------------------------------------
-
-// main window focus
-var focus = true ;
-
-function setContextAppNode()
-{
-  const node = document.getElementById('app');
-  if (node) {
-    node.className =
-      'dome-container dome-platform-' + System.platform +
-      ( focus ? ' dome-window-active' : ' dome-window-inactive' ) ;
-  }
-  return node;
-}
-
-// --------------------------------------------------------------------------
-// --- Helpers
-// --------------------------------------------------------------------------
-
-/** @summary Development mode flag.
-    @description
-    Configured to be `'true'` when in development mode
-*/
-export const DEVEL = System.DEVEL ;
-
-/** @summary System platform.
-    @description
-    Same as `platform` from `dome/system` */
-export const platform = System.platform ;
-
-// --------------------------------------------------------------------------
-// --- Application Emitter
-// --------------------------------------------------------------------------
-
-/** @summary Application Emitter.
-    @description
-    Can be used as a basic _Flux_ dispatcher. */
-export const emitter = new EventEmitter();
-
-/** Same as `emitter.on` */
-export function on(evt,job) { emitter.on(evt,job); }
-
-/** Same as `emitter.off` */
-export function off(evt,job) { emitter.off(evt,job); }
-
-/** Same as `emitter.emit` */
-export function emit(evt,...args) { emitter.emit(evt,...args); }
-
-{
-  emitter.setMaxListeners(250);
-}
-
-// --------------------------------------------------------------------------
-// --- Application Events
-// --------------------------------------------------------------------------
-
-/** @event 'dome.update'
-    @description
-    Convenient pre-defined events for triggering a global re-render.
-    See also [Dome.onUpdate](#.onUpdate), [Dome.update](#.update) methods and
-    the [Dome.useUpdate](#.useUpdate) hook.
-*/
-
-/** @event 'dome.reload'
-    @description
-    Triggered when the application has been loaded or re-loaded
-    See also [Dome.onReload](#.onReload).
-*/
-
-/** @event 'dome.command'
-    @param {Array.<string>} argv - command line arguments
-    @param {string} wdir - working directory
-    @description
-    Triggered when the command line argument has been received, and when
-    the application is re-loaded (in development mode).
-
-    See also [Dome.onCommand](#.onCommand).
-*/
-
-/**
-   @summary Emits the `dome.update` event.
-*/
-export function update() { emitter.emit('dome.update'); }
-
-/**
-   @summary Update event handler.
-   @param {function} cb - invoked on update events.
-   @description
-   Register a callback on [dome.update](#~event:'dome.update') event.
-*/
-export function onUpdate(job) { emitter.on('dome.update',job); }
-
-/**
-   @summary Update event handler.
-   @param {function} cb - invoked on reload events.
-   @description
-   Register a callback on [dome.reload](#~event:'dome.reload') event.
-*/
-export function onReload(job) { emitter.on('dome.reload',job); }
-
-/** @summary Command-line event handler.
-    @param {function} cb - invoked with `cb(argv,wdir)`
-    @description
-Register a callback on [dome.command](#~event:'dome.reload') event,
-emitted by the `Main` process when the application instance is launched.
-
-See also:
- - [[useCommand]]
- - `System.getArguments`
- - `System.getWorkingDir`
-*/
-export function onCommand(job) { emitter.on('dome.command',job); }
-
-ipcRenderer.on('dome.ipc.reload',() => emitter.emit('dome.reload'));
-ipcRenderer.on('dome.ipc.command', (_event,argv,wdir) => {
-  SYS.SET_COMMAND(argv,wdir);
-  emitter.emit('dome.command',argv,wdir);
-});
-
-// --------------------------------------------------------------------------
-// --- Window Management
-// --------------------------------------------------------------------------
-
-export function isApplicationWindow()
-{
-  return process.argv.includes( SYS.WINDOW_APPLICATION_ARGV );
-}
-
-export function isPreferencesWindow()
-{
-  return process.argv.includes( SYS.WINDOW_PREFERENCES_ARGV );
-}
-
-// --------------------------------------------------------------------------
-// --- Window Title
-// --------------------------------------------------------------------------
-
-export function setModified( modified )
-{
-  ipcRenderer.send('dome.ipc.window.modified',modified);
-}
-
-export function setTitle( title )
-{
-  ipcRenderer.send('dome.ipc.window.title',title);
-}
-
-// --------------------------------------------------------------------------
-// --- Main Content
-// --------------------------------------------------------------------------
-
-/**
-   @summary Defines the user's main window content.
-   @param {React.Component} Component - to be rendered in the main window
-   @description
-   Binds the component to the main window.
-
-   <strong>Notes:</strong> a `<Component/>` instance is generated and rendered in the `#app`
-   window element. Its class name is set to `dome-platform-<platform>` with
-   the `<platform>` set to the `Dome.platform` value. This class name can be used
-   as a CSS selector for platform-dependent styling.
-*/
-export function setApplicationWindow( Component )
-{
-  if (isApplicationWindow()) {
-    syncSettings();
-    const appNode = setContextAppNode();
-    ReactDOM.render( <AppContainer><Component/></AppContainer> , appNode );
-  }
-}
-
-// --------------------------------------------------------------------------
-// --- Settings Window
-// --------------------------------------------------------------------------
-
-/**
-   @summary Defines the user's preferences window content.
-   @param {React.Component} Component - to be rendered in the settings window
-   @description
-   Binds the component to the settings window.
-
-   <strong>Notes:</strong> a `<Component/>` instance is generated and rendered in the `#app`
-   window element. Its class name is set to `dome-platform-<platform>` with
-   the `<platform>` set to the `Dome.platform` value. This class name can be used
-   as a CSS selector for platform-dependent styling.
-*/
-export function setPreferencesWindow( Component )
-{
-  if (isPreferencesWindow()) {
-    syncSettings();
-    const appNode = setContextAppNode();
-    ReactDOM.render( <AppContainer><Component/></AppContainer> , appNode );
-  }
-}
-
-// --------------------------------------------------------------------------
-// --- MenuBar Management
-// --------------------------------------------------------------------------
-
-const customItemCallbacks = {} ;
-
-/**
-   @summary Create a new custom menu in the menu bar.
-   @param {string} label - the menu title (shall be unique)
-   @description
-   This function can be triggered at any time, and will eventually trigger
-   an update of the whole application menubar.
-
-   It is also possible to call this function from the main process.
-*/
-export function addMenu( label ) { ipcRenderer.send( 'dome.ipc.menu.addmenu' , label ); }
-
-/**
-   @summary Insert a new custom item in a menu.
-   @param {object} spec - the menu-item specification
-   @description
-The menu-item shall be specified by using the following fields:
- - `menu` (`string`, _required_) : the label of the menu to insert the item in;
-   can be a custom menu, or one of the predefined `'File'`, `'Edit'` or `'View'` menus.
- - `id` (`string|number`, _required_) : the item identifier;
-   shall be unique among the entire menu-bar.
- - `type` (`string`, _optional_) : one of `'normal'`, `'separator'`, `'checkbox'` or `'radio'`.
- - `label` (`string`, _optional_) : the item label.
- - `visible` (`boolean`, _optional_, default is `true`).
- - `enabled` (`boolean`, _optional_, default is `true`).
- - `checked` (`boolean`, _optional_, for `type:'checkbox'` and `type:'radio'` only, default is `false`).
- - `key` (`string`, _optional_) : a keyboard shortcut for menu-item.
- - `onClick` (`function`, _optional_) : an optional callback.
-
-These options (except `menu` and `id`) can be modified later on by using the [setMenuItem](#.setMenuItem) function.
-
-When clicked, the menu-item will also trigger a `'dome.menu.clicked'` event on the entire application (both process)
-with the corresponding `id`.
-
-Key short cuts shall be specified with the following codes:
- - `"Cmd+<Key>"` for command (MacOS) or control (Linux) key
- - `"Alt+<Key>"` for command+option (MacOS) or alt (Linux) key
- - `"Meta+<Key>"` for command+shift (MacOS) or control+alt (Linux) key
-
-Alternatively, more precise keybord shortcuts can be specified with the `'accelerator'` option,
-which follows the same encoding that menu-item specifications from Electron.
-
-The `addMenu` function can be triggered at any time, and will eventually trigger
-an update of the whole application menubar.
-It is also possible to call this function from the main process.
-
-*/
-export function addMenuItem( spec )
-{
-  if (!spec.id && spec.type !== 'separator') {
-    console.error('[Dome] Missing menu-item identifier',spec);
-    return;
-  }
-  const { onClick , ...options } = spec ;
-  if ( onClick ) customItemCallbacks[ spec.id ] = onClick ;
-  ipcRenderer.send( 'dome.ipc.menu.addmenuitem' , options );
-}
-
-/**
-   @summary Update properties of an existing menu-item.
-   @param {object} options - the menu-item specification to update
-   @description
-   Options must follow the specification of the [addMenuItem](#.addMenuItem) function.
-   Option `id` must specify the identifier of the menu item to update.
-   The menu and item positions can _not_ be modified.
-   If an `onClick` callback is specified, it will _replace_ the previous one.
-   You shall specify `null` to remove the previously registered callback
-   (`undefined` callback is ignored).
-
-   This function can be triggered at any time, and will possibly trigger
-   an update of the whole application menubar if the properties
-   can not be changed dynamically in Electron.
-
-   It is also possible to call this function from the main process.
-   When specified, the item callback is only invoked in the process which
-   specify it. To register callbacks in other process,
-   you shall listen to the `'dome.menu.clicked'` event.
- */
-export function setMenuItem( options ) {
-  if (!options.id) {
-    console.error('[Dome] Missing menu-item identifier',options);
-    return;
-  }
-  const { onClick , ...updates } = options ;
-  if (onClick !== undefined) {
-    if (onClick) customItemCallbacks[options.id] = onClick ;
-    else delete customItemCallbacks[options.id] ;
-  }
-  ipcRenderer.send( 'dome.ipc.menu.setmenuitem', updates );
-}
-
-/** @event 'dome.menu.clicked'
-    @description Emitted with the clicked menu-item identifier */
-
-ipcRenderer.on('dome.ipc.menu.clicked',(id) => {
-  const callback = customItemCallbacks[id] ;
-  callback && callback();
-});
-
-// --------------------------------------------------------------------------
-// --- Context Menus
-// --------------------------------------------------------------------------
-
-/**
-   @summary Popup a contextual menu.
-   @param {item[]} items - the array of menu items
-   @param {function} [callback] - an optional callback
-   @description
-Each menu item is specified by an object with the following fields:
- - `id` (`string|number`, _optional_) : the item identifier.
- - `label` (`string`, _optional_) : the item label.
- - `enabled` (`boolean`, _optional_, default is `true`).
- - `display` (`boolean`, _optional_, default is `true`).
- - `checked` (`boolean`, _optional_, default is `undefined`).
- - `onClick` (`function`, _optional_) : callback on item selection.
-
-Items can be separated by inserting a `'separator'` constant string
-in the array. Item identifier and label default to each others. Alternatively,
-an item can be specified by a single string that will be used for both
-its label and identifier. Undefined or null items are allowed (and skipped).
-
-The menu is displayed at the current mouse location.
-The callback is called with the selected item identifier or label.
-If the menu popup is canceled by the user, the callback is called with `undefined`.
-
-@example
-let myPopup = (_evt) => Dome.popupMenu([ …items… ],(id) => … );
-<div onRightClick={myPopup}>...</div>
-
-*/
-export function popupMenu( items, callback )
-{
-  const { Menu , MenuItem } = remote ;
-  const menu = new Menu();
-  var selected = undefined ;
-  var kid = 0 ;
-  items.forEach((item) => {
-    if (item === 'separator')
-      menu.append(new MenuItem({ type:'separator' }));
-    else if (item)
-    {
-      const { display=true, enabled, checked } = item ;
-      if (display) {
-        const label = item.label || '#'+(++kid) ;
-        const id = item.id || label ;
-        const click = () => {
-          selected = id ;
-          item.onClick && item.onClick();
-        };
-        const type = checked !== undefined ? 'checkbox' : 'normal' ;
-        menu.append(new MenuItem({ label, enabled, type, checked, click }));
-      }
-    }
-  });
-  const job = callback ? () => callback( selected ) : undefined ;
-  menu.popup({window: remote.getCurrentWindow(), callback:job });
-}
-
-// --------------------------------------------------------------------------
-// --- Closing
-// --------------------------------------------------------------------------
-
-ipcRenderer.on('dome.ipc.closing', System.doExit);
-
-// --------------------------------------------------------------------------
-// --- Focus Management
-// --------------------------------------------------------------------------
-
-/** Current focus state of the main window. */
-export function isFocused() { return focus; }
-
-/**
-    @event 'dome.focus'
-    @param {boolean} state - updated focus state
-    @description Emitted when the application gain or loses focus.
-*/
-ipcRenderer.on('dome.ipc.focus',(sender,value) => {
-  focus = value;
-  setContextAppNode();
-  emitter.emit('dome.focus',value);
-});
-
-// --------------------------------------------------------------------------
-// --- Web Navigation
-// --------------------------------------------------------------------------
-
-/**
-    @event 'dome.href'
-    @param {string} href - internal `<a href=...>` target
-    @description
-    Emitted when the user clicks on a local `<a href=...>`.
-    URL with an `http://` protocole are opened externally
-    by the user's default browser.
-*/
-ipcRenderer.on('dome.ipc.href',(href) => emitter.emit('dome.href',href));
-
-// --------------------------------------------------------------------------
-// --- Function Component
-// --------------------------------------------------------------------------
-
-/**
-   @summary Inlined Function React Component.
-   @property {function} children - render function as children
-   @description
-   Allows to define an inlined functional component inside JSX.
-   The children function _can_ use hooks.
-
-@example
-<Render>
-   {() => {
-        let [ state, setState ] = React.useState();
-        …
-        return (<div>…</div>);
-   }}
-</Render>
-*/
-export const Render = ({children}) => {
-  return children();
-};
-
-// --------------------------------------------------------------------------
-// --- React Hooks
-// --------------------------------------------------------------------------
-
-/**
-   @summary Hook to re-render on demand (Custom React Hook).
-   @return {function} to trigger re-rendering
-   @description
-   Returns a callback to trigger a render on demand.
-*/
-export function useForceUpdate()
-{
-  const [tac,onTic] = React.useState();
-  return () => onTic(!tac);
-}
-
-/**
-   @summary Hook to re-render on Dome events (Custom React Hook).
-   @param {string} [event,...] - event names (default: `'dome.update'`)
-   @description
-   Returns nothing.
-*/
-export function useUpdate(...evts)
-{
-  const update = useForceUpdate();
-  React.useEffect(() => {
-    const trigger = () => setImmediate(update);
-    if (evts.length == 0) evts.push('dome.update');
-    evts.forEach((evt) => emitter.on(evt,trigger));
-    return () => evts.forEach((evt) => emitter.off(evt,trigger));
-  });
-}
-
-/**
-   @summary Hook to register callbacks to Dome events (Custom React Hook).
-   @param {string} event - Event to register on
-   @param {function} callback - The callback to register
-   @description
-   Register the callback on event until the component is unmount.
-   Do not force the component to re-render (unless the callback does).<br/>
-   Returns nothing.
-*/
-export function useEvent(evt,callback)
-{
-  React.useEffect(() => {
-    emitter.on(evt,callback);
-    return () => emitter.off(evt,callback);
-  });
-}
-
-/**
-   @summary Hook to register callbacks to events (Custom React Hook).
-   @param {EventEmitter} emitter - event emitter
-   @param {string} event - Event to register on
-   @param {function} callback - The callback to register
-   @description
-   Register the callback on event until the component is unmount.
-   Do not force the component to re-render (unless the callback does).<br/>
-   Returns nothing.
-*/
-export function useEmitter(emitter,evt,callback)
-{
-  React.useEffect(() => {
-    emitter.on(evt,callback);
-    return () => emitter.off(evt,callback);
-  });
-}
-
-const NULL = {}; // Dummy initial value
-
-// --------------------------------------------------------------------------
-// --- Commands Hooks
-// --------------------------------------------------------------------------
-
-/**
-   @summary Hook for command-line interface (Custom React Hook).
-   @return {array} `[argv,wdir]` command-line arguments and working directory
-   @description
-   Returns the command-line arguments and working directory for the application
-   instance running in the window. Automatically updated on `dome.command` events.
-
-   See also [[onCommand]] event handler.
-*/
-export function useCommand() {
-  useUpdate('dome.command');
-  const wdir = System.getWorkingDir();
-  const argv = System.getArguments();
-  return [ argv , wdir ];
-}
-
-// --------------------------------------------------------------------------
-// --- Settings Hooks
-// --------------------------------------------------------------------------
-
-function useSettings( local, settings, defaultValue )
-{
-  const [ value, setValue ] =
-        React.useState(() => readSetting( local, settings, defaultValue ));
-  React.useEffect(() => {
-    let callback = () => {
-      let v = readSetting( local, settings , defaultValue );
-      setValue(v);
-    };
-    const event = local ? 'dome.defaults' : 'dome.settings' ;
-    emitter.on(event,callback);
-    return () => emitter.off(event, callback);
-  });
-  const doUpdate = (upd) => {
-    const theValue = typeof(upd)==='function' ? upd(value) : upd ;
-    if (settings) writeSetting( local, settings, theValue );
-    if (local) setValue(theValue);
-  };
-  return [ value, doUpdate ];
-}
-
-/**
-   @summary Local state with optional window settings (Custom React Hook).
-   @param {string} [settings] - optional window settings to backup the value
-   @param {any} [defaultValue] - the initial (and default) value
-   @return {array} `[value,setValue]` of the local state
-   @description
-   Similar to `React.useState()` with persistent _window_ settings.
-   When the settings key is undefined, it simply uses a local React state.
-   Also responds to `'dome.defaults'`.
-
-   The `setValue` callback accepts either a value, or a function to be applied
-   on current value.
-*/
-export function useState( settings, defaultValue )
-{
-  return useSettings( true, settings, defaultValue );
-}
-
-/**
-   @summary Local boolean state with optional window settings (Custom React Hook).
-   @param {string} [settings] - optional window settings to backup the value
-   @param {boolean} [defaultValue] - the initial value (default is `false`)
-   @return {array} `[value,flipValue]` for the local state
-   @description
-   Same as [useState](#.useState) with a boolean value that can be set or flipped:
-    - `flipValue()` change the value to its opposite;
-    - `flipValue(v)` change the value to `v`.
-*/
-export function useSwitch( settings, defaultValue=false )
-{
-  const [ value, update ] = useSettings( true, settings, defaultValue );
-  return [ value, v => update(v===undefined ? !value : v) ];
-}
-
-/**
-   @summary Local state with global settings (Custom React Hook).
-   @param {string} settings - global settings for storing the value
-   @param {any} [defaultValue] - the initial and default value
-   @return {array} `[value,setValue]` of the local state
-   @description
-   Similar to `React.useState()` with persistent _global_ settings.
-   When the settings key is undefined, it simply uses a local React state.
-   Also responds to `'dome.settings'` to update the state.
-
-   The `setValue` callback accepts either a value, or a function to be applied
-   on current value.
-*/
-export function useGlobalSetting( settings, defaultValue )
-{
-  return useSettings( false, settings, defaultValue );
-}
-
-// --------------------------------------------------------------------------
-// --- Global States
-// --------------------------------------------------------------------------
-
-/** @event 'dome.state.update'
-    @description
-    Notify updates within a State object.
-*/
-
-const STATE_UPDATE = 'dome.state.update' ;
-
-/**
-  @summary Global state object.
-  @property {object} state - the current state properties
-  @property {object} defaults - the default state properties
-  @description
-
-You may use this class as convenient way to implement global
-state for your Dome application. Simply create a state `s` with `new State(defaults)`
-and use `s.setState()`, `s.getState()` or `s.state` property, and `s.useState()`
-custom hooks.
-
-A state is also an event emitter that you can use to fire events, and you can use
-the React custom hooks `s.useUpdate()` and `s.useEvent()`.
-
-All above methods are bound to `this` by the constructor.
-
-*/
-export class State extends EventEmitter
-{
-
-  constructor(props) {
-    super();
-    // Makes this field private
-    this.defaults = props ;
-    this.state = Object.assign( {}, props );
-    this.update = this.update.bind(this);
-    this.getState = this.getState.bind(this);
-    this.setState = this.setState.bind(this);
-    this.clearState = this.clearState.bind(this);
-    this.replaceState = this.replaceState.bind(this);
-    this.useState = this.useState.bind(this);
-    this.useEvent = this.useEvent.bind(this);
-    this.useUpdate = this.useUpdate.bind(this);
-  }
-
-  /** Emits the `dome.state.update` event */
-  update() { this.emit('dome.state.update'); }
-
-  /** Returns the state property. */
-  getState() { return this.state; }
-
-  /** @summary Update the state with (some) properties.
-      @param {object} props - the properties to be updated
-      @description
-      Update the state with `Object.assign`, like `setState()` on React components.
-      Also fire the `'dome.update'` property on the object. */
-  setState(props) {
-    Object.assign( this.state, props );
-    this.update();
-  }
-
-  /** @summary Replace (all) state properties.
-      @description
-      Replace the entire store with the new properties.
-      Also fire the `'dome.update'` property on the object. */
-  replaceState(props) {
-    this.state = Object.assign( {}, props );
-    this.update();
-  }
-
-  /** @summary Reset (all) state properties.
-      @description
-      Restore the entire store with the default properties.
-      Also fire the `'dome.state.update'` property on the object. */
-  clearState() {
-    this.state = Object.assign( {}, this.defaults );
-    this.update();
-  }
-
-  /** @summary Hook to use the state (custom React Hook).
-      @return {array} `[state,setState]` with current object properties and
-      function to update them. */
-  useState() {
-    let forceUpdate = useForceUpdate();
-    useEmitter( this, 'dome.state.update', forceUpdate );
-    return [ this.state , this.setState ];
-  }
-
-  /** @summary Hook to re-render your component on State events.
-      @param {string} [event] - the event to listen to (defaults to `'dome.update'`)
-  */
-  useUpdate(evt = 'dome.state.update') {
-    let forceUpdate = useForceUpdate();
-    useEmitter( this, evt, forceUpdate );
-  }
-
-  /** @summary Hook to trigger callbacks on State events.
-      @param {string} event - the event to listen to
-      @param {function} callback - the callback triggered on event
-  */
-  useEvent(evt,callback) {
-    useEmitter( this, evt, callback );
-  }
-
-}
-
-// --------------------------------------------------------------------------
-// --- Timer Hooks
-// --------------------------------------------------------------------------
-
-// Collection of { pending, timer, period, time, event } indexed by period
-const clocks = {};
-
-const CLOCKEVENT = (period) => 'dome.clock.' + period ;
-
-const TIC_CLOCK = (clk) => () => {
-  if (0 < clk.pending) {
-    clk.time += clk.period ;
-    emitter.emit(clk.event,clk.time);
-  } else {
-    clearInterval(clk.timer);
-    delete clocks[clk.period];
-  }
-};
-
-const INC_CLOCK = (period) => {
-  let clk = clocks[period] ;
-  if (!clk) {
-    let event = CLOCKEVENT(period);
-    let time = (new Date()).getTime();
-    clk = { pending: 0, time, period, event };
-    clocks[period] = clk ;
-    let tic = TIC_CLOCK(clk);
-    clk.timer = setInterval(tic,period);
-  }
-  clk.pending++;
-};
-
-const DEC_CLOCK = (period) => {
-  let clk = clocks[period] ;
-  if (clk) {
-    clk.pending--;
-  }
-};
-
-/**
-   @summary Synchronized start & stop timer (Custom React Hook).
-   @param {number} period - timer interval, in milliseconds (ms)
-   @param {boolean} [initStart] - whether to initially start the timer (default is `false`)
-   @return {timer} Timer object
-   @description
-   Create a local timer, synchronized on a global clock, that can be started
-   and stopped on demand during the life cycle of the component.
-
-   Each timer has its individual start & stop state. However,
-   all timers with the same period _are_ synchronized with each others.
-
-   The timer object has the following properties and methods:
-   - `timer.start()` starts the timer,
-   - `timer.stop()` starts the timer,
-   - `timer.time` is the time stamp of the last clock (see below)
-
-   It is safe to call `start()` and `stop()` whether the timer is running or not.
-   When `timer.time` is `-1`, it means the timer is stopped.
-   When `timer.time` is `0` it means the timer has just been started and no tic has
-   been received yet. The time stamp is in milliseconds; it is shared among all
-   timers synchronized on the same period and roughly equal to the `Date.getTime()`
-   of the associated clock.
-
- */
-
-export function useClock(period,initStart)
-{
-  const [time,setTime] = React.useState(initStart ? 0 : -1);
-  const running = 0 <= time ;
-  React.useEffect(() => {
-    if (running) {
-      INC_CLOCK(period);
-      const event = CLOCKEVENT(period);
-      emitter.on(event,setTime);
-      return () => {
-        DEC_CLOCK(period);
-        emitter.off(event,setTime);
-      };
-    } else
-      return undefined ;
-  });
-  return {
-    time,
-    start: () => { if (!running) setTime(0); },
-    stop: () => { if (running) setTime(-1); }
-  };
-}
-
-// --------------------------------------------------------------------------
-// --- Pretty Printing (Browser Console)
-// --------------------------------------------------------------------------
-
-export class PP {
-  constructor(moduleName) {
-    this.moduleName = moduleName;
-  }
-  log(...args) { console.log(`[${this.moduleName}]`,...args); }
-  warn(...args) { console.warn(`[${this.moduleName}]`,...args); }
-  error(...args) { console.error(`[${this.moduleName}]`,...args); }
-}
-
-// --------------------------------------------------------------------------
diff --git a/ivette/src/dome/src/renderer/dome.ts b/ivette/src/dome/src/renderer/dome.ts
new file mode 100644
index 0000000000000000000000000000000000000000..873367b4b83e9842581442305af84f8d4e72b4d9
--- /dev/null
+++ b/ivette/src/dome/src/renderer/dome.ts
@@ -0,0 +1,659 @@
+/**
+   @packageDocumentation
+   @module dome(renderer)
+   @description
+
+   ## Dome Application (Renderer Process)
+
+   This modules manages your main application window
+   and its interaction with the main process.
+
+   Example:
+
+   ```typescript
+   // File 'src/renderer/index.js':
+   import Application from './Application.js' ;
+   Dome.setContent( Application );
+   ```
+ */
+
+import _ from 'lodash';
+import React from 'react';
+import ReactDOM from 'react-dom';
+import type Emitter from 'events';
+import { AppContainer } from 'react-hot-loader';
+import { remote, ipcRenderer } from 'electron';
+import SYS, * as System from 'dome/system';
+import * as Json from 'dome/data/json';
+import * as Settings from 'dome/data/settings';
+import './style.css';
+
+// --------------------------------------------------------------------------
+// --- Context
+// --------------------------------------------------------------------------
+
+// main window focus
+var focus = true;
+
+function setContextAppNode() {
+  const node = document.getElementById('app');
+  if (node) {
+    node.className =
+      'dome-container dome-platform-' + System.platform +
+      (focus ? ' dome-window-active' : ' dome-window-inactive');
+  }
+  return node;
+}
+
+// --------------------------------------------------------------------------
+// --- Helpers
+// --------------------------------------------------------------------------
+
+/** Configured to be `'true'` when in development mode. */
+export const DEVEL = System.DEVEL;
+
+export type PlatformKind = 'linux' | 'macos' | 'windows';
+
+/** System platform. */
+export const platform: PlatformKind = (System.platform as PlatformKind);
+
+// --------------------------------------------------------------------------
+// --- Application Emitter
+// --------------------------------------------------------------------------
+
+/** Register a callback on Dome event. */
+export function on(
+  evt: string,
+  job: (...args: any[]) => void,
+) { System.emitter.on(evt, job); }
+
+/** Register a callback on Dome event. */
+export function off(
+  evt: string,
+  job: (...args: any[]) => void,
+) { System.emitter.off(evt, job); }
+
+/** Emit a Dome event (Same as [[dome/misc/system.event]]). */
+export function emit(
+  evt: string,
+  ...args: any[]
+) { System.emitter.emit(evt, ...args); }
+
+// --------------------------------------------------------------------------
+// --- Application Events
+// --------------------------------------------------------------------------
+
+/** Emits the `dome.update` event. */
+export function update() { emit('dome.update'); }
+
+/** Update event handler. */
+export function onUpdate(job: () => void) { on('dome.update', job); }
+
+/** Unregister an update event handler. */
+export function offUpdate(job: () => void) { off('dome.update', job); }
+
+/** Reload event handler. */
+export function onReload(job: () => void) { on('dome.reload', job); }
+ipcRenderer.on('dome.ipc.reload', () => emit('dome.reload'));
+
+/** Command-line arguments event handler. */
+export function onCommand(
+  job: (argv: string[], workingDir: string) => void
+) { on('dome.command', job); }
+ipcRenderer.on('dome.ipc.command', (_event, argv, wdir) => {
+  SYS.SET_COMMAND(argv, wdir);
+  emit('dome.command', argv, wdir);
+});
+
+// --------------------------------------------------------------------------
+// --- Window Management
+// --------------------------------------------------------------------------
+
+export function isApplicationWindow() {
+  return process.argv.includes(SYS.WINDOW_APPLICATION_ARGV);
+}
+
+export function isPreferencesWindow() {
+  return process.argv.includes(SYS.WINDOW_PREFERENCES_ARGV);
+}
+
+// --------------------------------------------------------------------------
+// --- Window Title
+// --------------------------------------------------------------------------
+
+/** Sets the modified status of the window-frame flag.
+    User feedback is platform dependent. */
+export function setModified(modified = false) {
+  ipcRenderer.send('dome.ipc.window.modified', modified);
+}
+
+/** Sets the window-frame title. */
+export function setTitle(title: string) {
+  ipcRenderer.send('dome.ipc.window.title', title);
+}
+
+// --------------------------------------------------------------------------
+// --- Window Container
+// --------------------------------------------------------------------------
+
+function setContainer(
+  Component: React.FunctionComponent | React.ComponentClass
+) {
+  Settings.synchronize();
+  const appNode = setContextAppNode();
+  const appContents = React.createElement(Component);
+  const appContainer = React.createElement(AppContainer, {}, [appContents]);
+  ReactDOM.render(appContainer, appNode);
+}
+
+// --------------------------------------------------------------------------
+// --- Main Content
+// --------------------------------------------------------------------------
+
+/**
+   Defines the user's main window content.
+
+   Binds the component to the main window.
+   <strong>Notes:</strong> a `<Component/>` instance is generated and rendered in the `#app`
+   window element. Its class name is set to `dome-platform-<platform>` with
+   the `<platform>` set to the `Dome.platform` value. This class name can be used
+   as a CSS selector for platform-dependent styling.
+
+   @param Component - to be rendered in the main window
+*/
+export function setApplicationWindow(
+  Component: React.FunctionComponent | React.ComponentClass
+) {
+  if (isApplicationWindow()) setContainer(Component);
+}
+
+// --------------------------------------------------------------------------
+// --- Settings Window
+// --------------------------------------------------------------------------
+
+/**
+   Defines the user's preferences window content.
+
+   <strong>Notes:</strong> a `<Component/>` instance is generated and rendered in the `#app`
+   window element. Its class name is set to `dome-platform-<platform>` with
+   the `<platform>` set to the `Dome.platform` value. This class name can be used
+   as a CSS selector for platform-dependent styling.
+
+   @param Component - to be rendered in the preferences window
+*/
+export function setPreferencesWindow(
+  Component: React.FunctionComponent | React.ComponentClass
+) {
+  if (isPreferencesWindow()) setContainer(Component);
+}
+
+// --------------------------------------------------------------------------
+// --- MenuBar Management
+// --------------------------------------------------------------------------
+
+const customItemCallbacks = new Map<string, (() => void)>();
+
+/**
+   Create a new custom menu in the menu bar.
+
+   This function can be triggered at any time, and will eventually trigger
+   an update of the whole application menubar.
+
+   It is also possible to call this function from the main process.
+
+   @param label - the menu title (shall be unique)
+*/
+export function addMenu(label: string) {
+  ipcRenderer.send('dome.ipc.menu.addmenu', label);
+}
+
+export type MenuName = 'File' | 'Edit' | 'View' | string;
+export type MenuItemType = 'normal' | 'separator' | 'checkbox' | 'radio';
+
+export interface MenuItemProps {
+  /** The label of the menu to insert the item in. */
+  menu: MenuName;
+  /** The menu item identifier. Shall be unique in the _entire_ menu bar. */
+  id: string;
+  /** Default is `'normal'`. */
+  type: MenuItemType;
+  /** Item label. Only optional for separators. */
+  label?: string;
+  /** Item is visible or not (default is `true`). */
+  visible?: boolean;
+  /** Enabled item (default is `true`). */
+  enabled?: boolean;
+  /** Item status for radio and checkbox. Default is `false`. */
+  checked?: boolean;
+  /** Keyboard shortcut. */
+  key?: string;
+  /** Callback. */
+  onClick?: () => void;
+}
+
+/**
+   Inserts a new custom item in a menu.
+
+   The menu can be modified later with [[setMenuItem]].
+
+   When clicked, the menu-item will also trigger a `'dome.menu.clicked'(id)`
+   event on all application windows.  The item callback, if any, is invoked only
+   in the process that specify it.
+
+   Key short cuts shall be specified with the following codes:
+   - `"Cmd+<Key>"` for command (MacOS) or control (Linux) key
+   - `"Alt+<Key>"` for command+option (MacOS) or alt (Linux) key
+   - `"Meta+<Key>"` for command+shift (MacOS) or control+alt (Linux) key
+
+   This function can be triggered at any time, and will eventually trigger
+   an update of the complete application menubar.
+   It is also possible to call this function from the main process.
+*/
+export function addMenuItem(props: MenuItemProps) {
+  if (!props.id && props.type !== 'separator') {
+    console.error('[Dome] Missing menu-item identifier', props);
+    return;
+  }
+  const { onClick, ...options } = props;
+  if (onClick) customItemCallbacks.set(props.id, onClick);
+  ipcRenderer.send('dome.ipc.menu.addmenuitem', options);
+}
+
+export interface MenuItemOptions {
+  id: string;
+  label?: string;
+  visible?: boolean;
+  enabled?: boolean;
+  checked?: boolean;
+  onClick?: null | (() => void);
+}
+
+/**
+   Update properties of an existing menu-item.
+
+   If an `onClick` callback is specified, it will _replace_ the previous one.
+   You shall specify `null` to remove the previously registered callback
+   (`undefined` callback is ignored).
+
+   This function can be triggered at any time, and will possibly trigger
+   an update of the application menubar if the properties
+   can not be changed dynamically in Electron.
+
+   It is also possible to call this function from the main process.
+ */
+export function setMenuItem(options: MenuItemOptions) {
+  const { onClick, ...updates } = options;
+  if (onClick === null) {
+    customItemCallbacks.delete(options.id);
+  } else if (onClick !== undefined) {
+    customItemCallbacks.set(options.id, onClick);
+  }
+  ipcRenderer.send('dome.ipc.menu.setmenuitem', updates);
+}
+
+ipcRenderer.on('dome.ipc.menu.clicked', (_sender, id: string) => {
+  const callback = customItemCallbacks.get(id);
+  callback && callback();
+});
+
+// --------------------------------------------------------------------------
+// --- Context Menus
+// --------------------------------------------------------------------------
+
+export interface PopupMenuItemProps {
+  /** Item label. */
+  label: string;
+  /** Optional menu identifier. */
+  id?: string;
+  /** Displayed item, default is `true`. */
+  display?: boolean;
+  /** Enabled item, default is `true`. */
+  enabled?: boolean;
+  /** Checked item, default is `false`. */
+  checked?: boolean;
+  /** Item selection callback. */
+  onClick?: (() => void);
+}
+
+export type PopupMenuItem = PopupMenuItemProps | 'separator';
+
+/**
+   Popup a contextual menu.
+
+   Items can be separated by inserting a `'separator'` constant string in the
+   array. Item identifier and label default to each others. Alternatively, an
+   item can be specified by a single string that will be used for both its label
+   and identifier. Undefined or null items are allowed (and skipped).
+
+   The menu is displayed at the current mouse location.  The callback is called
+   with the selected item identifier or label.  If the menu popup is canceled by
+   the user, the callback is called with `undefined`.
+
+   Example:
+
+   * ```ts
+   *    let myPopup = (_evt) => Dome.popupMenu([ …items… ],(id) => … );
+   *    <div onRightClick={myPopup}>...</div>
+   * ```
+
+*/
+export function popupMenu(
+  items: PopupMenuItem[],
+  callback?: (item: string | undefined) => void,
+) {
+  const { Menu, MenuItem } = remote;
+  const menu = new Menu();
+  var selected = '';
+  var kid = 0;
+  items.forEach((item) => {
+    if (item === 'separator')
+      menu.append(new MenuItem({ type: 'separator' }));
+    else if (item) {
+      const { display = true, enabled, checked } = item;
+      if (display) {
+        const label = item.label || '#' + (++kid);
+        const id = item.id || label;
+        const click = () => {
+          selected = id;
+          item.onClick && item.onClick();
+        };
+        const type = checked !== undefined ? 'checkbox' : 'normal';
+        menu.append(new MenuItem({ label, enabled, type, checked, click }));
+      }
+    }
+  });
+  const job = callback ? () => callback(selected) : undefined;
+  menu.popup({ window: remote.getCurrentWindow(), callback: job });
+}
+
+// --------------------------------------------------------------------------
+// --- Closing
+// --------------------------------------------------------------------------
+
+ipcRenderer.on('dome.ipc.closing', System.doExit);
+
+// --------------------------------------------------------------------------
+// --- Focus Management
+// --------------------------------------------------------------------------
+
+/** Current focus state of the main window. See also [[useWindowFocus]]. */
+export function isFocused() { return focus; }
+
+ipcRenderer.on('dome.ipc.focus', (_sender, value) => {
+  focus = value;
+  setContextAppNode();
+  System.emitter.emit('dome.focus', value);
+});
+
+/** Return the current window focus. See [[isfocused]]. */
+export function useWindowFocus(): boolean {
+  useUpdate('dome.focus');
+  return focus;
+}
+
+// --------------------------------------------------------------------------
+// --- Web Navigation
+// --------------------------------------------------------------------------
+
+ipcRenderer.on(
+  'dome.ipc.href',
+  (href) => System.emitter.emit('dome.href', href)
+);
+
+/**
+   Register a callback to handle clicks on a local `<a href=...>`
+   with non-http protocoles.
+
+   URL with an `http://` protocole are opened externally
+   by the user's default browser.
+
+   Other URLs shall be treated by the application _via_ this callback.
+*/
+export function onDOMhref(callback: (href: string) => void) {
+  System.emitter.on('dome.href', callback);
+}
+
+// --------------------------------------------------------------------------
+// --- React Hooks
+// --------------------------------------------------------------------------
+
+/**
+   Hook to re-render on demand (Custom React Hook).
+   Returns a callback to trigger a render on demand.
+*/
+export function useForceUpdate() {
+  const [tac, onTic] = React.useState(false);
+  return () => onTic(!tac);
+}
+
+/**
+   Hook to re-render on Dome events (Custom React Hook).
+   @param events - event names, defaults to a single `'dome.update'`.
+*/
+export function useUpdate(...events: string[]) {
+  const update = useForceUpdate();
+  React.useEffect(() => {
+    const trigger = () => setImmediate(update);
+    if (events.length == 0) events.push('dome.update');
+    events.forEach((evt) => System.emitter.on(evt, trigger));
+    return () => events.forEach((evt) => System.emitter.off(evt, trigger));
+  });
+}
+
+/**
+   Hook to register callbacks to Dome events (Custom React Hook).
+
+   Register the callback on event until the component is unmount.
+   Do not force the component to re-render (unless the callback does).
+
+   @param event - Event to register on
+   @param callback - The callback to register
+*/
+export function useEvent(event: string, callback: () => void) {
+  React.useEffect(() => {
+    System.emitter.on(event, callback);
+    return () => { System.emitter.off(event, callback); };
+  });
+}
+
+/**
+   Hook to register callbacks to events on an emitter (Custom React Hook).
+   Similar to [[useEvent]].
+*/
+export function useEmitter(
+  emitter: Emitter,
+  evt: string,
+  callback: () => void,
+) {
+  React.useEffect(() => {
+    emitter.on(evt, callback);
+    return () => { emitter.off(evt, callback); };
+  });
+}
+
+// --------------------------------------------------------------------------
+// --- Commands Hooks
+// --------------------------------------------------------------------------
+
+/**
+   Hook for command-line interface (Custom React Hook).
+   Returns the command-line arguments and working directory for the application
+   instance running in the window. Automatically updated on `dome.command` events.
+
+   @returns `[argv,wdir]` command-line arguments and working directory
+
+   See also [[onCommand]] event handler.
+*/
+export function useCommand(): [string[], string] {
+  useUpdate('dome.command');
+  const wdir = System.getWorkingDir();
+  const argv = System.getArguments();
+  return [argv, wdir];
+}
+
+// --------------------------------------------------------------------------
+// --- Timer Hooks
+// --------------------------------------------------------------------------
+
+interface Clock {
+  timer?: NodeJS.Timeout;
+  pending: number; // Number of listeners
+  time: number; // Ellapsed time since firts pending
+  event: string; // Tic events
+  period: number; // Period
+};
+
+// Collection of clocks indexed by period
+const CLOCKS = new Map<number, Clock>();
+
+const CLOCKEVENT = (period: number) => 'dome.clock.' + period;
+
+const TIC_CLOCK = (clk: Clock) => () => {
+  if (0 < clk.pending) {
+    clk.time += clk.period;
+    System.emitter.emit(clk.event, clk.time);
+  } else {
+    if (clk.timer) clearInterval(clk.timer);
+    CLOCKS.delete(clk.period);
+  }
+};
+
+const INC_CLOCK = (period: number) => {
+  let clk = CLOCKS.get(period);
+  if (!clk) {
+    let event = CLOCKEVENT(period);
+    let time = (new Date()).getTime();
+    clk = { pending: 0, time, period, event };
+    clk.timer = setInterval(TIC_CLOCK(clk), period);
+    CLOCKS.set(period, clk);
+  }
+  clk.pending++;
+  return clk.event;
+};
+
+const DEC_CLOCK = (period: number) => {
+  let clk = CLOCKS.get(period);
+  if (clk) clk.pending--;
+};
+
+export interface Timer {
+  /** Starts the timer, if not yet. */
+  start(): void;
+  /** Stops the timer. Can be restarted after. */
+  stop(): void;
+  /** Elapsed time (in milliseconds). */
+  time: number;
+  /** Running timer. */
+  running: boolean;
+}
+
+/**
+   Synchronized start & stop timer (Custom React Hook).
+
+   Create a local timer, synchronized on a global clock, that can be started
+   and stopped on demand during the life cycle of the component.
+
+   Each timer has its individual start & stop state. However,
+   all timers with the same period _are_ synchronized with each others.
+
+   @param period - timer interval, in milliseconds (ms)
+   @param initStart - whether to initially start the timer (default is `false`)
+
+ */
+export function useClock(period: number, initStart: boolean): Timer {
+  const started = React.useRef(0);
+  const [time, setTime] = React.useState(0);
+  const [running, setRunning] = React.useState(initStart);
+  const start = React.useCallback(() => setRunning(false), []);
+  const stop = React.useCallback(() => {
+    setRunning(false);
+    setTime(0);
+    started.current = 0;
+  }, []);
+  React.useEffect(() => {
+    if (running) {
+      const event = INC_CLOCK(period);
+      const callback = (t: number) => {
+        if (!started.current) started.current = t;
+        else setTime(t - started.current);
+      };
+      System.emitter.on(event, callback);
+      return () => {
+        System.emitter.off(event, callback);
+        DEC_CLOCK(period);
+      };
+    } else
+      return undefined;
+  }, [running]);
+  return { time, running, start, stop };
+}
+
+// --------------------------------------------------------------------------
+// --- Settings Hookds
+// --------------------------------------------------------------------------
+
+export type FlipState = [boolean, (newState?: boolean) => void];
+
+/**
+   Bool window settings helper. Default is `false` unless specified.
+   See also [[dome/data/settings]].
+   @returns `[state,flipState]` where flipState can be invoked with an
+   optional argument. By default, `flipState()` invert the state and
+    `flipState(s)` set the state to `s`.
+*/
+export function useBoolSettings(
+  key: string | undefined,
+  defaultValue = false,
+): FlipState {
+  const [state, setState] = Settings.useWindowSettings(
+    key, Json.jBoolean, defaultValue
+  );
+  const flipState = React.useCallback(
+    (v) => setState(v === undefined ? !state : v),
+    [state, setState]
+  );
+  return [state, flipState];
+}
+
+/** Number window settings helper. Default is `0` unless specified. */
+export function useNumberSettings(key: string | undefined, defaultValue = 0) {
+  return Settings.useWindowSettings(
+    key, Json.jNumber, defaultValue
+  );
+}
+
+/** String window settings. Default is `''` unless specified). */
+export function useStringSettings(key: string | undefined, defaultValue = '') {
+  return Settings.useWindowSettings(
+    key, Json.jString, defaultValue
+  );
+}
+
+/** Optional string window settings. Default is `undefined`. */
+export function useStringOptSettings(key: string | undefined) {
+  return Settings.useWindowSettings(
+    key, Json.jString, undefined
+  );
+}
+
+// --------------------------------------------------------------------------
+// --- Pretty Printing (Browser Console)
+// --------------------------------------------------------------------------
+
+export class Debug {
+  moduleName: string;
+  constructor(moduleName: string) {
+    this.moduleName = moduleName;
+  }
+  log(...args: any) {
+    if (DEVEL) console.log(`[${this.moduleName}]`, ...args);
+  }
+  warn(...args: any) {
+    if (DEVEL) console.warn(`[${this.moduleName}]`, ...args);
+  }
+  error(...args: any) {
+    if (DEVEL) console.error(`[${this.moduleName}]`, ...args);
+  }
+}
+
+// --------------------------------------------------------------------------
diff --git a/ivette/src/dome/src/renderer/frame/sidebars.js b/ivette/src/dome/src/renderer/frame/sidebars.js
index 6fcd8e42a50b7fca2f0dff2261ebd09b4daf413b..3ee74333bc29cb5eca0b43ba037945c1a613110c 100644
--- a/ivette/src/dome/src/renderer/frame/sidebars.js
+++ b/ivette/src/dome/src/renderer/frame/sidebars.js
@@ -8,7 +8,7 @@
 */
 
 import React from 'react' ;
-import * as Dome from 'dome' ;
+import { useBoolSettings } from 'dome';
 import { Badge } from 'dome/controls/icons' ;
 import { Label } from 'dome/controls/labels' ;
 
@@ -107,9 +107,8 @@ const disableAll = (children) =>
 export function Section(props) {
 
   const context = React.useContext( SideBarContext );
-  const [ state=true, setState ] = Dome.useState(
-    makeSettings(context.settings,props),
-    props.defaultUnfold
+  const [ state=true, setState ] = useBoolSettings(
+    makeSettings(context.settings,props), props.defaultUnfold
   );
   const { enabled=true, disabled=false, unfold, children } = props ;
 
diff --git a/ivette/src/dome/src/renderer/layout/boxes.js b/ivette/src/dome/src/renderer/layout/boxes.js
index e7848a9ddcc671c3b9c0dfeb80a733708875357d..a53800adcfb36d77fd00682cb14fcdf855b43eef 100644
--- a/ivette/src/dome/src/renderer/layout/boxes.js
+++ b/ivette/src/dome/src/renderer/layout/boxes.js
@@ -38,7 +38,7 @@
 */
 
 import React from 'react';
-import * as Dome from 'dome';
+import { useBoolSettings } from 'dome';
 import { Title } from 'dome/controls/labels' ;
 import './style.css' ;
 
@@ -168,12 +168,13 @@ export const Grid = ({columns='auto',...props}) =>
 export const Folder =
   ({ settings, defaultUnfold=false, indent=18, label, title, children }) =>
 {
-  const [ unfold , setUnfold ] = Dome.useState( settings, defaultUnfold );
+  const [ unfold , flipUnfold ] = useBoolSettings( settings, defaultUnfold );
   const icon = unfold ? 'TRIANGLE.DOWN' : 'TRIANGLE.RIGHT' ;
-  const onClick = () => setUnfold( !unfold );
   return (
     <Vpack>
-      <Hpack onClick={onClick}><Title icon={icon} label={label} title={title} /></Hpack>
+      <Hpack onClick={flipUnfold}>
+        <Title icon={icon} label={label} title={title} />
+      </Hpack>
       <Vpack style={{ marginLeft:indent }}>
         { unfold && children }
       </Vpack>
diff --git a/ivette/src/dome/src/renderer/layout/forms.js b/ivette/src/dome/src/renderer/layout/forms.js
index 3a0d3a9010bb3e786488577602e1960bd415d4e4..468963396f2fc5c9d2476a1bec04c7159c5bd716 100644
--- a/ivette/src/dome/src/renderer/layout/forms.js
+++ b/ivette/src/dome/src/renderer/layout/forms.js
@@ -9,7 +9,7 @@
 
 import _ from 'lodash' ;
 import React from 'react' ;
-import * as Dome from 'dome' ;
+import { useBoolSettings } from 'dome';
 import { SVG } from 'dome/controls/icons' ;
 import { Checkbox, Radio, Select as Selector } from 'dome/controls/buttons' ;
 import './style.css' ;
@@ -400,9 +400,7 @@ const TITLE_DISABLED = 'dome-text-title dome-disabled' ;
 export function Section(props)
 {
 
-  let [ unfold, setUnfold ] = Dome.useState(props.settings,props.unfold);
-
-  const onSwitch = () => setUnfold(!unfold);
+  let [ unfold, flipUnfold ] = useBoolSettings(props.settings,props.unfold);
 
   const { label, title, path, children, ...otherProps } = props ;
 
@@ -411,7 +409,7 @@ export function Section(props)
       {(context) => (
         <React.Fragment>
           <div className='dome-xForm-section'>
-            <div className='dome-xForm-fold' onClick={onSwitch}>
+            <div className='dome-xForm-fold' onClick={flipUnfold}>
               <SVG id={unfold?'TRIANGLE.DOWN':'TRIANGLE.RIGHT'} size={11}/>
             </div>
             <label className={ (path && context.disabled) ? TITLE_DISABLED : TITLE_ENABLED }
diff --git a/ivette/src/dome/src/renderer/layout/grids.js b/ivette/src/dome/src/renderer/layout/grids.js
index dd38a71915d290b50a82601b796ce8a9152e1938..bab058a6ef71d174318bf400125ea3909684a455 100644
--- a/ivette/src/dome/src/renderer/layout/grids.js
+++ b/ivette/src/dome/src/renderer/layout/grids.js
@@ -9,6 +9,8 @@
 
 import _ from 'lodash' ;
 import React from 'react' ;
+import * as Json from 'dome/data/json';
+import * as Settings from 'dome/data/settings';
 import { dispatchEvent, DnD, DragSource, DropTarget } from 'dome/dnd' ;
 import { AutoSizer } from 'react-virtualized' ;
 import { DraggableCore } from 'react-draggable' ;
@@ -1179,11 +1181,11 @@ export class GridLayout extends React.Component
   }
 
   componentDidMount() {
-    Dome.on('dome.defaults',this.onReloadSettings);
+    Dome.on('dome.settings.window',this.onReloadSettings);
   }
 
   componentWillUnmont() {
-    Dome.off('dome.defaults',this.onReloadSettings);
+    Dome.off('dome.settings.window',this.onReloadSettings);
   }
 
   computeTargetProposal(target) {
@@ -1226,7 +1228,7 @@ export class GridLayout extends React.Component
   onReloadSettings() {
     const { settings, onReshape } = this.props ;
     if (!settings) return;
-    const newShape = Dome.getWindowSetting( settings );
+    const newShape = Settings.getWindowSettings( settings, Json.jAny, undefined );
     this.setState({ shape: newShape });
     if (onReshape) onReshape( newShape );
   }
@@ -1234,7 +1236,7 @@ export class GridLayout extends React.Component
   onReshape(newShape) {
     const { settings, shape:setShape, onReshape } = this.props ;
     if (!setShape) this.setState({ shape: newShape });
-    if (settings) Dome.setWindowSetting( settings, newShape );
+    if (settings) Settings.setWindowSettings( settings, newShape );
     if (onReshape) onReshape( newShape );
   }
 
@@ -1299,7 +1301,8 @@ export class GridLayout extends React.Component
     const setShape = propShape === null ? {} : propShape ;
     const insert = inserted ? inserted.id : undefined ;
     const render = DRAGGABLEITEM(this.dnd,anchor,this.onSelfDrag,insert);
-    const shape = holdedShape || setShape || newShape || Dome.getWindowSetting(settings) ;
+    const shape = holdedShape || setShape || newShape ||
+          Settings.getWindowSettings(settings,Json.jAny,undefined) ;
     return (
       <DropTarget
         dnd={this.dnd}
diff --git a/ivette/src/dome/src/renderer/layout/splitters.js b/ivette/src/dome/src/renderer/layout/splitters.js
index b6468165cfcf2a07a4e425d291150a7c1a8b8527..14c0cbde86e8443dc97933ab8e64a5b47069aef0 100644
--- a/ivette/src/dome/src/renderer/layout/splitters.js
+++ b/ivette/src/dome/src/renderer/layout/splitters.js
@@ -10,6 +10,8 @@
 import _ from 'lodash' ;
 import * as React from 'react' ;
 import * as Dome from 'dome' ;
+import * as Json from 'dome/data/json';
+import * as Settings from 'dome/data/settings';
 import { Layout } from 'dome/misc/layout' ;
 
 import './style.css' ;
@@ -165,22 +167,12 @@ export class Splitter extends React.Component {
   // --------------------------------------------------------------------------
 
   componentDidMount() {
-    if (this.refs.container && this.refs.splitter) {
-      const container = this.refs.container.getBoundingClientRect() ;
-      const dimension = this.lr ? container.width : container.height ;
-      this.range = dimension - this.margin ;
-      const settings = this.props.settings ;
-      if (settings) {
-        const offset = Dome.getWindowSetting(settings,-1);
-        if (this.margin <= offset && offset <= this.range)
-          this.setState({ absolute: true, offset });
-      }
-    }
-    Dome.on( 'dome.defaults', this.handleReset );
+    this.handleReload();
+    Dome.on( 'dome.settings.window', this.handleReload );
   }
 
   componentWillUnmount() {
-    Dome.off( 'dome.defaults', this.handleReset );
+    Dome.off( 'dome.settings.window', this.handleReload );
   }
 
   componentDidUpdate() {
@@ -194,7 +186,7 @@ export class Splitter extends React.Component {
 
   handleReset() {
     this.setState({ absolute: false, dragging: false, anchor: 0, offset: 0 });
-    Dome.setWindowSetting(this.props.settings, -1);
+    Settings.setWindowSettings(this.props.settings, -1);
   }
 
   handleClick(event) {
@@ -202,6 +194,20 @@ export class Splitter extends React.Component {
       this.handleReset();
   }
 
+  handleReload() {
+    if (this.refs.container && this.refs.splitter) {
+      const container = this.refs.container.getBoundingClientRect() ;
+      const dimension = this.lr ? container.width : container.height ;
+      this.range = dimension - this.margin ;
+      const settings = this.props.settings ;
+      if (settings) {
+        const offset = Settings.getWindowSettings(settings,JSON.jNumber,-1);
+        if (this.margin <= offset && offset <= this.range)
+          this.setState({ absolute: true, offset });
+      }
+    }
+  }
+
   // --------------------------------------------------------------------------
   // --- Resizing Handler
   // --------------------------------------------------------------------------
@@ -285,7 +291,7 @@ export class Splitter extends React.Component {
   // --------------------------------------------------------------------------
 
   handleDragStop(evt) {
-    Dome.setWindowSetting( this.props.settings, this.state.offset );
+    Settings.setWindowSettings( this.props.settings, this.state.offset );
     this.setState({ dragging: false });
   }
 
diff --git a/ivette/src/dome/src/renderer/table/views.tsx b/ivette/src/dome/src/renderer/table/views.tsx
index 5e7888b7c89035af4b1b8de6cfa738f47a075fdd..4efa8a5b090320cf4c72f4794dbfdfbe741d4b37 100644
--- a/ivette/src/dome/src/renderer/table/views.tsx
+++ b/ivette/src/dome/src/renderer/table/views.tsx
@@ -11,6 +11,8 @@ import React, { ReactNode } from 'react';
 import { forEach, debounce, throttle } from 'lodash';
 import isEqual from 'react-fast-compare';
 import * as Dome from 'dome';
+import * as Json from 'dome/data/json';
+import * as Settings from 'dome/data/settings';
 import { DraggableCore } from 'react-draggable';
 import {
   AutoSizer, Size,
@@ -254,13 +256,16 @@ function makeDataRenderer(
 // --- Table Settings
 // --------------------------------------------------------------------------
 
-type ColSettings<A> = { [id: string]: undefined | null | A };
-
 type TableSettings = {
-  resize?: ColSettings<number>;
-  visible?: ColSettings<boolean>;
+  resize?: Json.dict<number>;
+  visible?: Json.dict<boolean>;
 }
 
+const jTableSettings = Json.jObject({
+  resize: Json.jDict(Json.jNumber),
+  visible: Json.jDict(Json.jBoolean),
+});
+
 // --------------------------------------------------------------------------
 // --- Table State
 // --------------------------------------------------------------------------
@@ -305,7 +310,7 @@ class TableState<Key, Row> {
     this.onRowRightClick = this.onRowRightClick.bind(this);
     this.onKeyDown = this.onKeyDown.bind(this);
     this.onSorting = this.onSorting.bind(this);
-    this.clearSettings = this.clearSettings.bind(this);
+    this.reloadSettings = this.reloadSettings.bind(this);
     this.rebuild = debounce(this.rebuild.bind(this), 5);
     this.rowGetter = makeRowGetter();
   }
@@ -383,49 +388,48 @@ class TableState<Key, Row> {
 
   // --- Table settings
 
-  clearSettings() {
-    this.resize.clear();
-    this.visible.clear();
-    this.forceUpdate();
-  }
-
   updateSettings() {
     const userSettings = this.settings;
     if (userSettings) {
-      const cws: ColSettings<number> = {};
-      const cvs: ColSettings<boolean> = {};
+      const cws: Json.dict<number> = {};
+      const cvs: Json.dict<boolean> = {};
       const resize = this.resize;
       const visible = this.visible;
       this.columns.forEach(({ id }) => {
         const cw = resize.get(id);
         const cv = visible.get(id);
-        cws[id] = cw === undefined ? null : cw;
-        cvs[id] = cv === undefined ? null : cv;
+        if (cw) cws[id] = cw;
+        if (cv) cvs[id] = cv;
       });
       const theSettings: TableSettings = { resize: cws, visible: cvs };
-      Dome.setWindowSetting(userSettings, theSettings);
+      Settings.setWindowSettings(userSettings, theSettings);
     }
     this.forceUpdate();
   }
 
+  reloadSettings() {
+    const settings = this.settings;
+    const resize = this.resize;
+    const visible = this.visible;
+    resize.clear();
+    visible.clear();
+    const theSettings: undefined | TableSettings =
+      Settings.getWindowSettings(settings, jTableSettings, undefined);
+    if (theSettings) {
+      forEach(theSettings.resize, (cw, cid) => {
+        this.resize.set(cid, cw);
+      });
+      forEach(theSettings.visible, (cv, cid) => {
+        this.visible.set(cid, cv);
+      });
+      this.forceUpdate();
+    }
+  }
+
   importSettings(settings?: string) {
     if (settings !== this.settings) {
       this.settings = settings;
-      const resize = this.resize;
-      const visible = this.visible;
-      resize.clear();
-      visible.clear();
-      const theSettings: undefined | TableSettings =
-        Dome.getWindowSetting(settings);
-      if (theSettings) {
-        forEach(theSettings.resize, (cw, cid) => {
-          if (typeof cw === 'number') this.resize.set(cid, cw);
-        });
-        forEach(theSettings.visible, (cv, cid) => {
-          if (typeof cv === 'boolean') this.visible.set(cid, cv);
-        });
-        this.forceUpdate();
-      }
+      this.reloadSettings();
     }
   }
 
@@ -1083,7 +1087,7 @@ export function Table<Key, Row>(props: TableProps<Key, Row>) {
     state.onContextMenu = props.onContextMenu;
     return state.unwind;
   });
-  Dome.useEvent('dome.defaults', state.clearSettings);
+  Dome.useEvent('dome.settings.window', state.reloadSettings);
   return (
     <div className='dome-xTable'>
       <React.Fragment key='columns'>
diff --git a/ivette/src/frama-c/LabViews.tsx b/ivette/src/frama-c/LabViews.tsx
index 52bc3151cac0951f6f9642dee1e7ceb83b05dc6b..810996d572907d0c1fffc7511e46bc9f45b1ec7b 100644
--- a/ivette/src/frama-c/LabViews.tsx
+++ b/ivette/src/frama-c/LabViews.tsx
@@ -10,6 +10,8 @@
 import _ from 'lodash';
 import React from 'react';
 import * as Dome from 'dome';
+import * as Json from 'dome/data/json';
+import * as Settings from 'dome/data/settings';
 import { Catch } from 'dome/errors';
 import { DnD, DragSource } from 'dome/dnd';
 import { SideBar, Section, Item } from 'dome/frame/sidebars';
@@ -349,9 +351,13 @@ const makeGridItem = (customize: any, onClose: any) => (comp: any) => {
 // --- Customization Views
 // --------------------------------------------------------------------------
 
+const Stock = new Settings.GDefault('frama-c.labView', Json.jAny, {});
+
 function CustomViews({ settings, shape, setShape, views: libViews }: any) {
-  const [local, setLocal] = Dome.useState(settings, {});
-  const [customs, setCustoms] = Dome.useGlobalSetting(settings, {});
+  const [local, setLocal] = Settings.useWindowSettings(
+    settings, Json.jAny, {},
+  ) as any;
+  const [customs, setCustoms] = Settings.useGlobalSettings(Stock) as any;
   const [edited, setEdited]: any = React.useState();
   const triggerDefault = React.useRef();
   const { current, shapes = {} } = local;
@@ -633,10 +639,15 @@ export function LabView(props: any) {
   const settingShape = settings && `${settings}.shape`;
   const settingPanel = settings && `${settings}.panel`;
   // Hooks & State
-  Dome.useUpdate('labview.library', 'dome.defaults');
+  Dome.useUpdate(
+    'labview.library',
+    'dome.settings.window',
+    'dome.settings.global',
+  );
   const dnd = React.useMemo(() => new DnD(), []);
   const lib = React.useMemo(() => new Library(), []);
-  const [shape, setShape] = Dome.useState(settingShape);
+  const [shape, setShape] =
+    Settings.useWindowSettings(settingShape, Json.jAny, undefined);
   const [dragging, setDragging] = React.useState();
   // Preparation
   const onClose =
diff --git a/ivette/src/frama-c/server.ts b/ivette/src/frama-c/server.ts
index d400a9745fe2cb5429a904414641a6def97d3a0e..51190f03fdc8debdf08ab53104736a44a02d1a76 100644
--- a/ivette/src/frama-c/server.ts
+++ b/ivette/src/frama-c/server.ts
@@ -21,7 +21,7 @@ import { ChildProcess } from 'child_process';
 // --- Pretty Printing (Browser Console)
 // --------------------------------------------------------------------------
 
-const PP = new Dome.PP('Server');
+const D = new Dome.Debug('Server');
 
 // --------------------------------------------------------------------------
 // --- Events
@@ -223,7 +223,7 @@ export function onActivity(signal: string, callback: any) {
 
 function _status(newStatus: Status) {
   if (Dome.DEVEL && hasErrorStatus(newStatus)) {
-    PP.error(newStatus.error);
+    D.error(newStatus.error);
   }
 
   if (newStatus !== status) {
@@ -256,7 +256,7 @@ export async function start() {
         await _launch();
         _status(okStatus(Stage.ON));
       } catch (error) {
-        PP.error(error.toString());
+        D.error(error.toString());
         buffer.append(error.toString(), '\n');
         _exit(error);
       }
@@ -484,7 +484,7 @@ async function _launch() {
   process?.stdout?.on('data', logger);
   process?.stderr?.on('data', logger);
   process?.on('exit', (code: number | null, signal: string | null) => {
-    PP.log('Process exited');
+    D.log('Process exited');
 
     if (signal) {
       // [signal] is non-null.
@@ -514,7 +514,7 @@ async function _launch() {
 // --------------------------------------------------------------------------
 
 function _reset() {
-  PP.log('Reset to initial configuration');
+  D.log('Reset to initial configuration');
 
   rqCount = 0;
   queueCmd = [];
@@ -536,7 +536,7 @@ function _reset() {
 }
 
 function _kill() {
-  PP.log('Hard kill');
+  D.log('Hard kill');
 
   _reset();
   if (process) {
@@ -545,7 +545,7 @@ function _kill() {
 }
 
 async function _shutdown() {
-  PP.log('Shutdown');
+  D.log('Shutdown');
 
   _reset();
   queueCmd.push('SHUTDOWN');
@@ -602,7 +602,7 @@ class SignalHandler {
   }
 
   on(callback: any) {
-    const n = Dome.emitter.listenerCount(this.event);
+    const n = System.emitter.listenerCount(this.event);
     Dome.on(this.event, callback);
     if (n === 0) {
       this.active = true;
@@ -612,7 +612,7 @@ class SignalHandler {
 
   off(callback: any) {
     Dome.off(this.event, callback);
-    const n = Dome.emitter.listenerCount(this.event);
+    const n = System.emitter.listenerCount(this.event);
     if (n === 0) {
       this.active = false;
       if (isRunning()) this.sigoff();
@@ -846,7 +846,7 @@ async function _send() {
         const resp = await zmqSocket?.receive();
         _receive(resp);
       } catch (error) {
-        PP.error(`Error in send/receive on ZMQ socket. ${error.toString()}`);
+        D.error(`Error in send/receive on ZMQ socket. ${error.toString()}`);
         _cancel(ids);
       }
       zmqIsBusy = false;
@@ -895,10 +895,10 @@ function _receive(resp: any) {
           break;
         case 'WRONG':
           err = shift();
-          PP.error(`ZMQ Protocol Error: ${err}`);
+          D.error(`ZMQ Protocol Error: ${err}`);
           break;
         default:
-          PP.error(`Unknown Response: ${cmd}`);
+          D.error(`Unknown Response: ${cmd}`);
           unknownResponse = true;
           break;
       }
diff --git a/ivette/src/frama-c/states.ts b/ivette/src/frama-c/states.ts
index 3474e9acd6cd3c21998f410e6a8a3d1381e1733f..f1e6d91c15b70cd82d413ce414967bb4d45ed9f1 100644
--- a/ivette/src/frama-c/states.ts
+++ b/ivette/src/frama-c/states.ts
@@ -25,7 +25,7 @@ const STATE_PREFIX = 'frama-c.state.';
 // --- Pretty Printing (Browser Console)
 // --------------------------------------------------------------------------
 
-const PP = new Dome.PP('States');
+const D = new Dome.Debug('States');
 
 // --------------------------------------------------------------------------
 // --- Synchronized Current Project
@@ -45,7 +45,7 @@ Server.onReady(async () => {
     currentProject = current.id;
     Dome.emit(PROJECT);
   } catch (error) {
-    PP.error(`Fail to retrieve the current project. ${error.toString()}`);
+    D.error(`Fail to retrieve the current project. ${error.toString()}`);
   }
 });
 
@@ -85,7 +85,7 @@ export async function setProject(project: string) {
       currentProject = project;
       Dome.emit(PROJECT);
     } catch (error) {
-      PP.error(`Fail to set the current project. ${error.toString()}`);
+      D.error(`Fail to set the current project. ${error.toString()}`);
     }
   }
 }
@@ -131,7 +131,7 @@ export function useRequest<In, Out>(
         const r = await Server.send(rq, params);
         update(r);
       } catch (error) {
-        PP.error(`Fail in useRequest '${rq.name}'. ${error.toString()}`);
+        D.error(`Fail in useRequest '${rq.name}'. ${error.toString()}`);
         update(options.onError);
       }
     } else {
@@ -250,7 +250,7 @@ class SyncState<A> {
       if (setter) await Server.send(setter, v);
       Dome.emit(this.UPDATE);
     } catch (error) {
-      PP.error(
+      D.error(
         `Fail to set value of syncState '${this.handler.name}'.`,
         `${error.toString()}`,
       );
@@ -264,7 +264,7 @@ class SyncState<A> {
       this.value = v;
       Dome.emit(this.UPDATE);
     } catch (error) {
-      PP.error(
+      D.error(
         `Fail to update syncState '${this.handler.name}'.`,
         `${error.toString()}`,
       );
@@ -311,7 +311,7 @@ export function useSyncState<A>(
  */
 export function useSyncValue<A>(va: Value<A>): A | undefined {
   const s = getSyncState(va);
-  Dome.useUpdate(s.update);
+  Dome.useUpdate(PROJECT, s.UPDATE);
   Server.useSignal(s.handler.signal, s.update);
   return s.getValue();
 }
@@ -361,7 +361,7 @@ class SyncArray<K, A> {
       } while (pending > 0);
       /* eslint-enable no-await-in-loop */
     } catch (error) {
-      PP.error(
+      D.error(
         `Fail to retrieve the value of syncArray '${this.handler.name}.`,
         `${error.toString()}`,
       );
@@ -380,7 +380,7 @@ class SyncArray<K, A> {
         this.fetch();
       }
     } catch (error) {
-      PP.error(
+      D.error(
         `Fail to set reload of syncArray '${this.handler.name}'.`,
         `${error.toString()}`,
       );
diff --git a/ivette/src/renderer/ASTview.tsx b/ivette/src/renderer/ASTview.tsx
index a635b1a7869202b426cbf363bf03a009a6194da9..e2463f89692a41ce7a97e300e9ae5c6d6e9885ec 100644
--- a/ivette/src/renderer/ASTview.tsx
+++ b/ivette/src/renderer/ASTview.tsx
@@ -7,6 +7,7 @@ import * as Server from 'frama-c/server';
 import * as States from 'frama-c/states';
 
 import * as Dome from 'dome';
+import * as Settings from 'dome/data/settings';
 import { key } from 'dome/data/json';
 import { RichTextBuffer } from 'dome/text/buffers';
 import { Text } from 'dome/text/editors';
@@ -19,6 +20,8 @@ import 'codemirror/mode/clike/clike';
 import 'codemirror/theme/ambiance.css';
 import 'codemirror/theme/solarized.css';
 
+import { Theme, FontSize } from './Preferences';
+
 const THEMES = [
   { id: 'default', label: 'Default' },
   { id: 'ambiance', label: 'Ambiance' },
@@ -30,7 +33,7 @@ const THEMES = [
 // --- Pretty Printing (Browser Console)
 // --------------------------------------------------------------------------
 
-const PP = new Dome.PP('AST View');
+const D = new Dome.Debug('AST View');
 
 // --------------------------------------------------------------------------
 // --- Rich Text Printer
@@ -55,7 +58,7 @@ async function loadAST(
             buffer.scroll(theMarker, undefined);
         });
       } catch (err) {
-        PP.error(
+        D.error(
           'Fail to retrieve the AST of function', theFunction,
           'marker:', theMarker, err,
         );
@@ -74,9 +77,9 @@ const ASTview = () => {
   const buffer = React.useMemo(() => new RichTextBuffer(), []);
   const printed: React.MutableRefObject<string | undefined> = React.useRef();
   const [selection, updateSelection] = States.useSelection();
-  const [theme, setTheme] = Dome.useGlobalSetting('ASTview.theme', 'default');
-  const [fontSize, setFontSize] = Dome.useGlobalSetting('ASTview.fontSize', 12);
-  const [wrapText, setWrapText] = Dome.useSwitch('ASTview.wrapText', false);
+  const [theme, setTheme] = Settings.useGlobalSettings(Theme);
+  const [fontSize, setFontSize] = Settings.useGlobalSettings(FontSize);
+  const [wrapText, flipWrapText] = Dome.useBoolSettings('ASTview.wrapText');
   const markers = States.useSyncModel(markerInfo);
 
   const theFunction = selection?.current?.function;
@@ -122,10 +125,10 @@ const ASTview = () => {
 
   // Theme Popup
   const selectTheme = (id?: string) => id && setTheme(id);
-  const checkTheme =
-    (th: { id: string }) => ({ checked: th.id === theme, ...th });
-  const themePopup =
-    () => Dome.popupMenu(THEMES.map(checkTheme), selectTheme);
+  const themeItem = (th: { id: string; label: string }) => (
+    { checked: th.id === theme, ...th }
+  );
+  const themePopup = () => Dome.popupMenu(THEMES.map(themeItem), selectTheme);
 
   // Component
   return (
@@ -151,7 +154,7 @@ const ASTview = () => {
         <IconButton
           icon="WRAPTEXT"
           selected={wrapText}
-          onClick={setWrapText}
+          onClick={flipWrapText}
           title="Wrap text"
         />
       </TitleBar>
diff --git a/ivette/src/renderer/Application.tsx b/ivette/src/renderer/Application.tsx
index 7aee4d0277d9d5bca6044a4e436c220f2006dcbd..a593a1e967ec5e5847105b5f203b8a3b76f066f4 100644
--- a/ivette/src/renderer/Application.tsx
+++ b/ivette/src/renderer/Application.tsx
@@ -54,14 +54,8 @@ const SelectionControls = () => {
 // --------------------------------------------------------------------------
 
 export default (() => {
-  const [sidebar, flipSidebar] = Dome.useSwitch(
-    'frama-c.sidebar.unfold',
-    false,
-  );
-  const [viewbar, flipViewbar] = Dome.useSwitch(
-    'frama-c.viewbar.unfold',
-    false,
-  );
+  const [sidebar, flipSidebar] = Dome.useBoolSettings('frama-c.sidebar.unfold');
+  const [viewbar, flipViewbar] = Dome.useBoolSettings('frama-c.viewbar.unfold');
 
   return (
     <Vfill>
diff --git a/ivette/src/renderer/Controller.tsx b/ivette/src/renderer/Controller.tsx
index 699fa98dc8a2018dc87afac4848253179e67aaad..17e78da201562f6c311fc1a94b8a5bd94435b838 100644
--- a/ivette/src/renderer/Controller.tsx
+++ b/ivette/src/renderer/Controller.tsx
@@ -4,6 +4,8 @@
 
 import React from 'react';
 import * as Dome from 'dome';
+import * as Json from 'dome/data/json';
+import * as Settings from 'dome/data/settings';
 
 import { Button as ToolButton, ButtonGroup, Space } from 'dome/frame/toolbars';
 import { LED, LEDstatus, IconButton } from 'dome/controls/buttons';
@@ -97,8 +99,10 @@ function insertConfig(hs: string[], cfg: Server.Configuration) {
 let reloadCommand: string | undefined;
 
 Dome.onReload(() => {
-  const hst = Dome.getWindowSetting('Controller.history');
-  reloadCommand = Array.isArray(hst) && hst[0];
+  const [lastCmd] = Settings.getWindowSettings(
+    'Controller.history', Json.jList(Json.jString), [],
+  );
+  reloadCommand = lastCmd;
 });
 
 Dome.onCommand((argv: string[], cwd: string) => {
@@ -169,9 +173,11 @@ const editor = new RichTextBuffer();
 const RenderConsole = () => {
   const scratch = React.useRef([] as string[]);
   const [cursor, setCursor] = React.useState(-1);
-  const [history, setHistory] = Dome.useState('Controller.history', []);
   const [isEmpty, setEmpty] = React.useState(true);
   const [noTrash, setNoTrash] = React.useState(true);
+  const [history, setHistory] = Settings.useWindowSettings(
+    'Controller.history', Json.jList(Json.jString), [],
+  );
 
   Dome.useEmitter(editor, 'change', () => {
     const cmd = editor.getValue().trim();
diff --git a/ivette/src/renderer/Preferences.js b/ivette/src/renderer/Preferences.js
index 7a9d1f76f585e32a17058ba1bd3c7151644aa108..1847aa2dda1a8f4429102222b8fb6034694400ff 100644
--- a/ivette/src/renderer/Preferences.js
+++ b/ivette/src/renderer/Preferences.js
@@ -14,12 +14,17 @@
 import React from 'react' ;
 
 import * as Dome from 'dome';
+import * as Json from 'dome/data/json';
+import * as Settings from 'dome/data/settings';
 import { Form, Section, FieldSelect, FieldCheckbox, FieldSlider } from 'dome/layout/forms' ;
 
+export const Theme = new Settings.GString('ASTview.theme','default');
+export const FontSize = new Settings.GNumber('ASTview.fontSize',12);
+
 const ASTviewPrefs = () => {
 
-  const [theme, setTheme] = Dome.useGlobalSetting('ASTview.theme', 'default');
-  const [fontSize, setFontSize] = Dome.useGlobalSetting('ASTview.fontSize', 12);
+  const [theme, setTheme] = Settings.useGlobalSettings(Theme);
+  const [fontSize, setFontSize] = Settings.useGlobalSettings(FontSize);
 
   return (
     <React.Fragment>
diff --git a/ivette/src/renderer/Properties.tsx b/ivette/src/renderer/Properties.tsx
index e2a434f7a7e0743ff27b63b55aa4ac0d0f9d5fa5..f1722e6816cc6d12dd84aea1baacdf4e1c2ed632 100644
--- a/ivette/src/renderer/Properties.tsx
+++ b/ivette/src/renderer/Properties.tsx
@@ -5,7 +5,7 @@
 import _ from 'lodash';
 import React, { useEffect } from 'react';
 import * as Dome from 'dome';
-import { key } from 'dome/data/json';
+import * as Json from 'dome/data/json';
 import * as States from 'frama-c/states';
 import * as Compare from 'dome/data/compare';
 import { Label, Code } from 'dome/controls/labels';
@@ -239,7 +239,7 @@ const byColumn: Arrays.ByColumns<Property> = {
   file: Compare.byFields<Property>({ source: byFile }),
 };
 
-class PropertyModel extends Arrays.CompactModel<key<'#status'>, Property> {
+class PropertyModel extends Arrays.CompactModel<Json.key<'#status'>, Property> {
 
   private filterFun?: string;
   private filterProp = _.cloneDeep(defaultFilter);
@@ -438,10 +438,11 @@ const RenderTable = () => {
     model.reload();
   }, [model, data]);
 
-  const [selection, updateSelection] = States.useSelection();
+  const [selection, updateSelection] =
+    States.useSelection();
 
   const [showFilter, flipFilter] =
-    Dome.useSwitch('ivette.properties.showFilter', true);
+    Dome.useBoolSettings('ivette.properties.showFilter');
 
   // Updating the filter
   const selectedFunction = selection?.current?.function;