Compare commits

..

20 Commits

Author SHA1 Message Date
Julien Calixte
dec3359ddf feat: max width so it's not too wide 2026-03-20 23:47:31 +01:00
Julien Calixte
6b0711f19a chore: fix nixpacks 2026-03-19 21:30:25 +01:00
Julien Calixte
75765b5299 chore: fix nixpacks 2026-03-19 21:29:55 +01:00
Julien Calixte
3d87e5822b chore: fix nixpacks 2026-03-19 21:28:08 +01:00
Julien Calixte
d56ad61751 fix: delay 2026-03-19 21:27:08 +01:00
Julien Calixte
f768a97491 fix: serve dist folder as static site
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 21:25:24 +01:00
Julien Calixte
b5a1ca62ea fix: remove redundant nodejs_24 nix package
NIXPACKS_NODE_VERSION already handles Node.js version selection.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 21:23:12 +01:00
Julien Calixte
babe6e84b0 chore: init nixpacks 2026-03-19 21:18:03 +01:00
Julien Calixte
40984d5fd1 fix deps 2026-03-19 21:16:00 +01:00
Julien Calixte
3c21579905 test 2026-03-19 21:13:03 +01:00
Julien Calixte
07a4953504 feat: change topics and fix image in Firefox 2026-02-21 21:52:02 +01:00
Julien Calixte
aa9e068adc feat: wip 2026-02-21 21:46:28 +01:00
Julien Calixte
08dd330fc3 fix: remove warning 2026-02-02 16:10:29 +01:00
Julien Calixte
d0e5a07d3b deps: upgrade deps 2026-02-02 15:25:17 +01:00
Julien Calixte
4ed8516259 design: change primary color for change 2026-01-24 23:20:37 +01:00
Julien Calixte
efc6655afd feat: init cash flow 2026-01-03 20:49:10 +01:00
Julien Calixte
df83fb5a29 design: lower title size 2026-01-03 20:48:58 +01:00
Julien Calixte
95a17c9820 article: add some planification paraphraph 2026-01-03 20:24:04 +01:00
Julien Calixte
70581f00d9 feat: add better colors 2026-01-03 20:22:19 +01:00
Julien Calixte
1accacdac1 refacto: remove planning state 2026-01-03 11:23:51 +01:00
11 changed files with 173 additions and 59 deletions

View File

@@ -1,7 +1,7 @@
@import url('https://fonts.googleapis.com/css2?family=Noto+Serif&family=Cutive+Mono&display=swap');
:root {
--primary-color: #002992;
--primary-color: #30394a;
--primary-color-no-focus: #abbbdf;
--color: white;
--font-size: 28px;
@@ -19,7 +19,7 @@
}
body {
font-size: 28px;
font-size: 22px;
font-family: 'Noto Serif', serif;
margin: 0;
}

View File

@@ -2,6 +2,11 @@ body {
font-size: clamp(var(--min-font-size, 11px), 2.1vw, var(--font-size, 28px));
}
#thinking-people-system {
max-width: 1400px;
margin: auto;
}
ul {
padding-left: 0;
margin: 0;
@@ -64,6 +69,10 @@ li {
font-size: clamp(var(--min-font-size, 11px), 2.1vw, var(--font-size, 28px));
}
.customer-satisfaction h2 {
display: block;
}
.customer-satisfaction h2,
.customer-satisfaction p {
margin: 0;

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
@@ -24,8 +24,8 @@
<section class="customer-satisfaction focusable">
<h2 class="customer-satisfaction-title">Customer Satisfaction</h2>
<p class="value-analysis-value-engineering">
<span class="use-value">Use</span> Value analysis /
<span class="use-value">Use</span> Value engineering
<span class="use-value">Use</span> Value Analysis /
<span class="use-value">Use</span> Value Engineering
</p>
</section>
</div>
@@ -40,12 +40,12 @@
</section>
<section class="pilars">
<section class="just-in-time-pilar">
<h3 class="just-in-time focusable">Just-in-time</h3>
<h3 class="just-in-time focusable">Just-in-Time</h3>
<ul>
<li class="takt-time takt focusable">Takt time</li>
<li class="one-piece-flow focusable">One piece flow</li>
<li class="takt-time takt focusable">Takt Time</li>
<li class="one-piece-flow focusable">One Piece Flow</li>
<li class="pull-system focusable">
<a href="/pull-system">Pull system</a>
<a href="/pull-system">Pull System</a>
</li>
</ul>
</section>
@@ -99,8 +99,8 @@
<h3 class="jidoka focusable">Jidoka</h3>
<ul>
<li class="andon focusable">Andon</li>
<li class="poka-yoke focusable">Poka yoke</li>
<li class="human-machine focusable">Human / machine</li>
<li class="poka-yoke focusable">Poka Yoke</li>
<li class="human-machine focusable">Human / Machine</li>
</ul>
</section>
</section>
@@ -111,7 +111,9 @@
<!-- <a href="/heijunka">Heijunka</a> -->
Heijunka
</li>
<li class="standards focusable">Standards</li>
<li class="standards standardized-work focusable">
Standardized Work
</li>
<li class="kaizen focusable">Kaizen</li>
</ul>
</section>
@@ -121,7 +123,7 @@
<!-- <a href="/5s">5S</a> -->
5S
</li>
<li class="problem-solving focusable">Problem solving</li>
<li class="problem-solving focusable">Problem Solving</li>
<li class="tpm focusable">TPM</li>
</ul>
</section>

View File

@@ -13,7 +13,7 @@ const focusList = document.querySelector('#focus-list')
if (focusList) {
focusables.forEach((focusable, index) => {
const a = document.createElement('a')
a.textContent = [...focusable.classList]
a.textContent = Array.from(focusable.classList)
.filter((c) => c !== 'focusable')
.join(' ')
a.href = `?focus=${a.textContent}`
@@ -103,6 +103,7 @@ const screenshotHouseButton = document.querySelector('#screenshot-house')
if (screenshotHouseButton) {
screenshotHouseButton.addEventListener('click', async () => {
const house = document.querySelector('#thinking-people-system')
if (!house) {
return
}

5
nixpacks.toml Normal file
View File

@@ -0,0 +1,5 @@
[variables]
NIXPACKS_NODE_VERSION = "24"
[phases.setup]
nixPkgs = ["nodejs_24", "pnpm"]

View File

@@ -22,7 +22,7 @@
"comlink": "^4.4.2",
"daisyui": "^5.0.50",
"hex-color-regex": "^1.1.0",
"modern-screenshot": "^4.5.5",
"modern-screenshot": "^4.6.8",
"pinia": "^2.3.1",
"random-js": "^2.1.0",
"tailwindcss": "^4.1.11",

44
pnpm-lock.yaml generated
View File

@@ -30,8 +30,8 @@ importers:
specifier: ^1.1.0
version: 1.1.0
modern-screenshot:
specifier: ^4.5.5
version: 4.5.5
specifier: ^4.6.8
version: 4.6.8
pinia:
specifier: ^2.3.1
version: 2.3.1(typescript@5.7.2)(vue@3.5.13(typescript@5.7.2))
@@ -446,36 +446,42 @@ packages:
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.1':
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.1':
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.1':
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.1':
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.1':
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
'@parcel/watcher-win32-arm64@2.5.1':
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
@@ -563,101 +569,121 @@ packages:
resolution: {integrity: sha512-0O8ViX+QcBd3ZmGlcFTnYXZKGbFu09EhgD27tgTdGnkcYXLat4KIsBBQeKLR2xZDCXdIBAlWLkiXE1+rJpCxFw==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-gnueabihf@4.34.6':
resolution: {integrity: sha512-88fSzjC5xeH9S2Vg3rPgXJULkHcLYMkh8faix8DX4h4TIAL65ekwuQMA/g2CXq8W+NJC43V6fUpYZNjaX3+IIg==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.31.0':
resolution: {integrity: sha512-w5IzG0wTVv7B0/SwDnMYmbr2uERQp999q8FMkKG1I+j8hpPX2BYFjWe69xbhbP6J9h2gId/7ogesl9hwblFwwg==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm-musleabihf@4.34.6':
resolution: {integrity: sha512-wM4ztnutBqYFyvNeR7Av+reWI/enK9tDOTKNF+6Kk2Q96k9bwhDDOlnCUNRPvromlVXo04riSliMBs/Z7RteEg==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.31.0':
resolution: {integrity: sha512-JyFFshbN5xwy6fulZ8B/8qOqENRmDdEkcIMF0Zz+RsfamEW+Zabl5jAb0IozP/8UKnJ7g2FtZZPEUIAlUSX8cA==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-gnu@4.34.6':
resolution: {integrity: sha512-9RyprECbRa9zEjXLtvvshhw4CMrRa3K+0wcp3KME0zmBe1ILmvcVHnypZ/aIDXpRyfhSYSuN4EPdCCj5Du8FIA==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.31.0':
resolution: {integrity: sha512-kpQXQ0UPFeMPmPYksiBL9WS/BDiQEjRGMfklVIsA0Sng347H8W2iexch+IEwaR7OVSKtr2ZFxggt11zVIlZ25g==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-musl@4.34.6':
resolution: {integrity: sha512-qTmklhCTyaJSB05S+iSovfo++EwnIEZxHkzv5dep4qoszUMX5Ca4WM4zAVUMbfdviLgCSQOu5oU8YoGk1s6M9Q==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-loongarch64-gnu@4.31.0':
resolution: {integrity: sha512-pMlxLjt60iQTzt9iBb3jZphFIl55a70wexvo8p+vVFK+7ifTRookdoXX3bOsRdmfD+OKnMozKO6XM4zR0sHRrQ==}
cpu: [loong64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-loongarch64-gnu@4.34.6':
resolution: {integrity: sha512-4Qmkaps9yqmpjY5pvpkfOerYgKNUGzQpFxV6rnS7c/JfYbDSU0y6WpbbredB5cCpLFGJEqYX40WUmxMkwhWCjw==}
cpu: [loong64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-powerpc64le-gnu@4.31.0':
resolution: {integrity: sha512-D7TXT7I/uKEuWiRkEFbed1UUYZwcJDU4vZQdPTcepK7ecPhzKOYk4Er2YR4uHKme4qDeIh6N3XrLfpuM7vzRWQ==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-powerpc64le-gnu@4.34.6':
resolution: {integrity: sha512-Zsrtux3PuaxuBTX/zHdLaFmcofWGzaWW1scwLU3ZbW/X+hSsFbz9wDIp6XvnT7pzYRl9MezWqEqKy7ssmDEnuQ==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.31.0':
resolution: {integrity: sha512-wal2Tc8O5lMBtoePLBYRKj2CImUCJ4UNGJlLwspx7QApYny7K1cUYlzQ/4IGQBLmm+y0RS7dwc3TDO/pmcneTw==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.34.6':
resolution: {integrity: sha512-aK+Zp+CRM55iPrlyKiU3/zyhgzWBxLVrw2mwiQSYJRobCURb781+XstzvA8Gkjg/hbdQFuDw44aUOxVQFycrAg==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-s390x-gnu@4.31.0':
resolution: {integrity: sha512-O1o5EUI0+RRMkK9wiTVpk2tyzXdXefHtRTIjBbmFREmNMy7pFeYXCFGbhKFwISA3UOExlo5GGUuuj3oMKdK6JQ==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-s390x-gnu@4.34.6':
resolution: {integrity: sha512-WoKLVrY9ogmaYPXwTH326+ErlCIgMmsoRSx6bO+l68YgJnlOXhygDYSZe/qbUJCSiCiZAQ+tKm88NcWuUXqOzw==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.31.0':
resolution: {integrity: sha512-zSoHl356vKnNxwOWnLd60ixHNPRBglxpv2g7q0Cd3Pmr561gf0HiAcUBRL3S1vPqRC17Zo2CX/9cPkqTIiai1g==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.34.6':
resolution: {integrity: sha512-Sht4aFvmA4ToHd2vFzwMFaQCiYm2lDFho5rPcvPBT5pCdC+GwHG6CMch4GQfmWTQ1SwRKS0dhDYb54khSrjDWw==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.31.0':
resolution: {integrity: sha512-ypB/HMtcSGhKUQNiFwqgdclWNRrAYDH8iMYH4etw/ZlGwiTVxBz2tDrGRrPlfZu6QjXwtd+C3Zib5pFqID97ZA==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-x64-musl@4.34.6':
resolution: {integrity: sha512-zmmpOQh8vXc2QITsnCiODCDGXFC8LMi64+/oPpPx5qz3pqv0s6x46ps4xoycfUiVZps5PFn1gksZzo4RGTKT+A==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-win32-arm64-msvc@4.31.0':
resolution: {integrity: sha512-JuhN2xdI/m8Hr+aVO3vspO7OQfUFO6bKLIRTAy0U15vmWjnZDLrEgCZ2s6+scAYaQVpYSh9tZtRijApw9IXyMw==}
@@ -727,24 +753,28 @@ packages:
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@tailwindcss/oxide-linux-arm64-musl@4.1.11':
resolution: {integrity: sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@tailwindcss/oxide-linux-x64-gnu@4.1.11':
resolution: {integrity: sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@tailwindcss/oxide-linux-x64-musl@4.1.11':
resolution: {integrity: sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [musl]
'@tailwindcss/oxide-wasm32-wasi@4.1.11':
resolution: {integrity: sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==}
@@ -1091,24 +1121,28 @@ packages:
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
lightningcss-linux-arm64-musl@1.30.1:
resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
lightningcss-linux-x64-gnu@1.30.1:
resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
lightningcss-linux-x64-musl@1.30.1:
resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
lightningcss-win32-arm64-msvc@1.30.1:
resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==}
@@ -1161,8 +1195,8 @@ packages:
engines: {node: '>=10'}
hasBin: true
modern-screenshot@4.5.5:
resolution: {integrity: sha512-k5AC0UjY8YccnKn53upeQMzgDdPYkDN/706ma3yPHCwOZi+AoL0NeMlLS3nQwA/s0xrM7s8WO+UWnx5YJNpQeA==}
modern-screenshot@4.6.8:
resolution: {integrity: sha512-GJkv/yWPOJTlxj1LZDU2k474cDyOWL+LVaqTdDWQwQ5d8zIuTz1892+1cV9V0ZpK6HYZFo/+BNLBbierO9d2TA==}
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -2297,7 +2331,7 @@ snapshots:
mkdirp@3.0.1: {}
modern-screenshot@4.5.5: {}
modern-screenshot@4.6.8: {}
ms@2.1.3: {}

View File

@@ -19,7 +19,7 @@ import OrderItem from '@/modules/heijkunka/assets/OrderItem.vue'
const days = Array.from({ length: NUMBER_OF_DAYS }, (_, i) => i + 1)
const hours = Array.from({ length: NUMBER_OF_HOURS_PER_DAY }, (_, i) => i + 1)
const orders = ref(
const planning = ref(
Array.from(
{ length: days.length * hours.length },
(): ProductType => pickRandomElement(['shirt', 'jeans', 'shoes', 'hat'])
@@ -56,7 +56,7 @@ const levelingPlanning: ProductType[] = [
'jeans'
]
const orderIndex = (dayIndex: number, hourIndex: number) => {
const planningIndex = (dayIndex: number, hourIndex: number) => {
return dayIndex * hours.length + hourIndex
}
@@ -103,6 +103,11 @@ const createdAt = new Date('2026-01-01').toLocaleDateString(undefined, {
per day to meet the 12 orders every 3 days. At the end, you produce 1
product every hour.
</p>
<p>
The mere reality is that we don't really know the exact orders we'll have.
This is presisely the whole point of plannification, it is a bet into the
future. The play is to know how to bet.
</p>
<section class="factory">
<h2>Factory</h2>
@@ -110,10 +115,11 @@ const createdAt = new Date('2026-01-01').toLocaleDateString(undefined, {
<thead>
<tr>
<th scope="col"></th>
<th scope="col">hour 1</th>
<th scope="col">hour 2</th>
<th scope="col">hour 3</th>
<th scope="col">hour 4</th>
<th scope="col">8:00</th>
<th scope="col">9:00</th>
<th scope="col">10:00</th>
<th scope="col">11:00</th>
<th>dock</th>
</tr>
</thead>
<tbody>
@@ -121,7 +127,7 @@ const createdAt = new Date('2026-01-01').toLocaleDateString(undefined, {
<th scope="row">day {{ day }}</th>
<td v-for="(hour, hourIndex) in hours">
<select
v-model="orders[orderIndex(dayIndex, hourIndex)]"
v-model="planning[planningIndex(dayIndex, hourIndex)]"
:name="`day-${day}-hour-${hour}`"
:id="`day-${day}-hour-${hour}`"
>
@@ -131,13 +137,34 @@ const createdAt = new Date('2026-01-01').toLocaleDateString(undefined, {
<option value="hat">Hat</option>
</select>
</td>
<td>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-truck"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M5 17a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />
<path d="M15 17a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />
<path
d="M5 17h-2v-11a1 1 0 0 1 1 -1h9v12m-4 0h6m4 0h2v-6h-8m0 -5h5l3 5"
/>
</svg>
</td>
</tr>
</tbody>
</table>
</section>
<section class="commands">
<button class="button-outline" @click="heijunkaStore.newHour()">
<button class="button-outline" @click="heijunkaStore.newHour(planning)">
next hour
<!--
<svg
@@ -161,7 +188,7 @@ const createdAt = new Date('2026-01-01').toLocaleDateString(undefined, {
reset
</button>
<button class="button-outline" @click="orders = [...levelingPlanning]">
<button class="button-outline" @click="planning = [...levelingPlanning]">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
@@ -184,7 +211,7 @@ const createdAt = new Date('2026-01-01').toLocaleDateString(undefined, {
</svg>
levelling
</button>
<button class="button-outline" @click="orders = [...batchPlanning]">
<button class="button-outline" @click="planning = [...batchPlanning]">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
@@ -200,14 +227,18 @@ const createdAt = new Date('2026-01-01').toLocaleDateString(undefined, {
</svg>
batch
</button>
<button class="button-outline" @click="heijunkaStore.simulateMonth()">
<button
class="button-outline"
@click="heijunkaStore.simulateMonth(planning)"
>
simulate a month
</button>
</section>
<div>
<span v-if="heijunkaStore.meta.currentHour > 0">
day: {{ heijunkaStore.currentDay }} | current hour:
{{ heijunkaStore.meta.currentHour }} hours
{{ heijunkaStore.meta.currentHour }} hours | cash flow:
{{ heijunkaStore.cashFlow }}
</span>
</div>
@@ -217,8 +248,6 @@ const createdAt = new Date('2026-01-01').toLocaleDateString(undefined, {
Orders made: {{ heijunkaStore.orders.length }}
</section>
<HeijunkaStat />
<section class="shop">
<div class="inventory">
<h2>Inventory</h2>
@@ -269,9 +298,12 @@ const createdAt = new Date('2026-01-01').toLocaleDateString(undefined, {
<OrderItem />
<span class="numeric">
{{ order.product }} | {{ order.leadTime }}
</span>
<ShirtItem v-show="order.product === 'shirt'" />
<JeanItem v-show="order.product === 'jeans'" />
<ShoeItem v-show="order.product === 'shoes'" />
<HatItem v-show="order.product === 'hat'" />
<span class="numeric">{{ order.leadTime }}</span>
</li>
</ol>
</div>
@@ -283,6 +315,8 @@ const createdAt = new Date('2026-01-01').toLocaleDateString(undefined, {
Orders made: {{ heijunkaStore.orders.length }}
</section>
<HeijunkaStat />
<p>
The longer the lead time is, the longer it takes to have return on
investment. You already paid for the raw material, the workforce, the
@@ -319,7 +353,11 @@ const createdAt = new Date('2026-01-01').toLocaleDateString(undefined, {
what you can make per day.
</p>
<h2>Heijunka is fun</h2>
<p>There's no ///</p>
<p>
For craftspersonns, there's no such thing repeating over and over again
the making of the same product - even if you love doing it - work needs
diversity. This is what the heijunka adds by doing a bit of everything.
</p>
</article>
</template>
@@ -347,17 +385,36 @@ li {
align-items: center;
}
.factory {
border: 2px solid var(--primary-color);
padding: 0 1rem;
margin: 1rem 0;
}
.shop {
display: flex;
border: 2px solid var(--primary-color);
border-radius: 1rem;
padding: 0 0.5rem;
width: 100%;
h2 {
text-align: center;
}
& > div {
flex: 1;
}
}
.orders {
ol {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
}
button {
display: flex;
align-items: center;

View File

@@ -22,10 +22,10 @@ const renderChart = () => {
const config = {
title: `Orders made`,
xLabel: 'Products',
xLabel: 'Products (ordered | made)',
yLabel: '# of orders',
data: {
labels: products.map((p) => [`${p} ordered`, `${p} made`]).flat(),
labels: products.map((p) => [`${p} o`, `${p}`]).flat(),
datasets: [
{
data: products
@@ -39,7 +39,18 @@ const renderChart = () => {
},
options: {
showLegend: true,
fontFamily: 'Noto Serif'
fontFamily: 'Noto Serif',
dataColors: [
'#55efc4',
'#00b894',
'#81ecec',
'#00cec9',
'#74b9ff',
'#0984e3',
'#a29bfe',
'#6c5ce7'
],
strokeColor: 'var(--primary-color)'
}
}
new chartXkcd.Bar(svgElement.value, config)

View File

@@ -1,2 +1,3 @@
export const NUMBER_OF_DAYS = 3
export const NUMBER_OF_HOURS_PER_DAY = 4
export const INITIAL_CASH_FLOW = 20

View File

@@ -1,4 +1,5 @@
import {
INITIAL_CASH_FLOW,
NUMBER_OF_DAYS,
NUMBER_OF_HOURS_PER_DAY
} from '@/modules/heijkunka/heijunka-config'
@@ -20,10 +21,8 @@ type Inventory = {
}
type HeijunkaState = {
money: number
inventory: Inventory
orders: Order[]
planning: ProductType[]
meta: {
currentHour: number
}
@@ -53,21 +52,14 @@ const initialInventory: Inventory = {
export const useHeijunkaStore = defineStore('heijunka', {
state: (): HeijunkaState => ({
money: 100,
inventory: { ...initialInventory },
orders: [],
planning: [],
meta: {
currentHour: 0
}
}),
actions: {
newHour() {
// End of the production
if (this.gameEnded) {
return
}
newHour(planning: ProductType[]) {
this.meta.currentHour++
// Add to inventory every day
@@ -75,16 +67,16 @@ export const useHeijunkaStore = defineStore('heijunka', {
this.inventory = {
shirt:
this.inventory.shirt +
getInventoryByProduct('shirt', this.planning, this.currentDay),
getInventoryByProduct('shirt', planning, this.currentDay),
jeans:
this.inventory.jeans +
getInventoryByProduct('jeans', this.planning, this.currentDay),
getInventoryByProduct('jeans', planning, this.currentDay),
shoes:
this.inventory.shoes +
getInventoryByProduct('shoes', this.planning, this.currentDay),
getInventoryByProduct('shoes', planning, this.currentDay),
hat:
this.inventory.hat +
getInventoryByProduct('hat', this.planning, this.currentDay)
getInventoryByProduct('hat', planning, this.currentDay)
}
}
@@ -136,19 +128,22 @@ export const useHeijunkaStore = defineStore('heijunka', {
},
reset() {
this.meta.currentHour = 0
this.planning = []
this.orders = []
this.inventory = { ...initialInventory }
},
simulateMonth() {
simulateMonth(planning: ProductType[]) {
for (let index = 0; index < 80; index++) {
this.newHour()
this.newHour(planning)
}
}
},
getters: {
currentDay: (state) =>
Math.ceil(state.meta.currentHour / NUMBER_OF_HOURS_PER_DAY),
cashFlow: (state) =>
INITIAL_CASH_FLOW -
state.meta.currentHour * 1 +
state.orders.filter((o) => o.status === 'received').length * 2,
remainingInventory: (state): Inventory => ({
shirt: Math.max(
state.inventory.shirt -
@@ -171,7 +166,6 @@ export const useHeijunkaStore = defineStore('heijunka', {
0
)
}),
gameEnded: () => false,
// state.meta.currentHour >= NUMBER_OF_DAYS * NUMBER_OF_HOURS_PER_DAY,
meanLeadTime: (state) => getMean(state.orders.map((o) => o.leadTime))
}