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,11 @@
1
+ const locks=new Set();
2
+ let originalOverflow;
3
+ export function lockPage(owner,root=document.documentElement) {
4
+ if(locks.has(owner))return;
5
+ if(!locks.size){originalOverflow=root.style.overflow;root.style.overflow='hidden';}
6
+ locks.add(owner);
7
+ }
8
+ export function unlockPage(owner,root=document.documentElement) {
9
+ if(!locks.delete(owner))return;
10
+ if(!locks.size)root.style.overflow=originalOverflow;
11
+ }
@@ -0,0 +1,48 @@
1
+ const actionIds=Object.freeze({vacation:'vacation-toggle',scanlines:'scanline-toggle',eink:'eink-toggle',mute:'mute-btn',reset:'reset-game-btn'});
2
+ export function configurationActionId(action,classic=true){
3
+ return typeof action==='string' && Object.hasOwn(actionIds,action) && (action!=='eink'||classic) ? actionIds[action] : null;
4
+ }
5
+ export function validConfiguration(value){
6
+ return !!value && ['vacation','scanlines','eink','muted','classic'].every(key=>typeof value[key]==='boolean');
7
+ }
8
+ export function mountSettings(container,sendCommand){
9
+ const doc=container.ownerDocument;
10
+ const rows=new Map();
11
+ const specs=[
12
+ ['vacation','Vacation','Pause care and growth until you return.'],
13
+ ['scanlines','LCD scanlines','Faint lines for an old LCD look.'],
14
+ ['eink','E ink theme','A simple black and white screen.'],
15
+ ['mute','Sound','Little sounds while you play.'],
16
+ ];
17
+ let ready=false,configuration=null;
18
+ for(const [action,label,description] of specs){
19
+ const row=doc.createElement('div');row.className='setting-row';
20
+ const copy=doc.createElement('div');copy.className='setting-copy';
21
+ const title=doc.createElement('strong');title.textContent=label;
22
+ const hint=doc.createElement('p');hint.textContent=description;copy.append(title,hint);
23
+ const button=doc.createElement('button');button.type='button';button.className='setting-toggle';
24
+ button.setAttribute('role','switch');button.setAttribute('aria-label',label);button.setAttribute('aria-checked','false');
25
+ const state=doc.createElement('span');state.setAttribute('aria-hidden','true');state.textContent='Off';button.append(state);
26
+ button.disabled=true;
27
+ button.addEventListener('click',()=>{if(ready&&configuration&&configurationActionId(action,configuration.classic))sendCommand(action);});
28
+ row.append(copy,button);container.append(row);rows.set(action,{row,button,state});
29
+ }
30
+ const reset=doc.createElement('div');reset.className='settings-reset';
31
+ const hint=doc.createElement('p');hint.textContent='Start fresh with this pet. You will be asked to confirm.';
32
+ const restart=doc.createElement('button');restart.type='button';restart.textContent='Start again';restart.disabled=true;
33
+ restart.addEventListener('click',()=>{if(ready&&configuration)sendCommand('reset');});
34
+ reset.append(hint,restart);container.append(reset);
35
+ function render(){
36
+ for(const [action,{row,button,state}] of rows){
37
+ row.hidden=action==='eink'&&!configuration?.classic;
38
+ const enabled=configuration ? action==='mute'?!configuration.muted:configuration[action] : false;
39
+ button.setAttribute('aria-checked',String(enabled));state.textContent=enabled?'On':'Off';
40
+ button.disabled=!ready||!configuration;
41
+ }
42
+ restart.disabled=!ready||!configuration;
43
+ }
44
+ return {
45
+ update(value){if(!validConfiguration(value))return;configuration={...value};render();},
46
+ setReady(value){ready=value===true;if(!ready)configuration=null;render();},
47
+ };
48
+ }
@@ -0,0 +1,63 @@
1
+ :host{--lilgotchi-surface:#121619;--lilgotchi-text:#eef1ed;--lilgotchi-accent:#d9bc83;--lilgotchi-spacing:18px;--lilgotchi-z:1000;font:14px/1.5 system-ui,sans-serif;color:var(--lilgotchi-text);color-scheme:dark}
2
+ *{box-sizing:border-box}button,select,input{font:inherit}button,select{color:inherit;background:#20262a;border:1px solid #46504f;border-radius:9px;padding:9px 12px;min-height:44px}button{cursor:pointer}button:focus-visible,select:focus-visible,summary:focus-visible,a:focus-visible{outline:2px solid var(--lilgotchi-accent);outline-offset:3px}button:disabled{cursor:wait;opacity:.6}
3
+ .launcher{position:fixed;right:var(--lilgotchi-spacing);bottom:calc(var(--lilgotchi-spacing) + env(safe-area-inset-bottom));z-index:var(--lilgotchi-z);width:64px;height:64px;border-radius:20px;box-shadow:0 5px 25px #0006;padding:2px}.launcher svg{width:100%;height:100%}
4
+ :host([placement=bottom-left]) .launcher{right:auto;left:var(--lilgotchi-spacing)}
5
+ dialog,.inline{color:var(--lilgotchi-text);background:var(--lilgotchi-surface);border:1px solid #46504f;border-radius:18px;padding:0 14px 12px;width:360px;max-width:calc(100vw - 24px);box-shadow:0 16px 60px #0008}
6
+ dialog{position:fixed;margin:0;inset:auto max(12px,var(--lilgotchi-spacing)) calc(12px + env(safe-area-inset-bottom)) auto;max-height:calc(100dvh - 24px - env(safe-area-inset-bottom));overflow:auto;overscroll-behavior:contain;z-index:var(--lilgotchi-z)}
7
+ dialog::backdrop{background:#06090a99}:host([placement=bottom-left]) dialog{left:12px;right:auto}.inline{max-width:100%;width:360px}
8
+ header{display:grid;grid-template-columns:1fr 44px;align-items:center;gap:5px 12px;padding:10px 0;background:var(--lilgotchi-surface);position:sticky;top:0;z-index:2;border-bottom:1px solid #343d3d}h2{font-size:18px;margin:0;letter-spacing:-.03em}.close{font-size:24px;padding:0}.chooser{grid-column:1/-1;display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:12px;color:#bdc8be}select{max-width:70%;min-width:150px}.frame{margin-top:10px;border-radius:10px;overflow:hidden}iframe{display:block;border:0;width:100%;height:340px;background:transparent}.status{font-size:12px;color:#bdc8be;min-height:18px;margin:10px 0}details{border-top:1px solid #343d3d}summary{cursor:pointer;min-height:44px;padding:12px 0;color:#d6ddd4;font-size:12px}.tools{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:14px}.tools button{font-size:12px;flex:1}footer{margin-top:10px;font-size:11px;color:#aeb9ae}a{color:var(--lilgotchi-accent);display:inline-block;min-height:44px;padding:12px 0}[hidden]{display:none!important}.error{color:#ffb3a1}.loading{padding:35px 8px;text-align:center;color:#bdc8be}.import{border:1px solid #46504f;border-radius:10px;padding:12px;margin-top:10px}.import p{margin-top:0}
9
+ @media(max-width:380px){dialog{right:12px;left:12px;padding-inline:10px;max-width:calc(100vw - 24px)}}
10
+ @media(prefers-reduced-motion:no-preference){dialog[open]{animation:appear .2s ease-out}@keyframes appear{from{transform:translateY(18px);opacity:0}to{transform:translateY(0);opacity:1}}}
11
+ /* Host chrome stays readable independently of the pet palette. */
12
+ .care-dot{position:absolute;right:5px;top:5px;width:12px;height:12px;border:2px solid var(--lilgotchi-surface);border-radius:50%;background:#ffcb83}
13
+ .welcome,.return-summary{font-size:13px;line-height:1.6;border:1px solid #46504f;border-radius:10px;padding:12px;margin:12px 0;color:var(--lilgotchi-text)}
14
+ .welcome p{margin:0 0 8px}.welcome button{font-size:13px}.status{transition:color .2s}.status.saved{color:#9de4ce}
15
+ @media(prefers-reduced-motion:reduce){.status{transition:none}}
16
+ :host([appearance=light]){--lilgotchi-surface:#f5f2e9;--lilgotchi-text:#202921;--lilgotchi-accent:#426847;color-scheme:light}
17
+ :host([appearance=light]) button,:host([appearance=light]) select{background:#e5e8df;color:#202921;border-color:#7b887a}
18
+ :host([appearance=light]) .chooser,:host([appearance=light]) .status,:host([appearance=light]) summary,:host([appearance=light]) footer{color:#354736}
19
+ :host([appearance=light]) .status.saved{color:#24612b}
20
+ .care-guide-content{font-size:14px;line-height:1.65;padding:0 2px 14px}.care-guide-content h3{font-size:16px;margin:4px 0 10px}.care-guide-progress{font-size:12px;color:var(--lilgotchi-accent)}.care-guide-controls{display:flex;flex-wrap:wrap;gap:8px}.care-guide-controls button{font-size:13px;min-height:44px}.care-guide-content h3:focus{outline:2px solid var(--lilgotchi-accent);outline-offset:3px}.history-list{padding-left:22px;font-size:14px;line-height:1.8}.history-status{font-size:14px;line-height:1.6}
21
+
22
+ /* Keep the next iframe's initial blank document out of view while it boots. */
23
+ .frame{position:relative;background:#121619}
24
+ iframe{background:#121619;color-scheme:dark}
25
+ .frame.is-loading::after{content:'Loading your pet…';position:absolute;inset:0;display:grid;place-content:center;color:#bdc8be;font-size:13px;pointer-events:none}
26
+ .save-help>summary{display:flex;align-items:baseline;justify-content:space-between;gap:8px;list-style:none}
27
+ .save-help>summary::-webkit-details-marker{display:none}
28
+ .save-label{white-space:nowrap}
29
+ .save-label::before{content:'▸';display:inline-block;width:12px}
30
+ .save-help[open]>summary .save-label::before{content:'▾'}
31
+ .save-help>summary .status{margin:0;text-align:right;font-size:11px;min-width:0;overflow-wrap:anywhere}
32
+ .chooser .pet-identity{font-size:13px;font-weight:600;color:var(--lilgotchi-text);line-height:1.4}
33
+ .chooser select{min-width:120px;max-width:48%}
34
+ .chooser select{appearance:none;padding-right:44px;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='10' viewBox='0 0 14 10'%3E%3Cpath d='m2 3 5 5 5-5' fill='none' stroke='%23bdc8be' stroke-width='1.5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 16px center}
35
+ :host([appearance=light]) .chooser select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='10' viewBox='0 0 14 10'%3E%3Cpath d='m2 3 5 5 5-5' fill='none' stroke='%23202921' stroke-width='1.5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 16px center}
36
+ .retry{display:block;margin:0 auto 20px}
37
+
38
+ .game-options{padding:0 0 14px}
39
+ .setting-row{display:flex;align-items:center;justify-content:space-between;gap:18px;padding:12px 0;border-bottom:1px solid #343d3d}
40
+ .setting-copy strong{font-size:13px;font-weight:600}.setting-copy p,.settings-reset p{font-size:12px;line-height:1.5;color:#bdc8be;margin:4px 0 0}
41
+ .setting-toggle{flex:none;min-width:58px;font-size:12px;font-weight:600}.setting-toggle[aria-checked=true]{background:#314a40;border-color:#8ab49b;color:#effff5}
42
+ .settings-reset{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:14px 0 4px}.settings-reset p{margin:0;max-width:21ch}.settings-reset button{flex:none;font-size:12px}
43
+ .settings-close{width:100%;margin:8px 0 0;font-size:13px}
44
+ :host([appearance=light]) .setting-copy p,:host([appearance=light]) .settings-reset p{color:#354736}
45
+
46
+ :host([launcher=pet]) .launcher{width:auto;display:flex;align-items:center;gap:9px;padding:10px 14px}
47
+ :host([launcher=pet]) .launcher svg{width:32px;height:36px;flex:none}.launcher-label{font-size:14px;font-weight:600}
48
+
49
+ /* Top corner drawers unfold downward from their launcher. */
50
+ :host([placement=top-left]) .launcher,:host([placement=top-right]) .launcher{top:calc(var(--lilgotchi-spacing) + env(safe-area-inset-top));bottom:auto}
51
+ :host([placement=top-left]) .launcher{left:var(--lilgotchi-spacing);right:auto}
52
+ :host([placement=top-left]) dialog,:host([placement=top-right]) dialog{top:calc(12px + env(safe-area-inset-top));bottom:auto;max-height:calc(100dvh - 24px - env(safe-area-inset-top) - env(safe-area-inset-bottom))}
53
+ :host([placement=top-left]) dialog{left:12px;right:auto}
54
+ @media(prefers-reduced-motion:no-preference){:host([placement=top-left]) dialog[open],:host([placement=top-right]) dialog[open]{animation-name:appear-down}@keyframes appear-down{from{transform:translateY(-18px);opacity:0}to{transform:translateY(0);opacity:1}}}
55
+
56
+ :host .launcher.brand-launcher{width:auto;height:52px;display:flex;align-items:center;gap:8px;padding:10px 16px;border-radius:16px}
57
+ :host .launcher.brand-launcher .brand-egg{width:22px;height:28px;image-rendering:pixelated;flex:none}
58
+ :host .launcher.brand-launcher .launcher-label{font-size:28px;font-weight:800;letter-spacing:-.04em;line-height:1}
59
+ .care-badge{position:absolute;top:3px;right:3px;min-width:23px;height:23px;padding:0 5px;border:2px solid var(--lilgotchi-surface);border-radius:20px;background:#ffcb83;color:#252016;font-size:12px;font-weight:700;line-height:19px;text-align:center}
60
+ .care-needs{margin-top:0;border-top:0}.care-needs summary{font-size:13px}.needs-list{display:grid;gap:6px;padding-bottom:10px}.needs-list button{text-align:left;font-size:12px}
61
+
62
+ .inactive-card{text-align:center;padding:32px 16px}.inactive-card h3{font-size:18px}.inactive-card p{color:#bdc8be;line-height:1.6}.make-inactive{flex:none;font-size:12px}.inactive-option{margin-bottom:12px}:host([appearance=light]) .inactive-card p{color:#354736}
63
+ .color-options{padding:16px 0;border-top:1px solid #343c48}.color-options p{font-size:12px;margin:8px 0;color:#bdc8be}.color-choice{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:10px 0;font-size:13px}.color-choice input{width:64px;height:44px;padding:4px;border:1px solid #667486;border-radius:8px;background:transparent}.color-options>button{margin-top:8px}
package/package.json CHANGED
@@ -1,6 +1,43 @@
1
- {
2
- "name": "lilgotchi",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
1
+ {
2
+ "name": "lilgotchi",
3
+ "version": "3.0.2",
4
+ "license": "MIT",
5
+ "author": "Taylor Dorsett",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/TaylorOD/lilgotchi.git"
9
+ },
10
+ "homepage": "https://www.taylordorsett.com/lilgotchi/",
11
+ "files": [
12
+ "dist",
13
+ "LICENSE.md",
14
+ "README.md"
15
+ ],
16
+ "exports": {
17
+ ".": "./dist/lilgotchi.js",
18
+ "./embed.js": "./dist/embed.js",
19
+ "./dist/*": "./dist/*"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "type": "module",
25
+ "description": "A little pixel pet for your website",
26
+ "scripts": {
27
+ "start": "node scripts/serve.mjs",
28
+ "test": "node --test pets/game.test.mjs tests/*.test.mjs",
29
+ "inventory": "node scripts/inventory.mjs",
30
+ "build": "node scripts/build.mjs",
31
+ "prepack": "npm run build"
32
+ },
33
+ "keywords": [
34
+ "virtual-pet",
35
+ "tamagotchi",
36
+ "web-component",
37
+ "pixel-art",
38
+ "website-widget"
39
+ ],
40
+ "bugs": {
41
+ "url": "https://github.com/TaylorOD/lilgotchi/issues"
42
+ }
43
+ }