Files
workbuddy_skills/oil-ui-pro/assets/cards/flow-object/material.js
T
admin d9445b5888 oil-ui-pro 0.15.4 → 0.22.2(上游 ui.oiloil.org 正式包)+ 记 P0-98 跨盘 rename 坑
- oil-ui-pro 升到 0.22.2:references 13→28 份(新增 16、删 imagery.md)、assets 增 cards/(22 组)与 fonts/、SKILL.md 顶层五步结构未改名。
- 升级路径:官方 `npx github:oil-oil/oil-cli update` 稳定失败(error=replace、报「检查目录权限」)。
  真身为 EXDEV —— 解压在 os.tmpdir()(C 盘)、技能目录在 E 盘,Windows 上 rename 不能跨盘;
  CLI 的 catch 把非 CliError 原生异常一律兜底成 replaceFailed,真错误一个字不吐。
  做法=借其 prepare() 只做下载+校验,再 cp 到同盘 stage、rename 交换;官方命令复验 up_to_date。
- 回归:product-planning 按名引用的 visual-review.md/tools.md/design-direction.md/style-explorer.md 全部健在;命名闸门 2061|0|27。
- session-mechanism/references/pitfalls.md 新增 P0-98(含通则:更新器把原生错误兜底成指错方向的人话)。
2026-10-14 10:21:46 +08:00

78 lines
3.8 KiB
JavaScript

import {glProgram, glNoise, glColor} from '../shared/runtime.js';
// One coated surface, not a stack of ribbons. Paint stays still; light travels.
const vertex = `attribute vec2 a_position;varying vec2 v_uv;
void main(){v_uv=a_position*.5+.5;gl_Position=vec4(a_position,0.,1.);}`;
const fragment = `precision highp float;
varying vec2 v_uv;uniform vec2 u_resolution,u_pointer;
uniform float u_time;uniform vec3 u_a,u_b,u_c;
${glNoise}
${glColor}
float bell(float d,float w){return exp(-d*d/(w*w));}
void main(){
// Fit the field to the short side: a wider host reveals more of the material.
vec2 uv=vec2(v_uv.x,1.-v_uv.y);
vec2 p=(uv-.5)*u_resolution/min(u_resolution.x,u_resolution.y);
float grain=hash(gl_FragCoord.xy)-.5;
float dye=p.y+.42*p.x+.07*sin(p.x*2.1);
vec3 color=mix(lab(u_b),lab(u_a),smoothstep(-.48,.30,dye));
// Warm pigment is a broad off-centre pool, not another repeated band.
float warm=smoothstep(-.01,.43,p.y+.18*p.x-.12*sin(p.x*2.));
color=mix(color,lab(u_c),warm);
color=mix(color,lab(vec3(1.)),.18+.09*bell(dye+.52,.40));
float drift=.055*sin(u_time*.32)+u_pointer.x*.065-u_pointer.y*.035;
float d=p.y+.43*p.x-.065*p.x*p.x+.10-drift;
// One narrow glint nested inside an asymmetric, much wider bloom.
float width=max(1.6/min(u_resolution.x,u_resolution.y),.005);
float glint=bell(d,width*1.5);
float shoulder=bell(d-.012,.035)*.20;
float bloom=bell(d-.055,.14)*.29;
float envelope=.66+.34*bell(p.x-.10-.22*sin(u_time*.19),.85);
float brushed=simplex(vec2(p.x*.9,d*220.));
float echo=bell(d+.038+.008*sin(p.x*4.),.014)*.07;
float grazing=(glint*.29+shoulder+bloom+echo)*envelope;
color=mix(color,lab(vec3(1.)),clamp(grazing,0.,.78));
// A broad reflected softbox moves independently of the pigment boundary.
float softbox=bell(p.x*.70-p.y*.22+.27*sin(u_time*.25)+u_pointer.x*.14,.52);
color.x+=softbox*.035;
color.x+=brushed*.009*bell(d,.14);
vec3 outcolor=srgb(color)+grain*.020;
gl_FragColor=vec4(outcolor,1.);
}`;
export function coatedSurface(canvas) {
let gpu, uniforms, lastFrame=null, disposed=false;
// Use the untransformed plane, so tilting the host cannot stretch its grain.
const resize=()=>{
const dpr=Math.min(devicePixelRatio || 1,2.5);
const w=Math.max(1,Math.round(canvas.clientWidth*dpr)),h=Math.max(1,Math.round(canvas.clientHeight*dpr));
if(canvas.width!==w || canvas.height!==h){canvas.width=w;canvas.height=h;}
};
const initialize=()=>{
gpu=glProgram(canvas,vertex,fragment);
canvas.dataset.renderer=gpu?'webgl':'css';
if(!gpu)return;
gpu.attribute('a_position',[-1,-1,1,-1,-1,1,-1,1,1,-1,1,1],2);
uniforms=Object.fromEntries(['resolution','pointer','time','a','b','c'].map(n=>[n,gpu.uniform('u_'+n)]));
resize();
};
const lost=e=>{if(disposed)return;e.preventDefault();gpu=null;canvas.dataset.renderer='css';};
const restored=()=>{if(!disposed){initialize();if(lastFrame)draw(...lastFrame);}};
canvas.addEventListener('webglcontextlost',lost);
canvas.addEventListener('webglcontextrestored',restored);
initialize();
function draw(time,palette,pointer=[0,0]){
lastFrame=[time,palette,pointer];
if(!gpu || !palette || disposed)return;
const {gl}=gpu;gl.useProgram(gpu.program);gl.viewport(0,0,canvas.width,canvas.height);
gl.uniform2f(uniforms.resolution,canvas.width,canvas.height);
gl.uniform2f(uniforms.pointer,...pointer);gl.uniform1f(uniforms.time,time);
for(const n of ['a','b','c'])gl.uniform3fv(uniforms[n],palette[n]);
gl.drawArrays(gl.TRIANGLES,0,6);
}
return {
resize,draw,
destroy(){if(disposed)return;disposed=true;canvas.removeEventListener('webglcontextlost',lost);canvas.removeEventListener('webglcontextrestored',restored);gpu?.destroy();gpu=null;lastFrame=null;canvas.width=canvas.height=1;delete canvas.dataset.renderer;}
};
}