#!/usr/bin/env python3 """Render the maintained Markdown guide into a self-contained HTML document.""" from pathlib import Path import re,html,json,base64 ROOT=Path(__file__).resolve().parents[1] source=ROOT/'colorBlock-level-editor/docs/SCREENSHOT_RECOGNITION_EXPLAINED.md' # This small renderer supports precisely the tables/headings/lists/code in this guide. def inline(s): s=html.escape(s);s=re.sub(r'`([^`]+)`',r'\1',s);return re.sub(r'\*\*([^*]+)\*\*',r'\1',s) lines=source.read_text().splitlines();out=[];toc=[];i=0 while i'+html.escape('\n'.join(block))+'');i+=1;continue if line.startswith('#'): level=len(line)-len(line.lstrip('#'));title=line[level:].strip();id='section-'+str(len(toc)) if level==2 else 'h-'+str(i) if level==2:toc.append((id,title)) if level>1:out.append(f'{inline(title)}') i+=1;continue if line.startswith('|'): rows=[] while i'+''.join('' for c in rows[0])+''+''.join(''+''.join('' for c in row)+'' for row in rows[1:])+'
'+inline(c)+'
'+inline(c)+'
');continue if re.match(r'(- |\d+\. )',line): tag='ul' if line.startswith('-') else 'ol';items=[] while i'+''.join('
  • '+inline(c)+'
  • ' for c in items)+'');continue paragraph=[] while i'+inline(' '.join(paragraph))+'

    ') result=json.loads((ROOT/'outputs/editor-level19-20261015/result.json').read_text()) grid=result['inspections'][0]['grid'];old={'cols':6,'rows':10,'corners':[[152.5197,338],[646.7146,338],[661.6781,1130],[127.5033,1130]],'rowCurve':-.154803758} def point(g,c,r): u=c/g['cols'];t=r/g['rows'];v=t+g['rowCurve']*t*(t-1);a,b,d,e=g['corners'];return [(1-v)*((1-u)*a[j]+u*b[j])+v*((1-u)*e[j]+u*d[j]) for j in (0,1)] def grid_svg(g): poly=[] for c in range(g['cols']+1):poly.append([point(g,c,r/4) for r in range(g['rows']*4+1)]) for r in range(g['rows']+1):poly.append([point(g,0,r),point(g,g['cols'],r)]) return ''.join('' for ps in poly) img=base64.b64encode(Path('/Users/ruoruo/Desktop/截屏2026-10-15 19.37.51.png').read_bytes()).decode() figure=f'''
    用这关看网格边界

    门在网格外,方块在网格内。

    切换查看同一原图上的修复前后网格。旧网格把顶门算入高度,造成6×10;修复后为6×9,并保留轻微透视。

    这是原始图片与程序计算网格的叠加示意;不替代浏览器操作验收。下方记录完整算法与限制。

    {grid_svg(grid)}
    ''' css='''*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:#f3f1ea;color:#223236;font:16px/1.85 -apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif}header{background:#133c39;color:#f6f3e6;padding:64px max(24px,calc((100vw - 1120px)/2)) 42px}header h1{font-size:38px;line-height:1.4;margin:16px 0}header p{max-width:720px;color:#d1e1d8}.eyebrow{letter-spacing:2px;font-size:12px;text-transform:uppercase;color:#95b4a6}.metrics{display:flex;gap:12px;flex-wrap:wrap;margin-top:30px}.metrics div{padding:14px 25px;border:1px solid #54736a;border-radius:8px}.metrics strong{font-size:27px;margin-right:8px}.comparison{max-width:1120px;margin:32px auto;padding:32px;background:#fffdf7;display:grid;grid-template-columns:1fr 380px;gap:36px;border-radius:12px}.comparison h2{border:0;margin-top:16px}.comparison svg{width:100%;max-height:510px;border-radius:8px}.switch{display:flex;gap:12px;flex-wrap:wrap}button{font:inherit;padding:10px 16px;border:1px solid #739488;background:transparent;color:#234740;border-radius:6px;cursor:pointer}button[aria-pressed=true]{background:#164d43;color:white}.note{font-size:13px;color:#67766d}.layout{display:grid;grid-template-columns:220px minmax(0,850px);gap:40px;max-width:1120px;margin:40px auto 100px}nav{position:sticky;top:24px;align-self:start;font-size:13px}nav a{display:block;padding:7px 0;color:#35584c;text-decoration:none}nav a:hover{text-decoration:underline}article{background:#fffdf7;border-radius:12px;padding:32px 42px;min-width:0}h2{font-size:24px;line-height:1.5;border-top:1px solid #d5ddd4;padding-top:30px;margin-top:44px;scroll-margin-top:20px}h3{font-size:18px;color:#266251;margin-top:28px}p{margin:16px 0}strong{color:#204e42}header strong{color:#fff5d8}code{font:13px/1.6 ui-monospace,Menlo,monospace;background:#eaf0e8;padding:2px 5px;border-radius:4px;overflow-wrap:anywhere}pre{overflow-x:auto;background:#1c3735;color:#e1f0e2;padding:22px;border-radius:8px}pre code{background:none;color:inherit;padding:0;overflow-wrap:normal}.table{overflow-x:auto}table{border-collapse:collapse;font-size:13px;min-width:100%}th,td{padding:11px 12px;text-align:left;border-bottom:1px solid #d9dfd5}th{background:#e9efe5;color:#264b40}li{padding:4px 0}footer{text-align:center;padding:26px;font-size:13px;color:#637269}@media(max-width:900px){.layout{display:block;margin:20px}.comparison{grid-template-columns:1fr;margin:20px;padding:24px}.comparison svg{max-height:480px}nav{position:static;margin-bottom:24px;columns:2}article{padding:20px}header{padding:30px 24px}header h1{font-size:30px}}@media print{nav,.switch{display:none}.layout{display:block}.comparison{break-inside:avoid}body,article{background:white}header{padding:25px}article{padding:0}h2{break-after:avoid}tr{break-inside:avoid}}''' page='本地截图识别 · 方法与第19关修复
    ColorBlock Studio / 0.19.3 / 2026.10.19

    一张截图,怎样变成可编辑关卡

    从像素、透视网格到方块与门。以第19关解释完整实现、错误原因、修复方式,以及补图真正能提供的信息。

    6 × 9可玩网格
    27方块
    8门
    10 / 10冻结块初值
    '+figure+'
    '+''.join(out)+'
    本地离线文档 · 不加载外部资源 · 原图不修改 · 开发样本不等于独立准确率
    ' (ROOT/'colorBlock-level-editor/docs/SCREENSHOT_RECOGNITION_EXPLAINED.html').write_text(page) print('Wrote self-contained guide',len(page),'characters')