diff --git a/stock/.playwright-mcp/page-2026-01-22T07-30-13-408Z.png b/stock/.playwright-mcp/page-2026-01-22T07-30-13-408Z.png
new file mode 100644
index 0000000..d1a9213
Binary files /dev/null and b/stock/.playwright-mcp/page-2026-01-22T07-30-13-408Z.png differ
diff --git a/stock/.playwright-mcp/page-2026-01-22T07-34-16-652Z.png b/stock/.playwright-mcp/page-2026-01-22T07-34-16-652Z.png
new file mode 100644
index 0000000..e3dcd07
Binary files /dev/null and b/stock/.playwright-mcp/page-2026-01-22T07-34-16-652Z.png differ
diff --git a/stock/.playwright-mcp/page-2026-01-22T07-45-58-532Z.png b/stock/.playwright-mcp/page-2026-01-22T07-45-58-532Z.png
new file mode 100644
index 0000000..abba1a2
Binary files /dev/null and b/stock/.playwright-mcp/page-2026-01-22T07-45-58-532Z.png differ
diff --git a/stock/avatar/body-arm-left.svg b/stock/avatar/body-arm-left.svg
new file mode 100644
index 0000000..3655c64
--- /dev/null
+++ b/stock/avatar/body-arm-left.svg
@@ -0,0 +1,26 @@
+
diff --git a/stock/avatar/body-arm-right.svg b/stock/avatar/body-arm-right.svg
new file mode 100644
index 0000000..35cd14b
--- /dev/null
+++ b/stock/avatar/body-arm-right.svg
@@ -0,0 +1,26 @@
+
diff --git a/stock/avatar/body-hand-left.svg b/stock/avatar/body-hand-left.svg
new file mode 100644
index 0000000..e06e0f3
--- /dev/null
+++ b/stock/avatar/body-hand-left.svg
@@ -0,0 +1,32 @@
+
diff --git a/stock/avatar/body-hand-right.svg b/stock/avatar/body-hand-right.svg
new file mode 100644
index 0000000..a172021
--- /dev/null
+++ b/stock/avatar/body-hand-right.svg
@@ -0,0 +1,32 @@
+
diff --git a/stock/avatar/body-neck.svg b/stock/avatar/body-neck.svg
new file mode 100644
index 0000000..67b90e5
--- /dev/null
+++ b/stock/avatar/body-neck.svg
@@ -0,0 +1,17 @@
+
diff --git a/stock/avatar/body-sparkle.svg b/stock/avatar/body-sparkle.svg
new file mode 100644
index 0000000..963dd93
--- /dev/null
+++ b/stock/avatar/body-sparkle.svg
@@ -0,0 +1,24 @@
+
diff --git a/stock/avatar/body-torso.svg b/stock/avatar/body-torso.svg
new file mode 100644
index 0000000..3e0333b
--- /dev/null
+++ b/stock/avatar/body-torso.svg
@@ -0,0 +1,34 @@
+
diff --git a/stock/avatar/create-stock-avatar.sh b/stock/avatar/create-stock-avatar.sh
new file mode 100755
index 0000000..cdf96aa
--- /dev/null
+++ b/stock/avatar/create-stock-avatar.sh
@@ -0,0 +1,238 @@
+#!/bin/bash
+# Create a stock avatar from uploaded props and set it as server default.
+#
+# Usage: ./stock/avatar/create-stock-avatar.sh [--force|-f] [HOST]
+#
+# Prerequisites:
+# 1. Props must be uploaded first: ./stock/avatar/upload-stockavatars.sh
+# 2. Dev server must be running: ./run-dev.sh -f
+#
+# This script:
+# 1. Queries existing props by slug to get UUIDs
+# 2. Creates a server avatar with all emotion slots populated
+# 3. Sets the avatar as the server default for all gender/age combinations
+
+set -e
+
+# Parse arguments
+FORCE=""
+HOST="http://localhost:3001"
+DB="chattyness"
+
+for arg in "$@"; do
+ case "$arg" in
+ --force|-f)
+ FORCE="?force=true"
+ ;;
+ http://*)
+ HOST="$arg"
+ ;;
+ esac
+done
+
+echo "=========================================="
+echo "Creating Stock Avatar"
+echo "=========================================="
+echo "Host: $HOST"
+echo "Database: $DB"
+echo ""
+
+# Check if server is running
+echo "Checking server health..."
+health_response=$(curl -s -o /dev/null -w "%{http_code}" "$HOST/api/admin/health" 2>/dev/null || echo "000")
+if [ "$health_response" != "200" ]; then
+ echo "ERROR: Server is not responding at $HOST (HTTP $health_response)"
+ echo "Make sure the server is running: ./run-dev.sh -f"
+ exit 1
+fi
+echo "Server is healthy!"
+echo ""
+
+# Query prop UUIDs by slug
+echo "Querying prop UUIDs..."
+
+get_prop_id() {
+ local slug="$1"
+ psql -d "$DB" -t -A -c "SELECT id FROM server.props WHERE slug = '$slug'" 2>/dev/null | tr -d '[:space:]'
+}
+
+# Get face prop (skin layer)
+FACE_ID=$(get_prop_id "face")
+if [ -z "$FACE_ID" ]; then
+ echo "ERROR: Face prop not found. Run upload-stockavatars.sh first."
+ exit 1
+fi
+echo " face: $FACE_ID"
+
+# Get emotion props
+NEUTRAL_ID=$(get_prop_id "neutral")
+SMILE_ID=$(get_prop_id "smile") # This is "happy" emotion
+SAD_ID=$(get_prop_id "sad")
+ANGRY_ID=$(get_prop_id "angry")
+SURPRISED_ID=$(get_prop_id "surprised")
+THINKING_ID=$(get_prop_id "thinking")
+LAUGHING_ID=$(get_prop_id "laughing")
+CRYING_ID=$(get_prop_id "crying")
+LOVE_ID=$(get_prop_id "love")
+CONFUSED_ID=$(get_prop_id "confused")
+SLEEPING_ID=$(get_prop_id "sleeping")
+WINK_ID=$(get_prop_id "wink")
+
+# Validate all emotion props exist
+missing=""
+[ -z "$NEUTRAL_ID" ] && missing="$missing neutral"
+[ -z "$SMILE_ID" ] && missing="$missing smile"
+[ -z "$SAD_ID" ] && missing="$missing sad"
+[ -z "$ANGRY_ID" ] && missing="$missing angry"
+[ -z "$SURPRISED_ID" ] && missing="$missing surprised"
+[ -z "$THINKING_ID" ] && missing="$missing thinking"
+[ -z "$LAUGHING_ID" ] && missing="$missing laughing"
+[ -z "$CRYING_ID" ] && missing="$missing crying"
+[ -z "$LOVE_ID" ] && missing="$missing love"
+[ -z "$CONFUSED_ID" ] && missing="$missing confused"
+[ -z "$SLEEPING_ID" ] && missing="$missing sleeping"
+[ -z "$WINK_ID" ] && missing="$missing wink"
+
+if [ -n "$missing" ]; then
+ echo "ERROR: Missing emotion props:$missing"
+ echo "Run upload-stockavatars.sh first."
+ exit 1
+fi
+
+echo " neutral: $NEUTRAL_ID"
+echo " smile (happy): $SMILE_ID"
+echo " sad: $SAD_ID"
+echo " angry: $ANGRY_ID"
+echo " surprised: $SURPRISED_ID"
+echo " thinking: $THINKING_ID"
+echo " laughing: $LAUGHING_ID"
+echo " crying: $CRYING_ID"
+echo " love: $LOVE_ID"
+echo " confused: $CONFUSED_ID"
+echo " sleeping: $SLEEPING_ID"
+echo " wink: $WINK_ID"
+echo ""
+
+# Check if avatar already exists
+existing_avatar=$(psql -d "$DB" -t -A -c "SELECT id FROM server.avatars WHERE slug = 'stock-avatar'" 2>/dev/null | tr -d '[:space:]')
+
+if [ -n "$existing_avatar" ] && [ -z "$FORCE" ]; then
+ echo "Stock avatar already exists with ID: $existing_avatar"
+ echo "Use --force to recreate it."
+ AVATAR_ID="$existing_avatar"
+else
+ # Create the avatar via API
+ echo "Creating stock avatar via API..."
+
+ # Build the JSON payload
+ avatar_json=$(cat < /dev/null
+ fi
+
+ # Create the avatar
+ response=$(curl -s -w "\n%{http_code}" -X POST "$HOST/api/admin/avatars" \
+ -H "Content-Type: application/json" \
+ -d "$avatar_json")
+
+ http_code=$(echo "$response" | tail -n1)
+ body=$(echo "$response" | sed '$d')
+
+ if [ "$http_code" = "200" ] || [ "$http_code" = "201" ]; then
+ AVATAR_ID=$(echo "$body" | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4)
+ echo " ✓ Created avatar: $AVATAR_ID"
+ else
+ echo " ✗ Failed to create avatar (HTTP $http_code): $body"
+ exit 1
+ fi
+fi
+
+echo ""
+
+# Set as server default for all gender/age combinations
+echo "Setting stock avatar as server defaults..."
+
+psql -d "$DB" -c "
+UPDATE server.config SET
+ default_avatar_neutral_child = '$AVATAR_ID',
+ default_avatar_neutral_adult = '$AVATAR_ID',
+ default_avatar_male_child = '$AVATAR_ID',
+ default_avatar_male_adult = '$AVATAR_ID',
+ default_avatar_female_child = '$AVATAR_ID',
+ default_avatar_female_adult = '$AVATAR_ID',
+ updated_at = now()
+WHERE id = '00000000-0000-0000-0000-000000000001'
+" > /dev/null
+
+echo " ✓ Set all 6 default avatar columns"
+echo ""
+
+# Verify
+echo "=========================================="
+echo "Verification"
+echo "=========================================="
+
+# Check avatar slots
+echo "Avatar emotion slots populated:"
+psql -d "$DB" -t -c "
+SELECT
+ CASE WHEN l_skin_4 IS NOT NULL THEN '✓' ELSE '✗' END || ' body (l_skin_4)',
+ CASE WHEN e_neutral_4 IS NOT NULL THEN '✓' ELSE '✗' END || ' neutral',
+ CASE WHEN e_happy_4 IS NOT NULL THEN '✓' ELSE '✗' END || ' happy',
+ CASE WHEN e_sad_4 IS NOT NULL THEN '✓' ELSE '✗' END || ' sad',
+ CASE WHEN e_angry_4 IS NOT NULL THEN '✓' ELSE '✗' END || ' angry',
+ CASE WHEN e_surprised_4 IS NOT NULL THEN '✓' ELSE '✗' END || ' surprised',
+ CASE WHEN e_thinking_4 IS NOT NULL THEN '✓' ELSE '✗' END || ' thinking',
+ CASE WHEN e_laughing_4 IS NOT NULL THEN '✓' ELSE '✗' END || ' laughing',
+ CASE WHEN e_crying_4 IS NOT NULL THEN '✓' ELSE '✗' END || ' crying',
+ CASE WHEN e_love_4 IS NOT NULL THEN '✓' ELSE '✗' END || ' love',
+ CASE WHEN e_confused_4 IS NOT NULL THEN '✓' ELSE '✗' END || ' confused',
+ CASE WHEN e_sleeping_4 IS NOT NULL THEN '✓' ELSE '✗' END || ' sleeping',
+ CASE WHEN e_wink_4 IS NOT NULL THEN '✓' ELSE '✗' END || ' wink'
+FROM server.avatars WHERE slug = 'stock-avatar'
+" | tr '|' '\n' | grep -v '^$' | sed 's/^ */ /'
+
+echo ""
+
+# Check server defaults
+echo "Server config defaults:"
+psql -d "$DB" -t -c "
+SELECT
+ CASE WHEN default_avatar_neutral_adult IS NOT NULL THEN '✓' ELSE '✗' END || ' default_avatar_neutral_adult',
+ CASE WHEN default_avatar_neutral_child IS NOT NULL THEN '✓' ELSE '✗' END || ' default_avatar_neutral_child',
+ CASE WHEN default_avatar_male_adult IS NOT NULL THEN '✓' ELSE '✗' END || ' default_avatar_male_adult',
+ CASE WHEN default_avatar_male_child IS NOT NULL THEN '✓' ELSE '✗' END || ' default_avatar_male_child',
+ CASE WHEN default_avatar_female_adult IS NOT NULL THEN '✓' ELSE '✗' END || ' default_avatar_female_adult',
+ CASE WHEN default_avatar_female_child IS NOT NULL THEN '✓' ELSE '✗' END || ' default_avatar_female_child'
+FROM server.config WHERE id = '00000000-0000-0000-0000-000000000001'
+" | tr '|' '\n' | grep -v '^$' | sed 's/^ */ /'
+
+echo ""
+echo "=========================================="
+echo "Stock avatar setup complete!"
+echo "Avatar ID: $AVATAR_ID"
+echo "=========================================="
diff --git a/stock/avatar/face-backup.svg b/stock/avatar/face-backup.svg
new file mode 100644
index 0000000..91e7c7e
--- /dev/null
+++ b/stock/avatar/face-backup.svg
@@ -0,0 +1,45 @@
+
diff --git a/stock/avatar/index.html b/stock/avatar/index.html
new file mode 100644
index 0000000..a55b853
--- /dev/null
+++ b/stock/avatar/index.html
@@ -0,0 +1,282 @@
+
+
+
+
+
+ Avatar Renderer
+
+
+
+ Avatar Renderer
+
+
+
+
+
+
+
+
+
+
+
+

+

+
+
+
+
+
+

+
+
+
+
+
+ Expressions
+
+
+
+
+
+
diff --git a/stock/index.html b/stock/index.html
index d18bd0e..ed3a894 100644
--- a/stock/index.html
+++ b/stock/index.html
@@ -429,6 +429,16 @@
Good Pol
+
+
+
+
@@ -548,7 +558,9 @@
soda: ['cola', 'lemonlime', 'orange', 'grape', 'rootbeer'],
tea: ['iced', 'pot', 'cup', 'cup-empty', 'bag'],
misc: ['iou', 'signed-dollar', 'thankyou', 'yousuck'],
- goodpol: ['cccp', 'china', 'palestine']
+ goodpol: ['cccp', 'china', 'palestine'],
+ screen: ['projector', 'projector-with-stand'],
+ keyboard: ['media']
};
// Flags
@@ -638,6 +650,8 @@
const teaContainer = document.getElementById('tea-props');
const miscContainer = document.getElementById('misc-props');
const goodpolContainer = document.getElementById('goodpol-props');
+ const screenContainer = document.getElementById('screen-props');
+ const keyboardContainer = document.getElementById('keyboard-props');
for (const name of props.hookah) {
await loadPropPreview('hookah', name, hookahContainer);
@@ -657,6 +671,12 @@
for (const name of props.goodpol) {
await loadPropPreview('goodpol', name, goodpolContainer);
}
+ for (const name of props.screen) {
+ await loadPropPreview('screen', name, screenContainer);
+ }
+ for (const name of props.keyboard) {
+ await loadPropPreview('keyboard', name, keyboardContainer);
+ }
// Select first prop by default
const firstCard = document.querySelector('#props-tab .prop-card');
diff --git a/stock/props/keyboard-media.svg b/stock/props/keyboard-media.svg
new file mode 100644
index 0000000..fb71656
--- /dev/null
+++ b/stock/props/keyboard-media.svg
@@ -0,0 +1,47 @@
+
diff --git a/stock/props/screen-projector-with-stand.svg b/stock/props/screen-projector-with-stand.svg
new file mode 100644
index 0000000..4349333
--- /dev/null
+++ b/stock/props/screen-projector-with-stand.svg
@@ -0,0 +1,44 @@
+
diff --git a/stock/props/screen-projector.svg b/stock/props/screen-projector.svg
new file mode 100644
index 0000000..d2b708d
--- /dev/null
+++ b/stock/props/screen-projector.svg
@@ -0,0 +1,24 @@
+
diff --git a/stock/props/upload-stockprops.sh b/stock/props/upload-stockprops.sh
index 9ea5bcb..c83ad25 100755
--- a/stock/props/upload-stockprops.sh
+++ b/stock/props/upload-stockprops.sh
@@ -88,6 +88,12 @@ get_tags() {
misc)
echo '["misc", "droppable"]'
;;
+ screen)
+ echo '["screen", "projector", "droppable"]'
+ ;;
+ keyboard)
+ echo '["keyboard", "media", "droppable"]'
+ ;;
*)
echo '["prop", "droppable"]'
;;