Brand pulse-dot translated to favicon: dark rounded square (#0d1b12) + inner green dot (#6ab98a) + faint outer ring (#2d7a4f @60%). Identical visual language to .brand::before in the nav. Assets: - favicon.svg — vector primary (modern browsers, scales) - favicon-32.png — PNG hint - favicon.ico — legacy multi-size (16/24/32/48) - apple-touch-icon.png — iOS home-screen 180x180 PIL-generated PNG/ICO at 8x supersample + Lanczos downscale for clean antialiasing. No external dependency added (PIL already on system). index.html: 4 <link> tags wired in <head> (SVG, PNG 32, ICO alternate, apple-touch). CV HTML left untouched; browser auto-fetches /favicon.ico from root as fallback — TODO logged to mirror the link block when the user finalizes CV edits. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1612 lines
55 KiB
HTML
1612 lines
55 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="description" content="Bastien Chanot — Développeur Systèmes · Embarqué · Backend. 7 ans en C, Rust, Linux kernel, AOSP, cloud gaming et GPU bare-metal en production.">
|
||
<meta name="author" content="Bastien Chanot">
|
||
<meta name="theme-color" content="#0d1b12">
|
||
<title>Bastien Chanot — Développeur Systèmes · Embarqué · Backend</title>
|
||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png">
|
||
<link rel="alternate icon" href="/favicon.ico">
|
||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Fraunces:ital,wght@0,300;0,500;0,600;0,700;1,400&family=DM+Sans:wght@300;400;500;600&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root {
|
||
/* Palette — non négociable */
|
||
--dark: #0d1b12;
|
||
--dark-mid: #183325;
|
||
--g900: #0e3320;
|
||
--g700: #1b5e3b;
|
||
--g500: #2d7a4f;
|
||
--g300: #6ab98a;
|
||
--g100: #dff0e7;
|
||
--g050: #eef7f1;
|
||
|
||
--ink-1: #111111;
|
||
--ink-2: #1e1e1e;
|
||
--ink-3: #636363;
|
||
|
||
--page: #f5f3ec;
|
||
--rule: #d8d4c8;
|
||
--tag: #e6e2d8;
|
||
|
||
/* Typographies */
|
||
--mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;
|
||
--serif: 'Fraunces', Georgia, serif;
|
||
--sans: 'DM Sans', system-ui, -apple-system, sans-serif;
|
||
|
||
/* Échelle */
|
||
--r-sm: 4px;
|
||
--r-md: 6px;
|
||
--r-pill: 999px;
|
||
--shadow-sm: 0 1px 2px rgba(13, 27, 18, 0.06);
|
||
--shadow-md: 0 6px 24px rgba(13, 27, 18, 0.08);
|
||
--shadow-lg: 0 20px 60px rgba(13, 27, 18, 0.12);
|
||
|
||
--nav-h: 64px;
|
||
--max-w: 1100px;
|
||
}
|
||
|
||
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
|
||
|
||
html { scroll-behavior: smooth; scroll-padding-top: calc(var(--nav-h) + 16px); }
|
||
|
||
body {
|
||
background: var(--page);
|
||
color: var(--ink-2);
|
||
font-family: var(--sans);
|
||
font-size: 16px;
|
||
line-height: 1.6;
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
::selection { background: var(--g300); color: var(--dark); }
|
||
|
||
a { color: var(--g700); text-decoration: none; transition: color .18s ease; }
|
||
a:hover { color: var(--g500); }
|
||
a:focus-visible { outline: 2px solid var(--g500); outline-offset: 3px; border-radius: 2px; }
|
||
|
||
button, .btn { font-family: inherit; cursor: pointer; }
|
||
|
||
/* ── NAV ── */
|
||
.nav {
|
||
position: fixed;
|
||
top: 0; left: 0; right: 0;
|
||
height: var(--nav-h);
|
||
background: rgba(13, 27, 18, 0.92);
|
||
backdrop-filter: saturate(140%) blur(10px);
|
||
-webkit-backdrop-filter: saturate(140%) blur(10px);
|
||
border-bottom: 1px solid rgba(106, 185, 138, 0.12);
|
||
z-index: 50;
|
||
}
|
||
.nav-inner {
|
||
max-width: var(--max-w);
|
||
height: 100%;
|
||
margin: 0 auto;
|
||
padding: 0 24px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 24px;
|
||
}
|
||
.brand {
|
||
font-family: var(--mono);
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: var(--g100);
|
||
letter-spacing: 0.5px;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
.brand::before {
|
||
content: "";
|
||
width: 8px; height: 8px;
|
||
border-radius: 50%;
|
||
background: var(--g300);
|
||
box-shadow: 0 0 0 0 rgba(106,185,138,.7);
|
||
animation: pulse 2.4s infinite;
|
||
}
|
||
@keyframes pulse {
|
||
0% { box-shadow: 0 0 0 0 rgba(106,185,138,.5); }
|
||
70% { box-shadow: 0 0 0 10px rgba(106,185,138,0); }
|
||
100% { box-shadow: 0 0 0 0 rgba(106,185,138,0); }
|
||
}
|
||
.nav-links { display: flex; gap: 4px; list-style: none; }
|
||
.nav-links a {
|
||
font-family: var(--mono);
|
||
font-size: 13px;
|
||
color: rgba(223, 240, 231, 0.75);
|
||
padding: 8px 12px;
|
||
border-radius: var(--r-sm);
|
||
transition: color .18s ease, background .18s ease;
|
||
}
|
||
.nav-links a:hover { color: var(--g100); background: rgba(106,185,138,0.08); }
|
||
.nav-toggle { display: none; }
|
||
|
||
@media (max-width: 768px) {
|
||
.nav-links {
|
||
position: absolute;
|
||
top: var(--nav-h); left: 0; right: 0;
|
||
flex-direction: column;
|
||
gap: 0;
|
||
background: var(--dark);
|
||
border-bottom: 1px solid rgba(106,185,138,0.12);
|
||
padding: 8px 0;
|
||
transform: translateY(-200%);
|
||
transition: transform .25s ease;
|
||
}
|
||
.nav-links.open { transform: translateY(0); }
|
||
.nav-links a { padding: 14px 24px; border-radius: 0; }
|
||
.nav-toggle {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 40px; height: 40px;
|
||
margin-left: auto;
|
||
background: transparent;
|
||
border: 1px solid rgba(106,185,138,0.25);
|
||
border-radius: var(--r-sm);
|
||
color: var(--g100);
|
||
}
|
||
.nav-toggle svg { width: 18px; height: 18px; }
|
||
}
|
||
|
||
/* ── LAYOUT ── */
|
||
main { padding-top: var(--nav-h); }
|
||
section { padding: 96px 24px; }
|
||
.container { max-width: var(--max-w); margin: 0 auto; }
|
||
|
||
.section-label {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
font-family: var(--mono);
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
color: var(--g500);
|
||
letter-spacing: 0.12em;
|
||
text-transform: uppercase;
|
||
margin-bottom: 18px;
|
||
}
|
||
.section-label::before {
|
||
content: "";
|
||
width: 24px; height: 1px; background: var(--g500);
|
||
}
|
||
.section-dark .section-label { color: var(--g300); }
|
||
.section-dark .section-label::before { background: var(--g300); }
|
||
|
||
h2.section-title {
|
||
font-family: var(--serif);
|
||
font-weight: 600;
|
||
font-size: clamp(28px, 4vw, 40px);
|
||
line-height: 1.1;
|
||
color: var(--ink-1);
|
||
letter-spacing: -0.02em;
|
||
margin-bottom: 20px;
|
||
}
|
||
.section-dark h2.section-title { color: #fff; }
|
||
|
||
.section-intro {
|
||
font-family: var(--sans);
|
||
font-size: 17px;
|
||
color: var(--ink-2);
|
||
max-width: 64ch;
|
||
}
|
||
.section-dark .section-intro { color: rgba(223, 240, 231, 0.85); }
|
||
|
||
/* ── HERO ── */
|
||
.hero {
|
||
position: relative;
|
||
min-height: calc(100vh - var(--nav-h));
|
||
padding: 80px 24px 96px;
|
||
display: flex;
|
||
align-items: center;
|
||
overflow: hidden;
|
||
background:
|
||
radial-gradient(ellipse 80% 60% at 80% 0%, rgba(45,122,79,0.10) 0%, transparent 60%),
|
||
radial-gradient(ellipse 60% 50% at 0% 100%, rgba(27,94,59,0.08) 0%, transparent 55%),
|
||
var(--page);
|
||
}
|
||
.hero-inner {
|
||
max-width: var(--max-w);
|
||
width: 100%;
|
||
margin: 0 auto;
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: 28px;
|
||
position: relative;
|
||
}
|
||
.hero-eyebrow {
|
||
font-family: var(--mono);
|
||
font-size: 13px;
|
||
color: var(--g700);
|
||
letter-spacing: 0.08em;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
.hero-eyebrow::before {
|
||
content: "▍";
|
||
color: var(--g500);
|
||
font-weight: 700;
|
||
}
|
||
.hero-name {
|
||
font-family: var(--serif);
|
||
font-size: clamp(48px, 8vw, 96px);
|
||
font-weight: 600;
|
||
line-height: 0.95;
|
||
letter-spacing: -0.04em;
|
||
color: var(--ink-1);
|
||
}
|
||
.hero-name em {
|
||
font-style: italic;
|
||
font-weight: 400;
|
||
color: var(--g700);
|
||
}
|
||
.hero-title {
|
||
font-family: var(--mono);
|
||
font-size: clamp(14px, 1.6vw, 17px);
|
||
color: var(--ink-2);
|
||
font-weight: 500;
|
||
letter-spacing: 0.02em;
|
||
}
|
||
.hero-title .sep { color: var(--g500); margin: 0 8px; }
|
||
.hero-tagline {
|
||
font-family: var(--serif);
|
||
font-style: italic;
|
||
font-weight: 300;
|
||
font-size: clamp(20px, 2.6vw, 28px);
|
||
line-height: 1.35;
|
||
color: var(--ink-2);
|
||
max-width: 56ch;
|
||
border-left: 3px solid var(--g500);
|
||
padding-left: 20px;
|
||
}
|
||
.hero-cta {
|
||
display: flex;
|
||
gap: 14px;
|
||
flex-wrap: wrap;
|
||
margin-top: 12px;
|
||
}
|
||
.btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
font-family: var(--mono);
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.02em;
|
||
padding: 14px 22px;
|
||
border-radius: var(--r-md);
|
||
border: 1px solid transparent;
|
||
transition: transform .18s ease, background .18s ease, color .18s ease, border-color .18s ease, box-shadow .18s ease;
|
||
text-decoration: none;
|
||
}
|
||
.btn-primary {
|
||
background: var(--dark);
|
||
color: var(--g100);
|
||
border-color: var(--dark);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
.btn-primary:hover {
|
||
background: var(--g700);
|
||
border-color: var(--g700);
|
||
color: #fff;
|
||
transform: translateY(-1px);
|
||
box-shadow: var(--shadow-md);
|
||
}
|
||
.btn-secondary {
|
||
background: transparent;
|
||
color: var(--dark);
|
||
border-color: var(--rule);
|
||
}
|
||
.btn-secondary:hover {
|
||
border-color: var(--g500);
|
||
color: var(--g700);
|
||
background: var(--g050);
|
||
transform: translateY(-1px);
|
||
}
|
||
.btn .arrow {
|
||
width: 14px; height: 14px;
|
||
transition: transform .18s ease;
|
||
}
|
||
.btn:hover .arrow { transform: translate(2px, -2px); }
|
||
|
||
.hero-meta {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 24px;
|
||
margin-top: 16px;
|
||
font-family: var(--mono);
|
||
font-size: 12px;
|
||
color: var(--ink-3);
|
||
letter-spacing: 0.04em;
|
||
}
|
||
.hero-meta span { display: inline-flex; align-items: center; gap: 8px; }
|
||
.hero-meta .dot {
|
||
display: inline-block;
|
||
width: 6px; height: 6px;
|
||
border-radius: 50%;
|
||
background: var(--g500);
|
||
}
|
||
|
||
/* Stagger entrance */
|
||
.reveal { opacity: 0; transform: translateY(14px); animation: rise .8s cubic-bezier(.2,.7,.2,1) forwards; }
|
||
.reveal.d1 { animation-delay: .08s; }
|
||
.reveal.d2 { animation-delay: .18s; }
|
||
.reveal.d3 { animation-delay: .30s; }
|
||
.reveal.d4 { animation-delay: .42s; }
|
||
.reveal.d5 { animation-delay: .55s; }
|
||
.reveal.d6 { animation-delay: .68s; }
|
||
@keyframes rise {
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.reveal { opacity: 1; transform: none; animation: none; }
|
||
.brand::before { animation: none; }
|
||
html { scroll-behavior: auto; }
|
||
}
|
||
|
||
/* ── ABOUT ── */
|
||
.about {
|
||
background: var(--dark);
|
||
background-image:
|
||
radial-gradient(ellipse 60% 50% at 100% 0%, rgba(45,122,79,0.16) 0%, transparent 55%),
|
||
radial-gradient(ellipse 50% 40% at 0% 100%, rgba(27,94,59,0.12) 0%, transparent 60%);
|
||
color: #fff;
|
||
position: relative;
|
||
}
|
||
.about::before {
|
||
content: ""; position: absolute; left: 0; top: 0; bottom: 0;
|
||
width: 3px;
|
||
background: linear-gradient(to bottom, var(--g300), var(--g700));
|
||
}
|
||
.about-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: 32px;
|
||
align-items: start;
|
||
}
|
||
.about-text p {
|
||
font-size: 18px;
|
||
line-height: 1.65;
|
||
color: rgba(223, 240, 231, 0.92);
|
||
margin-bottom: 16px;
|
||
max-width: 62ch;
|
||
}
|
||
.about-text strong { color: var(--g300); font-weight: 500; }
|
||
.about-callout {
|
||
border: 1px solid rgba(106,185,138,0.25);
|
||
border-radius: var(--r-md);
|
||
padding: 20px 22px;
|
||
background: rgba(13, 27, 18, 0.4);
|
||
}
|
||
.about-callout dt {
|
||
font-family: var(--mono);
|
||
font-size: 11px;
|
||
color: var(--g300);
|
||
letter-spacing: 0.12em;
|
||
text-transform: uppercase;
|
||
margin-bottom: 6px;
|
||
}
|
||
.about-callout dd {
|
||
font-family: var(--sans);
|
||
font-size: 15px;
|
||
color: var(--g100);
|
||
margin-bottom: 14px;
|
||
}
|
||
.about-callout dd:last-child { margin-bottom: 0; }
|
||
.about-callout a { color: var(--g300); }
|
||
.about-callout a:hover { color: var(--g100); }
|
||
|
||
@media (min-width: 768px) {
|
||
.about-grid { grid-template-columns: 1.6fr 1fr; gap: 56px; }
|
||
}
|
||
|
||
/* ── STACK ── */
|
||
.stack { background: var(--page); }
|
||
.stack-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: 20px;
|
||
margin-top: 40px;
|
||
}
|
||
.stack-card {
|
||
background: #fff;
|
||
border: 1px solid var(--rule);
|
||
border-radius: var(--r-md);
|
||
padding: 24px;
|
||
transition: border-color .25s ease, transform .25s ease, box-shadow .25s ease;
|
||
}
|
||
.stack-card:hover {
|
||
border-color: var(--g300);
|
||
transform: translateY(-2px);
|
||
box-shadow: var(--shadow-md);
|
||
}
|
||
.stack-card-head {
|
||
display: flex;
|
||
align-items: baseline;
|
||
justify-content: space-between;
|
||
margin-bottom: 16px;
|
||
padding-bottom: 12px;
|
||
border-bottom: 1px dashed var(--rule);
|
||
}
|
||
.stack-card h3 {
|
||
font-family: var(--serif);
|
||
font-weight: 600;
|
||
font-size: 19px;
|
||
color: var(--ink-1);
|
||
letter-spacing: -0.01em;
|
||
}
|
||
.stack-card-tag {
|
||
font-family: var(--mono);
|
||
font-size: 11px;
|
||
color: var(--g500);
|
||
letter-spacing: 0.1em;
|
||
}
|
||
.pills {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
list-style: none;
|
||
}
|
||
.pill {
|
||
display: inline-block;
|
||
font-family: var(--mono);
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
color: var(--g900);
|
||
background: var(--g050);
|
||
border: 1px solid var(--g100);
|
||
padding: 6px 12px;
|
||
border-radius: var(--r-pill);
|
||
transition: background .18s ease, border-color .18s ease, color .18s ease;
|
||
}
|
||
.pill:hover {
|
||
background: var(--g100);
|
||
border-color: var(--g300);
|
||
color: var(--g700);
|
||
}
|
||
.pill-context {
|
||
opacity: 0.65;
|
||
font-weight: 400;
|
||
margin-left: 3px;
|
||
}
|
||
.stack-note {
|
||
margin-top: 14px;
|
||
padding-top: 12px;
|
||
border-top: 1px dashed var(--rule);
|
||
font-family: var(--mono);
|
||
font-size: 12px;
|
||
color: var(--ink-3);
|
||
letter-spacing: 0.02em;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
flex-wrap: wrap;
|
||
}
|
||
.stack-note code {
|
||
font-family: var(--mono);
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
color: var(--g700);
|
||
background: var(--g050);
|
||
border: 1px solid var(--g100);
|
||
padding: 2px 8px;
|
||
border-radius: var(--r-sm);
|
||
}
|
||
|
||
@media (min-width: 768px) { .stack-grid { grid-template-columns: repeat(2, 1fr); } }
|
||
@media (min-width: 1200px) { .stack-grid { grid-template-columns: repeat(3, 1fr); } }
|
||
|
||
/* ── EXPERIENCE ── */
|
||
.experience { background: var(--g050); }
|
||
.timeline {
|
||
position: relative;
|
||
margin-top: 40px;
|
||
padding-left: 28px;
|
||
border-left: 2px solid var(--g100);
|
||
}
|
||
.timeline-item {
|
||
position: relative;
|
||
padding: 0 0 36px 24px;
|
||
}
|
||
.timeline-item:last-child { padding-bottom: 0; }
|
||
.timeline-item::before {
|
||
content: "";
|
||
position: absolute;
|
||
left: -34px; top: 6px;
|
||
width: 12px; height: 12px;
|
||
border-radius: 50%;
|
||
background: var(--page);
|
||
border: 2px solid var(--g500);
|
||
box-shadow: 0 0 0 4px var(--g050);
|
||
}
|
||
.timeline-item.current::before {
|
||
background: var(--g500);
|
||
box-shadow: 0 0 0 4px var(--g050), 0 0 0 8px rgba(45,122,79,0.18);
|
||
}
|
||
.timeline-meta {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: baseline;
|
||
gap: 12px;
|
||
margin-bottom: 8px;
|
||
font-family: var(--mono);
|
||
font-size: 12px;
|
||
color: var(--ink-3);
|
||
letter-spacing: 0.04em;
|
||
}
|
||
.timeline-meta .period {
|
||
color: var(--g700);
|
||
font-weight: 600;
|
||
}
|
||
.timeline-meta .badge {
|
||
display: inline-block;
|
||
background: var(--g100);
|
||
color: var(--g700);
|
||
padding: 2px 8px;
|
||
border-radius: var(--r-pill);
|
||
font-size: 10px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
}
|
||
.timeline-item h3 {
|
||
font-family: var(--serif);
|
||
font-weight: 600;
|
||
font-size: 22px;
|
||
color: var(--ink-1);
|
||
margin-bottom: 4px;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
.timeline-item h3 a {
|
||
color: inherit;
|
||
border-bottom: 1px solid transparent;
|
||
transition: border-color .18s ease, color .18s ease;
|
||
}
|
||
.timeline-item h3 a:hover { color: var(--g700); border-color: var(--g500); }
|
||
.timeline-role {
|
||
font-family: var(--mono);
|
||
font-size: 13px;
|
||
color: var(--g700);
|
||
margin-bottom: 12px;
|
||
}
|
||
.timeline-desc {
|
||
color: var(--ink-2);
|
||
line-height: 1.6;
|
||
max-width: 64ch;
|
||
}
|
||
.timeline-contract {
|
||
font-family: var(--mono);
|
||
font-size: 12px;
|
||
color: var(--ink-3);
|
||
font-style: italic;
|
||
margin-top: -6px;
|
||
margin-bottom: 12px;
|
||
}
|
||
.timeline-intro {
|
||
color: var(--ink-2);
|
||
line-height: 1.55;
|
||
max-width: 64ch;
|
||
margin-bottom: 14px;
|
||
}
|
||
.timeline-bullets {
|
||
list-style: none;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
margin-bottom: 18px;
|
||
max-width: 70ch;
|
||
}
|
||
.timeline-bullets li {
|
||
position: relative;
|
||
padding-left: 22px;
|
||
color: var(--ink-2);
|
||
line-height: 1.55;
|
||
font-size: 15px;
|
||
}
|
||
.timeline-bullets li::before {
|
||
content: "▸";
|
||
position: absolute;
|
||
left: 0;
|
||
top: 1px;
|
||
color: var(--g500);
|
||
font-size: 13px;
|
||
line-height: 1.55;
|
||
}
|
||
.timeline-stack {
|
||
margin-top: 4px;
|
||
}
|
||
.timeline-stack .pill {
|
||
font-size: 11px;
|
||
padding: 4px 10px;
|
||
}
|
||
|
||
/* ── PROJETS ── */
|
||
.projets { background: var(--page); }
|
||
.projects-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: 20px;
|
||
margin-top: 40px;
|
||
}
|
||
@media (min-width: 768px) { .projects-grid { grid-template-columns: repeat(2, 1fr); } }
|
||
.project-card {
|
||
background: #fff;
|
||
border: 1px solid var(--rule);
|
||
border-radius: var(--r-md);
|
||
padding: 24px;
|
||
transition: border-color .25s ease, transform .25s ease, box-shadow .25s ease;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.project-card:hover {
|
||
border-color: var(--g300);
|
||
transform: translateY(-2px);
|
||
box-shadow: var(--shadow-md);
|
||
}
|
||
.project-card-head {
|
||
display: flex;
|
||
align-items: baseline;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
margin-bottom: 12px;
|
||
padding-bottom: 10px;
|
||
border-bottom: 1px dashed var(--rule);
|
||
}
|
||
.project-card h3 {
|
||
font-family: var(--serif);
|
||
font-weight: 600;
|
||
font-size: 20px;
|
||
color: var(--ink-1);
|
||
letter-spacing: -0.01em;
|
||
}
|
||
.project-card-tag {
|
||
font-family: var(--mono);
|
||
font-size: 11px;
|
||
color: var(--g500);
|
||
letter-spacing: 0.1em;
|
||
flex-shrink: 0;
|
||
white-space: nowrap;
|
||
}
|
||
.project-tagline {
|
||
font-family: var(--serif);
|
||
font-style: italic;
|
||
font-weight: 300;
|
||
font-size: 15px;
|
||
color: var(--g700);
|
||
margin-bottom: 12px;
|
||
line-height: 1.4;
|
||
}
|
||
.project-desc {
|
||
color: var(--ink-2);
|
||
line-height: 1.6;
|
||
font-size: 15px;
|
||
margin-bottom: 14px;
|
||
}
|
||
.project-link {
|
||
margin-top: auto;
|
||
font-family: var(--mono);
|
||
font-size: 13px;
|
||
color: var(--g500);
|
||
border-bottom: 1px solid transparent;
|
||
transition: color .18s ease, border-color .18s ease;
|
||
align-self: flex-start;
|
||
}
|
||
.project-link:hover {
|
||
color: var(--g700);
|
||
border-bottom-color: var(--g500);
|
||
}
|
||
|
||
/* ── FORMATION ── */
|
||
.formation { background: var(--g050); }
|
||
.formation .timeline { border-left-color: var(--g100); }
|
||
.formation .timeline-item::before { box-shadow: 0 0 0 4px var(--g050); }
|
||
|
||
.formation-school-desc {
|
||
font-family: var(--serif);
|
||
font-style: italic;
|
||
font-weight: 300;
|
||
color: var(--ink-2);
|
||
line-height: 1.55;
|
||
max-width: 64ch;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.formation-themes {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: 18px;
|
||
margin-top: 24px;
|
||
}
|
||
@media (min-width: 768px) { .formation-themes { grid-template-columns: repeat(2, 1fr); } }
|
||
@media (min-width: 1200px) { .formation-themes { grid-template-columns: repeat(3, 1fr); } }
|
||
|
||
.theme-card {
|
||
background: #fff;
|
||
border: 1px solid var(--rule);
|
||
border-radius: var(--r-md);
|
||
padding: 22px;
|
||
transition: border-color .25s ease, transform .25s ease, box-shadow .25s ease;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.theme-card:hover {
|
||
border-color: var(--g300);
|
||
transform: translateY(-2px);
|
||
box-shadow: var(--shadow-md);
|
||
}
|
||
.theme-card-head {
|
||
display: flex;
|
||
align-items: baseline;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
margin-bottom: 12px;
|
||
padding-bottom: 10px;
|
||
border-bottom: 1px dashed var(--rule);
|
||
}
|
||
.theme-card h4 {
|
||
font-family: var(--serif);
|
||
font-weight: 600;
|
||
font-size: 18px;
|
||
color: var(--ink-1);
|
||
letter-spacing: -0.01em;
|
||
line-height: 1.2;
|
||
}
|
||
.theme-card-tag {
|
||
font-family: var(--mono);
|
||
font-size: 11px;
|
||
color: var(--g500);
|
||
letter-spacing: 0.1em;
|
||
flex-shrink: 0;
|
||
}
|
||
.theme-quote {
|
||
font-family: var(--serif);
|
||
font-style: italic;
|
||
font-weight: 300;
|
||
color: var(--ink-2);
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
padding-left: 12px;
|
||
border-left: 2px solid var(--g500);
|
||
margin-bottom: 16px;
|
||
}
|
||
.theme-list {
|
||
list-style: none;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
}
|
||
.theme-list li {
|
||
font-size: 13.5px;
|
||
line-height: 1.55;
|
||
color: var(--ink-2);
|
||
}
|
||
.theme-list code {
|
||
font-family: var(--mono);
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
color: var(--g700);
|
||
background: var(--g050);
|
||
border: 1px solid var(--g100);
|
||
padding: 1px 7px;
|
||
border-radius: var(--r-sm);
|
||
}
|
||
|
||
.formation-tsrit-list {
|
||
list-style: none;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
margin-top: 12px;
|
||
max-width: 64ch;
|
||
}
|
||
.formation-tsrit-list li {
|
||
color: var(--ink-2);
|
||
line-height: 1.55;
|
||
padding-left: 18px;
|
||
position: relative;
|
||
}
|
||
.formation-tsrit-list li::before {
|
||
content: "";
|
||
position: absolute;
|
||
left: 0; top: 0.65em;
|
||
width: 8px; height: 1px;
|
||
background: var(--g500);
|
||
}
|
||
.formation-tsrit-list li strong { color: var(--ink-1); font-weight: 600; }
|
||
|
||
.honors {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
font-family: var(--mono);
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
color: var(--g700);
|
||
background: var(--g100);
|
||
border: 1px solid var(--g300);
|
||
padding: 6px 14px;
|
||
border-radius: var(--r-pill);
|
||
letter-spacing: 0.04em;
|
||
margin: 4px 0 14px;
|
||
}
|
||
.honors::before {
|
||
content: "★";
|
||
color: var(--g500);
|
||
font-size: 13px;
|
||
}
|
||
|
||
/* ── MÉTHODE ── */
|
||
.methode { background: var(--page); }
|
||
.methode-list {
|
||
list-style: none;
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: 16px;
|
||
margin-top: 40px;
|
||
max-width: 820px;
|
||
}
|
||
.methode-item {
|
||
display: grid;
|
||
grid-template-columns: 56px 1fr;
|
||
gap: 20px;
|
||
align-items: start;
|
||
background: #fff;
|
||
border: 1px solid var(--rule);
|
||
border-radius: var(--r-md);
|
||
padding: 22px 24px;
|
||
transition: border-color .25s ease, transform .25s ease, box-shadow .25s ease;
|
||
}
|
||
.methode-item:hover {
|
||
border-color: var(--g300);
|
||
transform: translateY(-2px);
|
||
box-shadow: var(--shadow-md);
|
||
}
|
||
.methode-num {
|
||
font-family: var(--mono);
|
||
font-size: 22px;
|
||
font-weight: 700;
|
||
color: var(--g500);
|
||
letter-spacing: -0.02em;
|
||
line-height: 1;
|
||
padding-top: 4px;
|
||
}
|
||
.methode-body h3 {
|
||
font-family: var(--serif);
|
||
font-weight: 600;
|
||
font-size: 19px;
|
||
color: var(--ink-1);
|
||
letter-spacing: -0.01em;
|
||
margin-bottom: 6px;
|
||
line-height: 1.25;
|
||
}
|
||
.methode-body p {
|
||
color: var(--ink-2);
|
||
line-height: 1.6;
|
||
font-size: 15px;
|
||
max-width: 64ch;
|
||
}
|
||
@media (max-width: 640px) {
|
||
.methode-item { grid-template-columns: 1fr; gap: 8px; padding: 20px; }
|
||
.methode-num { font-size: 18px; padding-top: 0; }
|
||
}
|
||
|
||
/* ── CONTACT ── */
|
||
.contact {
|
||
background: var(--dark);
|
||
color: #fff;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.contact::after {
|
||
content: "";
|
||
position: absolute;
|
||
right: -120px; bottom: -120px;
|
||
width: 360px; height: 360px;
|
||
border-radius: 50%;
|
||
background: radial-gradient(circle, rgba(45,122,79,0.18) 0%, transparent 70%);
|
||
pointer-events: none;
|
||
}
|
||
.contact-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: 32px;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
.contact-list {
|
||
list-style: none;
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: 12px;
|
||
margin-top: 32px;
|
||
}
|
||
.contact-row {
|
||
display: grid;
|
||
grid-template-columns: 28px 1fr;
|
||
gap: 18px;
|
||
align-items: center;
|
||
padding: 18px 20px;
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border: 1px solid rgba(106,185,138,0.18);
|
||
border-radius: var(--r-md);
|
||
transition: border-color .18s ease, background .18s ease, transform .18s ease;
|
||
color: var(--g100);
|
||
}
|
||
.contact-row:hover {
|
||
border-color: var(--g300);
|
||
background: rgba(106,185,138,0.08);
|
||
transform: translateY(-1px);
|
||
color: #fff;
|
||
}
|
||
.contact-row svg { width: 20px; height: 20px; color: var(--g300); flex-shrink: 0; }
|
||
.contact-row .label {
|
||
display: block;
|
||
font-family: var(--mono);
|
||
font-size: 11px;
|
||
color: var(--g300);
|
||
letter-spacing: 0.12em;
|
||
text-transform: uppercase;
|
||
margin-bottom: 2px;
|
||
}
|
||
.contact-row .value {
|
||
font-family: var(--mono);
|
||
font-size: 15px;
|
||
color: #fff;
|
||
font-weight: 500;
|
||
word-break: break-word;
|
||
}
|
||
|
||
@media (min-width: 768px) {
|
||
.contact-list { grid-template-columns: repeat(2, 1fr); }
|
||
}
|
||
|
||
/* ── FOOTER ── */
|
||
.footer {
|
||
background: #061008;
|
||
color: rgba(223, 240, 231, 0.55);
|
||
padding: 32px 24px;
|
||
border-top: 1px solid rgba(106,185,138,0.1);
|
||
}
|
||
.footer-inner {
|
||
max-width: var(--max-w);
|
||
margin: 0 auto;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 16px 32px;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-family: var(--mono);
|
||
font-size: 12px;
|
||
letter-spacing: 0.04em;
|
||
}
|
||
.footer a { color: var(--g300); }
|
||
.footer a:hover { color: var(--g100); }
|
||
.footer-links { display: flex; gap: 20px; flex-wrap: wrap; }
|
||
|
||
/* ── RESPONSIVE TWEAKS ── */
|
||
@media (max-width: 768px) {
|
||
section { padding: 72px 20px; }
|
||
.hero { padding: 56px 20px 72px; }
|
||
.hero-cta .btn { flex: 1 1 auto; justify-content: center; }
|
||
.timeline { padding-left: 22px; }
|
||
.timeline-item { padding-left: 18px; }
|
||
.timeline-item::before { left: -29px; }
|
||
}
|
||
|
||
@media (min-width: 1200px) {
|
||
section { padding: 120px 24px; }
|
||
}
|
||
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- NAV -->
|
||
<header class="nav" role="banner">
|
||
<div class="nav-inner">
|
||
<a href="#hero" class="brand" aria-label="Bastien Chanot — accueil">bchanot.fr</a>
|
||
<button class="nav-toggle" type="button" aria-label="Ouvrir le menu" aria-expanded="false" aria-controls="primary-nav">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
|
||
</button>
|
||
<nav aria-label="Navigation principale">
|
||
<ul id="primary-nav" class="nav-links">
|
||
<li><a href="#about">À propos</a></li>
|
||
<li><a href="#stack">Stack</a></li>
|
||
<li><a href="#experience">Parcours</a></li>
|
||
<li><a href="#projets">Projets</a></li>
|
||
<li><a href="#formation">Formation</a></li>
|
||
<li><a href="#methode">Méthode</a></li>
|
||
<li><a href="#contact">Contact</a></li>
|
||
</ul>
|
||
</nav>
|
||
</div>
|
||
</header>
|
||
|
||
<main>
|
||
|
||
<!-- HERO -->
|
||
<section id="hero" class="hero" aria-labelledby="hero-name">
|
||
<div class="hero-inner">
|
||
<p class="hero-eyebrow reveal">Disponible — CDI systèmes / embarqué · missions freelance</p>
|
||
<h1 id="hero-name" class="hero-name reveal d1">Bastien <em>Chanot</em></h1>
|
||
<p class="hero-title reveal d2">Développeur Systèmes<span class="sep">·</span>Embarqué<span class="sep">·</span>Backend</p>
|
||
<p class="hero-tagline reveal d3">Du kernel Linux au backend Rust — 7 ans de développement systèmes en production.</p>
|
||
<div class="hero-cta reveal d4">
|
||
<a class="btn btn-primary" href="#contact">
|
||
Me contacter
|
||
<svg class="arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="19" x2="19" y2="5"/><polyline points="8 5 19 5 19 16"/></svg>
|
||
</a>
|
||
<a class="btn btn-secondary" href="CV_Bastien_Chanot.html">
|
||
Voir le CV
|
||
<svg class="arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="19" x2="19" y2="5"/><polyline points="8 5 19 5 19 16"/></svg>
|
||
</a>
|
||
<a class="btn btn-secondary" href="CV_Bastien_Chanot.pdf" download>
|
||
Télécharger PDF
|
||
<svg class="arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
|
||
</a>
|
||
</div>
|
||
<div class="hero-meta reveal d5">
|
||
<span><span class="dot"></span>C · Rust · Linux Kernel</span>
|
||
<span><span class="dot"></span>AOSP · Embarqué</span>
|
||
<span><span class="dot"></span>Backend · Cloud</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ABOUT -->
|
||
<section id="about" class="about section-dark" aria-labelledby="about-title">
|
||
<div class="container">
|
||
<span class="section-label">À propos</span>
|
||
<h2 id="about-title" class="section-title">Sept ans à écrire du code qui tourne là où ça compte.</h2>
|
||
<div class="about-grid">
|
||
<div class="about-text">
|
||
<p>Je suis développeur systèmes senior, formé à l'<strong>École 42</strong> et passé par six ans chez <strong>CareGame</strong> où j'ai écrit des drivers Linux kernel, un backend Rust temps réel et fait tourner des serveurs GPU bare-metal en production.</p>
|
||
<p>Mon terrain de jeu : <strong>C, Rust, Linux kernel, AOSP, embarqué, infrastructure</strong>. Quand un problème touche au bas niveau — port matériel, latence, sécurité, kernel — c'est là que j'apporte le plus de valeur.</p>
|
||
<p>Ce qui m'intéresse, c'est descendre jusqu'à ce qu'il n'y ait plus de magie — <strong>kernel, hardware, drivers</strong>. Là, soit ça marche, soit ça ne marche pas.</p>
|
||
<p>C'est ce confort-là que je cherche dans une équipe : <strong>systèmes, embarqué, backend bas niveau</strong>, sur une stack dont on peut lire le code source. Pas envie d'aller vers le buzzword-driven — microservices à tout prix, framework du mois, archi conçue pour le pitch deck.</p>
|
||
<p>Aujourd'hui indépendant sous la marque <strong>ZenQuality</strong>, mais avant tout en recherche d'un <strong>CDI en systèmes embarqués ou logiciel</strong> — les missions freelance se font en parallèle.</p>
|
||
<p>Côté présence : <strong>full remote</strong> idéalement, ou <strong>hybride 1 à 2 jours par mois</strong> si l'équipe est à Paris. Mobilité visée à moyen terme : <strong>Pays de la Loire</strong>.</p>
|
||
</div>
|
||
<dl class="about-callout">
|
||
<dt>Recherche prioritaire</dt>
|
||
<dd>CDI systèmes embarqués / logiciel</dd>
|
||
<dt>En parallèle</dt>
|
||
<dd>Missions freelance · ZenQuality</dd>
|
||
<dt>Localisation actuelle</dt>
|
||
<dd>Yerres (91) · mobilité Pays de la Loire</dd>
|
||
<dt>Présence</dt>
|
||
<dd>Full remote · ou 1–2 j/mois si Paris</dd>
|
||
<dt>Site pro</dt>
|
||
<dd><a href="https://zenquality.fr" target="_blank" rel="noopener">zenquality.fr ↗</a></dd>
|
||
</dl>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- STACK -->
|
||
<section id="stack" class="stack" aria-labelledby="stack-title">
|
||
<div class="container">
|
||
<span class="section-label">Stack technique</span>
|
||
<h2 id="stack-title" class="section-title">Ce avec quoi je travaille, sans le marketing.</h2>
|
||
<p class="section-intro">Outils éprouvés, choisis pour leurs garanties — pas pour leur hype. Tout ce qui suit est en production ou l'a été.</p>
|
||
<div class="stack-grid">
|
||
|
||
<article class="stack-card">
|
||
<header class="stack-card-head">
|
||
<h3>Langages</h3>
|
||
<span class="stack-card-tag">// 01</span>
|
||
</header>
|
||
<ul class="pills">
|
||
<li class="pill">C</li>
|
||
<li class="pill">Rust</li>
|
||
<li class="pill">Bash</li>
|
||
<li class="pill">Python</li>
|
||
<li class="pill">Java<span class="pill-context">(AOSP/Android)</span></li>
|
||
</ul>
|
||
<p class="stack-note">Familier avec : <code>C++</code></p>
|
||
</article>
|
||
|
||
<article class="stack-card">
|
||
<header class="stack-card-head">
|
||
<h3>Embarqué</h3>
|
||
<span class="stack-card-tag">// 02</span>
|
||
</header>
|
||
<ul class="pills">
|
||
<li class="pill">Linux kernel drivers</li>
|
||
<li class="pill">AOSP</li>
|
||
<li class="pill">ARM / x86</li>
|
||
<li class="pill">GPIO</li>
|
||
<li class="pill">NFC</li>
|
||
<li class="pill">ESC/POS</li>
|
||
<li class="pill">cross-compilation GCC</li>
|
||
</ul>
|
||
</article>
|
||
|
||
<article class="stack-card">
|
||
<header class="stack-card-head">
|
||
<h3>Conteneurs</h3>
|
||
<span class="stack-card-tag">// 03</span>
|
||
</header>
|
||
<ul class="pills">
|
||
<li class="pill">Docker</li>
|
||
<li class="pill">LXC / LXD</li>
|
||
<li class="pill">QEMU</li>
|
||
<li class="pill">cgroups</li>
|
||
<li class="pill">namespaces</li>
|
||
</ul>
|
||
</article>
|
||
|
||
<article class="stack-card">
|
||
<header class="stack-card-head">
|
||
<h3>Backend</h3>
|
||
<span class="stack-card-tag">// 04</span>
|
||
</header>
|
||
<ul class="pills">
|
||
<li class="pill">Rust</li>
|
||
<li class="pill">WebSocket</li>
|
||
<li class="pill">GPU bare-metal</li>
|
||
<li class="pill">ramdisk I/O</li>
|
||
</ul>
|
||
</article>
|
||
|
||
<article class="stack-card">
|
||
<header class="stack-card-head">
|
||
<h3>Systèmes</h3>
|
||
<span class="stack-card-tag">// 05</span>
|
||
</header>
|
||
<ul class="pills">
|
||
<li class="pill">Linux bare-metal</li>
|
||
<li class="pill">AOSP</li>
|
||
<li class="pill">Android Backup</li>
|
||
<li class="pill">systemd</li>
|
||
<li class="pill">SELinux</li>
|
||
</ul>
|
||
</article>
|
||
|
||
<article class="stack-card">
|
||
<header class="stack-card-head">
|
||
<h3>Cloud / Infra</h3>
|
||
<span class="stack-card-tag">// 06</span>
|
||
</header>
|
||
<ul class="pills">
|
||
<li class="pill">AWS EC2</li>
|
||
<li class="pill">AWS g4dn bare-metal</li>
|
||
<li class="pill">IAM</li>
|
||
<li class="pill">S3</li>
|
||
<li class="pill">CloudWatch</li>
|
||
<li class="pill">Scaleway VPS</li>
|
||
<li class="pill">OVH / Hetzner</li>
|
||
<li class="pill">Nginx</li>
|
||
<li class="pill">Apache</li>
|
||
<li class="pill">Let's Encrypt</li>
|
||
</ul>
|
||
</article>
|
||
|
||
<article class="stack-card">
|
||
<header class="stack-card-head">
|
||
<h3>DevOps</h3>
|
||
<span class="stack-card-tag">// 07</span>
|
||
</header>
|
||
<ul class="pills">
|
||
<li class="pill">Git</li>
|
||
<li class="pill">GitHub Actions</li>
|
||
<li class="pill">GitLab</li>
|
||
<li class="pill">CI/CD</li>
|
||
</ul>
|
||
</article>
|
||
|
||
<article class="stack-card">
|
||
<header class="stack-card-head">
|
||
<h3>IA / Outils</h3>
|
||
<span class="stack-card-tag">// 08</span>
|
||
</header>
|
||
<ul class="pills">
|
||
<li class="pill">Claude Code (agents/skills custom)</li>
|
||
<li class="pill">N8N</li>
|
||
<li class="pill">automatisation</li>
|
||
</ul>
|
||
</article>
|
||
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- EXPERIENCE -->
|
||
<section id="experience" class="experience" aria-labelledby="experience-title">
|
||
<div class="container">
|
||
<span class="section-label">Parcours</span>
|
||
<h2 id="experience-title" class="section-title">Trois expériences qui résument l'essentiel.</h2>
|
||
<p class="section-intro">Sept ans de développement systèmes en production — du kernel au backend, de la puce au serveur.</p>
|
||
|
||
<ol class="timeline">
|
||
|
||
<li class="timeline-item current">
|
||
<div class="timeline-meta">
|
||
<span class="period">avr. 2026 — présent</span>
|
||
<span class="badge">En cours</span>
|
||
<span>Yerres · Full remote</span>
|
||
</div>
|
||
<h3><a href="https://zenquality.fr" target="_blank" rel="noopener">ZenQuality</a></h3>
|
||
<p class="timeline-role">Développeur indépendant · Systèmes & Backend</p>
|
||
<p class="timeline-intro">Indépendant systèmes / embarqué / backend. En recherche prioritaire d'un CDI en parallèle.</p>
|
||
<ul class="timeline-bullets">
|
||
<li>Mission SEO et conformité légale RGPD pour PME service (Île-de-France) — audit technique Core Web Vitals + Schema.org + NAP, refonte CGV B2B/B2C, RGPD, mentions légales, médiateur CM2C. Plan d'action 12 sprints.</li>
|
||
<li>Site vitrine WordPress (Gutenverse) pour PME esthétique — conception, intégration, déploiement et support continu (hébergement client).</li>
|
||
<li>Setup et auto-hébergement de l'infra ZenQuality sur VPS Scaleway — stack Astro / React / PHP 8 / PostgreSQL conteneurisée Docker, déploiement automatisé, pipeline de production complet.</li>
|
||
</ul>
|
||
<ul class="pills timeline-stack">
|
||
<li class="pill">Astro</li>
|
||
<li class="pill">React</li>
|
||
<li class="pill">PHP 8</li>
|
||
<li class="pill">PostgreSQL</li>
|
||
<li class="pill">Docker</li>
|
||
<li class="pill">Scaleway VPS</li>
|
||
<li class="pill">WordPress / Gutenverse</li>
|
||
<li class="pill">SEO</li>
|
||
<li class="pill">RGPD</li>
|
||
</ul>
|
||
</li>
|
||
|
||
<li class="timeline-item">
|
||
<div class="timeline-meta">
|
||
<span class="period">mars 2019 — mars 2025</span>
|
||
<span>Paris · Full remote dès 2020</span>
|
||
</div>
|
||
<h3>CareGame</h3>
|
||
<p class="timeline-role">Développeur logiciel · Systèmes & Backend</p>
|
||
<p class="timeline-intro">Plateforme de cloud gaming en production : fleet GPU bare-metal AWS g4dn, conteneurs AOSP, backend Rust temps réel. Plusieurs centaines de joueurs servis simultanément.</p>
|
||
<ul class="timeline-bullets">
|
||
<li>Conception et maintenance de modules kernel Linux en C (x86 / ARM) — drivers d'interface hôte / conteneur (Linux → AOSP), en interface avec les équipes infra et produit.</li>
|
||
<li>Conception de l'isolation CPU/GPU par session — adaptation de modules GPU Nvidia, partitionnement 2 cœurs/session, sérialisation des accès concurrents sur zones GPU partagées. Résultat : 32 sessions AAA stables par serveur.</li>
|
||
<li>Co-développement du backend Rust orchestrant le cycle de vie des conteneurs AOSP — WebSocket temps réel clients ↔ instances, intégration Docker + LXC, scheduling des sessions sur la fleet GPU.</li>
|
||
<li>Développement de virtual input devices AOSP en Java (touchscreen, gamepad) — pipeline complet inputs frontend → backend Rust → drivers hôtes → injection AOSP, optimisé latence temps réel gameplay AAA.</li>
|
||
<li>Architecture et exploitation de fleet GPU bare-metal AWS g4dn.metal (8× GPU T4, 64 vCPU, ~20 serveurs en pic) — isolation 2 cœurs CPU/session, ramdisk I/O, 32 sessions AAA simultanées/serveur. Plusieurs centaines de joueurs servis en parallèle (Asphalt 9 : 3 sessions/T4).</li>
|
||
<li>Reprise et hardening d'un PoC LXD + Docker issu d'une R&D Nvidia (intégration côté Docker principalement) — adaptation production cloud gaming, débogage kernel/conteneur, performance validée par les équipes Nvidia comme dépassant le scope initial du PoC.</li>
|
||
<li>Collaboration technique directe en anglais avec Canonical (Anbox + builds LXC/LXD non commerciaux, remontée bugs et feature requests) et Ampere Computing (intégration et benchmark de serveurs ARM pré-commerciaux pour évaluation de migration de fleet).</li>
|
||
<li>Pipeline d'installation automatique de jeux AOSP et persistance des sauvegardes utilisateur — fusion Android Backup natif + scripts custom pour cas non gérés nativement (DRM, données externes).</li>
|
||
<li>Développement d'un outil d'orchestration Bash modulaire (1000+ lignes) — parsing avancé arguments Docker, préparation et lancement automatisé conteneurs AOSP, brique appelée par la CI et le backend Rust.</li>
|
||
</ul>
|
||
<ul class="pills timeline-stack">
|
||
<li class="pill">C</li>
|
||
<li class="pill">Rust</li>
|
||
<li class="pill">Java</li>
|
||
<li class="pill">Bash</li>
|
||
<li class="pill">Linux kernel</li>
|
||
<li class="pill">AOSP</li>
|
||
<li class="pill">Docker</li>
|
||
<li class="pill">LXC / LXD</li>
|
||
<li class="pill">AWS g4dn.metal</li>
|
||
<li class="pill">WebSocket</li>
|
||
<li class="pill">Nvidia GPU T4</li>
|
||
</ul>
|
||
</li>
|
||
|
||
<li class="timeline-item">
|
||
<div class="timeline-meta">
|
||
<span class="period">fév. 2017 — nov. 2017</span>
|
||
<span>Ivry-sur-Seine</span>
|
||
</div>
|
||
<h3>Deewee</h3>
|
||
<p class="timeline-role">Développeur C · Système embarqué</p>
|
||
<p class="timeline-contract">Stage 42 (6 mois) puis CDD (4 mois)</p>
|
||
<p class="timeline-intro">Boîtier connecté pour interception du flux d'une imprimante thermique.</p>
|
||
<ul class="timeline-bullets">
|
||
<li>Développement du logiciel embarqué en C pour boîtier connecté basé Orange Pi (Debian ARM) — interception du flux ESC/POS d'une imprimante thermique, génération PNG du ticket, transfert WiFi direct vers application mobile à la connexion.</li>
|
||
<li>Intégration matérielle : GPIO physique (bouton + timeout), hotspot WiFi embarqué avec diffusion des credentials via NFC pour appairage automatique.</li>
|
||
</ul>
|
||
<ul class="pills timeline-stack">
|
||
<li class="pill">C</li>
|
||
<li class="pill">Debian ARM</li>
|
||
<li class="pill">Orange Pi</li>
|
||
<li class="pill">ESC/POS</li>
|
||
<li class="pill">GPIO</li>
|
||
<li class="pill">NFC</li>
|
||
<li class="pill">WiFi</li>
|
||
</ul>
|
||
</li>
|
||
|
||
</ol>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- PROJETS -->
|
||
<section id="projets" class="projets" aria-labelledby="projets-title">
|
||
<div class="container">
|
||
<span class="section-label">Projets</span>
|
||
<h2 id="projets-title" class="section-title">Ce que je fais à côté.</h2>
|
||
<p class="section-intro">Infra perso et code public — l'environnement où je teste, casse, documente, et reprends.</p>
|
||
|
||
<div class="projects-grid">
|
||
|
||
<article class="project-card">
|
||
<header class="project-card-head">
|
||
<h3>Code source & projets persos</h3>
|
||
<span class="project-card-tag">en continu</span>
|
||
</header>
|
||
<p class="project-tagline">Serveur Git auto-hébergé en production.</p>
|
||
<p class="project-desc">Configuration Claude Code, dotfiles, projets bas-niveau (42, expérimentations C/Rust) — accessibles publiquement. Mirror automatique vers GitHub via push hook.</p>
|
||
<a class="project-link" href="https://git.bchanot.fr/bchanot" target="_blank" rel="noopener">git.bchanot.fr/bchanot ↗</a>
|
||
</article>
|
||
|
||
<article class="project-card">
|
||
<header class="project-card-head">
|
||
<h3>Homelab</h3>
|
||
<span class="project-card-tag">en continu</span>
|
||
</header>
|
||
<p class="project-tagline">Infrastructure personnelle.</p>
|
||
<p class="project-desc">Auto-hébergement Git (Gogs) / DNS / VPN / SMB — NAS Asustor, Freebox WireGuard VPN site-to-site, Pi-hole, segmentation réseau, hardening fail2ban, gocryptfs sur dossiers sensibles.</p>
|
||
</article>
|
||
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- FORMATION -->
|
||
<section id="formation" class="formation" aria-labelledby="formation-title">
|
||
<div class="container">
|
||
<span class="section-label">Formation</span>
|
||
<h2 id="formation-title" class="section-title">Deux écoles, un fil rouge : le bas niveau.</h2>
|
||
<p class="section-intro">Le socle technique derrière sept ans de production.</p>
|
||
|
||
<ol class="timeline">
|
||
|
||
<li class="timeline-item">
|
||
<div class="timeline-meta">
|
||
<span class="period">2015 — 2019</span>
|
||
<span>Clichy</span>
|
||
</div>
|
||
<h3>École 42</h3>
|
||
<p class="timeline-role">Cursus en informatique fondamentale</p>
|
||
<p class="formation-school-desc">Kernel, mémoire, shell, sécurité — recoder pour comprendre.</p>
|
||
|
||
<div class="formation-themes">
|
||
|
||
<article class="theme-card">
|
||
<header class="theme-card-head">
|
||
<h4>Systèmes & Kernel</h4>
|
||
<span class="theme-card-tag">// 01</span>
|
||
</header>
|
||
<p class="theme-quote">Bootstrap d'OS, drivers, gestion matérielle, allocation mémoire.</p>
|
||
<ul class="theme-list">
|
||
<li><code>ft_linux</code> & <code>kfs-1</code> — Linux From Scratch et noyau minimaliste : bootloader ASM, GDT, interruptions, driver char device clavier mappé.</li>
|
||
<li><code>drivers & interrupt</code> — drivers kernel Linux et gestion d'interruptions niveau noyau.</li>
|
||
<li><code>process & memory</code> — modèle de processus Unix, gestion mémoire kernel.</li>
|
||
<li><code>little penguin</code> — contribution kernel Linux : style guide, patch submission, contrib upstream.</li>
|
||
<li><code>malloc</code> — allocateur mémoire complet (libft_malloc.so) avec mmap, zones tiny / small / large.</li>
|
||
</ul>
|
||
</article>
|
||
|
||
<article class="theme-card">
|
||
<header class="theme-card-head">
|
||
<h4>Bas niveau & Outils système</h4>
|
||
<span class="theme-card-tag">// 02</span>
|
||
</header>
|
||
<p class="theme-quote">Recoder les outils qu'on utilise tous les jours pour comprendre vraiment ce qu'ils font.</p>
|
||
<ul class="theme-list">
|
||
<li><code>nm</code> — parsing d'exécutables ELF, tables de symboles.</li>
|
||
<li><code>42sh</code> / <code>21</code> — shell POSIX complet : parser, redirections, jobs, history, autocomplétion.</li>
|
||
<li><code>ft_ls</code> — réimplémentation <code>ls</code> avec options POSIX, permissions, tri, formats.</li>
|
||
<li><code>ft_select</code> — TUI custom avec gestion termios, signaux, redessin partiel.</li>
|
||
</ul>
|
||
</article>
|
||
|
||
<article class="theme-card">
|
||
<header class="theme-card-head">
|
||
<h4>Sécurité & Algorithmie</h4>
|
||
<span class="theme-card-tag">// 03</span>
|
||
</header>
|
||
<p class="theme-quote">Comprendre comment un système peut être cassé pour savoir le sécuriser.</p>
|
||
<ul class="theme-list">
|
||
<li><code>snow crash</code> — wargame exploitation système : escalation de privilèges, stack overflow, format string, race conditions.</li>
|
||
<li><code>doctor quine</code> — programme auto-réplicatif (métaprogrammation).</li>
|
||
<li><code>ft_ssl_md5</code> — réimplémentation MD5, SHA-256, base64.</li>
|
||
<li><code>lem-in</code>, <code>push-swap</code> — algorithmique : pathfinding (Edmonds-Karp), optimisation de tri sous contrainte.</li>
|
||
</ul>
|
||
</article>
|
||
|
||
</div>
|
||
</li>
|
||
|
||
<li class="timeline-item">
|
||
<div class="timeline-meta">
|
||
<span class="period">2013 — 2015</span>
|
||
<span>Vincennes</span>
|
||
</div>
|
||
<h3>TSRIT — Next Formation</h3>
|
||
<p class="timeline-role">BTS Technicien Supérieur Réseaux Informatiques & Télécoms</p>
|
||
<span class="honors">Félicitations du jury</span>
|
||
<p class="timeline-desc">Le socle réseau et infrastructure derrière les compétences systèmes.</p>
|
||
<ul class="formation-tsrit-list">
|
||
<li>Architecture réseau (<strong>OSI</strong>, <strong>TCP/IP</strong>), routage, commutation.</li>
|
||
<li>Administration <strong>Linux</strong> / <strong>Windows Server</strong>, sécurité réseau, virtualisation.</li>
|
||
</ul>
|
||
</li>
|
||
|
||
</ol>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- MÉTHODE -->
|
||
<section id="methode" class="methode" aria-labelledby="methode-title">
|
||
<div class="container">
|
||
<span class="section-label">Méthode</span>
|
||
<h2 id="methode-title" class="section-title">Façon de travailler.</h2>
|
||
<p class="section-intro">Cinq habitudes héritées de sept ans en prod — pas un manifeste, des réflexes.</p>
|
||
|
||
<ol class="methode-list">
|
||
|
||
<li class="methode-item">
|
||
<span class="methode-num">01</span>
|
||
<div class="methode-body">
|
||
<h3>Comprendre avant d'écrire.</h3>
|
||
<p>Si je n'arrive pas à expliquer comment un système se comporte, je ne touche pas au code.</p>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="methode-item">
|
||
<span class="methode-num">02</span>
|
||
<div class="methode-body">
|
||
<h3>Solutions éprouvées > hype.</h3>
|
||
<p>Choix techniques défendus sur leurs garanties (perf, lisibilité, maintenabilité), pas sur leur buzz.</p>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="methode-item">
|
||
<span class="methode-num">03</span>
|
||
<div class="methode-body">
|
||
<h3>Autonome sur la décomposition technique.</h3>
|
||
<p>En interface directe avec les équipes produit, infra et stakeholders externes quand ça compte.</p>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="methode-item">
|
||
<span class="methode-num">04</span>
|
||
<div class="methode-body">
|
||
<h3>Trace écrite par défaut.</h3>
|
||
<p>Décisions, post-mortems, docs internes. Le code qui n'est pas documenté est un code qui sera réécrit dans 6 mois.</p>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="methode-item">
|
||
<span class="methode-num">05</span>
|
||
<div class="methode-body">
|
||
<h3>Anglais ou français.</h3>
|
||
<p>Communication aussi bien en anglais (Nvidia, Canonical, Ampere) qu'en français — peu importe, je m'adapte à l'équipe.</p>
|
||
</div>
|
||
</li>
|
||
|
||
</ol>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- CONTACT -->
|
||
<section id="contact" class="contact section-dark" aria-labelledby="contact-title">
|
||
<div class="container">
|
||
<span class="section-label">Contact</span>
|
||
<h2 id="contact-title" class="section-title">Une mission, une question technique, un projet ?</h2>
|
||
<p class="section-intro">Le plus simple : l'email. Réponse sous 48 h ouvrées.</p>
|
||
|
||
<div class="contact-grid">
|
||
<ul class="contact-list">
|
||
|
||
<li>
|
||
<a class="contact-row" href="mailto:bastien@bchanot.fr">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2"/><polyline points="3 7 12 13 21 7"/></svg>
|
||
<span>
|
||
<span class="label">Email</span>
|
||
<span class="value">bastien@bchanot.fr</span>
|
||
</span>
|
||
</a>
|
||
</li>
|
||
|
||
<li>
|
||
<a class="contact-row" href="tel:+33778822297">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.86 19.86 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6A19.86 19.86 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.37 1.9.72 2.8a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.9.35 1.84.59 2.8.72A2 2 0 0 1 22 16.92z"/></svg>
|
||
<span>
|
||
<span class="label">Téléphone</span>
|
||
<span class="value">+33 7 78 82 22 97</span>
|
||
</span>
|
||
</a>
|
||
</li>
|
||
|
||
<li>
|
||
<a class="contact-row" href="https://zenquality.fr" target="_blank" rel="noopener">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
|
||
<span>
|
||
<span class="label">Site pro</span>
|
||
<span class="value">zenquality.fr</span>
|
||
</span>
|
||
</a>
|
||
</li>
|
||
|
||
<li>
|
||
<a class="contact-row" href="CV_Bastien_Chanot.pdf" download>
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
|
||
<span>
|
||
<span class="label">CV</span>
|
||
<span class="value">Télécharger le PDF</span>
|
||
</span>
|
||
</a>
|
||
</li>
|
||
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
</main>
|
||
|
||
<!-- FOOTER -->
|
||
<footer class="footer" role="contentinfo">
|
||
<div class="footer-inner">
|
||
<span>© 2026 · Bastien Chanot · bchanot.fr</span>
|
||
<div class="footer-links">
|
||
<a href="CV_Bastien_Chanot.html">CV (HTML)</a>
|
||
<a href="CV_Bastien_Chanot.pdf" download>CV (PDF)</a>
|
||
<a href="https://zenquality.fr" target="_blank" rel="noopener">zenquality.fr ↗</a>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
|
||
<script>
|
||
// Mobile nav toggle
|
||
(function () {
|
||
const toggle = document.querySelector('.nav-toggle');
|
||
const links = document.getElementById('primary-nav');
|
||
if (!toggle || !links) return;
|
||
|
||
toggle.addEventListener('click', () => {
|
||
const open = links.classList.toggle('open');
|
||
toggle.setAttribute('aria-expanded', String(open));
|
||
toggle.setAttribute('aria-label', open ? 'Fermer le menu' : 'Ouvrir le menu');
|
||
});
|
||
|
||
links.addEventListener('click', (e) => {
|
||
if (e.target instanceof HTMLAnchorElement && links.classList.contains('open')) {
|
||
links.classList.remove('open');
|
||
toggle.setAttribute('aria-expanded', 'false');
|
||
toggle.setAttribute('aria-label', 'Ouvrir le menu');
|
||
}
|
||
});
|
||
})();
|
||
|
||
// Active section highlight in nav (subtle — color shift only)
|
||
(function () {
|
||
const sections = document.querySelectorAll('main section[id]');
|
||
const navLinks = document.querySelectorAll('.nav-links a[href^="#"]');
|
||
if (!('IntersectionObserver' in window) || !sections.length) return;
|
||
|
||
const map = new Map();
|
||
navLinks.forEach(a => {
|
||
const id = a.getAttribute('href').slice(1);
|
||
map.set(id, a);
|
||
});
|
||
|
||
const io = new IntersectionObserver((entries) => {
|
||
entries.forEach(entry => {
|
||
const link = map.get(entry.target.id);
|
||
if (!link) return;
|
||
if (entry.isIntersecting) {
|
||
navLinks.forEach(a => a.style.color = '');
|
||
link.style.color = 'var(--g100)';
|
||
}
|
||
});
|
||
}, { rootMargin: '-40% 0px -55% 0px', threshold: 0 });
|
||
|
||
sections.forEach(s => io.observe(s));
|
||
})();
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|