Adding the skills
This commit is contained in:
Generated
+10
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "@glitch-university/glitch-components-workspace",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "@glitch-university/glitch-components-workspace"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,14 +27,14 @@ function parseArgs(argv) {
|
|||||||
const options = {
|
const options = {
|
||||||
command,
|
command,
|
||||||
components: [],
|
components: [],
|
||||||
hostDir: '',
|
hostDirs: [],
|
||||||
stagingDir: path.join(cwd, '.glitch-release')
|
stagingDir: path.join(cwd, '.glitch-release')
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let index = 0; index < rest.length; index += 1) {
|
for (let index = 0; index < rest.length; index += 1) {
|
||||||
const arg = rest[index]
|
const arg = rest[index]
|
||||||
if (arg === '--host') {
|
if (arg === '--host') {
|
||||||
options.hostDir = path.resolve(cwd, rest[index + 1] ?? '')
|
options.hostDirs.push(path.resolve(cwd, rest[index + 1] ?? ''))
|
||||||
index += 1
|
index += 1
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -176,6 +176,14 @@ function ensureDirectory(directory) {
|
|||||||
fs.mkdirSync(directory, { recursive: true })
|
fs.mkdirSync(directory, { recursive: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDefaultHostDirs() {
|
||||||
|
return [
|
||||||
|
path.resolve(cwd, '..', 'gnommoweb', 'public', 'glitch'),
|
||||||
|
path.resolve(cwd, '..', 'gnommoplayer', 'public', 'glitch'),
|
||||||
|
path.resolve(cwd, '..', 'gnommoeditor', 'public', 'glitch')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
function copyDirectoryContents(sourceDir, destinationDir) {
|
function copyDirectoryContents(sourceDir, destinationDir) {
|
||||||
ensureDirectory(destinationDir)
|
ensureDirectory(destinationDir)
|
||||||
for (const entry of fs.readdirSync(sourceDir)) {
|
for (const entry of fs.readdirSync(sourceDir)) {
|
||||||
@@ -186,7 +194,7 @@ function copyDirectoryContents(sourceDir, destinationDir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function releaseComponent(component, hostDir, stagingDir) {
|
function releaseComponent(component, hostDirs, stagingDir) {
|
||||||
const distDir = path.join(component.componentDir, 'dist')
|
const distDir = path.join(component.componentDir, 'dist')
|
||||||
if (!fs.existsSync(distDir)) {
|
if (!fs.existsSync(distDir)) {
|
||||||
fail(`Missing dist directory for ${component.componentDirName}. Run build first.`)
|
fail(`Missing dist directory for ${component.componentDirName}. Run build first.`)
|
||||||
@@ -205,9 +213,11 @@ function releaseComponent(component, hostDir, stagingDir) {
|
|||||||
tags: ['legacy']
|
tags: ['legacy']
|
||||||
}
|
}
|
||||||
|
|
||||||
const releaseDir = path.join(hostDir, manifest.folderName)
|
for (const hostDir of hostDirs) {
|
||||||
copyDirectoryContents(distDir, releaseDir)
|
const releaseDir = path.join(hostDir, manifest.folderName)
|
||||||
fs.writeFileSync(path.join(releaseDir, 'glitch.manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`)
|
copyDirectoryContents(distDir, releaseDir)
|
||||||
|
fs.writeFileSync(path.join(releaseDir, 'glitch.manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`)
|
||||||
|
}
|
||||||
|
|
||||||
const stagingComponentDir = path.join(stagingDir, manifest.folderName)
|
const stagingComponentDir = path.join(stagingDir, manifest.folderName)
|
||||||
copyDirectoryContents(distDir, stagingComponentDir)
|
copyDirectoryContents(distDir, stagingComponentDir)
|
||||||
@@ -268,17 +278,17 @@ switch (options.command) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'release': {
|
case 'release': {
|
||||||
const hostDir =
|
const hostDirs = options.hostDirs.length > 0 ? options.hostDirs : getDefaultHostDirs()
|
||||||
options.hostDir ||
|
|
||||||
path.resolve(cwd, '..', 'gnommoweb', 'src', 'components', 'glitch')
|
|
||||||
|
|
||||||
ensureDirectory(hostDir)
|
for (const hostDir of hostDirs) {
|
||||||
|
ensureDirectory(hostDir)
|
||||||
|
}
|
||||||
ensureDirectory(options.stagingDir)
|
ensureDirectory(options.stagingDir)
|
||||||
|
|
||||||
for (const component of components) {
|
for (const component of components) {
|
||||||
console.log(`=== Releasing ${component.componentDirName} ===`)
|
console.log(`=== Releasing ${component.componentDirName} ===`)
|
||||||
runBuild(component)
|
runBuild(component)
|
||||||
releaseComponent(component, hostDir, options.stagingDir)
|
releaseComponent(component, hostDirs, options.stagingDir)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-31
@@ -1,12 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Sets up git remotes for all glitch-component folders and pushes to ramanujan.
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# ./setup-remotes.sh # set remotes only
|
|
||||||
# ./setup-remotes.sh --push # set remotes and push all
|
|
||||||
#
|
|
||||||
# Reads GIT_USER / GIT_PASSWORD from ../.env if present, otherwise prompts.
|
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
REMOTE_HOST="ramanujan.glitch.university"
|
REMOTE_HOST="ramanujan.glitch.university"
|
||||||
@@ -14,34 +6,17 @@ COMPONENTS_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|||||||
PUSH=false
|
PUSH=false
|
||||||
[[ "$1" == "--push" ]] && PUSH=true
|
[[ "$1" == "--push" ]] && PUSH=true
|
||||||
|
|
||||||
# ── Load credentials ──────────────────────────────────────────────────────────
|
REMOTE_BASE="ssh://git@${REMOTE_HOST}/git/repos"
|
||||||
|
|
||||||
ENV_FILE="$COMPONENTS_DIR/../gnommoweb/.env.prod"
|
|
||||||
if [ -f "$ENV_FILE" ]; then
|
|
||||||
GIT_USER=$(grep -E '^GIT_USER=' "$ENV_FILE" | cut -d= -f2 | tr -d '"'"'" | head -1)
|
|
||||||
GIT_PASSWORD=$(grep -E '^GIT_PASSWORD=' "$ENV_FILE" | cut -d= -f2 | tr -d '"'"'" | head -1)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$GIT_USER" ] || [ -z "$GIT_PASSWORD" ]; then
|
|
||||||
read -rp "Git username: " GIT_USER
|
|
||||||
read -rsp "Git password: " GIT_PASSWORD
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
|
|
||||||
REMOTE_BASE="https://${GIT_USER}:${GIT_PASSWORD}@${REMOTE_HOST}"
|
|
||||||
|
|
||||||
# ── Process each component folder ─────────────────────────────────────────────
|
|
||||||
|
|
||||||
for dir in "$COMPONENTS_DIR"/*/; do
|
for dir in "$COMPONENTS_DIR"/*/; do
|
||||||
name=$(basename "$dir")
|
name=$(basename "$dir")
|
||||||
|
|
||||||
# Skip the skills folder and any non-component entries
|
|
||||||
[[ "$name" == "skills" ]] && continue
|
[[ "$name" == "skills" ]] && continue
|
||||||
|
|
||||||
echo "── $name"
|
echo "── $name"
|
||||||
cd "$dir"
|
cd "$dir"
|
||||||
|
|
||||||
# Init if not already a git repo
|
|
||||||
if [ ! -d ".git" ]; then
|
if [ ! -d ".git" ]; then
|
||||||
git init -q
|
git init -q
|
||||||
git add -A
|
git add -A
|
||||||
@@ -49,21 +24,27 @@ for dir in "$COMPONENTS_DIR"/*/; do
|
|||||||
echo " initialised"
|
echo " initialised"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Add or update remote
|
REMOTE_URL="https://${REMOTE_HOST}/${name}.git"
|
||||||
|
|
||||||
if git remote get-url origin &>/dev/null; then
|
if git remote get-url origin &>/dev/null; then
|
||||||
git remote set-url origin "${REMOTE_BASE}/${name}.git"
|
git remote set-url origin "$REMOTE_URL"
|
||||||
echo " remote updated"
|
echo " remote updated"
|
||||||
else
|
else
|
||||||
git remote add origin "${REMOTE_BASE}/${name}.git"
|
git remote add origin "$REMOTE_URL"
|
||||||
echo " remote added"
|
echo " remote added"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Push
|
|
||||||
if $PUSH; then
|
if $PUSH; then
|
||||||
|
if ssh git@"$REMOTE_HOST" create-repo "${name}.git" 2>/dev/null; then
|
||||||
|
echo " remote repo ensured"
|
||||||
|
else
|
||||||
|
echo " remote repo may already exist"
|
||||||
|
fi
|
||||||
|
|
||||||
if git push -u origin main -q 2>/dev/null || git push -u origin master:main -q 2>/dev/null; then
|
if git push -u origin main -q 2>/dev/null || git push -u origin master:main -q 2>/dev/null; then
|
||||||
echo " pushed"
|
echo " pushed"
|
||||||
else
|
else
|
||||||
echo " push failed (repo may not exist on server yet)"
|
echo " push failed"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
# GlitchComponent Contract (Canonical Shape)
|
||||||
|
|
||||||
|
Use the local `lightlane` project as the canonical source when available:
|
||||||
|
|
||||||
|
- `../lightlane/src/types.ts`
|
||||||
|
- `../lightlane/src/index.tsx`
|
||||||
|
|
||||||
|
This reference captures the current shape observed in `lightlane` so the skill can scaffold quickly.
|
||||||
|
|
||||||
|
## Required Exports
|
||||||
|
|
||||||
|
`src/index.tsx` should export:
|
||||||
|
|
||||||
|
- `default` component
|
||||||
|
- `metadata` object (`GlitchComponentMetadata`)
|
||||||
|
- relevant types re-exported from `src/types.ts`
|
||||||
|
|
||||||
|
## Core Types (Current Lightlane-Compatible Shape)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export interface GlitchComponentConfig {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
params: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GlitchTheme {
|
||||||
|
primary: string;
|
||||||
|
accent: string;
|
||||||
|
bg: string;
|
||||||
|
bgSecondary: string;
|
||||||
|
text: string;
|
||||||
|
textMuted: string;
|
||||||
|
border: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GlitchComponentResult {
|
||||||
|
success: boolean;
|
||||||
|
score?: number;
|
||||||
|
data?: unknown;
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GlitchComponentProps {
|
||||||
|
config: GlitchComponentConfig;
|
||||||
|
onComplete: (result: GlitchComponentResult) => void;
|
||||||
|
onProgress?: (percent: number) => void;
|
||||||
|
theme?: GlitchTheme;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ParamSchema {
|
||||||
|
[key: string]: {
|
||||||
|
type: 'number' | 'string' | 'boolean' | 'color' | 'select' | 'range';
|
||||||
|
label?: string;
|
||||||
|
description?: string;
|
||||||
|
default: unknown;
|
||||||
|
options?: { value: string | number; label: string }[];
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
|
step?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GlitchComponentMetadata {
|
||||||
|
name: string;
|
||||||
|
displayName: string;
|
||||||
|
version: string;
|
||||||
|
paramSchema: ParamSchema;
|
||||||
|
defaultParams: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Metadata Expectations
|
||||||
|
|
||||||
|
- `name`: kebab-case slug used by host registration
|
||||||
|
- `displayName`: human-friendly title
|
||||||
|
- `version`: semantic version string
|
||||||
|
- `paramSchema`: controls/settings schema for host and dev harness
|
||||||
|
- `defaultParams`: values that produce a working component without additional configuration
|
||||||
|
|
||||||
|
## Behavioral Expectations
|
||||||
|
|
||||||
|
- Call `onComplete(...)` when the experience completes or fails definitively.
|
||||||
|
- Call `onProgress(percent)` for multi-step flows when progress is meaningful.
|
||||||
|
- Use `config.params` as the single source of runtime config.
|
||||||
|
- Respect `theme` if provided, but keep fallbacks for standalone mode.
|
||||||
|
|
||||||
|
## Validation Tip
|
||||||
|
|
||||||
|
Before finalizing a scaffold, compare generated `src/types.ts` and `src/index.tsx` against the current `../lightlane/src/types.ts` and `../lightlane/src/index.tsx` to catch drift.
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Create GlitchComponent
|
||||||
|
|
||||||
|
The canonical Glitch University component workflow now lives at the workspace root:
|
||||||
|
|
||||||
|
- `/Users/jenstandstad/Projects/glitch-components/GLITCH_COMPONENT_STANDARD.md`
|
||||||
|
- `/Users/jenstandstad/Projects/glitch-components/templates/react-vite-glitch-component/`
|
||||||
|
- `/Users/jenstandstad/Projects/glitch-components/scripts/new-glitch-component.mjs`
|
||||||
|
|
||||||
|
Use the root scaffold instead of copying this folder or reusing older component boilerplate.
|
||||||
|
|
||||||
|
For special features suchas 3D, Sound bridge etc consider the referenes in
|
||||||
|
|
||||||
|
/Users/jenstandstad/Projects/glitch-components/skills/references
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Sound Bridge Notes
|
||||||
|
|
||||||
|
Glitch University uses a host-managed sound system (Howler-based) with string sound keys, for example:
|
||||||
|
|
||||||
|
- `playSound('ui.button_click')`
|
||||||
|
- `playSound('ui.button_hover')`
|
||||||
|
|
||||||
|
## Recommendation
|
||||||
|
|
||||||
|
Treat sound as an optional host integration:
|
||||||
|
|
||||||
|
- Use a small wrapper function in the component (`safePlaySound`) that checks whether a host sound function exists.
|
||||||
|
- No-op when unavailable (standalone dev should still run).
|
||||||
|
- Keep sound identifiers as strings/constants so they match host definitions.
|
||||||
|
|
||||||
|
## Example Pattern
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type PlaySound = (id: string) => void;
|
||||||
|
|
||||||
|
export function safePlaySound(playSound: PlaySound | undefined, id: string) {
|
||||||
|
try {
|
||||||
|
playSound?.(id);
|
||||||
|
} catch {
|
||||||
|
// Ignore host sound errors in standalone/local mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Unknowns to Confirm Later
|
||||||
|
|
||||||
|
- How the host exposes `playSound` to glitch-components (prop, context, global import, event bus)
|
||||||
|
- Which sound keys are safe/standardized across experiences
|
||||||
|
- Whether completion/reward sounds are triggered by host or component
|
||||||
Reference in New Issue
Block a user