lilgotchi 0.0.0-stage → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +69 -3
  3. package/dist/LICENSE.md +21 -0
  4. package/dist/README.md +69 -0
  5. package/dist/design/evolution/README.md +7 -0
  6. package/dist/design/evolution/cypunk.js +3 -0
  7. package/dist/design/evolution/cypunk.md +20 -0
  8. package/dist/design/evolution/index.html +20 -0
  9. package/dist/design/evolution/lilgotchi.js +3 -0
  10. package/dist/design/evolution/lilgotchi.md +20 -0
  11. package/dist/design/evolution/preview.css +3 -0
  12. package/dist/design/evolution/preview.js +47 -0
  13. package/dist/design/evolution/slice.js +3 -0
  14. package/dist/design/evolution/slice.md +14 -0
  15. package/dist/design/games/README.md +52 -0
  16. package/dist/design/games/bump.md +23 -0
  17. package/dist/design/games/catalog.md +24 -0
  18. package/dist/design/games/flag.md +19 -0
  19. package/dist/design/games/get.md +21 -0
  20. package/dist/design/games/heading.md +23 -0
  21. package/dist/design/games/hoops.md +17 -0
  22. package/dist/design/games/left-right.md +30 -0
  23. package/dist/design/games/memory.md +21 -0
  24. package/dist/design/games/polish-review.md +11 -0
  25. package/dist/design/games/release-checklist.md +52 -0
  26. package/dist/design/games/sprint.md +21 -0
  27. package/dist/docs/README.md +14 -0
  28. package/dist/docs/care.md +51 -0
  29. package/dist/docs/characters.md +51 -0
  30. package/dist/docs/credits.md +17 -0
  31. package/dist/docs/development.md +87 -0
  32. package/dist/docs/frame-contract.md +38 -0
  33. package/dist/docs/images/cypunk-family.jpg +0 -0
  34. package/dist/docs/images/lilgotchi-family.jpg +0 -0
  35. package/dist/docs/images/original-family.jpg +0 -0
  36. package/dist/docs/images/slice-family.jpg +0 -0
  37. package/dist/docs/install.md +41 -0
  38. package/dist/docs/release-review.md +47 -0
  39. package/dist/embed.js +21 -0
  40. package/dist/examples/cross-origin.html +7 -0
  41. package/dist/examples/curated.html +12 -0
  42. package/dist/examples/duplicate.html +3 -0
  43. package/dist/examples/install.html +11 -0
  44. package/dist/examples/launcher-review.html +23 -0
  45. package/dist/examples/launchers.html +10 -0
  46. package/dist/examples/nested/index.html +6 -0
  47. package/dist/examples/one-line.html +9 -0
  48. package/dist/index.html +100 -0
  49. package/dist/lilgotchi.js +437 -0
  50. package/dist/pets/NOTICE.md +19 -0
  51. package/dist/pets/README.md +7 -0
  52. package/dist/pets/arcade-catalog.js +52 -0
  53. package/dist/pets/arcade-geometry.js +18 -0
  54. package/dist/pets/arcade-opponents.js +16 -0
  55. package/dist/pets/arcade-renderer.js +116 -0
  56. package/dist/pets/arcade-sprites.js +64 -0
  57. package/dist/pets/arcade.js +393 -0
  58. package/dist/pets/away.js +20 -0
  59. package/dist/pets/boot.js +161 -0
  60. package/dist/pets/catalog.js +32 -0
  61. package/dist/pets/celebrations.js +54 -0
  62. package/dist/pets/classic-sprites.js +672 -0
  63. package/dist/pets/clock.js +3 -0
  64. package/dist/pets/colors.js +38 -0
  65. package/dist/pets/constants.js +20 -0
  66. package/dist/pets/custom-themes.css +80 -0
  67. package/dist/pets/cyberpunk-sprites.js +68 -0
  68. package/dist/pets/cypunk-original.js +2 -0
  69. package/dist/pets/embed.css +130 -0
  70. package/dist/pets/engine.js +38 -0
  71. package/dist/pets/evolution.js +46 -0
  72. package/dist/pets/focus.js +27 -0
  73. package/dist/pets/font.js +185 -0
  74. package/dist/pets/game.css +275 -0
  75. package/dist/pets/game.html +148 -0
  76. package/dist/pets/game.js +626 -0
  77. package/dist/pets/layout.js +53 -0
  78. package/dist/pets/lilgotchi-sprites.js +62 -0
  79. package/dist/pets/minigames/bump.js +52 -0
  80. package/dist/pets/minigames/flag.js +87 -0
  81. package/dist/pets/minigames/get.js +59 -0
  82. package/dist/pets/minigames/heading.js +117 -0
  83. package/dist/pets/minigames/hoops.js +96 -0
  84. package/dist/pets/minigames/memory.js +81 -0
  85. package/dist/pets/minigames/model.js +40 -0
  86. package/dist/pets/minigames/sprint.js +103 -0
  87. package/dist/pets/original-roster.js +46 -0
  88. package/dist/pets/original-sprites.js +3861 -0
  89. package/dist/pets/overlay-size.js +13 -0
  90. package/dist/pets/pixel-size.js +6 -0
  91. package/dist/pets/presentation.js +80 -0
  92. package/dist/pets/renderer.js +100 -0
  93. package/dist/pets/scenery.css +24 -0
  94. package/dist/pets/simulation.js +185 -0
  95. package/dist/pets/skins.js +14 -0
  96. package/dist/pets/slice-sprites.js +38 -0
  97. package/dist/pets/sound.js +33 -0
  98. package/dist/pets/status.js +28 -0
  99. package/dist/pets/storage.js +49 -0
  100. package/dist/pets/valid-state.js +26 -0
  101. package/dist/pets/wellbeing.js +73 -0
  102. package/dist/reference/source.json +8 -0
  103. package/dist/version.json +5 -0
  104. package/dist/widget/care-guide.js +50 -0
  105. package/dist/widget/care-monitor.js +52 -0
  106. package/dist/widget/color-controls.js +15 -0
  107. package/dist/widget/configurator.js +24 -0
  108. package/dist/widget/egg.svg +1 -0
  109. package/dist/widget/focus.js +6 -0
  110. package/dist/widget/gallery.js +17 -0
  111. package/dist/widget/inactive.js +24 -0
  112. package/dist/widget/install-snippet.js +14 -0
  113. package/dist/widget/launcher.js +63 -0
  114. package/dist/widget/pet-history.js +57 -0
  115. package/dist/widget/pet-label.js +12 -0
  116. package/dist/widget/save-store.js +198 -0
  117. package/dist/widget/scroll-lock.js +11 -0
  118. package/dist/widget/settings.js +48 -0
  119. package/dist/widget/shell.css +63 -0
  120. package/package.json +43 -6
@@ -0,0 +1,20 @@
1
+ export const C = {
2
+ W: 32, H: 16, SCALE: 8,
3
+ MAX_HUNGER: 4, MAX_HAPPY: 4, MAX_DISC: 100, DISC_INC: 25,
4
+ MAX_WEIGHT: 99, MAX_POOP: 4,
5
+ MEAL_WT: 1, SNACK_WT: 2, GAME_WT_LOSS: 1,
6
+ EGG_MS: 90000, // 90 seconds
7
+ BABY_MS: 3600000, // 1 hr
8
+ CHILD_MS: 86400000, // 24 hr
9
+ TEEN_MS: 86400000, // 24 hr
10
+ HUNGER_DECAY: { baby:1800000, child:3600000, teen:3600000, adult:3600000 },
11
+ HAPPY_DECAY: { baby:1800000, child:3600000, teen:3600000, adult:4200000 },
12
+ POOP_RATE: { baby:900000, child:10800000, teen:10800000, adult:10800000 },
13
+ SLEEP: { baby:{s:20,w:9}, child:{s:20,w:9}, teen:{s:21,w:9}, adult:{s:22,w:9} },
14
+ BASE_WT: { baby:5, child:10, teen:20, adult:30 },
15
+ CARE_WINDOW: 900000, // 15 min
16
+ ADULT_MAX_MISTAKES: 5,
17
+ MAX_AGE: 25,
18
+ SNACK_SICK: 10,
19
+ };
20
+
@@ -0,0 +1,80 @@
1
+ /* Dark embedded version. Gameplay and control layout come from the P1 clone. */
2
+ :root {
3
+ --bg-page:#080a09;
4
+ --device-bg:linear-gradient(145deg,#594632,#302820);
5
+ --device-shadow:none;
6
+ --device-inset:inset 0 2px 4px #ffffff18;
7
+ --screen-frame:#1b201b;
8
+ --lcd-bg:#29231c;
9
+ --lcd-fg:#e6c79d;
10
+ --accent:#ffbb79;
11
+ --accent-dark:#29231c;
12
+ --btn-bg:#141815;
13
+ --btn-border:#41483f;
14
+ --btn-color:#e7e5df;
15
+ --btn-active-bg:#242a25;
16
+ --btn-shadow:none;
17
+ --btn-inset:none;
18
+ --overlay-bg:#080a09;
19
+ --overlay-color:#e7e5df;
20
+ --overlay-btn-bg:#141815;
21
+ --overlay-btn-border:#535d50;
22
+ --overlay-btn-color:#e7e5df;
23
+ --overlay-btn-active-bg:#29231c;
24
+ --overlay-btn-active-color:#ffbb79;
25
+ --overlay-close-color:#b5beb0;
26
+ --overlay-close-border:#535d50;
27
+ --overlay-close-active:#242a25;
28
+ --stat-border:#343a34;
29
+ --stat-hearts:#ffbb79;
30
+ --settings-btn-color:#b5beb0;
31
+ --info-color:#aeb5ad;
32
+ --death-msg:#c6cbbf;
33
+ --toast-bg:#141815;
34
+ --toast-border:#535d50;
35
+ --toast-color:#ffbb79;
36
+ }
37
+ :root[data-pet="classic"] { --lcd-bg:#20281d; --lcd-fg:#b4ce83; --accent:#b4ce83; --stat-hearts:#b4ce83; }
38
+ :root[data-pet="cyberpunk"] { --device-bg:linear-gradient(145deg,#304e59,#172c36); --lcd-bg:#0b1c24; --lcd-fg:#8cebdc; --accent:#83e8d7; --stat-hearts:#83e8d7; }
39
+ html,body { height:auto; overflow-x:hidden; overflow-y:auto; color-scheme:dark; }
40
+ body { min-height:0; display:block; padding:0; color:#e7e5df; }
41
+ /* Keep the shared egg silhouette and spacing for every character family. */
42
+ #settings-btn { top:0; right:3px; width:32px; height:30px; opacity:1; }
43
+ html[data-embedded="true"] #settings-btn { color:#e7e5df; }
44
+ .ctrl-btn .icon-color { display:none; }
45
+ .ctrl-btn .icon-mono { display:block; color:var(--accent); }
46
+ #pet-status { min-height:38px; margin:12px 2px 4px; font-size:11px; line-height:1.6; color:var(--lcd-fg); }
47
+ #save-status { margin:4px 2px; font-size:10px; color:#99a197; }
48
+ .overlay { padding:16px 8px; overflow:auto; justify-content:flex-start; }
49
+ .overlay-title { font-size:14px; margin:12px 0; letter-spacing:1px; }
50
+ .overlay-close { background:transparent; font:inherit; }
51
+ .overlay-btn { max-width:100%; padding:12px; font-size:13px; }
52
+ #stats-overlay .stat-row { max-width:100%; font-size:12px; padding:6px 0; }
53
+ #game-overlay .game-area { gap:12px; }
54
+ #game-overlay .game-arrow { width:60px; height:60px; font-size:26px; }
55
+ #game-overlay .game-score { font-size:13px; }
56
+ #game-overlay .game-result { font-size:12px; text-align:center; }
57
+ #toast { max-width:95%; white-space:normal; text-align:center; font-size:11px; padding:8px 10px; }
58
+ button:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
59
+ :root[data-scene="morning"] { --scene-top:#79633f; --lcd-bg:#332b20; }
60
+ :root[data-scene="afternoon"] { --scene-top:#635c3c; --lcd-bg:#292b20; }
61
+ :root[data-scene="evening"] { --scene-top:#805440; --lcd-bg:#35231f; }
62
+ :root[data-scene="night"],:root[data-scene="sleep"],:root[data-scene="dark"] { --scene-top:#3d4759; --lcd-bg:#1b202b; }
63
+ :root[data-pet="cyberpunk"][data-scene="morning"] { --scene-top:#4e7478; --lcd-bg:#153039; }
64
+ :root[data-pet="cyberpunk"][data-scene="afternoon"] { --scene-top:#426d74; --lcd-bg:#0c2932; }
65
+ :root[data-pet="cyberpunk"][data-scene="evening"] { --scene-top:#625678; --lcd-bg:#241d35; }
66
+ :root[data-pet="cyberpunk"][data-scene="night"],:root[data-pet="cyberpunk"][data-scene="sleep"],:root[data-pet="cyberpunk"][data-scene="dark"] { --scene-top:#304755; --lcd-bg:#0b1c24; }
67
+ #pet-clock { color:#f0e9df; }
68
+ @media(prefers-reduced-motion:reduce) { * { animation:none!important; transition:none!important; } }
69
+
70
+
71
+ :root[data-pet="lilgotchi"] { --device-bg:linear-gradient(145deg,#fff0cc,#e7c88d); --lcd-bg:#20281d; --lcd-fg:#fff0cc; --accent:#e7c88d; --stat-hearts:#e7c88d; }
72
+ :root[data-pet="lilgotchi"] #pet-clock { color:#3d4937; }
73
+
74
+ /* Cool daylight keeps the warm pizza pixels separate from their surroundings. */
75
+ :root[data-pet="pizza"] { --device-bg:linear-gradient(145deg,#839c98,#526f70); --screen-frame:#38545a; }
76
+ :root[data-pet="pizza"][data-scene="morning"] { --scene-top:#a1c1be; --lcd-bg:#779c9e; }
77
+ :root[data-pet="pizza"][data-scene="afternoon"] { --scene-top:#8db8bc; --lcd-bg:#648e97; }
78
+ :root[data-pet="pizza"][data-scene="evening"] { --scene-top:#939eb7; --lcd-bg:#657e97; }
79
+ :root[data-pet="pizza"][data-scene="night"] { --scene-top:#596d88; --lcd-bg:#344d68; }
80
+ :root[data-pet="pizza"][data-scene="sleep"],:root[data-pet="pizza"][data-scene="dark"] { --scene-top:#34475a; --lcd-bg:#192a3a; }
@@ -0,0 +1,68 @@
1
+ import { originalCypunk } from './cypunk-original.js';
2
+ const palette = ['', '#d9fcff', '#102238', '#22dbe7', '#ec4cb4', '#53718c', '#70f79a', '#f4d45b', '#a97ef5', '#3569c8'];
3
+ const expressions = {
4
+ idle1:['101','000','010'], idle2:['101','000','111'],
5
+ happy:['101','000','101'], sad:['000','101','010'],
6
+ eat:['101','010','111'], sleep:['000','101','000'],
7
+ lookLeft:['110','100','010'],lookRight:['011','001','010'],lookUp:['101','000','010'],
8
+ };
9
+ const drawings = [
10
+ {id:'egg',name:'Binary Seed',stage:'egg',rows:['000033330000','000322223000','003212122300','032112122230','032212112230','032212122230','032111122230','003222222300','000333333000','000000000000']},
11
+ {id:'babytchi',name:'Bit',stage:'baby',face:[4,6],rows:['000000000000','000000000000','000000000000','000333330000','003222223000','003222223000','003222223000','003222223000','003222223000','000333330000','000320230000','000330330000']},
12
+ {id:'marutchi',name:'Byte',stage:'child',face:[4,5],rows:['000004000000','000003000000','003333333000','032222222300','032222222300','332222222330','322222222230','332222222330','032222222300','003333333000','000320230000','000330330000']},
13
+ {id:'tamatchi',name:'Compiler',stage:'teen',face:[4,5],rows:['000033330000','000322223000','003222222300','003333333300','003222222300','033222222330','032222222230','003222222300','000344430000','000322230000','003300033000','003000003000']},
14
+ {id:'kuchitamatchi',name:'Syntax Error',stage:'teen',face:[4,5],rows:['000440000000','000030330000','000333223000','043222222300','003222222300','003222222340','003222222300','003222222300','000334433000','003220030000','000330233000','000030003000']},
15
+ {id:'mametchi',name:'JavaScript',stage:'adult',face:[4,3],faceWidth:5,rows:['000070070000','000333333300','003222222230','003222222230','003222222230','003333333330','073032230370','033037730330','000032230000','000032230000','000032023000','000333033300']},
16
+ {id:'ginjirotchi',name:'Sentinel',stage:'adult',original:true},
17
+ {id:'maskutchi',name:'Matrix',stage:'adult',face:[4,3],faceWidth:5,rows:['000060060000','000666666600','006222222260','006222222260','006222222260','066666666660','062062260260','066061160660','000062260000','000061260000','000062026000','000666066600']},
18
+ {id:'kuchipatchi',name:'404',stage:'adult',face:[4,3],faceWidth:5,rows:['000440000000','000033333300','003222222230','003222222230','003222222230','003333333330','003032230300','043032230340','003034430300','000032230000','000032023000','000333033300']},
19
+ {id:'nyorotchi',name:'MissingNumber',stage:'adult',face:[4,5],rows:['033000000000','032300040000','033330033000','032233322300','043222222330','003222222230','033222222300','032222222330','033444333030','000322233000','000033003300','000330000030']},
20
+ {id:'tarakotchi',name:'Blue Screen',stage:'adult',face:[3,3],faceWidth:5,background:9,rows:['055555555550','559999999955','599999999995','599999999995','599999999995','599999999995','559999999955','055555555550','033053350330','000052250000','000032023000','000333033300']},
21
+ {id:'oyajitchi',name:'Glitch Elder',stage:'adult',face:[4,4],rows:['003000004000','004033330000','000322223300','043222222300','003222222340','003222222300','003222222300','000334443330','043222230000','000322223040','003330033000','000300003300']},
22
+ ];
23
+ function canvas(rows) {
24
+ if(rows.length>12||rows.some(row=>row.length>12))throw new Error('Proposal exceeds 12 by 12');
25
+ return [...Array(12-rows.length).fill(''),...rows].map(row=>[...row.padEnd(12,'0')].map(Number));
26
+ }
27
+ function draw(definition,expression) {
28
+ if(definition.id==='egg')return originalCypunk.egg[expression];
29
+ if(definition.original){
30
+ if(!expression.startsWith('look'))return originalCypunk.mametchi[expression];
31
+ const frame=originalCypunk.mametchi.idle1.map(row=>[...row]);
32
+ for(let y=3;y<=5;y++)for(let x=3;x<=8;x++)frame[y][x]=2;
33
+ if(expression==='lookUp'){frame[2][4]=3;frame[2][7]=3;frame[4][5]=1;return frame;}
34
+ const left=expression==='lookLeft',x=left?3:6;
35
+ frame[3][x]=3;frame[3][x+2]=3;
36
+ frame[4][left?3:8]=3;frame[5][left?4:7]=1;
37
+ return frame;
38
+ }
39
+ const pixels=canvas(definition.rows);
40
+ if(definition.face){
41
+ const [x,faceY]=definition.face,y=faceY-(expression==='lookUp'?1:0);
42
+ const wide={idle1:['10001','00000','00100'],idle2:['10001','00000','01110'],happy:['01010','10001','01110'],sad:['00000','10001','01110'],eat:['10001','00100','01110'],sleep:['00000','11011','00000'],lookLeft:['10100','10000','01000'],lookRight:['00101','00001','00010'],lookUp:['10001','00000','00100']};
43
+ const face=definition.faceWidth===5?wide[expression]:expressions[expression];
44
+ face.forEach((row,dy)=>[...row].forEach((pixel,dx)=>{
45
+ pixels[y+dy][x+dx]=pixel==='1'?(definition.ink||1):(definition.background||2);
46
+ }));
47
+ }
48
+ // Small antenna and code movements keep the face and silhouette steady.
49
+ if(expression==='idle2'){
50
+ if(definition.id==='egg')pixels[9][7]=4;
51
+ else if(definition.id==='maskutchi'){pixels[8][5]=1;pixels[9][5]=2;}
52
+ else if(definition.id==='oyajitchi'){pixels[0][8]=0;pixels[0][9]=4;}
53
+ else if(definition.id==='nyorotchi'){pixels[1][7]=0;pixels[1][8]=4;}
54
+ }
55
+ return pixels.map(Object.freeze);
56
+ }
57
+ const artwork = {
58
+ type:'Cypunk', palette,
59
+ pets:drawings.map(definition=>({
60
+ id:definition.id,name:definition.name,stage:definition.stage,
61
+ frames:Object.fromEntries((definition.stage==='egg'?['idle1','idle2']:Object.keys(expressions)).map(expression=>[expression,draw(definition,expression)])),
62
+ })),
63
+ };
64
+
65
+ const freezeFrame=frame=>Object.freeze(frame.map(row=>Object.freeze([...row])));
66
+ export const cyberpunkPalette=Object.freeze(artwork.palette);
67
+ export const cyberpunkNames=Object.freeze(Object.fromEntries(artwork.pets.map(pet=>[pet.id,pet.name])));
68
+ export const cyberpunkSprites=Object.freeze(Object.fromEntries(artwork.pets.map(pet=>[pet.id,Object.freeze(Object.fromEntries(Object.entries(pet.frames).map(([key,frame])=>[key,freezeFrame(frame)])))])));
@@ -0,0 +1,2 @@
1
+ // Original Binary Seed and Sentinel poses retained across releases.
2
+ export const originalCypunk = {"egg":{"idle1":[[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,3,3,3,3,3,3,0,0,0],[0,0,3,2,2,2,2,2,2,3,0,0],[0,3,2,1,1,1,2,2,1,2,3,0],[0,3,2,1,2,1,2,1,1,2,3,0],[0,3,2,1,2,1,2,2,1,2,3,0],[0,3,2,1,2,1,2,2,1,2,3,0],[0,3,2,1,1,1,2,1,1,1,3,0],[0,0,3,2,2,2,2,2,2,3,0,0],[0,0,0,3,3,3,3,3,3,0,0,0]],"idle2":[[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,3,3,3,3,3,3,0,0,0],[0,0,3,2,2,2,2,2,2,3,0,0],[0,3,2,1,1,1,2,2,1,2,3,0],[0,3,2,1,2,1,2,1,1,2,3,0],[0,3,2,1,2,1,2,2,1,2,3,0],[0,3,2,1,2,1,2,2,1,2,3,0],[0,3,2,1,1,1,2,1,1,1,3,0],[0,0,3,2,4,2,2,3,2,3,0,0],[0,0,0,3,3,3,3,3,3,0,0,0]]},"mametchi":{"idle1":[[0,0,0,0,3,0,0,3,0,0,0,0],[0,0,0,3,3,3,3,3,3,3,0,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,3,2,2,2,3,2,3,0],[0,0,3,2,2,2,2,2,2,2,3,0],[3,3,3,3,2,2,1,2,2,3,3,3],[3,2,2,0,3,2,2,3,0,2,2,3],[0,3,3,0,3,2,2,3,0,3,3,0],[0,0,0,0,3,4,4,3,0,0,0,0],[0,0,0,0,3,2,2,3,0,0,0,0],[0,0,0,0,3,2,0,2,3,0,0,0],[0,0,0,3,3,3,0,3,3,3,0,0]],"idle2":[[0,0,0,0,3,0,0,3,0,0,0,0],[0,0,0,3,3,3,3,3,3,3,0,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,3,2,2,2,3,2,3,0],[0,0,3,2,2,2,2,2,2,2,3,0],[3,3,3,3,2,1,1,1,2,3,3,3],[3,2,2,0,3,2,2,3,0,2,2,3],[0,3,3,0,3,2,2,3,0,3,3,0],[0,0,0,0,3,4,4,3,0,0,0,0],[0,0,0,0,3,2,2,3,0,0,0,0],[0,0,0,0,3,2,0,2,3,0,0,0],[0,0,3,0,3,3,0,3,3,3,0,0]],"happy":[[0,0,0,0,3,0,0,3,0,0,0,0],[0,0,0,3,3,3,3,3,3,3,0,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,2,3,2,3,2,2,3,0],[0,0,3,2,3,2,2,2,3,2,3,0],[3,3,3,3,2,1,1,1,2,3,3,3],[3,2,2,0,3,2,2,3,0,2,2,3],[0,3,3,0,3,2,2,3,0,3,3,0],[0,0,0,0,3,4,4,3,0,0,0,0],[0,0,0,0,3,2,2,3,0,0,0,0],[0,0,0,0,3,2,0,2,3,0,0,0],[0,0,0,3,3,3,0,3,3,3,0,0]],"sad":[[0,0,0,0,3,0,0,3,0,0,0,0],[0,0,0,3,3,3,3,3,3,3,0,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,3,2,2,2,3,2,3,0],[3,3,3,3,2,4,4,4,2,3,3,3],[3,2,2,0,3,2,2,3,0,2,2,3],[0,3,3,0,3,2,2,3,0,3,3,0],[0,0,0,0,3,4,4,3,0,0,0,0],[0,0,0,0,3,2,2,3,0,0,0,0],[0,0,0,0,3,2,0,2,3,0,0,0],[0,0,0,3,3,3,0,3,3,3,0,0]],"eat":[[0,0,0,0,3,0,0,3,0,0,0,0],[0,0,0,3,3,3,3,3,3,3,0,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,3,2,2,2,3,2,3,0],[0,0,3,2,2,2,1,2,2,2,3,0],[3,3,3,3,2,1,3,1,2,3,3,3],[3,2,2,0,3,2,2,3,0,2,2,3],[0,3,3,0,3,2,2,3,0,3,3,0],[0,0,0,0,3,4,4,3,0,0,0,0],[0,0,0,0,3,2,2,3,0,0,0,0],[0,0,0,0,3,2,0,2,3,0,0,0],[0,0,0,3,3,3,0,3,3,3,0,0]],"sleep":[[0,0,0,0,3,0,0,3,0,0,0,0],[0,0,0,3,3,3,3,3,3,3,0,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,5,5,2,5,5,2,3,0],[3,3,3,3,2,2,2,2,2,3,3,3],[3,2,2,0,3,2,2,3,0,2,2,3],[0,3,3,0,3,2,2,3,0,3,3,0],[0,0,0,0,3,4,4,3,0,0,0,0],[0,0,0,0,3,2,2,3,0,0,0,0],[0,0,0,0,3,2,0,2,3,0,0,0],[0,0,0,3,3,3,0,3,3,3,0,0]]}};
@@ -0,0 +1,130 @@
1
+ /* The source stylesheet stays intact. These are embedding and access exceptions. */
2
+ [hidden] { display:none!important; }
3
+ html[data-embedded="true"] #settings-btn { display:none; }
4
+ button:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
5
+ .overlay-close { background:transparent; font-family:inherit; }
6
+ .overlay { overflow:auto; }
7
+ .settings-row[hidden] { display:none; }
8
+ #pet-needs { width:94%; min-height:24px; padding:4px 0; text-align:center; color:var(--lcd-fg); font-size:10px; line-height:1.5; }
9
+ #lcd { margin-inline:auto; max-width:100%; }
10
+ #pet-status, #save-status { position:absolute; width:1px; height:1px; padding:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }
11
+ html[data-embedded="true"], html[data-embedded="true"] body { height:100%; min-height:0; }
12
+ html[data-embedded="true"] body { justify-content:flex-start; padding:12px 0; }
13
+ html[data-embedded="true"] #device { box-shadow:var(--device-inset); }
14
+ html[data-embedded="true"] .overlay { padding:12px 8px; }
15
+ html[data-embedded="true"] .overlay-title { margin-top:12px; }
16
+ html[data-embedded="true"] #settings-btn { top:8px; right:10px; }
17
+ @media(max-width:359px) {
18
+ .overlay-title { font-size:15px; }
19
+ #game-overlay .game-area { gap:12px; }
20
+ #game-overlay .game-arrow { width:56px; height:56px; font-size:28px; }
21
+ #stats-overlay .stat-row, .settings-row { max-width:100%; }
22
+ #toast { max-width:95%; white-space:normal; text-align:center; }
23
+ }
24
+ @media(max-height:400px) { .overlay { justify-content:flex-start; padding:12px 8px; } }
25
+ @media(prefers-reduced-motion:reduce) { * { animation:none!important; transition:none!important; } }
26
+ /* The host owns scrolling. Height comes from the private frame channel. */
27
+ html[data-embedded="true"], html[data-embedded="true"] body { height:auto; overflow:hidden; }
28
+ html[data-embedded="true"] #device { flex-shrink:0; }
29
+ html[data-embedded="true"] .overlay { overflow:hidden; }
30
+ html[data-embedded="true"] #save-status { display:none; }
31
+ html[data-embedded="true"] #settings-btn { width:44px; height:44px; top:0; }
32
+
33
+
34
+ /* Leave a visible shell around the display and both rows of controls. */
35
+ #device { padding:44px 14px 38px; }
36
+ #screen-frame { width:82%; border-radius:22px; padding:7px; }
37
+ #lcd { border-radius:15px; }
38
+ #attention-bar { width:76%; }
39
+ #controls { width:82%; gap:8px; margin-top:8px; }
40
+ .ctrl-btn { border-radius:22px; min-height:52px; padding:8px 2px; }
41
+ html[data-embedded="true"] #settings-btn { top:2px; right:calc(50% - 22px); }
42
+
43
+ /* The pet has its own screen. Information and secondary care sit below the shell. */
44
+ html[data-embedded="true"] #device,#device { padding:0; border-radius:0; background:transparent; box-shadow:none; width:100%; }
45
+ #egg-shell { box-sizing:border-box; width:100%; padding:42px 14px 32px; position:relative; display:flex; flex-direction:column; align-items:center; border-radius:48% 48% 44% 44% / 52% 52% 42% 42%; background:var(--device-bg); box-shadow:var(--device-inset); }
46
+ #pet-clock { position:absolute; top:17px; left:0; right:0; text-align:center; font:12px/1.3 system-ui,sans-serif; color:#28352b; }
47
+ .keychain { position:absolute; width:78px; height:73px; top:0; right:0; pointer-events:none; opacity:.82; }
48
+ #device { position:relative; isolation:isolate; }
49
+ #egg-shell { z-index:1; }
50
+ html[data-embedded="true"] #settings-btn { top:5px; right:23%; width:44px; height:44px; font-size:19px; opacity:1; color:#28352b; }
51
+ #screen-frame { position:relative; width:80%; padding:12px; border-radius:24px; overflow:visible; background:linear-gradient(150deg,var(--scene-top,#a8b69a),var(--screen-frame)); }
52
+ #lcd { border-radius:0; position:relative; }
53
+ #attention-bar { width:68%; height:4px; margin:8px 0; }
54
+ #controls { width:78%; grid-template-columns:repeat(3,minmax(0,1fr)); margin-top:2px; gap:10px; }
55
+ .ctrl-btn { min-height:56px; padding:8px 3px; border-radius:24px; }
56
+ .ctrl-btn .label { font:11px/1.3 system-ui,sans-serif; letter-spacing:0; opacity:1; }
57
+ .ctrl-btn .icon-color { display:none; }
58
+ .ctrl-btn .icon-mono { display:block; width:20px; height:20px; }
59
+ .ctrl-btn:disabled { opacity:.58; }
60
+ .care-symbol { font:24px/1 system-ui,sans-serif; margin-bottom:3px; }
61
+ #care-panel { width:100%; padding:12px 8px 0; box-sizing:border-box; color:#e7e5df; font:12px/1.5 system-ui,sans-serif; }
62
+ #pet-identity { text-align:center; font-weight:600; font-size:13px; margin-bottom:8px; text-transform:capitalize; }
63
+ #pet-needs { width:100%; color:inherit; font:12px/1.5 system-ui,sans-serif; min-height:0; }
64
+ #care-meters { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:4px 16px; }
65
+ .need { display:flex; justify-content:space-between; gap:6px; }
66
+ .need strong { font-variant-numeric:tabular-nums; }
67
+ .care-grade { grid-column:1/-1; text-align:center; font-size:11px; color:#bac7bc; margin-top:3px; }
68
+ #care-hint { margin:8px 0; text-align:center; color:#c6cfc7; font-size:12px; }
69
+ #more-care { border-top:1px solid #414941; }
70
+ /* Match the 12px frame space below the care row. */
71
+ #more-care summary { box-sizing:border-box; min-height:56px; padding-top:12px; display:flex; align-items:center; justify-content:center; cursor:pointer; }
72
+ #more-care summary::after { content:' +'; margin-left:6px; }
73
+ #more-care[open] summary::after { content:' −'; }
74
+ .secondary-controls { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:8px; padding-bottom:8px; }
75
+ .secondary-controls .ctrl-btn { border-radius:14px; }
76
+ :root[data-scene="morning"] { --scene-top:#b8b389; --lcd-bg:#c6cfa7; }
77
+ :root[data-scene="afternoon"] { --scene-top:#9fb6ac; --lcd-bg:#c4cfa1; }
78
+ :root[data-scene="evening"] { --scene-top:#ba9c86; --lcd-bg:#c9b89b; }
79
+ :root[data-scene="night"],:root[data-scene="sleep"],:root[data-scene="dark"] { --scene-top:#697c79; --lcd-bg:#a4b2a0; }
80
+ :root.eink { --scene-top:#ddd; --lcd-bg:#f0f0f0; }
81
+ .scanlines:not(.eink) #screen-frame::after { content:''; position:absolute; inset:12px; pointer-events:none; background:repeating-linear-gradient(transparent 0 3px,#0000000b 3px 4px); }
82
+ html[data-embedded="true"],html[data-embedded="true"] body { background:#121619; }
83
+ @media(max-width:300px) { #egg-shell {padding-inline:8px;} #controls{width:86%;gap:6px;} #screen-frame{width:84%;padding:10px;} #care-panel{padding-inline:3px;} }
84
+
85
+ /* Dialog text needs the same readable contrast and sizing as the care panel. */
86
+ .overlay { background:#121619; color:#eef1ed; font:14px/1.6 system-ui,sans-serif; gap:12px; }
87
+ .overlay-title { color:#e7c88d; font:700 18px/1.4 system-ui,sans-serif; letter-spacing:.04em; }
88
+ #settings-overlay .settings-info,#death-overlay .death-msg { color:#c6cfc7; font:14px/1.6 system-ui,sans-serif; max-width:30ch; }
89
+ .settings-row { font:14px/1.5 system-ui,sans-serif; min-height:44px; gap:12px; }
90
+ .overlay-btn,.overlay-close { font:14px/1.5 system-ui,sans-serif; min-height:44px; padding:10px 14px; }
91
+ .overlay-btn { color:#eef1ed; background:#27332b; border-color:#9ba996; }
92
+ .overlay-close { color:#eef1ed; border-color:#9ba996; }
93
+ .stat-row,.game-score,.game-result { font:14px/1.5 system-ui,sans-serif; color:#eef1ed; }
94
+ .toggle { flex-shrink:0; min-width:48px; min-height:28px; }
95
+ html[data-embedded="true"] .overlay { padding:20px 12px; }
96
+ /* Let the host size and scroll the entire dialog without squeezing its controls. */
97
+ html[data-embedded="true"] .overlay { position:absolute; height:auto; min-height:100%; box-sizing:border-box; justify-content:flex-start; }
98
+ html[data-embedded="true"] .overlay > * { flex-shrink:0; }
99
+ .settings-header { display:flex; align-items:center; justify-content:space-between; gap:12px; width:100%; max-width:280px; }
100
+ .settings-header .overlay-title { margin:0; }
101
+ .settings-header .overlay-close { margin:0; }
102
+ #settings-overlay .settings-row { max-width:280px; width:100%; margin:0; padding:6px 0; }
103
+ #settings-overlay .settings-info { max-width:280px; width:100%; margin:0 0 6px; text-align:left; }
104
+ #settings-overlay #reset-game-btn { margin:8px 0 0; max-width:100%; }
105
+ @media(forced-colors:active) { .overlay,.overlay-btn,.overlay-close { forced-color-adjust:auto; } .toggle { border:2px solid ButtonText; } }
106
+
107
+ .arcade-picker{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;width:100%}.arcade-instruction,.arcade-score{margin:0;text-align:center;max-width:30ch}.arcade-actions{display:flex;gap:8px;width:100%}.arcade-actions button{flex:1}.arcade-field{width:100%;max-width:320px;image-rendering:pixelated;aspect-ratio:2}.arcade-pet{width:64px;height:64px;object-fit:contain;image-rendering:pixelated}.arcade-cue{min-height:28px;font-size:20px;text-align:center}.arcade-options{font-size:13px}
108
+
109
+ .arcade-meter{height:24px;width:90%;position:relative;background:#283b45;border:1px solid #96aaa4}.arcade-meter span{position:absolute;inset-block:0;background:#5e9c70}.arcade-meter i{position:absolute;top:0;bottom:0;width:3px;background:white}.arcade-actions button{touch-action:none}
110
+ /* Full size guessing pets keep their own pixels and leave room for both arrows. */
111
+ #game-overlay .game-area { gap:8px; max-width:100%; }
112
+ #game-overlay .game-pet { width:128px; height:128px; flex:none; }
113
+ #game-overlay .game-arrow { width:48px; height:48px; flex:none; font-size:28px; }
114
+
115
+ /* Game controls fit the drawer instead of inheriting fixed menu button widths. */
116
+ #arcade-overlay, #game-overlay { box-sizing:border-box; gap:12px; justify-content:flex-start; padding:16px 0; }
117
+ html[data-embedded="true"] #arcade-overlay, html[data-embedded="true"] #game-overlay { padding:16px 0; }
118
+ #arcade-overlay .overlay-title, #game-overlay .overlay-title { margin:0; font-size:18px; line-height:1.4; letter-spacing:0; }
119
+ #arcade-overlay .overlay-btn, #game-overlay .overlay-btn { box-sizing:border-box; width:100%; min-width:0; min-height:48px; margin:0; padding:12px 8px; font:inherit; line-height:1.25; border-radius:12px; }
120
+ #arcade-overlay .arcade-picker { width:100%; gap:10px; grid-template-columns:repeat(2,minmax(0,1fr)); }
121
+ #arcade-overlay .arcade-picker button { min-height:60px; }
122
+ #arcade-overlay .arcade-actions, #game-overlay .game-area { display:flex; width:100%; gap:8px; margin:0; }
123
+ #arcade-overlay .arcade-actions button, #game-overlay .game-arrow { flex:1 1 0; width:0; min-width:0; font-size:14px; border-radius:12px; }
124
+ #arcade-overlay .arcade-field, #game-overlay .guess-field { width:100%; max-width:100%; height:auto; aspect-ratio:4/3; display:block; image-rendering:pixelated; border-radius:12px; }
125
+ #arcade-overlay .arcade-cue { min-height:0; font-size:16px; line-height:1.4; }
126
+ #arcade-overlay .arcade-score, #game-overlay .game-score, #game-overlay .game-result { margin:0; font-size:14px; line-height:1.4; text-align:center; color:inherit; }
127
+ #arcade-overlay .arcade-pause { width:auto; min-width:96px; padding:8px 16px; background:transparent; }
128
+ #arcade-overlay .arcade-exit, #game-overlay #guess-exit { box-sizing:border-box; margin:0; min-height:44px; padding:10px 16px; }
129
+ #arcade-overlay .arcade-instruction { max-width:100%; font-size:14px; line-height:1.5; }
130
+ #arcade-overlay .arcade-options { font-size:14px; min-height:36px; display:flex; align-items:center; gap:6px; }
@@ -0,0 +1,38 @@
1
+ import { now as clockNow } from './clock.js';
2
+ import { initializeWellbeing } from './wellbeing.js';
3
+ import { C } from './constants.js';
4
+ import { saveState, loadState, clearState, selectedCharacter } from './storage.js';
5
+
6
+ export class GameState {
7
+ constructor(choice=selectedCharacter){ Object.defineProperty(this,'preset',{value:choice}); this.reset(); }
8
+ reset(){
9
+ const now=clockNow();
10
+ Object.assign(this,{
11
+ stage:this.preset.stage, character:this.preset.character, age:0, weight:C.BASE_WT[this.preset.stage] || 5,
12
+ hunger:0, happiness:0, discipline:0,
13
+ careMistakes:0, poopCount:0,
14
+ isSick:false, isSleeping:false, lightOn:true,
15
+ isDead:false, isMisbehaving:false,
16
+ bornAt:now, stageStartTime:now, lastProcessed:now,
17
+ lastHungerDecay:now, lastHappyDecay:now,
18
+ lastPoopTime:now, lastAgeInc:now,
19
+ attentionCallTime:null, attentionReason:null,
20
+ snacksInWindow:0, snackWindowStart:now,
21
+ medDoses:0, prevTeen:null, sickCount:0,
22
+ energy:100, health:100, wellbeingUpdatedAt:now, careTotal:0, careDuration:0,
23
+ sleepOverride:'auto', sleepOverrideUntil:0,
24
+ vacationAt:0,
25
+ });
26
+ }
27
+ save(){ return saveState(this); }
28
+ load(){
29
+ // Leave known fields enumerable so the storage adapter can copy new saves.
30
+ this.energy=undefined; this.health=undefined; this.wellbeingUpdatedAt=undefined;
31
+ const loaded=loadState(this);
32
+ initializeWellbeing(this,this.lastProcessed);
33
+ return loaded;
34
+ }
35
+ clearSave(){ clearState(); }
36
+ }
37
+
38
+ export { Evo } from './evolution.js';
@@ -0,0 +1,46 @@
1
+ import { now as clockNow } from './clock.js';
2
+ import { C } from './constants.js';
3
+ import { isP2, evolveP2 } from './original-roster.js';
4
+ export const Evo = {
5
+ evolve(st){
6
+ if(isP2(st))return evolveP2(st);
7
+ switch(st.stage){
8
+ case 'egg': return {stage:'baby',character:'babytchi',weight:C.BASE_WT.baby};
9
+ case 'baby': return {stage:'child',character:'marutchi',weight:C.BASE_WT.child};
10
+ case 'child':
11
+ if(st.careMistakes<=1)
12
+ return {stage:'teen',character:'tamatchi',weight:C.BASE_WT.teen};
13
+ return {stage:'teen',character:'kuchitamatchi',weight:C.BASE_WT.teen};
14
+ case 'teen': return Evo.toAdult(st);
15
+ default: return null;
16
+ }
17
+ },
18
+ toAdult(st){
19
+ const d=st.discipline, cm=st.careMistakes;
20
+ if(st.character==='tamatchi'){
21
+ if(cm<=2&&d>=100) return {stage:'adult',character:'mametchi',weight:25};
22
+ if(cm<=2&&d>=75) return {stage:'adult',character:'ginjirotchi',weight:30};
23
+ if(cm<=4&&d>=50) return {stage:'adult',character:'maskutchi',weight:30};
24
+ if(d>=50) return {stage:'adult',character:'kuchipatchi',weight:35};
25
+ if(d>=25) return {stage:'adult',character:'nyorotchi',weight:30};
26
+ return {stage:'adult',character:'tarakotchi',weight:35};
27
+ }
28
+ if(d>=75) return {stage:'adult',character:'kuchipatchi',weight:35};
29
+ if(d>=50) return {stage:'adult',character:'nyorotchi',weight:30};
30
+ return {stage:'adult',character:'tarakotchi',weight:35};
31
+ },
32
+ shouldEvolve(st){
33
+ const e=clockNow()-st.stageStartTime;
34
+ switch(st.stage){
35
+ case 'egg': return e>=C.EGG_MS;
36
+ case 'baby': return e>=C.BABY_MS;
37
+ case 'child': return e>=C.CHILD_MS;
38
+ case 'teen': return e>=C.TEEN_MS;
39
+ default: return false;
40
+ }
41
+ },
42
+ checkOyajitchi(st){
43
+ return st.character==='maskutchi'&&st.discipline>=100&&st.age>=10;
44
+ }
45
+ };
46
+
@@ -0,0 +1,27 @@
1
+ export function visibleEnabledControl(node) {
2
+ if(node.disabled || node.hidden || node.closest?.('[hidden], [inert]'))return false;
3
+ if(node.getClientRects && !node.getClientRects().length)return false;
4
+ if(typeof getComputedStyle==='function' && getComputedStyle(node).visibility==='hidden')return false;
5
+ const closed=node.closest?.('details:not([open])');
6
+ return !closed || (node.tagName==='SUMMARY' && node.parentElement===closed);
7
+ }
8
+
9
+ export function overlayControls(overlay) {
10
+ const nodes=overlay.querySelectorAll?.('button, input, select, textarea, a[href], summary') || [overlay.querySelector?.('button')].filter(Boolean);
11
+ return [...nodes].filter(visibleEnabledControl);
12
+ }
13
+
14
+ // A game can focus its dialog rather than a button when a round starts.
15
+ export function trapOverlayTab(event,overlay,active=document.activeElement) {
16
+ if(event.key!=='Tab')return;
17
+ const controls=overlayControls(overlay);
18
+ const first=controls[0],last=controls.at(-1);
19
+ if(!controls.includes(active)){
20
+ event.preventDefault();
21
+ (event.shiftKey?last:first)?.focus();
22
+ }else if(event.shiftKey&&active===first){
23
+ event.preventDefault();last.focus();
24
+ }else if(!event.shiftKey&&active===last){
25
+ event.preventDefault();first.focus();
26
+ }
27
+ }
@@ -0,0 +1,185 @@
1
+ export const PF = {};
2
+ const _f = s => s.trim().split('\n').map(r => r.trim().split('').map(Number));
3
+ const FONT_DATA = {
4
+ A:`010
5
+ 101
6
+ 111
7
+ 101
8
+ 101`,B:`110
9
+ 101
10
+ 110
11
+ 101
12
+ 110`,C:`011
13
+ 100
14
+ 100
15
+ 100
16
+ 011`,D:`110
17
+ 101
18
+ 101
19
+ 101
20
+ 110`,E:`111
21
+ 100
22
+ 110
23
+ 100
24
+ 111`,F:`111
25
+ 100
26
+ 110
27
+ 100
28
+ 100`,G:`011
29
+ 100
30
+ 101
31
+ 101
32
+ 011`,H:`101
33
+ 101
34
+ 111
35
+ 101
36
+ 101`,I:`111
37
+ 010
38
+ 010
39
+ 010
40
+ 111`,J:`001
41
+ 001
42
+ 001
43
+ 101
44
+ 010`,K:`101
45
+ 110
46
+ 100
47
+ 110
48
+ 101`,L:`100
49
+ 100
50
+ 100
51
+ 100
52
+ 111`,M:`10001
53
+ 11011
54
+ 10101
55
+ 10001
56
+ 10001`,N:`101
57
+ 111
58
+ 111
59
+ 101
60
+ 101`,O:`010
61
+ 101
62
+ 101
63
+ 101
64
+ 010`,P:`110
65
+ 101
66
+ 110
67
+ 100
68
+ 100`,Q:`010
69
+ 101
70
+ 101
71
+ 011
72
+ 001`,R:`110
73
+ 101
74
+ 110
75
+ 101
76
+ 101`,S:`011
77
+ 100
78
+ 010
79
+ 001
80
+ 110`,T:`111
81
+ 010
82
+ 010
83
+ 010
84
+ 010`,U:`101
85
+ 101
86
+ 101
87
+ 101
88
+ 010`,V:`101
89
+ 101
90
+ 101
91
+ 010
92
+ 010`,W:`10001
93
+ 10001
94
+ 10101
95
+ 10101
96
+ 01010`,X:`101
97
+ 101
98
+ 010
99
+ 101
100
+ 101`,Y:`101
101
+ 101
102
+ 010
103
+ 010
104
+ 010`,Z:`111
105
+ 001
106
+ 010
107
+ 100
108
+ 111`,
109
+ '0':`111
110
+ 101
111
+ 101
112
+ 101
113
+ 111`,'1':`010
114
+ 110
115
+ 010
116
+ 010
117
+ 111`,'2':`110
118
+ 001
119
+ 010
120
+ 100
121
+ 111`,'3':`110
122
+ 001
123
+ 010
124
+ 001
125
+ 110`,'4':`101
126
+ 101
127
+ 111
128
+ 001
129
+ 001`,'5':`111
130
+ 100
131
+ 110
132
+ 001
133
+ 110`,'6':`011
134
+ 100
135
+ 110
136
+ 101
137
+ 010`,'7':`111
138
+ 001
139
+ 010
140
+ 010
141
+ 010`,'8':`010
142
+ 101
143
+ 010
144
+ 101
145
+ 010`,'9':`010
146
+ 101
147
+ 011
148
+ 001
149
+ 110`,
150
+ '%':`101
151
+ 001
152
+ 010
153
+ 100
154
+ 101`,'/':`001
155
+ 001
156
+ 010
157
+ 100
158
+ 100`,':':`0
159
+ 1
160
+ 0
161
+ 1
162
+ 0`,'!':`1
163
+ 1
164
+ 1
165
+ 0
166
+ 1`,'-':`000
167
+ 000
168
+ 111
169
+ 000
170
+ 000`,' ':`00
171
+ 00
172
+ 00
173
+ 00
174
+ 00`,'?':`110
175
+ 001
176
+ 010
177
+ 000
178
+ 010`,'.':`0
179
+ 0
180
+ 0
181
+ 0
182
+ 1`,
183
+ };
184
+ for(const[k,v] of Object.entries(FONT_DATA)) PF[k]=_f(v);
185
+