<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://shanghaidc1.gaoice.run/index.php?action=history&amp;feed=atom&amp;title=%E6%A8%A1%E5%9D%97%3A%E7%BA%B8%E5%BC%A0</id>
	<title>模块:纸张 - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://shanghaidc1.gaoice.run/index.php?action=history&amp;feed=atom&amp;title=%E6%A8%A1%E5%9D%97%3A%E7%BA%B8%E5%BC%A0"/>
	<link rel="alternate" type="text/html" href="https://shanghaidc1.gaoice.run/index.php?title=%E6%A8%A1%E5%9D%97:%E7%BA%B8%E5%BC%A0&amp;action=history"/>
	<updated>2026-10-31T20:56:04Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.46.2</generator>
	<entry>
		<id>https://shanghaidc1.gaoice.run/index.php?title=%E6%A8%A1%E5%9D%97:%E7%BA%B8%E5%BC%A0&amp;diff=58487&amp;oldid=prev</id>
		<title>晨茗biu～：​纸张模拟模块</title>
		<link rel="alternate" type="text/html" href="https://shanghaidc1.gaoice.run/index.php?title=%E6%A8%A1%E5%9D%97:%E7%BA%B8%E5%BC%A0&amp;diff=58487&amp;oldid=prev"/>
		<updated>2026-10-22T16:51:53Z</updated>

		<summary type="html">&lt;p&gt;纸张模拟模块&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local p = {}&lt;br /&gt;
&lt;br /&gt;
local TYPES = { [&amp;#039;咖啡&amp;#039;]=&amp;#039;st1&amp;#039;,[&amp;#039;墨&amp;#039;]=&amp;#039;st2&amp;#039;,[&amp;#039;水&amp;#039;]=&amp;#039;st3&amp;#039;,[&amp;#039;茶&amp;#039;]=&amp;#039;st4&amp;#039;,[&amp;#039;霉&amp;#039;]=&amp;#039;st5&amp;#039;,[&amp;#039;血迹&amp;#039;]=&amp;#039;st6&amp;#039; }&lt;br /&gt;
local RING = { st1=true, st3=true, st4=true }&lt;br /&gt;
&lt;br /&gt;
local OFF = { {5,-6,0.66}, {-6,7,0.58}, {9,6,0.50}, {-5,-8,0.44} }&lt;br /&gt;
&lt;br /&gt;
local WEARPTS = {&lt;br /&gt;
  {10,14,1.30,1.00},{72,30,1.70,1.20},{38,66,1.55,1.10},{84,72,1.20,0.95},&lt;br /&gt;
  {20,86,1.85,1.30},{56,8,1.10,0.85},{90,44,1.00,0.80},{6,52,1.40,1.05},&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local CORNERCLS = { [&amp;#039;左上&amp;#039;]=&amp;#039;tl&amp;#039;,[&amp;#039;右上&amp;#039;]=&amp;#039;tr&amp;#039;,[&amp;#039;左下&amp;#039;]=&amp;#039;bl&amp;#039;,[&amp;#039;右下&amp;#039;]=&amp;#039;br&amp;#039; }&lt;br /&gt;
local CORNERPOS = { tl=&amp;#039;0% 0%&amp;#039;, tr=&amp;#039;100% 0%&amp;#039;, bl=&amp;#039;0% 100%&amp;#039;, br=&amp;#039;100% 100%&amp;#039; }&lt;br /&gt;
&lt;br /&gt;
local function trim(s) if not s then return &amp;#039;&amp;#039; end s=s:gsub(&amp;#039;^%s+&amp;#039;,&amp;#039;&amp;#039;) s=s:gsub(&amp;#039;%s+$&amp;#039;,&amp;#039;&amp;#039;) return s end&lt;br /&gt;
local function clamp(v,lo,hi) if v&amp;lt;lo then return lo end if v&amp;gt;hi then return hi end return v end&lt;br /&gt;
local function lcg(n) return (n*1103515245+12345) % 2147483648 end&lt;br /&gt;
&lt;br /&gt;
local function pageSeed()&lt;br /&gt;
  local t = mw.title.getCurrentTitle().text or &amp;#039;&amp;#039;&lt;br /&gt;
  local h = 5381&lt;br /&gt;
  for i = 1, #t do h = (h*33 + t:byte(i)) % 100003 end&lt;br /&gt;
  return h&lt;br /&gt;
end&lt;br /&gt;
local function normOpacity(s)&lt;br /&gt;
  local o=tonumber(s) if not o then return nil end&lt;br /&gt;
  if o&amp;gt;1 then o=o/100 end&lt;br /&gt;
  if o&amp;lt;0 then o=0 end&lt;br /&gt;
  if o&amp;gt;1 then o=1 end&lt;br /&gt;
  return o&lt;br /&gt;
end&lt;br /&gt;
local function opStr(o) if not o then return &amp;#039;&amp;#039; end return &amp;#039;opacity:&amp;#039;..string.format(&amp;#039;%.2f&amp;#039;,o)..&amp;#039;;&amp;#039; end&lt;br /&gt;
local function mix(n, salt)&lt;br /&gt;
  local v = (n + salt*7919) % 2147483647&lt;br /&gt;
  v = (v * 1103515245 + 12345) % 2147483647&lt;br /&gt;
  v = (v * 1103515245 + 12345) % 2147483647&lt;br /&gt;
  return v&lt;br /&gt;
end&lt;br /&gt;
local function jitterR(h,i)&lt;br /&gt;
  local a = mix(h+i, 1) % 33 - 16&lt;br /&gt;
  local b = mix(h+i, 2) % 33 - 16&lt;br /&gt;
  local c = mix(h+i, 3) % 33 - 16&lt;br /&gt;
  local d = mix(h+i, 4) % 33 - 16&lt;br /&gt;
  return string.format(&amp;#039;%d%% %d%% %d%% %d%%&amp;#039;,50+a,50+b,50+c,50+d)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function strhash(s)&lt;br /&gt;
  if not s or s == &amp;#039;&amp;#039; then return 0 end&lt;br /&gt;
  local n = #s&lt;br /&gt;
  local step = 1&lt;br /&gt;
  if n &amp;gt; 400 then step = math.floor(n / 400) end&lt;br /&gt;
  local h = 5381&lt;br /&gt;
  for i = 1, n, step do h = (h*31 + s:byte(i)) % 1000033 end&lt;br /&gt;
  return h&lt;br /&gt;
end&lt;br /&gt;
local function contentSeed(content, seed, typ)&lt;br /&gt;
  return (pageSeed() + strhash(content or &amp;#039;&amp;#039;)*389 + strhash(seed or &amp;#039;&amp;#039;)*701 + strhash(typ or &amp;#039;&amp;#039;)*47 + 17) % 1000003&lt;br /&gt;
end&lt;br /&gt;
local function instSeed(frame)&lt;br /&gt;
  return contentSeed(frame.args[1], frame.args[2], frame.args[3])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.stain(frame)&lt;br /&gt;
  local src    = trim(frame.args[1] or &amp;#039;&amp;#039;)&lt;br /&gt;
  local qtyG   = clamp(math.floor(tonumber(trim(frame.args[2] or &amp;#039;&amp;#039;)) or 1),1,5)&lt;br /&gt;
  local opaG   = normOpacity(trim(frame.args[3] or &amp;#039;&amp;#039;))&lt;br /&gt;
  local spread = clamp(math.floor(tonumber(trim(frame.args[4] or &amp;#039;&amp;#039;)) or 0),0,5)&lt;br /&gt;
&lt;br /&gt;
  src = src:gsub(&amp;#039;，&amp;#039;,&amp;#039;,&amp;#039;):gsub(&amp;#039;；&amp;#039;,&amp;#039;;&amp;#039;):gsub(&amp;#039;＠&amp;#039;,&amp;#039;@&amp;#039;):gsub(&amp;#039;　&amp;#039;,&amp;#039; &amp;#039;)&lt;br /&gt;
  src = trim(src)&lt;br /&gt;
  local srch = 7&lt;br /&gt;
  for i = 1, #src do srch = (srch*31 + src:byte(i)) % 100003 end&lt;br /&gt;
  local h = (contentSeed(frame.args[5], frame.args[6], frame.args[7]) + srch * 131) % 1000003&lt;br /&gt;
&lt;br /&gt;
  local list = {}&lt;br /&gt;
  for entry in mw.text.gsplit(src,&amp;#039;;&amp;#039;) do&lt;br /&gt;
    entry = trim(entry)&lt;br /&gt;
    if entry ~= &amp;#039;&amp;#039; and entry ~= &amp;#039;无&amp;#039; then&lt;br /&gt;
      local at = entry:find(&amp;#039;@&amp;#039;,1,true)&lt;br /&gt;
      local tname, rest&lt;br /&gt;
      if at then tname=trim(entry:sub(1,at-1)) rest=entry:sub(at+1) else tname=entry rest=&amp;#039;&amp;#039; end&lt;br /&gt;
      local cls = TYPES[tname]&lt;br /&gt;
      if cls then&lt;br /&gt;
        local x,y,color,splash = nil,nil,&amp;#039;&amp;#039;,&amp;#039;&amp;#039;&lt;br /&gt;
        local opa,qty = opaG,qtyG&lt;br /&gt;
        if rest ~= &amp;#039;&amp;#039; then&lt;br /&gt;
          local segs = mw.text.split(rest,&amp;#039;,&amp;#039;,true)&lt;br /&gt;
          local px = tonumber(trim(segs[1] or &amp;#039;&amp;#039;) or &amp;#039;&amp;#039;)&lt;br /&gt;
          local py = tonumber(trim(segs[2] or &amp;#039;&amp;#039;) or &amp;#039;&amp;#039;)&lt;br /&gt;
          if px then x = clamp(px,0,95) end&lt;br /&gt;
          if py then y = clamp(py,0,95) end&lt;br /&gt;
          color = trim(segs[3] or &amp;#039;&amp;#039;)&lt;br /&gt;
          local sp = trim(segs[4] or &amp;#039;&amp;#039;)&lt;br /&gt;
          if sp==&amp;#039;飞溅&amp;#039; or sp==&amp;#039;splash&amp;#039; then splash=&amp;#039; limbo-paper-splash&amp;#039; end&lt;br /&gt;
          local o5 = normOpacity(trim(segs[5] or &amp;#039;&amp;#039;)) if o5 then opa=o5 end&lt;br /&gt;
          local q6 = tonumber(trim(segs[6] or &amp;#039;&amp;#039;) or &amp;#039;&amp;#039;) if q6 then qty=clamp(math.floor(q6),1,5) end&lt;br /&gt;
        end&lt;br /&gt;
        list[#list+1] = { cls=cls, x=x, y=y, color=color, splash=splash, opa=opa, qty=qty }&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  local out, idx = {}, 0&lt;br /&gt;
  for _, it in ipairs(list) do&lt;br /&gt;
    idx = idx + 1&lt;br /&gt;
    local x = it.x&lt;br /&gt;
    local y = it.y&lt;br /&gt;
    if not x then x = 6 + (mix(h, idx*37+1) % 87) end&lt;br /&gt;
    if not y then y = 6 + (mix(h, idx*37+2) % 80) end&lt;br /&gt;
    local colStyle = it.color ~= &amp;#039;&amp;#039; and (&amp;#039;--limbo-paper-stain:&amp;#039;..it.color..&amp;#039;;&amp;#039;) or &amp;#039;&amp;#039;&lt;br /&gt;
    local shape = &amp;#039;border-radius:&amp;#039;..jitterR(h,idx)..&amp;#039;;&amp;#039;&lt;br /&gt;
    local spin = string.format(&amp;#039;transform:rotate(%.1fdeg) scale(%.2f);&amp;#039;, ((mix(h, idx*9+1) % 4000)/100.0) - 20, 0.68 + (mix(h, idx*9+2) % 78)/100.0)&lt;br /&gt;
    local bwid = &amp;#039;&amp;#039;&lt;br /&gt;
    if RING[it.cls] then&lt;br /&gt;
      local bbase = (it.cls == &amp;#039;st3&amp;#039;) and 0.18 or 0.24&lt;br /&gt;
      bwid = string.format(&amp;#039;border-width:%.2fem;&amp;#039;, bbase * (0.60 + (mix(h, idx*29+3) % 91)/100.0))&lt;br /&gt;
    end&lt;br /&gt;
    out[#out+1] = string.format(&amp;#039;&amp;lt;span class=&amp;quot;limbo-paper-stain limbo-paper-%s%s&amp;quot; style=&amp;quot;left:%d%%;top:%d%%;%s%s%s%s%s&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;,&lt;br /&gt;
      it.cls, it.splash, math.floor(x), math.floor(y), colStyle, shape, bwid, spin, opStr(it.opa))&lt;br /&gt;
    for i = 1, it.qty-1 do&lt;br /&gt;
      local d = OFF[i]&lt;br /&gt;
      if d then&lt;br /&gt;
        local ring = RING[it.cls]&lt;br /&gt;
        local k = ring and (2.2 + (mix(h, idx*13+i) % 141)/100.0) or (0.60 + (mix(h, idx*13+i) % 86)/100.0)&lt;br /&gt;
        local rot = ((mix(h, idx*17+i) % 4800)/100.0) - 24&lt;br /&gt;
        local fs = d[3] * (0.70 + (mix(h, idx*31+i) % 61)/100.0)&lt;br /&gt;
        local dx, dy = d[1]*k, d[2]*k&lt;br /&gt;
        if ring then&lt;br /&gt;
          local ang = math.rad(((mix(h, idx*43+i) % 4400)/100.0) - 22)&lt;br /&gt;
          local ca, sa = math.cos(ang), math.sin(ang)&lt;br /&gt;
          dx, dy = dx*ca - dy*sa, dx*sa + dy*ca&lt;br /&gt;
        end&lt;br /&gt;
        out[#out+1] = string.format(&amp;#039;&amp;lt;span class=&amp;quot;limbo-paper-stain limbo-paper-%s&amp;quot; style=&amp;quot;left:%d%%;top:%d%%;font-size:%.2fem;transform:rotate(%.1fdeg);%s%s%s&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;,&lt;br /&gt;
          it.cls, math.floor(clamp(x+dx,0,94)), math.floor(clamp(y+dy,0,94)), fs, rot,&lt;br /&gt;
          colStyle, &amp;#039;border-radius:&amp;#039;..jitterR(h,idx*7+i)..&amp;#039;;&amp;#039;, opStr(it.opa))&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if spread &amp;gt; 0 and #list &amp;gt; 0 then&lt;br /&gt;
    local total = spread * 6&lt;br /&gt;
    local cols = math.ceil(math.sqrt(total*1.4))&lt;br /&gt;
    local rows = math.ceil(total/cols)&lt;br /&gt;
    local cw = 90.0/cols&lt;br /&gt;
    local ch = 86.0/rows&lt;br /&gt;
    for i = 1, total do&lt;br /&gt;
      local it = list[(i-1) % #list + 1]&lt;br /&gt;
      local col = (i-1) % cols&lt;br /&gt;
      local row = math.floor((i-1)/cols)&lt;br /&gt;
      local jx = lcg(i*7919) % math.max(1, math.floor(cw*0.55))&lt;br /&gt;
      local jy = lcg(i*104729+17) % math.max(1, math.floor(ch*0.55))&lt;br /&gt;
      local x = math.floor(4 + col*cw + jx)&lt;br /&gt;
      local y = math.floor(4 + row*ch + jy)&lt;br /&gt;
      local sc = 0.12 + (lcg(i*31337) % 84) / 100.0&lt;br /&gt;
      local rot = (mix(h + i, 9) % 12000) / 100.0 - 60&lt;br /&gt;
      local colStyle = it.color ~= &amp;#039;&amp;#039; and (&amp;#039;--limbo-paper-stain:&amp;#039;..it.color..&amp;#039;;&amp;#039;) or &amp;#039;&amp;#039;&lt;br /&gt;
      out[#out+1] = string.format(&lt;br /&gt;
        &amp;#039;&amp;lt;span class=&amp;quot;limbo-paper-stain limbo-paper-%s&amp;quot; style=&amp;quot;left:%d%%;top:%d%%;font-size:%.2fem;transform:rotate(%.1fdeg);%s%s%s&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;,&lt;br /&gt;
        it.cls, x, y, sc, rot, colStyle, &amp;#039;border-radius:&amp;#039;..jitterR(h,i*11+3)..&amp;#039;;&amp;#039;, opStr(it.opa))&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  return table.concat(out)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.corner(frame)&lt;br /&gt;
  local src = trim(frame.args[1] or &amp;#039;&amp;#039;)&lt;br /&gt;
  src = src:gsub(&amp;#039;，&amp;#039;,&amp;#039;,&amp;#039;):gsub(&amp;#039;、&amp;#039;,&amp;#039;,&amp;#039;):gsub(&amp;#039;；&amp;#039;,&amp;#039;;&amp;#039;):gsub(&amp;#039;　&amp;#039;,&amp;#039; &amp;#039;)&lt;br /&gt;
  local out, seen = {}, {}&lt;br /&gt;
  for entry in mw.text.gsplit(src,&amp;#039;[,;]&amp;#039;) do&lt;br /&gt;
    local c = CORNERCLS[trim(entry)]&lt;br /&gt;
    if c and not seen[c] then&lt;br /&gt;
      seen[c] = true&lt;br /&gt;
      out[#out+1] = &amp;#039;&amp;lt;span class=&amp;quot;limbo-paper-deco limbo-paper-corner limbo-paper-cn-&amp;#039;..c..&amp;#039;&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  return table.concat(out)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.damage(frame)&lt;br /&gt;
  local n = clamp(math.floor(tonumber(trim(frame.args[1] or &amp;#039;&amp;#039;)) or 0),0,8)&lt;br /&gt;
  if n &amp;lt; 1 then return &amp;#039;&amp;#039; end&lt;br /&gt;
  local h = contentSeed(frame.args[2], frame.args[3], frame.args[4])&lt;br /&gt;
  local grow = 0.55 + 0.11*(n-1)&lt;br /&gt;
  local out = {}&lt;br /&gt;
  for i = 1, n do&lt;br /&gt;
    local w = WEARPTS[i]&lt;br /&gt;
    if w then&lt;br /&gt;
      local jx = ((h+i*97)%23)-11&lt;br /&gt;
      local jy = ((h+i*131)%23)-11&lt;br /&gt;
      local sz = 0.65 + (mix(h+i,7)%81)/100.0&lt;br /&gt;
      out[#out+1] = string.format(&amp;#039;&amp;lt;span class=&amp;quot;limbo-paper-wear&amp;quot; style=&amp;quot;left:%d%%;top:%d%%;width:%.2fem;height:%.2fem;border-radius:%s&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;,&lt;br /&gt;
        clamp(w[1]+jx,0,92), clamp(w[2]+jy,0,90), w[3]*grow*sz, w[4]*grow*sz, jitterR(h,i*5))&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  return table.concat(out)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- 裁切：每个图层都铺满纸张，仅在目标处留透明洞（配合 mask-composite:intersect）&lt;br /&gt;
-- 折角：45° 线性渐变，缺口两条直角边与折痕完全贴合&lt;br /&gt;
-- 缺口：椭圆簇切出指定长宽/位置的不规则孔洞&lt;br /&gt;
local CORNERGRAD = { tl=135, tr=225, br=315, bl=45 }&lt;br /&gt;
local CORNERLEG = 1.33&lt;br /&gt;
local function gapCores(src, h, base)&lt;br /&gt;
  local list = {}&lt;br /&gt;
  src = (src or &amp;#039;&amp;#039;):gsub(&amp;#039;；&amp;#039;,&amp;#039;;&amp;#039;):gsub(&amp;#039;，&amp;#039;,&amp;#039;,&amp;#039;):gsub(&amp;#039;　&amp;#039;,&amp;#039; &amp;#039;)&lt;br /&gt;
  local gi = 0&lt;br /&gt;
  for entry in mw.text.gsplit(src,&amp;#039;;&amp;#039;) do&lt;br /&gt;
    entry = trim(entry)&lt;br /&gt;
    if entry ~= &amp;#039;&amp;#039; then&lt;br /&gt;
      local body, pos = entry:match(&amp;#039;^(.-)@(.*)$&amp;#039;)&lt;br /&gt;
      if not body then body = entry end&lt;br /&gt;
      body = body:gsub(&amp;#039;×&amp;#039;,&amp;#039;x&amp;#039;):gsub(&amp;#039;%*&amp;#039;,&amp;#039;x&amp;#039;)&lt;br /&gt;
      local gw, gh = body:match(&amp;#039;([%d%.]+)%s*[x,]%s*([%d%.]+)&amp;#039;)&lt;br /&gt;
      if gw and gh then&lt;br /&gt;
        gi = gi + 1&lt;br /&gt;
        local w2, h2 = tonumber(gw), tonumber(gh)&lt;br /&gt;
        local gx, gy = 50, 50&lt;br /&gt;
        if pos then&lt;br /&gt;
          local px, py = pos:match(&amp;#039;([%d%.%-]+)%s*,%s*([%d%.%-]+)&amp;#039;)&lt;br /&gt;
          gx = tonumber(px) or 50  gy = tonumber(py) or 50&lt;br /&gt;
        end&lt;br /&gt;
        local seed = h + base + gi * 3571&lt;br /&gt;
        local n = 1 + (mix(seed, 51) % 3)&lt;br /&gt;
        local cores = {}&lt;br /&gt;
        for i = 1, n do&lt;br /&gt;
          local s = seed + i * 97&lt;br /&gt;
          local rx, ry, xe, ye&lt;br /&gt;
          if n == 1 then&lt;br /&gt;
            rx = (w2 / 2) * (0.95 + (mix(s, 56) % 11) / 100.0)&lt;br /&gt;
            ry = (h2 / 2) * (0.95 + (mix(s, 57) % 11) / 100.0)&lt;br /&gt;
            xe, ye = 0, 0&lt;br /&gt;
          else&lt;br /&gt;
            local ang = (mix(s, 54) % 6283) / 1000.0&lt;br /&gt;
            local off = 0.14 + (mix(s, 55) % 13) / 100.0&lt;br /&gt;
            xe = math.cos(ang) * (w2 / 2) * off&lt;br /&gt;
            ye = math.sin(ang) * (h2 / 2) * off&lt;br /&gt;
            rx = (w2 / 2) * (0.62 + (mix(s, 56) % 19) / 100.0)&lt;br /&gt;
            ry = (h2 / 2) * (0.62 + (mix(s, 57) % 19) / 100.0)&lt;br /&gt;
          end&lt;br /&gt;
          cores[#cores+1] = { rx=rx, ry=ry, xp=gx, xe=xe, yp=gy, ye=ye }&lt;br /&gt;
        end&lt;br /&gt;
        list[#list+1] = cores&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  return list&lt;br /&gt;
end&lt;br /&gt;
function p.cut(frame)&lt;br /&gt;
  local corners = trim(frame.args[1] or &amp;#039;&amp;#039;)&lt;br /&gt;
  local dmg = clamp(math.floor(tonumber(trim(frame.args[2] or &amp;#039;&amp;#039;)) or 0),0,8)&lt;br /&gt;
  local gaps = trim(frame.args[3] or &amp;#039;&amp;#039;)&lt;br /&gt;
  local h = contentSeed(frame.args[4], frame.args[5], frame.args[6])&lt;br /&gt;
  local layers = {}&lt;br /&gt;
  local function calcMix(pct, em)&lt;br /&gt;
    if em &amp;gt;= 0 then return string.format(&amp;#039;calc(%.2f%% + %.2fem)&amp;#039;, pct, em) end&lt;br /&gt;
    return string.format(&amp;#039;calc(%.2f%% - %.2fem)&amp;#039;, pct, -em)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  corners = corners:gsub(&amp;#039;，&amp;#039;,&amp;#039;,&amp;#039;):gsub(&amp;#039;、&amp;#039;,&amp;#039;,&amp;#039;):gsub(&amp;#039;；&amp;#039;,&amp;#039;;&amp;#039;)&lt;br /&gt;
  local seen = {}&lt;br /&gt;
  for entry in mw.text.gsplit(corners,&amp;#039;[,;]&amp;#039;) do&lt;br /&gt;
    local c = CORNERCLS[trim(entry)]&lt;br /&gt;
    if c and not seen[c] then&lt;br /&gt;
      seen[c] = true&lt;br /&gt;
      layers[#layers+1] = string.format(&amp;#039;linear-gradient(%ddeg,transparent 0 %.2fem,#000 %.2fem)&amp;#039;,&lt;br /&gt;
        CORNERGRAD[c], CORNERLEG, CORNERLEG + 0.02)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  local grow = 0.55 + 0.11*(dmg-1)&lt;br /&gt;
  for i = 1, dmg do&lt;br /&gt;
    local w = WEARPTS[i]&lt;br /&gt;
    if w then&lt;br /&gt;
      local jx = ((h+i*97)%23)-11&lt;br /&gt;
      local jy = ((h+i*131)%23)-11&lt;br /&gt;
      local sz = 0.65 + (mix(h+i,7)%81)/100.0&lt;br /&gt;
      local r = w[3]*grow*sz*0.52&lt;br /&gt;
      layers[#layers+1] = string.format(&amp;#039;radial-gradient(circle at %d%% %d%%,transparent %.2fem,#000 %.2fem)&amp;#039;,&lt;br /&gt;
        clamp(w[1]+jx,0,92), clamp(w[2]+jy,0,90), r, r*1.35)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  for _, cores in ipairs(gapCores(frame.args[3], h, 0)) do&lt;br /&gt;
    for _, c in ipairs(cores) do&lt;br /&gt;
      layers[#layers+1] = string.format(&amp;#039;radial-gradient(ellipse %.2fem %.2fem at %s %s,transparent 0 96%%,#000 100%%)&amp;#039;,&lt;br /&gt;
        c.rx, c.ry, calcMix(c.xp, c.xe), calcMix(c.yp, c.ye))&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  for _, cores in ipairs(gapCores(frame.args[7], h, 777)) do&lt;br /&gt;
    for _, c in ipairs(cores) do&lt;br /&gt;
      layers[#layers+1] = string.format(&amp;#039;radial-gradient(ellipse %.2fem %.2fem at %s %s,transparent 0 96%%,#000 100%%)&amp;#039;,&lt;br /&gt;
        c.rx, c.ry, calcMix(c.xp, c.xe), calcMix(c.yp, c.ye))&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if #layers == 0 then return &amp;#039;&amp;#039; end&lt;br /&gt;
  return &amp;#039;mask-image:&amp;#039;..table.concat(layers,&amp;#039;,&amp;#039;)..&amp;#039;;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.burnholes(frame)&lt;br /&gt;
  local h = contentSeed(frame.args[2], frame.args[3], frame.args[4])&lt;br /&gt;
  local out, idx = {}, 0&lt;br /&gt;
  local function calc(pct, em)&lt;br /&gt;
    if em &amp;gt;= 0 then return string.format(&amp;#039;calc(%.2f%% + %.2fem)&amp;#039;, pct, em) end&lt;br /&gt;
    return string.format(&amp;#039;calc(%.2f%% - %.2fem)&amp;#039;, pct, -em)&lt;br /&gt;
  end&lt;br /&gt;
  for _, cores in ipairs(gapCores(frame.args[1], h, 777)) do&lt;br /&gt;
    for _, c in ipairs(cores) do&lt;br /&gt;
      idx = idx + 1&lt;br /&gt;
      local function v(k) return 48 + ((mix(h + idx, 90 + k) % 9) - 4) end&lt;br /&gt;
      local radius = string.format(&amp;#039;%d%% %d%% %d%% %d%%&amp;#039;, v(1), v(2), v(3), v(4))&lt;br /&gt;
      out[#out+1] = string.format(&amp;#039;&amp;lt;span class=&amp;quot;limbo-paper-burnhole&amp;quot; style=&amp;quot;left:%s;top:%s;width:%.2fem;height:%.2fem;border-radius:%s&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;,&lt;br /&gt;
        calc(c.xp, c.xe), calc(c.yp, c.ye), (c.rx + 0.30) * 2, (c.ry + 0.30) * 2, radius)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  return table.concat(out)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.charb(frame)&lt;br /&gt;
  local h = instSeed(frame)&lt;br /&gt;
  local out = {}&lt;br /&gt;
  local function rad(seed, base)&lt;br /&gt;
    local function v(k) return 50 + ((mix(h, seed*7+k) % 33) - 16) end&lt;br /&gt;
    return string.format(&amp;#039;%d%% %d%% %d%% %d%%&amp;#039;, v(1), v(2), v(3), v(4))&lt;br /&gt;
  end&lt;br /&gt;
  local function pos(basePct, em)&lt;br /&gt;
    if em &amp;gt;= 0 then return string.format(&amp;#039;calc(%.1f%% + %.2fem)&amp;#039;, basePct, em) end&lt;br /&gt;
    return string.format(&amp;#039;calc(%.1f%% - %.2fem)&amp;#039;, basePct, -em)&lt;br /&gt;
  end&lt;br /&gt;
  local function push(x, y, wem, hhem, seed, a)&lt;br /&gt;
    out[#out+1] = string.format(&lt;br /&gt;
      &amp;#039;&amp;lt;span class=&amp;quot;limbo-paper-charb&amp;quot; style=&amp;quot;left:%.1f%%;top:%.1f%%;width:%.2fem;height:%.2fem;border-radius:%s;background-color:rgba(28,15,4,%.2f);transform:translate(-50%%,-50%%)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;,&lt;br /&gt;
      clamp(x,-4,104), clamp(y,-4,104), wem, hhem, rad(seed, math.max(0.18, hhem)), a)&lt;br /&gt;
  end&lt;br /&gt;
  local function pushAt(xstr, ystr, wem, hem, seed, a)&lt;br /&gt;
    out[#out+1] = string.format(&lt;br /&gt;
      &amp;#039;&amp;lt;span class=&amp;quot;limbo-paper-charb&amp;quot; style=&amp;quot;left:%s;top:%s;width:%.2fem;height:%.2fem;border-radius:%s;background-color:rgba(28,15,4,%.2f);transform:translate(-50%%,-50%%)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;,&lt;br /&gt;
      xstr, ystr, wem, hem, rad(seed, math.max(0.20, math.min(wem, hem))), a)&lt;br /&gt;
  end&lt;br /&gt;
  local function pushW(x, ystr, wpct, hhem, seed, a)&lt;br /&gt;
    out[#out+1] = string.format(&lt;br /&gt;
      &amp;#039;&amp;lt;span class=&amp;quot;limbo-paper-charb&amp;quot; style=&amp;quot;left:%.1f%%;top:%s;width:%.1f%%;height:%.2fem;border-radius:%s;background-color:rgba(28,15,4,%.2f);transform:translate(-50%%,-50%%)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;,&lt;br /&gt;
      clamp(x,-4,104), ystr, wpct, hhem, rad(seed, math.max(0.20, hhem)), a)&lt;br /&gt;
  end&lt;br /&gt;
  local function pushH(xstr, y, wem, hpct, seed, a)&lt;br /&gt;
    out[#out+1] = string.format(&lt;br /&gt;
      &amp;#039;&amp;lt;span class=&amp;quot;limbo-paper-charb&amp;quot; style=&amp;quot;left:%s;top:%.1f%%;width:%.2fem;height:%.1f%%;border-radius:%s;background-color:rgba(28,15,4,%.2f);transform:translate(-50%%,-50%%)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;,&lt;br /&gt;
      xstr, clamp(y,-4,104), wem, hpct, rad(seed, math.max(0.20, wem)), a)&lt;br /&gt;
  end&lt;br /&gt;
  local function edgeH(y, salt)&lt;br /&gt;
    local per = 26 + (mix(h+salt, 5) % 14)&lt;br /&gt;
    local step = 100.0/(per-1)&lt;br /&gt;
    for i = 0, per-1 do&lt;br /&gt;
      local t = i/(per-1)&lt;br /&gt;
      local x = t*100 + (((mix(h+i, 30+salt) % 100)/100.0) - 0.5) * step * 0.9&lt;br /&gt;
      local off = ((mix(h+i, 40+salt) % 350)/1000.0) - 0.10&lt;br /&gt;
      local ystr&lt;br /&gt;
      if y == 0 then ystr = pos(0, off) else ystr = pos(100, -off) end&lt;br /&gt;
      local pick = mix(h+i, 55+salt) % 10&lt;br /&gt;
      local w = step * (1.7 + (mix(h+i, 50+salt) % 90)/100.0)&lt;br /&gt;
      local hh&lt;br /&gt;
      if pick &amp;lt; 8 then&lt;br /&gt;
        hh = 0.30 + (mix(h+i, 60+salt) % 55)/100.0&lt;br /&gt;
      else&lt;br /&gt;
        hh = 0.35 + (mix(h+i, 60+salt) % 85)/100.0&lt;br /&gt;
      end&lt;br /&gt;
      pushW(x, ystr, w, hh, i*4+salt, 1)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  local function edgeV(x0, salt)&lt;br /&gt;
    local per = 26 + (mix(h+salt, 6) % 14)&lt;br /&gt;
    local step = 100.0/(per-1)&lt;br /&gt;
    for i = 0, per-1 do&lt;br /&gt;
      local t = i/(per-1)&lt;br /&gt;
      local y = t*100 + (((mix(h+i, 31+salt) % 100)/100.0) - 0.5) * step * 0.9&lt;br /&gt;
      local off = ((mix(h+i, 41+salt) % 350)/1000.0) - 0.10&lt;br /&gt;
      local xstr&lt;br /&gt;
      if x0 == 0 then xstr = pos(0, off) else xstr = pos(100, -off) end&lt;br /&gt;
      local pick = mix(h+i, 56+salt) % 10&lt;br /&gt;
      local hh = step * (1.7 + (mix(h+i, 61+salt) % 90)/100.0)&lt;br /&gt;
      local w&lt;br /&gt;
      if pick &amp;lt; 8 then&lt;br /&gt;
        w = 0.30 + (mix(h+i, 51+salt) % 55)/100.0&lt;br /&gt;
      else&lt;br /&gt;
        w = 0.35 + (mix(h+i, 51+salt) % 85)/100.0&lt;br /&gt;
      end&lt;br /&gt;
      pushH(xstr, y, w, hh, i*4+salt, 1)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  edgeH(0, 10)&lt;br /&gt;
  edgeH(100, 20)&lt;br /&gt;
  edgeV(0, 30)&lt;br /&gt;
  edgeV(100, 40)&lt;br /&gt;
  for i = 1, 14 do&lt;br /&gt;
    local side = i % 4&lt;br /&gt;
    local t = (mix(h+i, 81) % 92) + 4&lt;br /&gt;
    local inset = 0.12 + (mix(h+i, 82) % 45)/100.0&lt;br /&gt;
    local sz = 0.10 + (mix(h+i, 83) % 30)/100.0&lt;br /&gt;
    local xstr, ystr&lt;br /&gt;
    if side == 0 then xstr = string.format(&amp;#039;%.1f%%&amp;#039;, t) ystr = pos(0, inset)&lt;br /&gt;
    elseif side == 1 then xstr = string.format(&amp;#039;%.1f%%&amp;#039;, t) ystr = pos(100, -inset)&lt;br /&gt;
    elseif side == 2 then xstr = pos(0, inset) ystr = string.format(&amp;#039;%.1f%%&amp;#039;, t)&lt;br /&gt;
    else xstr = pos(100, -inset) ystr = string.format(&amp;#039;%.1f%%&amp;#039;, t) end&lt;br /&gt;
    pushAt(xstr, ystr, sz*2.2, sz, i*7+3, 0.88)&lt;br /&gt;
  end&lt;br /&gt;
  return table.concat(out)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.charring(frame)&lt;br /&gt;
  local h = instSeed(frame)&lt;br /&gt;
  local n = 96&lt;br /&gt;
  local function walk(seed)&lt;br /&gt;
    local t = 0.33&lt;br /&gt;
    local out = {}&lt;br /&gt;
    for i = 1, n do&lt;br /&gt;
      local r = (mix(h + i, seed) % 1000) / 1000.0&lt;br /&gt;
      t = t + (r * 2 - 1) * 0.055&lt;br /&gt;
      if t &amp;lt; 0.18 then t = 0.18 end&lt;br /&gt;
      if t &amp;gt; 0.48 then t = 0.48 end&lt;br /&gt;
      if (mix(h + i, seed + 7) % 100) &amp;lt; 8 then t = t + 0.09 end&lt;br /&gt;
      if t &amp;gt; 0.58 then t = 0.58 end&lt;br /&gt;
      out[i] = t&lt;br /&gt;
    end&lt;br /&gt;
    for pass = 1, 3 do&lt;br /&gt;
      local sm = {}&lt;br /&gt;
      for i = 1, n do&lt;br /&gt;
        local a = out[math.max(1, i-1)]&lt;br /&gt;
        local b = out[i]&lt;br /&gt;
        local c = out[math.min(n, i+1)]&lt;br /&gt;
        sm[i] = a*0.25 + b*0.5 + c*0.25&lt;br /&gt;
      end&lt;br /&gt;
      out = sm&lt;br /&gt;
    end&lt;br /&gt;
    return out&lt;br /&gt;
  end&lt;br /&gt;
  local T, R, B, L = walk(101), walk(211), walk(307), walk(401)&lt;br /&gt;
  local pts = {}&lt;br /&gt;
  local function pct(v) return string.format(&amp;#039;%.1f%%&amp;#039;, v) end&lt;br /&gt;
  local function em(v) return string.format(&amp;#039;%.2fem&amp;#039;, v) end&lt;br /&gt;
  local function right(v) return string.format(&amp;#039;calc(100%% - %.2fem)&amp;#039;, v) end&lt;br /&gt;
  local function bottom(v) return string.format(&amp;#039;calc(100%% - %.2fem)&amp;#039;, v) end&lt;br /&gt;
  pts[#pts+1] = &amp;#039;0% 0%&amp;#039;&lt;br /&gt;
  pts[#pts+1] = &amp;#039;100% 0%&amp;#039;&lt;br /&gt;
  pts[#pts+1] = &amp;#039;100% 100%&amp;#039;&lt;br /&gt;
  pts[#pts+1] = &amp;#039;0% 100%&amp;#039;&lt;br /&gt;
  pts[#pts+1] = &amp;#039;0% 0%&amp;#039;&lt;br /&gt;
  pts[#pts+1] = em(L[1]) .. &amp;#039; &amp;#039; .. em(T[1])&lt;br /&gt;
  for i = 2, n do&lt;br /&gt;
    pts[#pts+1] = em(L[i]) .. &amp;#039; &amp;#039; .. pct((i-1)*100/(n-1))&lt;br /&gt;
  end&lt;br /&gt;
  for i = 1, n do&lt;br /&gt;
    pts[#pts+1] = pct((i-1)*100/(n-1)) .. &amp;#039; &amp;#039; .. bottom(B[i])&lt;br /&gt;
  end&lt;br /&gt;
  for i = n, 1, -1 do&lt;br /&gt;
    pts[#pts+1] = right(R[i]) .. &amp;#039; &amp;#039; .. pct((i-1)*100/(n-1))&lt;br /&gt;
  end&lt;br /&gt;
  for i = n, 1, -1 do&lt;br /&gt;
    pts[#pts+1] = pct((i-1)*100/(n-1)) .. &amp;#039; &amp;#039; .. em(T[i])&lt;br /&gt;
  end&lt;br /&gt;
  pts[#pts+1] = em(L[1]) .. &amp;#039; &amp;#039; .. em(T[1])&lt;br /&gt;
  return &amp;#039;&amp;lt;span class=&amp;quot;limbo-paper-charring&amp;quot; style=&amp;quot;clip-path:polygon(&amp;#039; .. table.concat(pts, &amp;#039;,&amp;#039;) .. &amp;#039;)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.charstyle(frame)&lt;br /&gt;
  local h = instSeed(frame)&lt;br /&gt;
  local function v(seed, lo, hi) return lo + (mix(h, seed) % (hi-lo+1)) end&lt;br /&gt;
  return string.format(&amp;#039;style=&amp;quot;background-position:%d%% %d%%,%d%% %d%%;background-size:%d%% %d%%,%d%% %d%%&amp;quot;&amp;#039;,&lt;br /&gt;
    v(1,8,62), v(2,8,62), v(3,42,82), v(4,48,86),&lt;br /&gt;
    v(5,48,70), v(6,26,42), v(7,28,46), v(8,16,28))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.edge(frame)&lt;br /&gt;
  local kind = trim(frame.args[1] or &amp;#039;&amp;#039;)&lt;br /&gt;
  local h = instSeed(frame)&lt;br /&gt;
  local ampT, ampS&lt;br /&gt;
  if kind == &amp;#039;撕边&amp;#039; then ampT, ampS = 0.16, 0.06 else ampT, ampS = 0.14, 0.07 end&lt;br /&gt;
  local per = 26&lt;br /&gt;
  local pts = {}&lt;br /&gt;
  local function rnd(salt, amp) return amp * ((mix(h+salt, 11) % 1000)/1000.0) end&lt;br /&gt;
  local function p(v) return string.format(&amp;#039;%.1f%%&amp;#039;, v) end&lt;br /&gt;
  local function e(v) return string.format(&amp;#039;%.2fem&amp;#039;, v) end&lt;br /&gt;
  local function topEdge(salt) return e(0.01 + rnd(salt, ampT)) end&lt;br /&gt;
  local function bottomEdge(salt) return &amp;#039;calc(100% - &amp;#039;..e(0.01 + rnd(salt, ampT))..&amp;#039;)&amp;#039; end&lt;br /&gt;
  local function leftEdge(salt) return e(0.01 + rnd(salt, ampS)) end&lt;br /&gt;
  local function rightEdge(salt) return &amp;#039;calc(100% - &amp;#039;..e(0.01 + rnd(salt, ampS))..&amp;#039;)&amp;#039; end&lt;br /&gt;
  for i = 0, per do pts[#pts+1] = p(i*100/per)..&amp;#039; &amp;#039;..topEdge(i*3+1) end&lt;br /&gt;
  for i = 1, per do pts[#pts+1] = rightEdge(i*3+2)..&amp;#039; &amp;#039;..p(i*100/per) end&lt;br /&gt;
  for i = 1, per do pts[#pts+1] = p(100 - i*100/per)..&amp;#039; &amp;#039;..bottomEdge(i*3+3) end&lt;br /&gt;
  for i = 1, per do pts[#pts+1] = leftEdge(i*3+4)..&amp;#039; &amp;#039;..p(100 - i*100/per) end&lt;br /&gt;
  return &amp;#039;clip-path:polygon(&amp;#039;..table.concat(pts,&amp;#039;,&amp;#039;)..&amp;#039;);&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>晨茗biu～</name></author>
	</entry>
</feed>