oneie
Version:
Build apps, websites, and AI agents in English. Zero-interaction setup for AI agents (Claude Code, Cursor, Windsurf). Download to your computer, run in the cloud, deploy to the edge. Open source and free forever.
1,026 lines (863 loc) • 23.8 kB
Markdown
---
title: Demo Accessibility Animations
dimension: things
category: demo-accessibility-animations.md
tags: ai
related_dimensions: connections, events, knowledge
scope: global
created: 2025-11-03
updated: 2025-11-03
version: 1.0.0
ai_context: |
This document is part of the things dimension in the demo-accessibility-animations.md category.
Location: one/things/demo-accessibility-animations.md
Purpose: Documents one platform demo - accessibility & animations
Related dimensions: connections, events, knowledge
For AI agents: Read this to understand demo accessibility animations.
---
# ONE Platform Demo - Accessibility & Animations
## Version 1.0.0 - Accessibility and Motion Specifications
This document defines accessibility requirements and animation patterns for all ONE Platform demo pages.
---
## Part 1: Accessibility (WCAG 2.1 AA Compliance)
### 1.1 Semantic HTML Foundation
**REQUIREMENT:** Use semantic HTML elements, never repurpose `<div>` for interactive content.
#### Required HTML Elements
| Element | Purpose | Example |
| ------------------------------------------------------ | ---------------------- | ---------------------- |
| `<button>` | Interactive actions | CTAs, form submission |
| `<a>` | Navigation links | Documentation links |
| `<form>` | Form containers | Data input |
| `<input>`, `<select>`, `<textarea>` | Form inputs | Playground forms |
| `<label>` | Form field labels | Associated with inputs |
| `<h1>` - `<h6>` | Headings | Page structure |
| `<header>`, `<nav>`, `<main>`, `<section>`, `<footer>` | Page regions | Document outline |
| `<article>` | Self-contained content | Blog posts, cards |
**EXAMPLE - CORRECT:**
```astro
<!-- CORRECT: Semantic HTML -->
<form class="space-y-4">
<div class="flex flex-col">
<label for="email">Email Address</label>
<input
id="email"
type="email"
required
aria-describedby="email-error"
/>
<p id="email-error" class="text-sm text-destructive">
Must be a valid email
</p>
</div>
<button type="submit">Submit</button>
</form>
<!-- WRONG: Repurposed divs -->
<div class="form">
<div class="form-field">
<div class="label">Email</div>
<div class="input" contenteditable></div>
<div class="error">Invalid</div>
</div>
<div class="button" onclick="submit()">Submit</div>
</div>
```
### 1.2 Color Contrast (WCAG AAA)
**REQUIREMENT:** All text must meet WCAG AAA contrast ratios (4.5:1 body, 3:1 large).
#### Validation Checklist
- [ ] Body text on background: ≥ 4.5:1
- [ ] Large text (18px+, bold 14px+) on background: ≥ 3:1
- [ ] Button text on button background: ≥ 4.5:1
- [ ] Links on background: ≥ 4.5:1
- [ ] Placeholder text: ≥ 3:1 (relaxed)
- [ ] Border/dividers: ≥ 3:1
- [ ] Icons (single color): ≥ 3:1 if conveying meaning
- [ ] Dark mode colors meet same ratios
**Testing:**
```
Tool: WebAIM Contrast Checker
URL: https://webaim.org/resources/contrastchecker/
For each color pair:
1. Enter foreground color (text)
2. Enter background color
3. Verify WCAG AAA pass
4. Test in both light and dark modes
```
**Automated Testing:**
```bash
# Install axe DevTools for automated checking
# Browser: Chrome, Firefox
# Manual: Right-click → Inspect → axe DevTools → Scan
# Or use npm package
npm install --save-dev axe-core jest-axe
```
### 1.3 Keyboard Navigation
**REQUIREMENT:** All interactive elements accessible via keyboard only.
#### Tab Order
```html
<!-- Logical tab order (follow reading order) -->
<nav>
<a href="/">Home</a>
<!-- Tab 1 -->
<a href="/docs">Docs</a>
<!-- Tab 2 -->
</nav>
<main>
<input type="text" />
<!-- Tab 3 -->
<button>Submit</button>
<!-- Tab 4 -->
<a href="/learn">Learn more</a>
<!-- Tab 5 -->
</main>
<!-- Use tabindex sparingly for complex layouts -->
<button tabindex="0">Normal flow</button>
<button tabindex="-1">Not in tab order (but focusable)</button>
<!-- AVOID -->
<button tabindex="5">Arbitrary order</button>
<button tabindex="10">Breaks accessibility</button>
```
#### Focus Management
```astro
<!-- Visible focus indicators -->
<button class="
focus-visible:outline-2
focus-visible:outline-offset-2
focus-visible:outline-ring
">
Keyboard accessible
</button>
<!-- Modal focus trap -->
<dialog
role="dialog"
aria-modal="true"
id="modal"
on:keydown={(e) => {
if (e.key === 'Escape') {
modal.close();
}
}}
>
<button autofocus>First button in modal</button>
<!-- Focus automatically returns to trigger on close -->
</dialog>
```
#### Keyboard Shortcuts
| Key | Action | Element |
| ---------- | -------------------------------- | ------------------------ |
| Tab | Move focus forward | All interactive |
| Shift+Tab | Move focus backward | All interactive |
| Enter | Activate button | `<button>`, `<a>` |
| Space | Activate button, toggle checkbox | `<button>`, `<checkbox>` |
| Escape | Close modal/dropdown | `<dialog>`, `<menu>` |
| Arrow Keys | Navigate menu items | `<nav>`, `<select>` |
### 1.4 ARIA Labels & Descriptions
**REQUIREMENT:** All interactive elements have appropriate ARIA labels.
#### ARIA Attributes
```html
<!-- Button with icon - needs label -->
<button aria-label="Close dialog">
<svg><!-- X icon --></svg>
</button>
<!-- Form with error -->
<input
id="email"
type="email"
aria-describedby="email-error"
aria-invalid="true"
/>
<p id="email-error" role="alert">Invalid email format</p>
<!-- List of items -->
<ul role="list">
<li>Item 1</li>
<li>Item 2</li>
</ul>
<!-- Loading state -->
<button aria-busy="true" disabled>
Loading <span class="animate-spin">○</span>
</button>
<!-- Current page in navigation -->
<nav>
<a href="/current" aria-current="page">Current</a>
<a href="/other">Other</a>
</nav>
<!-- Live region (status messages) -->
<div role="status" aria-live="polite" aria-atomic="true">
Item added successfully
</div>
<!-- Expandable section -->
<button aria-expanded="false" aria-controls="details">Show details</button>
<div id="details" hidden>
<!-- Details content -->
</div>
```
### 1.5 Form Accessibility
**REQUIREMENT:** All form fields properly labeled and validated.
```astro
<!-- Proper form structure -->
<form>
<!-- Text input -->
<div class="flex flex-col mb-4">
<label for="name" class="mb-2 font-medium">
Full Name
<span aria-label="required">*</span>
</label>
<input
id="name"
type="text"
name="name"
required
aria-required="true"
placeholder="John Doe"
/>
</div>
<!-- Email with validation -->
<div class="flex flex-col mb-4">
<label for="email" class="mb-2 font-medium">
Email Address
</label>
<input
id="email"
type="email"
name="email"
required
aria-required="true"
aria-describedby="email-hint email-error"
/>
<p id="email-hint" class="text-xs text-muted-foreground mt-1">
We'll never share your email
</p>
<p id="email-error" class="text-xs text-destructive mt-1" hidden>
Invalid email format
</p>
</div>
<!-- Select dropdown -->
<div class="flex flex-col mb-4">
<label for="type" class="mb-2 font-medium">
Entity Type
</label>
<select
id="type"
name="type"
required
aria-label="Select entity type"
>
<option value="">Select...</option>
<option value="thing">Thing</option>
<option value="connection">Connection</option>
</select>
</div>
<!-- Checkbox -->
<div class="flex items-center mb-4">
<input
id="agree"
type="checkbox"
name="agree"
required
aria-required="true"
/>
<label for="agree" class="ml-2">
I agree to the terms
</label>
</div>
<!-- Submit button -->
<button
type="submit"
class="px-6 py-3 bg-primary text-primary-foreground rounded-md"
disabled={isLoading}
>
{isLoading ? 'Submitting...' : 'Submit Form'}
</button>
</form>
```
### 1.6 Screen Reader Testing
**REQUIREMENT:** Test with actual screen readers, not just plugins.
#### Test Checklist
- [ ] **Page title** - Describes page purpose
- [ ] **Page landmarks** - `<header>`, `<nav>`, `<main>`, `<footer>`
- [ ] **Heading hierarchy** - h1 → h2 → h3 (no skipping)
- [ ] **Link text** - Descriptive (not "click here")
- [ ] **Image alt text** - Meaningful and concise
- [ ] **Form labels** - Associated with inputs
- [ ] **Button purposes** - Clear from text/label
- [ ] **Error messages** - Announced and associated with inputs
- [ ] **Loading states** - Announced as aria-busy
- [ ] **Modal announcements** - Focused and trapped
#### Screen Reader Tools
**Windows:**
- NVDA (free) - https://www.nvaccess.org/
- JAWS (paid) - https://www.freedomscientific.com/
**Mac:**
- VoiceOver (built-in) - Cmd+F5 to enable
- JAWS (paid)
**Testing Process:**
```
1. Enable screen reader
2. Start from page top
3. Press Tab to navigate (interactive elements)
4. Press H to navigate (headings)
5. Verify all content is announced
6. Verify nothing unexpected is announced
7. Test forms with keyboard only
8. Test modal interactions
```
### 1.7 Mobile & Touch Accessibility
**REQUIREMENT:** Touch-friendly interface for mobile users.
#### Touch Target Sizes
```html
<!-- Minimum 44x44 pixels (11.2mm) -->
<button class="px-4 py-2 h-11">
<!-- 44px height -->
Touch-friendly button
</button>
<a href="#" class="px-4 py-2.5 h-12">
<!-- 48px height -->
Touch-friendly link
</a>
<!-- Spacing between targets: minimum 8px -->
<div class="flex gap-3">
<!-- 12px gap is safe -->
<button class="h-11">Button 1</button>
<button class="h-11">Button 2</button>
</div>
```
#### Mobile Viewport
```html
<!-- Allows pinch zoom (accessibility requirement) -->
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=5, user-scalable=yes"
/>
<!-- NOT this (disables zoom) -->
<meta
name="viewport"
content="width=device-width, initial-scale=1, user-scalable=no"
/>
```
### 1.8 Accessibility Audit Checklist
Before shipping any page:
- [ ] **Semantic HTML:** All interactive elements use proper tags
- [ ] **Color Contrast:** WCAG AAA (4.5:1 body, 3:1 large)
- [ ] **Keyboard Navigation:** Tab, Enter, Escape all work
- [ ] **Focus States:** Visible outline on all interactive elements
- [ ] **ARIA Labels:** Buttons, links, forms all labeled
- [ ] **Form Validation:** Errors associated with fields
- [ ] **Images:** All have meaningful alt text
- [ ] **Screen Reader:** Page makes sense read top-to-bottom
- [ ] **Touch Targets:** Minimum 44x44px with 8px spacing
- [ ] **Language:** `lang="en"` on `<html>` element
- [ ] **Links:** No "click here", descriptive text
- [ ] **Color:** Not sole means of conveying information
**Automated Tools:**
```bash
# axe DevTools
1. Open browser DevTools
2. Find axe DevTools tab
3. Click "Scan ALL of my page"
4. Fix issues marked as violations
# Lighthouse
1. Open DevTools → Lighthouse
2. Check "Accessibility"
3. Run audit
4. Fix critical issues
# WAVE
1. Install WAVE extension
2. Click icon to scan page
3. Review errors and alerts
4. Fix accessibility issues
```
---
## Part 2: Animations & Transitions
### 2.1 Animation Philosophy
**PRINCIPLE:** Animations should enhance, not distract. All animations:
- Are less than 300ms (except intentional long animations)
- Use `prefers-reduced-motion` for accessibility
- Don't autoplay audio or video
- Are reversible (hover effects undo on unhover)
### 2.2 Core Animations
```css
/* Global CSS */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideInFromLeft {
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideInFromRight {
from {
opacity: 0;
transform: translateX(20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes float {
0%,
100% {
transform: translateY(0px) scale(1);
}
50% {
transform: translateY(-15px) scale(1.02);
}
}
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
@keyframes shimmer {
0% {
background-position: -1000px 0;
}
100% {
background-position: 1000px 0;
}
}
/* Utility classes */
.animate-fadeIn {
animation: fadeIn 300ms ease-out forwards;
}
.animate-fadeInUp {
animation: fadeInUp 300ms ease-out forwards;
}
.animate-slideInLeft {
animation: slideInFromLeft 300ms ease-out forwards;
}
.animate-slideInRight {
animation: slideInFromRight 300ms ease-out forwards;
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
/* Respect user motion preferences */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
```
### 2.3 Transition Patterns
#### Page Transitions
```astro
<!-- Fade in on load -->
<div class="opacity-0 animate-fadeIn">
Page content fades in
</div>
<!-- Staggered animations for lists -->
<ul class="space-y-4">
{items.map((item, i) => (
<li
class="opacity-0 animate-fadeInUp"
style={{ animationDelay: `${i * 100}ms` }}
>
{item}
</li>
))}
</ul>
```
#### Button Interactions
```astro
<!-- Hover scale -->
<button class="
transition-all duration-200
hover:scale-105 active:scale-95
hover:shadow-lg active:shadow-md
">
Click me
</button>
<!-- Hover color -->
<button class="
bg-primary text-primary-foreground
transition-colors duration-200
hover:bg-primary/90
">
Hover effect
</button>
<!-- Hover lift -->
<button class="
transition-all duration-300
hover:-translate-y-1 hover:shadow-lg
">
Lift on hover
</button>
```
#### Card Interactions
```astro
<!-- Card hover effect -->
<div class="
rounded-lg bg-card border border-border p-6
transition-all duration-300
hover:shadow-lg hover:-translate-y-1 hover:border-primary/50
">
Card content
</div>
<!-- Gradient animation -->
<div class="
bg-gradient-to-r from-primary via-primary/50 to-primary
bg-[length:200%_auto]
animate-gradient
">
Animated gradient background
</div>
```
#### Form Interactions
```astro
<!-- Input focus -->
<input class="
px-4 py-2.5 rounded-md border border-border
transition-colors duration-200
focus:border-primary focus:ring-2 focus:ring-primary/20
"/>
<!-- Smooth label movement (floating label pattern) -->
<div class="relative">
<input
id="name"
type="text"
class="peer px-4 py-3 border border-border rounded-md"
placeholder=" "
/>
<label
for="name"
class="
absolute top-3 left-4
transition-all duration-200
peer-placeholder-shown:top-3 peer-placeholder-shown:text-muted-foreground
peer-focus:top-1 peer-focus:text-sm peer-focus:text-primary
"
>
Full Name
</label>
</div>
```
#### Loading States
```astro
<!-- Skeleton loader -->
<div class="space-y-4">
<div class="h-12 bg-muted rounded-md animate-pulse"></div>
<div class="h-8 bg-muted rounded-md animate-pulse"></div>
<div class="h-8 bg-muted rounded-md animate-pulse w-2/3"></div>
</div>
<!-- Spinner -->
<div class="flex items-center gap-3">
<div class="w-5 h-5 border-2 border-primary/20 border-t-primary rounded-full animate-spin"></div>
<span>Loading...</span>
</div>
<!-- Progress bar -->
<div class="h-1 bg-muted rounded-full overflow-hidden">
<div class="h-full bg-primary rounded-full animate-pulse"
style="width: 65%; animation: pulse 1.5s ease-in-out infinite;"></div>
</div>
```
#### Success/Error Animations
```astro
<!-- Success toast -->
<div class="
p-4 rounded-lg bg-green-500/10 border border-green-500/20
animate-fadeInUp
flex items-start gap-3
">
<svg class="w-5 h-5 text-green-600 flex-shrink-0 mt-0.5">
<!-- Check icon -->
</svg>
<p class="text-green-700">Success message</p>
</div>
<!-- Error shake animation -->
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
}
<div class="animate-shake" style="animation: shake 0.3s ease-in-out;">
Error message
</div>
```
### 2.4 Animation Timing
| Duration | Use Case |
| -------- | ---------------------------------------- |
| 150ms | UI micro-interactions (hover, focus) |
| 200ms | Button clicks, form interactions |
| 300ms | Standard transitions, page sections |
| 500ms | Modals, significant layout changes |
| 800ms+ | Long-form animations, intentional delays |
```astro
<!-- Micro-interaction: 150ms -->
<button class="transition-all duration-150 hover:bg-primary/90">
Quick feedback
</button>
<!-- Standard transition: 300ms -->
<div class="transition-all duration-300 hover:shadow-lg">
Card animation
</div>
<!-- Modal: 500ms -->
<dialog class="
opacity-0 scale-95
data-[open]:opacity-100 data-[open]:scale-100
transition-all duration-500
">
Modal
</dialog>
```
### 2.5 Motion Preferences
**REQUIREMENT:** Respect `prefers-reduced-motion` system setting.
```css
/* Disable all animations for users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
```
### 2.6 Hero Section Animation
```astro
<section class="relative overflow-hidden px-4 py-32">
<!-- Background blurs -->
<div class="absolute inset-0 -z-10 overflow-hidden">
<!-- Left blur - float in from left -->
<div class="
absolute left-1/4 top-0 h-96 w-96
rounded-full bg-primary/10 blur-[120px]
opacity-0 animate-fadeIn
"></div>
<!-- Right blur - float in from right -->
<div class="
absolute right-1/3 bottom-0 h-80 w-80
rounded-full bg-accent/10 blur-[120px]
opacity-0 animate-fadeIn
animation-delay-200ms
"></div>
</div>
<!-- Content -->
<div class="max-w-4xl mx-auto text-center">
<!-- Badge slides in -->
<div class="
inline-block mb-6
opacity-0 animate-fadeInUp
animation-delay-100ms
">
<span class="text-sm font-medium">New Feature</span>
</div>
<!-- Title slides in -->
<h1 class="
text-5xl font-bold mb-6
opacity-0 animate-fadeInUp
animation-delay-200ms
">
Main Title
</h1>
<!-- Subtitle slides in -->
<p class="
text-xl text-muted-foreground mb-12
opacity-0 animate-fadeInUp
animation-delay-300ms
">
Subtitle
</p>
<!-- Buttons slide in -->
<div class="
flex gap-4 justify-center
opacity-0 animate-fadeInUp
animation-delay-400ms
">
<button>Primary CTA</button>
<button>Secondary CTA</button>
</div>
</div>
<!-- Scroll indicator bounces -->
<div class="flex justify-center mt-12">
<svg class="w-6 h-6 animate-bounce">
<!-- Chevron down icon -->
</svg>
</div>
</section>
```
### 2.7 Playground Animation
```astro
<!-- Form appears on load -->
<form class="opacity-0 animate-fadeInUp animation-delay-200ms space-y-4">
<!-- Form fields -->
</form>
<!-- Data updates with fade -->
<div class="
relative transition-opacity duration-300
opacity-0 data-[loaded]:opacity-100
">
<pre>{JSON.stringify(liveData)}</pre>
</div>
<!-- Stats cards stagger in -->
{stats.map((stat, i) => (
<div
class="
opacity-0 animate-fadeInUp
rounded-lg p-6 border border-border text-center
"
style={{
animationDelay: `${i * 100}ms`
}}
>
<p class="text-2xl font-bold">{stat.value}</p>
<p class="text-sm text-muted-foreground">{stat.label}</p>
</div>
))}
```
### 2.8 Relationship Graph Animation
```astro
<!-- Graph canvas with fade in -->
<div class="
rounded-lg border border-border overflow-hidden
opacity-0 animate-fadeIn animation-delay-300ms
">
<canvas class="w-full h-[500px]"></canvas>
</div>
<!-- Selected entity info slides in from right -->
<div class="
rounded-lg bg-background p-6
opacity-0 animate-slideInRight
animation-delay-400ms
">
<!-- Entity properties -->
</div>
<!-- Connected items with stagger -->
{connections.map((conn, i) => (
<div
class="
flex items-center gap-2 p-2
opacity-0 animate-fadeInUp
rounded-md hover:bg-muted
transition-colors duration-200
"
style={{
animationDelay: `${500 + i * 50}ms`
}}
>
{/* Connection item */}
</div>
))}
```
### 2.9 CTA Section Animation
```astro
<section class="
relative overflow-hidden px-4 py-28
bg-gradient-to-br from-primary to-primary/80
text-primary-foreground
">
<!-- Content stagger -->
<div class="max-w-4xl mx-auto text-center">
<!-- Icon floats -->
<div class="
mb-6 flex justify-center
opacity-0 animate-fadeIn
">
<div class="animate-float">
<!-- Icon -->
</div>
</div>
<!-- Headline slides in -->
<h2 class="
text-5xl font-bold mb-6
opacity-0 animate-fadeInUp
animation-delay-100ms
">
Ready to build?
</h2>
<!-- Description slides in -->
<p class="
text-xl opacity-0 animate-fadeInUp
animation-delay-200ms
">
Get started with the ontology
</p>
<!-- Buttons slide in -->
<div class="
flex gap-4 justify-center mt-8
opacity-0 animate-fadeInUp
animation-delay-300ms
">
<button>Get Started</button>
<button>Learn More</button>
</div>
<!-- Stats appear with stagger -->
{stats.map((stat, i) => (
<div
class="
opacity-0 animate-fadeIn
animation-delay-[${400 + i * 100}ms]
"
>
{stat}
</div>
))}
</div>
</section>
```
---
## Version History
| Version | Date | Changes |
| ------- | -------- | -------------------------------------------------- |
| 1.0.0 | Oct 2024 | Initial accessibility and animation specifications |
---
**Specifications Maintained By:** Design Agent
**Last Updated:** October 25, 2024
**Status:** Production Ready
---
## Quick Reference
### Accessibility Checklist
- [ ] Semantic HTML
- [ ] WCAG AAA contrast (4.5:1 body, 3:1 large)
- [ ] Keyboard navigation works
- [ ] Focus indicators visible
- [ ] ARIA labels present
- [ ] Forms properly labeled
- [ ] Touch targets 44x44px
- [ ] Mobile zoom not disabled
### Animation Checklist
- [ ] All animations < 500ms (except intentional)
- [ ] `prefers-reduced-motion` respected
- [ ] No autoplay audio/video
- [ ] Animations enhance, don't distract
- [ ] Smooth easing (ease-in-out, ease-out)
- [ ] Staggered animations for lists
- [ ] Loading states animated
- [ ] Focus states visible