惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

量子位
F
Fortinet All Blogs
J
Java Code Geeks
Y
Y Combinator Blog
Stack Overflow Blog
Stack Overflow Blog
V
Visual Studio Blog
M
MIT News - Artificial intelligence
腾讯CDC
Last Week in AI
Last Week in AI
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Jina AI
Jina AI
Microsoft Security Blog
Microsoft Security Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
P
Proofpoint News Feed
博客园 - 叶小钗
Recent Announcements
Recent Announcements
T
Tailwind CSS Blog
Engineering at Meta
Engineering at Meta
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
人人都是产品经理
人人都是产品经理
L
LangChain Blog
博客园 - 司徒正美
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

Hacker News: Show HN

PurrrrrFocus: Pomodoro Timer App - App Store Workflow Engine — Multi-Step Orchestration for Bun RapidPhoto: Pro Photo Editor App - App Store GitHub - DheerG/swarms: Achieve extraordinary results with claude code across a variety of tasks SPICE simulation → oscilloscope → verification with Claude Code — Lucas Gerads Show HN: VCoding – A 5 MB native Windows IDE with no dynamic dependencies Show HN: LLMs don't hallucinate because they're bad at math, it's the format GitHub - Agent-FM/agentfm-core: AgentFM is a peer-to-peer network that turns everyday computers into a decentralized AI supercomputer. AgentFM lets you run massive AI workloads directly across a global mesh of idle CPUs and GPUs. Show HN: Tracking Top US Science Olympiad Alumni over Last 25 Years GitHub - Potarix/agent-hub: One place to talk to all your agents Show HN: Runtime security for AI agents(injection,tool abuse, data exfiltration) GitHub - dubeyKartikay/lazyspotify: Terminal Spotify client for macOS and Linux GitHub - the-banana-tool/king-louie: Easy to use GUI Personal AI Assistant. Win/Linux/Mac. Show HN I made my vacation rental bookable by AI agents–no Airbnb, 0% commission GitHub - basteez/jsf-autoreload: maven plugin to enable hot reload on jsf projects uvm32/hosts/host-gdbstub at main · ringtailsoftware/uvm32 GitHub - labsai/EDDI: Config-driven engine that turns JSON into production-grade AI agents. Multi-agent orchestration, 12+ LLM providers, MCP/A2A protocols, RAG, persistent memory, and enterprise compliance (EU AI Act, GDPR, HIPAA). Built on Quarkus. GitHub - glitchnsec/fortyone-oss: AI Executive Assistant Platform Quickstart | Alien GitHub - muxshed/shed: One stream in, or many. Every destination, simultaneously. No cloud middleman, no per-channel fees, no limits. GitHub - ocrbase-hq/ocrbase: 📄 PDF/IMG ->.MD/JSON Document OCR API for PaddleOCR and GLMOCR. Self-hostable. GitHub - impactjo/home-memory: MCP server that lets your AI assistant remember everything about your home. GitHub - Sets88/dbcls: DbCls is a powerful terminal database client that supports various databases GitHub - neptun2000/heor-agent-mcp GitHub - SeanFDZ/macmind: Single-layer transformer in HyperTalk for the classic Macintosh RollQuation: Math Puzzles - Apps on Google Play GitHub - dropbox/witchcraft Show HN: Agent-cache – Multi-tier LLM/tool/session caching for Valkey and Redis GitHub - opentalon/opentalon: OpenTalon is an open-source platform built from the ground up in Go as a robust alternative to OpenClaw LinkedIn™ 职位抓取工具 - Chrome 应用商店
javascript tutorial
h1yapp · 2026-06-24 · via Hacker News: Show HN
javascript is the standard programming language for the browser.

quaternion 3d

hello world[blob uri]

code

<!doctype html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width'><style>
body{background-color:#ffffffff;color:#000000ff}
@media(prefers-color-scheme:dark){body{background-color:#000000ff;color:#ffffffff}}
</style>
<script>{
    console.log(`hello world`)//hello world
}</script></head></html>

operations[blob uri]

code

<!doctype html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width'><style>
body{background-color:#ffffffff;color:#000000ff}
@media(prefers-color-scheme:dark){body{background-color:#000000ff;color:#ffffffff}}
</style>
<script>{
    const augend=1,addend=2,sum=3
    console.log(`--addition-- augend + addend === sum`)
    console.log(`${augend} + ${addend} = ${sum}`)//1 + 2 = 3
    console.log(augend+addend===sum)//true
    const minuend=3,subtrahend=2,difference=1
    console.log(`--subtraction-- minuend - subtrahend === difference`)
    console.log(`${minuend} - ${subtrahend} = ${difference}`)//3 - 2 = 1
    console.log(minuend-subtrahend===difference)//true
    const multiplicand=2,multiplier=3,product=6
    console.log(`--multiplication-- multiplicand * multiplier === product`)
    console.log(`${multiplicand} * ${multiplier} = ${product}`)//2 * 3 = 6
    console.log(multiplicand*multiplier===product)//true
    const dividend=6,divisor=3,quotient=2
    console.log(`--division-- dividend / divisor === quotient`)
    console.log(`${dividend} / ${divisor} = ${quotient}`)//6 / 3 = 2
    console.log(dividend/divisor===quotient)//true
    const remainder=0
    console.log(`--division(modulo)-- dividend % divisor === remainder`)
    console.log(`${dividend} % ${divisor} = ${remainder}`)//6 % 3 = 0
    console.log(dividend%divisor===remainder)//true
    const base=3,exponent=2,power=9
    console.log(`--exponentiation-- base ** exponent === power`)
    console.log(`${base} ** ${exponent} = ${power}`)//3 ** 2 = 9
    console.log(base**exponent===power)//true
    const radicand=9,root=3
    console.log(`--square root-- Math.sqrt(radicand) === root`)
    console.log(`√${radicand} = ${root}`)//√9 = 3
    console.log(Math.sqrt(radicand)===root)//true
}</script></head></html>

bitwise operations[blob uri]

code

<!doctype html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width'><style>
body{background-color:#ffffffff;color:#000000ff}
@media(prefers-color-scheme:dark){body{background-color:#000000ff;color:#ffffffff}}
</style>
<script>{
    console.log((0|0b00000000000000000000000000000001)===0b01)//true
    console.log((0|0b11111111111111111111111111111110)===-0b10)//true
    console.log((0|0b01111111111111111111111111111111)===2147483647)//true
    console.log(`--not-- ~0b01 = -0b10`)
    console.log(~0b01===-0b10)//true
    console.log(`--and-- (0b01 & 0b11) = 0b01`)
    console.log((0b01&0b11)===0b01)//true
    console.log(`--xor-- (0b01 ^ 0b11) = 0b10`)
    console.log((0b01^0b11)===0b10)//true
    console.log(`--or-- (0b01 | 0b11) = 0b11`)
    console.log((0b01|0b11)===0b11)//true
    console.log(`--left shift-- 0b01<<1=0b10`)
    console.log(0b01<<1===0b10)//true
    console.log(`--right shift-- 0b11>>1=0b01`)
    console.log(0b11>>1===0b01)//true
    console.log(`--unsigned right shift-- -0b10>>>1=2147483647`)
    console.log(-0b10>>>1===2147483647)//true
}</script></head></html>

Array[blob uri]

code

<!doctype html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width'><style>
body{background-color:#ffffffff;color:#000000ff}
@media(prefers-color-scheme:dark){body{background-color:#000000ff;color:#ffffffff}}
</style>
<script>{
    console.log(`--Array--`)
    console.log([])//[]
    console.log([0])//[0]
    console.log(Array(1))//[empty]
    console.log(Array(0,1))//[0, 1]
    console.log(`--push, pop, reverse--`)
    const vs=[]
    console.log(vs.push(0))//1
    console.log(vs)//[0]
    console.log(vs.push(1,2))//3
    console.log(vs)//[0, 1, 2]
    console.log(vs[1]=3)//3
    console.log(vs)//[0, 3, 2]
    console.log(vs.pop())//2
    console.log(vs)//[0, 3]
    console.log(vs.reverse())//[3, 0]
    console.log(vs)//[3, 0]
    console.log(`--isArray--`)
    console.log(Array.isArray([]))//true
    console.log(`--equals--`)
    Array.prototype.equals=function(v){
        return v.length===this.length&&v.every((v,i)=>v===this[i])
    }
    console.log(Object.getOwnPropertyDescriptor(Array.prototype,'equals'))//{'writable': true,'enumerable': true,'configurable': true}
    console.log([].equals([]))//true
}</script></head></html>

binary search[blob uri, how to use, logic]

code

<!doctype html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width'><style>
body{background-color:#ffffffff;color:#000000ff}
@media(prefers-color-scheme:dark){body{background-color:#000000ff;color:#ffffffff}}
</style>
<script>{
    Number.prototype.toBinarySearchIndex=function(l,c){
        let v=0
        for(let i;1<l-v;)this<c(i=v+l>>>1)?l=i:v=i
        return v
    }
    const vs=[0,2,4,6,8]
    console.log((0).toBinarySearchIndex(vs.length,i=>vs[i]))//0
    console.log((2).toBinarySearchIndex(vs.length,i=>vs[i]))//1
    console.log((6).toBinarySearchIndex(vs.length,i=>vs[i]))//3
}</script></head></html>

split from[blob uri, how to use, logic]

code

<!doctype html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width'><style>
body{background-color:#ffffffff;color:#000000ff}
@media(prefers-color-scheme:dark){body{background-color:#000000ff;color:#ffffffff}}
</style>
<script>{
    String.prototype.splitFrom=function(pattern){
        const vs=[]
        vs.length=1+this.length-this.matchAll(RegExp(pattern,`g`)).reduce((a,v)=>a+(vs[v.index-a]=v[0]).length,0)
        return vs
    }
    console.log(`,1,,,,"5",,"""7""",,`.splitFrom(`"(?:""|[^"])*"|[^,]+`))//[empty, '1', empty × 3, '"5"', empty, '"""7"""', empty × 2]
}</script></head></html>

ordinalize[blob uri, how to use, logic]

code

<!doctype html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width'><style>
body{background-color:#ffffffff;color:#000000ff}
@media(prefers-color-scheme:dark){body{background-color:#000000ff;color:#ffffffff}}
</style>
<script>{
    Number.prototype.ordinalize=function(){
        return(this+`th`).replace(/(?<!1)[123]th$/,v=>`1th`===v?`1st`:`2th`===v?`2nd`:`3rd`)
    }
    console.log([0,1,2,3,4,10,11,12,13,14,100,111,122,133,144].map(v=>v.ordinalize()))//['0th', '1st', '2nd', '3rd', '4th', '10th', '11th', '12th', '13th', '14th', '100th', '111th', '122nd', '133rd', '144th']
}</script></head></html>

recursion[blob uri]

code

<!doctype html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width'><style>
body{background-color:#ffffffff;color:#000000ff}
@media(prefers-color-scheme:dark){body{background-color:#000000ff;color:#ffffffff}}
</style>
<script>{
    console.log(`--factorial--`)
    Number.prototype.toFactorial=function(){
        return 1<this?this*(this-1).toFactorial():1
    }
    console.log((10).toFactorial())//3628800
    console.log(`--greatest common divisor--`)
    Number.prototype.toGCD=function(v){
        return v?v.toGCD(this%v):this
    }
    console.log((16).toGCD(24))//Number {8}
}</script></head></html>

SubtleCrypto[blob uri, how to use]

code

<!doctype html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width'><style>
body{background-color:#ffffffff;color:#000000ff}
@media(prefers-color-scheme:dark){body{background-color:#000000ff;color:#ffffffff}}
</style>
<script>{
    if(!crypto.subtle)throw Error(`available in secure contexts.`)
    const encoder=new TextEncoder(),decoder=new TextDecoder()
    ,aes=async(string,object,hashObject)=>{
        const key=await generateKey(object.lengthParams,[`encrypt`])
        ,encrypted=await crypto.subtle.encrypt(object.params,key,encoder.encode(string))
        ,exportedKey=await crypto.subtle.exportKey(object.format,key)
        ,decrypted=await crypto.subtle.decrypt(object.params,await importKey(object.format,exportedKey,object.algorithm,[`decrypt`]),encrypted)
        if(hashObject){
            const verified=await verify(hashObject,encrypted)
            return[object.algorithm.name,decoder.decode(decrypted),verified]
        }else return[object.algorithm.name,decoder.decode(decrypted)]
    }
    ,rsa=async(string,object)=>{
        const keys=await generateKey(object.lengthParams,[`encrypt`,`decrypt`])
        ,encrypted=await crypto.subtle.encrypt(object.algorithm,keys.publicKey,encoder.encode(string))
        ,exportedKey=await crypto.subtle.exportKey(object.format,keys.privateKey)
        ,decrypted=await crypto.subtle.decrypt(object.algorithm,await importKey(object.format,exportedKey,object.params,[`decrypt`]),encrypted)
        return[object.algorithm.name,decoder.decode(decrypted)]
    }
    ,generateKey=async(params,usages)=>await crypto.subtle.generateKey(params,true,usages)//extractable=true
    ,importKey=async(format,key,params,usages)=>await crypto.subtle.importKey(format,key,params,false,usages)//extractable=false
    ,verify=async(object,encrypted)=>{
        const key=await generateKey(object.params,[`sign`])
        ,signature=await crypto.subtle.sign(object.algorithm,key,encrypted)
        ,exportedKey=await crypto.subtle.exportKey(object.format,key)
        return crypto.subtle.verify(object.algorithm,await importKey(object.format,exportedKey,object.params,[`verify`]),signature,encrypted)
    }
    (async()=>{
        const string=`hello world`
        ,aesCTRObject={algorithm:{name:`AES-CTR`},params:{counter:crypto.getRandomValues(new Uint8Array(16)),length:64},lengthParams:{length:128},format:`raw`}
        ,aesCTRHashObject={algorithm:{name:`HMAC`},params:{hash:`SHA-256`},format:`raw`}
        ,aesCBCObject={algorithm:{name:`AES-CBC`},params:{iv:crypto.getRandomValues(new Uint8Array(16))},lengthParams:{length:128},format:`raw`}
        ,aesCBCHashObject={algorithm:{name:`HMAC`},params:{hash:`SHA-256`},format:`raw`}
        ,aesGCMObject={algorithm:{name:`AES-GCM`},params:{iv:crypto.getRandomValues(new Uint8Array(12))},lengthParams:{length:128},format:`raw`}
        ,rsaOAEPObject={algorithm:{name:`RSA-OAEP`},params:{hash:`SHA-256`},lengthParams:{modulusLength:2048,publicExponent:new Uint8Array([0x01,0x00,0x01])},format:`pkcs8`}
        Object.assign(aesCTRObject.params,aesCTRObject.algorithm)
        Object.assign(aesCTRObject.lengthParams,aesCTRObject.algorithm)
        Object.assign(aesCTRHashObject.params,aesCTRHashObject.algorithm)
        Object.assign(aesCBCObject.params,aesCBCObject.algorithm)
        Object.assign(aesCBCObject.lengthParams,aesCBCObject.algorithm)
        Object.assign(aesCBCHashObject.params,aesCBCHashObject.algorithm)
        Object.assign(aesGCMObject.params,aesGCMObject.algorithm)
        Object.assign(aesGCMObject.lengthParams,aesGCMObject.algorithm)
        Object.assign(rsaOAEPObject.params,rsaOAEPObject.algorithm)
        Object.assign(rsaOAEPObject.lengthParams,rsaOAEPObject.params)
        console.log(await aes(string,aesCTRObject,aesCTRHashObject))//['AES-CTR', 'hello world', true]
        console.log(await aes(string,aesCBCObject,aesCBCHashObject))//['AES-CBC', 'hello world', true]
        console.log(await aes(string,aesGCMObject))//['AES-GCM', 'hello world']
        console.log(await rsa(string,rsaOAEPObject))//['RSA-OAEP', 'hello world']
    })()
}</script></head></html>

quaternion 3d[blob uri, logic]

code

<!doctype html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width'><style>
body{
    *{background-color:inherit;color:inherit}
    background-color:#ffffffff;color:#000000ff
}
@media(prefers-color-scheme:dark){body{background-color:#000000ff;color:#ffffffff}}
</style>
<style>
html{
    *{margin:0;padding:0}
    >body{
        *{font-family:monospace;box-sizing:border-box;overflow-wrap:anywhere;vertical-align:bottom}
        >:nth-child(1){
            >dl>dd>canvas{width:100%;aspect-ratio:1}
            display:grid;grid-template-columns:1fr 1fr 1fr
        }
        >:nth-child(2){
            >dd{margin-inline-start:.5rem}
            display:grid;grid-template-columns:auto 1fr
        }
        touch-action:none
    }
}
</style>
<script>
const quaternionRotated=`p+2.*cross(q.xyz,cross(q.xyz,p)+q.w*p)`
,getRotated=(q0,q1,precision)=>`vec4${precision}(c(c(p,${q0}),${q1}),0.)+vec4${precision}(0.,0.,1.,2.)`
WebGLRenderingContext.prototype.getRenderer=function(p,is,mode,color){
    const vertexShaderSrc=`precision highp float;attribute vec3 p;uniform vec4 q0;uniform vec4 q1;vec3 c(vec3 p,vec4 q){return ${quaternionRotated};}void main(){gl_Position=${getRotated(`q0`,`q1`,``)};}`
    ,fragmentShaderSrc=`precision highp float;void main(){gl_FragColor=vec4(${color.map(v=>v+`.`).join(`,`)});}`
    ,program=(()=>{
        const createShader=(type,src)=>{
            const shader=this.createShader(type)
            this.shaderSource(shader,src)
            this.compileShader(shader)
            return shader
        }
        const program=this.createProgram()
        this.attachShader(program,createShader(this.VERTEX_SHADER,vertexShaderSrc))
        this.attachShader(program,createShader(this.FRAGMENT_SHADER,fragmentShaderSrc))
        this.linkProgram(program)
        return program
    })()
    ,q0Location=this.getUniformLocation(program,`q0`)
    ,q1Location=this.getUniformLocation(program,`q1`)
    this.clearColor(0,0,0,0)
    this.useProgram(program)
    this.enableVertexAttribArray(0)
    this.bindBuffer(this.ARRAY_BUFFER,this.createBuffer())
    this.bufferData(this.ARRAY_BUFFER,p,this.STATIC_DRAW)
    this.bindBuffer(this.ELEMENT_ARRAY_BUFFER,this.createBuffer())
    this.bufferData(this.ELEMENT_ARRAY_BUFFER,is,this.STATIC_DRAW)
    this.vertexAttribPointer(0,3,this.FLOAT,false,0,0)
    return(q0,q1)=>{
        this.uniform4fv(q0Location,q0)
        this.uniform4fv(q1Location,q1)
        this.clear(this.COLOR_BUFFER_BIT|this.DEPTH_BUFFER_BIT)
        this.drawElements(mode,is.length,this.UNSIGNED_SHORT,0)
    }
}
WebGL2RenderingContext.prototype.getRenderer=function(p,is,mode,color){
    const vertexShaderSrc=`#version 300 es\nprecision highp float;in vec3 p;layout(std140)uniform q{vec4 q0;vec4 q1;};vec3 c(vec3 p,vec4 q){return ${quaternionRotated};}void main(){gl_Position=${getRotated(`q0`,`q1`,``)};}`
    ,fragmentShaderSrc=`#version 300 es\nprecision highp float;out vec4 c;void main(){c=vec4(${color.map(v=>v+`.`).join(`,`)});}`
    ,program=(()=>{
        const createShader=(type,src)=>{
            const shader=this.createShader(type)
            this.shaderSource(shader,src)
            this.compileShader(shader)
            return shader
        }
        const program=this.createProgram()
        this.attachShader(program,createShader(this.VERTEX_SHADER,vertexShaderSrc))
        this.attachShader(program,createShader(this.FRAGMENT_SHADER,fragmentShaderSrc))
        this.linkProgram(program)
        return program
    })()
    ,uniformBuffer=this.createBuffer()
    this.clearColor(0,0,0,0)
    this.useProgram(program)
    this.enableVertexAttribArray(0)
    this.bindBuffer(this.ARRAY_BUFFER,this.createBuffer())
    this.bufferData(this.ARRAY_BUFFER,p,this.STATIC_DRAW)
    this.bindBuffer(this.ELEMENT_ARRAY_BUFFER,this.createBuffer())
    this.bufferData(this.ELEMENT_ARRAY_BUFFER,is,this.STATIC_DRAW)
    this.vertexAttribPointer(0,3,this.FLOAT,false,0,0)
    this.uniformBlockBinding(program,0,0)
    this.bindBuffer(this.UNIFORM_BUFFER,uniformBuffer)
    this.bindBufferBase(this.UNIFORM_BUFFER,0,uniformBuffer)
    return(q0,q1)=>{
        const q=new Float32Array(q0.length+q1.length)
        q.set(q0)
        q.set(q1,q0.length)
        this.bufferData(this.UNIFORM_BUFFER,q,this.STATIC_DRAW)
        this.clear(this.COLOR_BUFFER_BIT|this.DEPTH_BUFFER_BIT)
        this.drawElements(mode,is.length,this.UNSIGNED_SHORT,0)
    }
}
if(navigator.gpu)GPUCanvasContext.prototype.getRenderer=function(p,is,topology,color){
    const createBuffer=(usage,src)=>{
        const buffer=configuration.device.createBuffer({usage:usage,size:src.byteLength,mappedAtCreation:true})
        new src.constructor(buffer.getMappedRange()).set(src)
        buffer.unmap()
        return buffer
    }
    ,configuration=this.getConfiguration()
    ,layout=configuration.device.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{}}]})
    ,vertexShaderSrc=`struct Q{q0:vec4f,q1:vec4f}@binding(0)@group(0)var<uniform>q:Q;fn c(p:vec3f,q:vec4f)->vec3f{return ${quaternionRotated};}@vertex fn main(@location(0)p:vec3f)->@builtin(position)vec4f{return ${getRotated(`q.q0`,`q.q1`,`f`)};}`
    ,fragmentShaderSrc=`@fragment fn main()->@location(0)vec4f{return vec4f(${color.map(v=>v+`.`).join(`,`)});}`
    ,pipeline=configuration.device.createRenderPipeline({
        layout:configuration.device.createPipelineLayout({bindGroupLayouts:[layout]})
        ,primitive:{topology:topology}
        ,vertex:{buffers:[{attributes:[{format:`float32x3`,offset:0,shaderLocation:0}],arrayStride:12}],module:configuration.device.createShaderModule({code:vertexShaderSrc})}
        ,fragment:{targets:[{format:configuration.format}],module:configuration.device.createShaderModule({code:fragmentShaderSrc})}
    })
    ,encoder=configuration.device.createRenderBundleEncoder({colorFormats:[configuration.format]})
    ,uniformBuffer=configuration.device.createBuffer({usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,size:32})
    encoder.setPipeline(pipeline)
    encoder.setVertexBuffer(0,createBuffer(GPUBufferUsage.VERTEX,p))
    encoder.setBindGroup(0,configuration.device.createBindGroup({entries:[{binding:0,resource:{buffer:uniformBuffer}}],layout:layout}))
    encoder.setIndexBuffer(createBuffer(GPUBufferUsage.INDEX,is),`uint16`)
    encoder.drawIndexed(is.length)
    const bundle=encoder.finish(),descriptor={colorAttachments:[{loadOp:`clear`,storeOp:`store`,clearValue:[0,0,0,0]}]}
    return(q0,q1)=>{
        const q=new Float32Array(q0.length+q1.length)
        q.set(q0)
        q.set(q1,q0.length)
        configuration.device.queue.writeBuffer(uniformBuffer,0,q)
        descriptor.colorAttachments[0].view=this.getCurrentTexture().createView()
        const encoder=configuration.device.createCommandEncoder(),pass=encoder.beginRenderPass(descriptor)
        pass.executeBundles([bundle])
        pass.end()
        configuration.device.queue.submit([encoder.finish()])
    }
}
addEventListener(`DOMContentLoaded`,async()=>{
    let size,clientX,clientY
    const render=(q0,q1)=>renderers.forEach(c=>c(q0,q1))
    ,canvas=document.querySelector(`body>:nth-child(1)`),[webGLCanvas,webGL2Canvas,webGPUCanvas]=canvas.querySelectorAll(`dl>dd>canvas`)
    ,sensitivity=document.querySelector(`body>:nth-child(2)>dd>input[type=number]`),order=document.querySelector(`body>:nth-child(2)>dd>select`)
    ,[webGLContext,webGL2Context]=[webGLCanvas.getContext(`webgl`),webGL2Canvas.getContext(`webgl2`)]
    ,p=new Float32Array([
        [
            -1,-1,-1
           , 1,-1,-1
           ,-1, 1,-1
           ,-1,-1, 1
           , 1, 1,-1
           , 1,-1, 1
           ,-1, 1, 1
           , 1, 1, 1
        ].map(v=>v/2)
        ,[
             1, 0, 0
           , 0, 1, 0
           , 0, 0, 1
           , 0, 0,-1
           , 0,-1, 0
           ,-1, 0, 0
        ]
    ].flat())
    ,is=new Uint16Array([
        [
             0,1,1,4
            ,7,6,6,3
            ,0,2,2,6
            ,7,5,5,1
            ,0,3,3,5
            ,7,4,4,2
        ]
        ,[
             0,1,1,2,2,5
            ,0,4,4,3,3,5
            ,0,2,2,4,4,5
            ,0,3,3,1,1,5
        ].map(v=>8+v)
    ].flat())
    ,renderers=[webGLContext.getRenderer(p,is,1,[1,0,0,1]),webGL2Context.getRenderer(p,is,1,[0,1,0,1])]
    ,identity=new Float32Array([0,0,0,1])
    if(navigator.gpu){
        const adapter=await navigator.gpu.requestAdapter()
        if(adapter){
            const device=await adapter.requestDevice()
            if(device){
                const webGPUContext=webGPUCanvas.getContext(`webgpu`)
                webGPUContext.configure({device:device,format:navigator.gpu.getPreferredCanvasFormat(),alphaMode:`premultiplied`})
                renderers.push(webGPUContext.getRenderer(p,is,`line-list`,[0,0,1,1]))
            }else webGPUCanvas.parentElement.textContent=`the device request failed.`
        }else webGPUCanvas.parentElement.textContent=`the adapter request failed.`
    }else webGPUCanvas.parentElement.textContent=`available in secure contexts.`
    canvas.addEventListener(`pointerup`,event=>(clientX=clientY=null)||canvas.releasePointerCapture(event.pointerId)||render(new Float32Array([0,0,0,1]),new Float32Array([0,0,0,1])))
    canvas.addEventListener(`pointerdown`,event=>{
        canvas.setPointerCapture(event.pointerId)
        clientX=event.clientX
        clientY=event.clientY
    })
    canvas.addEventListener(`pointermove`,event=>{
        if(!clientX&&!clientY)return
        let x,y
        const v=Number(sensitivity.value)
        x=(event.clientX-clientX)*v/2
        y=(event.clientY-clientY)*v/2
        x=new Float32Array([0,Math.sin(x),0,Math.cos(x)])
        y=new Float32Array([Math.sin(y),0,0,Math.cos(y)])
        render(...Number(order.value)?[x,y]:[y,x])
    })
    onresize=()=>{
        if(webGLCanvas.clientWidth===size)return
        size=webGLCanvas.clientWidth
        webGPUCanvas.height=webGPUCanvas.width=webGL2Canvas.height=webGL2Canvas.width=webGLCanvas.height=webGLCanvas.width=size
        webGLContext.viewport(0,0,size,size)
        webGL2Context.viewport(0,0,size,size)
        render(identity,identity)
    }
    onresize()
},{once:true})
</script>
</head>
<body>
    <dl>
        <dl><dt>WebGL</dt><dd><canvas></canvas></dd></dl>
        <dl><dt>WebGL2</dt><dd><canvas></canvas></dd></dl>
        <dl><dt>WebGPU</dt><dd><canvas></canvas></dd></dl>
    </dl>
    <dl>
        <dt>sensitivity</dt><dd><input type='number' step='.01' min='0' value='.05'></dd>
        <dt>order</dt><dd><select><option value='0'>false</option><option value='1'>true</option></select></dd>
    </dl>
</body>
</html>

RTCPeerConnection[blob uri, how to use]

code

<!doctype html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width'><style>
body{
    *{background-color:inherit;color:inherit}
    hr{background-color:var(--color);color:var(--background-color)}
    --background-color:#ffffffff;--color:#000000ff;background-color:var(--background-color);color:var(--color)
}
@media(prefers-color-scheme:dark){body{--background-color:#000000ff;--color:#ffffffff}}
</style>
<style>
html{
    *{margin:0;padding:0}
    >body{
        *{font-family:monospace;box-sizing:border-box;overflow-wrap:anywhere;vertical-align:bottom}
        textarea{resize:none}
        >dl,>textarea{overflow-y:auto}
        >dl{
            >dl{
                >dd{margin-inline-start:.5rem}
                display:grid;grid-template-columns:auto 1fr;margin-bottom:.5rem
            }
            >dd{
                >span{display:inline-block;border:1px solid;text-align:start}
                &.end{text-align:end}
                white-space:pre-wrap
            }
        }
        >hr{padding:1px;border:1rem solid;cursor:row-resize}
        >textarea{width:100%;border:none;outline:none}
        height:100dvh;display:grid;grid-template-rows:var(--grid-template-rows,1fr auto 1fr);touch-action:none
    }
}
</style>
<script>
addEventListener(`DOMContentLoaded`,()=>{
    let row,clientY,v,offset=0
    const clamp=v=>row<(0>v?-v:v)?0>v?-row:row:v
    ,send=(v,c)=>{
        const dd=document.createElement(`dd`),span=document.createElement(`span`)
        span.textContent=v
        dd.append(span)
        if(c)c(dd)
        dl.append(dd)
        dd.scrollIntoView({behavior:`smooth`})
    }
    ,connection=new RTCPeerConnection(),channels=[0,1].map(v=>connection.createDataChannel(``,{negotiated:true,id:v}))
    ,dl=document.querySelector(`body>dl`),state=dl.querySelector(`dl>dd`),hr=document.querySelector(`body>hr`),textarea=document.querySelector(`body>textarea`)
    channels[0].addEventListener(`message`,event=>send(event.data)||channels[1].send(event.data))
    channels[1].addEventListener(`message`,event=>send(event.data,e=>e.setAttribute(`class`,`end`)))
    connection.addEventListener(`icegatheringstatechange`,()=>{
        state.textContent=connection.iceGatheringState
        if(`complete`!==connection.iceGatheringState)return
        textarea.value=JSON.stringify(connection.localDescription)
        textarea.select()
    })
    connection.addEventListener(`connectionstatechange`,()=>{
        state.textContent=connection.connectionState
        if(`connected`===connection.connectionState)textarea.value=``
    })
    dl.addEventListener(`pointerdown`,async event=>{
        event.preventDefault()
        if(`connected`===connection.connectionState){
            if(!textarea.value||`open`!==channels[0].readyState)return
            channels[0].send(textarea.value)
            textarea.value=``
        }else if([`new`,`connecting`].includes(connection.connectionState))try{
            if(!textarea.value)throw Error()
            let b=0
            const sdp=JSON.parse(textarea.value)
            if(![`offer`,`answer`].includes(sdp.type))throw Error()
            if(!connection.localDescription&&`new`===connection.connectionState&&`offer`===sdp.type)b|=0b01
            if(connection.localDescription&&`connecting`===connection.connectionState&&`answer`===sdp.type)b|=0b10
            if(!b)throw Error()
            await connection.setRemoteDescription(sdp)
            if(0b01&b)await connection.setLocalDescription(await connection.createAnswer())
        }catch{
            await connection.setLocalDescription(await connection.createOffer())
        }
    })
    hr.addEventListener(`pointerup`,event=>(clientY=null)||hr.releasePointerCapture(event.pointerId)||(offset=v))
    hr.addEventListener(`pointerdown`,event=>hr.setPointerCapture(event.pointerId)||(clientY=event.clientY))
    hr.addEventListener(`pointermove`,event=>clientY&&((v=clamp(event.clientY-clientY+offset))?document.body.style.setProperty(`--grid-template-rows`,`${0>v?(row+v)/(row-v):1}fr auto ${0>v?1:(row-v)/(row+v)}fr`):document.body.removeAttribute(`style`)))
    onresize=()=>{
        row=(document.body.getBoundingClientRect().height-hr.getBoundingClientRect().height)/2
        offset=clamp(offset)
    }
    onresize()
},{once:true})
</script>
</head>
<body>
    <dl><dl><dt>state</dt><dd></dd></dl></dl>
    <hr>
    <textarea autofocus></textarea>
</body>
</html>