frogoe 0.1.0
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.
- package/bin/frogoe.mjs +11 -0
- package/dist/cli.js +3124 -0
- package/dist/contract/contract.js +236 -0
- package/dist/registry/blocks/coin-counter/coin-counter.html +101 -0
- package/dist/registry/blocks/coin-counter/registry-item.json +27 -0
- package/dist/registry/blocks/combo-counter/combo-counter.html +106 -0
- package/dist/registry/blocks/combo-counter/registry-item.json +27 -0
- package/dist/registry/blocks/fuel-gauge/fuel-gauge.html +130 -0
- package/dist/registry/blocks/fuel-gauge/registry-item.json +29 -0
- package/dist/registry/blocks/game-over-card/game-over-card.html +185 -0
- package/dist/registry/blocks/game-over-card/registry-item.json +30 -0
- package/dist/registry/blocks/hearts-row/hearts-row.html +92 -0
- package/dist/registry/blocks/hearts-row/registry-item.json +27 -0
- package/dist/registry/blocks/mini-board/mini-board.html +125 -0
- package/dist/registry/blocks/mini-board/registry-item.json +28 -0
- package/dist/registry/blocks/objective-chip/objective-chip.html +101 -0
- package/dist/registry/blocks/objective-chip/registry-item.json +29 -0
- package/dist/registry/blocks/ready-gate/ready-gate.html +124 -0
- package/dist/registry/blocks/ready-gate/registry-item.json +28 -0
- package/dist/registry/blocks/ready-hint/ready-hint.html +104 -0
- package/dist/registry/blocks/ready-hint/registry-item.json +29 -0
- package/dist/registry/blocks/score-card/registry-item.json +27 -0
- package/dist/registry/blocks/score-card/score-card.html +92 -0
- package/dist/registry/blocks/timer-ring/registry-item.json +28 -0
- package/dist/registry/blocks/timer-ring/timer-ring.html +123 -0
- package/dist/registry/registry.json +51 -0
- package/dist/registry/schema/registry-item.schema.json +36 -0
- package/dist/registry/schema/registry.schema.json +22 -0
- package/dist/runtimeVersion.js +10 -0
- package/dist/templates/_shared/AGENTS.md +105 -0
- package/dist/templates/_shared/CLAUDE.md +105 -0
- package/package.json +42 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<!-- frogoe block source: game-over-card — this file IS viewable in a browser (default
|
|
3
|
+
state on a neutral backdrop). Copy ONLY between the markers into your
|
|
4
|
+
game's blocks/ layer; the interactive playground is demo.html. -->
|
|
5
|
+
<html lang="en">
|
|
6
|
+
<head>
|
|
7
|
+
<meta charset="utf-8" />
|
|
8
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
9
|
+
<title>frogoe block — game-over-card</title>
|
|
10
|
+
<style>
|
|
11
|
+
body {
|
|
12
|
+
margin: 0;
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
display: grid;
|
|
15
|
+
place-items: center;
|
|
16
|
+
background: radial-gradient(120% 120% at 50% 0%, #182031 0%, #0d1220 60%, #080b13 100%);
|
|
17
|
+
}
|
|
18
|
+
</style>
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<!-- ===================== COPY FROM HERE ===================== -->
|
|
22
|
+
<!--
|
|
23
|
+
frogoe block: game-over-card
|
|
24
|
+
End-of-run card: title, score, best, one chunky retry button. Hidden by
|
|
25
|
+
default; the game shows it on death and wires the button to restart.
|
|
26
|
+
Entrance pops in; NEW BEST state is a data attribute that flips the
|
|
27
|
+
subtitle and tints the accent.
|
|
28
|
+
|
|
29
|
+
Bind from game.js (vanilla, no helper):
|
|
30
|
+
const card = document.querySelector("[data-block-gameover]");
|
|
31
|
+
card.querySelector("[data-block-final]").textContent = score;
|
|
32
|
+
card.querySelector("[data-block-best]").textContent = best;
|
|
33
|
+
card.toggleAttribute("data-new-best", isNewBest);
|
|
34
|
+
card.showModal === undefined; // it is a plain overlay:
|
|
35
|
+
card.toggleAttribute("data-open", true);
|
|
36
|
+
card.querySelector("[data-block-retry]").addEventListener("click", () => {
|
|
37
|
+
location.reload(); // or your own reset
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
Theme: --block-card, --block-accent, --block-cta, --block-cta-label, --block-font.
|
|
41
|
+
-->
|
|
42
|
+
<style>
|
|
43
|
+
.block-game-over {
|
|
44
|
+
--block-accent: #ffd166;
|
|
45
|
+
--block-card: #171d2e;
|
|
46
|
+
--block-cta: #ffcf3f;
|
|
47
|
+
--block-cta-label: #241a06;
|
|
48
|
+
--block-font: "Fredoka", "Baloo 2", system-ui, sans-serif;
|
|
49
|
+
--block-outline: #0a0e1a;
|
|
50
|
+
|
|
51
|
+
position: absolute;
|
|
52
|
+
inset: 0;
|
|
53
|
+
display: grid;
|
|
54
|
+
place-items: center;
|
|
55
|
+
background: rgba(4, 6, 12, 0.55);
|
|
56
|
+
font-family: var(--block-font);
|
|
57
|
+
color: #fffdf7;
|
|
58
|
+
opacity: 0;
|
|
59
|
+
pointer-events: none;
|
|
60
|
+
transition: opacity 220ms ease;
|
|
61
|
+
-webkit-user-select: none;
|
|
62
|
+
user-select: none;
|
|
63
|
+
}
|
|
64
|
+
.block-game-over[data-open] {
|
|
65
|
+
opacity: 1;
|
|
66
|
+
pointer-events: auto;
|
|
67
|
+
}
|
|
68
|
+
.block-game-over__card {
|
|
69
|
+
display: grid;
|
|
70
|
+
justify-items: center;
|
|
71
|
+
gap: 0.35em;
|
|
72
|
+
min-width: min(78vw, 20rem);
|
|
73
|
+
padding: 2rem 2.4rem 2.2rem;
|
|
74
|
+
background: var(--block-card);
|
|
75
|
+
border: 2px solid rgba(255, 255, 255, 0.12);
|
|
76
|
+
border-radius: 1.6rem;
|
|
77
|
+
box-shadow: 0 1.2rem 3rem rgba(0, 0, 0, 0.45);
|
|
78
|
+
text-align: center;
|
|
79
|
+
}
|
|
80
|
+
.block-game-over[data-open] .block-game-over__card {
|
|
81
|
+
animation: block-card-in 320ms cubic-bezier(0.34, 1.56, 0.5, 1);
|
|
82
|
+
}
|
|
83
|
+
@keyframes block-card-in {
|
|
84
|
+
from {
|
|
85
|
+
transform: translateY(1.2rem) scale(0.92);
|
|
86
|
+
opacity: 0;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
.block-game-over__title {
|
|
90
|
+
font-size: clamp(1.6rem, 7vmin, 2.4rem);
|
|
91
|
+
font-weight: 700;
|
|
92
|
+
letter-spacing: 0.06em;
|
|
93
|
+
text-shadow: 0 3px 0 var(--block-outline);
|
|
94
|
+
}
|
|
95
|
+
.block-game-over__subtitle {
|
|
96
|
+
font-size: 0.9rem;
|
|
97
|
+
font-weight: 600;
|
|
98
|
+
letter-spacing: 0.28em;
|
|
99
|
+
text-transform: uppercase;
|
|
100
|
+
opacity: 0.6;
|
|
101
|
+
}
|
|
102
|
+
.block-game-over[data-new-best] .block-game-over__subtitle {
|
|
103
|
+
color: var(--block-accent);
|
|
104
|
+
opacity: 1;
|
|
105
|
+
animation: block-best-pulse 800ms ease-in-out infinite alternate;
|
|
106
|
+
}
|
|
107
|
+
@keyframes block-best-pulse {
|
|
108
|
+
from {
|
|
109
|
+
opacity: 1;
|
|
110
|
+
}
|
|
111
|
+
to {
|
|
112
|
+
opacity: 0.55;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
.block-game-over__score {
|
|
116
|
+
font-size: clamp(2.6rem, 12vmin, 4rem);
|
|
117
|
+
font-weight: 700;
|
|
118
|
+
font-variant-numeric: tabular-nums;
|
|
119
|
+
line-height: 1.1;
|
|
120
|
+
text-shadow: 0 4px 0 var(--block-outline);
|
|
121
|
+
}
|
|
122
|
+
.block-game-over__best {
|
|
123
|
+
font-size: 0.95rem;
|
|
124
|
+
font-weight: 600;
|
|
125
|
+
opacity: 0.75;
|
|
126
|
+
}
|
|
127
|
+
.block-game-over__retry {
|
|
128
|
+
margin-top: 0.9em;
|
|
129
|
+
font-family: inherit;
|
|
130
|
+
font-size: 1.05rem;
|
|
131
|
+
font-weight: 700;
|
|
132
|
+
letter-spacing: 0.12em;
|
|
133
|
+
text-transform: uppercase;
|
|
134
|
+
color: var(--block-cta-label);
|
|
135
|
+
background: var(--block-cta);
|
|
136
|
+
border: none;
|
|
137
|
+
border-radius: 999px;
|
|
138
|
+
padding: 0.85em 2.6em;
|
|
139
|
+
cursor: pointer;
|
|
140
|
+
/* chunky button: hard extrusion under, push-in on press */
|
|
141
|
+
box-shadow: 0 5px 0 color-mix(in srgb, var(--block-cta) 62%, black);
|
|
142
|
+
transition:
|
|
143
|
+
transform 80ms ease,
|
|
144
|
+
box-shadow 80ms ease;
|
|
145
|
+
}
|
|
146
|
+
.block-game-over__retry:active {
|
|
147
|
+
transform: translateY(4px);
|
|
148
|
+
box-shadow: 0 1px 0 color-mix(in srgb, var(--block-cta) 62%, black);
|
|
149
|
+
}
|
|
150
|
+
@media (prefers-reduced-motion: reduce) {
|
|
151
|
+
.block-game-over[data-open] .block-game-over__card {
|
|
152
|
+
animation: none;
|
|
153
|
+
}
|
|
154
|
+
.block-game-over[data-new-best] .block-game-over__subtitle {
|
|
155
|
+
animation: none;
|
|
156
|
+
}
|
|
157
|
+
.block-game-over {
|
|
158
|
+
transition: none;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
</style>
|
|
162
|
+
|
|
163
|
+
<div class="block-game-over" data-block-gameover>
|
|
164
|
+
<div class="block-game-over__card">
|
|
165
|
+
<span class="block-game-over__title">Run Over</span>
|
|
166
|
+
<span class="block-game-over__subtitle" data-block-subtitle>Score</span>
|
|
167
|
+
<span class="block-game-over__score" data-block-final>0</span>
|
|
168
|
+
<span class="block-game-over__best">Best <b data-block-best>0</b></span>
|
|
169
|
+
<button class="block-game-over__retry" type="button" data-block-retry>Retry</button>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
<!-- ===================== COPY TO HERE ======================= -->
|
|
173
|
+
|
|
174
|
+
<!-- preview-only: games toggle data-open themselves; this script exists so
|
|
175
|
+
the source file shows its open state when opened directly -->
|
|
176
|
+
<script type="module">
|
|
177
|
+
const card = document.querySelector("[data-block-gameover]");
|
|
178
|
+
card.toggleAttribute("data-open", true);
|
|
179
|
+
card.querySelector("[data-block-retry]").addEventListener("click", () => {
|
|
180
|
+
card.toggleAttribute("data-open", false);
|
|
181
|
+
setTimeout(() => card.toggleAttribute("data-open", true), 700);
|
|
182
|
+
});
|
|
183
|
+
</script>
|
|
184
|
+
</body>
|
|
185
|
+
</html>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../schema/registry-item.schema.json",
|
|
3
|
+
"name": "game-over-card",
|
|
4
|
+
"type": "frogoe:block",
|
|
5
|
+
"title": "Game Over Card",
|
|
6
|
+
"description": "End-of-run overlay: title, score, best, NEW BEST state, chunky retry button with press feedback; themeable via --block-*",
|
|
7
|
+
"tags": [
|
|
8
|
+
"hud",
|
|
9
|
+
"game-over",
|
|
10
|
+
"results",
|
|
11
|
+
"retry"
|
|
12
|
+
],
|
|
13
|
+
"files": [
|
|
14
|
+
{
|
|
15
|
+
"path": "game-over-card.html",
|
|
16
|
+
"target": "blocks/game-over-card.html",
|
|
17
|
+
"type": "frogoe:markup"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"bindings": [
|
|
21
|
+
"data-block-gameover",
|
|
22
|
+
"data-block-final",
|
|
23
|
+
"data-block-best",
|
|
24
|
+
"data-block-retry"
|
|
25
|
+
],
|
|
26
|
+
"placement": "overlay-fullscreen",
|
|
27
|
+
"preview": {
|
|
28
|
+
"demo": "demo.html"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<!-- frogoe block source: hearts-row — this file IS viewable in a browser (default
|
|
3
|
+
state on a neutral backdrop). Copy ONLY between the markers into your
|
|
4
|
+
game's blocks/ layer; the interactive playground is demo.html. -->
|
|
5
|
+
<html lang="en">
|
|
6
|
+
<head>
|
|
7
|
+
<meta charset="utf-8" />
|
|
8
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
9
|
+
<title>frogoe block — hearts-row</title>
|
|
10
|
+
<style>
|
|
11
|
+
body {
|
|
12
|
+
margin: 0;
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
display: grid;
|
|
15
|
+
place-items: center;
|
|
16
|
+
background: radial-gradient(120% 120% at 50% 0%, #182031 0%, #0d1220 60%, #080b13 100%);
|
|
17
|
+
}
|
|
18
|
+
</style>
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<!-- ===================== COPY FROM HERE ===================== -->
|
|
22
|
+
<!--
|
|
23
|
+
frogoe block: hearts-row
|
|
24
|
+
Lives / health as a row of hearts. Filled hearts on the left, lost hearts
|
|
25
|
+
ghost on the right; a lost heart pops as it empties.
|
|
26
|
+
|
|
27
|
+
Bind from game.js (vanilla, no helper):
|
|
28
|
+
const row = document.querySelector("[data-block-hearts]");
|
|
29
|
+
row.dataset.value = String(lives); // hearts shown as full
|
|
30
|
+
// data-block-hearts element carries: data-value (full), data-max (slots)
|
|
31
|
+
|
|
32
|
+
Theme: --block-heart (fill), --block-heart-empty (ghost), --block-outline.
|
|
33
|
+
-->
|
|
34
|
+
<style>
|
|
35
|
+
.block-hearts-row {
|
|
36
|
+
--block-gap: 0.5em;
|
|
37
|
+
--block-heart: #ff4d6d;
|
|
38
|
+
--block-heart-empty: rgba(255, 255, 255, 0.18);
|
|
39
|
+
--block-outline: #33101d;
|
|
40
|
+
--block-size: clamp(1.4rem, 5vmin, 2rem);
|
|
41
|
+
|
|
42
|
+
display: flex;
|
|
43
|
+
gap: var(--block-gap);
|
|
44
|
+
pointer-events: none;
|
|
45
|
+
-webkit-user-select: none;
|
|
46
|
+
user-select: none;
|
|
47
|
+
}
|
|
48
|
+
.block-hearts-row__heart {
|
|
49
|
+
width: var(--block-size);
|
|
50
|
+
height: var(--block-size);
|
|
51
|
+
background: var(--block-heart);
|
|
52
|
+
/* heart silhouette — no icon font, no image */
|
|
53
|
+
-webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z'/></svg>")
|
|
54
|
+
center / contain no-repeat;
|
|
55
|
+
mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z'/></svg>")
|
|
56
|
+
center / contain no-repeat;
|
|
57
|
+
filter: drop-shadow(0 2px 0 var(--block-outline)) drop-shadow(0 4px 6px rgba(0, 0, 0, 0.3));
|
|
58
|
+
transition:
|
|
59
|
+
opacity 160ms ease,
|
|
60
|
+
transform 160ms ease;
|
|
61
|
+
}
|
|
62
|
+
.block-hearts-row__heart[aria-hidden="true"] {
|
|
63
|
+
background: var(--block-heart-empty);
|
|
64
|
+
filter: drop-shadow(0 2px 0 rgba(0, 0, 0, 0.25));
|
|
65
|
+
transform: scale(0.86);
|
|
66
|
+
animation: block-heart-pop 320ms cubic-bezier(0.34, 1.8, 0.5, 1);
|
|
67
|
+
}
|
|
68
|
+
@keyframes block-heart-pop {
|
|
69
|
+
from {
|
|
70
|
+
transform: scale(1.35) rotate(-8deg);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
@media (prefers-reduced-motion: reduce) {
|
|
74
|
+
.block-hearts-row__heart,
|
|
75
|
+
.block-hearts-row__heart[aria-hidden="true"] {
|
|
76
|
+
animation: none;
|
|
77
|
+
transition: none;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
</style>
|
|
81
|
+
|
|
82
|
+
<div class="block-hearts-row" data-block-hearts data-value="3" data-max="3">
|
|
83
|
+
<span class="block-hearts-row__heart"></span>
|
|
84
|
+
<span class="block-hearts-row__heart"></span>
|
|
85
|
+
<span class="block-hearts-row__heart"></span>
|
|
86
|
+
<!-- hearts are managed by the game script: set data-value, then update
|
|
87
|
+
each child's aria-hidden (full: remove; lost: set). Demo shows the
|
|
88
|
+
six-line binder. More slots? Add more <span> children. -->
|
|
89
|
+
</div>
|
|
90
|
+
<!-- ===================== COPY TO HERE ======================= -->
|
|
91
|
+
</body>
|
|
92
|
+
</html>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../schema/registry-item.schema.json",
|
|
3
|
+
"name": "hearts-row",
|
|
4
|
+
"type": "frogoe:block",
|
|
5
|
+
"title": "Hearts Row",
|
|
6
|
+
"description": "Lives as a row of hearts (clip-path silhouettes); lost hearts ghost with a pop, reduced-motion safe; themeable via --block-*",
|
|
7
|
+
"tags": [
|
|
8
|
+
"hud",
|
|
9
|
+
"lives",
|
|
10
|
+
"health",
|
|
11
|
+
"hearts"
|
|
12
|
+
],
|
|
13
|
+
"files": [
|
|
14
|
+
{
|
|
15
|
+
"path": "hearts-row.html",
|
|
16
|
+
"target": "blocks/hearts-row.html",
|
|
17
|
+
"type": "frogoe:markup"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"bindings": [
|
|
21
|
+
"data-block-hearts"
|
|
22
|
+
],
|
|
23
|
+
"placement": "overlay",
|
|
24
|
+
"preview": {
|
|
25
|
+
"demo": "demo.html"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<!-- frogoe block source: mini-board — this file IS viewable in a browser (default
|
|
3
|
+
state on a neutral backdrop). Copy ONLY between the markers into your
|
|
4
|
+
game's blocks/ layer; the interactive playground is demo.html. -->
|
|
5
|
+
<html lang="en">
|
|
6
|
+
<head>
|
|
7
|
+
<meta charset="utf-8" />
|
|
8
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
9
|
+
<title>frogoe block — mini-board</title>
|
|
10
|
+
<style>
|
|
11
|
+
body {
|
|
12
|
+
margin: 0;
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
display: grid;
|
|
15
|
+
place-items: center;
|
|
16
|
+
background: radial-gradient(120% 120% at 50% 0%, #182031 0%, #0d1220 60%, #080b13 100%);
|
|
17
|
+
}
|
|
18
|
+
</style>
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<!-- ===================== COPY FROM HERE ===================== -->
|
|
22
|
+
<!--
|
|
23
|
+
frogoe block: mini-board
|
|
24
|
+
Top-3 scores in a compact board — the "one more run" social proof. Seeds
|
|
25
|
+
are ORGANIC numbers by doctrine: never round slop (1234567), never
|
|
26
|
+
fake-perfect (99.99%). The player's row is marked; new bests glow once.
|
|
27
|
+
|
|
28
|
+
Bind from game.js (vanilla, no helper):
|
|
29
|
+
const board = document.querySelector("[data-block-board]");
|
|
30
|
+
board.querySelector("[data-block-board-r1-score]").textContent = "1,283";
|
|
31
|
+
// rows r1..r3: name + score; [data-block-board-you] marks the player row.
|
|
32
|
+
board.toggleAttribute("data-hidden", false);
|
|
33
|
+
|
|
34
|
+
Theme: --block-accent, --block-fg, --block-outline, --block-chip.
|
|
35
|
+
-->
|
|
36
|
+
<style>
|
|
37
|
+
.block-board {
|
|
38
|
+
--block-accent: #ffd166;
|
|
39
|
+
--block-chip: rgba(12, 16, 30, 0.55);
|
|
40
|
+
--block-fg: #fffdf7;
|
|
41
|
+
--block-font: "Fredoka", "Baloo 2", system-ui, sans-serif;
|
|
42
|
+
--block-outline: #26180a;
|
|
43
|
+
|
|
44
|
+
display: grid;
|
|
45
|
+
gap: 2px; /* razor rows: contrast gap, not borders */
|
|
46
|
+
min-width: 11rem;
|
|
47
|
+
padding: 0.7em 0.9em;
|
|
48
|
+
background: var(--block-chip);
|
|
49
|
+
border: 2px solid rgba(255, 255, 255, 0.14);
|
|
50
|
+
border-radius: 1rem;
|
|
51
|
+
color: var(--block-fg);
|
|
52
|
+
font-family: var(--block-font);
|
|
53
|
+
pointer-events: none;
|
|
54
|
+
-webkit-user-select: none;
|
|
55
|
+
user-select: none;
|
|
56
|
+
}
|
|
57
|
+
.block-board__row {
|
|
58
|
+
display: grid;
|
|
59
|
+
grid-template-columns: auto 1fr auto;
|
|
60
|
+
align-items: baseline;
|
|
61
|
+
gap: 0.6em;
|
|
62
|
+
padding: 0.25em 0.3em;
|
|
63
|
+
font-size: 0.95rem;
|
|
64
|
+
}
|
|
65
|
+
.block-board__row + .block-board__row {
|
|
66
|
+
background: rgba(255, 255, 255, 0.05);
|
|
67
|
+
}
|
|
68
|
+
.block-board__rank {
|
|
69
|
+
font-weight: 700;
|
|
70
|
+
opacity: 0.6;
|
|
71
|
+
font-variant-numeric: tabular-nums;
|
|
72
|
+
}
|
|
73
|
+
.block-board__name {
|
|
74
|
+
font-weight: 600;
|
|
75
|
+
overflow: hidden;
|
|
76
|
+
text-overflow: ellipsis;
|
|
77
|
+
white-space: nowrap;
|
|
78
|
+
}
|
|
79
|
+
.block-board__score {
|
|
80
|
+
font-weight: 700;
|
|
81
|
+
font-variant-numeric: tabular-nums;
|
|
82
|
+
text-shadow: 0 1px 0 var(--block-outline);
|
|
83
|
+
}
|
|
84
|
+
.block-board__row[data-block-board-you] {
|
|
85
|
+
background: color-mix(in srgb, var(--block-accent) 16%, transparent);
|
|
86
|
+
}
|
|
87
|
+
.block-board__row[data-block-board-you] .block-board__name {
|
|
88
|
+
color: var(--block-accent);
|
|
89
|
+
}
|
|
90
|
+
.block-board[data-fresh-best] .block-board__row[data-block-board-you] .block-board__score {
|
|
91
|
+
animation: block-board-best 700ms cubic-bezier(0.34, 1.8, 0.5, 1);
|
|
92
|
+
}
|
|
93
|
+
@keyframes block-board-best {
|
|
94
|
+
from {
|
|
95
|
+
transform: scale(1.35);
|
|
96
|
+
color: var(--block-accent);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
@media (prefers-reduced-motion: reduce) {
|
|
100
|
+
.block-board[data-fresh-best] .block-board__row[data-block-board-you] .block-board__score {
|
|
101
|
+
animation: none;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
</style>
|
|
105
|
+
|
|
106
|
+
<div class="block-board" data-block-board>
|
|
107
|
+
<div class="block-board__row">
|
|
108
|
+
<span class="block-board__rank">1</span>
|
|
109
|
+
<span class="block-board__name" data-block-board-r1-name>muja</span>
|
|
110
|
+
<span class="block-board__score" data-block-board-r1-score>1,283</span>
|
|
111
|
+
</div>
|
|
112
|
+
<div class="block-board__row">
|
|
113
|
+
<span class="block-board__rank">2</span>
|
|
114
|
+
<span class="block-board__name" data-block-board-r2-name>kiri</span>
|
|
115
|
+
<span class="block-board__score" data-block-board-r2-score>947</span>
|
|
116
|
+
</div>
|
|
117
|
+
<div class="block-board__row" data-block-board-you>
|
|
118
|
+
<span class="block-board__rank">3</span>
|
|
119
|
+
<span class="block-board__name" data-block-board-r3-name>you</span>
|
|
120
|
+
<span class="block-board__score" data-block-board-r3-score>512</span>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
<!-- ===================== COPY TO HERE ======================= -->
|
|
124
|
+
</body>
|
|
125
|
+
</html>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../schema/registry-item.schema.json",
|
|
3
|
+
"name": "mini-board",
|
|
4
|
+
"type": "frogoe:block",
|
|
5
|
+
"title": "Mini Board",
|
|
6
|
+
"description": "Top-3 leaderboard chip with organic seed numbers, player-row highlight, and a fresh-best pop; themeable via --block-*",
|
|
7
|
+
"tags": [
|
|
8
|
+
"hud",
|
|
9
|
+
"leaderboard",
|
|
10
|
+
"scores",
|
|
11
|
+
"social-proof"
|
|
12
|
+
],
|
|
13
|
+
"files": [
|
|
14
|
+
{
|
|
15
|
+
"path": "mini-board.html",
|
|
16
|
+
"target": "blocks/mini-board.html",
|
|
17
|
+
"type": "frogoe:markup"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"bindings": [
|
|
21
|
+
"data-block-board",
|
|
22
|
+
"data-block-board-you"
|
|
23
|
+
],
|
|
24
|
+
"placement": "overlay",
|
|
25
|
+
"preview": {
|
|
26
|
+
"demo": "demo.html"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<!-- frogoe block source: objective-chip — this file IS viewable in a browser (default
|
|
3
|
+
state on a neutral backdrop). Copy ONLY between the markers into your
|
|
4
|
+
game's blocks/ layer; the interactive playground is demo.html. -->
|
|
5
|
+
<html lang="en">
|
|
6
|
+
<head>
|
|
7
|
+
<meta charset="utf-8" />
|
|
8
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
9
|
+
<title>frogoe block — objective-chip</title>
|
|
10
|
+
<style>
|
|
11
|
+
body {
|
|
12
|
+
margin: 0;
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
display: grid;
|
|
15
|
+
place-items: center;
|
|
16
|
+
background: radial-gradient(120% 120% at 50% 0%, #182031 0%, #0d1220 60%, #080b13 100%);
|
|
17
|
+
}
|
|
18
|
+
</style>
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<!-- ===================== COPY FROM HERE ===================== -->
|
|
22
|
+
<!--
|
|
23
|
+
frogoe block: objective-chip
|
|
24
|
+
Compact corner chip for one resource that must be WATCHED: moves left,
|
|
25
|
+
balls left, retries left. Big tabular number + label; warning state at
|
|
26
|
+
data-low. For anything less critical, use coin-counter.
|
|
27
|
+
|
|
28
|
+
Bind from game.js (vanilla, no helper):
|
|
29
|
+
const chip = document.querySelector("[data-block-objective]");
|
|
30
|
+
chip.querySelector("[data-block-objective-value]").textContent = String(moves);
|
|
31
|
+
chip.toggleAttribute("data-low", moves <= 5);
|
|
32
|
+
|
|
33
|
+
Theme: --block-accent, --block-danger, --block-fg, --block-outline, --block-chip (bg).
|
|
34
|
+
-->
|
|
35
|
+
<style>
|
|
36
|
+
.block-objective {
|
|
37
|
+
--block-accent: #ffd166;
|
|
38
|
+
--block-chip: rgba(12, 16, 30, 0.55);
|
|
39
|
+
--block-danger: #ff5d5d;
|
|
40
|
+
--block-fg: #fffdf7;
|
|
41
|
+
--block-font: "Fredoka", "Baloo 2", system-ui, sans-serif;
|
|
42
|
+
--block-outline: #26180a;
|
|
43
|
+
--block-value-color: var(--block-fg);
|
|
44
|
+
|
|
45
|
+
display: inline-flex;
|
|
46
|
+
align-items: baseline;
|
|
47
|
+
gap: 0.5em;
|
|
48
|
+
padding: 0.5em 1em;
|
|
49
|
+
background: var(--block-chip);
|
|
50
|
+
border: 2px solid rgba(255, 255, 255, 0.14);
|
|
51
|
+
border-radius: 999px;
|
|
52
|
+
color: var(--block-fg);
|
|
53
|
+
font-family: var(--block-font);
|
|
54
|
+
pointer-events: none;
|
|
55
|
+
-webkit-user-select: none;
|
|
56
|
+
user-select: none;
|
|
57
|
+
}
|
|
58
|
+
.block-objective__value {
|
|
59
|
+
font-size: clamp(1.4rem, 6vmin, 2rem);
|
|
60
|
+
font-weight: 700;
|
|
61
|
+
font-variant-numeric: tabular-nums;
|
|
62
|
+
line-height: 1;
|
|
63
|
+
color: var(--block-value-color);
|
|
64
|
+
text-shadow: 0 2px 0 var(--block-outline);
|
|
65
|
+
}
|
|
66
|
+
.block-objective__label {
|
|
67
|
+
font-size: 0.78rem;
|
|
68
|
+
font-weight: 700;
|
|
69
|
+
letter-spacing: 0.22em;
|
|
70
|
+
text-transform: uppercase;
|
|
71
|
+
opacity: 0.8;
|
|
72
|
+
}
|
|
73
|
+
.block-objective[data-low] {
|
|
74
|
+
--block-value-color: var(--block-danger);
|
|
75
|
+
border-color: color-mix(in srgb, var(--block-danger) 55%, transparent);
|
|
76
|
+
}
|
|
77
|
+
.block-objective[data-low] .block-objective__value {
|
|
78
|
+
animation: block-objective-low 640ms ease-in-out infinite alternate;
|
|
79
|
+
}
|
|
80
|
+
@keyframes block-objective-low {
|
|
81
|
+
from {
|
|
82
|
+
opacity: 1;
|
|
83
|
+
}
|
|
84
|
+
to {
|
|
85
|
+
opacity: 0.6;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
@media (prefers-reduced-motion: reduce) {
|
|
89
|
+
.block-objective[data-low] .block-objective__value {
|
|
90
|
+
animation: none;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
</style>
|
|
94
|
+
|
|
95
|
+
<div class="block-objective" data-block-objective>
|
|
96
|
+
<span class="block-objective__value" data-block-objective-value>25</span>
|
|
97
|
+
<span class="block-objective__label">moves</span>
|
|
98
|
+
</div>
|
|
99
|
+
<!-- ===================== COPY TO HERE ======================= -->
|
|
100
|
+
</body>
|
|
101
|
+
</html>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../schema/registry-item.schema.json",
|
|
3
|
+
"name": "objective-chip",
|
|
4
|
+
"type": "frogoe:block",
|
|
5
|
+
"title": "Objective Chip",
|
|
6
|
+
"description": "Corner chip for one watched resource (moves/balls/retries): big tabular number, label, data-low warning state; themeable via --block-*",
|
|
7
|
+
"tags": [
|
|
8
|
+
"hud",
|
|
9
|
+
"objective",
|
|
10
|
+
"moves",
|
|
11
|
+
"resource",
|
|
12
|
+
"chip"
|
|
13
|
+
],
|
|
14
|
+
"files": [
|
|
15
|
+
{
|
|
16
|
+
"path": "objective-chip.html",
|
|
17
|
+
"target": "blocks/objective-chip.html",
|
|
18
|
+
"type": "frogoe:markup"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"bindings": [
|
|
22
|
+
"data-block-objective",
|
|
23
|
+
"data-block-objective-value"
|
|
24
|
+
],
|
|
25
|
+
"placement": "overlay",
|
|
26
|
+
"preview": {
|
|
27
|
+
"demo": "demo.html"
|
|
28
|
+
}
|
|
29
|
+
}
|