diff --git a/ivette/.eslintignore b/ivette/.eslintignore
index e0d530b07981ceaa194fcffe211a324d309dc00e..e5fe0a814d6250a91f43a72a3dda9cee662b1b47 100644
--- a/ivette/.eslintignore
+++ b/ivette/.eslintignore
@@ -11,4 +11,3 @@ src/api
 # lint Dome step by step
 src/dome/src/renderer/layout
 src/dome/src/renderer/table
-src/dome/src/renderer/data
diff --git a/ivette/.eslintrc.js b/ivette/.eslintrc.js
index 1d1eaf1486b532b7221407287a5350c65b4823a1..10db14fc4fdb270ff4b03fd3e7523f6d42b9c924 100644
--- a/ivette/.eslintrc.js
+++ b/ivette/.eslintrc.js
@@ -55,6 +55,8 @@ module.exports = {
     "padded-blocks": "off",
     // Allow braces on their own line
     "@typescript-eslint/brace-style": "off",
+    // Already has built-in compiler checks in TSC for that
+    "@typescript-eslint/no-unused-vars": "off",
     // Allow range conditions such as 0 <= x && x < 10
     "yoda": [2, "never", { "onlyEquality": true }],
     // Allow single command on new line after 'if' statement
@@ -89,5 +91,12 @@ module.exports = {
     "jsx-a11y/no-autofocus": "off",
     // Completely broken rule
     "react/prop-types": "off",
+    // Enable ++ and --
+    "no-plusplus": "off",
+    // Enable nested ternary operations
+    "no-nested-ternary": "off",
+    // Checked by TSC compiler
+    "default-case": "off",
+    "consistent-return": "off",
   }
 };
diff --git a/ivette/api/server_tsc.ml b/ivette/api/server_tsc.ml
index 8f5eb6e829b7992c706487f59d1b23b226f80421..2c17909b1007893e522bffed614b6858e666968d 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 js -> Format.fprintf fmt "@[<hov 2>Json.Dict<@,%a>@]" pp js
     | Jdata id | Jenum id -> pp_ident fmt id
     | Joption js -> Format.fprintf fmt "%a |@ undefined" pp js
     | Jtuple js ->
@@ -172,10 +172,10 @@ let rec makeDecoder ~safe ?self ~names fmt js =
   | Jenum id -> jsafe ~safe (Pkg.name_of_ident id) (jenum names) fmt id
   | Jself -> jcall names fmt (Pkg.Derived.decode ~safe (getSelf self))
   | Joption js -> makeLoose fmt js
-  | Jdict(kd,js) ->
-    Format.fprintf fmt "@[<hov 2>Json.jDictionary('#%s',@,%a)@]" kd makeLoose js
+  | Jdict js ->
+    Format.fprintf fmt "@[<hov 2>Json.jDict(@,%a)@]" makeLoose js
   | Jlist js ->
-    Format.fprintf fmt "@[<hov 2>Json.jList(%a)@]" makeLoose js
+    Format.fprintf fmt "@[<hov 2>Json.jList(@,%a)@]" makeLoose js
   | Jarray js ->
     if safe
     then Format.fprintf fmt "@[<hov 2>Json.jArray(%a)@]" makeSafe js
@@ -245,11 +245,11 @@ let makeOrder ~self ~names fmt js =
       List.iter
         (fun (fd,js) -> Format.fprintf fmt "@ @[<hov 2>%s: %a,@]" fd pp js) jfs ;
       Format.fprintf fmt "@]@ })@]" ;
-    | Jdict(kd,js) ->
+    | Jdict js ->
       let jtype fmt js = makeJtype ~names fmt js in
       Format.fprintf fmt
-        "@[<hov 2>Compare.dictionary<@,Json.dict<'#%s'@,%a>>(@,%a)@]"
-        kd jtype js pp js
+        "@[<hov 2>Compare.dictionary<@,Json.dict<%a>>(@,%a)@]"
+        jtype js pp js
   in pp fmt js
 
 (* -------------------------------------------------------------------------- *)
diff --git a/ivette/src/dome/src/renderer/data/compare.ts b/ivette/src/dome/src/renderer/data/compare.ts
index 31185f33ee006c019b53b8438c9f1b3f390ef10e..b8cb955f537d46ed630dc805df3b696afc931706 100644
--- a/ivette/src/dome/src/renderer/data/compare.ts
+++ b/ivette/src/dome/src/renderer/data/compare.ts
@@ -13,7 +13,7 @@ import FastCompare from 'react-fast-compare';
 /**
    Interface for comparison functions.
    These function shall fullfill the following contract:
-   - `compare(x,y) == 0` shall be an equivalence relation
+   - `compare(x,y) === 0` shall be an equivalence relation
      (reflexive, symmetric, transitive)
    - `compare(x,y) <= 0` shall be a complete order
      (reflexive, antisymetric, transitive)
@@ -38,7 +38,10 @@ export type bignum = bigint | number;
 
 /** Detect Non-NaN numbers and big-ints. */
 export function isBigNum(x: any): x is bignum {
-  return typeof (x) === 'bigint' || (typeof (x) === 'number' && !Number.isNaN(x));
+  return (
+    (typeof (x) === 'bigint') ||
+    (typeof (x) === 'number' && !Number.isNaN(x))
+  );
 }
 
 /**
@@ -79,17 +82,18 @@ export function float(x: number, y: number) {
 */
 export function alpha(x: string, y: string) {
   const cmp = primitive(x.toLowerCase(), y.toLowerCase());
-  return cmp != 0 ? cmp : primitive(x, y);
+  return cmp !== 0 ? cmp : primitive(x, y);
 }
 
 /** Combine comparison orders in sequence. */
 export function sequence<A>(...orders: (Order<A> | undefined)[]): Order<A> {
   return (x: A, y: A) => {
     if (x === y) return 0;
-    for (const order of orders) {
+    for (let k = 0; k < orders.length; k++) {
+      const order = orders[k];
       if (order) {
         const cmp = order(x, y);
-        if (cmp != 0) return cmp;
+        if (cmp !== 0) return cmp;
       }
     }
     return 0;
@@ -99,9 +103,9 @@ export function sequence<A>(...orders: (Order<A> | undefined)[]): Order<A> {
 /** Compare optional values. Undefined values come first. */
 export function option<A>(order: Order<A>): Order<undefined | A> {
   return (x?: A, y?: A) => {
-    if (x == undefined && y == undefined) return 0;
-    if (x == undefined) return -1;
-    if (y == undefined) return 1;
+    if (x === undefined && y === undefined) return 0;
+    if (x === undefined) return -1;
+    if (y === undefined) return 1;
     return order(x, y);
   };
 }
@@ -109,9 +113,9 @@ export function option<A>(order: Order<A>): Order<undefined | A> {
 /** Compare optional values. Undefined values come last. */
 export function defined<A>(order: Order<A>): Order<undefined | A> {
   return (x?: A, y?: A) => {
-    if (x == undefined && y == undefined) return 0;
-    if (x == undefined) return 1;
-    if (y == undefined) return -1;
+    if (x === undefined && y === undefined) return 0;
+    if (x === undefined) return 1;
+    if (y === undefined) return -1;
     return order(x, y);
   };
 }
@@ -125,7 +129,7 @@ export function array<A>(order: Order<A>): Order<A[]> {
     const m = p < q ? p : q;
     for (let k = 0; k < m; k++) {
       const cmp = order(x[k], y[k]);
-      if (cmp != 0) return cmp;
+      if (cmp !== 0) return cmp;
     }
     return p - q;
   };
@@ -134,11 +138,13 @@ export function array<A>(order: Order<A>): Order<A[]> {
 /** Order by dictionary order.
     Can be used directly with an enum type declaration.
  */
-export function byEnum<A extends string>(d: { [key: string]: A }): Order<A> {
+export function byEnum<A extends string>(
+  d: { [key: string]: A },
+): Order<A> {
   const ranks: { [index: string]: number } = {};
   const values = Object.keys(d);
   const wildcard = values.length;
-  values.forEach((C, k) => ranks[C] = k);
+  values.forEach((C, k) => { ranks[C] = k; });
   return (x: A, y: A) => {
     if (x === y) return 0;
     const rx = ranks[x] ?? wildcard;
@@ -148,20 +154,21 @@ export function byEnum<A extends string>(d: { [key: string]: A }): Order<A> {
 }
 
 /** Order string enumeration constants.
-    `byRank(v1,...,vN)` will order constant following the order of arguments.
-    Non-listed constants appear at the end, or at the rank specified by `'*'`. */
+    `byRank(v1,...,vN)` will order constant following the
+    order of arguments.
+    Non-listed constants appear at the end, or at the rank
+    specified by `'*'`. */
 export function byRank(...args: string[]): Order<string> {
   const ranks: { [index: string]: number } = {};
-  args.forEach((C, k) => ranks[C] = k);
+  args.forEach((C, k) => { ranks[C] = k; });
   const wildcard = ranks['*'] ?? ranks.length;
   return (x: string, y: string) => {
     if (x === y) return 0;
     const rx = ranks[x] ?? wildcard;
     const ry = ranks[y] ?? wildcard;
-    if (rx == wildcard && ry == wildcard)
+    if (rx === wildcard && ry === wildcard)
       return primitive(x, y);
-    else
-      return rx - ry;
+    return rx - ry;
   };
 }
 
@@ -187,7 +194,7 @@ export function getKeys<T>(a: T): (keyof T)[] {
  */
 export type ByFields<A> = {
   [P in keyof A]?: Order<A[P]>;
-}
+};
 
 /**
    Maps each field of `A` to some comparison of the associated type.
@@ -196,36 +203,39 @@ export type ByFields<A> = {
 */
 export type ByAllFields<A> = {
   [P in keyof A]: Order<A[P]>;
-}
+};
 
-/** Object comparison by (some) fields.
+/**
+   Object comparison by (some) fields.
 
-    Compare objects field by field, using the comparison orders provided by the
-    `order` argument. Order of field comparison is taken from the `order`
-    argument, not from the compared values.
+   Compare objects field by field, using the comparison orders provided by the
+   `order` argument. Order of field comparison is taken from the `order`
+   argument, not from the compared values.
 
-    You may not compare _all_ fields of the compared values.  For optional
-    fields, you shall provide a comparison function compatible with type
-    `undefined`.
+   You may not compare _all_ fields of the compared values.  For optional
+   fields, you shall provide a comparison function compatible with type
+   `undefined`.
 
-    It might be difficult for Typescript to typecheck `byFields(…)` expressions
-    when dealing with optional types. In such cases, you shall use `byFields<A>(…)`
-    and explicitly mention the type of compared values.
+   It might be difficult for Typescript to typecheck `byFields(…)` expressions
+   when dealing with optional types. In such cases, you shall use
+   `byFields<A>(…)` and explicitly mention the type of compared values.
 
-    Example:
+   Example:
 
-        type foo = { id: number, name?: string, descr?: string }
-        const compare = fields<foo>({ id: number, name: option(alpha) });
+   *   type foo = { id: number, name?: string, descr?: string }
+   *   const compare = fields<foo>({ id: number, name: option(alpha) });
 
 */
 export function byFields<A>(order: ByFields<A>): Order<A> {
   return (x: A, y: A) => {
     if (x === y) return 0;
-    for (const fd of getKeys(order)) {
+    const fds = getKeys(order);
+    for (let k = 0; k < fds.length; k++) {
+      const fd = fds[k];
       const byFd = order[fd];
       if (byFd !== undefined) {
         const cmp = byFd(x[fd], y[fd]);
-        if (cmp != 0) return cmp;
+        if (cmp !== 0) return cmp;
       }
     }
     return 0;
@@ -239,10 +249,12 @@ export function byFields<A>(order: ByFields<A>): Order<A> {
 export function byAllFields<A>(order: ByAllFields<A>): Order<A> {
   return (x: A, y: A) => {
     if (x === y) return 0;
-    for (const fd of getKeys<ByFields<A>>(order)) {
+    const fds = getKeys<ByFields<A>>(order);
+    for (let k = 0; k < fds.length; k++) {
+      const fd = fds[k];
       const byFd = order[fd];
       const cmp = byFd(x[fd], y[fd]);
-      if (cmp != 0) return cmp;
+      if (cmp !== 0) return cmp;
     }
     return 0;
   };
@@ -264,13 +276,14 @@ export function dictionary<A>(order: Order<A>): Order<dict<A>> {
     const p = fs.length;
     const q = gs.length;
     for (let i = 0, j = 0; i < p && j < q;) {
-      let a = undefined, b = undefined;
+      let a;
+      let b;
       const f = fs[i];
       const g = gs[j];
       if (f <= g) { a = dx[f]; i++; }
       if (g <= f) { b = dy[g]; j++; }
       const cmp = phi(a, b);
-      if (cmp != 0) return cmp;
+      if (cmp !== 0) return cmp;
     }
     return p - q;
   };
@@ -283,7 +296,7 @@ export function pair<A, B>(ordA: Order<A>, ordB: Order<B>): Order<[A, B]> {
     const [x1, y1] = u;
     const [x2, y2] = v;
     const cmp = ordA(x1, x2);
-    return cmp != 0 ? cmp : ordB(y1, y2);
+    return cmp !== 0 ? cmp : ordB(y1, y2);
   };
 }
 
@@ -298,9 +311,9 @@ export function triple<A, B, C>(
     const [x1, y1, z1] = u;
     const [x2, y2, z2] = v;
     const cmp1 = ordA(x1, x2);
-    if (cmp1 != 0) return cmp1;
+    if (cmp1 !== 0) return cmp1;
     const cmp2 = ordB(y1, y2);
-    if (cmp2 != 0) return cmp2;
+    if (cmp2 !== 0) return cmp2;
     return ordC(z1, z2);
   };
 }
@@ -317,11 +330,11 @@ export function tuple4<A, B, C, D>(
     const [x1, y1, z1, t1] = u;
     const [x2, y2, z2, t2] = v;
     const cmp1 = ordA(x1, x2);
-    if (cmp1 != 0) return cmp1;
+    if (cmp1 !== 0) return cmp1;
     const cmp2 = ordB(y1, y2);
-    if (cmp2 != 0) return cmp2;
+    if (cmp2 !== 0) return cmp2;
     const cmp3 = ordC(z1, z2);
-    if (cmp3 != 0) return cmp3;
+    if (cmp3 !== 0) return cmp3;
     return ordD(t1, t2);
   };
 }
@@ -339,13 +352,13 @@ export function tuple5<A, B, C, D, E>(
     const [x1, y1, z1, t1, w1] = u;
     const [x2, y2, z2, t2, w2] = v;
     const cmp1 = ordA(x1, x2);
-    if (cmp1 != 0) return cmp1;
+    if (cmp1 !== 0) return cmp1;
     const cmp2 = ordB(y1, y2);
-    if (cmp2 != 0) return cmp2;
+    if (cmp2 !== 0) return cmp2;
     const cmp3 = ordC(z1, z2);
-    if (cmp3 != 0) return cmp3;
+    if (cmp3 !== 0) return cmp3;
     const cmp4 = ordD(t1, t2);
-    if (cmp4 != 0) return cmp4;
+    if (cmp4 !== 0) return cmp4;
     return ordE(w1, w2);
   };
 }
@@ -355,11 +368,16 @@ export function tuple5<A, B, C, D, E>(
 // --------------------------------------------------------------------------
 
 /** @internal */
-enum RANK { UNDEFINED, BOOLEAN, SYMBOL, NAN, BIGNUM, STRING, ARRAY, OBJECT, FUNCTION };
+enum RANK {
+  UNDEFINED,
+  BOOLEAN, SYMBOL, NAN, BIGNUM,
+  STRING,
+  ARRAY, OBJECT, FUNCTION
+}
 
 /** @internal */
 function rank(x: any): RANK {
-  let t = typeof x;
+  const t = typeof x;
   switch (t) {
     case 'undefined': return RANK.UNDEFINED;
     case 'boolean': return RANK.BOOLEAN;
@@ -369,14 +387,16 @@ function rank(x: any): RANK {
     case 'bigint':
       return RANK.BIGNUM;
     case 'string': return RANK.STRING;
-    case 'object': return Array.isArray(x) ? RANK.ARRAY : RANK.OBJECT;
     case 'function': return RANK.FUNCTION;
+    case 'object':
+      return Array.isArray(x) ? RANK.ARRAY : RANK.OBJECT;
   }
 }
 
 /**
    Universal structural comparison.
-   Values are ordered by _rank_, each being associated with some type of values:
+   Values are ordered by _rank_, each being
+   associated with some type of values:
    1. undefined values;
    2. booleans;
    3. symbols;
@@ -389,10 +409,9 @@ function rank(x: any): RANK {
    For values of same primitive type, primitive ordering is performed.
 
    For array values, lexicographic ordering is performed.
-
-   For object values, lexicographic ordering is performed over their properties:
-   properties are ordered by name, and recursive structural ordering is performed
-   on property values.
+   For object values, lexicographic ordering is performed over their
+   properties: they are ordered by name, and recursive structural
+   ordering is performed on property values.
 
    All functions are compared equal.
  */
@@ -409,17 +428,18 @@ export function structural(x: any, y: any): number {
     const p = fs.length;
     const q = gs.length;
     for (let i = 0, j = 0; i < p && j < q;) {
-      let a = undefined, b = undefined;
+      let a;
+      let b;
       const f = fs[i];
       const g = gs[j];
       if (f <= g) { a = x[f]; i++; }
       if (g <= f) { b = y[g]; j++; }
       const cmp = structural(a, b);
-      if (cmp != 0) return cmp;
+      if (cmp !== 0) return cmp;
     }
     return p - q;
   }
   return rank(x) - rank(y);
-};
+}
 
 // --------------------------------------------------------------------------
diff --git a/ivette/src/dome/src/renderer/data/json.ts b/ivette/src/dome/src/renderer/data/json.ts
index ba0be2fc66fcef5b3a37e5e436633d1f4ebfba3f..033aa4e88286f42fa17933a301bad367b2ab2dfd 100644
--- a/ivette/src/dome/src/renderer/data/json.ts
+++ b/ivette/src/dome/src/renderer/data/json.ts
@@ -11,7 +11,7 @@
 import { DEVEL } from 'dome/system';
 
 export type json =
-  undefined | null | number | string | json[] | { [key: string]: json }
+  undefined | null | number | string | json[] | { [key: string]: json };
 
 /**
    Parse without _revivals_.
@@ -71,14 +71,14 @@ export interface Encoder<D> {
 }
 
 /** Can be used for most encoders. */
-export function identity<A>(v: A): A { return v; };
+export function identity<A>(v: A): A { return v; }
 
 // --------------------------------------------------------------------------
 // --- Primitives
 // --------------------------------------------------------------------------
 
 /** Always returns `undefined` on any input. */
-export const jNull: Safe<undefined> = (_: json) => undefined;
+export const jNull: Safe<undefined> = () => undefined;
 
 /** Identity. */
 export const jAny: Safe<json> = (js: json) => js;
@@ -123,7 +123,7 @@ export const jString: Loose<string> = (js: json) => (
    Can be used directly for enum types, eg. `jEnum(myEnumType)`.
  */
 export function jEnum<A>(d: { [tag: string]: A }): Loose<A> {
-  return (v: json) => typeof v === 'string' ? d[v] : undefined;
+  return (v: json) => (typeof v === 'string' ? d[v] : undefined);
 }
 
 /**
@@ -132,8 +132,8 @@ export function jEnum<A>(d: { [tag: string]: A }): Loose<A> {
    type `A`. However, it will not protected you from missings constants in `A`.
 */
 export function jTags<A>(...values: ((string | number) & A)[]): Loose<A> {
-  var m = new Map<string | number, A>();
-  values.forEach(v => m.set(v, v));
+  const m = new Map<string | number, A>();
+  values.forEach((v) => m.set(v, v));
   return (v: json) => (typeof v === 'string' ? m.get(v) : undefined);
 }
 
@@ -146,16 +146,20 @@ export function jDefault<A>(
   fn: Loose<A>,
   defaultValue: A,
 ): Safe<A> {
-  return (js: json) =>
-    js === undefined ? defaultValue : (fn(js) ?? defaultValue);
+  return (js: json) => (
+    js === undefined ? defaultValue : (fn(js) ?? defaultValue)
+  );
 }
 
 /**
-   Force returning `undefined` or a default value for `undefined` _or_ `null` JSON input.
+   Force returning `undefined` or a default value for
+   `undefined` _or_ `null` JSON input.
    Typically useful to leverage an existing `Safe<A>` decoder.
  */
 export function jOption<A>(fn: Safe<A>, defaultValue?: A): Loose<A> {
-  return (js: json) => (js === undefined || js === null ? defaultValue : fn(js));
+  return (js: json) => (
+    js === undefined || js === null ? defaultValue : fn(js)
+  );
 }
 
 /**
@@ -166,7 +170,7 @@ export function jFail<A>(fn: Loose<A>, error: string | Error): Safe<A> {
   return (js: json) => {
     const d = fn(js);
     if (d !== undefined) return d;
-    throw error;
+    throw (typeof (error) === 'string' ? new Error(error) : error);
   };
 }
 
@@ -206,10 +210,11 @@ export function jMap<A>(fn: Loose<A>): Safe<Map<string, A>> {
   return (js: json) => {
     const m = new Map<string, A>();
     if (js !== null && typeof js === 'object' && !Array.isArray(js)) {
-      for (let k of Object.keys(js)) {
+      const keys = Object.keys(js);
+      keys.forEach((k) => {
         const v = fn(js[k]);
         if (v !== undefined) m.set(k, v);
-      }
+      });
     }
     return m;
   };
@@ -219,7 +224,7 @@ export function jMap<A>(fn: Loose<A>): Safe<Map<string, A>> {
    Converts dictionaries to maps.
  */
 export function eMap<A>(fn: Encoder<A>): Encoder<Map<string, undefined | A>> {
-  return m => {
+  return (m) => {
     const js: json = {};
     m.forEach((v, k) => {
       if (v !== undefined) {
@@ -238,7 +243,7 @@ export function eMap<A>(fn: Encoder<A>): Encoder<Map<string, undefined | A>> {
    to discard undefined elements, or use a true _safe_ decoder.
  */
 export function jArray<A>(fn: Safe<A>): Safe<A[]> {
-  return (js: json) => Array.isArray(js) ? js.map(fn) : [];
+  return (js: json) => (Array.isArray(js) ? js.map(fn) : []);
 }
 
 /**
@@ -249,7 +254,7 @@ export function jArray<A>(fn: Safe<A>): Safe<A[]> {
 export function jList<A>(fn: Loose<A>): Safe<A[]> {
   return (js: json) => {
     const buffer: A[] = [];
-    if (Array.isArray(js)) js.forEach(vj => {
+    if (Array.isArray(js)) js.forEach((vj) => {
       const d = fn(vj);
       if (d !== undefined) buffer.push(d);
     });
@@ -261,9 +266,9 @@ export function jList<A>(fn: Loose<A>): Safe<A[]> {
    Exports all non-undefined elements.
  */
 export function eList<A>(fn: Encoder<A>): Encoder<(A | undefined)[]> {
-  return m => {
+  return (m) => {
     const js: json[] = [];
-    m.forEach(v => {
+    m.forEach((v) => {
       if (v !== undefined) {
         const u = fn(v);
         if (u !== undefined) js.push(u);
@@ -278,10 +283,10 @@ export function jPair<A, B>(
   fa: Safe<A>,
   fb: Safe<B>,
 ): Loose<[A, B]> {
-  return (js: json) => Array.isArray(js) ? [
+  return (js: json) => (Array.isArray(js) ? [
     fa(js[0]),
     fb(js[1]),
-  ] : undefined;
+  ] : undefined);
 }
 
 /** Similar to [[jPair]]. */
@@ -290,11 +295,11 @@ export function jTriple<A, B, C>(
   fb: Safe<B>,
   fc: Safe<C>,
 ): Loose<[A, B, C]> {
-  return (js: json) => Array.isArray(js) ? [
+  return (js: json) => (Array.isArray(js) ? [
     fa(js[0]),
     fb(js[1]),
     fc(js[2]),
-  ] : undefined;
+  ] : undefined);
 }
 
 /** Similar to [[jPair]]. */
@@ -304,12 +309,12 @@ export function jTuple4<A, B, C, D>(
   fc: Safe<C>,
   fd: Safe<D>,
 ): Loose<[A, B, C, D]> {
-  return (js: json) => Array.isArray(js) ? [
+  return (js: json) => (Array.isArray(js) ? [
     fa(js[0]),
     fb(js[1]),
     fc(js[2]),
     fd(js[3]),
-  ] : undefined;
+  ] : undefined);
 }
 
 /** Similar to [[jPair]]. */
@@ -320,13 +325,13 @@ export function jTuple5<A, B, C, D, E>(
   fd: Safe<D>,
   fe: Safe<E>,
 ): Loose<[A, B, C, D, E]> {
-  return (js: json) => Array.isArray(js) ? [
+  return (js: json) => (Array.isArray(js) ? [
     fa(js[0]),
     fb(js[1]),
     fc(js[2]),
     fd(js[3]),
     fe(js[4]),
-  ] : undefined;
+  ] : undefined);
 }
 
 /**
@@ -335,7 +340,7 @@ export function jTuple5<A, B, C, D, E>(
 */
 export type Props<A> = {
   [P in keyof A]: Safe<A[P]>;
-}
+};
 
 /**
    Decode an object given the decoders of its fields.
@@ -345,7 +350,8 @@ export function jObject<A>(fp: Props<A>): Loose<A> {
   return (js: json) => {
     if (js !== null && typeof js === 'object' && !Array.isArray(js)) {
       const buffer = {} as A;
-      for (var k of Object.keys(fp)) {
+      const keys = Object.keys(fp);
+      keys.forEach((k) => {
         const fn = fp[k as keyof A];
         if (fn !== undefined) {
           const fj = js[k];
@@ -354,7 +360,7 @@ export function jObject<A>(fp: Props<A>): Loose<A> {
             if (fv !== undefined) buffer[k as keyof A] = fv;
           }
         }
-      }
+      });
       return buffer;
     }
     return undefined;
@@ -366,8 +372,8 @@ export function jObject<A>(fp: Props<A>): Loose<A> {
  */
 export function jUnion<A>(...cases: Loose<A>[]): Loose<A> {
   return (js: json) => {
-    for (var fn of cases) {
-      const fv = fn(js);
+    for (let i = 0; i < cases.length; i++) {
+      const fv = cases[i](js);
       if (fv !== undefined) return fv;
     }
     return undefined;
@@ -379,7 +385,7 @@ export function jUnion<A>(...cases: Loose<A>[]): Loose<A> {
 */
 export type EProps<A> = {
   [P in keyof A]?: Encoder<A[P]>;
-}
+};
 
 /**
    Encode an object given the provided encoders by fields.
@@ -389,7 +395,8 @@ export type EProps<A> = {
 export function eObject<A>(fp: EProps<A>): Encoder<A> {
   return (m: A) => {
     const js: json = {};
-    for (var k of Object.keys(fp)) {
+    const keys = Object.keys(fp);
+    keys.forEach((k) => {
       const fn = fp[k as keyof A];
       if (fn !== undefined) {
         const fv = m[k as keyof A];
@@ -398,9 +405,9 @@ export function eObject<A>(fp: EProps<A>): Encoder<A> {
           if (r !== undefined) js[k] = r;
         }
       }
-    }
+    });
     return js;
-  }
+  };
 }
 
 // Intentionnaly internal and only declared
@@ -413,56 +420,43 @@ export function forge<K, A>(_tag: K, data: A): phantom<K, A> {
   return data as any;
 }
 
-/** String key with kind. Can be used as a `string` but shall be created with [forge]. */
+/** String key with kind.
+    Can be used as a `string` but shall be created with [forge]. */
 export type key<K> = phantom<K, string>;
 
-/** Number index with kind. Can be used as a `number` but shall be created with [forge]. */
+/** Number index with kind.
+    Can be used as a `number` but shall be created with [forge]. */
 export type index<K> = phantom<K, number>;
 
 /** Decoder for `key<K>` strings. */
 export function jKey<K>(kd: K): Loose<key<K>> {
-  return (js: json) => typeof js === 'string' ? forge(kd, js) : undefined;
+  return (js: json) => (typeof js === 'string' ? forge(kd, js) : undefined);
 }
 
 /** Decoder for `index<K>` numbers. */
 export function jIndex<K>(kd: K): Loose<index<K>> {
-  return (js: json) => typeof js === 'number' ? forge(kd, js) : undefined;
-}
-
-/** Dictionaries with « typed » keys. */
-export type dict<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 {
-  return d[k];
-}
-
-/** Empty dictionary. */
-export function empty<K, A>(kd: K): dict<K, A> {
-  return forge(kd, {} as any);
+  return (js: json) => (typeof js === 'number' ? forge(kd, js) : undefined);
 }
 
-/** Dictionary extension. */
-export function index<K, A>(d: dict<K, A>, key: key<K>, value: A) {
-  d[key] = value;
-}
+/** Dictionaries. */
+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 jDictionary<K, A>(kd: K, fn: Loose<A>): Safe<dict<K, A>> {
+export function jDict<A>(fn: Loose<A>): Safe<dict<A>> {
   return (js: json) => {
-    const buffer: dict<K, A> = empty(kd);
+    const buffer: dict<A> = {};
     if (js !== null && typeof js === 'object' && !Array.isArray(js)) {
-      for (var key of Object.keys(js)) {
+      const keys = Object.keys(js);
+      keys.forEach((key) => {
         const fd = js[key];
         if (fd !== undefined) {
           const fv = fn(fd);
-          if (fv !== undefined) index(buffer, forge(kd, key), fv);
+          if (fv !== undefined) buffer[key] = fv;
         }
-      }
+      });
     }
     return buffer;
   };
@@ -472,16 +466,17 @@ 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 eDict<A>(fn: Encoder<A>): Encoder<dict<A>> {
+  return (d: dict<A>) => {
     const js: json = {};
-    for (var k of Object.keys(d)) {
+    const keys = Object.keys(d);
+    keys.forEach((k) => {
       const fv = d[k];
       if (fv !== undefined) {
         const fr = fn(fv);
         if (fr !== undefined) js[k] = fr;
       }
-    }
+    });
     return js;
   };
 }
diff --git a/ivette/src/dome/src/renderer/data/states.ts b/ivette/src/dome/src/renderer/data/states.ts
index c1fbb827435c3b1f721268d059e9a4640d7aeb0b..ce7704696991024b8dc1ecb49baaa7825a6c3466 100644
--- a/ivette/src/dome/src/renderer/data/states.ts
+++ b/ivette/src/dome/src/renderer/data/states.ts
@@ -11,9 +11,6 @@
 import React from 'react';
 import Emitter from 'events';
 import isEqual from 'react-fast-compare';
-import { DEVEL } from 'dome/misc/system';
-import * as Dome from 'dome';
-import * as JSON from './json';
 
 const UPDATE = 'dome.states.update';
 
@@ -25,7 +22,7 @@ export class State<A> {
 
   constructor(initValue: A) {
     this.value = initValue;
-    this.emitter = new Emitter;
+    this.emitter = new Emitter();
     this.getValue = this.getValue.bind(this);
     this.setValue = this.setValue.bind(this);
   }
@@ -59,222 +56,8 @@ export function useState<A>(s: State<A>): [A, (update: A) => void] {
   React.useEffect(() => {
     s.on(setCurrent);
     return () => s.off(setCurrent);
-  });
+  }, [s]);
   return [current, s.setValue];
-};
-
-// --------------------------------------------------------------------------
-// --- Settings
-// --------------------------------------------------------------------------
-
-/**
-   Generic interface to Window and Global Settings.
-   To be used with [[useSettings]] with instances of its derived classes,
-   typically [[WindowSettings]] and [[GlobalSettings]]. You should never have
-   to implement a Settings class on your own.
-
-   All setting values are identified with
-   an untyped `dataKey: string`, that can be dynamically modified
-   for each component. Hence, two components might share both datakeys
-   and settings.
-
-   When several components share the same setting `dataKey` the behavior will be
-   different depending on the situation:
-   - for Window Settings, each component in each window retains its own
-   setting value, although the last modified value from _any_ of them will be
-   saved and used for any further initial value;
-   - for Global Settings, all components synchronize to the last modified value
-   from any component of any window.
-
-   Type safety is ensured by safe JSON encoders and decoders, however, they
-   might fail at runtime, causing settings value to be initialized to their
-   fallback and not to be saved nor synchronized.
-   This is not harmful but annoying.
-
-   To mitigate this effect, each instance of a Settings class has its
-   own, private, unique symbol that we call its « role ». A given `dataKey`
-   shall always be used with the same « role » otherwise it is discarded,
-   and an error message is logged when in DEVEL mode.
- */
-export abstract class Settings<A> {
-
-  private static keyRoles = new Map<string, symbol>();
-
-  private readonly role: symbol;
-  protected readonly decoder: JSON.Safe<A>;
-  protected readonly encoder: JSON.Encoder<A>;
-
-  /**
-     Encoders shall be protected against exception.
-     Use [[dome/data/json.jTry]] and [[dome/data/json.jCatch]] in case of uncertainty.
-     Decoders are automatically protected internally to the Settings class.
-     @param role Debugging name of instance roles (each instance has its unique
-     role, though)
-     @param decoder JSON decoder for the setting values
-     @param encoder JSON encoder for the setting values
-     @param fallback If provided, used to automatically protect your encoders
-     against exceptions.
-   */
-  constructor(
-    role: string,
-    decoder: JSON.Safe<A>,
-    encoder: JSON.Encoder<A>,
-    fallback?: A,
-  ) {
-    this.role = Symbol(role);
-    this.encoder = encoder;
-    this.decoder =
-      fallback !== undefined ? JSON.jCatch(decoder, fallback) : decoder;
-  }
-
-  /**
-     Returns identity if the data key is only
-     used with the same setting instance.
-     Otherwise, returns `undefined`.
-   */
-  validateKey(dataKey?: string): string | undefined {
-    if (dataKey === undefined) return undefined;
-    const rq = this.role;
-    const rk = Settings.keyRoles.get(dataKey);
-    if (rk === undefined) {
-      Settings.keyRoles.set(dataKey, rq);
-    } else {
-      if (rk !== rq) {
-        if (DEVEL) console.error(
-          `[Dome.settings] Key ${dataKey} used with incompatible roles`, rk, rq,
-        );
-        return undefined;
-      }
-    }
-    return dataKey;
-  }
-
-  /** @internal */
-  abstract loadData(key: string): JSON.json;
-
-  /** @internal */
-  abstract saveData(key: string, data: JSON.json): void;
-
-  /** @internal */
-  abstract event: string;
-
-  /** Returns the current setting value for the provided data key. You shall
-      only use validated keys otherwise you might fallback to default values. */
-  loadValue(dataKey?: string) {
-    return this.decoder(dataKey ? this.loadData(dataKey) : undefined)
-  }
-
-  /** Push the new setting value for the provided data key.
-      You shall only use validated keys otherwise further loads
-      might fail and fallback to defaults. */
-  saveValue(dataKey: string, value: A) {
-    try { this.saveData(dataKey, this.encoder(value)); }
-    catch (err) {
-      if (DEVEL) console.error(
-        '[Dome.settings] Error while encoding value',
-        dataKey, value, err,
-      );
-    }
-  }
-
-}
-
-/**
-   Generic React Hook to be used with any kind of [[Settings]].
-   You may share `dataKey` between components, or change it dynamically.
-   However, a given data key shall always be used for the same Setting instance.
-   See [[Settings]] documentation for details.
-   @param S The instance settings to be used.
-   @param dataKey Identifies which value in the settings to be used.
- */
-export function useSettings<A>(
-  S: Settings<A>,
-  dataKey?: string,
-): [A, (update: A) => void] {
-
-  const theKey = React.useMemo(() => S.validateKey(dataKey), [S, dataKey]);
-  const [value, setValue] = React.useState<A>(() => S.loadValue(theKey));
-
-  React.useEffect(() => {
-    if (theKey) {
-      const callback = () => setValue(S.loadValue(theKey));
-      Dome.on(S.event, callback);
-      return () => Dome.off(S.event, callback);
-    }
-    return undefined;
-  });
-
-  const updateValue = React.useCallback((update: A) => {
-    if (!isEqual(value, update)) {
-      setValue(update);
-      if (theKey) S.saveValue(theKey, update);
-    }
-  }, [S, theKey]);
-
-  return [value, updateValue];
-
-}
-
-/** Window Settings for non-JSON data.
-    In most situations, you can use [[WindowSettings]] instead.
-    You can use a [[dome/data/json.Loose]] decoder for optional values. */
-export class WindowSettingsData<A> extends Settings<A> {
-
-  constructor(
-    role: string,
-    decoder: JSON.Safe<A>,
-    encoder: JSON.Encoder<A>,
-    fallback?: A,
-  ) {
-    super(role, decoder, encoder, fallback);
-  }
-
-  event = 'dome.defaults';
-  loadData(key: string) { return Dome.getWindowSetting(key) as JSON.json; }
-  saveData(key: string, data: JSON.json) { Dome.setWindowSetting(key, data); }
-
-}
-
-/** Global Settings for non-JSON data.
-    In most situations, you can use [[WindowSettings]] instead.
-    You can use a [[dome/data/json.Loose]] decoder for optional values. */
-export class GlobalSettingsData<A> extends Settings<A> {
-
-  constructor(
-    role: string,
-    decoder: JSON.Safe<A>,
-    encoder: JSON.Encoder<A>,
-    fallback?: A,
-  ) {
-    super(role, decoder, encoder, fallback);
-  }
-
-  event = 'dome.settings';
-  loadData(key: string) { return Dome.getGlobalSetting(key) as JSON.json; }
-  saveData(key: string, data: JSON.json) { Dome.setGlobalSetting(key, data); }
-
-}
-
-/** Window Settings.
-    For non-JSON data, use [[WindowSettingsData]] instead.
-    You can use a [[dome/data/json.Loose]] decoder for optional values. */
-export class WindowSettings<A extends JSON.json> extends WindowSettingsData<A> {
-
-  constructor(role: string, decoder: JSON.Safe<A>, fallback?: A) {
-    super(role, decoder, JSON.identity, fallback);
-  }
-
-}
-
-/** Global Settings.
-    For non-JSON data, use [[WindowSettingsData]] instead.
-    You can use a [[dome/data/json.Loose]] decoder for optional values. */
-export class GlobalSettings<A extends JSON.json> extends GlobalSettingsData<A> {
-
-  constructor(role: string, decoder: JSON.Safe<A>, fallback?: A) {
-    super(role, decoder, JSON.identity, fallback);
-  }
-
 }
 
 // --------------------------------------------------------------------------
diff --git a/src/plugins/server/package.ml b/src/plugins/server/package.ml
index 6f2e56f956b5cafbb98573b3d8712d95206ed9d6..7bc235b55a5d3e95c1f9e47c5aa0565141a52cdf 100644
--- a/src/plugins/server/package.ml
+++ b/src/plugins/server/package.ml
@@ -169,7 +169,7 @@ type jtype =
   | Jkey of string (* kind of a string used for indexing *)
   | Jindex of string (* kind of an integer used for indexing *)
   | Joption of jtype
-  | Jdict of string * jtype (* kind of keys *)
+  | Jdict of jtype (* dictionaries *)
   | Jlist of jtype (* order does not matter *)
   | Jarray of jtype (* order matters *)
   | Jtuple of jtype list
@@ -290,14 +290,14 @@ let rec isRecursive = function
   | Jdata _ | Jenum _
   | Jany | Jnull | Jboolean | Jnumber
   | Jstring | Jalpha | Jkey _ | Jindex _ -> false
-  | Joption js | Jdict(_,js)  | Jarray js | Jlist js -> isRecursive js
+  | Joption js | Jdict js  | Jarray js | Jlist js -> isRecursive js
   | Jtuple js | Junion js -> List.exists isRecursive js
   | Jrecord fjs -> List.exists (fun (_,js) -> isRecursive js) fjs
 
 let rec visit_jtype fn = function
   | Jany | Jself | Jnull | Jboolean | Jnumber
   | Jstring | Jalpha | Jkey _ | Jindex _ -> ()
-  | Joption js | Jdict(_,js)  | Jarray js | Jlist js -> visit_jtype fn js
+  | Joption js | Jdict js  | Jarray js | Jlist js -> visit_jtype fn js
   | Jtuple js | Junion js -> List.iter (visit_jtype fn) js
   | Jrecord fjs -> List.iter (fun (_,js) -> visit_jtype fn js) fjs
   | Jdata id | Jenum id ->
@@ -469,8 +469,8 @@ let rec md_jtype pp = function
   | Junion js -> md_jlist pp "|" js
   | Jarray js | Jlist js -> protect pp js @ Md.code "[]"
   | Jrecord fjs -> Md.code "{" @ fields pp fjs @ Md.code "}"
-  | Jdict (id,js) ->
-    Md.code "{[" @ key id @ Md.code "]:" @ md_jtype pp js @ Md.code "}"
+  | Jdict js ->
+    Md.code "{[key]:" @ md_jtype pp js @ Md.code "}"
 
 and md_jlist pp sep js =
   Md.glue ~sep:(Md.plain sep)  (List.map (md_jtype pp) js)
diff --git a/src/plugins/server/package.mli b/src/plugins/server/package.mli
index c040c985bc85129a3c15bb222e1afdffaf2262a4..019e1dd38130c103534e23001220ee13624f3eaf 100644
--- a/src/plugins/server/package.mli
+++ b/src/plugins/server/package.mli
@@ -37,7 +37,7 @@ type jtype =
   | Jkey of string (** kind of a string used for indexing *)
   | Jindex of string (** kind of an integer used for indexing *)
   | Joption of jtype
-  | Jdict of string * jtype (** kind of keys *)
+  | Jdict of jtype (** dictionaries *)
   | Jlist of jtype (** order does not matter *)
   | Jarray of jtype (** order matters *)
   | Jtuple of jtype list