動(dòng)庫(kù) motion.js 詳解:用純函數(shù)時(shí)間驅(qū)動(dòng) DOM 與 Canvas 的一鏡到底動(dòng)效體系)
AI 技能音視頻媒體生成【免費(fèi)下載鏈接】onetakeMotion films that never cut to the next slide: every beat grows out of the one before, one continuous camera, continuity measured by an oracle. A Claude Agent Skill for product launch films and feature demos.項(xiàng)目地址https://gitcode.com/gh_mirrors/on/onetake點(diǎn)擊查看免費(fèi)下載本文圍繞 references/motion-library.md 展開(kāi)系統(tǒng)講解 onetake 倉(cāng)庫(kù)中 lib/motion.js 運(yùn)動(dòng)庫(kù)的設(shè)計(jì)原則、五大類(lèi) moveenter / carry / contact / camera / fluid的完整目錄與參數(shù)、以及配套的校驗(yàn)與渲染鏈路。讀完你可以掌握如何用「絕對(duì)時(shí)間的純函數(shù)」寫(xiě)出不依賴(lài)任何動(dòng)畫(huà)框架的動(dòng)效、如何在 DOM 與 canvas 之間復(fù)用同一組數(shù)字以及怎樣用 scripts/test_motion.js 與 scripts/probe.py 驗(yàn)證每個(gè) move 的數(shù)值與連續(xù)性。設(shè)計(jì)原則Numbers, not styles運(yùn)動(dòng)庫(kù)的核心主張寫(xiě)在文檔開(kāi)頭每個(gè) move 都是絕對(duì)影片時(shí)間的純函數(shù)返回一組普通數(shù)值——偏移、縮放、不透明度、圓角、矩陣——由你把這些數(shù)字寫(xiě)進(jìn) DOM 的transform或 canvas 的調(diào)用。它不訪問(wèn) DOM、無(wú)依賴(lài)、無(wú)構(gòu)建步驟瀏覽器里script srcmotion.js得到window.OMNode 里require(./motion.js)直接可用lib/motion.js 末尾通過(guò)module.exports導(dǎo)出node scripts/test_motion.js校驗(yàn)本頁(yè)引用的所有數(shù)字。從源碼結(jié)構(gòu)看lib/motion.js文件頭注釋明確了這一契約Numbers in, numbers out. Nothing here touches the DOM or a canvas, so one call drives el.style.transform or ctx.setTransform alike. No state and no Math.random: the same arguments always give the same answer, which is what __seek(t) needs.「同參數(shù)必同輸出」不是潔癖而是整個(gè) onetake 渲染管線的硬性前提合成頁(yè)通過(guò)window.__seek(t)支持跳轉(zhuǎn)到任意一幀scripts/render.py 與 scripts/probe.py 都靠它逐幀采樣。庫(kù)中唯一的例外是四個(gè) sims 和相機(jī)積分它們一次性以 240 Hz 預(yù)積分SDT 1 / 240見(jiàn) lib/motion.js之后按時(shí)間采樣因此每一幀依然是 t 的純函數(shù)。導(dǎo)出的對(duì)象帶version: 1.1.0-lite與lineage: otk-7f3e1clib/motion.js全部 API 一覽// curves ease.* · bezier · tween · t80 · spring · springVel · ring · settle · spline · rng // enter wordRise · letterDrop · popIn · liftOut · maskRise · typeOn · tick · flyThrough // carry morphRect · iris · zoomThrough · hop · gather · ribbon · seal · staccato // contact impact · impactSplit · press · cursor · squash · sim.{magnet, follow, jelly, verlet} // camera camera · view · dof · whip · shake · drift · lattice · project · unproject · projectBox · screenTravel // fluid swiftSpring · lightField · ripple · silk · carouselLoop先看圖再選 movegallery sheet 工作流文檔要求「Look before you pick」每個(gè) move 在gallery/sheets/move.png都有一張 sheet上方是六幀畫(huà)面下排是它在 60 fps 下被追蹤元素的速度曲線px/frame與該 move 的 t80。部分 sheet 被多個(gè) move 共用liftOut在 popIn 的 sheet 上、impact在 hop 與 impactSplit 的 sheet 上、cursor在 press 的、sim.*在 sims 的、view和dof在 camera 的。配套的三個(gè)入口用途命令/地址實(shí)時(shí)循環(huán)播放某個(gè) movegallery/gallery.html?demomoveplaygallery/gallery.html修改庫(kù)后重新渲染全部 sheetpython3 scripts/gallery.py或--only ribbon,iris只渲染部分scripts/gallery.py數(shù)值自檢node scripts/test_motion.jsscripts/test_motion.js從源碼看scripts/gallery.py 的 docstring 解釋了 sheet 的讀法「a tall spike at the start of a move is a snap (low t80), a symmetric hill is a soft S-curve」——開(kāi)頭的高尖峰是 snapt80 低對(duì)稱(chēng)的丘是柔和 S 曲線。腳本本身用 Playwright 打開(kāi) gallery 頁(yè)對(duì)每個(gè) demo 調(diào)用probe.collect_page再?gòu)?fù)用 scripts/probe.py 的plot_speeds畫(huà)出速度圖。這兩個(gè) move 的「血統(tǒng)」同樣來(lái)自?xún)刹勘唤邮艿挠捌臋n稱(chēng)之為T(mén)wo films are the sourcemotion-webcase 1貢獻(xiàn)了 entrances 與 live 機(jī)制Pocket Weather Clubcase 2貢獻(xiàn)了 carries——那些把「被否決的幻燈片」變成「被接受的影片」的 move。fluid 組則是從 cases/ebb-15s 晉升而來(lái)2026-09-24 通過(guò)驗(yàn)收其參數(shù)參照了 David Ch 的 Shipper launch 與 Nazday 的 Elera carousel。應(yīng)用一個(gè) move絕對(duì)時(shí)間 雙端復(fù)用所有時(shí)間都是絕對(duì)秒數(shù)所以時(shí)間線就是合成文件頂部的一串?dāng)?shù)字任意幀可被 seek。文檔給出的標(biāo)準(zhǔn)用法const w OM.wordRise(t, 0.15); // DOM el.style.opacity w.op; el.style.transform translateY(${w.y}px) scale(${w.s}); // canvas g.save(); g.globalAlpha w.op; g.translate(x, y w.y); g.scale(w.s, w.s); g.fillText(word, 0, 0); g.restore(); const z OM.zoomThrough(t, 6.3, 7.3, card); // a matrix move: the same numbers either way g.setTransform(...z.matrix); // canvas layer.style.transform matrix(${z.matrix.join(,)}); // DOM, with transform-origin: 0 0注意 matrix 類(lèi) move如zoomThrough在兩端是同一組六個(gè)數(shù)canvas 用setTransform(...matrix)DOM 用matrix(...)并設(shè)transform-origin: 0 0。倉(cāng)庫(kù)里的真實(shí)合成模板 templates/comp.html 完整演示了這套契約時(shí)間線是頂部常量列表const W1[0.15,0.50,0.92], W1_OUT1.55; const MARK_IN1.65, ...templates/comp.html頁(yè)面暴露window.__seek(t)resolve 后本幀圖片已解碼、window.__ready、window.__meta {dur,fps,w,h}另支持?play實(shí)時(shí)循環(huán)與?t6.4hud釘住某幀sims 需要手的軌跡歷史所以在__ready里建一次OM.sim.jelly(card, hand)渲染路徑上只用.at(t)采樣模板中的simulate()templates/comp.html。文檔還列出了庫(kù)自帶的工具函數(shù)clamp、lerp、seg(t, t0, t1)、sstep/ssstep、spline(knots, t)Hermite 曲線穿過(guò){t, x, y}節(jié)點(diǎn)返回[x, y]、以及用于任何「一次性隨機(jī)」的rng(seed)。它們都定義在 lib/motion.js其中rng是 xorshift32——注釋特別強(qiáng)調(diào)「for layout jitter decided once in setup, never on the render path」隨機(jī)數(shù)只允許出現(xiàn)在搭建期不能出現(xiàn)在渲染路徑上。五組 move 完整目錄以下表格完整繼承自 references/motion-library.mdfrom列注明血統(tǒng)motion-web / Pocket Weather / 兩者 / ebb。enter — 某物到達(dá)move返回值說(shuō)明fromwordRise(t, t0, {zeta, omega, dist, s0, fade}){op, y, s}一個(gè)詞落地彈簧上升加縮放不透明度領(lǐng)先于彈簧所以讀起來(lái)絕不是淡入motion-webletterDrop(t, t0, i, {stagger, dist, squash}){op, y, sx, sy}wordmark 字母逐個(gè)落下速度把每個(gè)字母壓扁squash彈簧再把它恢復(fù)motion-webpopIn(t, t0, {rise, s0})·liftOut(t, t1, {dur, dist, blur}){op, s, dy}·{op, dy, blur, s}卡片彈簧彈出 · 卡片抬升、略微放大并模糊離場(chǎng)motion-webmaskRise(t, t0, i, {stagger, dist}){y, visible}行從裁剪遮罩后升起就位Pocket WeathertypeOn(t, t0, text, {cps, blink}){n, str, done, caret}恒定速率打字打字時(shí)光標(biāo)常亮motion-webtick(t, tl){on, s}到達(dá)該行時(shí)勾選框從 0.8 彈出motion-webflyThrough(t, t0, hold, {from, exit, rotY0, blurIn}){visible, x, rotY, rotX, s, op, blur}一個(gè)屏幕傾斜地飛入、停留、飛出CSS 3Dmotion-web實(shí)現(xiàn)細(xì)節(jié)舉例wordRise的不透明度是clamp(k * fade, 0, 1)fade 默認(rèn) 1.5讓透明度比彈簧進(jìn)度更快地到 1這正是「opacity leads the spring」的落地lib/motion.js。letterDrop則用數(shù)值微分dk (spring(tau) ? spring(tau ? h)) / h得到速度sq clamp(|dk| * squash, 0, max)——下落越快壓扁越狠落地后自然恢復(fù)lib/motion.js。flyThrough返回的blur是進(jìn)出場(chǎng)兩段模糊的取大值供 CSSfilter: blur()使用lib/motion.js。carry — 下一個(gè)節(jié)拍從這個(gè)節(jié)拍里長(zhǎng)出來(lái)這一組是 onetake「一鏡到底」的核心在 scripts/probe.py 的術(shù)語(yǔ)里一個(gè)邊界被稱(chēng)為carried當(dāng)且僅當(dāng)有東西存活跨越它并且可見(jiàn)地移動(dòng)或縮放進(jìn)了下一個(gè)節(jié)拍。probe 的判定規(guī)則scripts/probe.py存活元素的中心位移 ≥ 2% 對(duì)角線、或?qū)?shù)尺寸差 ≥ 0.1即計(jì)為強(qiáng)載體若唯一的存活物是大面積不變的內(nèi)容如整頁(yè)換內(nèi)容的窗口框架只能算anchored得分減半什么都沒(méi)有則bare。連續(xù)分score (carried anchored/2) / 計(jì)入的邊界數(shù)另有豁免硬切連發(fā)1.5 秒內(nèi) ≥3 刀即 staccato 語(yǔ)境、最后 1.2 秒的結(jié)束卡、以及window.__meta.cuts聲明的時(shí)間點(diǎn)。move返回值說(shuō)明適用場(chǎng)景morphRect(t, t0, t1, A, B, {curve}){x, y, w, h, r, cx, cy}容器變換一個(gè)矩形變成另一個(gè)矩形被按下的東西變成結(jié)果按鈕 → 窗口卡片 → 頁(yè)面iris(t, t0, t1, cx, cy){r, covered}圓從某點(diǎn)打開(kāi)直到蓋住整幀主體打開(kāi)自己的世界Pocket Weather 6.95 szoomThrough(t, t0, t1, target, {curve, fit}){s, tx, ty, matrix}對(duì)數(shù)空間推進(jìn)直到目標(biāo)充滿(mǎn)畫(huà)面眾多卡片中的一張就是下一個(gè)場(chǎng)景hop(t, t0, t1, from, to, {height}){x, y}從一槽位到下一槽位的弧線落地配impact主體選擇下一個(gè)東西Pocket Weather 1.8 sgather(t, t0, t1, i, n, from, to, {stagger, arc, spin}){x, y, rot}角色群沿扇形弧線匯入一個(gè)簇多物歸為一組10.05 sribbon(t, switches, {amp, lag}){shift, index, wobble, rot, sx, sy, textDx}彈性軌道面板切換帶 ring-out文字滯后跟隨選項(xiàng)在手下變化8.05、8.95 sseal(t, t0, t1, {r, turns}){r, rot}一個(gè)旋轉(zhuǎn)的圓盤(pán)在折疊的角色群下生長(zhǎng)角色群變成品牌標(biāo)11.5 sstaccato(t, list){word, i}硬切詞一串重音爆發(fā)——整個(gè)片里唯一允許純硬切的地方文檔補(bǔ)充作用于單一連續(xù)世界上的cameramove見(jiàn)下同樣構(gòu)成 carry——它的邊界上「一切存活」。幾個(gè)關(guān)鍵實(shí)現(xiàn)值得展開(kāi)zoomThrough的對(duì)數(shù)空間縮放s Math.exp(Math.log(sEnd) * k)讓推近「讀起來(lái)是一個(gè)恒定速度」而非線性插值那種先慢后快的失速感l(wèi)ib/motion.js。fit: cover時(shí)目標(biāo)恰好鋪滿(mǎn)畫(huà)面contain時(shí)留邊。scripts/test_motion.js 驗(yàn)證了 k1 時(shí)目標(biāo)四角恰好映射到(0,0)–(1920,1080)、k0 時(shí)為單位矩陣。iris的半徑取到最遠(yuǎn)角far max(hypot 到四個(gè)角) 2保證covered: k 1時(shí)真的一幀不漏lib/motion.js測(cè)試同樣斷言「iris covers the farthest corner at k 1」。ribbon是少數(shù)帶內(nèi)部循環(huán)的 moveshift對(duì)每個(gè)切換時(shí)刻累加curve(seg(t, ts, ts dur))r累加ring(t - ts)由此同時(shí)驅(qū)動(dòng)位移、wobble、傾斜、拉伸與textDx -r * amp * lag的文字滯后lib/motion.js。測(cè)試斷言 t5 時(shí)「settles on the last panel」shift 2且 wobble 收斂到 0。gather按索引扇開(kāi)o i ? (n?1)/2rot bump * o * spin中間項(xiàng)不轉(zhuǎn)、兩端轉(zhuǎn)得最多。contact — 一個(gè)東西引起另一個(gè)move返回值說(shuō)明fromimpact(t, tHit, {decay, omega, sqx, sqy}){r, sx, sy}落地命中瞬間壓扁隨后 ring out兩者皆有impactSplit(t, tHit, x, cx, {width, spread, bounce}){dx, dy, rot}字形按與命中點(diǎn)的距離被推開(kāi)、回彈、重新合攏Pocket Weatherpress(t, tc, {depth, flash}){s, sq, down, active}一次點(diǎn)擊下陷、ring、狀態(tài)翻轉(zhuǎn)motion-webcursor(t, knots, clicks){x, y, s}指針走在手的樣條上每次點(diǎn)擊時(shí)縮小motion-websquash(vx, vy, {k, max}){ang, sx, sy}沿速度方向拉伸、垂直方向變薄motion-websim.magnet·follow·jelly·verlet(card, hand, opts){at(t), …}磁吸按鈕、彈簧跟隨、果凍環(huán)、Verlet 繩——以 240 Hz 預(yù)積分motion-web四個(gè) sim 是庫(kù)中僅有的「積分型」成員源碼細(xì)節(jié)lib/motion.js統(tǒng)一以SDT 1/240步進(jìn)從card.t積分到card.out 0.3結(jié)果存入Float32Array狀態(tài)序列at(t)通過(guò)sampler按幀索引取整值——st[clamp(floor((t ? t0)/per), 0, len?1)]保證采樣無(wú)隨機(jī)性magnet手進(jìn)入半徑 R 時(shí)按pull * (1 ? (d/R)2)產(chǎn)生吸引再經(jīng)彈簧-阻尼積分B是按鈕中心460×270 卡片坐標(biāo)系jelly48 個(gè)徑向彈簧 鄰域耦合拉普拉斯項(xiàng)CP1800手在reach內(nèi)按壓產(chǎn)生dent每 4 步存一幀等效 60 Hz 采樣verlet16 節(jié)點(diǎn)懸掛鏈位置 Verlet 每步 3 次迭代約束同樣隔 4 步存幀。scripts/test_motion.js 對(duì)四個(gè) sim 各做兩次獨(dú)立構(gòu)建并斷言at(0.73)的 JSON 完全一致——確定性是驗(yàn)收項(xiàng)不是口頭承諾。模板 templates/comp.html 展示了它們?nèi)绾闻cpress、squash組合magnet 卡片用OM.press(t, CLICKS[1])的sq做按壓形變follow 卡片用OM.squash(vx, vy)at(t)返回含速度做速度拉伸。camera — 一臺(tái)被操作的相機(jī)move返回值說(shuō)明camera(t, keys){x, y, zoom, rot}關(guān)鍵幀相機(jī){t, x, y, zoom, rot, curve}zoom 在對(duì)數(shù)空間插值view(cam, {depth})[a, b, c, d, e, f]深度為depth的圖層的矩陣0 焦點(diǎn)面正 更遠(yuǎn)負(fù) 更近一臺(tái)相機(jī)的視差dof(depth, focus, {k, max})px按離焦平面距離產(chǎn)生的模糊whip(t, t0, dur, dist){k, d}甩鏡頭shake(t, tHit, {amp, decay, freq, seed}){x, y, rot}衰減的、確定性的、命中前嚴(yán)格為零drift(t, t0, t1, amount)scale停留鏡頭的緩慢推近1 → 1 amount —— verify 的 rest 段會(huì)計(jì)入運(yùn)動(dòng)所以別放在 rest 上lattice(cam, {depth, spacing, px}){matrix, r, spacing, x0, x1, y0, y1}OD · 透過(guò)cam看到的遠(yuǎn)網(wǎng)格的可見(jiàn)點(diǎn)屏幕上點(diǎn)半徑恒為px——給 move 一個(gè)可以滑過(guò)的背景project(M, x, y)·unproject(M, x, y)·projectBox(M, box)[x, y]· box經(jīng)view()矩陣做世界 ? 屏幕換算__track報(bào)屏上盒screenTravel(c0, c1, cMid)px兩臺(tái)相機(jī)之間畫(huà)面四角移動(dòng)的距離——__motion中相機(jī)的那一份視差矩陣的構(gòu)造lib/motion.js值得細(xì)讀深度經(jīng)f 1 / (1 max(?0.9, depth))衰減——depth 1 的圖層f 0.5正好「走得慢一半」這正是 scripts/test_motion.js 斷言的三條相機(jī)性質(zhì)居中相機(jī)是單位矩陣、view()把相機(jī)注視點(diǎn)送到畫(huà)面中心、depth 1 圖層移動(dòng)距離減半。screenTravel則取屏幕四角用中間相機(jī)cMid反投影回世界點(diǎn)再分別用c0、c1投影取四角位移最大者——scripts/render.py 用它計(jì)算每幀快門(mén)應(yīng)展開(kāi)多大。文檔中「A keyed camera that feels operated」一節(jié)記錄了 one-dot 片的兩次迭代靜態(tài)版缺「靈動(dòng)的跟蹤運(yùn)鏡」改成跟隨每個(gè)節(jié)拍主體的關(guān)鍵幀相機(jī)后得到「運(yùn)鏡、鏡頭和物理都沒(méi)問(wèn)題」。具體手法在sineInOut上提前約 0.1 s 給主體打關(guān)鍵幀追隨、在expoInOut上給落點(diǎn)提前打關(guān)鍵幀甩過(guò)去、疊加「手」——一段慢速雙正弦漂浮、在停留段歸零——以及每次落地的shake見(jiàn) references/composition.md 的A camera一節(jié)。ebb 與 onetake launch film 都是這樣做的。兩條硬約束空背景上跑相機(jī)讀不出來(lái)——在后方depth 1.2畫(huà)一層lattice。lattice通過(guò)r px / hypot(M[0], M[1])保證點(diǎn)在任何縮放下屏幕尺寸恒定并用四角反投影算出需要鋪畫(huà)的世界范圍lib/motion.jsone-dot 片用的是 48 間距、depth 1.2、1.4 px 的點(diǎn)。相機(jī)的行程疊加在元素自身行程之上one-dot 相機(jī)切點(diǎn)處峰值達(dá)935 px/frame 30 fps。fluid — 光的地面、絲綢與傳送帶ebb這一組由 cases/ebb-15s 晉升而來(lái)2026-09-24 通過(guò)驗(yàn)收參數(shù)參照 David Ch 的 Shipper launch 與 Nazday 的 Elera carousel。ebb 的合成頁(yè)就是工作示例光場(chǎng)即時(shí)間洪水以圓環(huán)形式退進(jìn)下一個(gè)場(chǎng)景絲綢填滿(mǎn)每張卡片傳送帶用自己的時(shí)鐘減速。move返回值說(shuō)明適用場(chǎng)景swiftSpring(tau, kind, {duration, bounce})numberSwiftUI 的Spring(duration d, bounce b) ζ 1 ? b、ω 2π/d 的OM.spring.smoothb 0、.snappy.15、.bouncy.3讓 UI 有原生Apple的手感而非「動(dòng)畫(huà)感」lightField(level, {rest, top, r0, r1}){cx, cy, rx, ry, tilt, horizon, core, stops}錨定在畫(huà)面下方的持續(xù)輝光level 0 為靜止horizon 0.84 H1 為淹沒(méi)。用徑向漸變按stops填充橢圓core半半徑處是文字可轉(zhuǎn)白的位置。Flood ≤ 0.4 sdrain ~1 s讓地面本身成為標(biāo)點(diǎn)它升起、淹沒(méi)退水時(shí)下一場(chǎng)景浮現(xiàn)ripple(t, t0, {n, stagger, dur, rMax}){r: [radii], done}n 個(gè)圓環(huán)以stagger間隔離開(kāi)同一點(diǎn)在 r[0] 之外填充洪水環(huán)間交替兩種色調(diào)最內(nèi)環(huán)里透出世界洪水必須在不使用擦除的情況下結(jié)束于新場(chǎng)景silk(tau, seed, stops, {gx, gy, contrast, out})·silk.ramps·silk.rampRGBAgx × gy域扭曲噪聲兩個(gè) octave16×20 網(wǎng)格對(duì)比 ×3.4putImageData后放大繪制配 blur520 寬時(shí) 28 px與一縷淺色 screen 光霧。ember/peach/dusk三條 ramp 用「兩亮之間一道暗褶」表現(xiàn)布料讓卡片、壁紙、鎖屏在沒(méi)有內(nèi)容時(shí)也是活的carouselLoop({dur, start, speed, rampDur, stop}){at(t) → {x, tau}}傳送帶.smooth起步后勻速一次積分完成tau是隨它一起減速的時(shí)鐘——用它驅(qū)動(dòng)每張卡片自己的循環(huán)多物品流過(guò)并一同停住Elera0.106 W/s源碼層面有三個(gè)可驗(yàn)證的細(xì)節(jié)silk是確定性哈希值噪聲silkHash用Math.imul整型運(yùn)算 雙 octavesilkFbm域扭曲測(cè)試斷言 16×20 RGBA、同參數(shù)逐位一致、tau變化時(shí)畫(huà)面漂移且emberramp 在 0.42 處確實(shí)存在比 0.22/0.74 更暗的明度折scripts/test_motion.jslightField(1)的洪水橢圓會(huì)越出畫(huà)面頂部且寬度超 1920scripts/test_motion.jscarouselLoop的tau是逐幀累加的減速時(shí)鐘測(cè)試斷言「start 前靜止、巡航段 ~speed、stop 后 x 與 tau 都不再變」scripts/test_motion.js。曲線與彈簧庫(kù)的數(shù)學(xué)地基所有 move 共享同一套曲線工具定義與注釋在 lib/motion.js。理解t80是理解整庫(kù)的鑰匙它定義為「覆蓋 80% 路程之前耗費(fèi)的時(shí)長(zhǎng)占比」——低 t80 先 snap 后 settlelaunch-clip 手感~0.7 對(duì)稱(chēng) S 曲線柔和用于位移時(shí)會(huì)讀作 web 過(guò)渡。scripts/probe.py 對(duì)整部影片按同樣口徑統(tǒng)計(jì)每個(gè) move 的 t80并把t80 0.55的路程占比報(bào)為soft share。scripts/test_motion.js 鎖定的 t80 表4000 步數(shù)值求根曲線t80曲線t80linear0.80quartOut0.33smoothsmoothstep0.713quintOut0.275smoothersmootherstepPW 的位移曲線0.674expoOut0.232quadOut0.553cubicOut0.415彈簧族是第二塊地基spring(tau, zeta, omega)是 0→1 的阻尼彈簧階躍響應(yīng)分欠阻尼ζ1過(guò)沖0.4 彈性…0.8 扎實(shí)、臨界ζ1、過(guò)阻尼三分支實(shí)現(xiàn)lib/motion.js。圍繞它還有四個(gè)配套springVelspring的時(shí)間導(dǎo)數(shù)注釋直言用途是squash-from-velocity測(cè)試用中心差分驗(yàn)證導(dǎo)數(shù)一致誤差 1e-3ring(tau, decay, omega)圍繞 0 的衰減振蕩點(diǎn)擊、落地、wobble 共用它impact/press/ribbon的 ring-out 都是它settle(zeta, omega, eps)彈簧保持在 1 ± eps 內(nèi)所需秒數(shù)——用來(lái)規(guī)劃一個(gè)節(jié)拍要停多久測(cè)試斷言 ζ 0.6 / ω 22 時(shí)結(jié)果在 0.1–1 s 區(qū)間bezier(x1,y1,x2,y2)CSS cubic-bezier 的求值器牛頓迭代 二分回退供直接引用設(shè)計(jì)規(guī)范或參考片的曲線測(cè)試與 20 萬(wàn)點(diǎn)暴力搜索對(duì)比最大誤差 2e-4。spring()還與合成模板原始spr()做了逐位相等斷言-0.1…3 s、步長(zhǎng) 0.0137保證庫(kù)升級(jí)不改變既有影片。速度與快門(mén)決定動(dòng)效需要多少 motion blur文檔的Speed and the shutter一節(jié)給出在 gallery 中 60 fps 下測(cè)得的峰值速度表——峰值速度決定一個(gè) move 是否需要運(yùn)動(dòng)模糊排名move峰值 px/frame 60fps1whip5402iris2063flyThrough1894morphRect1565ribbon1186shake1157follow sim1028zoomThrough72所有 entrance 與其他 carry 都在 50 以下。文檔的關(guān)鍵推論30 fps 下每個(gè)數(shù)字翻倍于是草稿階段大多數(shù) carry 會(huì)越過(guò) verify 的 80 px/frame 閾值。而liftOut/flyThrough返回的blur是營(yíng)造縱深感的 CSS filter不能替代快門(mén)。渲染端由 scripts/render.py 落實(shí)它模擬膠片相機(jī)在快門(mén)張開(kāi)期間積分曝光默認(rèn)--shutter 180°在幀時(shí)間兩側(cè)取多個(gè)子幀曝光并在線性光域求平均先拍快門(mén)兩端若兩曝光相同則本幀無(wú)運(yùn)動(dòng)、直接跳過(guò)。固定采樣數(shù)會(huì)讓快速 move 出現(xiàn)頻閃因此頁(yè)面可定義window.__motion(t0, t1)回報(bào)快門(mén)期間移動(dòng)的最大距離render 按--gap 24 px自適應(yīng)決定每幀曝光數(shù)。--shutter 0關(guān)閉模糊用于對(duì)比。也就是說(shuō)「速度數(shù)字 → 快門(mén)采樣數(shù)」是一條從screenTravel到最終成片的可審計(jì)鏈路。校驗(yàn)閉環(huán)test_motion.js 與 probe.py運(yùn)動(dòng)庫(kù)的驗(yàn)收分兩層單元級(jí)node scripts/test_motion.js覆蓋端點(diǎn)所有 ease 滿(mǎn)足 f(0)0、f(1)1、t80 表、bezier 對(duì)暴力求解、彈簧對(duì)導(dǎo)數(shù)與 ζ1 連續(xù)性、carry 幾何iris 覆蓋、zoomThrough 鋪滿(mǎn)、view 居中與視差、sim 確定性、project ° unproject互逆、靜止相機(jī)的screenTravel為 010 px pan zoom 2 應(yīng)得 20 px以及全 move 在 t ?1…4 s 掃掠下所有輸出均為有限數(shù)scripts/test_motion.js。影片級(jí)python3 scripts/probe.py comp.html --fps 30 --out probe/無(wú)需任何標(biāo)注即可讀取頁(yè)面——自動(dòng)追蹤 DOM 的 img/video/canvas/文本/繪制盒以及 canvas 的每次 draw/fill/stroke鉤子裝在頁(yè)面腳本之前若頁(yè)面定義了window.__track(t)則改讀注記。輸出 continuity 分?jǐn)?shù)、每個(gè) move 的 t80/峰值/過(guò)沖、以及__meta.inFrame聲明元素的出框時(shí)刻。gallery/gallery.html 中的每個(gè) demo 同樣遵守__seek / __track / __meta契約gallery/gallery.html這就是 sheet 能自動(dòng)重渲、速度曲線能自動(dòng)標(biāo)注 t80 的原因。動(dòng)手路徑從模板到你的合成把 templates/comp.html 作為起點(diǎn)是最短路徑它的注釋規(guī)定了編輯順序與庫(kù)的使用紀(jì)律EDIT HERE (in order): 1 INFO/FR after record_footage.py · 2 beats · 3 copy · 4 the HAND knots so the pointer causes what the footage shows · 5 nothing else until stills.py looks right. The moves are OM.* from motion.js — call them, do not re-derive springs inline.即調(diào)用OM.*不要在合成里重新推導(dǎo)彈簧手的節(jié)點(diǎn)HAND knots要用同一條樣條喂給指針與所有 sim因果關(guān)系才一致__seek是純函數(shù)的渲染入口__ready里做一次性搭建測(cè)量文字寬度、simulate()預(yù)積分 sims。配合本文的目錄選 move、看 sheet 定曲線、跑test_motion.js保數(shù)值、用probe.py看 carry 分?jǐn)?shù)、用render.py的快門(mén)成片——這就是 onetake「continuity measured by an oracle」的完整工作流。贊分享AI 技能音視頻媒體生成【免費(fèi)下載鏈接】onetakeMotion films that never cut to the next slide: every beat grows out of the one before, one continuous camera, continuity measured by an oracle. A Claude Agent Skill for product launch films and feature demos.項(xiàng)目地址https://gitcode.com/gh_mirrors/on/onetake點(diǎn)擊查看免費(fèi)下載相關(guān)推薦onetake skill-demo如何用純 DOM 與 OM 動(dòng)效庫(kù)做一條 15 秒操作演示片onetake skill demo如何用純 DOM 與 OM 動(dòng)效庫(kù)做一條 15 秒操作演示片 本文以 cases/skill demo 15s/READMAI 技能音視頻媒體生成onetake 案例解析15 秒「ebb」一鏡到底如何用一束光接住五個(gè)場(chǎng)景 —— 節(jié)拍表、Keyed Camera 與流體動(dòng)效集onetake 案例解析15 秒「ebb」一鏡到底如何用一束光接住五個(gè)場(chǎng)景 —— 節(jié)拍表、Keyed Camera 與流體動(dòng)效集 本文以 onetake 技能AI 技能音視頻媒體生成onetake:把產(chǎn)品發(fā)布動(dòng)效片寫(xiě)成一鏡到底的工程協(xié)議——Claude Agent Skill 的 SKILL.md 全解onetake:把產(chǎn)品發(fā)布動(dòng)效片寫(xiě)成一鏡到底的工程協(xié)議——Claude Agent Skill 的 SKILL.md 全解 onetake 是一個(gè) ClauAI 技能音視頻媒體生成上一篇終極指南如何訓(xùn)練自定義waifu2x-caffe模型打造專(zhuān)屬圖像增強(qiáng)工具下一篇PHP Font Lib 開(kāi)發(fā)者手冊(cè)擴(kuò)展自定義字體格式支持創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考