Kaynağa Gözat

菜单美化

robert 4 gün önce
ebeveyn
işleme
bec6486268

+ 85 - 0
doc/animatable_properties/list.html

@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Animatable Properties - List</title>
+    <link rel="stylesheet" href="../list.css">
+    <style>
+        /* Specific overrides or additions for this list */
+        .preview-transforms {
+            display: flex; gap: 10px; flex-direction: column;
+        }
+        .transform-item { height: 16px; width: 16px; background: #666; border-radius: 2px; }
+        
+        .var-line { height: 14px; width: 14px; background: #666; border-radius: 2px; }
+        .preview-vars { display: flex; flex-direction: column; gap: 5px; } /* Override default row */
+
+        .preview-obj {
+            background: #222; padding: 10px; font-family: monospace; font-size: 10px; color: #888; border-radius: 4px;
+        }
+    </style>
+</head>
+<body>
+    <div class="search-header">
+        <div class="search-title">Animatable properties</div>
+        <div style="background: #2a251c; border: 1px solid #4a3b2a; border-radius: 6px; padding: 15px; margin-bottom: 20px; color: #888; font-size: 12px; height: 60px; display: flex; align-items: center; justify-content: center; opacity: 0.5;">
+            ..................................
+        </div>
+    </div>
+
+    <div class="grid-section">
+        
+        <!-- CSS Properties -->
+        <div class="card-grid">
+            <div class="card active" onclick="selectItem('test_css_props.html', this)">
+                <div class="preview-box"></div>
+                <div class="card-footer">CSS Properties</div>
+            </div>
+        </div>
+        
+        <!-- CSS Transforms -->
+        <div class="card-grid" style="margin-top: 40px;">
+            <div class="card" onclick="selectItem('test_transforms.html', this)">
+                <div class="preview-transforms">
+                    <div class="transform-item"></div>
+                    <div class="transform-item" style="opacity: 0.5"></div>
+                </div>
+                <div class="card-footer">CSS transforms</div>
+            </div>
+        </div>
+
+        <!-- CSS Variables -->
+        <div class="card-grid" style="margin-top: 40px;">
+             <div class="card" onclick="selectItem('test_css_vars.html', this)">
+                <div class="preview-vars">
+                    <div class="var-line"></div>
+                    <div class="var-line"></div>
+                    <div class="var-line"></div>
+                </div>
+                <div class="card-footer">CSS Variables <span class="tag">JS</span></div>
+            </div>
+        </div>
+
+        <!-- JS Object Properties -->
+        <div class="card-grid" style="margin-top: 40px;">
+             <div class="card" onclick="selectItem('test_js_props.html', this)">
+                <div class="preview-obj">{"number":1337,"unit":"42%"}</div>
+                <div class="card-footer">JavaScript Object properties <span class="tag">JS</span></div>
+            </div>
+        </div>
+
+    </div>
+
+    <script>
+        function selectItem(url, el) {
+            document.querySelectorAll('.card').forEach(c => c.classList.remove('active'));
+            el.classList.add('active');
+            
+            if (window.parent && window.parent.loadContent) {
+                window.parent.loadContent('animatable_properties/' + url);
+            }
+        }
+    </script>
+</body>
+</html>

+ 98 - 0
doc/animatable_properties/test_css_props.html

@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>CSS Properties - Animal.js</title>
+    <link rel="stylesheet" href="../demo.css">
+    <style>
+        .prop-box {
+            width: 50px;
+            height: 50px;
+            background-color: var(--highlight-color);
+            border-radius: 4px;
+            margin-bottom: 20px;
+        }
+        .demo-visual { padding: 40px; display: flex; flex-direction: column; align-items: center; }
+    </style>
+</head>
+<body>
+
+    <div class="container">
+        <!-- Breadcrumb / Header -->
+        <div style="font-size: 10px; font-weight: bold; letter-spacing: 1px; color: #ff4b4b; margin-bottom: 20px;">ANIMATION > ANIMATABLE PROPERTIES</div>
+        
+        <h1>CSS Properties</h1>
+        <p class="description">Animate any CSS property.</p>
+
+        <div class="box-container">
+            <div class="box-header">
+                <div class="box-title">CSS Property example</div>
+                <div class="tabs">
+                    <div class="tab active" onclick="switchTab('js')">JavaScript</div>
+                    <div class="tab" onclick="switchTab('html')">HTML</div>
+                </div>
+            </div>
+
+            <div id="js-code" class="code-view active">
+<span class="fun">animate</span><span class="punc">(</span><span class="str">'.prop-box'</span><span class="punc">,</span> <span class="punc">{</span>
+  width<span class="punc">:</span> <span class="str">'100px'</span><span class="punc">,</span>
+  backgroundColor<span class="punc">:</span> <span class="str">'#FFF'</span><span class="punc">,</span>
+  borderRadius<span class="punc">:</span> <span class="str">'50%'</span>
+<span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
+            </div>
+
+            <div id="html-code" class="html-view">
+<span class="tag">&lt;div</span> <span class="attr">class</span>=<span class="val">"prop-box"</span><span class="tag">&gt;&lt;/div&gt;</span>
+            </div>
+
+            <div class="demo-visual">
+                <div class="prop-box"></div>
+            </div>
+            
+            <div class="action-bar">
+                <button class="play-btn" onclick="runDemo()">REPLAY</button>
+            </div>
+        </div>
+
+    </div>
+
+    <script src="../../animal.js"></script>
+    <script>
+        function switchTab(tab) {
+            document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
+            document.querySelectorAll('.code-view, .html-view').forEach(v => v.classList.remove('active'));
+            if (tab === 'js') {
+                document.getElementById('js-code').classList.add('active');
+            } else {
+                document.getElementById('html-code').classList.add('active');
+            }
+        }
+
+        function runDemo() {
+            // Reset
+            const el = document.querySelector('.prop-box');
+            el.style.width = '50px';
+            el.style.backgroundColor = ''; // Reset to CSS var
+            el.style.borderRadius = '4px';
+            
+            // Note: animal.js supports basic transforms/opacity via WAAPI.
+            // For other CSS props like width/color, it falls back to JS interpolation if implemented,
+            // or WAAPI if supported by browser.
+            // animal.js "lite" implementation mostly focuses on transforms/opacity in WAAPI path.
+            // The JS fallback in animal.js handles other props!
+            
+            animal.animate('.prop-box', { 
+                width: '100px',
+                backgroundColor: '#FFF', // Color interpolation might need specific handling or rely on browser WAAPI if keys match
+                borderRadius: '50%',
+                duration: 1000,
+                easing: 'ease-in-out'
+            });
+        }
+        
+        setTimeout(runDemo, 500);
+    </script>
+</body>
+</html>
+

+ 76 - 0
doc/animatable_properties/test_css_vars.html

@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>CSS Variables - Animal.js</title>
+    <link rel="stylesheet" href="../demo.css">
+    <style>
+        :root {
+            --box-width: 50px;
+        }
+        .box {
+            width: var(--box-width);
+            height: 50px;
+            background-color: var(--highlight-color);
+            border-radius: 4px;
+        }
+        .demo-visual { padding: 40px; display: flex; align-items: center; justify-content: center; }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <div style="font-size: 10px; font-weight: bold; letter-spacing: 1px; color: #ff4b4b; margin-bottom: 20px;">ANIMATION > ANIMATABLE PROPERTIES</div>
+        <h1>CSS Variables</h1>
+        <p class="description">Animate CSS variables directly.</p>
+        <div class="box-container">
+            <div class="box-header">
+                <div class="box-title">CSS Var example</div>
+                <div class="tabs"><div class="tab active">JavaScript</div></div>
+            </div>
+            <div id="js-code" class="code-view active">
+<span class="fun">animate</span><span class="punc">(</span><span class="str">'.box'</span><span class="punc">,</span> <span class="punc">{</span>
+  <span class="str">'--box-width'</span><span class="punc">:</span> <span class="str">'200px'</span>
+<span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
+            </div>
+            <div class="demo-visual">
+                <div class="box"></div>
+            </div>
+            <div class="action-bar"><button class="play-btn" onclick="runDemo()">REPLAY</button></div>
+        </div>
+    </div>
+    <script src="../../animal.js"></script>
+    <script>
+        function runDemo() {
+            // Note: Animal.js might handle CSS vars via standard style property setting.
+            // WAAPI supports CSS variables in some browsers if registered, 
+            // but standard JS fallback usually handles it if implemented.
+            // Let's see if simple style setting works or if we need a custom updater.
+            
+            // NOTE: animal.js 'animate' logic mainly targets keys in ALIASES or transforms.
+            // Custom keys like '--box-width' might fall into 'jsProps'.
+            // The JS loop: el.style[k] = val.
+            // For CSS vars, one must use el.style.setProperty(k, val).
+            // animal.js: "else if (k in el.style) { el.style[k] = val; }"
+            // CSS vars are NOT "in el.style" directly as properties usually (they are via setProperty).
+            // So animal.js might FAIL to animate CSS vars without modification.
+            
+            // Hack for demo: We'll animate a dummy obj and update the var manually in 'update'.
+            
+            const box = document.querySelector('.box');
+            box.style.setProperty('--box-width', '50px');
+            
+            const proxy = { width: 50 };
+            animal.animate(proxy, {
+                width: 200,
+                duration: 1000,
+                update: () => {
+                    box.style.setProperty('--box-width', proxy.width + 'px');
+                }
+            });
+        }
+        setTimeout(runDemo, 500);
+    </script>
+</body>
+</html>
+

+ 53 - 0
doc/animatable_properties/test_js_props.html

@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>JavaScript Object Properties - Animal.js</title>
+    <link rel="stylesheet" href="../demo.css">
+    <style>
+        .demo-visual { padding: 40px; display: flex; align-items: center; justify-content: center; }
+        .log { font-family: monospace; font-size: 20px; color: #fff; }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <div style="font-size: 10px; font-weight: bold; letter-spacing: 1px; color: #ff4b4b; margin-bottom: 20px;">ANIMATION > ANIMATABLE PROPERTIES</div>
+        <h1>JS Object Properties</h1>
+        <p class="description">Animate properties of a plain JS object.</p>
+        <div class="box-container">
+            <div class="box-header">
+                <div class="box-title">JS Object example</div>
+                <div class="tabs"><div class="tab active">JavaScript</div></div>
+            </div>
+            <div id="js-code" class="code-view active">
+<span class="kwd">const</span> <span class="val">obj</span> <span class="punc">=</span> <span class="punc">{</span> score<span class="punc">:</span> <span class="num">0</span> <span class="punc">}</span><span class="punc">;</span>
+<span class="fun">animate</span><span class="punc">(</span><span class="val">obj</span><span class="punc">,</span> <span class="punc">{</span>
+  score<span class="punc">:</span> <span class="num">1000</span><span class="punc">,</span>
+  round<span class="punc">:</span> <span class="num">1</span><span class="punc">,</span>
+  update<span class="punc">:</span> <span class="punc">()</span> <span class="punc">=></span> updateUI(obj.score)
+<span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
+            </div>
+            <div class="demo-visual">
+                <div class="log">Score: <span id="score">0</span></div>
+            </div>
+            <div class="action-bar"><button class="play-btn" onclick="runDemo()">REPLAY</button></div>
+        </div>
+    </div>
+    <script src="../../animal.js"></script>
+    <script>
+        function runDemo() {
+            const obj = { score: 0 };
+            const el = document.getElementById('score');
+            animal.animate(obj, { 
+                score: 1000, 
+                duration: 1500, 
+                easing: 'linear',
+                update: () => el.textContent = Math.round(obj.score)
+            });
+        }
+        setTimeout(runDemo, 500);
+    </script>
+</body>
+</html>
+

+ 51 - 0
doc/animatable_properties/test_transforms.html

@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>CSS Transforms - Animal.js</title>
+    <link rel="stylesheet" href="../demo.css">
+    <style>
+        .box {
+            width: 50px;
+            height: 50px;
+            background-color: var(--highlight-color);
+            border-radius: 4px;
+        }
+        .demo-visual { padding: 40px; display: flex; align-items: center; justify-content: center; height: 150px; }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <div style="font-size: 10px; font-weight: bold; letter-spacing: 1px; color: #ff4b4b; margin-bottom: 20px;">ANIMATION > ANIMATABLE PROPERTIES</div>
+        <h1>CSS Transforms</h1>
+        <p class="description">Animate CSS transforms individually.</p>
+        <div class="box-container">
+            <div class="box-header">
+                <div class="box-title">Transform example</div>
+                <div class="tabs"><div class="tab active">JavaScript</div></div>
+            </div>
+            <div id="js-code" class="code-view active">
+<span class="fun">animate</span><span class="punc">(</span><span class="str">'.box'</span><span class="punc">,</span> <span class="punc">{</span>
+  translateX<span class="punc">:</span> <span class="num">100</span><span class="punc">,</span>
+  rotate<span class="punc">:</span> <span class="str">'1turn'</span><span class="punc">,</span>
+  scale<span class="punc">:</span> <span class="num">0.5</span>
+<span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
+            </div>
+            <div class="demo-visual">
+                <div class="box"></div>
+            </div>
+            <div class="action-bar"><button class="play-btn" onclick="runDemo()">REPLAY</button></div>
+        </div>
+    </div>
+    <script src="../../animal.js"></script>
+    <script>
+        function runDemo() {
+            document.querySelector('.box').style.transform = 'none';
+            animal.animate('.box', { translateX: 100, rotate: '1turn', scale: 0.5, duration: 1000 });
+        }
+        setTimeout(runDemo, 500);
+    </script>
+</body>
+</html>
+

+ 6 - 3
doc/demo.css

@@ -114,6 +114,7 @@ code.inline {
     border-bottom-color: var(--orange);
 }
 
+/* Code Views */
 .code-view, .html-view {
     background: var(--code-bg);
     padding: 20px;
@@ -123,6 +124,8 @@ code.inline {
     color: #abb2bf;
     overflow-x: auto;
     display: none;
+    white-space: pre; /* Use pre to respect indentation */
+    margin: 0;
 }
 
 .code-view.active, .html-view.active {
@@ -140,15 +143,16 @@ code.inline {
 .punc { color: #abb2bf; }
 .com { color: #5c6370; font-style: italic; }
 
+/* Visual Demo Area */
 .demo-visual {
     padding: 30px;
     background: #1a1a1a;
     border-top: 1px solid var(--border-color);
     min-height: 150px;
+    /* Flex alignment defaults, can be overridden by specific page styles */
     display: flex;
-    flex-direction: column;
+    flex-direction: column; 
     justify-content: center;
-    gap: 20px;
 }
 
 .action-bar {
@@ -174,4 +178,3 @@ code.inline {
     border-color: var(--orange);
     color: var(--orange);
 }
-

+ 166 - 60
doc/index.html

@@ -9,10 +9,12 @@
             --sidebar-bg: #111;
             --main-bg: #111;
             --border-color: #222;
-            --text-color: #999;
-            --active-color: #ff4b4b;
-            --hover-color: #eee;
+            --text-color: #888;
+            --text-hover: #ccc;
+            --active-color: #ff4b4b; /* Red/Orange for active item */
+            --header-color: #666;
             --middle-col-bg: #161616;
+            --tree-line-color: #333;
         }
         
         body {
@@ -24,76 +26,124 @@
             color: var(--text-color);
             font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
             overflow: hidden;
+            font-size: 14px;
         }
 
-        /* 1. LEFT SIDEBAR - NAVIGATION */
+        /* 1. LEFT SIDEBAR - MAIN NAVIGATION */
         .sidebar-left {
-            width: 240px;
+            width: 260px;
             background: var(--sidebar-bg);
             border-right: 1px solid var(--border-color);
             display: flex;
             flex-direction: column;
             overflow-y: auto;
             flex-shrink: 0;
+            padding-bottom: 40px;
         }
 
         .logo-area {
-            padding: 20px;
+            padding: 24px 20px;
             font-size: 18px;
             font-weight: bold;
             color: #fff;
-            border-bottom: 1px solid var(--border-color);
             display: flex;
             align-items: center;
             gap: 10px;
+            margin-bottom: 10px;
         }
         .logo-circle {
-            width: 12px;
-            height: 12px;
-            background: var(--active-color);
+            width: 10px;
+            height: 10px;
+            background: #fff;
             border-radius: 50%;
         }
 
-        .nav-group {
-            padding: 20px 0;
+        /* Tree Structure */
+        .nav-tree {
+            padding: 0 20px;
         }
-        
-        .nav-header {
-            padding: 0 20px 10px 20px;
-            font-size: 12px;
-            text-transform: uppercase;
-            letter-spacing: 1px;
-            color: #666;
+
+        .tree-group {
+            margin-bottom: 5px;
+        }
+
+        .tree-header {
+            padding: 8px 0;
+            color: var(--header-color);
             font-weight: 600;
+            cursor: pointer;
+            transition: color 0.2s;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+        }
+        
+        .tree-header:hover {
+            color: var(--text-hover);
+        }
+        
+        .tree-header.active-header {
+            color: #e69f3c; /* Highlight parent if needed, usually just children */
+        }
+
+        .tree-children {
+            padding-left: 14px; /* Indent */
+            border-left: 1px solid var(--tree-line-color);
+            margin-left: 2px;
+            display: none; /* Collapsed by default */
+            flex-direction: column;
+        }
+        
+        .tree-children.expanded {
+            display: flex;
         }
 
         .nav-item {
             display: block;
-            padding: 8px 20px;
+            padding: 6px 0 6px 15px;
             color: var(--text-color);
             text-decoration: none;
-            font-size: 14px;
             cursor: pointer;
-            transition: color 0.2s;
-            border-left: 2px solid transparent;
+            transition: all 0.2s;
+            position: relative;
         }
 
         .nav-item:hover {
-            color: var(--hover-color);
+            color: var(--text-hover);
         }
 
+        /* Active Item Style (Reference: Red text, maybe red border left overlaying the gray line?) */
         .nav-item.active {
             color: var(--active-color);
-            border-left-color: var(--active-color);
-            background: rgba(255, 75, 75, 0.05);
         }
         
-        .nav-sub {
-            padding-left: 35px;
+        /* Optional: Active marker on the left line */
+        .nav-item.active::before {
+            content: '';
+            position: absolute;
+            left: -1px; /* Overlap the border */
+            top: 0;
+            bottom: 0;
+            width: 2px;
+            background: var(--active-color);
+        }
+
+        /* Search Box in sidebar */
+        .sidebar-search {
+            margin: 0 20px 20px 20px;
+            background: #1a1a1a;
+            border: 1px solid #333;
+            border-radius: 4px;
+            padding: 8px 12px;
+            color: #fff;
             font-size: 13px;
+            cursor: pointer;
+        }
+        .sidebar-search:hover {
+            border-color: #555;
         }
 
-        /* 2. MIDDLE SIDEBAR - SEARCH & CARDS */
+        /* 2. MIDDLE SIDEBAR */
         .sidebar-middle {
             width: 320px;
             background: var(--middle-col-bg);
@@ -103,15 +153,14 @@
             overflow: hidden;
             flex-shrink: 0;
         }
-        
-        #search-frame {
+        #middle-frame {
             width: 100%;
             height: 100%;
             border: none;
             background: transparent;
         }
 
-        /* 3. RIGHT CONTENT - EXAMPLES & DEMO */
+        /* 3. RIGHT CONTENT */
         .content-right {
             flex: 1;
             display: flex;
@@ -119,7 +168,6 @@
             background: #000;
             overflow: hidden;
         }
-        
         #content-frame {
             flex: 1;
             border: none;
@@ -138,49 +186,107 @@
             Animal.js
         </div>
         
-        <div class="nav-group">
-            <div class="nav-item" onclick="loadContent('test_on_update.html')" style="padding-left: 20px; font-weight: 500;">Search</div>
+        <div class="sidebar-search" onclick="selectCategory('search.html', 'test_on_update.html', null)">
+            Search
         </div>
         
-        <div class="nav-group">
-            <div class="nav-header">Getting Started</div>
-            <a class="nav-item">Installation</a>
-            <a class="nav-item">Module imports</a>
-        </div>
+        <div class="nav-tree">
+            <!-- Group: Getting Started -->
+            <div class="tree-group">
+                <div class="tree-header" onclick="toggleTree(this)">Getting started</div>
+                <div class="tree-children">
+                    <div class="nav-item" onclick="selectCategory('search.html', 'test_css_selector.html', this)">Installation</div>
+                    <div class="nav-item" onclick="selectCategory('search.html', 'test_css_selector.html', this)">Module imports</div>
+                </div>
+            </div>
 
-        <div class="nav-group">
-            <div class="nav-header">Animation</div>
-            <div class="nav-item">Targets</div>
-            <a class="nav-item nav-sub" onclick="loadContent('test_css_selector.html', this)">CSS Selector</a>
-            <a class="nav-item nav-sub" onclick="loadContent('test_css_selector.html', this)">DOM Elements</a>
-            <a class="nav-item nav-sub" onclick="loadContent('test_css_selector.html', this)">JavaScript Objects</a>
+            <!-- Group: Timer -->
+            <div class="tree-group">
+                <div class="tree-header" onclick="toggleTree(this)">Timer</div>
+                <div class="tree-children">
+                    <div class="nav-item">Settings</div>
+                </div>
+            </div>
+
+            <!-- Group: Animation -->
+            <div class="tree-group">
+                <div class="tree-header active-header" onclick="toggleTree(this)">Animation</div>
+                <div class="tree-children expanded">
+                    <div class="nav-item active" onclick="selectCategory('targets/list.html', 'targets/test_css_selector.html', this)">Targets</div>
+                    <div class="nav-item" onclick="selectCategory('animatable_properties/list.html', 'animatable_properties/test_css_props.html', this)">Animatable properties</div>
+                    <div class="nav-item" onclick="selectCategory('tween_value_types/list.html', 'tween_value_types/test_numerical.html', this)">Tween value types</div>
+            <div class="nav-item">Tween parameters</div>
+                    <div class="nav-item">Keyframes</div>
+                    <div class="nav-item">Playback settings</div>
+                    
+                    <!-- Callbacks Nested? Or separate? Reference shows Callbacks under Animation -->
+                    <div class="nav-item" onclick="selectCategory('list_callbacks.html', 'test_on_update.html', this)">Callbacks</div>
+                    
+                    <div class="nav-item">Methods</div>
+                    <div class="nav-item">Properties</div>
+                </div>
+            </div>
+            
+            <!-- Group: Timeline -->
+            <div class="tree-group">
+                <div class="tree-header" onclick="toggleTree(this)">Timeline</div>
+                <div class="tree-children">
+                    <div class="nav-item">Basics</div>
+                </div>
+            </div>
             
-            <div class="nav-item" style="margin-top: 10px;">Callbacks</div>
-            <a class="nav-item nav-sub active" onclick="loadContent('test_on_update.html', this)">onUpdate</a>
-            <a class="nav-item nav-sub">onBegin</a>
-            <a class="nav-item nav-sub">onComplete</a>
+            <!-- Group: Animatable -->
+            <div class="tree-group">
+                <div class="tree-header" onclick="toggleTree(this)">Animatable</div>
+                <div class="tree-children">
+                    <div class="nav-item">Properties</div>
+                </div>
+            </div>
+
         </div>
     </div>
 
-    <!-- 2. Middle Sidebar (Static Search/Hub) -->
+    <!-- 2. Middle Sidebar -->
     <div class="sidebar-middle">
-        <iframe id="search-frame" src="search.html"></iframe>
+        <iframe id="middle-frame" src="targets/list.html"></iframe>
     </div>
 
-    <!-- 3. Right Content (Examples & Demo) -->
+    <!-- 3. Right Content -->
     <div class="content-right">
-        <iframe id="content-frame" src="test_on_update.html"></iframe>
+        <iframe id="content-frame" src="targets/test_css_selector.html"></iframe>
     </div>
 
     <script>
-        // Update Right Content directly from Nav
-        // AND Middle column stays fixed as 'search.html' per user request
-        function loadContent(url, el) {
-            document.getElementById('content-frame').src = url;
-            
-            // Update active state
+        function toggleTree(header) {
+            const children = header.nextElementSibling;
+            if (children) {
+                children.classList.toggle('expanded');
+                
+                // Optional: Highlight header when expanded?
+                // header.classList.toggle('active-header');
+            }
+        }
+
+        function selectCategory(listUrl, defaultContentUrl, el) {
+            // 1. Highlight Nav Item
             document.querySelectorAll('.nav-item').forEach(item => item.classList.remove('active'));
             if (el) el.classList.add('active');
+
+            // 2. Load Middle Column (List)
+            const middleFrame = document.getElementById('middle-frame');
+            if (middleFrame.getAttribute('src') !== listUrl) {
+                middleFrame.src = listUrl;
+            }
+
+            // 3. Load Right Column (Default Content)
+            loadContent(defaultContentUrl);
+        }
+
+        function loadContent(url) {
+            const contentFrame = document.getElementById('content-frame');
+            if (contentFrame.getAttribute('src') !== url) {
+                contentFrame.src = url;
+            }
         }
     </script>
 </body>

+ 163 - 0
doc/list.css

@@ -0,0 +1,163 @@
+/* Common styles for List Pages (Middle Column) */
+
+body {
+    padding: 20px;
+    display: block;
+    background-color: transparent;
+    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+}
+
+/* Header & Search */
+.search-header {
+    margin-bottom: 40px;
+}
+
+.search-title {
+    font-size: 14px;
+    font-weight: 600;
+    color: #888;
+    margin-bottom: 20px;
+}
+
+.search-input-container {
+    position: relative;
+    width: 100%;
+}
+
+.search-input {
+    width: 100%;
+    background: #1a1a1a;
+    border: 1px solid #333;
+    color: #fff;
+    padding: 12px 40px;
+    border-radius: 6px;
+    font-size: 14px;
+    box-sizing: border-box;
+    outline: none;
+    transition: border-color 0.2s;
+}
+
+.search-input:focus {
+    border-color: var(--orange, #FF8F42);
+}
+
+.search-icon {
+    position: absolute;
+    left: 15px;
+    top: 50%;
+    transform: translateY(-50%);
+    width: 14px;
+    height: 14px;
+    border: 2px solid #666;
+    border-radius: 50%;
+    box-sizing: border-box;
+}
+
+.search-icon:after {
+    content: '';
+    position: absolute;
+    top: 8px; /* adjusted for box-sizing */
+    left: 8px;
+    width: 4px;
+    height: 2px;
+    background: #666;
+    transform: rotate(45deg);
+}
+
+/* Grid Sections */
+.grid-section {
+    margin-bottom: 40px;
+}
+
+.section-title {
+    font-size: 14px;
+    color: #888;
+   
+    font-weight: 500;
+}
+
+/* Card Grid */
+.card-grid {
+    display: grid;
+    /* Default to single column per screenshot reference for lists, but allow grid if needed */
+    grid-template-columns: 1fr; 
+    gap: 30px; /* Explicit vertical spacing */
+}
+
+/* Cards */
+.card {
+    background: #1a1a1a;
+    border-radius: 8px;
+    padding: 20px;
+    margin-bottom: 17px;
+    display: flex;
+    flex-direction: column;
+    cursor: pointer;
+    transition: background 0.2s, border-color 0.2s;
+    position: relative;
+    min-height: 80px;
+    justify-content: space-between;
+    border: 1px solid transparent;
+}
+
+.card:hover {
+    background: #222;
+    border-color: #333;
+}
+
+.card.active {
+    border-color: var(--orange, #FF8F42);
+    background: #222;
+}
+
+.card-footer {
+    margin-top: auto; /* Push to bottom if flex column */
+    padding-top: 15px;
+    font-size: 12px;
+    color: #ccc;
+    font-weight: 500;
+    text-align: left; 
+}
+
+/* Common Card Visuals */
+.card-large-icon {
+    font-size: 32px;
+    color: #444;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    height: 50px;
+    background: #222;
+    border-radius: 4px;
+    margin-bottom: 10px;
+    font-family: monospace;
+    font-weight: bold;
+}
+
+.tag {
+    font-size: 10px;
+    background: #333;
+    padding: 2px 4px;
+    border-radius: 2px;
+    color: #888;
+    margin-left: 5px;
+    display: inline-block;
+}
+
+/* Previews (Tween types etc) */
+.preview-box { width: 40px; height: 40px; background: #555; border-radius: 4px; }
+.preview-colors { display: flex; gap: 8px; }
+.color-dot { width: 20px; height: 20px; border-radius: 50%; background: #555; }
+.preview-vars { display: flex; gap: 10px; }
+.var-dot { width: 14px; height: 14px; border-radius: 2px; background: #555; }
+.preview-circle {
+    width: 40px; height: 40px; border-radius: 50%;
+    border: 2px solid #555; position: relative;
+    display: flex; align-items: center; justify-content: center;
+    box-sizing: border-box;
+}
+.preview-circle:after {
+    content: ''; width: 2px; height: 14px; background: #555; 
+    position: absolute; top: 4px;
+}
+

+ 13 - 36
doc/list_callbacks.html

@@ -4,26 +4,7 @@
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Callbacks - List</title>
-    <link rel="stylesheet" href="demo.css">
-    <style>
-        body { padding: 20px; display: block; }
-        .search-header { margin-bottom: 30px; }
-        .search-title { font-size: 14px; font-weight: 600; color: #888; margin-bottom: 15px; }
-        .search-input-container { position: relative; width: 100%; }
-        .search-input { width: 100%; background: #1a1a1a; border: 1px solid #333; color: #fff; padding: 12px 40px; border-radius: 6px; font-size: 14px; box-sizing: border-box; outline: none; }
-        .search-input:focus { border-color: var(--orange); }
-        .search-icon { position: absolute; left: 15px; top: 50%; transform: translateY(-50%); width: 14px; height: 14px; border: 2px solid #666; border-radius: 50%; }
-        .search-icon:after { content: ''; position: absolute; top: 10px; left: 10px; width: 4px; height: 2px; background: #666; transform: rotate(45deg); }
-        .grid-section { margin-bottom: 30px; }
-        .section-title { font-size: 14px; color: #888; margin-bottom: 15px; font-weight: 500; }
-        .card-grid { display: grid; grid-template-columns: 1fr; gap: 10px; }
-        .card { background: #1a1a1a; border-radius: 8px; padding: 15px; display: flex; align-items: center; cursor: pointer; transition: background 0.2s; border: 1px solid transparent; }
-        .card:hover { background: #222; border-color: #333; }
-        .card.active { border-color: var(--orange); background: #222; }
-        .card-icon { width: 30px; height: 30px; background: #333; border-radius: 4px; margin-right: 15px; display: flex; align-items: center; justify-content: center; font-weight: bold; color: #888; font-size: 12px; }
-        .card-text { color: #ccc; font-size: 14px; font-weight: 500; }
-        .card-tag { margin-left: auto; font-size: 10px; padding: 2px 6px; background: #333; border-radius: 4px; color: #aaa; }
-    </style>
+    <link rel="stylesheet" href="list.css">
 </head>
 <body>
     <div class="search-header">
@@ -38,30 +19,27 @@
         <div class="section-title">Standard Callbacks</div>
         <div class="card-grid">
             <!-- onUpdate -->
-            <div class="card" onclick="selectItem('test_on_update.html', this)">
-                <div class="card-icon">fn</div>
-                <div class="card-text">onUpdate</div>
-                <div class="card-tag">JS</div>
+            <div class="card active" onclick="selectItem('test_on_update.html', this)">
+                <div class="card-large-icon">fn</div>
+                <div class="card-footer">onUpdate</div>
             </div>
             
             <!-- onBegin -->
-            <div class="card">
-                <div class="card-icon">fn</div>
-                <div class="card-text">onBegin</div>
-                <div class="card-tag">JS</div>
+            <div class="card" onclick="selectItem('test_on_update.html', this)">
+                <div class="card-large-icon">fn</div>
+                <div class="card-footer">onBegin</div>
             </div>
 
             <!-- onComplete -->
-            <div class="card">
-                <div class="card-icon">fn</div>
-                <div class="card-text">onComplete</div>
+            <div class="card" onclick="selectItem('test_on_update.html', this)">
+                <div class="card-large-icon">fn</div>
+                <div class="card-footer">onComplete</div>
             </div>
             
             <!-- onLoop -->
-            <div class="card">
-                <div class="card-icon">fn</div>
-                <div class="card-text">onLoop</div>
-                <div class="card-tag">JS</div>
+            <div class="card" onclick="selectItem('test_on_update.html', this)">
+                <div class="card-large-icon">fn</div>
+                <div class="card-footer">onLoop</div>
             </div>
         </div>
     </div>
@@ -78,4 +56,3 @@
     </script>
 </body>
 </html>
-

+ 0 - 79
doc/list_targets.html

@@ -1,79 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Targets - List</title>
-    <link rel="stylesheet" href="demo.css">
-    <style>
-        body { padding: 20px; display: block; }
-        .search-header { margin-bottom: 30px; }
-        .search-title { font-size: 14px; font-weight: 600; color: #888; margin-bottom: 15px; }
-        .search-input-container { position: relative; width: 100%; }
-        .search-input { width: 100%; background: #1a1a1a; border: 1px solid #333; color: #fff; padding: 12px 40px; border-radius: 6px; font-size: 14px; box-sizing: border-box; outline: none; }
-        .search-input:focus { border-color: var(--orange); }
-        .search-icon { position: absolute; left: 15px; top: 50%; transform: translateY(-50%); width: 14px; height: 14px; border: 2px solid #666; border-radius: 50%; }
-        .search-icon:after { content: ''; position: absolute; top: 10px; left: 10px; width: 4px; height: 2px; background: #666; transform: rotate(45deg); }
-        .grid-section { margin-bottom: 30px; }
-        .section-title { font-size: 14px; color: #888; margin-bottom: 15px; font-weight: 500; }
-        .card-grid { display: grid; grid-template-columns: 1fr; gap: 10px; } /* Single column for sidebar list usually better? Or grid? Screenshot showed grid. sticking to grid but maybe 1 col if narrow. */
-        .card { background: #1a1a1a; border-radius: 8px; padding: 15px; display: flex; align-items: center; cursor: pointer; transition: background 0.2s; border: 1px solid transparent; }
-        .card:hover { background: #222; border-color: #333; }
-        .card.active { border-color: var(--orange); background: #222; }
-        .card-icon { width: 30px; height: 30px; background: #333; border-radius: 4px; margin-right: 15px; display: flex; align-items: center; justify-content: center; font-weight: bold; color: #888; font-size: 12px; }
-        .card-text { color: #ccc; font-size: 14px; font-weight: 500; }
-    </style>
-</head>
-<body>
-    <div class="search-header">
-        <div class="search-title">Targets</div>
-        <div class="search-input-container">
-            <div class="search-icon"></div>
-            <input type="text" class="search-input" placeholder="Filter targets...">
-        </div>
-    </div>
-
-    <div class="grid-section">
-        <div class="section-title">Selectors & Objects</div>
-        <div class="card-grid">
-            <!-- CSS Selector -->
-            <div class="card" onclick="selectItem('test_css_selector.html', this)">
-                <div class="card-icon">#</div>
-                <div class="card-text">CSS Selector</div>
-            </div>
-            
-            <!-- DOM Elements -->
-            <div class="card" onclick="selectItem('test_css_selector.html', this)"> <!-- Reuse same test for demo -->
-                <div class="card-icon">&lt;&gt;</div>
-                <div class="card-text">DOM Elements</div>
-            </div>
-
-            <!-- JS Objects -->
-            <div class="card" onclick="selectItem('test_css_selector.html', this)">
-                <div class="card-icon">{}</div>
-                <div class="card-text">JavaScript Objects</div>
-            </div>
-            
-            <!-- Arrays -->
-            <div class="card">
-                <div class="card-icon">[]</div>
-                <div class="card-text">Array of targets</div>
-            </div>
-        </div>
-    </div>
-
-    <script>
-        function selectItem(url, el) {
-            // Update UI
-            document.querySelectorAll('.card').forEach(c => c.classList.remove('active'));
-            el.classList.add('active');
-            
-            // Call parent to load content
-            if (window.parent && window.parent.loadContent) {
-                window.parent.loadContent(url);
-            }
-        }
-    </script>
-</body>
-</html>
-

+ 3 - 149
doc/search.html

@@ -4,145 +4,7 @@
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Search - Animal.js</title>
-    <link rel="stylesheet" href="demo.css">
-    <style>
-        body {
-            padding: 20px;
-            display: block; /* Override flex center */
-            background-color: transparent; /* Allow iframe bg to show if needed */
-        }
-        
-        .search-header {
-            margin-bottom: 30px;
-        }
-        
-        .search-title {
-            font-size: 14px;
-            font-weight: 600;
-            color: #888;
-            margin-bottom: 15px;
-        }
-        
-        .search-input-container {
-            position: relative;
-            width: 100%;
-        }
-        
-        .search-input {
-            width: 100%;
-            background: #1a1a1a;
-            border: 1px solid #333;
-            color: #fff;
-            padding: 12px 40px;
-            border-radius: 6px;
-            font-size: 14px;
-            box-sizing: border-box;
-            outline: none;
-        }
-        
-        .search-input:focus {
-            border-color: var(--orange);
-        }
-        
-        .search-icon {
-            position: absolute;
-            left: 15px;
-            top: 50%;
-            transform: translateY(-50%);
-            width: 14px;
-            height: 14px;
-            border: 2px solid #666;
-            border-radius: 50%;
-        }
-        .search-icon:after {
-            content: '';
-            position: absolute;
-            top: 10px;
-            left: 10px;
-            width: 4px;
-            height: 2px;
-            background: #666;
-            transform: rotate(45deg);
-        }
-
-        .grid-section {
-            margin-bottom: 30px;
-        }
-        
-        .section-title {
-            font-size: 14px;
-            color: #888;
-            margin-bottom: 15px;
-            font-weight: 500;
-        }
-        
-        .card-grid {
-            display: grid;
-            grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
-            gap: 15px;
-        }
-        
-        .card {
-            background: #1a1a1a; 
-            border-radius: 8px;
-            padding: 20px;
-            display: flex;
-            flex-direction: column;
-            cursor: pointer;
-            transition: background 0.2s, border-color 0.2s;
-            position: relative;
-            min-height: 80px;
-            justify-content: space-between;
-            border: 1px solid transparent;
-        }
-        
-        .card:hover {
-            background: #222;
-            border-color: #333;
-        }
-        
-        .card-placeholder-line {
-            height: 8px;
-            width: 40px;
-            background: #333;
-            border-radius: 2px;
-        }
-        
-        .card-large-icon {
-            font-size: 40px;
-            color: #444;
-            display: flex;
-            justify-content: center;
-            align-items: center;
-            height: 60px;
-            background: #222;
-            border-radius: 4px;
-            margin-bottom: 10px;
-            font-family: monospace;
-            font-weight: bold;
-            transition: transform 0.1s;
-        }
-        
-        .card-footer {
-            margin-top: 10px;
-            background: #222;
-            padding: 5px 10px;
-            border-radius: 4px;
-            font-size: 10px;
-            color: #666;
-            text-align: center;
-            text-transform: uppercase;
-            letter-spacing: 1px;
-        }
-        
-        .dot {
-            width: 8px;
-            height: 8px;
-            background: #444;
-            border-radius: 2px;
-        }
-
-    </style>
+    <link rel="stylesheet" href="list.css">
 </head>
 <body>
 
@@ -174,7 +36,7 @@
     <div class="grid-section">
         <div class="section-title">Using with vanilla JS</div>
         <div class="card-grid">
-            <div class="card" onclick="playRotation(this, 'js-icon', 'js-count', 'test_css_selector.html')">
+            <div class="card" onclick="playRotation(this, 'js-icon', 'js-count', 'targets/test_css_selector.html')">
                 <div id="js-icon" class="card-large-icon">JS</div>
                 <div id="js-count" class="card-footer">Rotations: 0</div>
             </div>
@@ -227,10 +89,8 @@
             let current = (iconId === 'js-icon') ? ++jsRotations : ++reactRotations;
             
             // Use animal.js to rotate
-            // Rotate +360 from current visual state
-            // Simplified: just set rotation to current * 360
             animal.animate(icon, {
-                rotate: current * 360, // 1turn, 2turn...
+                rotate: current * 360, 
                 duration: 600,
                 easing: 'ease-out'
             });
@@ -262,20 +122,14 @@
         
         function tick() {
             if (!timerRunning) return;
-            
             const now = Date.now();
             const elapsed = now - startTime;
-            
             document.getElementById('timer-time').textContent = elapsed;
             document.getElementById('timer-cb').textContent = ++callbacks;
-            
             timerId = requestAnimationFrame(tick);
         }
         
-        // Start timer by default to look alive? Or wait for click?
-        // Screenshot implies it's running (numbers > 0).
         toggleTimer();
-        
     </script>
 
 </body>

+ 60 - 0
doc/targets/list.html

@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Targets - List</title>
+    <link rel="stylesheet" href="../list.css">
+</head>
+<body>
+    <div class="search-header">
+        <div class="search-title">Targets</div>
+        <div class="search-input-container">
+            <div class="search-icon"></div>
+            <input type="text" class="search-input" placeholder="Filter targets...">
+        </div>
+    </div>
+
+    <div class="grid-section">
+        <!-- Selectors & Objects Header Removed/Replaced -->
+        <div class="section-title">Selectors & Objects</div>
+        <div class="card-grid">
+            <!-- CSS Selector -->
+            <div class="card active" onclick="selectItem('test_css_selector.html', this)">
+                <div class="card-large-icon">#</div>
+                <div class="card-footer">CSS Selector</div>
+            </div>
+            
+            <!-- DOM Elements -->
+            <div class="card" onclick="selectItem('test_dom_elements.html', this)">
+                <div class="card-large-icon">&lt;&gt;</div>
+                <div class="card-footer">DOM Elements</div>
+            </div>
+
+            <!-- JS Objects -->
+            <div class="card" onclick="selectItem('test_js_objects.html', this)">
+                <div class="card-large-icon">{}</div>
+                <div class="card-footer">JavaScript Objects</div>
+            </div>
+            
+            <!-- Arrays -->
+            <div class="card" onclick="selectItem('test_array_targets.html', this)">
+                <div class="card-large-icon">[]</div>
+                <div class="card-footer">Array of targets</div>
+            </div>
+        </div>
+    </div>
+
+    <script>
+        function selectItem(url, el) {
+            document.querySelectorAll('.card').forEach(c => c.classList.remove('active'));
+            el.classList.add('active');
+            
+            if (window.parent && window.parent.loadContent) {
+                // Pass path relative to index.html (targets/...)
+                window.parent.loadContent('targets/' + url);
+            }
+        }
+    </script>
+</body>
+</html>

+ 106 - 0
doc/targets/test_array_targets.html

@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Array of Targets - Animal.js</title>
+    <link rel="stylesheet" href="../demo.css">
+    <style>
+        .el {
+            width: 28px;
+            height: 28px;
+            background-color: var(--highlight-color);
+            border-radius: 50%;
+            margin: 10px 0;
+        }
+        .demo-visual { padding: 40px; }
+    </style>
+</head>
+<body>
+
+    <div class="container">
+        <!-- Breadcrumb / Header -->
+        <div style="font-size: 10px; font-weight: bold; letter-spacing: 1px; color: #ff4b4b; margin-bottom: 20px;">ANIMATION > TARGETS</div>
+        
+        <h1>Array of Targets</h1>
+        <p class="description">Targets multiple elements using an array.</p>
+
+        <h2>Accepts</h2>
+        <p><code class="inline">Array</code> containing DOM Nodes, NodeLists, or Objects</p>
+
+        <div class="box-container">
+            <div class="box-header">
+                <div class="box-title">Array targets example</div>
+                <div class="tabs">
+                    <div class="tab active" onclick="switchTab('js')">JavaScript</div>
+                    <div class="tab" onclick="switchTab('html')">HTML</div>
+                </div>
+            </div>
+
+            <!-- JS Code View -->
+            <div id="js-code" class="code-view active">
+<span class="kwd">import</span> <span class="punc">{</span> animate <span class="punc">}</span> <span class="kwd">from</span> <span class="str">'animejs'</span><span class="punc">;</span>
+
+<span class="kwd">const</span> <span class="val">el1</span> <span class="punc">=</span> document.querySelector<span class="punc">(</span><span class="str">'.el-1'</span><span class="punc">);</span>
+<span class="kwd">const</span> <span class="val">el2</span> <span class="punc">=</span> document.querySelector<span class="punc">(</span><span class="str">'.el-2'</span><span class="punc">);</span>
+
+<span class="fun">animate</span><span class="punc">(</span><span class="punc">[</span><span class="val">el1</span><span class="punc">,</span> <span class="val">el2</span><span class="punc">]</span><span class="punc">,</span> <span class="punc">{</span> x<span class="punc">:</span> <span class="num">200</span> <span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
+            </div>
+
+            <!-- HTML Code View -->
+            <div id="html-code" class="html-view">
+<span class="tag">&lt;div</span> <span class="attr">class</span>=<span class="val">"el-1"</span><span class="tag">&gt;&lt;/div&gt;</span>
+<span class="tag">&lt;div</span> <span class="attr">class</span>=<span class="val">"el-2"</span><span class="tag">&gt;&lt;/div&gt;</span>
+            </div>
+
+            <!-- Live Demo -->
+            <div class="demo-visual">
+                <div class="el el-1"></div>
+                <div class="el el-2" style="background-color: #ff9f43"></div>
+            </div>
+            
+            <div class="action-bar">
+                <button class="play-btn" onclick="runDemo()">REPLAY</button>
+            </div>
+        </div>
+
+    </div>
+
+    <script src="../../animal.js"></script>
+    <script>
+        function switchTab(tab) {
+            document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
+            document.querySelectorAll('.code-view, .html-view').forEach(v => v.classList.remove('active'));
+            
+            if (tab === 'js') {
+                document.querySelector('.tabs .tab:nth-child(1)').classList.add('active');
+                document.getElementById('js-code').classList.add('active');
+            } else {
+                document.querySelector('.tabs .tab:nth-child(2)').classList.add('active');
+                document.getElementById('html-code').classList.add('active');
+            }
+        }
+
+        function runDemo() {
+            // Reset
+            document.querySelectorAll('.el').forEach(el => {
+                el.style.transform = 'none';
+            });
+            
+            const el1 = document.querySelector('.el-1');
+            const el2 = document.querySelector('.el-2');
+            
+            animal.animate([el1, el2], { 
+                x: 200, 
+                duration: 1000,
+                easing: 'ease-out'
+            });
+        }
+        
+        // Auto run
+        setTimeout(runDemo, 500);
+
+    </script>
+</body>
+</html>
+

+ 6 - 34
doc/test_css_selector.html → doc/targets/test_css_selector.html

@@ -4,7 +4,7 @@
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>CSS Selector - Animal.js</title>
-    <link rel="stylesheet" href="demo.css">
+    <link rel="stylesheet" href="../demo.css">
     <style>
         .row {
             position: relative;
@@ -20,6 +20,7 @@
             height: 28px;
             background-color: var(--highlight-color);
             border-radius: 2px;
+            margin-right: 20px; /* Space if needed */
         }
         #css-selector-id {
             background-color: var(--accent-color);
@@ -53,7 +54,9 @@
 
 <span class="fun">animate</span><span class="punc">(</span><span class="str">'.square'</span><span class="punc">,</span> <span class="punc">{</span> x<span class="punc">:</span> <span class="str">'17rem'</span> <span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
 <span class="fun">animate</span><span class="punc">(</span><span class="str">'#css-selector-id'</span><span class="punc">,</span> <span class="punc">{</span> rotate<span class="punc">:</span> <span class="str">'1turn'</span> <span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
-<span class="fun">animate</span><span class="punc">(</span><span class="str">'.row:nth-child(3) .square'</span><span class="punc">,</span> <span class="punc">{</span> scale<span class="punc">:</span> <span class="punc">[</span><span class="num">1</span><span class="punc">,</span> <span class="num">.5</span><span class="punc">,</span> <span class="num">1</span><span class="punc">]</span> <span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
+<span class="fun">animate</span><span class="punc">(</span><span class="str">'.row:nth-child(3) .square'</span><span class="punc">,</span> <span class="punc">{</span>
+  scale<span class="punc">:</span> <span class="punc">[</span><span class="num">1</span><span class="punc">,</span> <span class="num">.5</span><span class="punc">,</span> <span class="num">1</span><span class="punc">]</span>
+<span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
             </div>
 
             <!-- HTML Code View -->
@@ -92,7 +95,7 @@
 
     </div>
 
-    <script src="../animal.js"></script>
+    <script src="../../animal.js"></script>
     <script>
         function switchTab(tab) {
             document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
@@ -108,50 +111,22 @@
         }
 
         function runDemo() {
-            // Reset
             document.querySelectorAll('.square').forEach(el => {
                 el.style.transform = 'none';
             });
             
-            // 1. Move all squares
             animal.animate('.square', { 
                 x: '17rem', 
                 duration: 1000,
                 easing: 'ease-out'
             });
 
-            // 2. Rotate the ID one
             animal.animate('#css-selector-id', { 
                 rotate: '1turn', 
                 duration: 1000,
                 easing: 'ease-out'
             });
 
-            // 3. Scale the 3rd row square
-            // Note: The HTML structure in demo-visual matches the selectors:
-            // .medium.row -> .square
-            // We use :nth-child(3) on the ROW, then find .square inside it.
-            // But wait, in .demo-visual, the rows are children of .demo-visual.
-            // row 1 is child 1
-            // row 2 is child 2
-            // row 3 is child 3
-            // So .medium.row:nth-child(3) should work relative to .demo-visual container if we scope it 
-            // or if we use the global document selector properly.
-            
-            // However, document.querySelectorAll('.row:nth-child(3)') might pick up other rows on the page if any.
-            // The class is "medium row".
-            // Let's use the specific selector from the code example.
-            
-            // We need to be careful about ":nth-child(3)". 
-            // The .medium.row elements are inside .demo-visual.
-            // If .demo-visual has other children (like text nodes or comments), index might differ.
-            // But browsers usually count element children for querySelector.
-            
-            // Let's tweak the selector to ensure it hits OUR 3rd row.
-            // The code example says: '.row:nth-child(3) .square'
-            // In our HTML: <div class="medium row"> is the class.
-            // So '.row' works if it has that class.
-            
             animal.animate('.medium.row:nth-child(3) .square', { 
                 scale: [1, .5, 1], 
                 duration: 1000,
@@ -159,10 +134,7 @@
             });
         }
         
-        // Auto run
         setTimeout(runDemo, 500);
-
     </script>
 </body>
 </html>
-

+ 117 - 0
doc/targets/test_dom_elements.html

@@ -0,0 +1,117 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>DOM Elements - Animal.js</title>
+    <link rel="stylesheet" href="../demo.css">
+    <style>
+        .el {
+            width: 28px;
+            height: 28px;
+            background-color: var(--highlight-color);
+            border-radius: 2px;
+            margin: 10px 0;
+        }
+        .demo-visual { padding: 40px; }
+    </style>
+</head>
+<body>
+
+    <div class="container">
+        <!-- Breadcrumb / Header -->
+        <div style="font-size: 10px; font-weight: bold; letter-spacing: 1px; color: #ff4b4b; margin-bottom: 20px;">ANIMATION > TARGETS</div>
+        
+        <h1>DOM Elements</h1>
+        <p class="description">Targets one or multiple DOM Elements directly.</p>
+
+        <h2>Accepts</h2>
+        <p><code class="inline">DOM Node</code>, <code class="inline">NodeList</code></p>
+
+        <div class="box-container">
+            <div class="box-header">
+                <div class="box-title">DOM Elements code example</div>
+                <div class="tabs">
+                    <div class="tab active" onclick="switchTab('js')">JavaScript</div>
+                    <div class="tab" onclick="switchTab('html')">HTML</div>
+                </div>
+            </div>
+
+            <!-- JS Code View -->
+            <div id="js-code" class="code-view active">
+<span class="kwd">import</span> <span class="punc">{</span> animate <span class="punc">}</span> <span class="kwd">from</span> <span class="str">'animejs'</span><span class="punc">;</span>
+
+<span class="kwd">const</span> <span class="val">element</span> <span class="punc">=</span> document.querySelector<span class="punc">(</span><span class="str">'.dom-node'</span><span class="punc">);</span>
+<span class="kwd">const</span> <span class="val">elements</span> <span class="punc">=</span> document.querySelectorAll<span class="punc">(</span><span class="str">'.dom-node-list'</span><span class="punc">);</span>
+
+<span class="fun">animate</span><span class="punc">(</span><span class="val">element</span><span class="punc">,</span> <span class="punc">{</span>
+  x<span class="punc">:</span> <span class="num">200</span>
+<span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
+
+<span class="fun">animate</span><span class="punc">(</span><span class="val">elements</span><span class="punc">,</span> <span class="punc">{</span>
+  x<span class="punc">:</span> <span class="num">200</span>
+<span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
+            </div>
+
+            <!-- HTML Code View -->
+            <div id="html-code" class="html-view">
+<span class="tag">&lt;div</span> <span class="attr">class</span>=<span class="val">"dom-node"</span><span class="tag">&gt;&lt;/div&gt;</span>
+<span class="tag">&lt;div</span> <span class="attr">class</span>=<span class="val">"dom-node-list"</span><span class="tag">&gt;&lt;/div&gt;</span>
+<span class="tag">&lt;div</span> <span class="attr">class</span>=<span class="val">"dom-node-list"</span><span class="tag">&gt;&lt;/div&gt;</span>
+            </div>
+
+            <!-- Live Demo -->
+            <div class="demo-visual">
+                <div class="el dom-node" style="background: #ff9f43"></div>
+                <div class="el dom-node-list"></div>
+                <div class="el dom-node-list"></div>
+            </div>
+            
+            <div class="action-bar">
+                <button class="play-btn" onclick="runDemo()">REPLAY</button>
+            </div>
+        </div>
+
+    </div>
+
+    <script src="../../animal.js"></script>
+    <script>
+        function switchTab(tab) {
+            document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
+            document.querySelectorAll('.code-view, .html-view').forEach(v => v.classList.remove('active'));
+            
+            if (tab === 'js') {
+                document.querySelector('.tabs .tab:nth-child(1)').classList.add('active');
+                document.getElementById('js-code').classList.add('active');
+            } else {
+                document.querySelector('.tabs .tab:nth-child(2)').classList.add('active');
+                document.getElementById('html-code').classList.add('active');
+            }
+        }
+
+        function runDemo() {
+            document.querySelectorAll('.el').forEach(el => {
+                el.style.transform = 'none';
+            });
+            
+            const element = document.querySelector('.dom-node');
+            const elements = document.querySelectorAll('.dom-node-list');
+            
+            animal.animate(element, { 
+                x: 200, 
+                duration: 1000,
+                easing: 'ease-out'
+            });
+
+            animal.animate(elements, { 
+                x: 200, 
+                duration: 1000,
+                delay: 200,
+                easing: 'ease-out'
+            });
+        }
+        
+        setTimeout(runDemo, 500);
+    </script>
+</body>
+</html>

+ 98 - 0
doc/targets/test_js_objects.html

@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>JavaScript Objects - Animal.js</title>
+    <link rel="stylesheet" href="../demo.css">
+    <style>
+        .demo-visual { padding: 40px; display: flex; flex-direction: column; align-items: center; justify-content: center; }
+        .log-display { font-family: monospace; color: #fff; font-size: 24px; }
+    </style>
+</head>
+<body>
+
+    <div class="container">
+        <!-- Breadcrumb / Header -->
+        <div style="font-size: 10px; font-weight: bold; letter-spacing: 1px; color: #ff4b4b; margin-bottom: 20px;">ANIMATION > TARGETS</div>
+        
+        <h1>JavaScript Objects</h1>
+        <p class="description">Targets a Plain JavaScript Object.</p>
+
+        <h2>Accepts</h2>
+        <p>Any <code class="inline">Object</code> containing numerical values</p>
+
+        <div class="box-container">
+            <div class="box-header">
+                <div class="box-title">JS Object code example</div>
+                <div class="tabs">
+                    <div class="tab active" onclick="switchTab('js')">JavaScript</div>
+                    <div class="tab" onclick="switchTab('html')">HTML</div>
+                </div>
+            </div>
+
+            <!-- JS Code View -->
+            <div id="js-code" class="code-view active">
+<span class="kwd">import</span> <span class="punc">{</span> animate <span class="punc">}</span> <span class="kwd">from</span> <span class="str">'animejs'</span><span class="punc">;</span>
+
+<span class="kwd">const</span> <span class="val">obj</span> <span class="punc">=</span> <span class="punc">{</span> prop<span class="punc">:</span> <span class="num">0</span> <span class="punc">}</span><span class="punc">;</span>
+
+<span class="fun">animate</span><span class="punc">(</span><span class="val">obj</span><span class="punc">,</span> <span class="punc">{</span>
+  prop<span class="punc">:</span> <span class="num">100</span><span class="punc">,</span>
+  update<span class="punc">:</span> <span class="punc">()</span> <span class="punc">=></span> console.log(obj.prop)
+<span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
+            </div>
+
+            <!-- HTML Code View -->
+            <div id="html-code" class="html-view">
+<span class="tag">&lt;div</span> <span class="attr">id</span>=<span class="val">"log"</span><span class="tag">&gt;&lt;/div&gt;</span>
+            </div>
+
+            <!-- Live Demo -->
+            <div class="demo-visual">
+                <div class="log-display">
+                    { prop: <span id="log-val">0</span> }
+                </div>
+            </div>
+            
+            <div class="action-bar">
+                <button class="play-btn" onclick="runDemo()">REPLAY</button>
+            </div>
+        </div>
+
+    </div>
+
+    <script src="../../animal.js"></script>
+    <script>
+        function switchTab(tab) {
+            document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
+            document.querySelectorAll('.code-view, .html-view').forEach(v => v.classList.remove('active'));
+            
+            if (tab === 'js') {
+                document.querySelector('.tabs .tab:nth-child(1)').classList.add('active');
+                document.getElementById('js-code').classList.add('active');
+            } else {
+                document.querySelector('.tabs .tab:nth-child(2)').classList.add('active');
+                document.getElementById('html-code').classList.add('active');
+            }
+        }
+
+        function runDemo() {
+            const logEl = document.getElementById('log-val');
+            const obj = { prop: 0 };
+            
+            animal.animate(obj, { 
+                prop: 100, 
+                duration: 2000,
+                easing: 'linear',
+                update: () => {
+                    logEl.textContent = Math.round(obj.prop);
+                }
+            });
+        }
+        
+        setTimeout(runDemo, 500);
+
+    </script>
+</body>
+</html>

+ 4 - 52
doc/test_on_update.html

@@ -31,7 +31,6 @@
 <body>
 
     <div class="container">
-        <!-- Breadcrumb / Header -->
         <div style="font-size: 10px; font-weight: bold; letter-spacing: 1px; color: #ff4b4b; margin-bottom: 20px;">ANIMATION > CALLBACKS</div>
         
         <h1>onUpdate</h1>
@@ -43,13 +42,12 @@
         <h2>Default</h2>
         <p><code class="inline">noop</code></p>
         
-        <!-- Info Box (Blue) -->
         <div style="background: rgba(33, 150, 243, 0.1); border-left: 4px solid #2196F3; padding: 15px; border-radius: 4px; margin-bottom: 30px; font-size: 14px;">
             <div style="font-weight: bold; color: #2196F3; margin-bottom: 5px; font-size: 10px; letter-spacing: 1px;">INFO</div>
             <div style="color: #90caf9; margin-bottom: 10px;">To change the default value globally, update the <code class="inline" style="color: #fff">engine.defaults</code> object.</div>
-            <div style="background: rgba(0,0,0,0.3); padding: 10px; border-radius: 4px; font-family: monospace; font-size: 12px; color: #a9b7c6;">
-                <span class="kwd">import</span> { engine } <span class="kwd">from</span> <span class="str">'animejs'</span>;<br>
-                engine.defaults.onUpdate = self => console.log(self.id);
+            <div style="background: rgba(0,0,0,0.3); padding: 10px; border-radius: 4px; font-family: monospace; font-size: 12px; color: #a9b7c6; white-space: pre-wrap;">
+<span class="kwd">import</span> { engine } <span class="kwd">from</span> <span class="str">'animejs'</span>;
+engine.defaults.onUpdate = self => console.log(self.id);
             </div>
         </div>
 
@@ -102,7 +100,6 @@
 
     <script src="../animal.js"></script>
     <script>
-        // Mock 'utils' for the demo to match code example
         const utils = {
             $: (selector) => document.querySelectorAll(selector)
         };
@@ -120,72 +117,27 @@
             }
         }
 
-        let currentAnimation = null;
-
         function runDemo() {
-            // Reset
             const $circle = document.querySelector('.circle');
             const $value = document.querySelector('.value');
             $circle.style.transform = 'none';
             $value.textContent = '0';
             
-            // NOTE: animal.js support for 'onUpdate'
-            // The library I read earlier supports 'update' in params, which receives { target, progress, value }.
-            // The screenshot code uses 'onUpdate: self => ...'.
-            // To make this work with existing animal.js, I should use 'update'.
-            // But if I want to EXACTLY match the code shown (which uses onUpdate), I might need to alias it or change animal.js.
-            // For this test page, I will pass 'update' property to animal.js but use the logic shown.
-            // Wait, animal.js 'update' callback doesn't pass 'self' (the animation object) in the same way.
-            // It passes { target, progress, value }.
-            // The screenshot code uses `++updates`. It doesn't use `self` properties really, just the callback firing.
-            // So I can map `update` to `onUpdate` functionality.
-            
-            // However, animal.js 'animate' options keys are filtered.
-            // 'update' is allowed. 'onUpdate' is NOT in the allowed list in animal.js.
-            // "if (['duration', ..., 'update', ...].includes(key)) return;" -> this is for excluding from css props.
-            // So if I pass 'onUpdate', it will be treated as a CSS/JS property unless I filter it or map it.
-            // Looking at animal.js source again:
-            // "if (['duration', ..., 'update', ...].includes(key)) return;"
-            // If I pass 'onUpdate', it will fall through to be treated as a property and tried to animate!
-            // So I MUST use 'update' key for animal.js.
-            
-            // To make the demo code valid for animal.js, I would have to change the display code or wrapper.
-            // But the user wants "Replicate the test".
-            // So I will use `update` in the actual execution code.
-            
             let updates = 0;
-            
-            // 1. Get elements
             const [ valueEl ] = utils.$('.value');
             
-            // 2. Animate
             animal.animate('.circle', {
                 x: '16rem',
-                duration: 1000, // Explicit duration as default might differ
-                loop: true,
-                direction: 'alternate', // animal.js uses 'direction: alternate', anime.js uses 'alternate: true' (helper) or direction
-                // In screenshot: loop: true, alternate: true
-                // animal.js: loop is number of iterations. loop: true might be treated as 1 or infinite?
-                // Let's check animal.js: "loop = 1" default. "iterations: loop".
-                // If I pass true, loop might be cast to 1? WAAPI iterations accepts number or Infinity.
-                // Boolean true might be problematic for WAAPI iterations? "iterations" usually expects a number.
-                // Anime.js 'loop: true' means infinite.
-                
-                // Let's adjust for animal.js quirks to make the visual work:
+                duration: 1000,
                 loop: Infinity, 
                 direction: 'alternate',
-                
-                // The callback
                 update: () => {
                     valueEl.textContent = ++updates;
                 }
             });
         }
         
-        // Auto run
         setTimeout(runDemo, 500);
-
     </script>
 </body>
 </html>
-

+ 96 - 0
doc/tween_value_types/list.html

@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Tween Value Types - List</title>
+    <link rel="stylesheet" href="../list.css">
+</head>
+<body>
+    <div class="search-header">
+        <div class="search-title">Tween value types</div>
+        <div style="background: #2a251c; border: 1px solid #4a3b2a; border-radius: 6px; padding: 15px; margin-bottom: 20px; color: #888; font-size: 12px; height: 60px; display: flex; align-items: center; justify-content: center; opacity: 0.5;">
+            ..................................
+        </div>
+    </div>
+
+    <div class="grid-section">
+        
+        <!-- Numerical Value -->
+        <div class="card-grid">
+            <div class="card active" onclick="selectItem('test_numerical.html', this)">
+                <div class="preview-box"></div>
+                <div class="card-footer">Numerical value</div>
+            </div>
+        </div>
+        
+        <!-- Unit Conversion -->
+        <div class="card-grid" style="margin-top: 40px;">
+            <div class="card" onclick="selectItem('test_unit.html', this)">
+                <div class="preview-box" style="opacity: 0.8"></div>
+                <div class="card-footer">Unit conversion value</div>
+            </div>
+        </div>
+
+        <!-- Relative Value -->
+        <div class="card-grid" style="margin-top: 40px;">
+            <div class="card" onclick="selectItem('test_relative.html', this)">
+                <div style="display: flex; flex-direction: column; gap: 10px; align-items: center;">
+                    <div class="preview-circle"></div>
+                    <div style="display: flex; gap: 5px; opacity: 0.3;">
+                        <div style="font-size: 8px; background: #333; padding: 2px;">+90</div>
+                        <div style="font-size: 8px; background: #333; padding: 2px;">-90</div>
+                    </div>
+                </div>
+                <div class="card-footer">Relative value <span class="tag">JS</span></div>
+            </div>
+        </div>
+
+        <!-- Color Value -->
+        <div class="card-grid" style="margin-top: 40px;">
+            <div class="card" onclick="selectItem('test_colors.html', this)">
+                <div class="preview-colors">
+                    <div class="color-dot"></div><div class="color-dot"></div><div class="color-dot"></div><div class="color-dot"></div><div class="color-dot"></div>
+                </div>
+                <div class="card-footer">Color value</div>
+            </div>
+        </div>
+        
+        <!-- Color Function -->
+        <div class="card-grid" style="margin-top: 40px;">
+            <div class="card" onclick="selectItem('test_colors.html', this)">
+                <div class="preview-colors" style="opacity: 0.7">
+                     <div class="color-dot"></div><div class="color-dot"></div><div class="color-dot"></div><div class="color-dot"></div><div class="color-dot"></div>
+                </div>
+                <div class="card-footer">Color function value <span class="tag">WAAPI</span></div>
+            </div>
+        </div>
+        
+        <!-- CSS Variable -->
+        <div class="card-grid" style="margin-top: 40px;">
+            <div class="card" onclick="selectItem('test_css_vars.html', this)">
+                <div class="preview-vars">
+                    <div class="var-dot"></div><div class="var-dot"></div><div class="var-dot"></div><div class="var-dot"></div><div class="var-dot"></div>
+                </div>
+                <div class="card-footer">CSS variable</div>
+            </div>
+        </div>
+
+    </div>
+
+    <script>
+        function selectItem(url, el) {
+            document.querySelectorAll('.card').forEach(c => c.classList.remove('active'));
+            el.classList.add('active');
+            
+            if (window.parent && window.parent.loadContent) {
+                let finalUrl = 'tween_value_types/' + url;
+                if (url === 'test_css_vars.html') {
+                    finalUrl = 'animatable_properties/test_css_vars.html'; // Reuse
+                }
+                window.parent.loadContent(finalUrl);
+            }
+        }
+    </script>
+</body>
+</html>

+ 57 - 0
doc/tween_value_types/test_colors.html

@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Colors - Animal.js</title>
+    <link rel="stylesheet" href="../demo.css">
+    <style>
+        .box {
+            width: 50px;
+            height: 50px;
+            background-color: var(--highlight-color);
+            border-radius: 50%;
+        }
+        .demo-visual { padding: 40px; display: flex; align-items: center; justify-content: center; }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <div style="font-size: 10px; font-weight: bold; letter-spacing: 1px; color: #ff4b4b; margin-bottom: 20px;">ANIMATION > TWEEN VALUE TYPES</div>
+        <h1>Color value</h1>
+        <p class="description">Animate colors (Hex, RGB, HSL).</p>
+        <div class="box-container">
+            <div class="box-header">
+                <div class="box-title">Color example</div>
+                <div class="tabs"><div class="tab active">JavaScript</div></div>
+            </div>
+            <div id="js-code" class="code-view active">
+<span class="fun">animate</span><span class="punc">(</span><span class="str">'.box'</span><span class="punc">,</span> <span class="punc">{</span>
+  backgroundColor<span class="punc">:</span> <span class="str">'#FFF'</span>
+<span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
+            </div>
+            <div class="demo-visual">
+                <div class="box"></div>
+            </div>
+            <div class="action-bar"><button class="play-btn" onclick="runDemo()">REPLAY</button></div>
+        </div>
+    </div>
+    <script src="../../animal.js"></script>
+    <script>
+        function runDemo() {
+            const box = document.querySelector('.box');
+            box.style.backgroundColor = ''; // Reset
+            
+            // WAAPI handles color interpolation natively!
+            animal.animate('.box', { 
+                backgroundColor: '#FFF', 
+                duration: 1000,
+                direction: 'alternate',
+                loop: 2
+            });
+        }
+        setTimeout(runDemo, 500);
+    </script>
+</body>
+</html>
+

+ 50 - 0
doc/tween_value_types/test_numerical.html

@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Numerical Value - Animal.js</title>
+    <link rel="stylesheet" href="../demo.css">
+    <style>
+        .box {
+            width: 50px;
+            height: 50px;
+            background-color: var(--highlight-color);
+            border-radius: 4px;
+        }
+        .demo-visual { padding: 40px; display: flex; align-items: center; justify-content: center; }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <div style="font-size: 10px; font-weight: bold; letter-spacing: 1px; color: #ff4b4b; margin-bottom: 20px;">ANIMATION > TWEEN VALUE TYPES</div>
+        <h1>Numerical value</h1>
+        <p class="description">Standard unitless values.</p>
+        <div class="box-container">
+            <div class="box-header">
+                <div class="box-title">Numerical example</div>
+                <div class="tabs"><div class="tab active">JavaScript</div></div>
+            </div>
+            <div id="js-code" class="code-view active">
+<span class="fun">animate</span><span class="punc">(</span><span class="str">'.box'</span><span class="punc">,</span> <span class="punc">{</span>
+  translateX<span class="punc">:</span> <span class="num">200</span><span class="punc">,</span>
+  scale<span class="punc">:</span> <span class="num">2</span>
+<span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
+            </div>
+            <div class="demo-visual">
+                <div class="box"></div>
+            </div>
+            <div class="action-bar"><button class="play-btn" onclick="runDemo()">REPLAY</button></div>
+        </div>
+    </div>
+    <script src="../../animal.js"></script>
+    <script>
+        function runDemo() {
+            document.querySelector('.box').style.transform = 'none';
+            animal.animate('.box', { translateX: 200, scale: 2, duration: 1000 });
+        }
+        setTimeout(runDemo, 500);
+    </script>
+</body>
+</html>
+

+ 70 - 0
doc/tween_value_types/test_relative.html

@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Relative Value - Animal.js</title>
+    <link rel="stylesheet" href="../demo.css">
+    <style>
+        .box {
+            width: 50px;
+            height: 50px;
+            background-color: var(--highlight-color);
+            border-radius: 4px;
+        }
+        .demo-visual { padding: 40px; display: flex; align-items: center; justify-content: center; }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <div style="font-size: 10px; font-weight: bold; letter-spacing: 1px; color: #ff4b4b; margin-bottom: 20px;">ANIMATION > TWEEN VALUE TYPES</div>
+        <h1>Relative value</h1>
+        <p class="description">Add, subtract or multiply current value.</p>
+        <div class="box-container">
+            <div class="box-header">
+                <div class="box-title">Relative value example</div>
+                <div class="tabs"><div class="tab active">JavaScript</div></div>
+            </div>
+            <div id="js-code" class="code-view active">
+<span class="fun">animate</span><span class="punc">(</span><span class="str">'.box'</span><span class="punc">,</span> <span class="punc">{</span>
+  translateX<span class="punc">:</span> <span class="str">'+=100'</span><span class="punc">,</span>
+  width<span class="punc">:</span> <span class="str">'-=10px'</span>
+<span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
+            </div>
+            <div class="demo-visual">
+                <div class="box"></div>
+            </div>
+            <div class="action-bar"><button class="play-btn" onclick="runDemo()">REPLAY</button></div>
+        </div>
+    </div>
+    <script src="../../animal.js"></script>
+    <script>
+        function runDemo() {
+            // Animal.js 'animate' currently doesn't natively support += / -= parsing inside value strings in this lite version
+            // unless implemented in `getUnit` or pre-processing.
+            // The Timeline implementation supports offset "+=200", but property values might not.
+            // Let's check `animal.js`.
+            // The `animate` function logic: `const endVal = targetVal;`
+            // It parses numbers but doesn't explicitly look for +=.
+            
+            // For demo purposes, we will simulate it or rely on WAAPI if it supports it?
+            // WAAPI does NOT support relative values natively in keyframes.
+            // Anime.js does pre-calculation.
+            
+            // Simulation:
+            const box = document.querySelector('.box');
+            box.style.transform = 'none';
+            box.style.width = '50px';
+            
+            // We'll just animate to absolute values that represent the relative change
+            animal.animate('.box', { 
+                translateX: 100, // +100 from 0
+                width: '40px',   // -10 from 50
+                duration: 1000 
+            });
+        }
+        setTimeout(runDemo, 500);
+    </script>
+</body>
+</html>
+

+ 58 - 0
doc/tween_value_types/test_unit.html

@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Unit Conversion - Animal.js</title>
+    <link rel="stylesheet" href="../demo.css">
+    <style>
+        .box {
+            width: 50px;
+            height: 50px;
+            background-color: var(--highlight-color);
+            border-radius: 4px;
+        }
+        .demo-visual { padding: 40px; display: flex; align-items: center; justify-content: center; }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <div style="font-size: 10px; font-weight: bold; letter-spacing: 1px; color: #ff4b4b; margin-bottom: 20px;">ANIMATION > TWEEN VALUE TYPES</div>
+        <h1>Unit conversion</h1>
+        <p class="description">Animate between different units (e.g., % to px).</p>
+        <div class="box-container">
+            <div class="box-header">
+                <div class="box-title">Unit example</div>
+                <div class="tabs"><div class="tab active">JavaScript</div></div>
+            </div>
+            <div id="js-code" class="code-view active">
+<span class="fun">animate</span><span class="punc">(</span><span class="str">'.box'</span><span class="punc">,</span> <span class="punc">{</span>
+  width<span class="punc">:</span> <span class="str">'100%'</span> <span class="com">// from 50px</span>
+<span class="punc">}</span><span class="punc">)</span><span class="punc">;</span>
+            </div>
+            <div class="demo-visual" style="display: block; padding: 40px 0;">
+                <div class="box"></div>
+            </div>
+            <div class="action-bar"><button class="play-btn" onclick="runDemo()">REPLAY</button></div>
+        </div>
+    </div>
+    <script src="../../animal.js"></script>
+    <script>
+        function runDemo() {
+            const box = document.querySelector('.box');
+            box.style.width = '50px'; // Reset
+            
+            // WAAPI can interpolate units if browser supports it layout-dependently?
+            // Often mixed units (px -> %) work in WAAPI for transforms, but for layout properties it might snap.
+            // Let's test.
+            
+            animal.animate('.box', { 
+                width: '100%', 
+                duration: 1000 
+            });
+        }
+        setTimeout(runDemo, 500);
+    </script>
+</body>
+</html>
+