Aller au contenu

X 0000·Y 0000·— fps

Des applications qui tiennent en production.

Kouma Studio conçoit, développe et opère des applications web. Produit, design et ingénierie dans une seule équipe — du premier croquis au déploiement.

Cliquez sur l’afficheurDéfiler ↓

01 · Savoir-faire

Ce que nous savons construire.

Six terrains, de la conception à la mise en production.

C.01

Applications web & SaaS

Comptes, rôles, paiements, tableaux de bord : des produits complets, pas des prototypes.

C.02

Offline-first & PWA

Des applications qui s’installent comme des apps natives et continuent de fonctionner sans réseau.

C.03

Calcul dans le navigateur

Traitement local de fichiers lourds — PDF, image, vidéo, audio — sans serveur ni envoi.

C.04

Outils développeur & CLI

Protocoles, interfaces en ligne de commande et automatisations pour les équipes techniques.

C.05

Design produit & design system

Parcours, interfaces et systèmes de design livrés en tokens et en composants, pas seulement en maquettes.

C.06

Sites éditoriaux & SEO

Contenu structuré, données enrichies, performances mesurées : des pages qui se trouvent et se chargent vite.

02 · Sous le capot

Cette page, mesurée en direct.

Pas de chiffres marketing : ces valeurs sont relevées à l’instant, dans votre navigateur. Cliquez, tapez, faites défiler — l’INP se met à jour.

Core Web Vitals — cette visite

LCP
Mesure en cours…
INP
Interagissez avec la page
CLS
Mesure en cours…
FCP
Mesure en cours…
TTFB
Mesure en cours…

Ressources & rendu

Poids
Transféré, compressé
JavaScript
Dont scripts
Requêtes
Document compris
Afficheur
Dernier relevé (hors écran)
Cellules
Calculées par image
Draw calls
1Par image

L’afficheur du haut de page tient en un seul fragment shader.

WebGL2 · un triangle plein écran · un draw call par image · zéro dépendance.

components/led/shader.ts — fragment
1#version 300 es2precision highp float;34uniform vec2 uResolution;   // canevas, en pixels physiques5uniform vec2 uGrid;         // colonnes, rangées6uniform float uCell;        // côté d'une cellule, en pixels physiques7uniform vec2 uOrigin;       // coin haut-gauche de la grille8uniform float uDpr;9uniform float uTime;        // secondes10uniform float uMix;         // transition scène A -> B, de 0 à 111uniform float uIntro;       // apparition, de 0 à 112uniform float uMotion;      // 0 sous prefers-reduced-motion13uniform vec2 uPointer;      // pointeur (très loin s'il est absent)14uniform vec3 uRipple;       // clic : x, y, instant15uniform vec3 uInk;          // couleur des points16uniform sampler2D uSceneA;  // une texel par cellule : allumée ou non17uniform sampler2D uSceneB;1819out vec4 fragColor;2021// Hash stable par cellule : chacune bascule à son propre instant.22float hash(vec2 p) {23  p = fract(p * vec2(123.34, 456.21));24  p += dot(p, p + 45.32);25  return fract(p.x * p.y);26}2728// Carré arrondi en distance signée — rx = 0,32 x côté, comme le K pixel.29float roundedSquare(vec2 p, float side) {30  float r = 0.32 * side;31  vec2 q = abs(p) - 0.5 * side + r;32  return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r;33}3435void main() {36  vec2 px = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y) - uOrigin;37  vec2 cell = floor(px / uCell);38  if (cell.x < 0.0 || cell.y < 0.0 || cell.x >= uGrid.x || cell.y >= uGrid.y) discard;3940  vec2 local = px / uCell - cell - 0.5;41  vec2 uv = (cell + 0.5) / uGrid;42  vec2 center = (cell + 0.5) * uCell + uOrigin;4344  // Scène : A et B se relaient, cellule par cellule.45  float flip = smoothstep(hash(cell) * 0.7, hash(cell) * 0.7 + 0.3, uMix);46  float lit = mix(texture(uSceneA, uv).r, texture(uSceneB, uv).r, flip);4748  // Onde diagonale du loader Kouma, du coin haut-gauche au coin bas-droit.49  float diag = (cell.x + cell.y) / (uGrid.x + uGrid.y);50  float wave = 0.5 + 0.5 * sin(6.2832 * (diag * 4.0 - uTime * 0.4));5152  // Apparition en balayage diagonal.53  float intro = smoothstep(diag, diag + 0.2, uIntro * 1.2);5455  // Loupe sous le pointeur, rayon d'environ 110 px CSS.56  float d = length(center - uPointer) / (110.0 * uDpr);57  float lens = exp(-d * d * 2.0) * uMotion;5859  // Onde de choc au clic : un anneau qui s'étend et s'éteint.60  float age = uTime - uRipple.z;61  float rd = length(center - uRipple.xy) / uDpr;62  float ring = age < 0.0 ? 0.063    : exp(-pow((rd - age * 700.0) / 40.0, 2.0)) * exp(-age * 1.8) * uMotion;6465  float side = mix(0.28, 0.72, lit)66    + 0.06 * wave * lit * uMotion67    + (0.34 * lens + 0.5 * ring) * (1.0 - 0.7 * lit);68  float alpha = mix(0.08 + 0.06 * wave * uMotion, 1.0, lit)69    + (0.45 * lens + 0.6 * ring) * (1.0 - lit);7071  float dist = roundedSquare(local, min(side, 0.9) * intro) * uCell;72  float a = clamp(alpha, 0.0, 1.0) * (1.0 - smoothstep(-0.5, 0.5, dist)) * intro;73  fragColor = vec4(uInk * a, a);74}

03 · Contact

Un projet d’application ? Parlons-en.

Décrivez-le en quelques lignes — contexte, objectif, échéance. Nous revenons vers vous pour en discuter.

hello@koumalabs.org
Échap
↑ ↓ naviguer · ↵ ouvrirKouma Studio