封面图
玉清滴风小竹楼 玉清滴风小竹楼
今朝剑指叠云处

友链

在上一篇文章中,我们详细介绍了如何在绿联 NAS 上安装并配置 OpenClaw,体验了专属 AI 助手的便捷。但内置 MiniMax 模型免费体验期仅到 2026 年 4 月 13 日,到期后你需要更换其他大模型才能继续使用。同时,OpenClaw 还支持接入 QQ 平台,让你在手机或电脑的 QQ
绿联 NAS OpenClaw 进阶教程:自定义模型与接入 QQ 机器人

友链

一、安装与配置步骤 前置准备 在开始安装 OpenClaw 之前,请先前往绿联 NAS 的 “应用中心”,检查并确保 Docker 应用已更新至最新版本。 说明:OpenClaw 高度依赖 Docker 容器环境运行。若 Docker 版本过旧,可能会导致部署失败、权限配置错误或后续运行异常。 第一
绿联 NAS OpenClaw 安装指南,轻松部署专属 AI 助手

友链

晕死了!上周好不容易把Codex注册机给弄好了,结果在OpenCodeCodex App上用起来却老是跳403错误。我把CPA、CF、OpenResty这些都查了个遍,甚至一度怀疑是不是CPA没配对,可我就是万万没想到,竟然是1Panel自带的WAF搞的鬼😵‍💫!这下可好,原因找到了注册机也废了😤

友链

作者计划在春节回家期间升级家里的服务器,原本使用的是老旧的戴尔 R720XD,由于其性能不足,决定购买戴尔 R730XD 准系统,并在闲鱼上选购了内存、CPU 和硅脂等配件,总花费约 1409.7 元。旧服务器及内存条被出售,回血约 500 元。作者利用新服务器搭建了多个开源服务,包括 DDNS、VaultWarden、Jellyfin 等,用于家庭娱乐和远程办公需求。装机过程中遇到了功耗过高的问题,通过调整 BIOS 设置解决。此外,作者因公司放假通知延迟,未能改签车票,最终乘坐长途大巴返程,途中经历了超时运行被交警拦截的情况,但也结识了一位柳州大哥。文章结尾表达了对父亲的期望,希望他努力赚钱,减轻作者打工的负担,并以马年祝福结尾。
过年期间的事

友链

EasyChat 是一款基于 .NET 10 和 Avalonia 构建的现代化翻译工具,旨在解决高频跨语言沟通的难题,提供无缝流畅的交流体验。它通过集成 PaddleOCR 实现截图 OCR 翻译,支持在聊天窗口中自动翻译输入内容,并具备实时语音识别与翻译功能,可满足游戏玩家、影音爱好者及跨境交流等场景的需求。同时,软件支持多种翻译引擎,包括 AI 大模型与传统机器翻译,并计划引入语音合成功能以进一步提升交流便利性。
EasyChat 一款专为无障碍沟通打造的强大翻译软件[开源]

友链

问题背景 最近在使用 UG12(NX 12.0)软件时遇到了一个棘手的问题:每次启动软件都会弹出错误提示"捕获到标准C++异常,有关详细信息,请参见系统日志"。这个问题让我无法正常使用软件,经过一番排查和尝试,我终于找到了解决方案。 今天就把这个问题的完整解决过程分享给大家,希望能帮助到遇到同样问题

友链

背景 作为一个关注互联网热点的开发者,我经常需要在不同平台之间来回切换查看热搜榜——微博的热搜、知乎的热问、抖音的挑战话题、今日头条的资讯……每次都要打开多个应用,效率低下且容易遗漏重要信息。 市面上虽然有一些聚合工具,但要么收费、要么广告繁多、要么平台覆盖不全。后来我发现了一个宝藏 API ——
开源热搜监控工具,支持Docker一键部署,实时追踪微博知乎等45+平台,支持关键词筛选和邮件推送

友链

最近在搓一个Lyricify Lite类似物,原本使用渐变画刷实现歌词高亮,但是发现视觉效果与Apple Music相去甚远:单纯使用白色渐变画刷缺乏“高亮”的光照感觉,而Apple Music的歌词高亮则更像是有光线投射在歌词上,形成一种柔和的发光效果。

受到吕毅大佬的文章使用 WPF 做一个可以逼真地照亮你桌面的高性能阳光 - walterlv启发,遂尝试使用HLSL编写一个简单的文本高亮着色器。先来看实装在LemonLite中的效果:

整体上高亮文本与背景混色自然,渐变过渡由WPF动画驱动,高亮部分就有了光感。

以下是本文的最小可运行示例: ::github{repo="TwilightLemon/TextHighlighterTest"}

一、实现思路

简单说一下踩过的几个坑:

  1. 直接给TextBlock焊上Effect会导致文本像素化,变得模糊而且难以处理文本边界
  2. 使用VisualBrush,内部套一个Rectangle with Effect, 然后用这个VisualBrush作为TextBlock的Foreground,性能极差
  3. 给Rectangle with Effect做一个Clip裁剪出文本形状,性能可以,但是需要复刻TextBlock的排版逻辑

最终使用了第三种方案,并将其封装成一个用户控件。

如此一来,HLSL着色器要干的事情就很简单了:取一个高亮过渡位置pos,根据采样像素的X坐标计算光照强度,然后将这个强度与文本颜色做加法混合即可。

二、HLSL着色器代码

为了适配歌词高亮需求,我又追加了一些特性:

  1. 支持高亮颜色自定义
  2. 支持高亮宽度调整
  3. 支持切换高亮模式(加法混合/线性渐变)

以下是完整的HLSL代码:

sampler2D input : register(s0);

float HighlightPos : register(c0);
float HighlightWidth : register(c1);
float4 HighlightColor : register(c2);
float UseAdditive : register(c3); // 0 = lerp, 1 = additive
float HighlightIntensity : register(c4);

float4 main(float2 uv : TEXCOORD) : COLOR
{
    float4 color = tex2D(input, uv);
    float d = max(0, uv.x - HighlightPos);
    float glow = saturate(1 - d / HighlightWidth);
    glow = glow * glow;
    float intensity = glow * HighlightColor.a * HighlightIntensity;

    float3 lerpResult = lerp(color.rgb, HighlightColor.rgb, intensity);
    float lerpAlpha = lerp(color.a, 1.0, intensity);
    float3 additiveResult = color.rgb + HighlightColor.rgb * intensity;

    color.rgb = lerp(lerpResult, additiveResult, UseAdditive);
    color.a = lerp(lerpAlpha, color.a, UseAdditive);

    return color;
}
着色器输入参数 参数 作用 input 输入纹理(文本像素) HighlightPos 高亮过渡位置(0-1,从左到右, 当然也可以取负数) HighlightWidth 高亮衰减宽度(0-1) HighlightColor 高亮颜色(含透明度) UseAdditive 混合模式开关(0=线性渐变,1=加法混合) HighlightIntensity 高亮强度倍数 计算过程
  1. 采样 → 读取当前像素颜色
    color = tex2D(input, uv)
  2. 计算距离 → 像素X坐标与高亮位置的距离
    d = max(0, uv.x - HighlightPos)
  3. 计算光晕强度 → 根据距离生成平滑衰减
    glow = saturate(1 - d / HighlightWidth)
    glow = glow * glow // 平方处理,使衰减更陡峭
  4. 最终强度 = 光晕 × 颜色透明度 × 强度倍数
  5. 混合处理 → 根据UseAdditive选择混合方式
    • 线性渐变:在原色和高亮色间插值
    • 加法混合:直接叠加高亮色
函数说明
  • saturate(x) - 将值钳制在 [0, 1] 范围内
  • step(edge, x) - 如果 x < edge 返回 0,否则返回 1
  • lerp(a, b, t) - 线性插值,计算 a + (b-a)×t
  • tex2D(sampler, uv) - 从纹理采样指定坐标的像素
编译并加载着色器

编译HLSL代码生成.ps文件,然后在WPF中使用PixelShader类加载:

fxc /T ps_3_0 /E main /Fo TextGlow.ps TextGlow.hlsl

封装成Effect类此处不做赘述,只需要严格按照参数顺序传递即可。

三、WPF用户控件封装 核心出装

用一个 Rectangle 承载着色器效果,通过FormattedText生成文本的几何形状作为裁剪路径,这样WPF只会渲染文本区域并且保留清晰的文本边缘。

属性继承与元数据覆写

为了让高亮控件支持标准的文本属性(字体、大小、粗细等),使用了WPF的元数据覆写机制。在静态构造函数中对 FontFamilyFontSizeFontWeight 等属性进行 OverrideMetadata,绑定到统一的 OnTextPropertyChanged 回调。当这些属性变化时,触发文本裁剪的重新计算。类似地,Foreground 属性也被覆写,当文本颜色改变时直接更新 Rectangle 的填充颜色。

static HighlightTextBlock()
{
    FontFamilyProperty.OverrideMetadata(typeof(HighlightTextBlock),
        new FrameworkPropertyMetadata(SystemFonts.MessageFontFamily, OnTextPropertyChanged));
    FontSizeProperty.OverrideMetadata(typeof(HighlightTextBlock),
        new FrameworkPropertyMetadata(14.0, OnTextPropertyChanged));
    FontWeightProperty.OverrideMetadata(typeof(HighlightTextBlock),
        new FrameworkPropertyMetadata(FontWeights.Normal, OnTextPropertyChanged));
    ForegroundProperty.OverrideMetadata(typeof(HighlightTextBlock),
        new FrameworkPropertyMetadata(Brushes.Black, OnForegroundChanged));
}

private static void OnForegroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (d is HighlightTextBlock control)
        control.PART_Rectangle.Fill = e.NewValue as Brush;
}

这样用户就可以像使用普通 TextBlock 一样使用这个控件,享受XAML的属性绑定和样式系统。

文本排版与裁剪

UpdateTextClip() 方法负责:

  1. 创建排版对象 - 通过 FormattedText 将文本按照控件的字体、大小、样式参数进行排版,获得与实际渲染完全一致的文本度量
var formattedText = new FormattedText(
    Text,
    CultureInfo.CurrentCulture,
    FlowDirection,
    new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
    FontSize,
    Brushes.Black,
    VisualTreeHelper.GetDpi(this).PixelsPerDip);
  1. 处理换行与宽度约束 - 当启用 TextWrapping 时,从 WidthMaxWidthActualWidth 中取出约束宽度。只有在需要换行且有约束宽度的情况下,才设置 MaxTextWidth 让文本自动折行
var constraintWidth = !double.IsNaN(Width) && Width > 0
    ? Width
    : (!double.IsInfinity(MaxWidth) && MaxWidth > 0 ? MaxWidth : ActualWidth);

if (TextWrapping != TextWrapping.NoWrap && constraintWidth > 0)
    formattedText.MaxTextWidth = constraintWidth;
  1. 计算容器尺寸 - NoWrap下容器宽度就是文本宽度,换行模式下则为约束宽度,以确保 Rectangle 的大小与实际文本范围匹配
var containerWidth = TextWrapping == TextWrapping.NoWrap
    ? textWidth
    : (constraintWidth > 0 ? constraintWidth : textWidth);
  1. 处理文本对齐 - 根据 TextAlignment 计算文本相对于容器的起始偏移(用于居中和右对齐),然后生成Rectangle时传入这个偏移量,同时更新 Rectangle 的水平对齐属性使其与文本对齐方式一致
double offsetX = 0;
if (containerWidth > textWidth)
{
    offsetX = TextAlignment switch
    {
        TextAlignment.Center => (containerWidth - textWidth) / 2,
        TextAlignment.Right => containerWidth - textWidth,
        _ => 0
    };
}
  1. 生成并应用裁剪 - 调用 formattedText.BuildGeometry() 得到精确的文本轮廓Rectangle,设置为 Rectangle.Clip。这样着色器的输出就被限制在文本像素范围内
var geometry = formattedText.BuildGeometry(new Point(offsetX, 0));
PART_Rectangle.Clip = geometry;
PART_Rectangle.Width = containerWidth;
PART_Rectangle.Height = textHeight;
高亮参数的动画驱动

高亮效果的三个关键参数(HighlightPosHighlightWidthHighlightColor)都被暴露为依赖属性,在属性变化回调中直接同步到着色器 Effect 对象:

public static readonly DependencyProperty HighlightPosProperty =
    DependencyProperty.Register(
        nameof(HighlightPos),
        typeof(double),
        typeof(HighlightTextBlock),
        new PropertyMetadata(0.0, OnHighlightPosChanged));

private static void OnHighlightPosChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (d is HighlightTextBlock c)
        c._effect.HighlightPos = (double)e.NewValue;
}

这样就可以在XAML中轻松使用 StoryboardDoubleAnimation

<Storyboard>
    <DoubleAnimation
        Storyboard.TargetName="HighlightBlock"
        Storyboard.TargetProperty="HighlightPos"
        From="-0.2" To="1.2" Duration="0:0:2" RepeatBehavior="Forever" />
</Storyboard>

驱动 HighlightPos 的平滑变化,从而实现光线扫过文本的连贯动画效果。

四、看看效果

对比Additive叠加和Lerp线性渐变两种模式,可以看到Additive模式下高亮部分更亮更有光感,而Lerp模式尾段偏灰。

尝试使用彩色高亮,变成了混色效果。

写在最后

LemonLite正在龟速开发中,过程中遇到的各种问题和解决方案都会陆续写成博客分享出来,欢迎各位大佬持续关注。
什么!你问我开头的背景是怎么做的?见上一篇文章:WPF 使用GDI+提取图片主色调并生成Mica材质特效背景

参考资料:

    友链

    问题背景 在 Windows 中,你是否遇到过这样的情况:文件夹里出现了一个名为 nul 的文件,无法删除,删除时提示"MS-DOS功能无效"? 最近我在 Windows 使用 Claude Code 时,就遇到了这个问题。某个项目文件夹里多出了一个名为 nul 的文件,尝试删除时,系统弹出了错误提
    解决Windows中使用Cloude Code生成的nul文件无法删除的问题(MS-DOS功能无效)

    友链

    本文详细介绍了通过谷歌账号和信用卡订阅Gemini Pro等AI服务的流程。核心步骤包括:准备美国代理节点及全币种信用卡(推荐招商Visa卡);注册谷歌账号时切换英文界面;验证账号资格需修改地址和语言设置为美国英文;通过SheerId认证平台(需注意可能收费)完成资格验证;绑定信用卡后订阅服务;最后取消订阅以避免年度扣费。文中特别提醒需警惕代理节点风险、IP被封问题及银行推销陷阱,建议使用指纹浏览器或更换节点解决认证失败,并附有相关链接供参考。
    白嫖谷歌学生会员一年 Gemini Pro / Google One

    友链

    用户因租房使用的联通宽带突然无法连接到老家的电信公网IP,怀疑是上游网络被运营商阻断。经过排查,发现所有网络请求在抵达10.218.32.1节点后断开,推测为本地网络出口限制。用户曾因跑PT(点对点文件传输)产生大量上行流量,虽未被限速,但仍被要求签署承诺书以解除阻断。运营商处理态度消极,引发强烈不满。用户计划通过代理解决网络问题,并表达了对运营商的愤怒与失望。
    联通宽带疑似阻断了我与电信公网的通信

    友链

    本文介绍了多个适用于Jellyfin的影视和音乐客户端推荐。影视客户端方面,PC端推荐Fladder,因其解码能力强、跨平台支持好;安卓端推荐Findroid、Ghosten Player、Fladder和Streamyfin,其中Ghosten Player和Fladder较为实用;iOS端推荐Swiftfin和Stream Music,但功能较少;Android TV端则有官方客户端和Ghosten Player等选择。音乐客户端主要推荐Feishin、NSMusicS和Stream Music,其中Stream Music在移动端表现最佳。总体建议用户根据自身需求和平台选择合适的客户端,并前往推荐仓库查看更多细节。
    Jellyfin 客户端推荐 PC / Android / iOS / TV

    友链

    C# 在2025年再次被评为年度编程语言,这是它三年内第二次获得此荣誉,主要因其年度排名涨幅最大。C#在语言设计上不断采纳新趋势,实现了从Windows专属到跨平台、从微软专有到开源的两次重大转型。与此同时,C语言与C++排名互换,R语言因数据科学需求重回前十,而Go和Ruby则分别跌出前十与前20。预计TypeScript将在2026年进入前20,Zig也有望进入前30。
    C# 荣获 2025 年度编程语言