javascript

javascriptとは、ブラウザの標準プログラミング言語です。

hello world(data uri)

code

<!doctype html><head><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(data uri)

code

<!doctype html><head><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(data uri)

code

<!doctype html><head><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(data uri)

code

<!doctype html><head><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(data uri)

code

<!doctype html><head><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(data uri)

code

<!doctype html><head><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(data uri)

code

<!doctype html><head><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(data uri)

code

<!doctype html><head><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(data uri)

code

<!doctype html><head><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(data uri)

code

<!doctype html>
<head>
<style>
body{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}
        >:nth-child(1){
            >dl>dd>canvas{width:100%;aspect-ratio:1}
            display:grid;grid-template-columns:1fr 1fr 1fr
        }
        >:nth-child(2){
            >dd{margin-left:.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()=>{
    const setPointerEvent=(e,c)=>{
        let clientX,clientY
        const sensitivity=document.querySelector(`body>dl>dd>input[type=number]`),order=document.querySelector(`body>dl>dd>select`)
        e.addEventListener(`pointerup`,event=>{
            clientX=clientY=null
            c(new Float32Array([0,0,0,1]),new Float32Array([0,0,0,1]))
            e.releasePointerCapture(event.pointerId)
        })
        e.addEventListener(`pointerdown`,event=>{
            e.setPointerCapture(event.pointerId)
            clientX=event.clientX
            clientY=event.clientY
        })
        e.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)])
            c(...Number(order.value)?[x,y]:[y,x])
        })
    }
    ,[webGLCanvas,webGL2Canvas,webGPUCanvas]=document.querySelectorAll(`body>:nth-child(1)>dl>dd>canvas`)
    ,[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())
    ,cs=[webGLContext.getRenderer(p,is,1,[1,0,0,1]),webGL2Context.getRenderer(p,is,1,[0,1,0,1])]
    ,c=(q0,q1)=>cs.forEach(c=>c(q0,q1))
    ,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`})
                cs.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.`
    setPointerEvent(document.body,c)
    let size
    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)
        c(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>