这是测试站点!!!!
不要保存重要内容!不要保存重要内容!不要保存重要内容!不要保存重要内容!不要保存重要内容!
模块:抖动:修订间差异
来自Limbo Wiki
文字抖动模板 标签:(旧)WikiEditor |
小无编辑摘要 标签:(旧)WikiEditor |
||
| 第1行: | 第1行: | ||
-- 模块文档见 [[Module:抖动/doc]] | |||
local p = {} | local p = {} | ||
-- 模式 → 类前缀 + | -- 模式 → 类前缀 + 数值参数名 + 默认数值 | ||
local modeDef = { | local modeDef = { | ||
['平移'] = { pre = 'translate', | ['平移'] = { pre = 'translate', numParam = '平移幅度', def = '0.11' }, | ||
['旋转'] = { pre = 'rotate', | ['旋转'] = { pre = 'rotate', numParam = '旋转角度', def = '9' }, | ||
['跳动'] = { pre = 'bounce', | ['跳动'] = { pre = 'bounce', numParam = '跳动高度', def = '0.17' }, | ||
['摇摆'] = { pre = 'swing', | ['摇摆'] = { pre = 'swing', numParam = '摇摆角度', def = '9' }, | ||
['颤抖'] = { pre = 'jitter', | ['颤抖'] = { pre = 'jitter', numParam = '颤抖幅度', def = '0.09' }, | ||
['缩放'] = { pre = 'pulse', | ['缩放'] = { pre = 'pulse', numParam = '缩放倍数', def = '1.1' }, | ||
} | } | ||
-- | -- 颤抖角度参数(颤抖为位移 + 角度两个变量) | ||
local | local JITTER_ANGLE = '颤抖角度' | ||
local JITTER_DEF_ANGLE = '6' | |||
-- | -- 解析数值:非法/空 → 默认值 | ||
local function | local function numOf(v, def) | ||
if v == nil | if v == nil then return def end | ||
if | v = tostring(v):match('^%s*(.-)%s*$') | ||
if v == nil or v == '' then return def end | |||
local n = tonumber(v) | local n = tonumber(v) | ||
if not n then return | if not n then return def end | ||
return tostring(n) | |||
end | end | ||
-- 模式拆分 | -- 模式拆分 | ||
local function splitModes(s) | local function splitModes(s) | ||
if not s or s == '' then return { '颤抖' } end | if not s or s == '' then return { '颤抖' } end | ||
local out, seen = {}, {} | local out, seen = {}, {} | ||
for m in mw.ustring.gmatch(s, '[^%+、,, ]+') do | for m in mw.ustring.gmatch(s, '[^%+、,, ]+') do | ||
| 第43行: | 第36行: | ||
end | end | ||
end | end | ||
if #out == 0 then return { '颤抖' } end | if #out == 0 then return { '颤抖' } end | ||
return out | return out | ||
end | |||
-- 生成该模式的行内 CSS 变量声明 | |||
local function varDecls(m, args) | |||
local def = modeDef[m] | |||
local parts = {} | |||
if m == '颤抖' then | |||
parts[#parts + 1] = '--dk-amp:' .. numOf(args[def.numParam], def.def) .. 'em' | |||
parts[#parts + 1] = '--dk-angle:' .. numOf(args[JITTER_ANGLE], JITTER_DEF_ANGLE) .. 'deg' | |||
elseif m == '跳动' then | |||
parts[#parts + 1] = '--dk-amp:-' .. numOf(args[def.numParam], def.def) .. 'em' | |||
elseif m == '缩放' then | |||
parts[#parts + 1] = '--dk-scale:' .. numOf(args[def.numParam], def.def) | |||
elseif m == '平移' then | |||
parts[#parts + 1] = '--dk-amp:' .. numOf(args[def.numParam], def.def) .. 'em' | |||
else -- 旋转 / 摇摆 | |||
parts[#parts + 1] = '--dk-angle:' .. numOf(args[def.numParam], def.def) .. 'deg' | |||
end | |||
return parts | |||
end | end | ||
| 第52行: | 第64行: | ||
for i = #modes, 1, -1 do | for i = #modes, 1, -1 do | ||
local m = modes[i] | local m = modes[i] | ||
local cls = 'dk-' .. modeDef[m].pre | local cls = 'dk-' .. modeDef[m].pre | ||
local parts = {} | local parts = {} | ||
for _, v in ipairs(info.vars[i]) do parts[#parts + 1] = v end | |||
for _, pt in ipairs(info.styles[i]) do parts[#parts + 1] = pt end | for _, pt in ipairs(info.styles[i]) do parts[#parts + 1] = pt end | ||
if perChar and i == 1 then | if perChar and i == 1 then | ||
local filtered = {} | local filtered = {} | ||
for _, pt in ipairs(parts) do | for _, pt in ipairs(parts) do | ||
| 第82行: | 第94行: | ||
local modes = splitModes(args['模式']) | local modes = splitModes(args['模式']) | ||
local info = { | local info = { vars = {}, styles = {} } | ||
for i, m in ipairs(modes) do | for i, m in ipairs(modes) do | ||
info.vars[i] = varDecls(m, args) | |||
info. | |||
local parts = {} | local parts = {} | ||
local dur = args[m .. '速度'] | local dur = args[m .. '速度'] | ||
| 第97行: | 第108行: | ||
if perChar then | if perChar then | ||
local out, i = {}, 0 | local out, i = {}, 0 | ||
for ch in mw.ustring.gmatch(text, '.') do | for ch in mw.ustring.gmatch(text, '.') do | ||
| 第109行: | 第119行: | ||
return '<span class="shake-chars">' .. table.concat(out) .. '</span>' | return '<span class="shake-chars">' .. table.concat(out) .. '</span>' | ||
else | else | ||
return wrap(frame:preprocess(text), modes, info, false, 1) | return wrap(frame:preprocess(text), modes, info, false, 1) | ||
end | end | ||
2026年8月31日 (一) 21:13的最新版本
模板:抖动的底层生成器,负责把模板参数转换为最终的 HTML 结构。
工作原理
模块按以下步骤工作:
- 读取参数:从调用中取得「内容、模式、逐字、速度、延迟」以及各模式对应的数值幅度参数。
- 解析模式:把
模式=平移+旋转+跳动这类字符串拆分成模式列表。 - 解析数值:把用户传入的纯数字幅度值规整为合法数值,空值或非数字时回退为程序内置默认值。
- 生成变量:把各模式的幅度数值转换为行内 CSS 自定义属性(CSS 变量),如
--dk-amp:0.05em。 - 生成结构:为每个模式各包一层
<span>并依次嵌套;逐字模式下把文字按单个字符拆开。 - 输出 HTML:模块只生成 class 名、行内 CSS 变量和必要的内联样式,动画本身由模板:抖动/styles.css提供。
模式叠加的原理
CSS 中同一元素只能运行一个 transform 动画,无法直接叠加。因此模块让每种模式各占一层 <span>:
<span class="dk-translate" style="--dk-amp:0.11em"> ← 平移层
<span class="dk-rotate" style="--dk-angle:9deg"> ← 旋转层
<span class="dk-bounce" style="--dk-amp:-0.17em"> ← 跳动层
文字
</span>
</span>
</span>
各层动画独立运行,视觉上自然叠加:外层负责整体平移,内层负责局部抖动。
逐字与整段
- 整段模式:内容作为整体被包裹,先经
frame:preprocess()处理,支持 wikitext 语法。 - 逐字模式:用
mw.ustring.gmatch(text, '.')将文字按字符拆开,每个字符成为独立抖动单元,并配以递增的负值动画延迟,使各字错位、不同步。逐字模式仅适用于纯文本。
与样式表的关系
模块不包含任何动画定义,只负责产出:
- 形如
dk-模式的 class(如dk-translate); - 各模式幅度对应的行内 CSS 自定义属性(如
style="--dk-amp:0.05em"); - 用户显式设置的速度 / 延迟内联样式(如
style="animation-duration:0.3s")。
实际动画(keyframes、位移、旋转角度等)全部定义在模板:抖动/styles.css,二者通过 class 名和 CSS 变量对应。模块输出的 class 与 CSS 变量对应关系:
| 模式 | 类名 | 行内 CSS 变量 |
|---|---|---|
| 平移 | dk-translate |
--dk-amp: <幅度>em
|
| 旋转 | dk-rotate |
--dk-angle: <角度>deg
|
| 跳动 | dk-bounce |
--dk-amp: -<高度>em
|
| 摇摆 | dk-swing |
--dk-angle: <角度>deg
|
| 颤抖 | dk-jitter |
--dk-amp: <幅度>em; --dk-angle: <角度>deg
|
| 缩放 | dk-pulse |
--dk-scale: <倍数>
|
参数与默认值
以下为模块读取的全部参数及其程序内置默认值。模式专属参数只在对应模式被启用时生效。
| 参数 | 作用模式 | 默认值 | 单位 | 说明 |
|---|---|---|---|---|
内容 |
全局 | 空(必填) | — | 要抖动的文字;也可作为第 1 个匿名参数 |
模式 |
全局 | 颤抖 | — | 抖动模式:平移/旋转/跳动/摇摆/颤抖/缩放,用 + 叠加
|
逐字 |
全局 | 否 | — | 设为 是 时逐字独立抖动
|
速度 |
全局 | 各模式自带周期 (平移 0.5s / 旋转 0.6s / 跳动 0.7s / 摇摆 0.8s / 颤抖 0.18s / 缩放 0.8s) |
秒 | 全局动画周期,越小越快;被模式专属速度覆盖 |
延迟 |
全局 | 0 | 秒 | 全局动画延迟;被模式专属延迟覆盖 |
平移幅度 |
平移 | 0.11 | em | 水平位移幅度 |
平移速度 |
平移 | 继承全局 速度;否则 0.5 |
秒 | 平移层动画周期 |
平移延迟 |
平移 | 继承全局 延迟;否则 0 |
秒 | 平移层延迟 |
旋转角度 |
旋转 | 9 | deg | 旋转角度 |
旋转速度 |
旋转 | 继承全局 速度;否则 0.6 |
秒 | 旋转层动画周期 |
旋转延迟 |
旋转 | 继承全局 延迟;否则 0 |
秒 | 旋转层延迟 |
跳动高度 |
跳动 | 0.17 | em | 向上跳动高度 |
跳动速度 |
跳动 | 继承全局 速度;否则 0.7 |
秒 | 跳动层动画周期 |
跳动延迟 |
跳动 | 继承全局 延迟;否则 0 |
秒 | 跳动层延迟 |
摇摆角度 |
摇摆 | 9 | deg | 摇摆角度 |
摇摆速度 |
摇摆 | 继承全局 速度;否则 0.8 |
秒 | 摇摆层动画周期 |
摇摆延迟 |
摇摆 | 继承全局 延迟;否则 0 |
秒 | 摇摆层延迟 |
颤抖幅度 |
颤抖 | 0.09 | em | 颤抖位移幅度 |
颤抖角度 |
颤抖 | 6 | deg | 颤抖旋转角度 |
颤抖速度 |
颤抖 | 继承全局 速度;否则 0.18 |
秒 | 颤抖层动画周期 |
颤抖延迟 |
颤抖 | 继承全局 延迟;否则 0 |
秒 | 颤抖层延迟 |
缩放倍数 |
缩放 | 1.1 | — | 缩放倍数(无单位) |
缩放速度 |
缩放 | 继承全局 速度;否则 0.8 |
秒 | 缩放层动画周期 |
缩放延迟 |
缩放 | 继承全局 延迟;否则 0 |
秒 | 缩放层延迟 |
数值解析
- 幅度参数仅接受纯数字;空值或非数字时回退为程序内置默认值(见上表)。
- 单位由模块固定(em / deg / 无),无需(也不应)在数字后追加单位。
速度/延迟及模式专属版本单位为秒。
错误处理
- 未知模式:被忽略;全部未知时回退为
颤抖。 - 非法数值:回退为该参数的默认值。
- 内容为空:输出空字符串。
-- 模块文档见 [[Module:抖动/doc]]
local p = {}
-- 模式 → 类前缀 + 数值参数名 + 默认数值
local modeDef = {
['平移'] = { pre = 'translate', numParam = '平移幅度', def = '0.11' },
['旋转'] = { pre = 'rotate', numParam = '旋转角度', def = '9' },
['跳动'] = { pre = 'bounce', numParam = '跳动高度', def = '0.17' },
['摇摆'] = { pre = 'swing', numParam = '摇摆角度', def = '9' },
['颤抖'] = { pre = 'jitter', numParam = '颤抖幅度', def = '0.09' },
['缩放'] = { pre = 'pulse', numParam = '缩放倍数', def = '1.1' },
}
-- 颤抖角度参数(颤抖为位移 + 角度两个变量)
local JITTER_ANGLE = '颤抖角度'
local JITTER_DEF_ANGLE = '6'
-- 解析数值:非法/空 → 默认值
local function numOf(v, def)
if v == nil then return def end
v = tostring(v):match('^%s*(.-)%s*$')
if v == nil or v == '' then return def end
local n = tonumber(v)
if not n then return def end
return tostring(n)
end
-- 模式拆分
local function splitModes(s)
if not s or s == '' then return { '颤抖' } end
local out, seen = {}, {}
for m in mw.ustring.gmatch(s, '[^%+、,, ]+') do
if modeDef[m] and not seen[m] then
seen[m] = true
out[#out + 1] = m
end
end
if #out == 0 then return { '颤抖' } end
return out
end
-- 生成该模式的行内 CSS 变量声明
local function varDecls(m, args)
local def = modeDef[m]
local parts = {}
if m == '颤抖' then
parts[#parts + 1] = '--dk-amp:' .. numOf(args[def.numParam], def.def) .. 'em'
parts[#parts + 1] = '--dk-angle:' .. numOf(args[JITTER_ANGLE], JITTER_DEF_ANGLE) .. 'deg'
elseif m == '跳动' then
parts[#parts + 1] = '--dk-amp:-' .. numOf(args[def.numParam], def.def) .. 'em'
elseif m == '缩放' then
parts[#parts + 1] = '--dk-scale:' .. numOf(args[def.numParam], def.def)
elseif m == '平移' then
parts[#parts + 1] = '--dk-amp:' .. numOf(args[def.numParam], def.def) .. 'em'
else -- 旋转 / 摇摆
parts[#parts + 1] = '--dk-angle:' .. numOf(args[def.numParam], def.def) .. 'deg'
end
return parts
end
-- 嵌套包裹
local function wrap(inner, modes, info, perChar, idx)
local html = inner
for i = #modes, 1, -1 do
local m = modes[i]
local cls = 'dk-' .. modeDef[m].pre
local parts = {}
for _, v in ipairs(info.vars[i]) do parts[#parts + 1] = v end
for _, pt in ipairs(info.styles[i]) do parts[#parts + 1] = pt end
if perChar and i == 1 then
local filtered = {}
for _, pt in ipairs(parts) do
if not mw.ustring.match(pt, '^animation%-delay:') then
filtered[#filtered + 1] = pt
end
end
parts = filtered
local d = string.format('%.2f', ((idx - 1) * 0.12) % 0.5)
table.insert(parts, 1, 'animation-delay:-' .. d .. 's')
cls = 'shake-char ' .. cls
end
local attr = ''
if #parts > 0 then attr = ' style="' .. table.concat(parts, ';') .. '"' end
html = '<span class="' .. cls .. '"' .. attr .. '>' .. html .. '</span>'
end
return html
end
function p.main(frame)
local args = frame.args
local text = args['内容'] or ''
local perChar = (args['逐字'] or '否') == '是'
local gDur, gDel = args['速度'], args['延迟']
local modes = splitModes(args['模式'])
local info = { vars = {}, styles = {} }
for i, m in ipairs(modes) do
info.vars[i] = varDecls(m, args)
local parts = {}
local dur = args[m .. '速度']
if (dur == nil or dur == '') and gDur ~= nil and gDur ~= '' then dur = gDur end
if dur ~= nil and dur ~= '' then parts[#parts + 1] = 'animation-duration:' .. dur .. 's' end
local del = args[m .. '延迟']
if (del == nil or del == '') and gDel ~= nil and gDel ~= '' then del = gDel end
if del ~= nil and del ~= '' then parts[#parts + 1] = 'animation-delay:' .. del .. 's' end
info.styles[i] = parts
end
if perChar then
local out, i = {}, 0
for ch in mw.ustring.gmatch(text, '.') do
if ch == ' ' then
out[#out + 1] = ' '
else
i = i + 1
out[#out + 1] = wrap(mw.text.encode(ch), modes, info, true, i)
end
end
return '<span class="shake-chars">' .. table.concat(out) .. '</span>'
else
return wrap(frame:preprocess(text), modes, info, false, 1)
end
end
return p
