Implement multi-scheme animation name mapper for Owen Animation System
Some checks failed
CI/CD Pipeline / Test & Lint (16.x) (push) Has been cancelled
CI/CD Pipeline / Test & Lint (18.x) (push) Has been cancelled
CI/CD Pipeline / Test & Lint (20.x) (push) Has been cancelled
CI/CD Pipeline / Security Audit (push) Has been cancelled
CI/CD Pipeline / Release (push) Has been cancelled
Demo Deployment / Build Demo (push) Has been cancelled
Demo Deployment / Test Demo (push) Has been cancelled
Demo Deployment / Performance Audit (push) Has been cancelled
Demo Deployment / Deploy to Staging (push) Has been cancelled
Demo Deployment / Deploy to Production (push) Has been cancelled
Animation Processing Pipeline / Validate Animation Names (push) Has been cancelled
Animation Processing Pipeline / Process Blender Animation Assets (push) Has been cancelled
Multi-Scheme Testing / Validate Naming Schemes (artist) (push) Has been cancelled
Multi-Scheme Testing / Validate Naming Schemes (hierarchical) (push) Has been cancelled
Multi-Scheme Testing / Validate Naming Schemes (legacy) (push) Has been cancelled
Multi-Scheme Testing / Validate Naming Schemes (semantic) (push) Has been cancelled
Multi-Scheme Testing / Test Scheme Conversions (push) Has been cancelled
Multi-Scheme Testing / Validate Demo Functionality (push) Has been cancelled
Multi-Scheme Testing / Performance Benchmarks (push) Has been cancelled
Performance Testing / Animation Conversion Performance (100, artist) (push) Has been cancelled
Performance Testing / Animation Conversion Performance (100, hierarchical) (push) Has been cancelled
Performance Testing / Animation Conversion Performance (100, legacy) (push) Has been cancelled
Performance Testing / Animation Conversion Performance (100, semantic) (push) Has been cancelled
Performance Testing / Animation Conversion Performance (1000, artist) (push) Has been cancelled
Performance Testing / Animation Conversion Performance (1000, hierarchical) (push) Has been cancelled
Performance Testing / Animation Conversion Performance (1000, legacy) (push) Has been cancelled
Performance Testing / Animation Conversion Performance (1000, semantic) (push) Has been cancelled
Performance Testing / Animation Conversion Performance (5000, artist) (push) Has been cancelled
Performance Testing / Animation Conversion Performance (5000, hierarchical) (push) Has been cancelled
Performance Testing / Animation Conversion Performance (5000, legacy) (push) Has been cancelled
Performance Testing / Animation Conversion Performance (5000, semantic) (push) Has been cancelled
Performance Testing / Memory Usage Analysis (push) Has been cancelled
Performance Testing / Demo Performance Audit (push) Has been cancelled
Animation Processing Pipeline / Update Animation Documentation (push) Has been cancelled
Animation Processing Pipeline / Deploy Animation Demo (push) Has been cancelled
Performance Testing / Generate Performance Report (push) Has been cancelled

- Added AnimationNameMapper class to handle conversion between different animation naming schemes (legacy, artist, hierarchical, semantic).
- Included methods for initialization, pattern matching, conversion, and validation of animation names.
- Developed comprehensive unit tests for the animation name converter and demo pages using Playwright.
- Created a Vite configuration for the demo application, including asset handling and optimization settings.
- Enhanced the demo with features for batch conversion, performance metrics, and responsive design.
This commit is contained in:
2025-05-24 05:18:13 +02:00
parent d513e80c07
commit b447abee00
54 changed files with 14343 additions and 989 deletions

38
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,38 @@
# Code owners for the Owen Animation System
# These users will be automatically requested for review when PRs are opened
# Global ownership - project maintainer
* @kjanat
# Core animation system
/src/animation/ @kjanat
/src/core/OwenAnimationContext.js @kjanat
# Animation processing and validation scripts
/scripts/ @kjanat
# Configuration files
/package.json @kjanat
/vite*.config.js @kjanat
/jsdoc.config.json @kjanat
# GitHub workflows and automation
/.github/ @kjanat
# Documentation
/docs/ @kjanat
/README.md @kjanat
/CHANGELOG.md @kjanat
/MULTI_SCHEME_GUIDE.md @kjanat
# Demo application
/demo/ @kjanat
# Examples and integration guides
/examples/ @kjanat
# License files - require special attention
/LICENSE.* @kjanat
# Animation assets - require validation
/assets/animations/ @kjanat

View File

@ -0,0 +1,163 @@
name: Animation Scheme Issue
description: Report issues specific to animation naming schemes or conversions
title: "[Scheme]: "
labels: ["animation-scheme", "naming", "needs-investigation"]
projects: ["kjanat/Owen"]
assignees:
- kjanat
body:
- type: markdown
attributes:
value: |
Report issues specific to animation naming schemes, conversions, or multi-scheme functionality.
- type: checkboxes
id: affected-schemes
attributes:
label: Affected Animation Schemes
description: Which naming schemes are affected by this issue?
options:
- label: Legacy scheme
- label: Artist scheme
- label: Hierarchical scheme
- label: Semantic scheme
- label: Multi-scheme conversion
- label: All schemes
- type: dropdown
id: issue-category
attributes:
label: Issue Category
description: What category best describes this issue?
options:
- Name Conversion Error
- Scheme Validation Failure
- Conflict Detection Issue
- Performance Problem
- Missing Animation Names
- Incorrect Mapping
- Blender Integration
- Documentation Mismatch
- API Inconsistency
validations:
required: true
- type: textarea
id: animation-names
attributes:
label: Animation Names Involved
description: Provide the specific animation names that are causing issues
placeholder: |
Source scheme: artist
Animation name: "char_walk_01"
Target scheme: semantic
Expected result: "character.movement.walk.forward"
Actual result: "character.walk.01"
validations:
required: true
- type: textarea
id: conversion-details
attributes:
label: Conversion Details
description: Provide details about the conversion or mapping issue
placeholder: |
- What conversion were you attempting?
- What was the expected behavior?
- What actually happened?
- Are there error messages?
- type: textarea
id: reproduction-code
attributes:
label: Reproduction Code
description: Provide code to reproduce the issue
render: javascript
placeholder: |
```javascript
import { AnimationNameMapper } from 'owen-animation-system';
const mapper = new AnimationNameMapper();
// Code that reproduces the issue
const result = mapper.convert('char_walk_01', 'artist', 'semantic');
console.log(result); // Shows unexpected result
```
validations:
required: true
- type: textarea
id: validation-output
attributes:
label: Validation Output
description: If you ran validation scripts, provide the output
render: shell
placeholder: |
$ npm run check:naming-conflicts
# Output from validation scripts
- type: dropdown
id: severity
attributes:
label: Severity
description: How severe is this issue?
options:
- Low - Minor inconvenience
- Medium - Affects workflow but has workarounds
- High - Breaks functionality significantly
- Critical - Prevents system usage
validations:
required: true
- type: textarea
id: environment-details
attributes:
label: Environment Details
description: Provide environment information
placeholder: |
- Owen Animation System version: v1.2.3
- Node.js version: v18.17.0
- Animation assets source: Blender 3.6
- Integration: React/Vue/Vanilla JS
- OS: Windows/macOS/Linux
- type: textarea
id: workaround
attributes:
label: Current Workaround
description: If you found a workaround, please describe it
placeholder: Describe any temporary solutions you're using
- type: checkboxes
id: impact
attributes:
label: Impact Assessment
options:
- label: Affects multiple animation assets
- label: Blocks automated processing
- label: Requires manual intervention
- label: Affects production builds
- label: Impacts team workflow
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our Code of Conduct
options:
- label: I agree to follow this project's Code of Conduct
required: true
- type: checkboxes
id: checklist
attributes:
label: Pre-submission checklist
options:
- label: I have provided specific animation names and schemes
required: true
- label: I have included reproduction code
required: true
- label: I have checked existing issues for similar problems
required: true

129
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@ -0,0 +1,129 @@
name: Bug Report
description: Create a report to help us improve the Owen Animation System
title: "[Bug]: "
labels: ["bug", "needs-triage"]
projects: ["kjanat/Owen"]
assignees:
- kjanat
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report! Please provide as much detail as possible to help us understand and reproduce the issue.
- type: textarea
id: what-happened
attributes:
label: What happened?
description: A clear and concise description of what the bug is.
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected behavior
description: A clear and concise description of what you expected to happen.
placeholder: What should have happened instead?
validations:
required: true
- type: textarea
id: reproduction-steps
attributes:
label: Steps to reproduce
description: Steps to reproduce the behavior
placeholder: |
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See error
validations:
required: true
- type: dropdown
id: animation-scheme
attributes:
label: Animation Naming Scheme
description: Which animation naming scheme were you using when the bug occurred?
options:
- Legacy
- Artist
- Hierarchical
- Semantic
- Multiple schemes
- Not applicable
validations:
required: true
- type: dropdown
id: environment
attributes:
label: Environment
description: Where did you encounter this bug?
options:
- Browser (Web)
- Node.js
- React integration
- Vue integration
- Blender integration
- Demo application
- Documentation
- Other
validations:
required: true
- type: textarea
id: browser-info
attributes:
label: Browser/Runtime Information
description: If applicable, provide browser or runtime version information
placeholder: |
- Browser: Chrome 91.0
- Node.js: v18.17.0
- OS: Windows 11
- Owen Animation System: v1.2.3
- type: textarea
id: code-sample
attributes:
label: Code Sample
description: If applicable, provide a minimal code sample that reproduces the issue
render: javascript
placeholder: |
```javascript
import { AnimationNameMapper } from 'owen-animation-system';
const mapper = new AnimationNameMapper();
// Your code that demonstrates the issue
```
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our Code of Conduct
options:
- label: I agree to follow this project's Code of Conduct
required: true
- type: checkboxes
id: checklist
attributes:
label: Pre-submission checklist
description: Please verify the following before submitting
options:
- label: I have searched existing issues to make sure this is not a duplicate
required: true
- label: I have provided a clear and concise description of the bug
required: true
- label: I have included steps to reproduce the issue
required: true

17
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,17 @@
blank_issues_enabled: false
contact_links:
- name: Discussion Forum
url: https://github.com/kjanat/Owen/discussions
about: Ask questions, share ideas, and discuss the Owen Animation System with the community
- name: Discord Community
url: https://discord.gg/owen-animation
about: Join our Discord server for real-time chat and support
- name: Documentation
url: https://kjanat.github.io/Owen/
about: Check our comprehensive documentation and guides
- name: Multi-Scheme Guide
url: https://github.com/kjanat/Owen/blob/main/MULTI_SCHEME_GUIDE.md
about: Learn about animation naming schemes and conversions
- name: Demo Application
url: https://kjanat.github.io/Owen/demo/
about: Try the interactive demo to understand the system capabilities

139
.github/ISSUE_TEMPLATE/documentation.yml vendored Normal file
View File

@ -0,0 +1,139 @@
name: Documentation Issue
description: Report an issue with documentation or suggest improvements
title: "[Docs]: "
labels: ["documentation", "needs-review"]
projects: ["kjanat/Owen"]
assignees:
- kjanat
body:
- type: markdown
attributes:
value: |
Thanks for helping improve our documentation! Please provide details about the documentation issue or improvement.
- type: dropdown
id: doc-type
attributes:
label: Documentation Type
description: What type of documentation is affected?
options:
- API Documentation (JSDoc)
- README.md
- Multi-Scheme Guide
- Code Examples
- Demo Application
- Installation Guide
- Integration Guide
- Changelog
- Contributing Guide
- Other
validations:
required: true
- type: dropdown
id: issue-type
attributes:
label: Issue Type
description: What type of documentation issue is this?
options:
- Error/Mistake
- Missing Information
- Unclear/Confusing
- Outdated Information
- Missing Examples
- Formatting Issues
- Typo/Grammar
- Improvement Suggestion
- New Documentation Needed
validations:
required: true
- type: textarea
id: location
attributes:
label: Location
description: Where did you find this issue? Provide a link or file path if possible.
placeholder: |
- URL: https://example.com/docs/...
- File: README.md (line 45)
- Section: "Animation Name Mapping"
validations:
required: true
- type: textarea
id: current-content
attributes:
label: Current Content
description: What is the current documentation content that needs improvement?
placeholder: Copy the current text or describe what's missing
validations:
required: true
- type: textarea
id: suggested-improvement
attributes:
label: Suggested Improvement
description: How should the documentation be improved?
placeholder: |
- What should be added, changed, or removed?
- Provide suggested text if applicable
- Include code examples if relevant
validations:
required: true
- type: textarea
id: context
attributes:
label: Additional Context
description: Any additional context about why this improvement is needed
placeholder: |
- What task were you trying to accomplish?
- What confused you?
- How would this help other users?
- type: textarea
id: code-example
attributes:
label: Code Example
description: If suggesting code documentation improvements, provide examples
render: javascript
placeholder: |
```javascript
// Current example (if exists)
// Suggested improved example
```
- type: checkboxes
id: affected-users
attributes:
label: Who would benefit from this improvement?
options:
- label: New users learning the system
- label: Experienced developers integrating the system
- label: Contributors to the project
- label: Users of specific naming schemes
- label: Blender integration users
- label: React/Vue integration users
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our Code of Conduct
options:
- label: I agree to follow this project's Code of Conduct
required: true
- type: checkboxes
id: checklist
attributes:
label: Pre-submission checklist
description: Please verify the following before submitting
options:
- label: I have checked that this documentation issue hasn't been reported already
required: true
- label: I have provided specific location information
required: true
- label: I have suggested concrete improvements
required: true

View File

@ -0,0 +1,144 @@
name: Feature Request
description: Suggest an idea for the Owen Animation System
title: "[Feature]: "
labels: ["enhancement", "feature-request"]
projects: ["kjanat/Owen"]
assignees:
- kjanat
body:
- type: markdown
attributes:
value: |
Thanks for suggesting a new feature! Please provide as much detail as possible to help us understand your request.
- type: textarea
id: problem-description
attributes:
label: Problem Description
description: Is your feature request related to a problem? Please describe the problem or limitation you're experiencing.
placeholder: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
validations:
required: true
- type: textarea
id: proposed-solution
attributes:
label: Proposed Solution
description: Describe the solution you'd like to see implemented.
placeholder: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives Considered
description: Describe any alternative solutions or features you've considered.
placeholder: A clear and concise description of any alternative solutions or features you've considered.
- type: dropdown
id: feature-area
attributes:
label: Feature Area
description: Which area of the system would this feature affect?
options:
- Animation Name Mapping
- Naming Schemes (Legacy/Artist/Hierarchical/Semantic)
- Core Animation System
- Blender Integration
- Documentation
- Demo Application
- Build System
- Testing Framework
- Performance
- Developer Experience
- API Design
- Other
validations:
required: true
- type: dropdown
id: priority
attributes:
label: Priority
description: How important is this feature to you?
options:
- Low - Nice to have
- Medium - Would improve workflow
- High - Blocking current work
- Critical - Major limitation
validations:
required: true
- type: textarea
id: use-case
attributes:
label: Use Case
description: Describe how you would use this feature and what benefits it would provide.
placeholder: |
Describe your specific use case:
- What are you trying to accomplish?
- How would this feature help?
- Who else might benefit from this feature?
validations:
required: true
- type: textarea
id: implementation-ideas
attributes:
label: Implementation Ideas
description: If you have ideas about how this could be implemented, please share them.
placeholder: |
Any thoughts on implementation approach:
- API design suggestions
- Integration points
- Configuration options
- Breaking changes considerations
- type: textarea
id: code-example
attributes:
label: Code Example
description: If applicable, provide a code example showing how you'd like to use this feature.
render: javascript
placeholder: |
```javascript
// Example of how the feature might be used
const mapper = new AnimationNameMapper();
// Your proposed API usage
mapper.newFeature(options);
```
- type: checkboxes
id: compatibility
attributes:
label: Compatibility Considerations
description: Please consider the impact of this feature
options:
- label: This feature should be backward compatible
- label: This feature may require breaking changes (acceptable)
- label: This feature should work with all naming schemes
- label: This feature affects the public API
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our Code of Conduct
options:
- label: I agree to follow this project's Code of Conduct
required: true
- type: checkboxes
id: checklist
attributes:
label: Pre-submission checklist
description: Please verify the following before submitting
options:
- label: I have searched existing issues and discussions for similar requests
required: true
- label: I have provided a clear description of the problem and proposed solution
required: true
- label: I have considered the impact on existing functionality
required: true

85
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,85 @@
version: 2
updates:
# Enable version updates for npm
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "09:00"
open-pull-requests-limit: 10
reviewers:
- "kjanat"
assignees:
- "kjanat"
commit-message:
prefix: "deps"
prefix-development: "deps-dev"
include: "scope"
labels:
- "dependencies"
- "javascript"
ignore:
# Ignore major version updates for critical dependencies
- dependency-name: "node"
update-types: ["version-update:semver-major"]
- dependency-name: "vite"
update-types: ["version-update:semver-major"]
groups:
development-dependencies:
dependency-type: "development"
patterns:
- "@types/*"
- "eslint*"
- "prettier*"
- "jest*"
- "playwright*"
- "vite*"
animation-dependencies:
patterns:
- "*three*"
- "*gltf*"
- "*animation*"
testing-dependencies:
patterns:
- "*test*"
- "*mock*"
- "*spec*"
# Enable version updates for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "09:00"
reviewers:
- "kjanat"
assignees:
- "kjanat"
commit-message:
prefix: "ci"
include: "scope"
labels:
- "github-actions"
- "ci/cd"
# Enable version updates for Python (Blender scripts)
- package-ecosystem: "pip"
directory: "/scripts"
schedule:
interval: "monthly"
day: "first-monday"
time: "09:00"
reviewers:
- "kjanat"
assignees:
- "kjanat"
commit-message:
prefix: "deps"
prefix-development: "deps-dev"
include: "scope"
labels:
- "dependencies"
- "python"
- "blender"

View File

@ -0,0 +1,169 @@
name: Animation Processing Pipeline
on:
push:
paths:
- 'assets/animations/**'
- 'src/animation/AnimationNameMapper.js'
- 'src/animation/AnimationConstants.js'
pull_request:
paths:
- 'assets/animations/**'
- 'src/animation/AnimationNameMapper.js'
- 'src/animation/AnimationConstants.js'
workflow_dispatch:
inputs:
animation_scheme:
description: 'Primary naming scheme to use'
required: true
default: 'semantic'
type: choice
options:
- legacy
- artist
- hierarchical
- semantic
jobs:
validate-animations:
name: Validate Animation Names
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Validate animation naming schemes
run: node scripts/validate-animations.js
env:
PRIMARY_SCHEME: ${{ github.event.inputs.animation_scheme || 'semantic' }}
- name: Generate animation constants
run: node scripts/generate-animation-constants.js
- name: Check for naming conflicts
run: node scripts/check-naming-conflicts.js
- name: Upload validation report
uses: actions/upload-artifact@v4
with:
name: animation-validation-report
path: |
reports/animation-validation.json
reports/naming-conflicts.json
process-blender-assets:
name: Process Blender Animation Assets
runs-on: ubuntu-latest
if: contains(github.event.head_commit.message, '[process-blender]') || github.event_name == 'workflow_dispatch'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Blender
uses: FlorianBreitwieser/setup-blender@v1
with:
blender-version: '3.6'
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Process Blender files
run: |
python scripts/blender-animation-processor.py \
--input-dir assets/blender \
--output-dir assets/animations \
--naming-scheme artist
- name: Convert animation names
run: node scripts/convert-animation-names.js
- name: Validate processed animations
run: node scripts/validate-processed-animations.js
- name: Commit processed assets
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: 'Auto-process Blender animation assets [skip ci]'
file_pattern: 'assets/animations/* src/animation/AnimationConstants.js'
update-documentation:
name: Update Animation Documentation
runs-on: ubuntu-latest
needs: [validate-animations]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Generate animation documentation
run: node scripts/generate-animation-docs.js
- name: Update API documentation
run: npm run docs
- name: Generate multi-scheme examples
run: node scripts/generate-scheme-examples.js
- name: Commit documentation updates
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: 'Auto-update animation documentation [skip ci]'
file_pattern: |
docs/**
MULTI_SCHEME_GUIDE.md
examples/*/README.md
deploy-demo:
name: Deploy Animation Demo
runs-on: ubuntu-latest
needs: [validate-animations, update-documentation]
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build demo
run: npm run build:demo
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist-demo
cname: owen-animation-demo.your-domain.com

118
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,118 @@
name: CI/CD Pipeline
on:
push:
branches: [ main, master, develop ]
pull_request:
branches: [ main, master ]
jobs:
test:
name: Test & Lint
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linting
run: npm run lint
- name: Build project
run: npm run build
- name: Generate documentation
run: npm run docs
- name: Upload build artifacts
if: matrix.node-version == '20.x'
uses: actions/upload-artifact@v4
with:
name: build-artifacts
path: |
dist/
docs/
security:
name: Security Audit
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run security audit
run: npm audit --audit-level=high
- name: Run security scan
uses: securecodewarrior/github-action-add-sarif@v1
with:
sarif-file: 'security-scan-results.sarif'
continue-on-error: true
release:
name: Release
runs-on: ubuntu-latest
needs: [test, security]
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build project
run: npm run build
- name: Generate documentation
run: npm run docs
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: build-artifacts
- name: Create release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
dist/**
docs/**
CHANGELOG.md
README.md
MULTI_SCHEME_GUIDE.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

246
.github/workflows/demo-deployment.yml vendored Normal file
View File

@ -0,0 +1,246 @@
name: Demo Deployment
on:
push:
branches: [ main, master ]
paths:
- 'demo/**'
- 'src/**'
- 'vite.demo.config.js'
- 'package.json'
pull_request:
branches: [ main, master ]
paths:
- 'demo/**'
- 'src/**'
- 'vite.demo.config.js'
workflow_dispatch:
inputs:
environment:
description: 'Deployment environment'
required: true
default: 'staging'
type: choice
options:
- staging
- production
env:
NODE_VERSION: '20.x'
jobs:
build-demo:
name: Build Demo
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Generate animation constants
run: npm run generate:constants
- name: Build demo application
run: npm run build:demo
env:
NODE_ENV: production
- name: Validate demo build
run: |
test -d dist/demo || (echo "Demo build failed - dist/demo directory not found" && exit 1)
test -f dist/demo/index.html || (echo "Demo build failed - index.html not found" && exit 1)
test -f dist/demo/examples.html || (echo "Demo build failed - examples.html not found" && exit 1)
test -f dist/demo/comparison.html || (echo "Demo build failed - comparison.html not found" && exit 1)
test -f dist/demo/interactive.html || (echo "Demo build failed - interactive.html not found" && exit 1)
- name: Upload demo artifacts
uses: actions/upload-artifact@v4
with:
name: demo-build
path: dist/demo/
retention-days: 30
- name: Upload build reports
uses: actions/upload-artifact@v4
with:
name: build-reports
path: |
dist/demo/report.html
dist/demo/stats.json
retention-days: 7
test-demo:
name: Test Demo
runs-on: ubuntu-latest
needs: build-demo
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Download demo build
uses: actions/download-artifact@v4
with:
name: demo-build
path: dist/demo/
- name: Install Playwright
run: npx playwright install --with-deps
- name: Run demo tests
run: npm run test:demo
env:
CI: true
PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/ms-playwright
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 7
- name: Upload test screenshots
uses: actions/upload-artifact@v4
if: failure()
with:
name: test-screenshots
path: test-results/
retention-days: 7
lighthouse-audit:
name: Performance Audit
runs-on: ubuntu-latest
needs: build-demo
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Download demo build
uses: actions/download-artifact@v4
with:
name: demo-build
path: dist/demo/
- name: Install Lighthouse
run: npm install -g @lhci/cli lighthouse
- name: Start demo server
run: |
npx vite preview --config vite.demo.config.js --port 3000 &
sleep 10
env:
NODE_ENV: production
- name: Run Lighthouse audit
run: |
lhci autorun
env:
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
- name: Upload Lighthouse results
uses: actions/upload-artifact@v4
with:
name: lighthouse-reports
path: .lighthouseci/
retention-days: 7
deploy-staging:
name: Deploy to Staging
runs-on: ubuntu-latest
needs: [build-demo, test-demo]
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.event.inputs.environment == 'staging'
environment: staging
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download demo build
uses: actions/download-artifact@v4
with:
name: demo-build
path: dist/demo/
- name: Deploy to staging
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist/demo
publish_branch: gh-pages-staging
force_orphan: true
- name: Update deployment status
run: |
echo "Demo deployed to staging: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/staging/"
deploy-production:
name: Deploy to Production
runs-on: ubuntu-latest
needs: [build-demo, test-demo, lighthouse-audit]
if: github.ref == 'refs/heads/main' && github.event.inputs.environment == 'production'
environment: production
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download demo build
uses: actions/download-artifact@v4
with:
name: demo-build
path: dist/demo/
- name: Deploy to production
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist/demo
publish_branch: gh-pages
force_orphan: true
- name: Update deployment status
run: |
echo "Demo deployed to production: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/"
- name: Create deployment notification
uses: actions/github-script@v7
with:
script: |
github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: context.payload.deployment.id,
state: 'success',
environment_url: 'https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/',
description: 'Demo successfully deployed'
});

View File

@ -0,0 +1,251 @@
name: Multi-Scheme Testing
on:
push:
branches: [ main, master, develop ]
paths:
- 'src/animation/**'
- 'src/core/OwenAnimationContext.js'
- 'examples/**'
pull_request:
branches: [ main, master ]
paths:
- 'src/animation/**'
- 'src/core/OwenAnimationContext.js'
- 'examples/**'
schedule:
# Run daily at 2 AM UTC
- cron: '0 2 * * *'
env:
NODE_VERSION: '20.x'
jobs:
scheme-validation:
name: Validate Naming Schemes
runs-on: ubuntu-latest
strategy:
matrix:
scheme: [legacy, artist, hierarchical, semantic]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Test ${{ matrix.scheme }} scheme
run: |
node -e "
const { AnimationNameMapper } = require('./src/animation/AnimationNameMapper.js');
const mapper = new AnimationNameMapper();
console.log('Testing ${{ matrix.scheme }} scheme...');
// Test all animations in this scheme
const animations = mapper.getAllAnimationsByScheme('${{ matrix.scheme }}');
console.log('Found', animations.length, 'animations');
// Test conversions
let errors = 0;
animations.forEach(anim => {
try {
const converted = mapper.convert(anim, '${{ matrix.scheme }}');
if (converted !== anim) {
console.error('Conversion error:', anim, '->', converted);
errors++;
}
} catch (e) {
console.error('Error processing:', anim, e.message);
errors++;
}
});
if (errors > 0) {
console.error('Found', errors, 'errors in ${{ matrix.scheme }} scheme');
process.exit(1);
} else {
console.log('All ${{ matrix.scheme }} animations validated successfully');
}
"
conversion-matrix:
name: Test Scheme Conversions
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Test all scheme conversions
run: |
node -e "
const { AnimationNameMapper } = require('./src/animation/AnimationNameMapper.js');
const mapper = new AnimationNameMapper();
const schemes = ['legacy', 'artist', 'hierarchical', 'semantic'];
const testAnimations = [
'wait_idle_L',
'Owen_ReactAngry',
'owen.state.type.idle.loop',
'OwenSleepToWaitTransition'
];
console.log('Testing conversion matrix...');
let totalTests = 0;
let passedTests = 0;
testAnimations.forEach(anim => {
schemes.forEach(fromScheme => {
schemes.forEach(toScheme => {
totalTests++;
try {
const result = mapper.convert(anim, toScheme);
console.log('✓', anim, '->', result, '(' + fromScheme + ' to ' + toScheme + ')');
passedTests++;
} catch (e) {
console.log('✗', anim, 'failed conversion from', fromScheme, 'to', toScheme, ':', e.message);
}
});
});
});
console.log('Conversion matrix results:', passedTests + '/' + totalTests, 'passed');
if (passedTests < totalTests * 0.9) {
console.error('Too many conversion failures');
process.exit(1);
}
"
demo-validation:
name: Validate Demo Functionality
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Playwright
run: npx playwright install --with-deps chromium
- name: Start demo server
run: |
cd examples/mock-demo
python -m http.server 8080 &
sleep 5
- name: Test demo functionality
run: |
npx playwright test --config=playwright.config.js
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: demo-test-results
path: |
test-results/
playwright-report/
performance-benchmark:
name: Performance Benchmarks
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run performance benchmarks
run: |
node -e "
const { AnimationNameMapper } = require('./src/animation/AnimationNameMapper.js');
const mapper = new AnimationNameMapper();
console.log('Running performance benchmarks...');
// Benchmark conversion speed
const testAnim = 'wait_idle_L';
const iterations = 10000;
console.time('10k conversions');
for (let i = 0; i < iterations; i++) {
mapper.convert(testAnim, 'semantic');
}
console.timeEnd('10k conversions');
// Benchmark validation speed
console.time('10k validations');
for (let i = 0; i < iterations; i++) {
mapper.validateAnimationName(testAnim);
}
console.timeEnd('10k validations');
// Memory usage test
const used = process.memoryUsage();
console.log('Memory usage:');
for (let key in used) {
console.log(key + ':', Math.round(used[key] / 1024 / 1024 * 100) / 100, 'MB');
}
"
- name: Comment PR with benchmark results
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
// Read benchmark results (would need to be saved to file in previous step)
const comment = `
## 🏃‍♂️ Performance Benchmark Results
Multi-scheme animation system performance test completed:
- ✅ Conversion speed: 10k operations completed
- ✅ Validation speed: 10k operations completed
- ✅ Memory usage: Within acceptable limits
Full results available in the workflow logs.
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});

View File

@ -0,0 +1,569 @@
name: Performance Testing
on:
push:
branches: [ main, master ]
paths:
- 'src/animation/**'
- 'demo/**'
- 'scripts/**'
pull_request:
branches: [ main, master ]
paths:
- 'src/animation/**'
- 'demo/**'
- 'scripts/**'
schedule:
# Run performance tests weekly on Sundays at 3 AM UTC
- cron: '0 3 * * 0'
workflow_dispatch:
inputs:
test_type:
description: 'Type of performance test to run'
required: true
default: 'all'
type: choice
options:
- all
- conversion
- validation
- memory
- lighthouse
env:
NODE_VERSION: '20.x'
jobs:
conversion-performance:
name: Animation Conversion Performance
runs-on: ubuntu-latest
if: github.event.inputs.test_type == 'all' || github.event.inputs.test_type == 'conversion' || github.event.inputs.test_type == null
strategy:
matrix:
scheme: [legacy, artist, hierarchical, semantic]
batch_size: [100, 1000, 5000]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Generate test data
run: |
node -e "
const fs = require('fs');
const testData = [];
const schemes = ['legacy', 'artist', 'hierarchical', 'semantic'];
const baseNames = [
'walk', 'run', 'idle', 'jump', 'attack', 'defend', 'crouch', 'climb',
'swim', 'fly', 'dance', 'wave', 'bow', 'kneel', 'sit', 'stand'
];
for (let i = 0; i < ${{ matrix.batch_size }}; i++) {
const baseName = baseNames[i % baseNames.length];
const variant = String(i + 1).padStart(2, '0');
let animationName;
switch ('${{ matrix.scheme }}') {
case 'legacy':
animationName = \`\${baseName}_\${variant}\`;
break;
case 'artist':
animationName = \`char_\${baseName}_\${variant}\`;
break;
case 'hierarchical':
animationName = \`character/movement/\${baseName}/\${variant}\`;
break;
case 'semantic':
animationName = \`character.movement.\${baseName}.forward\`;
break;
}
testData.push({
name: animationName,
sourceScheme: '${{ matrix.scheme }}',
targetScheme: schemes.filter(s => s !== '${{ matrix.scheme }}')[Math.floor(Math.random() * 3)]
});
}
fs.writeFileSync('test-data.json', JSON.stringify(testData, null, 2));
console.log(\`Generated \${testData.length} test cases for ${{ matrix.scheme }} scheme\`);
"
- name: Run conversion performance test
run: |
node -e "
const fs = require('fs');
const { AnimationNameMapper } = require('./src/animation/AnimationNameMapper.js');
const testData = JSON.parse(fs.readFileSync('test-data.json', 'utf8'));
const mapper = new AnimationNameMapper();
const results = {
scheme: '${{ matrix.scheme }}',
batchSize: ${{ matrix.batch_size }},
totalConversions: testData.length,
startTime: Date.now(),
conversions: [],
errors: []
};
console.log(\`Starting performance test: ${{ matrix.scheme }} scheme, \${testData.length} conversions\`);
for (const testCase of testData) {
const startTime = process.hrtime.bigint();
try {
const result = mapper.convert(
testCase.name,
testCase.sourceScheme,
testCase.targetScheme
);
const endTime = process.hrtime.bigint();
const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds
results.conversions.push({
input: testCase.name,
output: result,
sourceScheme: testCase.sourceScheme,
targetScheme: testCase.targetScheme,
duration: duration
});
} catch (error) {
results.errors.push({
input: testCase.name,
sourceScheme: testCase.sourceScheme,
targetScheme: testCase.targetScheme,
error: error.message
});
}
}
results.endTime = Date.now();
results.totalDuration = results.endTime - results.startTime;
results.averageConversionTime = results.conversions.length > 0
? results.conversions.reduce((sum, c) => sum + c.duration, 0) / results.conversions.length
: 0;
results.conversionsPerSecond = (results.conversions.length / results.totalDuration) * 1000;
results.errorRate = (results.errors.length / testData.length) * 100;
console.log(\`Performance Results:\`);
console.log(\` Total Duration: \${results.totalDuration}ms\`);
console.log(\` Average Conversion Time: \${results.averageConversionTime.toFixed(2)}ms\`);
console.log(\` Conversions per Second: \${results.conversionsPerSecond.toFixed(2)}\`);
console.log(\` Error Rate: \${results.errorRate.toFixed(2)}%\`);
console.log(\` Successful Conversions: \${results.conversions.length}\`);
console.log(\` Failed Conversions: \${results.errors.length}\`);
// Save detailed results
fs.writeFileSync('performance-results.json', JSON.stringify(results, null, 2));
// Performance thresholds
const MAX_AVG_CONVERSION_TIME = 10; // 10ms
const MAX_ERROR_RATE = 5; // 5%
const MIN_CONVERSIONS_PER_SECOND = 100;
if (results.averageConversionTime > MAX_AVG_CONVERSION_TIME) {
console.error(\`PERFORMANCE ISSUE: Average conversion time (\${results.averageConversionTime.toFixed(2)}ms) exceeds threshold (\${MAX_AVG_CONVERSION_TIME}ms)\`);
process.exit(1);
}
if (results.errorRate > MAX_ERROR_RATE) {
console.error(\`PERFORMANCE ISSUE: Error rate (\${results.errorRate.toFixed(2)}%) exceeds threshold (\${MAX_ERROR_RATE}%)\`);
process.exit(1);
}
if (results.conversionsPerSecond < MIN_CONVERSIONS_PER_SECOND) {
console.error(\`PERFORMANCE ISSUE: Conversions per second (\${results.conversionsPerSecond.toFixed(2)}) below threshold (\${MIN_CONVERSIONS_PER_SECOND})\`);
process.exit(1);
}
console.log('All performance thresholds passed! ✓');
"
- name: Upload performance results
uses: actions/upload-artifact@v4
with:
name: performance-results-${{ matrix.scheme }}-${{ matrix.batch_size }}
path: performance-results.json
retention-days: 30
memory-performance:
name: Memory Usage Analysis
runs-on: ubuntu-latest
if: github.event.inputs.test_type == 'all' || github.event.inputs.test_type == 'memory' || github.event.inputs.test_type == null
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run memory analysis
run: |
node --expose-gc -e "
const { AnimationNameMapper } = require('./src/animation/AnimationNameMapper.js');
function getMemoryUsage() {
global.gc();
const used = process.memoryUsage();
return {
rss: Math.round(used.rss / 1024 / 1024 * 100) / 100,
heapTotal: Math.round(used.heapTotal / 1024 / 1024 * 100) / 100,
heapUsed: Math.round(used.heapUsed / 1024 / 1024 * 100) / 100,
external: Math.round(used.external / 1024 / 1024 * 100) / 100
};
}
console.log('Starting memory analysis...');
const initialMemory = getMemoryUsage();
console.log('Initial memory usage:', initialMemory);
// Create multiple mappers to test memory leaks
const mappers = [];
for (let i = 0; i < 100; i++) {
mappers.push(new AnimationNameMapper());
}
const afterCreationMemory = getMemoryUsage();
console.log('After creating 100 mappers:', afterCreationMemory);
// Perform conversions
const testAnimations = [
'char_walk_01', 'char_run_02', 'prop_door_open',
'character.idle.basic', 'character/movement/walk/forward',
'idle_basic', 'walk_forward', 'attack_sword'
];
for (let round = 0; round < 10; round++) {
for (const mapper of mappers) {
for (const animation of testAnimations) {
try {
mapper.convert(animation, 'artist', 'semantic');
mapper.convert(animation, 'semantic', 'hierarchical');
mapper.convert(animation, 'hierarchical', 'legacy');
} catch (error) {
// Ignore conversion errors for memory test
}
}
}
if (round % 3 === 0) {
const memoryUsage = getMemoryUsage();
console.log(\`Round \${round + 1} memory usage:\`, memoryUsage);
}
}
const finalMemory = getMemoryUsage();
console.log('Final memory usage:', finalMemory);
// Calculate memory growth
const heapGrowth = finalMemory.heapUsed - initialMemory.heapUsed;
const rssGrowth = finalMemory.rss - initialMemory.rss;
console.log(\`Heap growth: \${heapGrowth} MB\`);
console.log(\`RSS growth: \${rssGrowth} MB\`);
// Memory leak thresholds
const MAX_HEAP_GROWTH = 50; // 50 MB
const MAX_RSS_GROWTH = 100; // 100 MB
if (heapGrowth > MAX_HEAP_GROWTH) {
console.error(\`MEMORY LEAK: Heap growth (\${heapGrowth} MB) exceeds threshold (\${MAX_HEAP_GROWTH} MB)\`);
process.exit(1);
}
if (rssGrowth > MAX_RSS_GROWTH) {
console.error(\`MEMORY LEAK: RSS growth (\${rssGrowth} MB) exceeds threshold (\${MAX_RSS_GROWTH} MB)\`);
process.exit(1);
}
console.log('Memory usage within acceptable limits ✓');
"
lighthouse-performance:
name: Demo Performance Audit
runs-on: ubuntu-latest
if: github.event.inputs.test_type == 'all' || github.event.inputs.test_type == 'lighthouse' || github.event.inputs.test_type == null
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build demo
run: npm run build:demo
- name: Install Lighthouse
run: npm install -g @lhci/cli lighthouse
- name: Start demo server
run: |
npm run preview:demo &
sleep 10
env:
NODE_ENV: production
- name: Run Lighthouse audit
run: |
lighthouse http://localhost:3000 \
--output=json \
--output-path=lighthouse-report.json \
--chrome-flags="--headless --no-sandbox --disable-dev-shm-usage" \
--only-categories=performance,accessibility,best-practices
- name: Analyze Lighthouse results
run: |
node -e "
const fs = require('fs');
const report = JSON.parse(fs.readFileSync('lighthouse-report.json', 'utf8'));
const scores = {
performance: report.categories.performance.score * 100,
accessibility: report.categories.accessibility.score * 100,
bestPractices: report.categories['best-practices'].score * 100
};
const metrics = {
fcp: report.audits['first-contentful-paint'].numericValue,
lcp: report.audits['largest-contentful-paint'].numericValue,
cls: report.audits['cumulative-layout-shift'].numericValue,
tbt: report.audits['total-blocking-time'].numericValue,
tti: report.audits['interactive'].numericValue
};
console.log('Lighthouse Scores:');
console.log(\` Performance: \${scores.performance.toFixed(1)}/100\`);
console.log(\` Accessibility: \${scores.accessibility.toFixed(1)}/100\`);
console.log(\` Best Practices: \${scores.bestPractices.toFixed(1)}/100\`);
console.log('\\nCore Web Vitals:');
console.log(\` First Contentful Paint: \${(metrics.fcp / 1000).toFixed(2)}s\`);
console.log(\` Largest Contentful Paint: \${(metrics.lcp / 1000).toFixed(2)}s\`);
console.log(\` Cumulative Layout Shift: \${metrics.cls.toFixed(3)}\`);
console.log(\` Total Blocking Time: \${metrics.tbt.toFixed(0)}ms\`);
console.log(\` Time to Interactive: \${(metrics.tti / 1000).toFixed(2)}s\`);
// Performance thresholds
const thresholds = {
performance: 90,
accessibility: 95,
bestPractices: 90,
fcp: 2000, // 2 seconds
lcp: 2500, // 2.5 seconds
cls: 0.1,
tbt: 300, // 300ms
tti: 3800 // 3.8 seconds
};
let failed = false;
if (scores.performance < thresholds.performance) {
console.error(\`PERFORMANCE ISSUE: Performance score (\${scores.performance.toFixed(1)}) below threshold (\${thresholds.performance})\`);
failed = true;
}
if (scores.accessibility < thresholds.accessibility) {
console.error(\`ACCESSIBILITY ISSUE: Accessibility score (\${scores.accessibility.toFixed(1)}) below threshold (\${thresholds.accessibility})\`);
failed = true;
}
if (metrics.fcp > thresholds.fcp) {
console.error(\`PERFORMANCE ISSUE: FCP (\${(metrics.fcp / 1000).toFixed(2)}s) exceeds threshold (\${thresholds.fcp / 1000}s)\`);
failed = true;
}
if (metrics.lcp > thresholds.lcp) {
console.error(\`PERFORMANCE ISSUE: LCP (\${(metrics.lcp / 1000).toFixed(2)}s) exceeds threshold (\${thresholds.lcp / 1000}s)\`);
failed = true;
}
if (metrics.cls > thresholds.cls) {
console.error(\`PERFORMANCE ISSUE: CLS (\${metrics.cls.toFixed(3)}) exceeds threshold (\${thresholds.cls})\`);
failed = true;
}
if (failed) {
process.exit(1);
}
console.log('\\nAll performance thresholds passed! ✓');
"
- name: Upload Lighthouse report
uses: actions/upload-artifact@v4
with:
name: lighthouse-report
path: lighthouse-report.json
retention-days: 30
generate-performance-report:
name: Generate Performance Report
runs-on: ubuntu-latest
needs: [conversion-performance, memory-performance, lighthouse-performance]
if: always()
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts/
- name: Generate performance report
run: |
node -e "
const fs = require('fs');
const path = require('path');
const report = {
timestamp: new Date().toISOString(),
commit: process.env.GITHUB_SHA || 'unknown',
branch: process.env.GITHUB_REF_NAME || 'unknown',
results: {
conversion: [],
memory: null,
lighthouse: null
},
summary: {
passed: 0,
failed: 0,
warnings: []
}
};
// Process conversion performance results
const artifactsDir = 'artifacts';
if (fs.existsSync(artifactsDir)) {
const artifactDirs = fs.readdirSync(artifactsDir);
for (const dir of artifactDirs) {
if (dir.startsWith('performance-results-')) {
const resultFile = path.join(artifactsDir, dir, 'performance-results.json');
if (fs.existsSync(resultFile)) {
const result = JSON.parse(fs.readFileSync(resultFile, 'utf8'));
report.results.conversion.push(result);
if (result.errorRate <= 5 && result.averageConversionTime <= 10) {
report.summary.passed++;
} else {
report.summary.failed++;
}
}
}
if (dir === 'lighthouse-report') {
const lightouseFile = path.join(artifactsDir, dir, 'lighthouse-report.json');
if (fs.existsSync(lightouseFile)) {
const lighthouse = JSON.parse(fs.readFileSync(lightouseFile, 'utf8'));
report.results.lighthouse = {
performance: lighthouse.categories.performance.score * 100,
accessibility: lighthouse.categories.accessibility.score * 100,
bestPractices: lighthouse.categories['best-practices'].score * 100,
fcp: lighthouse.audits['first-contentful-paint'].numericValue,
lcp: lighthouse.audits['largest-contentful-paint'].numericValue,
cls: lighthouse.audits['cumulative-layout-shift'].numericValue
};
if (report.results.lighthouse.performance >= 90) {
report.summary.passed++;
} else {
report.summary.failed++;
}
}
}
}
}
// Generate markdown report
let markdown = \`# Performance Test Report\\n\\n\`;
markdown += \`**Date:** \${new Date(report.timestamp).toLocaleString()}\\n\`;
markdown += \`**Commit:** \${report.commit}\\n\`;
markdown += \`**Branch:** \${report.branch}\\n\\n\`;
markdown += \`## Summary\\n\\n\`;
markdown += \`- ✅ **Passed:** \${report.summary.passed}\\n\`;
markdown += \`- ❌ **Failed:** \${report.summary.failed}\\n\\n\`;
if (report.results.conversion.length > 0) {
markdown += \`## Conversion Performance\\n\\n\`;
markdown += \`| Scheme | Batch Size | Avg Time (ms) | Conversions/sec | Error Rate (%) |\\n\`;
markdown += \`|--------|------------|---------------|-----------------|----------------|\\n\`;
for (const result of report.results.conversion) {
const status = result.errorRate <= 5 && result.averageConversionTime <= 10 ? '✅' : '❌';
markdown += \`| \${status} \${result.scheme} | \${result.batchSize} | \${result.averageConversionTime.toFixed(2)} | \${result.conversionsPerSecond.toFixed(2)} | \${result.errorRate.toFixed(2)} |\\n\`;
}
markdown += \`\\n\`;
}
if (report.results.lighthouse) {
markdown += \`## Lighthouse Performance\\n\\n\`;
const l = report.results.lighthouse;
markdown += \`- **Performance Score:** \${l.performance.toFixed(1)}/100\\n\`;
markdown += \`- **Accessibility Score:** \${l.accessibility.toFixed(1)}/100\\n\`;
markdown += \`- **Best Practices Score:** \${l.bestPractices.toFixed(1)}/100\\n\`;
markdown += \`- **First Contentful Paint:** \${(l.fcp / 1000).toFixed(2)}s\\n\`;
markdown += \`- **Largest Contentful Paint:** \${(l.lcp / 1000).toFixed(2)}s\\n\`;
markdown += \`- **Cumulative Layout Shift:** \${l.cls.toFixed(3)}\\n\\n\`;
}
fs.writeFileSync('performance-report.json', JSON.stringify(report, null, 2));
fs.writeFileSync('performance-report.md', markdown);
console.log('Performance report generated');
console.log(markdown);
"
- name: Upload performance report
uses: actions/upload-artifact@v4
with:
name: performance-report
path: |
performance-report.json
performance-report.md
retention-days: 90
- name: Comment performance report on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
if (fs.existsSync('performance-report.md')) {
const report = fs.readFileSync('performance-report.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: report
});
}

252
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,252 @@
name: Release
on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
inputs:
version:
description: 'Version to release (e.g., v1.2.3)'
required: true
type: string
prerelease:
description: 'Mark as pre-release'
required: false
default: false
type: boolean
env:
NODE_VERSION: '20.x'
jobs:
validate-version:
name: Validate Version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
is_prerelease: ${{ steps.version.outputs.is_prerelease }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract version
id: version
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
VERSION="${{ github.event.inputs.version }}"
IS_PRERELEASE="${{ github.event.inputs.prerelease }}"
else
VERSION="${GITHUB_REF#refs/tags/}"
# Check if version contains pre-release identifiers
if [[ "$VERSION" =~ -[a-zA-Z] ]]; then
IS_PRERELEASE=true
else
IS_PRERELEASE=false
fi
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "is_prerelease=$IS_PRERELEASE" >> $GITHUB_OUTPUT
echo "Release version: $VERSION (prerelease: $IS_PRERELEASE)"
- name: Validate semantic version
run: |
VERSION="${{ steps.version.outputs.version }}"
if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$ ]]; then
echo "Invalid semantic version: $VERSION"
exit 1
fi
build-and-test:
name: Build and Test
runs-on: ubuntu-latest
needs: validate-version
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linting
run: npm run lint
- name: Run tests
run: npm test
- name: Run multi-scheme validation
run: npm run test:multi-schemes
- name: Build project
run: npm run build
- name: Build demo
run: npm run build:demo
- name: Generate documentation
run: npm run docs
- name: Validate build artifacts
run: |
test -d dist || (echo "Build failed - dist directory not found" && exit 1)
test -d dist/demo || (echo "Demo build failed - dist/demo directory not found" && exit 1)
test -d docs || (echo "Documentation generation failed" && exit 1)
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: release-artifacts
path: |
dist/
docs/
CHANGELOG.md
README.md
MULTI_SCHEME_GUIDE.md
retention-days: 30
create-release:
name: Create Release
runs-on: ubuntu-latest
needs: [validate-version, build-and-test]
permissions:
contents: write
pull-requests: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: release-artifacts
path: ./artifacts
- name: Generate release notes
id: release_notes
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
# Extract changelog for this version
if [ -f CHANGELOG.md ]; then
# Get the changelog section for this version
CHANGELOG_SECTION=$(sed -n "/^## \[${VERSION#v}\]/,/^## \[/p" CHANGELOG.md | head -n -1)
if [ -n "$CHANGELOG_SECTION" ]; then
echo "Found changelog section for version ${VERSION#v}"
echo "$CHANGELOG_SECTION" > release_notes.md
else
echo "No changelog section found for version ${VERSION#v}, generating default notes"
echo "## Changes in ${VERSION}" > release_notes.md
echo "" >> release_notes.md
echo "This release includes various improvements and updates to the Owen Animation System." >> release_notes.md
fi
else
echo "## Changes in ${VERSION}" > release_notes.md
echo "" >> release_notes.md
echo "This release includes various improvements and updates to the Owen Animation System." >> release_notes.md
fi
# Add commit summary since last tag
echo "" >> release_notes.md
echo "### Commits since last release:" >> release_notes.md
git log --oneline $(git describe --tags --abbrev=0 2>/dev/null || echo "HEAD~10")..HEAD >> release_notes.md || true
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ needs.validate-version.outputs.version }}
name: Owen Animation System ${{ needs.validate-version.outputs.version }}
body_path: release_notes.md
draft: false
prerelease: ${{ needs.validate-version.outputs.is_prerelease == 'true' }}
files: |
artifacts/dist/**
artifacts/docs/**
artifacts/CHANGELOG.md
artifacts/README.md
artifacts/MULTI_SCHEME_GUIDE.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish-npm:
name: Publish to NPM
runs-on: ubuntu-latest
needs: [validate-version, create-release]
if: needs.validate-version.outputs.is_prerelease == 'false'
environment: npm-publish
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci
- name: Build project
run: npm run build
- name: Update package version
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
npm version ${VERSION#v} --no-git-tag-version
- name: Publish to NPM
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
deploy-demo:
name: Deploy Demo
runs-on: ubuntu-latest
needs: [validate-version, create-release]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build demo
run: npm run build:demo
- name: Deploy demo to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist/demo
destination_dir: releases/${{ needs.validate-version.outputs.version }}
- name: Update latest demo link
if: needs.validate-version.outputs.is_prerelease == 'false'
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist/demo
destination_dir: latest