@polycode-projects/the-mechanical-code-talker 2.7.25 → 2.7.26
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/data/sprites/adventurer-icon.toml +13 -0
- package/data/sprites/animal-icon.toml +15 -0
- package/data/sprites/butler-icon.toml +16 -0
- package/data/sprites/cabinet-icon.toml +13 -0
- package/data/sprites/container-icon.toml +12 -0
- package/data/sprites/{cook.toml → cook-icon.toml} +8 -1
- package/data/sprites/desk-icon.toml +14 -0
- package/data/sprites/dog-icon.toml +17 -0
- package/data/sprites/dog-with-colour-icon.toml +31 -0
- package/data/sprites/egg-icon.toml +9 -0
- package/data/sprites/fly-icon.toml +19 -0
- package/data/sprites/furniture-icon.toml +12 -0
- package/data/sprites/gardener-icon.toml +11 -0
- package/data/sprites/housekeeper-icon.toml +14 -0
- package/data/sprites/key-icon.toml +12 -0
- package/data/sprites/lamp-icon.toml +11 -0
- package/data/sprites/letter-icon.toml +11 -0
- package/data/sprites/person-icon.toml +10 -0
- package/data/sprites/poodle-icon.toml +22 -0
- package/data/sprites/portable-icon.toml +12 -0
- package/data/sprites/portrait-icon.toml +12 -0
- package/data/sprites/room-icon.toml +11 -0
- package/data/sprites/spider-icon.toml +21 -0
- package/package.json +4 -2
- package/src/adapters/corpus/sprite-large-template-files.mjs +62 -0
- package/src/domain/sprite-materials.mjs +73 -0
- package/src/domain/sprite-size.mjs +34 -0
- package/src/domain/sprite-templates.mjs +106 -15
- package/src/domain/svg-instance-ids.mjs +40 -0
- package/data/sprites/adventurer.toml +0 -5
- package/data/sprites/animal.toml +0 -6
- package/data/sprites/butler.toml +0 -8
- package/data/sprites/cabinet.toml +0 -5
- package/data/sprites/container.toml +0 -5
- package/data/sprites/desk.toml +0 -4
- package/data/sprites/dog-with-colour.toml +0 -20
- package/data/sprites/dog.toml +0 -5
- package/data/sprites/egg.toml +0 -4
- package/data/sprites/fly.toml +0 -5
- package/data/sprites/furniture.toml +0 -5
- package/data/sprites/gardener.toml +0 -4
- package/data/sprites/housekeeper.toml +0 -6
- package/data/sprites/key.toml +0 -5
- package/data/sprites/lamp.toml +0 -4
- package/data/sprites/letter.toml +0 -5
- package/data/sprites/person.toml +0 -4
- package/data/sprites/poodle.toml +0 -5
- package/data/sprites/portable.toml +0 -6
- package/data/sprites/portrait.toml +0 -5
- package/data/sprites/room.toml +0 -5
- package/data/sprites/spider.toml +0 -5
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# adventurer — the player's own sprite: the person silhouette plus a
|
|
2
|
+
# strap-and-satchel, so the one individual the player controls always
|
|
3
|
+
# reads as visually distinct from the room's own cast of NPCs.
|
|
4
|
+
classes = ["adventurer"]
|
|
5
|
+
svg = """
|
|
6
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
7
|
+
<circle cx="12" cy="6.6" r="3.3" fill="currentColor"/>
|
|
8
|
+
<path d="M6 21 C6 15.3 8.7 12.8 12 12.8 C15.3 12.8 18 15.3 18 21 Z" fill="currentColor"/>
|
|
9
|
+
<path d="M8.4 13.4 L17 17.6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity="0.85"/>
|
|
10
|
+
<rect x="14.6" y="15.8" width="5" height="4.6" rx="1" fill="currentColor" opacity="0.6"/>
|
|
11
|
+
<rect x="16.3" y="16.6" width="1.6" height="1.2" rx="0.3" fill="currentColor" opacity="0.9"/>
|
|
12
|
+
</svg>
|
|
13
|
+
"""
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# animal — the deliberately plainest shape in the set: an unadorned
|
|
2
|
+
# four-legged blob, so an unregistered species reads as "some animal"
|
|
3
|
+
# rather than suggesting one the taxonomy never named. The declared root
|
|
4
|
+
# fallback for the spider-and-fly world.
|
|
5
|
+
classes = ["animal"]
|
|
6
|
+
svg = """
|
|
7
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
8
|
+
<ellipse cx="12" cy="13" rx="7" ry="4.4" fill="currentColor"/>
|
|
9
|
+
<circle cx="12" cy="7" r="3.4" fill="currentColor"/>
|
|
10
|
+
<g stroke="currentColor" stroke-width="1.6" stroke-linecap="round">
|
|
11
|
+
<line x1="7" y1="17" x2="7" y2="21"/>
|
|
12
|
+
<line x1="17" y1="17" x2="17" y2="21"/>
|
|
13
|
+
</g>
|
|
14
|
+
</svg>
|
|
15
|
+
"""
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# butler — Ashcombe Hall's own butler: the person silhouette plus a stiff
|
|
2
|
+
# wing-collar flaring OUT past the shoulder line (changing the outer
|
|
3
|
+
# silhouette, not an internal opacity knockout — an internal light-on-dark
|
|
4
|
+
# accent was tried first and proved invisible once shrunk to 44px; a
|
|
5
|
+
# silhouette change survives shrinking the way gardener.toml's wide brim
|
|
6
|
+
# does) and a bow-tie.
|
|
7
|
+
classes = ["butler"]
|
|
8
|
+
svg = """
|
|
9
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
10
|
+
<circle cx="12" cy="6.6" r="3.3" fill="currentColor"/>
|
|
11
|
+
<path d="M6 21 C6 15.3 8.7 12.8 12 12.8 C15.3 12.8 18 15.3 18 21 Z" fill="currentColor"/>
|
|
12
|
+
<path d="M7.6 11.6 L11.3 13.2 L8.6 15.4 Z" fill="currentColor"/>
|
|
13
|
+
<path d="M16.4 11.6 L12.7 13.2 L15.4 15.4 Z" fill="currentColor"/>
|
|
14
|
+
<path d="M10.6 14.2 L12 16.1 L13.4 14.2 L12 18.6 Z" fill="currentColor" opacity="0.95"/>
|
|
15
|
+
</svg>
|
|
16
|
+
"""
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# cabinet — Ashcombe Hall's own locked cabinet (a container): a two-door
|
|
2
|
+
# wardrobe silhouette, the gap between the doors reading as the seam, with
|
|
3
|
+
# two knobs and a cornice band.
|
|
4
|
+
classes = ["cabinet"]
|
|
5
|
+
svg = """
|
|
6
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
7
|
+
<rect x="4.5" y="2.5" width="7.2" height="19" rx="1" fill="currentColor"/>
|
|
8
|
+
<rect x="12.3" y="2.5" width="7.2" height="19" rx="1" fill="currentColor"/>
|
|
9
|
+
<rect x="4.5" y="2.5" width="15" height="1.4" fill="currentColor" opacity="0.4"/>
|
|
10
|
+
<circle cx="10.6" cy="12" r="0.9" fill="currentColor" opacity="0.35"/>
|
|
11
|
+
<circle cx="13.4" cy="12" r="0.9" fill="currentColor" opacity="0.35"/>
|
|
12
|
+
</svg>
|
|
13
|
+
"""
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# container — the generic fallback for any container with no sprite of
|
|
2
|
+
# its own (see cabinet/portrait for Ashcombe Hall's own two): a solid
|
|
3
|
+
# chest silhouette with a carved lid-seam and a latch highlight.
|
|
4
|
+
classes = ["container"]
|
|
5
|
+
svg = """
|
|
6
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
7
|
+
<path d="M3 10 L5 5 H19 L21 10 Z" fill="currentColor"/>
|
|
8
|
+
<rect x="3" y="10" width="18" height="10" rx="1.2" fill="currentColor"/>
|
|
9
|
+
<rect x="3" y="10" width="18" height="1.6" fill="currentColor" opacity="0.35"/>
|
|
10
|
+
<rect x="10.6" y="9.2" width="2.8" height="2.6" rx="0.5" fill="currentColor" opacity="0.85"/>
|
|
11
|
+
</svg>
|
|
12
|
+
"""
|
|
@@ -4,4 +4,11 @@
|
|
|
4
4
|
# housekeeper.toml's cap use — a same-width tall hat read as just an
|
|
5
5
|
# elongated head once shrunk, tried and rejected first).
|
|
6
6
|
classes = ["cook"]
|
|
7
|
-
svg = """
|
|
7
|
+
svg = """
|
|
8
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
9
|
+
<ellipse cx="12" cy="3.4" rx="5.4" ry="3" fill="currentColor"/>
|
|
10
|
+
<rect x="8.6" y="5.6" width="6.8" height="2.2" rx="0.6" fill="currentColor"/>
|
|
11
|
+
<circle cx="12" cy="10" r="3.1" fill="currentColor"/>
|
|
12
|
+
<path d="M6 21 C6 15.6 8.7 13.2 12 13.2 C15.3 13.2 18 15.6 18 21 Z" fill="currentColor"/>
|
|
13
|
+
</svg>
|
|
14
|
+
"""
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# desk — Ashcombe Hall's own study desk: a tabletop bar over two drawer
|
|
2
|
+
# blocks with pull-knobs, on tapered legs.
|
|
3
|
+
classes = ["desk"]
|
|
4
|
+
svg = """
|
|
5
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
6
|
+
<rect x="3" y="7" width="18" height="2.6" rx="0.6" fill="currentColor"/>
|
|
7
|
+
<rect x="4.4" y="9.6" width="6.6" height="5.6" rx="0.6" fill="currentColor" opacity="0.85"/>
|
|
8
|
+
<rect x="13" y="9.6" width="6.6" height="5.6" rx="0.6" fill="currentColor" opacity="0.85"/>
|
|
9
|
+
<circle cx="9.6" cy="12.4" r="0.55" fill="currentColor" opacity="0.4"/>
|
|
10
|
+
<circle cx="16.4" cy="12.4" r="0.55" fill="currentColor" opacity="0.4"/>
|
|
11
|
+
<path d="M4.6 15.2 L3.8 20.5 L5.6 20.5 L6.2 15.2 Z" fill="currentColor"/>
|
|
12
|
+
<path d="M17.8 15.2 L17.2 20.5 L19 20.5 L18.2 15.2 Z" fill="currentColor"/>
|
|
13
|
+
</svg>
|
|
14
|
+
"""
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# dog — the plain-class sprite a taxonomy hop away from poodle/sheepdog.
|
|
2
|
+
# Same body language as poodle's, without the pompom cut, so the family
|
|
3
|
+
# reads as one dog rather than two unrelated animals.
|
|
4
|
+
classes = ["dog"]
|
|
5
|
+
svg = """
|
|
6
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
7
|
+
<ellipse cx="13" cy="15" rx="6.4" ry="4.3" fill="currentColor"/>
|
|
8
|
+
<circle cx="7" cy="9" r="3.6" fill="currentColor"/>
|
|
9
|
+
<ellipse cx="6.1" cy="8" rx="1" ry="1.3" fill="currentColor" opacity="0.3"/>
|
|
10
|
+
<path d="M4.5 6.5 L2 3 L6 5 Z" fill="currentColor"/>
|
|
11
|
+
<path d="M19 13 C22 12 22.5 15 20 16 Z" fill="currentColor"/>
|
|
12
|
+
<g stroke="currentColor" stroke-width="1.6" stroke-linecap="round">
|
|
13
|
+
<line x1="9" y1="19" x2="9" y2="22"/>
|
|
14
|
+
<line x1="17" y1="19" x2="17" y2="22"/>
|
|
15
|
+
</g>
|
|
16
|
+
</svg>
|
|
17
|
+
"""
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# dog-with-colour — the parameterized-property worked example: "a dog that
|
|
2
|
+
# is black". Same silhouette as dog.toml, but every filled shape takes its
|
|
3
|
+
# color from the instance's OWN observed
|
|
4
|
+
# mgx:hasProperty value rather than the page's currentColor accent, with a
|
|
5
|
+
# thin currentColor stroke kept on each shape so a light value (white)
|
|
6
|
+
# still reads against a light card background. A property value with no
|
|
7
|
+
# entry in [parameters.colour.values] is not a match for this template at
|
|
8
|
+
# all (see sprite-templates.mjs's own header for the naming/specificity
|
|
9
|
+
# convention) — it falls through to the plain dog.toml sprite, never a
|
|
10
|
+
# guessed color.
|
|
11
|
+
classes = ["dog"]
|
|
12
|
+
svg = """
|
|
13
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
14
|
+
<ellipse cx="13" cy="15" rx="6.4" ry="4.3" fill="{{FILL}}" stroke="currentColor" stroke-width="0.9"/>
|
|
15
|
+
<circle cx="7" cy="9" r="3.6" fill="{{FILL}}" stroke="currentColor" stroke-width="0.9"/>
|
|
16
|
+
<path d="M4.5 6.5 L2 3 L6 5 Z" fill="{{FILL}}" stroke="currentColor" stroke-width="0.9"/>
|
|
17
|
+
<path d="M19 13 C22 12 22.5 15 20 16 Z" fill="{{FILL}}" stroke="currentColor" stroke-width="0.9"/>
|
|
18
|
+
<g stroke="currentColor" stroke-width="1.6" stroke-linecap="round">
|
|
19
|
+
<line x1="9" y1="19" x2="9" y2="22"/>
|
|
20
|
+
<line x1="17" y1="19" x2="17" y2="22"/>
|
|
21
|
+
</g>
|
|
22
|
+
</svg>
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
[parameters.colour]
|
|
26
|
+
property = "mgx:hasProperty"
|
|
27
|
+
placeholder = "{{FILL}}"
|
|
28
|
+
|
|
29
|
+
[parameters.colour.values]
|
|
30
|
+
black = "#22201d"
|
|
31
|
+
white = "#f5f2ea"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# egg — the spider-and-fly board's laid egg. The plain shell silhouette
|
|
2
|
+
# plus one small carved highlight.
|
|
3
|
+
classes = ["egg"]
|
|
4
|
+
svg = """
|
|
5
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
6
|
+
<path d="M12 2 C7 2 4 10 4 15.5 C4 20 7.6 22 12 22 C16.4 22 20 20 20 15.5 C20 10 17 2 12 2 Z" fill="currentColor"/>
|
|
7
|
+
<ellipse cx="9.6" cy="9.5" rx="1.7" ry="2.4" fill="currentColor" opacity="0.28"/>
|
|
8
|
+
</svg>
|
|
9
|
+
"""
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# fly — the spider-and-fly board's other agent. A round head, a tapered
|
|
2
|
+
# body with a carved highlight, translucent wings, and two thin trailing
|
|
3
|
+
# legs for a touch of character at rest.
|
|
4
|
+
classes = ["fly"]
|
|
5
|
+
svg = """
|
|
6
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
7
|
+
<ellipse cx="12" cy="13.6" rx="3.4" ry="5.2" fill="currentColor"/>
|
|
8
|
+
<circle cx="12" cy="7" r="2.7" fill="currentColor"/>
|
|
9
|
+
<ellipse cx="11.1" cy="12" rx="1.1" ry="1.7" fill="currentColor" opacity="0.3"/>
|
|
10
|
+
<g fill="currentColor" opacity="0.55">
|
|
11
|
+
<path d="M9 10 C3 6 2 4 3 2 C6 2 9 6 10.5 10 Z"/>
|
|
12
|
+
<path d="M15 10 C21 6 22 4 21 2 C18 2 15 6 13.5 10 Z"/>
|
|
13
|
+
</g>
|
|
14
|
+
<g stroke="currentColor" stroke-width="1" stroke-linecap="round">
|
|
15
|
+
<path d="M9.6 17 L7.4 19.4"/>
|
|
16
|
+
<path d="M14.4 17 L16.6 19.4"/>
|
|
17
|
+
</g>
|
|
18
|
+
</svg>
|
|
19
|
+
"""
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# furniture — the generic fallback for any furniture piece with no sprite
|
|
2
|
+
# of its own: a solid console-table silhouette (tapered legs, a carved
|
|
3
|
+
# highlight along the top edge), replacing the old hollow-shelf outline.
|
|
4
|
+
classes = ["furniture"]
|
|
5
|
+
svg = """
|
|
6
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
7
|
+
<rect x="3.5" y="6.5" width="17" height="3.2" rx="0.8" fill="currentColor"/>
|
|
8
|
+
<rect x="3.5" y="6.5" width="17" height="1" fill="currentColor" opacity="0.35"/>
|
|
9
|
+
<path d="M5.6 9.7 L4.6 20 L6.7 20 L7.2 9.7 Z" fill="currentColor"/>
|
|
10
|
+
<path d="M18.4 9.7 L16.8 20 L18.9 20 L19.4 9.7 Z" fill="currentColor"/>
|
|
11
|
+
</svg>
|
|
12
|
+
"""
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# gardener — Ashcombe Hall's own gardener: the person silhouette under a
|
|
2
|
+
# wide sunhat brim.
|
|
3
|
+
classes = ["gardener"]
|
|
4
|
+
svg = """
|
|
5
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
6
|
+
<ellipse cx="12" cy="5.6" rx="7.4" ry="2" fill="currentColor"/>
|
|
7
|
+
<path d="M8.8 5.2 C8.8 3.1 10.2 1.6 12 1.6 C13.8 1.6 15.2 3.1 15.2 5.2 C15.2 5.6 15.1 6 15 6.3 L9 6.3 C8.9 6 8.8 5.6 8.8 5.2 Z" fill="currentColor" opacity="0.85"/>
|
|
8
|
+
<circle cx="12" cy="8.6" r="3.1" fill="currentColor"/>
|
|
9
|
+
<path d="M6 21 C6 15.5 8.7 13.1 12 13.1 C15.3 13.1 18 15.5 18 21 Z" fill="currentColor"/>
|
|
10
|
+
</svg>
|
|
11
|
+
"""
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# housekeeper — Ashcombe Hall's own housekeeper: the person silhouette
|
|
2
|
+
# under a wide mob-cap brim (deliberately WIDER than the head, the same
|
|
3
|
+
# "wide silhouette reads at 44px" move gardener.toml's sunhat uses) and a
|
|
4
|
+
# tied apron line.
|
|
5
|
+
classes = ["housekeeper"]
|
|
6
|
+
svg = """
|
|
7
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
8
|
+
<ellipse cx="12" cy="4.6" rx="5.6" ry="2.1" fill="currentColor"/>
|
|
9
|
+
<path d="M8.6 5 C8.6 3 10 1.7 12 1.7 C14 1.7 15.4 3 15.4 5 L15.4 5.6 L8.6 5.6 Z" fill="currentColor" opacity="0.9"/>
|
|
10
|
+
<circle cx="12" cy="7.6" r="3.1" fill="currentColor"/>
|
|
11
|
+
<path d="M6 21 C6 15.5 8.7 13.1 12 13.1 C15.3 13.1 18 15.5 18 21 Z" fill="currentColor"/>
|
|
12
|
+
<path d="M9 16 C10 15.4 14 15.4 15 16" fill="none" stroke="currentColor" stroke-width="1" opacity="0.45" stroke-linecap="round"/>
|
|
13
|
+
</svg>
|
|
14
|
+
"""
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# key — Ashcombe Hall's own key (hidden in the portrait, unlocks the
|
|
2
|
+
# cabinet): a classic round-bow skeleton key, bold strokes so it stays
|
|
3
|
+
# legible at a 44px render.
|
|
4
|
+
classes = ["key"]
|
|
5
|
+
svg = """
|
|
6
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
7
|
+
<circle cx="7" cy="9" r="4.4" fill="none" stroke="currentColor" stroke-width="2.4"/>
|
|
8
|
+
<path d="M10.4 12 L19.5 21.1" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/>
|
|
9
|
+
<path d="M16.4 17.1 L18.6 14.9" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
10
|
+
<path d="M18.6 19.3 L20.6 17.3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
11
|
+
</svg>
|
|
12
|
+
"""
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# lamp — Ashcombe Hall's own study lamp: a Victorian hurricane-lamp
|
|
2
|
+
# silhouette — base, glass globe, a neck, and a small carved flame.
|
|
3
|
+
classes = ["lamp"]
|
|
4
|
+
svg = """
|
|
5
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
6
|
+
<path d="M9 21 H15 L14 18 H10 Z" fill="currentColor"/>
|
|
7
|
+
<path d="M8.4 18 C7 15.6 7 12.6 8.6 10.4 H15.4 C17 12.6 17 15.6 15.6 18 Z" fill="currentColor"/>
|
|
8
|
+
<rect x="10.6" y="6.4" width="2.8" height="4.4" fill="currentColor" opacity="0.85"/>
|
|
9
|
+
<path d="M12 3.2 C13.4 4.6 13.8 6 12 7.4 C10.2 6 10.6 4.6 12 3.2 Z" fill="currentColor" opacity="0.55"/>
|
|
10
|
+
</svg>
|
|
11
|
+
"""
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# letter — Ashcombe Hall's own objective (hidden in the cabinet): an
|
|
2
|
+
# envelope with a folded flap (a lighter overlay, the same carved-highlight
|
|
3
|
+
# trick as the lid on container.toml) and a small wax seal.
|
|
4
|
+
classes = ["letter"]
|
|
5
|
+
svg = """
|
|
6
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
7
|
+
<rect x="3" y="6" width="18" height="13" rx="1.2" fill="currentColor"/>
|
|
8
|
+
<path d="M3 6 L21 6 L21 6.8 L12 13.8 L3 6.8 Z" fill="currentColor" opacity="0.32"/>
|
|
9
|
+
<circle cx="12" cy="12.4" r="1.15" fill="currentColor" opacity="0.8"/>
|
|
10
|
+
</svg>
|
|
11
|
+
"""
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# person — the generic fallback for anyone with no NPC sprite of their own
|
|
2
|
+
# (see butler/housekeeper/cook/gardener for the named Ashcombe Hall staff).
|
|
3
|
+
classes = ["person"]
|
|
4
|
+
svg = """
|
|
5
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
6
|
+
<circle cx="12" cy="6.6" r="3.3" fill="currentColor"/>
|
|
7
|
+
<path d="M6 21 C6 15.3 8.7 12.8 12 12.8 C15.3 12.8 18 15.3 18 21 Z" fill="currentColor"/>
|
|
8
|
+
<path d="M12 12.8 C13.1 12.8 14.1 13 15 13.4" fill="none" stroke="currentColor" stroke-width="0.9" opacity="0.4" stroke-linecap="round"/>
|
|
9
|
+
</svg>
|
|
10
|
+
"""
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# poodle — the seed taxonomy's worked example (poodle IsA dog): its own
|
|
2
|
+
# pompom-cut head and tail, distinct from the plain dog sprite it would
|
|
3
|
+
# otherwise fall back to.
|
|
4
|
+
classes = ["poodle"]
|
|
5
|
+
svg = """
|
|
6
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
7
|
+
<ellipse cx="13" cy="15" rx="6.4" ry="4.6" fill="currentColor"/>
|
|
8
|
+
<ellipse cx="10.8" cy="13.2" rx="1.8" ry="1.3" fill="currentColor" opacity="0.28"/>
|
|
9
|
+
<circle cx="7" cy="8.5" r="4" fill="currentColor"/>
|
|
10
|
+
<g fill="currentColor">
|
|
11
|
+
<circle cx="4" cy="6" r="1.6"/>
|
|
12
|
+
<circle cx="7" cy="4.2" r="1.7"/>
|
|
13
|
+
<circle cx="10" cy="6" r="1.6"/>
|
|
14
|
+
</g>
|
|
15
|
+
<rect x="18.5" y="14" width="2.2" height="6" rx="1.1" fill="currentColor"/>
|
|
16
|
+
<circle cx="19.6" cy="13" r="1.5" fill="currentColor"/>
|
|
17
|
+
<g stroke="currentColor" stroke-width="1.6" stroke-linecap="round">
|
|
18
|
+
<line x1="9" y1="19.5" x2="9" y2="22"/>
|
|
19
|
+
<line x1="17" y1="19.5" x2="17" y2="22"/>
|
|
20
|
+
</g>
|
|
21
|
+
</svg>
|
|
22
|
+
"""
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# portable — the generic fallback for any carryable object with no sprite
|
|
2
|
+
# of its own: a drawstring parcel silhouette, replacing the old
|
|
3
|
+
# generic-gift-box outline so it reads as "an unspecified small thing"
|
|
4
|
+
# rather than a gift.
|
|
5
|
+
classes = ["portable"]
|
|
6
|
+
svg = """
|
|
7
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
8
|
+
<path d="M12 6 C7.5 6 5 9.4 5 13.4 C5 17.7 8.1 20 12 20 C15.9 20 19 17.7 19 13.4 C19 9.4 16.5 6 12 6 Z" fill="currentColor"/>
|
|
9
|
+
<path d="M9.4 6.4 C9.9 4.6 10.8 3.4 12 3.4 C13.2 3.4 14.1 4.6 14.6 6.4" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/>
|
|
10
|
+
<ellipse cx="9.8" cy="11.6" rx="1.6" ry="2.1" fill="currentColor" opacity="0.28"/>
|
|
11
|
+
</svg>
|
|
12
|
+
"""
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# portrait — Ashcombe Hall's own drawing-room portrait (a container, hiding
|
|
2
|
+
# the key): a gilt arched frame around a lighter canvas, with a bust
|
|
3
|
+
# silhouette so it reads as a picture of someone, not an empty frame.
|
|
4
|
+
classes = ["portrait"]
|
|
5
|
+
svg = """
|
|
6
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
7
|
+
<path d="M4 21 V7 C4 4 6.8 2 12 2 C17.2 2 20 4 20 7 V21 Z" fill="currentColor"/>
|
|
8
|
+
<path d="M6.3 19.4 V8.3 C6.3 6.2 8.4 4.8 12 4.8 C15.6 4.8 17.7 6.2 17.7 8.3 V19.4 Z" fill="currentColor" opacity="0.28"/>
|
|
9
|
+
<circle cx="12" cy="10.4" r="2.3" fill="currentColor" opacity="0.7"/>
|
|
10
|
+
<path d="M8 18.4 C8 15.2 9.6 13.4 12 13.4 C14.4 13.4 16 15.2 16 18.4 Z" fill="currentColor" opacity="0.7"/>
|
|
11
|
+
</svg>
|
|
12
|
+
"""
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# room — a schematic floor plan: a washed interior (a solid tint, not a
|
|
2
|
+
# hollow box) plus a doorway arch, kept abstract since a room is a space
|
|
3
|
+
# to draw, not an object to render literally.
|
|
4
|
+
classes = ["room"]
|
|
5
|
+
svg = """
|
|
6
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
7
|
+
<rect x="3" y="3" width="18" height="18" rx="1" fill="currentColor" opacity="0.14"/>
|
|
8
|
+
<rect x="3" y="3" width="18" height="18" rx="1" fill="none" stroke="currentColor" stroke-width="1.6"/>
|
|
9
|
+
<path d="M9 21 L9 13 A3 3 0 0 1 15 13 L15 21" fill="none" stroke="currentColor" stroke-width="1.6"/>
|
|
10
|
+
</svg>
|
|
11
|
+
"""
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# spider — the spider-and-fly board's own agent. A confident two-lobe body
|
|
2
|
+
# (a lighter carved patch on the abdomen for shading) and eight thin
|
|
3
|
+
# outward legs.
|
|
4
|
+
classes = ["spider"]
|
|
5
|
+
svg = """
|
|
6
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
7
|
+
<ellipse cx="12" cy="16" rx="5.2" ry="4.8" fill="currentColor"/>
|
|
8
|
+
<ellipse cx="10.3" cy="14.3" rx="1.8" ry="1.4" fill="currentColor" opacity="0.3"/>
|
|
9
|
+
<circle cx="12" cy="9.6" r="3.2" fill="currentColor"/>
|
|
10
|
+
<g stroke="currentColor" stroke-width="1.1" fill="none" stroke-linecap="round">
|
|
11
|
+
<path d="M9.4 8 L2.2 4.4"/>
|
|
12
|
+
<path d="M9 10.2 L1.4 9.4"/>
|
|
13
|
+
<path d="M9.2 12.6 L2 14.2"/>
|
|
14
|
+
<path d="M10 15.4 L3.4 19"/>
|
|
15
|
+
<path d="M14.6 8 L21.8 4.4"/>
|
|
16
|
+
<path d="M15 10.2 L22.6 9.4"/>
|
|
17
|
+
<path d="M14.8 12.6 L22 14.2"/>
|
|
18
|
+
<path d="M14 15.4 L20.6 19"/>
|
|
19
|
+
</g>
|
|
20
|
+
</svg>
|
|
21
|
+
"""
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polycode-projects/the-mechanical-code-talker",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.26",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "The Mechanical Code Talker (tmct) — a tolerant, offline, $0 chat surface that guides you toward precision queries about a software repository. ELIZA/PARRY-style but domain-obsessed with code. No model calls; no codebase index of its own.",
|
|
@@ -67,7 +67,8 @@
|
|
|
67
67
|
"corpus/",
|
|
68
68
|
"!corpus/wordnet/generate.mjs",
|
|
69
69
|
"!corpus/namenet/generate.mjs",
|
|
70
|
-
"data/"
|
|
70
|
+
"data/",
|
|
71
|
+
"!data/sprites-large/"
|
|
71
72
|
],
|
|
72
73
|
"publishConfig": {
|
|
73
74
|
"access": "public"
|
|
@@ -139,6 +140,7 @@
|
|
|
139
140
|
"build:chat-seed": "node scripts/build-chat-seed.mjs",
|
|
140
141
|
"build:demo-graph": "node scripts/build-demo-graph.mjs",
|
|
141
142
|
"build:demo-pack": "node scripts/build-demo-pack.mjs",
|
|
143
|
+
"build:demo-sprites-pack": "node scripts/build-demo-sprites-pack.mjs",
|
|
142
144
|
"build:demo-memory": "node scripts/build-demo-memory.mjs",
|
|
143
145
|
"gen:tool-docs": "node scripts/generate-tool-docs.mjs",
|
|
144
146
|
"gen:collisions": "node scripts/generate-real-word-collisions.mjs",
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// sprite-large-template-files.mjs — the filesystem side of the sprite TIER
|
|
2
|
+
// meant to be looked at closely (400px target, gradient/highlight shading):
|
|
3
|
+
// read data/sprites-large/*.toml and expand each file's by-name material
|
|
4
|
+
// references (sprite-materials.mjs's own `expandMaterialReferences`) before
|
|
5
|
+
// handing the templates to the SAME pure resolver the icon tier already
|
|
6
|
+
// uses (src/domain/sprite-templates.mjs). Mirrors sprite-template-files.mjs's
|
|
7
|
+
// own readSpriteTemplateFiles idiom exactly (same directory-of-toml-files
|
|
8
|
+
// shape, same per-file-defensive load) — the two loaders stay separate
|
|
9
|
+
// files, never merged into one, because they point at different directories
|
|
10
|
+
// and this one carries the extra material-expansion step the icon tier has
|
|
11
|
+
// no use for.
|
|
12
|
+
//
|
|
13
|
+
// Node-only (readdirSync/readFileSync), and — per package.json's own
|
|
14
|
+
// "!data/sprites-large/" exclusion — never reachable from an npm-installed
|
|
15
|
+
// consumer at all: only this git checkout (dev) or the deployed site's own
|
|
16
|
+
// fetched pack (scripts/build-demo-site.mjs's sprites-pack build step, which
|
|
17
|
+
// calls this loader once, in Node, at build time) can read this tier. The
|
|
18
|
+
// browser bundle never imports this module directly, the same reason
|
|
19
|
+
// sprite-template-files.mjs's own header gives for the icon tier.
|
|
20
|
+
|
|
21
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
22
|
+
import { fileURLToPath } from "node:url";
|
|
23
|
+
import { join, dirname } from "node:path";
|
|
24
|
+
import { parse as parseToml } from "smol-toml";
|
|
25
|
+
import { expandMaterialReferences } from "../../domain/sprite-materials.mjs";
|
|
26
|
+
|
|
27
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
28
|
+
/** The sprite-tier template directory (data, not code) — every *.toml file
|
|
29
|
+
* inside is loaded, in filename order, except `_materials.toml` itself
|
|
30
|
+
* (that file is a shared reference table, not a template — see
|
|
31
|
+
* sprite-materials.mjs, its palette is a plain JS constant, not read from
|
|
32
|
+
* here; a stray `_materials.toml` is tolerated defensively if one is ever
|
|
33
|
+
* added back, simply by never matching a real `classes` list). */
|
|
34
|
+
export const SPRITE_LARGE_TEMPLATES_DIR = join(HERE, "..", "..", "..", "data", "sprites-large");
|
|
35
|
+
|
|
36
|
+
/** Read every *.toml file in `dir` (sorted, deterministic), expand each
|
|
37
|
+
* file's material references against sprite-materials.mjs's shared
|
|
38
|
+
* palette, and return the flat array of fully-expanded template objects. A
|
|
39
|
+
* missing directory or an unparseable file is DEFENSIVE (per-file: a broken
|
|
40
|
+
* file is skipped, not fatal to the others) — a production page load can
|
|
41
|
+
* never go blank because one hand-authored sprite has a typo.
|
|
42
|
+
* test/adapters/sprite-large-template-files.test.mjs parses the real files
|
|
43
|
+
* directly (not through this lenient loader) so a broken file still fails a
|
|
44
|
+
* test loudly. */
|
|
45
|
+
export function readSpriteLargeTemplateFiles(dir = SPRITE_LARGE_TEMPLATES_DIR) {
|
|
46
|
+
let files;
|
|
47
|
+
try {
|
|
48
|
+
files = readdirSync(dir).filter((f) => f.endsWith(".toml") && !f.startsWith("_")).sort();
|
|
49
|
+
} catch {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
const templates = [];
|
|
53
|
+
for (const file of files) {
|
|
54
|
+
try {
|
|
55
|
+
const parsed = parseToml(readFileSync(join(dir, file), "utf8"));
|
|
56
|
+
templates.push(parsed);
|
|
57
|
+
} catch {
|
|
58
|
+
continue; // one malformed file never takes the others down
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return expandMaterialReferences(templates);
|
|
62
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// sprite-materials.mjs — the shared {light, base, dark} colour-triple palette
|
|
2
|
+
// the sprite tier's gradient-shaded materials draw from, one treatment per
|
|
3
|
+
// key. It exists so a hex triple is written ONCE and referenced by name from
|
|
4
|
+
// every data/sprites-large/*.toml file that uses it, rather than the same
|
|
5
|
+
// three hex values being hand-copied into six or more files (the drift this
|
|
6
|
+
// project's own conventions already try to avoid elsewhere, e.g.
|
|
7
|
+
// SOURCE_PRIOR/SPRITE_REGISTRY's single-frozen-table idiom).
|
|
8
|
+
//
|
|
9
|
+
// A raw taught mgx:madeOf value maps to a TREATMENT here, not one-for-one:
|
|
10
|
+
// "gold" and "metal" both read as the same warm shiny-metal treatment,
|
|
11
|
+
// "paper" and "cardboard" both read as the same matte-paper treatment — a
|
|
12
|
+
// per-file [parameters.material.values] table names which of ITS OWN
|
|
13
|
+
// plausible raw values map to which treatment (see data/sprites-large/*.toml),
|
|
14
|
+
// this module only owns the treatments themselves.
|
|
15
|
+
//
|
|
16
|
+
// expandMaterialReferences is the one place that indirection gets resolved:
|
|
17
|
+
// it turns a short by-name reference (`gold = "metal"`, valid TOML, safe to
|
|
18
|
+
// repeat across files) into the full triple object sprite-templates.mjs's
|
|
19
|
+
// resolver actually substitutes into an svg's three gradient stops. Domain
|
|
20
|
+
// code downstream of this never needs to know the palette exists at all — it
|
|
21
|
+
// only ever sees a [parameters.*.values] entry that is already either a
|
|
22
|
+
// plain string (single-placeholder fill) or a complete {light,base,dark}
|
|
23
|
+
// object (multi-placeholder fill), the same two shapes a hand-built test
|
|
24
|
+
// fixture can supply directly with no palette involved.
|
|
25
|
+
|
|
26
|
+
/** The 8 rendering treatments this pass covers (the operator's own read of
|
|
27
|
+
* init's 17 raw mgx:madeOf strings: 8 are distinct shiny/matte/finish
|
|
28
|
+
* treatments, the remaining 9 food/organic materials are a different
|
|
29
|
+
* rendering problem and out of scope here). Every value is a real, plain
|
|
30
|
+
* frozen {light, base, dark} hex triple — no computed shades — so the
|
|
31
|
+
* gradient a sprite draws is exactly the three stops this table names. */
|
|
32
|
+
export const MATERIAL_PALETTE = Object.freeze({
|
|
33
|
+
metal: Object.freeze({ light: "#f0dfa0", base: "#c9a24b", dark: "#8a6a1e" }),
|
|
34
|
+
paper: Object.freeze({ light: "#fdfaf1", base: "#e8dcbf", dark: "#b7a47c" }),
|
|
35
|
+
glass: Object.freeze({ light: "#eaf6f7", base: "#bfe2e7", dark: "#7fb6c1" }),
|
|
36
|
+
ceramic: Object.freeze({ light: "#fefefe", base: "#e6e1d8", dark: "#aba69c" }),
|
|
37
|
+
wood: Object.freeze({ light: "#c98f56", base: "#8a5a2e", dark: "#5a3a1c" }),
|
|
38
|
+
plastic: Object.freeze({ light: "#f3f3f3", base: "#c8c8c8", dark: "#8a8a8a" }),
|
|
39
|
+
wax: Object.freeze({ light: "#fff6de", base: "#f0d98c", dark: "#c9a94a" }),
|
|
40
|
+
"woven material": Object.freeze({ light: "#e8d9b7", base: "#c9a869", dark: "#8a6c3d" }),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Every [parameters.*.values] string entry, in every template, expanded from
|
|
45
|
+
* a treatment KEY (e.g. "metal") to that treatment's full {light,base,dark}
|
|
46
|
+
* object from `palette` — but only for a parameter that declares
|
|
47
|
+
* `placeholders` (the multi-placeholder shape); a parameter with only the
|
|
48
|
+
* older singular `placeholder` is left alone, since its values are literal
|
|
49
|
+
* fills, never palette references. A values entry that is already an object
|
|
50
|
+
* (a one-off hand-authored triple, not drawn from the shared palette) is
|
|
51
|
+
* left alone too. A string naming no known treatment is left as the plain
|
|
52
|
+
* string it was — spriteTemplateProblems then flags the leftover reference
|
|
53
|
+
* rather than this function silently rendering the wrong colour. Pure;
|
|
54
|
+
* `templates` is read only.
|
|
55
|
+
*/
|
|
56
|
+
export function expandMaterialReferences(templates, palette = MATERIAL_PALETTE) {
|
|
57
|
+
return (templates || []).map((t) => {
|
|
58
|
+
if (!t?.parameters) return t;
|
|
59
|
+
const parameters = {};
|
|
60
|
+
for (const [name, param] of Object.entries(t.parameters)) {
|
|
61
|
+
if (!param?.placeholders || !param?.values) {
|
|
62
|
+
parameters[name] = param;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const values = {};
|
|
66
|
+
for (const [key, value] of Object.entries(param.values)) {
|
|
67
|
+
values[key] = typeof value === "string" && palette[value] ? palette[value] : value;
|
|
68
|
+
}
|
|
69
|
+
parameters[name] = { ...param, values };
|
|
70
|
+
}
|
|
71
|
+
return { ...t, parameters };
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// sprite-size.mjs — a taught size-descriptive property (small/large/long/
|
|
2
|
+
// tall — words the corpus's own WordNet-derived property vocabulary already
|
|
3
|
+
// carries under mgx:hasProperty) resolved to a plain numeric render scale,
|
|
4
|
+
// NOT a new template file: vector sprite art scales for free, so this
|
|
5
|
+
// dimension costs nothing extra in the pack. The same "prove the mechanism,
|
|
6
|
+
// no live consumer required yet" posture the icon tier's dog-with-colour
|
|
7
|
+
// demo already established — no shipped world currently carries a size
|
|
8
|
+
// property on a real object, so nothing calls this yet.
|
|
9
|
+
|
|
10
|
+
const SIZE_PROPERTY_PREDICATE = "mgx:hasProperty";
|
|
11
|
+
|
|
12
|
+
/** Closed vocabulary only: a size word absent from this table never moves
|
|
13
|
+
* the scale, it simply doesn't match — the same never-guess posture every
|
|
14
|
+
* other property lookup in this pack takes. */
|
|
15
|
+
const SIZE_SCALE = Object.freeze({
|
|
16
|
+
small: 0.8,
|
|
17
|
+
large: 1.3,
|
|
18
|
+
long: 1.2,
|
|
19
|
+
tall: 1.25,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The render scale factor for `propertyFacts` (an instance's own small
|
|
24
|
+
* `{predicate, object}` fact set): the first mgx:hasProperty value found in
|
|
25
|
+
* SIZE_SCALE, else 1 (no size fact at all => the sprite's own natural size).
|
|
26
|
+
* Pure; `propertyFacts` is read only, never required to be non-empty.
|
|
27
|
+
*/
|
|
28
|
+
export function sizeScaleFor(propertyFacts) {
|
|
29
|
+
for (const f of propertyFacts || []) {
|
|
30
|
+
if (f?.predicate !== SIZE_PROPERTY_PREDICATE) continue;
|
|
31
|
+
if (Object.prototype.hasOwnProperty.call(SIZE_SCALE, f.object)) return SIZE_SCALE[f.object];
|
|
32
|
+
}
|
|
33
|
+
return 1;
|
|
34
|
+
}
|
|
@@ -28,6 +28,33 @@
|
|
|
28
28
|
// exact fact it requires, so it outranks the parameterized template
|
|
29
29
|
// when both would otherwise apply.
|
|
30
30
|
//
|
|
31
|
+
// A parameterized template's `[parameters.<name>]` table comes in two
|
|
32
|
+
// shapes, picked by which of `placeholder`/`placeholders` it declares:
|
|
33
|
+
// - single-placeholder (the shape above): one `placeholder` token, and
|
|
34
|
+
// every `[parameters.<name>.values]` entry is a plain string substituted
|
|
35
|
+
// for it directly.
|
|
36
|
+
// - multi-placeholder (data/sprites-large/*.toml's gradient-shaded
|
|
37
|
+
// materials): a `placeholders` table instead, naming several tokens at
|
|
38
|
+
// once (e.g. `{ light = "{{FILL_LIGHT}}", base = "{{FILL}}", dark =
|
|
39
|
+
// "{{FILL_DARK}}" }`), and every `[parameters.<name>.values]` entry is a
|
|
40
|
+
// table with the SAME sub-keys (e.g. `{ light = "#f0dfa0", base =
|
|
41
|
+
// "#c9a24b", dark = "#8a6a1e" }`), one substituted per token. A value
|
|
42
|
+
// missing even one of the declared sub-keys is never a partial match —
|
|
43
|
+
// the same never-guess posture as an unmapped value in the single shape.
|
|
44
|
+
// sprite-materials.mjs's `expandMaterialReferences` is what lets a
|
|
45
|
+
// sprite-large file write a short by-name reference (`gold = "metal"`)
|
|
46
|
+
// instead of hand-copying the triple — this module never has to know
|
|
47
|
+
// that indirection exists, it only ever sees the expanded table shape.
|
|
48
|
+
//
|
|
49
|
+
// An object with no taught material still gets a real gradient at the
|
|
50
|
+
// sprite tier (data/sprites-large/*.toml's own non-material files), built
|
|
51
|
+
// from currentColor via `color-mix(in srgb, currentColor N%, white/black)`
|
|
52
|
+
// rather than `stop-opacity` — opacity blends toward whatever sits BEHIND
|
|
53
|
+
// the shape, so its light/dark direction silently flips between a light
|
|
54
|
+
// theme (currentColor dark-on-light) and a dark one (currentColor
|
|
55
|
+
// light-on-dark); color-mix lightens/darkens currentColor itself, so the
|
|
56
|
+
// same corner of the shape reads as the lit one on either theme.
|
|
57
|
+
//
|
|
31
58
|
// Specificity order, checked at EACH term of the class's ancestor chain
|
|
32
59
|
// (nearest first, sprite-map.mjs's own classAncestorChain) before moving to
|
|
33
60
|
// the next ancestor: an exact fully-specific variant whose [match] is
|
|
@@ -39,6 +66,7 @@
|
|
|
39
66
|
// against `rootFallback`, falling back to spriteRegistry's own root entry
|
|
40
67
|
// only if nothing there matches either.
|
|
41
68
|
import { classAncestorChain } from "./sprite-map.mjs";
|
|
69
|
+
import { namespaceSvgIds } from "./svg-instance-ids.mjs";
|
|
42
70
|
|
|
43
71
|
/** Every template in `templates` whose `classes` list names `term`. */
|
|
44
72
|
function templatesForClass(term, templates) {
|
|
@@ -50,6 +78,24 @@ function matchSatisfied(match, propertyFacts) {
|
|
|
50
78
|
return (propertyFacts || []).some((f) => f.predicate === match.property && f.object === match.value);
|
|
51
79
|
}
|
|
52
80
|
|
|
81
|
+
/** Substitute one matched `[parameters.*.values]` entry into `svg`: a plain
|
|
82
|
+
* string fills the parameter's single `placeholder` token; an object fills
|
|
83
|
+
* every token `param.placeholders` names from the SAME sub-key — returning
|
|
84
|
+
* null (never a partial gradient) if the object is missing even one of the
|
|
85
|
+
* sub-keys the parameter declares. */
|
|
86
|
+
function fillFromValue(svg, param, value) {
|
|
87
|
+
if (typeof value === "string" && param.placeholder) return svg.split(param.placeholder).join(value);
|
|
88
|
+
if (value && typeof value === "object" && param.placeholders) {
|
|
89
|
+
let out = svg;
|
|
90
|
+
for (const [sub, token] of Object.entries(param.placeholders)) {
|
|
91
|
+
if (!Object.prototype.hasOwnProperty.call(value, sub)) return null;
|
|
92
|
+
out = out.split(token).join(value[sub]);
|
|
93
|
+
}
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
53
99
|
/** Fill a parameterized template's `svg` from the first of its own
|
|
54
100
|
* `[parameters.*]` whose observed property value maps to a substitution —
|
|
55
101
|
* or null when no property fact names a mapped value (never a guess). */
|
|
@@ -59,7 +105,9 @@ function parameterizedFill(template, propertyFacts) {
|
|
|
59
105
|
const hit = (propertyFacts || []).find(
|
|
60
106
|
(f) => f.predicate === param.property && Object.prototype.hasOwnProperty.call(values, f.object),
|
|
61
107
|
);
|
|
62
|
-
if (hit)
|
|
108
|
+
if (!hit) continue;
|
|
109
|
+
const filled = fillFromValue(template.svg, param, values[hit.object]);
|
|
110
|
+
if (filled) return filled;
|
|
63
111
|
}
|
|
64
112
|
return null;
|
|
65
113
|
}
|
|
@@ -82,6 +130,17 @@ function resolveAtTerm(term, propertyFacts, templates) {
|
|
|
82
130
|
return plain ? plain.svg : null;
|
|
83
131
|
}
|
|
84
132
|
|
|
133
|
+
function resolveSpriteAssetRaw(className, factRows, propertyFacts, templates, spriteRegistry, rootFallback) {
|
|
134
|
+
for (const term of classAncestorChain(className, factRows)) {
|
|
135
|
+
const hit = resolveAtTerm(term, propertyFacts, templates);
|
|
136
|
+
if (hit) return hit;
|
|
137
|
+
if (Object.prototype.hasOwnProperty.call(spriteRegistry, term)) return spriteRegistry[term];
|
|
138
|
+
}
|
|
139
|
+
const rootHit = resolveAtTerm(rootFallback, propertyFacts, templates);
|
|
140
|
+
if (rootHit) return rootHit;
|
|
141
|
+
return spriteRegistry[rootFallback];
|
|
142
|
+
}
|
|
143
|
+
|
|
85
144
|
/**
|
|
86
145
|
* Resolve `className` to sprite SVG markup, property-aware: the ancestor
|
|
87
146
|
* chain (from `factRows`, sprite-map.mjs's own walk) is checked nearest-
|
|
@@ -91,16 +150,19 @@ function resolveAtTerm(term, propertyFacts, templates) {
|
|
|
91
150
|
* as resolveSpriteForClass already does. `propertyFacts` is the instance's
|
|
92
151
|
* own small `{predicate, object}` fact set (e.g. its mgx:hasProperty rows) —
|
|
93
152
|
* read only, never required to be non-empty. Pure.
|
|
153
|
+
*
|
|
154
|
+
* `instanceKey`, when given, namespaces every gradient id the resolved svg
|
|
155
|
+
* declares (svg-instance-ids.mjs's own `namespaceSvgIds`) — pass the
|
|
156
|
+
* instance's own identity (e.g. its subject name) whenever more than one
|
|
157
|
+
* resolved sprite can appear in the same document at once, so two
|
|
158
|
+
* differently-valued instances of the SAME template (a gold lamp and a
|
|
159
|
+
* ceramic lamp both on screen) never share one `<linearGradient id>` and
|
|
160
|
+
* silently render each other's colours. Omit it for a single-instance
|
|
161
|
+
* caller (a template with no ids at all is untouched either way).
|
|
94
162
|
*/
|
|
95
|
-
export function resolveSpriteAsset(className, factRows, propertyFacts, templates, spriteRegistry, { rootFallback = "animal" } = {}) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (hit) return hit;
|
|
99
|
-
if (Object.prototype.hasOwnProperty.call(spriteRegistry, term)) return spriteRegistry[term];
|
|
100
|
-
}
|
|
101
|
-
const rootHit = resolveAtTerm(rootFallback, propertyFacts, templates);
|
|
102
|
-
if (rootHit) return rootHit;
|
|
103
|
-
return spriteRegistry[rootFallback];
|
|
163
|
+
export function resolveSpriteAsset(className, factRows, propertyFacts, templates, spriteRegistry, { rootFallback = "animal", instanceKey } = {}) {
|
|
164
|
+
const svg = resolveSpriteAssetRaw(className, factRows, propertyFacts, templates, spriteRegistry, rootFallback);
|
|
165
|
+
return instanceKey ? namespaceSvgIds(svg, instanceKey) : svg;
|
|
104
166
|
}
|
|
105
167
|
|
|
106
168
|
/** Every internal-consistency problem with one parsed template, as plain
|
|
@@ -109,8 +171,10 @@ export function resolveSpriteAsset(className, factRows, propertyFacts, templates
|
|
|
109
171
|
* data/sprites/ directory) and available to any future loader that wants to
|
|
110
172
|
* warn rather than silently drop a broken file. Checks: `classes` is a
|
|
111
173
|
* non-empty array, `svg` is a real `<svg` string, a `[parameters.*]` table
|
|
112
|
-
* names a `property` and
|
|
113
|
-
*
|
|
174
|
+
* names a `property` and exactly one of `placeholder`/`placeholders` (every
|
|
175
|
+
* token named appears in `svg`), its `values` map is non-empty and every
|
|
176
|
+
* entry matches the shape its own `placeholder`/`placeholders` choice
|
|
177
|
+
* expects, and a `[match]` table names both `property` and `value`. */
|
|
114
178
|
export function spriteTemplateProblems(template) {
|
|
115
179
|
const problems = [];
|
|
116
180
|
const t = template || {};
|
|
@@ -118,11 +182,38 @@ export function spriteTemplateProblems(template) {
|
|
|
118
182
|
if (typeof t.svg !== "string" || !t.svg.trim().startsWith("<svg")) problems.push("svg is missing or not an <svg> string");
|
|
119
183
|
for (const [name, param] of Object.entries(t.parameters || {})) {
|
|
120
184
|
if (!param?.property) problems.push(`parameters.${name}.property is missing`);
|
|
121
|
-
if (
|
|
122
|
-
|
|
185
|
+
if (param?.placeholder && param?.placeholders) {
|
|
186
|
+
problems.push(`parameters.${name} sets both placeholder and placeholders — pick one`);
|
|
187
|
+
} else if (param?.placeholders) {
|
|
188
|
+
const tokens = Object.entries(param.placeholders);
|
|
189
|
+
if (tokens.length === 0) problems.push(`parameters.${name}.placeholders is empty`);
|
|
190
|
+
for (const [sub, token] of tokens) {
|
|
191
|
+
if (typeof t.svg === "string" && !t.svg.includes(token)) {
|
|
192
|
+
problems.push(`parameters.${name}.placeholders.${sub} ${JSON.stringify(token)} does not appear in svg`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
} else if (!param?.placeholder) {
|
|
196
|
+
problems.push(`parameters.${name}.placeholder is missing`);
|
|
197
|
+
} else if (typeof t.svg === "string" && !t.svg.includes(param.placeholder)) {
|
|
123
198
|
problems.push(`parameters.${name}.placeholder ${JSON.stringify(param.placeholder)} does not appear in svg`);
|
|
124
199
|
}
|
|
125
|
-
if (!param?.values || Object.keys(param.values).length === 0)
|
|
200
|
+
if (!param?.values || Object.keys(param.values).length === 0) {
|
|
201
|
+
problems.push(`parameters.${name}.values is empty`);
|
|
202
|
+
} else {
|
|
203
|
+
for (const [key, value] of Object.entries(param.values)) {
|
|
204
|
+
if (param.placeholders) {
|
|
205
|
+
if (!value || typeof value !== "object") {
|
|
206
|
+
problems.push(`parameters.${name}.values.${key} is not an expanded {${Object.keys(param.placeholders).join("/")}} object — an unresolved material reference?`);
|
|
207
|
+
} else {
|
|
208
|
+
for (const sub of Object.keys(param.placeholders)) {
|
|
209
|
+
if (!Object.prototype.hasOwnProperty.call(value, sub)) problems.push(`parameters.${name}.values.${key} is missing "${sub}"`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} else if (typeof value !== "string") {
|
|
213
|
+
problems.push(`parameters.${name}.values.${key} must be a plain string for a single-placeholder parameter`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
126
217
|
}
|
|
127
218
|
if (t.match && (!t.match.property || t.match.value === undefined)) {
|
|
128
219
|
problems.push("match is missing property or value");
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// svg-instance-ids.mjs — a resolved sprite's own `id="…"`/`url(#…)` pairs
|
|
2
|
+
// (a gradient def and its fill/stroke reference) made unique per rendered
|
|
3
|
+
// instance. It exists because two DIFFERENT resolved values of the SAME
|
|
4
|
+
// class's SAME template — e.g. a gold lamp and a ceramic lamp, both on
|
|
5
|
+
// screen at once — share the identical `id="lamp-fill"` string (the id lives
|
|
6
|
+
// in the TEMPLATE, not the substituted colour), and duplicate ids are a real
|
|
7
|
+
// bug, not a cosmetic one: a browser's `url(#id)` reference resolves to
|
|
8
|
+
// whichever element with that id it saw FIRST in the document, so every
|
|
9
|
+
// later instance silently renders the FIRST instance's colours. Namespacing
|
|
10
|
+
// each id (and every reference to it) by the caller's own instanceKey before
|
|
11
|
+
// two instances share a DOM keeps each gradient its own.
|
|
12
|
+
//
|
|
13
|
+
// A resolved sprite with no ids at all (most non-material templates carry
|
|
14
|
+
// none) is untouched — this is a no-op unless there's actually a collision
|
|
15
|
+
// to prevent.
|
|
16
|
+
|
|
17
|
+
/** Every id `svg` declares, in first-appearance order. */
|
|
18
|
+
function idsIn(svg) {
|
|
19
|
+
return [...new Set([...svg.matchAll(/\bid="([^"]+)"/g)].map((m) => m[1]))];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Suffix every `id="X"` and every `url(#X)` reference to it in `svg` with
|
|
24
|
+
* `-{instanceKey}` (sanitized to id-safe characters) — so the SAME template
|
|
25
|
+
* resolved for two different instances never collides once both are in the
|
|
26
|
+
* same document. `instanceKey` falsy (undefined/""/0) returns `svg`
|
|
27
|
+
* unchanged, the same never-touch-it-unless-asked posture as any other
|
|
28
|
+
* optional pass-through in this pack. Pure.
|
|
29
|
+
*/
|
|
30
|
+
export function namespaceSvgIds(svg, instanceKey) {
|
|
31
|
+
if (!instanceKey || typeof svg !== "string") return svg;
|
|
32
|
+
const safe = String(instanceKey).replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
33
|
+
let out = svg;
|
|
34
|
+
for (const id of idsIn(svg)) {
|
|
35
|
+
const namespaced = `${id}-${safe}`;
|
|
36
|
+
out = out.split(`id="${id}"`).join(`id="${namespaced}"`);
|
|
37
|
+
out = out.split(`url(#${id})`).join(`url(#${namespaced})`);
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# adventurer — the player's own sprite: the person silhouette plus a
|
|
2
|
-
# strap-and-satchel, so the one individual the player controls always
|
|
3
|
-
# reads as visually distinct from the room's own cast of NPCs.
|
|
4
|
-
classes = ["adventurer"]
|
|
5
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.6" r="3.3" fill="currentColor"/><path d="M6 21 C6 15.3 8.7 12.8 12 12.8 C15.3 12.8 18 15.3 18 21 Z" fill="currentColor"/><path d="M8.4 13.4 L17 17.6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity="0.85"/><rect x="14.6" y="15.8" width="5" height="4.6" rx="1" fill="currentColor" opacity="0.6"/><rect x="16.3" y="16.6" width="1.6" height="1.2" rx="0.3" fill="currentColor" opacity="0.9"/></svg>"""
|
package/data/sprites/animal.toml
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
# animal — the deliberately plainest shape in the set: an unadorned
|
|
2
|
-
# four-legged blob, so an unregistered species reads as "some animal"
|
|
3
|
-
# rather than suggesting one the taxonomy never named. The declared root
|
|
4
|
-
# fallback for the spider-and-fly world.
|
|
5
|
-
classes = ["animal"]
|
|
6
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><ellipse cx="12" cy="13" rx="7" ry="4.4" fill="currentColor"/><circle cx="12" cy="7" r="3.4" fill="currentColor"/><g stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><line x1="7" y1="17" x2="7" y2="21"/><line x1="17" y1="17" x2="17" y2="21"/></g></svg>"""
|
package/data/sprites/butler.toml
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# butler — Ashcombe Hall's own butler: the person silhouette plus a stiff
|
|
2
|
-
# wing-collar flaring OUT past the shoulder line (changing the outer
|
|
3
|
-
# silhouette, not an internal opacity knockout — an internal light-on-dark
|
|
4
|
-
# accent was tried first and proved invisible once shrunk to 44px; a
|
|
5
|
-
# silhouette change survives shrinking the way gardener.toml's wide brim
|
|
6
|
-
# does) and a bow-tie.
|
|
7
|
-
classes = ["butler"]
|
|
8
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.6" r="3.3" fill="currentColor"/><path d="M6 21 C6 15.3 8.7 12.8 12 12.8 C15.3 12.8 18 15.3 18 21 Z" fill="currentColor"/><path d="M7.6 11.6 L11.3 13.2 L8.6 15.4 Z" fill="currentColor"/><path d="M16.4 11.6 L12.7 13.2 L15.4 15.4 Z" fill="currentColor"/><path d="M10.6 14.2 L12 16.1 L13.4 14.2 L12 18.6 Z" fill="currentColor" opacity="0.95"/></svg>"""
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# cabinet — Ashcombe Hall's own locked cabinet (a container): a two-door
|
|
2
|
-
# wardrobe silhouette, the gap between the doors reading as the seam, with
|
|
3
|
-
# two knobs and a cornice band.
|
|
4
|
-
classes = ["cabinet"]
|
|
5
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="4.5" y="2.5" width="7.2" height="19" rx="1" fill="currentColor"/><rect x="12.3" y="2.5" width="7.2" height="19" rx="1" fill="currentColor"/><rect x="4.5" y="2.5" width="15" height="1.4" fill="currentColor" opacity="0.4"/><circle cx="10.6" cy="12" r="0.9" fill="currentColor" opacity="0.35"/><circle cx="13.4" cy="12" r="0.9" fill="currentColor" opacity="0.35"/></svg>"""
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# container — the generic fallback for any container with no sprite of
|
|
2
|
-
# its own (see cabinet/portrait for Ashcombe Hall's own two): a solid
|
|
3
|
-
# chest silhouette with a carved lid-seam and a latch highlight.
|
|
4
|
-
classes = ["container"]
|
|
5
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 10 L5 5 H19 L21 10 Z" fill="currentColor"/><rect x="3" y="10" width="18" height="10" rx="1.2" fill="currentColor"/><rect x="3" y="10" width="18" height="1.6" fill="currentColor" opacity="0.35"/><rect x="10.6" y="9.2" width="2.8" height="2.6" rx="0.5" fill="currentColor" opacity="0.85"/></svg>"""
|
package/data/sprites/desk.toml
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
# desk — Ashcombe Hall's own study desk: a tabletop bar over two drawer
|
|
2
|
-
# blocks with pull-knobs, on tapered legs.
|
|
3
|
-
classes = ["desk"]
|
|
4
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="7" width="18" height="2.6" rx="0.6" fill="currentColor"/><rect x="4.4" y="9.6" width="6.6" height="5.6" rx="0.6" fill="currentColor" opacity="0.85"/><rect x="13" y="9.6" width="6.6" height="5.6" rx="0.6" fill="currentColor" opacity="0.85"/><circle cx="9.6" cy="12.4" r="0.55" fill="currentColor" opacity="0.4"/><circle cx="16.4" cy="12.4" r="0.55" fill="currentColor" opacity="0.4"/><path d="M4.6 15.2 L3.8 20.5 L5.6 20.5 L6.2 15.2 Z" fill="currentColor"/><path d="M17.8 15.2 L17.2 20.5 L19 20.5 L18.2 15.2 Z" fill="currentColor"/></svg>"""
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# dog-with-colour — the parameterized-property worked example
|
|
2
|
-
# (PLAN target: "a dog that is black"). Same silhouette as dog.toml, but
|
|
3
|
-
# every filled shape takes its color from the instance's OWN observed
|
|
4
|
-
# mgx:hasProperty value rather than the page's currentColor accent, with a
|
|
5
|
-
# thin currentColor stroke kept on each shape so a light value (white)
|
|
6
|
-
# still reads against a light card background. A property value with no
|
|
7
|
-
# entry in [parameters.colour.values] is not a match for this template at
|
|
8
|
-
# all (see sprite-templates.mjs's own header for the naming/specificity
|
|
9
|
-
# convention) — it falls through to the plain dog.toml sprite, never a
|
|
10
|
-
# guessed color.
|
|
11
|
-
classes = ["dog"]
|
|
12
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><ellipse cx="13" cy="15" rx="6.4" ry="4.3" fill="{{FILL}}" stroke="currentColor" stroke-width="0.9"/><circle cx="7" cy="9" r="3.6" fill="{{FILL}}" stroke="currentColor" stroke-width="0.9"/><path d="M4.5 6.5 L2 3 L6 5 Z" fill="{{FILL}}" stroke="currentColor" stroke-width="0.9"/><path d="M19 13 C22 12 22.5 15 20 16 Z" fill="{{FILL}}" stroke="currentColor" stroke-width="0.9"/><g stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><line x1="9" y1="19" x2="9" y2="22"/><line x1="17" y1="19" x2="17" y2="22"/></g></svg>"""
|
|
13
|
-
|
|
14
|
-
[parameters.colour]
|
|
15
|
-
property = "mgx:hasProperty"
|
|
16
|
-
placeholder = "{{FILL}}"
|
|
17
|
-
|
|
18
|
-
[parameters.colour.values]
|
|
19
|
-
black = "#22201d"
|
|
20
|
-
white = "#f5f2ea"
|
package/data/sprites/dog.toml
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# dog — the plain-class sprite a taxonomy hop away from poodle/sheepdog.
|
|
2
|
-
# Same body language as poodle's, without the pompom cut, so the family
|
|
3
|
-
# reads as one dog rather than two unrelated animals.
|
|
4
|
-
classes = ["dog"]
|
|
5
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><ellipse cx="13" cy="15" rx="6.4" ry="4.3" fill="currentColor"/><circle cx="7" cy="9" r="3.6" fill="currentColor"/><ellipse cx="6.1" cy="8" rx="1" ry="1.3" fill="currentColor" opacity="0.3"/><path d="M4.5 6.5 L2 3 L6 5 Z" fill="currentColor"/><path d="M19 13 C22 12 22.5 15 20 16 Z" fill="currentColor"/><g stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><line x1="9" y1="19" x2="9" y2="22"/><line x1="17" y1="19" x2="17" y2="22"/></g></svg>"""
|
package/data/sprites/egg.toml
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
# egg — the spider-and-fly board's laid egg. The plain shell silhouette
|
|
2
|
-
# plus one small carved highlight.
|
|
3
|
-
classes = ["egg"]
|
|
4
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2 C7 2 4 10 4 15.5 C4 20 7.6 22 12 22 C16.4 22 20 20 20 15.5 C20 10 17 2 12 2 Z" fill="currentColor"/><ellipse cx="9.6" cy="9.5" rx="1.7" ry="2.4" fill="currentColor" opacity="0.28"/></svg>"""
|
package/data/sprites/fly.toml
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# fly — the spider-and-fly board's other agent. A round head, a tapered
|
|
2
|
-
# body with a carved highlight, translucent wings, and two thin trailing
|
|
3
|
-
# legs for a touch of character at rest.
|
|
4
|
-
classes = ["fly"]
|
|
5
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><ellipse cx="12" cy="13.6" rx="3.4" ry="5.2" fill="currentColor"/><circle cx="12" cy="7" r="2.7" fill="currentColor"/><ellipse cx="11.1" cy="12" rx="1.1" ry="1.7" fill="currentColor" opacity="0.3"/><g fill="currentColor" opacity="0.55"><path d="M9 10 C3 6 2 4 3 2 C6 2 9 6 10.5 10 Z"/><path d="M15 10 C21 6 22 4 21 2 C18 2 15 6 13.5 10 Z"/></g><g stroke="currentColor" stroke-width="1" stroke-linecap="round"><path d="M9.6 17 L7.4 19.4"/><path d="M14.4 17 L16.6 19.4"/></g></svg>"""
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# furniture — the generic fallback for any furniture piece with no sprite
|
|
2
|
-
# of its own: a solid console-table silhouette (tapered legs, a carved
|
|
3
|
-
# highlight along the top edge), replacing the old hollow-shelf outline.
|
|
4
|
-
classes = ["furniture"]
|
|
5
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3.5" y="6.5" width="17" height="3.2" rx="0.8" fill="currentColor"/><rect x="3.5" y="6.5" width="17" height="1" fill="currentColor" opacity="0.35"/><path d="M5.6 9.7 L4.6 20 L6.7 20 L7.2 9.7 Z" fill="currentColor"/><path d="M18.4 9.7 L16.8 20 L18.9 20 L19.4 9.7 Z" fill="currentColor"/></svg>"""
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
# gardener — Ashcombe Hall's own gardener: the person silhouette under a
|
|
2
|
-
# wide sunhat brim.
|
|
3
|
-
classes = ["gardener"]
|
|
4
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><ellipse cx="12" cy="5.6" rx="7.4" ry="2" fill="currentColor"/><path d="M8.8 5.2 C8.8 3.1 10.2 1.6 12 1.6 C13.8 1.6 15.2 3.1 15.2 5.2 C15.2 5.6 15.1 6 15 6.3 L9 6.3 C8.9 6 8.8 5.6 8.8 5.2 Z" fill="currentColor" opacity="0.85"/><circle cx="12" cy="8.6" r="3.1" fill="currentColor"/><path d="M6 21 C6 15.5 8.7 13.1 12 13.1 C15.3 13.1 18 15.5 18 21 Z" fill="currentColor"/></svg>"""
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
# housekeeper — Ashcombe Hall's own housekeeper: the person silhouette
|
|
2
|
-
# under a wide mob-cap brim (deliberately WIDER than the head, the same
|
|
3
|
-
# "wide silhouette reads at 44px" move gardener.toml's sunhat uses) and a
|
|
4
|
-
# tied apron line.
|
|
5
|
-
classes = ["housekeeper"]
|
|
6
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><ellipse cx="12" cy="4.6" rx="5.6" ry="2.1" fill="currentColor"/><path d="M8.6 5 C8.6 3 10 1.7 12 1.7 C14 1.7 15.4 3 15.4 5 L15.4 5.6 L8.6 5.6 Z" fill="currentColor" opacity="0.9"/><circle cx="12" cy="7.6" r="3.1" fill="currentColor"/><path d="M6 21 C6 15.5 8.7 13.1 12 13.1 C15.3 13.1 18 15.5 18 21 Z" fill="currentColor"/><path d="M9 16 C10 15.4 14 15.4 15 16" fill="none" stroke="currentColor" stroke-width="1" opacity="0.45" stroke-linecap="round"/></svg>"""
|
package/data/sprites/key.toml
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# key — Ashcombe Hall's own key (hidden in the portrait, unlocks the
|
|
2
|
-
# cabinet): a classic round-bow skeleton key, bold strokes so it stays
|
|
3
|
-
# legible at a 44px render.
|
|
4
|
-
classes = ["key"]
|
|
5
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="7" cy="9" r="4.4" fill="none" stroke="currentColor" stroke-width="2.4"/><path d="M10.4 12 L19.5 21.1" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/><path d="M16.4 17.1 L18.6 14.9" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><path d="M18.6 19.3 L20.6 17.3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>"""
|
package/data/sprites/lamp.toml
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
# lamp — Ashcombe Hall's own study lamp: a Victorian hurricane-lamp
|
|
2
|
-
# silhouette — base, glass globe, a neck, and a small carved flame.
|
|
3
|
-
classes = ["lamp"]
|
|
4
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9 21 H15 L14 18 H10 Z" fill="currentColor"/><path d="M8.4 18 C7 15.6 7 12.6 8.6 10.4 H15.4 C17 12.6 17 15.6 15.6 18 Z" fill="currentColor"/><rect x="10.6" y="6.4" width="2.8" height="4.4" fill="currentColor" opacity="0.85"/><path d="M12 3.2 C13.4 4.6 13.8 6 12 7.4 C10.2 6 10.6 4.6 12 3.2 Z" fill="currentColor" opacity="0.55"/></svg>"""
|
package/data/sprites/letter.toml
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# letter — Ashcombe Hall's own objective (hidden in the cabinet): an
|
|
2
|
-
# envelope with a folded flap (a lighter overlay, the same carved-highlight
|
|
3
|
-
# trick as the lid on container.toml) and a small wax seal.
|
|
4
|
-
classes = ["letter"]
|
|
5
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="6" width="18" height="13" rx="1.2" fill="currentColor"/><path d="M3 6 L21 6 L21 6.8 L12 13.8 L3 6.8 Z" fill="currentColor" opacity="0.32"/><circle cx="12" cy="12.4" r="1.15" fill="currentColor" opacity="0.8"/></svg>"""
|
package/data/sprites/person.toml
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
# person — the generic fallback for anyone with no NPC sprite of their own
|
|
2
|
-
# (see butler/housekeeper/cook/gardener for the named Ashcombe Hall staff).
|
|
3
|
-
classes = ["person"]
|
|
4
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6.6" r="3.3" fill="currentColor"/><path d="M6 21 C6 15.3 8.7 12.8 12 12.8 C15.3 12.8 18 15.3 18 21 Z" fill="currentColor"/><path d="M12 12.8 C13.1 12.8 14.1 13 15 13.4" fill="none" stroke="currentColor" stroke-width="0.9" opacity="0.4" stroke-linecap="round"/></svg>"""
|
package/data/sprites/poodle.toml
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# poodle — the seed taxonomy's worked example (poodle IsA dog): its own
|
|
2
|
-
# pompom-cut head and tail, distinct from the plain dog sprite it would
|
|
3
|
-
# otherwise fall back to.
|
|
4
|
-
classes = ["poodle"]
|
|
5
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><ellipse cx="13" cy="15" rx="6.4" ry="4.6" fill="currentColor"/><ellipse cx="10.8" cy="13.2" rx="1.8" ry="1.3" fill="currentColor" opacity="0.28"/><circle cx="7" cy="8.5" r="4" fill="currentColor"/><g fill="currentColor"><circle cx="4" cy="6" r="1.6"/><circle cx="7" cy="4.2" r="1.7"/><circle cx="10" cy="6" r="1.6"/></g><rect x="18.5" y="14" width="2.2" height="6" rx="1.1" fill="currentColor"/><circle cx="19.6" cy="13" r="1.5" fill="currentColor"/><g stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><line x1="9" y1="19.5" x2="9" y2="22"/><line x1="17" y1="19.5" x2="17" y2="22"/></g></svg>"""
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
# portable — the generic fallback for any carryable object with no sprite
|
|
2
|
-
# of its own: a drawstring parcel silhouette, replacing the old
|
|
3
|
-
# generic-gift-box outline so it reads as "an unspecified small thing"
|
|
4
|
-
# rather than a gift.
|
|
5
|
-
classes = ["portable"]
|
|
6
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 6 C7.5 6 5 9.4 5 13.4 C5 17.7 8.1 20 12 20 C15.9 20 19 17.7 19 13.4 C19 9.4 16.5 6 12 6 Z" fill="currentColor"/><path d="M9.4 6.4 C9.9 4.6 10.8 3.4 12 3.4 C13.2 3.4 14.1 4.6 14.6 6.4" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/><ellipse cx="9.8" cy="11.6" rx="1.6" ry="2.1" fill="currentColor" opacity="0.28"/></svg>"""
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# portrait — Ashcombe Hall's own drawing-room portrait (a container, hiding
|
|
2
|
-
# the key): a gilt arched frame around a lighter canvas, with a bust
|
|
3
|
-
# silhouette so it reads as a picture of someone, not an empty frame.
|
|
4
|
-
classes = ["portrait"]
|
|
5
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 21 V7 C4 4 6.8 2 12 2 C17.2 2 20 4 20 7 V21 Z" fill="currentColor"/><path d="M6.3 19.4 V8.3 C6.3 6.2 8.4 4.8 12 4.8 C15.6 4.8 17.7 6.2 17.7 8.3 V19.4 Z" fill="currentColor" opacity="0.28"/><circle cx="12" cy="10.4" r="2.3" fill="currentColor" opacity="0.7"/><path d="M8 18.4 C8 15.2 9.6 13.4 12 13.4 C14.4 13.4 16 15.2 16 18.4 Z" fill="currentColor" opacity="0.7"/></svg>"""
|
package/data/sprites/room.toml
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# room — a schematic floor plan: a washed interior (a solid tint, not a
|
|
2
|
-
# hollow box) plus a doorway arch, kept abstract since a room is a space
|
|
3
|
-
# to draw, not an object to render literally.
|
|
4
|
-
classes = ["room"]
|
|
5
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="1" fill="currentColor" opacity="0.14"/><rect x="3" y="3" width="18" height="18" rx="1" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M9 21 L9 13 A3 3 0 0 1 15 13 L15 21" fill="none" stroke="currentColor" stroke-width="1.6"/></svg>"""
|
package/data/sprites/spider.toml
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# spider — the spider-and-fly board's own agent. A confident two-lobe body
|
|
2
|
-
# (a lighter carved patch on the abdomen for shading) and eight thin
|
|
3
|
-
# outward legs.
|
|
4
|
-
classes = ["spider"]
|
|
5
|
-
svg = """<svg viewBox="0 0 24 24" aria-hidden="true"><ellipse cx="12" cy="16" rx="5.2" ry="4.8" fill="currentColor"/><ellipse cx="10.3" cy="14.3" rx="1.8" ry="1.4" fill="currentColor" opacity="0.3"/><circle cx="12" cy="9.6" r="3.2" fill="currentColor"/><g stroke="currentColor" stroke-width="1.1" fill="none" stroke-linecap="round"><path d="M9.4 8 L2.2 4.4"/><path d="M9 10.2 L1.4 9.4"/><path d="M9.2 12.6 L2 14.2"/><path d="M10 15.4 L3.4 19"/><path d="M14.6 8 L21.8 4.4"/><path d="M15 10.2 L22.6 9.4"/><path d="M14.8 12.6 L22 14.2"/><path d="M14 15.4 L20.6 19"/></g></svg>"""
|