🌎
web.dev
  • 🌏web.dev
    • 🚧todo
    • 🧪lab
    • 🚸legend
    • 🗒️template
    • 🎹shortcuts
    • 📗reference
      • 📘JS spec
      • 📙javascript.info
      • 📙Eloquent JavaScript
      • 📙JavaScript: The Definitive Guide
      • 📗book
        • 📗You Don't Know JS: series (v.1)
        • 📗You Don't Know JS: series (v.2)
          • 📗YDKJS: Scope & Closures (v.2)
        • 📗Functional-Light JavaScript
      • 🔰website
        • 🔰freeCodeCamp
    • ❤️fav
  • ⚙️tools
    • 🔰tooltip
    • 🔰syntax highlighting
  • 🔰HTML
    • 🔰element
      • 🎛️<select>
      • <form>
      • 🏷️<hr>
      • <figure>
      • <input>
        • type="range"
        • type="radio"
    • block vs. inline
    • Semantic Elements
  • 🔰CSS
    • ⭐box model
      • height
      • border
      • outline
      • 🔸margin
        • layout with margin
        • default margin
        • 🔸negative margin
        • margin collapsing
      • 💊box-sizing
    • 🔰layout
      • 🔹position
        • 🔸positioned ancestor
        • 🔸nearest positioned ancestor
      • 🔹top
      • 🔹display
        • 🔸block
          • inset
        • 🔸inline
        • 🔸flex
          • 🚧Flexbox
            • flex-wrap
            • justify-content
            • align-content
            • flex
            • container properties
          • 🔸flex-direction
          • 🔸align-items
        • 🔸inline-block
        • 🔸inline-flex
        • 🔸none
      • 🔸formatting context
      • Layout System
        • Lorem
        • Spacer
        • VStack
        • HStack
        • Box
        • VCenter/HCenter
        • Dark Theme
      • ✨examples
        • Email Form
      • 🔰CSS grid
      • vertical-align
      • float
      • vertical centering
        • center with "transform"
        • center with "flex"
      • Block Formatting Context
    • 🔰values
      • 🔰units
        • 🔰相對單位
          • 🔸percentage (%)
          • 🔸rem
          • 🔸em
      • 🔰colors
        • HSL
      • 🔰gradients
        • radial-gradient()
    • 🔰variables
    • 🔰functions
      • 🔹calc()
    • 🔰selectors
      • select direct children by JS
      • basic selectors
      • attribute selectors
      • 🔰combinators
      • pseudo-class
      • 🔸pseudo-element
      • custom selectors
    • 🔰properties
      • get/set CSS props
      • Logical Properties
      • overflow
    • 💡Tips
    • CSS import
    • Responsive Design
    • CSS Rules
      • CSS reset
    • Design
      • 🔰CSS shadows
    • ✨examples
      • styling <details>
      • undefined tag
      • modal dialog
      • nav bar
      • glowing buttons
    • Cascade
      • Order
      • Specificity
      • Inheritance
    • Stacking Context
    • Font
      • Font Awesome
      • font-family
    • Text
    • List
  • 🍒JS
    • 💡tips
      • fill 2D array
    • 🧚technique
    • ⭐feature
      • ⭐️ ES5
      • ⭐️ ES6 (2015)
      • ⭐️ ES2017
      • ⭐️ ES2016
      • ⭐️ ES2018
      • ⭐️ ES2020
    • 🔰concept
      • 🔰execution context
        • 📘this
          • ❗"this" determined on call site❗️
        • 🔰running execution context
        • 🔰lexical environment
          • 🔰environment record
          • 🔸[[Environment]]
          • ❗lexical environment optimizaton
        • 🔰call stack
      • 🔰context
        • 🔰global context
        • 🔰class body context
      • 🔰environment
        • ⚙️JS engine
          • 🔰mode
            • 🛡️strict mode
              • 🛡️eval has its own scope in strict mode
              • ✅always use strict mode
            • ❗sloppy mode
              • ❗accidental global variable in sloppy mode❗️
              • ❗modify current scope at runtime❗️
            • ⚖️strict vs. sloppy
          • 🔰v8
        • 🔰Node.js
      • 🔰associated array
      • 🔰parser
    • 🔰compilation
      • 🔰lexing
      • 🔰parsing
      • 🔰code generation
      • 🔰JS is compiled
      • 🔰compile-time
      • 🔰runtime
    • 🔰grammar
      • 🚩directive
        • 📜'use strict'
      • *️token
        • 🗝️keyword
          • 🔐reserved word
            • ❗reserved word as property name is allowed❗️
          • 🔑contextual keyword
        • 🔣punctuator
          • *️hash (#)
          • 🔣semicolon (;)
            • 🔰automatic semicolon insertion
            • 🔰statements that must end with ";"
          • 🔣dot (.)
          • 🔣comma (,)
          • 🔣colon (:)
          • 🔣plus (+)
          • 🔣equal (=)
          • 🔣3 dots (...)
          • 🔣brackets []
          • 🔣braces {}
          • 🔣parentheses ()
          • 🔣question dot (?.)
          • 🔣question (?)
        • 🆔identifier
          • 🆔special identifier
          • ⚖️identifier vs. string
          • ⚖️identifier vs. keyword
          • ❗undeclared identifier
          • 🔰static binding
          • 🔰dynamic binding
        • ✡️literal
          • 🔰trailing comma
      • 🔰comment
      • 🈯declaration
        • ❗redeclaration
        • 🈯lexical declaration
      • 📜statement
        • 📦expression
          • 📦primary expression
          • 📦invocation expression:f()
            • 📦method invocation
          • 📦left-hand side expression
        • 🔁loop
          • 🔁while
          • 🔁do...while
          • 🔁for loops
            • 🔁for
              • 🔰"for-init" scope
              • 🔰"for-init" block
            • 🔁for-in
            • 🔁for-of
              • ❗arrays are iterated "live"❗️
              • 🔰for-of with objects
              • 🔰for-of with strings
              • ⚖️for-of vs. forEach
            • 🔁for-await
            • ⚖️for-in vs. for-of vs. in
            • 📘arr.forEach()
        • 🔀control flow
          • ⤴️jump
            • ⤴️return
            • ⤴️continue
            • ⤴️break
            • ⚖️continue vs. break
          • 🔀branch
            • 🔀if
            • 🔀switch
              • 🔀case clause
        • 📜other statement
          • 📜block
            • 🔰block scope
          • 📜label
          • 🛑with
          • 📜empty statement
        • ⛔statement expected❗️
      • 🚧operator
        • 🚧table of operators
        • 📖terms for operator
          • 🔰arity
          • 🔰associativity
          • 🔰lvalue
          • 🔰dividend
          • 🔰divisor
          • 🔰non-numeric operand
          • 🔰short-circuiting
        • 🔴assignment
          • ⭐destructuring assignment
            • 🔰destructuring array
            • 🔰destructuring iterable
            • 🔰object destructuring
            • 🔰nested destructuring
              • 🌟nested default values
            • 🔰destructuring arguments
          • ➕assignment (=)
        • 🔴arithmetic operator
          • ⭕unary arithmetic operator
            • 🚧unary plus (+)
          • ⭕binary arithmetic operator
            • ➕add/concate (+)
            • ➕division (/)
            • ➕remainder (%)
              • 💾modulo(a, b)
              • 💾mod(a, b)
              • ⚖️remainder vs. modulo vs. mod
            • ➕exponentiation (**)
          • ⭕bitwise operator
            • 🌟2's complement
            • 💾bitview()
            • ➕bitwise not (~)
              • 🔰double tilde (~~)
              • ⚖️(~~) vs. Math.trunc()
        • 🔴relational operator
          • 🔰equality & inequality operator
            • ➕sloppy equality (==)
            • ➕strict equality (===)
          • 🔰comparison operator
          • ➕in
          • ➕instanceof
        • 🚧logical operator
          • ➕nullish coalescing (??)
          • ⭕unary logical operator
          • ⭕binary logical operator
        • ⭕unary operator
          • ➕void
        • ⭕binary operator
          • ➕comma operator (,)
        • ⭕ternary operator
          • ➕conditional operator (?:)
        • 🔰spread operator (...)
        • ➕rest operator (...)
      • 🔰statement vs. declaration
    • 🔰scope
      • 🔰lexical scope
      • 🔰static scope
      • 🔰dynamic scope
      • ⚖️static vs. dynamic scoping
      • 🔰scope chain
      • ⚖️lexical environment vs. scope
      • 🔰top-level scope
      • 🌟global scope
        • 📘global object
          • 🏷️globalThis
          • 🍄window
            • 🔸window.name
            • 🔸window.navigator
          • 🍄global
          • 🔸eval
          • 🔸global object property
        • 💾isCurrentlyInGlobalScope()
        • 🔰global variable
          • 🔰global let
            • ❗global let shadows global object property
          • 🔰global var
        • 🔸DOM element with "id"
      • 🔰module scope
      • 🔰function scope
      • 🔰function name scope
      • 🔰parameter scope
      • 🔰hoisting
        • 🔰function hoisting
          • ❗function hoisting first❗️
        • 🔰variable hoisting
          • 🔰var hoisting
            • ❗function expression not hoisted
          • 🔰let/const/class hoisting
      • ⚖️context vs. scope
    • 💍value
      • 🔰type
        • 💍falsy
        • 📖terms for type
          • 🔰statically typed
          • 🔰dynamically typed
        • 🔰type conversion
        • 🔰type name
          • ➕typeof
          • 💾baseTypeName()
          • 💾typeName()
          • 💾custom type name
        • 🔰nested type
        • 👔type functions
          • 💾functionDefinition()
          • 💾isObject()
          • 💾isPrimitive()
          • 💾isFunction()
          • 💾isClass()
      • 🦠primitive
        • 💍nullish
        • 🔸undefined
        • 🔐null
        • 🔢Number
          • 🔰floating-point
          • 🔰integers
          • 🔴special number
            • 🔢Infinity
            • 🔢NaN
            • 🔢Number.EPSILON
            • 🔢Number.MAX_VALUE
            • 🔢Number.MAX_SAFE_INTEGER
          • 👔Number+ext
            • 💾n.toHex()
            • 💾n.isEqual()
            • 💾isNumber()
          • 👔Random
            • randomInt()
            • randomFloat()
          • 👔Quaternion
        • 🔢BigInt
        • 🦠Boolean
        • 🔤String
          • 🔰raw string
          • 🔰escape sequence
          • template literal
            • tagged template
            • tag function
          • 🔰String methods
            • str.map()
            • 💾str.capitalize()
            • str.countLetters()
            • 💾str.htmlToElement()
            • str.kebabToCamelCase()
            • 📘str.match()
              • ✨split into course names
            • 📘str.matchAll()
              • ✨matchAll() using named groups
              • ✨words in sentence
            • str.random()
            • str.removeWhitespaces()
            • 📘str.replace()
              • 🔰replacer function
              • ✨minus one
            • 💾str.replaceWhitespaces()
            • str.reverse()
            • str.shuffle()
            • 💾str.slice2()
            • 💾str.splice()
            • str.escapeHTML()
            • str.toDatasetPropName()
            • 💾str.words()
            • str.wordCounts()
            • String.fromCharCodes()
          • 👔String extension
            • 💾str.isKeyword
            • 💾str.isReservedWord
            • 💾str.isPunctuator
          • 🔰Unicode
            • 🔰code point
            • 🔰grapheme cluster
            • 🔰code plane
            • 🔰character encoding
              • 🔰UTF-16
                • 🔰code unit
                • 🔰surrogate pair
                • 🔰scalar
        • 🔺Symbol
          • 🔺Symbol.iterator
        • 🔰primitive wrapper
      • 🍄object
        • 🔸property
          • 🚩attribute
            • 🍄property descriptor
            • 💾ownPropertyFlags(obj)
          • 🔸getter/setter
          • 🔸property name
            • ⭐computed property name
          • ⭐shorthand property
          • 🔸internal property
          • 🔰property access
            • 📦property access expression
            • ➕dot notation (.)
              • ⚖️dot notation vs. decimal point
            • ➕bracket notation []
            • ➕optional chaining (?., ?.[])
              • ❓is Optional Chaining Supported?
              • 💾obj.prop(path)
            • ➕optional invocation ?.()
              • is Optional Chaining Supported?
              • obj.prop(path)
            • 🌟chaining rules
              • ✨jane.boyfriend?.money.more
          • 🔰property creation/deletion
            • 📘Object.defineProperty()
            • ➕delete
              • ❗unqualified identifier for delete
          • 🔰property testing
          • 🔰property enumeration
        • 🔰creating objects
          • ✡️object literal
            • ❗object literal is not a block❗️
          • ➕new
            • 🔸new.target
            • ⚖️callable vs. constructable
          • Ⓜ️Object.create()
            • ✨"pure" object
            • ✨guard against accidental modifications
        • 🔰extending objects
          • 📘Object.assign()
            • ⛔️ Object.assign causing TypeError
            • ❗️Object.assign copies with getter/setter
          • inheritance
            • 🔸__proto__
            • class A vs. class A extends Object
          • mixin
            • 💾mergeWithoutOverride()
            • 💾.assignDescriptors()
            • mixin inheritance
            • ✨mixin: HandleEvents
          • 💾 add default properties
          • extending built-in classes
        • 🔰converting objects
          • 🔰serializing objects
          • 🌟object -> primitive conversion
            • 🔘prefer-string
            • 🔘prefer-number
            • 🔘no preference
          • Ⓜ️.toString()
          • Ⓜ️.valueOf()
          • 💾valueToString()
        • Ⓜ️method
          • 💠[[HomeObject]]
          • 🔰polymorphism
        • 🔸prototype
          • 🔰prototype chain
            • 🚧printPrototypeChain()
      • 🍄function
        • 🔰creating functions
        • 🈯function declaration
          • ❗function in block (FiB)
          • ❗function redeclaration
          • 📘function declaration instantiation
        • 🔰function expression
          • ❗read-only identifier
          • 🔰named function expression
          • 🔰as variable
          • 🔰IIFE
        • 🔰arrow function
          • ❗arrow function as method❗️
          • 🔰arrow function as argument
          • ❗arrow function as class field❗️
          • ❗arrow function returning object literal needs (...)❗️
          • 🔰arrow function expression
        • 🔰closure
          • ❗scopes matter with closures
          • 💡private property by closure
          • ✨closure examples
            • ✨closure: to close over or not
            • ✨closure: manage grades
            • ✨closure as object
        • 🌿sorts of function
          • 🔰callback
          • 🔰higher-order function
            • 💾not(f)
            • 💾pipe(f, g, ...)
            • 💾partial(f, a, b ...)
            • 🧚decorator
              • 💾saveCallHistory(f)
              • 💾delay(f, s)
              • 💾benchmark(f)
              • 💾debounce(f, s)
              • 💾throttle(f, s)
              • ⚖️debounce vs. throttle
              • 🧚memoization
                • 🧚memoize by decorator
                  • 💾memoize(f)
                • 🧚memoize by closure
          • 🔰predicate
          • 🔰nested function
          • 🔰recursive function
            • ✨findSolution()
            • 💾deepEqual()
        • 🔰function boundary
        • 🔰function overloading
        • 🔰function forwarding
        • 🔸return value
        • 🔸function name
          • 🔰anonymous function
        • ⚖️parameter vs. argument
        • 🔸argument
          • ❗arguments are passed by value❗️
        • 🔸parameter
          • 🔸default parameter
          • 🔸rest parameters
            • 🔸rest parameters as object
          • 🔸destructured parameter
          • ⚖️simple vs. non-simple parameter
          • ❗deplicate parameters
        • 🔸prototype
        • 🔹constructor
      • 🍄class
        • 🔰initialization
          • 🔹static block
        • 🔸member
          • 🔸class field
          • 🔸private member
          • 🔸static member
            • 🔰init static property
          • private/protected members
          • 🔸getter/setter
          • 🔸method
          • 🔸bound method
        • 🔰creating class
          • 🔰delegation
        • 🔰inheritance
          • 📘super
          • derived class init
          • override constructor
          • override methods
          • override class fields
        • ✨examples
          • ✨Complex
          • ✨TypedMap
          • ✨Bag
      • 📘built-in objects
        • 📘Object
          • 🔸Object.prototype
          • 💾Object extension
            • 💾obj.mergeWith()
        • 📘Function
        • 📘Array
          • 🔸element
            • 🔸element index
              • ❗element index is string❗️
          • 🔸array length
          • 🔸array object property
          • 🍄sparse array
            • 🔰how array methods deal with "holes" ?
          • 🔰array-like
            • 👔Object+arrayLike
          • 🔰creating arrays
            • ✡️array literal
              • 🔰undefined element
          • 🔰accessing elements
          • 🔰iterating elements
          • 📘array methods
            • 📘arr.entries
            • 📘arr.filter()
            • 📘arr.flatMap()
            • 📘arr.reduce()
              • early break reduce()
            • 📘arr.slice()
            • 📘arr.splice()
          • 👔Array extension
            • 💾arr.containsSubarray()
            • 💾arr.copy()
            • 💾arr.isEmpty
            • 💾arr.last
            • 💾arr.none()
            • 💾arr.reversed()
            • 💾arr.shuffle()
            • 💾arr.randomElement
            • 💾arr.removeDuplicates()
            • 💾arr.uniqueMerge()
            • 💾arr.removeUndefined()
            • 💾arr.removeValue()
            • 💾arr.sum(), .average()
            • 💾arr.topN()
            • 💾arr.rank()
            • 💾arr.padEndSpaces()
            • 💾arr.max()
            • 💾arr.isMatrix
            • 💾arr.indexDictionaryForValues()
            • Array extensions (archive)
          • ✨array examples
            • 💾objects to HTML table
          • array & matrix methods
          • static methods
            • 📍Array(n) vs. Array(n).fill()
            • Array.from()
            • 🚧Array.list(n)
          • matrix methods
            • mat.matrixMap()
            • mat.transpose()
            • mat.maxElementInEachColumn()
          • Matrix methods
            • 🌀 Array.matrixFill()
        • 📘Set
          • 👔Set extension
            • 💾set.isEqualTo()
        • 📘Map
          • Don't use object properties
        • 📘RegExp
          • 🚩regex flag
            • 🚩flag /u
            • 🚩flag /d
          • 🔸lastIndex
          • 🔰creating regex
          • 🔰using regex
          • 🔰pattern
            • 🔰special characters
            • 🔰anchor
            • 🔰repeat
              • 🔰greedy vs. lazy
            • 🔰character set
            • 🔰alternation (or)
            • 🔰group
              • 🔰capturing group
                • 🔰named group
            • 🔰lookaround
            • 🔰inline modifier
            • 🔰replace pattern
            • 😀emoji
          • ✨regex examples
            • ✨parse .ini file
            • ✨quick brown fox
            • ✨JS-style numbers
        • 📘Proxy
          • 🔹handler method
          • 📘Reflect
          • ✨Proxy examples
            • ✨identity (proxy)
            • ✨read-only proxy
            • ✨observe()
        • 📘Date
    • 🔰variable
      • 🈯variable declaration
        • 📜var
          • ✅stop using var❗️
          • ❗var is a statement❗️
          • ❗var has no block scope❗️
          • ❗accessing var before declaration gets undefined❗️
          • ❗global var / function is global object property❗️
          • ❗var redeclaration applied even in strict mode❗️
          • ❗var in block can't shadow outer let❗️
          • ❗var can shadow parameter even in strict mode❗️
        • 🈯const
          • ⛔const requires initialization
          • ⛔const can't reassign
          • ⛔no const for classic "for"
        • 🈯let
          • ✅let redeclaration not allowed even in sloppy mode❗️
          • ✅let can't shadow parameter even in sloppy mode❗️
        • 🔰initial value
      • ❗variable redeclaration
        • ❗var redeclaration
        • ❗let redeclaration
      • 🔴accessing variables
        • ⛔temporal dead zone
          • ⛔TDZ
          • ⛔typeof let/const/class in TDZ gets an error❗️
        • ⛔uninitialized variable
        • 🔰LHS reference
        • 🔰RHS reference
        • ⚖️LHS vs. RHS reference
      • ❗variable shadowing
      • ❗can't delete variable/function❗️
    • 🔰module
      • ⭐ES module
        • 🈯import
          • ✨import ES module
          • dynamic import()
        • 🈯export
          • 📘default export
          • 📘named export
      • 🔰CommonJS
        • 📜package.json
      • ⚖️ES vs CommonJS
      • 🔰import.meta
      • 🔰package
      • 🔰bundler
      • 🔰minifier
      • 🔰browser-specific features
      • 🔰module pattern
    • 🔰iteration
      • 👔Iterable+ext
        • 💾range()
        • 💾obj.isIterable
      • 🔰iterable
        • 🔸make-iterator method
        • ❗only-iterate-once iterable
        • 🔰make iterables
        • ✨iterable examples
          • ✨ClosedRange
          • ✨Sequence
      • 🔰iterator
        • 🔸next()
        • 🔸return()
        • ❗iterators only iterate once❗️
        • 🔰iterable iterator
        • 🔰infinite iterator
        • 🔰make iterator iterable
        • 💾IteratorPrototype
        • 💾Iterator
      • 🔰iteration result
      • 📘Generator
        • 🔰generator function
          • 📘function*
          • 📦yield
          • 📘yield*
          • 🔰composition
          • 🔰generator function as ...
        • ✨generator examples
          • 💾*list()
          • 💾*integers()
          • 💾*closedRange()
          • 💾*fibonacci()
          • 💾*zip()
          • 💾*sequence()
          • 💾*interleave()
    • 🔰async code
      • 🔰thread
      • 🔰event loop
      • 🍄Promise
        • 👔custom promises
          • 💾getJSON()
          • 💾Promise.wait()
          • 💾futureValue()
        • 🔰using Promises
        • 🔰error handling
          • ⭐finally()
          • 🔰recoverable errors
        • 🔰chaining Promises
          • 💾Promise.inSeries()
        • 🔰Promises in parallel
      • 🆔async
        • 🔰async function
        • 🔰async method
        • 🔰async arrow function
        • 🔰async IIFE
        • 💾measureTime()
      • ➕await
        • 🔰await promises
          • 🔰await sequentially
          • 🔰await in parallel
        • 🔰await "thenable"
        • 🔰error handling
    • 🔰debugging
      • 🔰testing
      • 💊error handling
        • ⤴️throw
        • 🔰rethrow
        • ⤴️try-catch-finally
      • 🛠️devtools
        • 📜debugger
        • 🔰show built-in shadow DOM
    • ⛔Error
      • 🔴compile-time error
        • ⛔️ early errors
      • 🔴runtime error
      • ⛔️ SyntaxError
        • ⛔duplicate parameter not allowed in strict mode❗️
        • ⛔unexpected token "xxx"❗️
        • ⛔Named export 'xxx' not found❗️
        • ⛔unexpected number❗️
        • ⛔... parenthesis must be used to disambiguate operator precedence❗️
        • ⛔identifier 'xxx' has already been declared❗️
        • ⛔missing initializer in const declaration❗️
        • ⛔lexical declaration cannot appear in a single-statement context❗️
        • ⛔delete of an unqualified identifier in strict mode❗️
        • ⛔octal literals not allowed in strict mode❗️
      • ⛔️ ReferenceError
        • ⛔cannot access 'xxx' before initialization❗️
        • ⛔'xxx' is not defined❗️
      • ⛔️ TypeError
        • ⛔'xxx' is not a function❗️
        • ⛔assignment to constant variable❗️
        • ⛔cannot read properties of nullish❗️
        • ⛔cannot convert BigInt to Number❗️
        • ⛔cannot convert Symbol to Number❗️
        • ⛔cannot assign to read only property 'prototype' of function 'xxx'❗️
    • 🏛️Libraries
      • 🏛️JSXGraph
      • 🏛️grapheme-splitter
    • 🛠️tools
      • transpilers
    • ✨examples
      • Code Wars
        • Next Bigger Number
        • Changing Money
        • Game of Life
      • Exercises
        • flattenObject()
        • Pascal's Triangle
        • Permuations
        • Spiral Matrix
    • 💼projects
      • 💼Dictionary App
      • 💼Language: Egg
      • Calculator ❤️
      • Synth Keyboard ❤️
      • Form Validation
      • Password Generator
  • 🔰web component
    • 🔸custom element
      • lifecycle methods
      • getter/setter for attributes
      • Element Types
      • Element Info
      • Observed Attributes
      • Element Upgrades
      • Unknown Elements vs Undefined Custom Elements
      • Element-defined Content
    • 🔸shadow DOM
      • light, shadow, flattened DOM
      • shadow root vs. host
      • shadow DOM styles
        • Use CSS Variables
        • CSS reset in Shadow DOM
      • shadow DOM events
        • retargeting
        • Active Element
        • Events that Cross Shadow DOM Boundary
        • Bubbling in Shadow DOM
      • shadow DOM slots
    • 🔸<template>
      • 🔸<slot>
        • 🔸named slot
        • 🔸fallback content
        • 🔰slotted node styles
        • 🔸slotted nodes
        • 🔹`slotchange` event
        • 🔰Slot API
    • 🔸light DOM
    • 🔰implementing components
    • 🔰using components
      • 💡hide components until defined
    • Built-in Components
      • <details>
    • ✨web component examples
      • ✨<search-box>
      • <my-log> ❤️
      • <element-details>
      • <custom-dialog>
      • <user-card>
      • <expanding-list>
      • <dom-hierarchy> ⭐️
      • <time-formatted>
      • <live-timer>
      • <error-message>
      • <popup-info>
      • <custom-menu>
  • 🌐browser
    • 📘web API
      • 📘clearTimeout()
      • 📘setTimeout()
      • 🍄URL
      • 🍄navigator
      • 🔰web worker
        • 🍄self
    • 🔰concepts
      • 🔰coordinates
    • 🔰Event
      • 🔸event.type
      • 🔸event.currentTarget
      • 🔸event.target
        • ✨buttons A, B, C
      • 🔰event dispatching
      • 🔰event propagation
        • 🔰bubbling phase
        • 🔰capturing phase
        • 🔰stop propagation
          • ✨button in clickable paragraph
      • 🔰event handler
        • invocation context
        • ❌return value
        • 🔰"this" in event handler
        • 🔰register handler
          • 🔰handler options
          • capturing handler
          • 🍄object handler
        • 🔰remove handler
        • ❗window-reflecting body element event handlers
      • 🔰default action
        • ✨hide or not to hide?
        • ✨link going nowhere
      • 🌿event types
        • 🔰key event
          • ✨press shift + space
        • 🔰input event
        • 🔰mouse event
          • 🔸.buttons
          • 🔸.button
          • 🔰"click"
            • ✨draw dots
            • ✨sliding menu
            • ✨closing button [x]
            • ✨click to slide (carousel)
            • ✨click to move ball
          • 🔰"dblclick"
          • 🔰"mousemove"
            • ✨drag the bar
          • 🔰drag event
          • 👔MouseEvent+ext
          • ✨mouse event examples
            • ✨mouse event coords
        • 🔰touch event
          • 🔸.touches
          • 🔸.targetTouches
          • 👔TouchList+ext
        • 🔰scroll event
          • ✨scroll me
          • ✨scroll progress
          • ✨scroll progress on body
        • state-change
        • CSS events
      • client-side JavaScript timeline
      • custom events
        • event.isTrusted
      • "change" event
    • 🔰DOM
      • 🔰DOM hierarchy
      • 🔰querying elements
        • 💾$(), $all()
      • 🔰traversing DOM
      • 🔰create/insert/delete nodes
        • ✨table of contents
      • 🌿DOM types
        • 📘Node
          • 🔰.tagName vs .nodeName
          • 👔Node+ext
            • 💾node.isInPage
            • 🚧node.traverse()
            • 💾node.$(), .$all()
            • 🚧node.appendTag()
            • 💾newElement()
        • 📘Element
          • 🔸element content
          • 🔹.insertAdjacentHTML()
          • 🔸attribute
            • 🔸id
            • 🔰data attributes
            • ⚖️attributes vs. properties
          • 🔰box models
          • 👔Element+boxes
            • 🔸.scrollBox
              • 🔰scrollbar width
            • 🔸.paddingBox
            • 🔸.borderBox
              • 🔸.offsetParent
            • 🔸.boundingBox
              • ✨elem.showNote()
          • 👔Element+ext
            • 💾elem.isInside()
            • 💾elem.isHeading
            • 💾elem.wrappedWith()
            • 💾elem.wrappedWithHTML()
            • 🚧elem.attr()
            • 🚧elem.styleProp()
            • 🚧elem.showDataAttr()
            • 💾elem.position()
        • 🍄HTMLElement
          • 💾htmlElem.isHidden
        • 📘Document
          • 🔸document size
          • 🔸methods
            • 📘doc.elementFromPoint()
        • 📘Window
          • 🔹.requestAnimationFrame()
          • 🔰viewport
          • 🔰window scrolling
            • 🔰scroll smoothly
            • 🔰scroll lock
        • 🍄DocumentFragment
        • 🍄NodeList
          • NodeList vs. Array
        • CSSStyleDeclaration
      • ✨DOM examples
      • 👔custom methods
        • 🚧prop()
        • 🚧tag()
    • 🔰SVG
      • 💾SVGElement()
      • Attributes
        • fill
        • stroke-dasharray
        • transform
      • 🔰gradients
        • 📘<linearGradient>
        • 📘<radialGradient>
      • Patterns
      • 🔰SVG shapes
        • <rect>
        • <line>
        • <polygon>
        • <polyline>
        • <ellipse>
        • <path>
      • ✨SVG examples
        • SVG as background image
        • 3 circles
        • ✨SVG Clock
        • ✨pie chart
      • namespace
      • tools
    • 🔳<canvas>
      • 👔Canvas+ext
        • 💾drawOnCanvas2D()
        • 💾ctx.point()
        • 💾ctx.polyline()
        • 💾ctx.roundedRect()
      • 🔰rectangle
      • 🔰path
        • 🔰nonzero winding rule
        • 📘arcTo()
        • ✨curves
      • 🔰text
      • 🔰image
        • ✨canvas snapshot
      • 🔰graphics state
        • 🔰fill / stroke styles
          • 🔰colors
            • ✨color wheel
          • 🔰patterns
          • 🔰gradients
            • 💾ctx.gradient()
        • 🔰shadows
        • 🔰compositing
        • 🔰transformation
          • ✨Koch snowflake
        • 🔰clipping
      • ✨canvas examples
        • ✨square & circle
        • ✨open/closed subpaths
        • ✨fractal
        • ✨regular polygons
    • 🔰storage
    • 🔰animation
      • ✨animation examples
        • ✨moving cat
        • ✨cat in hat
        • ✨cat behind hat
  • 🔰React
    • 啟動
    • Hello React❗️
    • React Projects
      • FullStackOpen
        • Part 1
  • Server
    • HTTP status code
  • 🔖附錄
    • 👔custom
      • 👔element
        • 👔tabs control
        • 👔left tabs
      • 👔custom css
        • 👔Every Layout
      • 👔custom classes
        • 👔Vector
        • 👔Rect
        • 👔Size
        • 💾TableMaker
        • List
        • Point
        • Turtle
        • Matrix
      • 👔custom functions
        • randomElement()
        • randomColor()
        • randomPassword()
        • clone(obj)
        • functionName()
      • helper functions
    • 🧩three.js
      • 👔Director
      • 🔰renderer
        • 🔹set canvas size
      • ✨examples
        • ✨startup
      • 🔰primitives
      • 🔰scene graph
    • 🅰️Google Apps Script
      • 🍄app
        • 🔹helpers
        • 🔸app.init()
        • 🔸members
          • 🔸app.color
          • 💾app.dataRangeValuesFromSheet()
          • 💾app.sheetByName()
          • 💾app.valueOfNamedRange()
          • 💾app.deleteSheetByName()
          • 🚧app.cellValueAt()
          • ⭐app.makeTable()
          • 🚧app.mergedCellValue()
          • 🚧app.parseFields()
          • 🚧app.fetch()
          • 🚧app.resizeColumns()
          • 🚧app.setBorder()
          • 🚧app.writeAwardList()
        • 🔳prototypes
          • 🔳app.sheet.prototype
            • 💾 sheet.delete()
            • 💾 sheet.rangeByRect()
            • 💾 sheet.setValues()
            • 💾sheet.appendConditionalFormatRule()
            • 🚧SheetMethods
              • sheet.values()
          • 🔳app.range.prototype
            • range.alignCenter()
            • range.cellValue()
            • range.contains()
            • 🚧range.isEqualTo()
        • 🟥app menu
      • 🍄RawData
      • 🌿Classes
        • 🍄Sheet
        • 🍄Range
          • 🔰A1 notation
            • 💾columnName()
            • 💾A1Notation()
            • 💾A1NotationToRowColumn()
          • 🔰border
          • 📘range.setNumberFormat()
          • range.setRichTextValue()
        • 🍄ConditionalFormatRule
        • 🍄RichTextValueBuilder
        • 🍄Protection
        • 🍄Ui
      • 👔custom objects
        • 👔RangeRect
          • 💾rect.cell(i, j)
          • 💾RangeRect.byData()
        • 🚧BorderStyle
        • 🚧SheetFields, SheetField
      • 💼projects
        • 💼不能補考名單
        • 💼各班平均及前三名
        • 💼國中成績一覽表
        • 💼高中獎學金名冊
      • 💡tips
        • 💡 custom prototypes
        • 💡 refresh cells
        • 💡 條件格式:自訂公式
        • 處理字串
        • 顯示中文星期幾
        • 在儲存格使用陣列
        • Count non-blank cells
        • 💡 快速調整欄位寬度
      • ❓questions
      • 📊Google Sheet
      • 🔸GAS ⟩ commands
      • ✨GAS ⟩ examples
        • examples
        • ✨split data into tabs
          • migrate sheets into files
        • ✨event: onEdit
      • 🔰GAS ⟩ Events
        • onEdit
      • Dialogs & Sidebars
    • 📖JSDoc
      • return value
      • destructured parameter
    • 📦data structure
      • 📦Queue
      • 📦Stack
      • 📦WaitingList
      • 📦Graph
        • 🔹.findPath()
        • 🔹.findShortestPath()
        • 🤖breadth-first search
        • 🤖depth-first search
        • ✨Graph examples
          • ✨Mail Robot
    • 🔰algorithm
      • 🔰recursion
        • ✨recursion count
      • 🔰dynamic programming
      • Sort
        • sort strings
        • sort by multiple keys
        • bubble sort
      • ✨problems
        • ✨find couple
        • ✨knapsack problem
        • ✨longest path
    • 🔰paradigm
      • 🔰Test Driven Development (TDD)
      • 🔰Functional Programming (FP)
    • 🔰TypeScript
      • Setup
      • ⭐️ Cheat sheet
      • Type
        • type annotation
        • type predicate
        • Primitives
        • Narrowing
        • Tuples
        • Generics
          • Array<T>
          • Generic Functions
        • Object
          • Object Types
          • Object Properties
        • Function
          • optional/default parameters
          • return type
          • function type expression
          • callable objects with properties
          • function overloads
        • Union
          • discriminated union
      • TS Operators
    • 💎resource
      • ✏️editor
        • ✏️VSCode
          • emmet
          • shortcuts
        • ✏️replit.com
          • 🔰import .js file
      • 🔧tools
        • Vectornator
          • Tutorials
      • 📚books
Powered by GitBook
On this page
  • Pitch Formula
  • Notes
  • Live Demo
  • Code

Was this helpful?

  1. JS
  2. projects

Synth Keyboard ❤️

PreviousCalculator ❤️NextForm Validation

Last updated 3 years ago

Was this helpful?

  • CSSTricks ⟩ ⭐️

  • 維基 ⟩ (Octave)

  • MDN ⟩

    • EventTarget ⟩

      • BaseAudioContext ⟩

        • : number - ever-increasing timestamp in seconds

        • :

        • : GainNode

        • 📁

      • AudioNode ⟩

        • 📁 AudioScheduledSourceNode ⟩

          • 📁 - a constant tone

        • 📁 - control overall gain (volume) of the audio graph

          • : AudioParam

    • ⟩

      • schedules a gradual change in the value of the

    • CSS ⟩

      • - controls whether user can select text.

八度(英語:Octave,亦稱為完全八度)是的一種,它的組成是由2個相同但來自不同所組成。兩音的距離為 12 個,而的比例是 2:1,換而言之,較高音的頻率為較低音的兩倍。

Pitch Formula

計算音頻的公式:

pitch =a⋅2n12\boxed{\text{pitch }=a\cdot 2^{\frac{n}{12}}}pitch =a⋅212n​​

  • aaa: 440 Hz ( pitch of A4A_4A4​)

  • nnn: number of notes above or below A4A_4A4​

Notes

  • z-index only works on positioned elements❗️

Live Demo

Code

<!-- 
 store the note value in a custom `note` attribute 
 so it’s easy to access in JavaScript

 our keyboard covers just over an octave, 
 starting at C₃ and ending at F₄.
-->
<ul id="keyboard">
  <li note="C"  octave="3" class="white no-offset">A</li>
  <li note="C#" octave="3" class="black">W</li>
  <li note="D"  octave="3" class="white">S</li>
  <li note="D#" octave="3" class="black">E</li>
  <li note="E"  octave="3" class="white">D</li>
  <li note="F"  octave="3" class="white no-offset">F</li>
  <li note="F#" octave="3" class="black">T</li>
  <li note="G"  octave="3" class="white">G</li>
  <li note="G#" octave="3" class="black">Y</li>
  <li note="A"  octave="4" class="white">H</li>
  <li note="A#" octave="4" class="black">U</li>
  <li note="B"  octave="4" class="white">J</li>
  <li note="C2" octave="4" class="white no-offset">K</li>
  <li note="C#2" octave="4" class="black">O</li>
  <li note="D2" octave="4" class="white">L</li>
  <li note="D#2" octave="4" class="black">P</li>
  <li note="E2" octave="4" class="white">;</li>
  <li note="F2" octave="4" class="white no-offset">'</li>
</ul>
/* css reset */

/* :root = html (with higher specificity) */
:root { 
    box-sizing: border-box; 
}

/* "*" doesn't include pseudo-elements */
*, ::before, ::after {
    /* box-sizing isn’t normally an inherited property, */
    /* use `inherit` to force it.                       */
    box-sizing: inherit;
}

/* css vars for colors */
:root {
  
  --keyboard: hsl(300, 100%, 16%);
  --keyboard-shadow: hsla(19, 50%, 66%, 0.2);
  --keyboard-border: hsl(20, 91%, 5%);
  
  --black-10: hsla(0, 0%, 0%, 0.1);
  --black-20: hsla(0, 0%, 0%, 0.2);
  --black-30: hsla(0, 0%, 0%, 0.3);
  --black-50: hsla(0, 0%, 0%, 0.5);
  --black-60: hsla(0, 0%, 0%, 0.6);
  
  --white-20: hsla(0, 0%, 100%, 0.2);
  --white-50: hsla(0, 0%, 100%, 0.5);
  --white-80: hsla(0, 0%, 100%, 0.8);
}

/* keys */
.white, .black {
  
  /* ⭐️⭐️⭐️ 有此設定 z-index 才有作用 ⭐️⭐️⭐️ */
  position: relative;
  
  /* ⭐️ 讓所有鍵靠在一起 */
  float: left;
  
  /* ⭐️ 所有鍵往左移(自己一半的寬度) */
  margin: 0 0 0 -1rem;
  
  /* ⭐️ list-style 自動消失❓ */
  display: flex;            
  
  /*  ⭐️ 英文字母放到下方中間  */
  justify-content: center;
  align-items: flex-end;
  
  padding: .5rem 0;
  
  /* ⭐️ user can't select text */
  user-select: none;
  
  cursor: pointer;
  
/*   border: 1px solid black; */
}

#keyboard li:first-child {
  border-radius: 5px 0 5px 5px;
}

#keyboard li:last-child {
  border-radius: 0 5px 5px 5px;
}

.white {
  height: 12.5rem;
  width: 3.5rem;
  
  z-index: 1;
  
  border-left: 1px solid hsl(0, 0%, 73%);
  border-bottom: 1px solid hsl(0, 0%, 73%);
  border-radius: 0 0 5px 5px;
  
  box-shadow: 
    -1px 0 0 var(--white-80) inset, 
    0 0 5px hsl(0, 0%, 80%) inset,
    0 0 3px var(--black-20);
  
  background: linear-gradient(
    to bottom, 
    hsl(0, 0%, 93%) 0%, 
    white 100%
  );
  
  color: var(--black-30);
}

.black {
  height: 8rem;
  width: 2rem;
  
  /* ⭐️ 黑鍵在白鍵上方 */
  z-index: 2;
  
  border: 1px solid black;
  border-radius: 0 0 3px 3px;
  box-shadow: 
    -1px -1px 2px var(--white-20) inset,
    0 -5px 2px 3px var(--black-60) inset, 
    0 2px 4px var(--black-50);
  
  background: linear-gradient(
    45deg, hsl(0, 0%, 13%) 0%, hsl(0, 0%, 33%) 100%
  );
  
  color: var(--white-50);
}

/* ⭐️ A, F, K 鍵不需左移 */
.no-offset {
  margin: 0;
}

/* pressed state */

.white.pressed {
  border-top: 1px solid hsl(0, 0%, 47%);
  border-left: 1px solid hsl(0, 0%, 60%);
  border-bottom: 1px solid hsl(0, 0%, 60%);
  
  box-shadow: 
    2px 0 3px var(--black-10) inset,
    -5px 5px 20px var(--black-20) inset, 
    0 0 3px var(--black-20);
  
  background: linear-gradient(
    to bottom, 
    white 0%, 
    hsl(0, 0%, 91%) 100%
  );
/*   outline: none; */
}

.black.pressed {
  box-shadow: 
    -1px -1px 2px var(--white-20) inset,
    0 -2px 2px 3px var(--black-60) inset, 
    0 1px 2px var(--black-50);
  
  background: linear-gradient(
    to right,
    hsl(0, 0%, 27%) 0%,
    hsl(0, 0%, 13%) 100%
  );
/*   outline: none; */
}

/* keyboard */
#keyboard {
  background-color: var(--keyboard);
  box-shadow: 
    0 0 50px var(--black-50) inset, 
    0 1px var(--keyboard-shadow) inset,
    0 5px 15px var(--black-50);
  
  border: 1px solid var(--keyboard-border);
  border-radius: 1rem;
  
  height: 15.25rem;
  width: 41rem;
  
  margin: 0.5rem auto;
  
  /* ⭐️ 將鍵盤移往下方偏右 */
  padding: 3rem 0 0 1.25rem;
}
// ⭐️ audio context
const audioContext = new AudioContext();

// all note elements
const allNoteElems = document.querySelectorAll(`[note]`);

// ⭐️ keyboard keys (dictionary)
// keys[key] = {element: , note: , octave: }
let keys = {};

allNoteElems.forEach(elem => {
  
  let key = elem.textContent;
  
  keys[key] = { 
    element: elem, 
    note: elem.getAttribute('note'), 
    octave: +elem.getAttribute('octave')
  };
  
});

// console.log(keys);

/*
  pitch = 440 * 2^(n/12) 
  • 440 Hz: pitch value of A₄
  • n: number of notes above or below that pitch
  
  Musical Notation
  ----------------
  • A# == Bb
*/

// ⭐️ usage: pitch("B#", 5)
function pitch(note="A", octave=4){
  
  const notes = {
    A: 0, B: 2, C: 3, D: 5, E:7, F: 8, G: 10
  };
  
  let n = notes[note[0]];
  if(note.includes('#')) n += 1;
  if(note.includes('b')) n -= 1;
  if(note.includes('Ab')) n += 12;    // "Ab" == 11
  n += 12 * (octave - 4);             // 1 octave = 12 notes
  
  // pitch = 440 Hz * 2^(n/12)
  return 440 * Math.pow(2, n/12);
}

// console.log(pitch("C#", 4));

/*
  ⭐️ pressedNotes
  ---------------
  • notes that are playing at any given time.
  • its unique key constraint can help prevent triggering
    the same note multiple times in a single press.
*/
const pressedNotes = new Map();

// ⭐️ 
// user can only click one key at a time.
let clickedKey = "";

// ⭐️ usage: playKey('A')
const playKey = (key) => {
  
  // no such key
  if (!keys[key]) {
    console.log(`no such key: ${key}`)
    return;
  }
  
  // playback timestamp
  const t = audioContext.currentTime;
  
  // ⭐️ note's pitch
  const freq = pitch(keys[key].note, keys[key].octave);
  
  const GAIN = {
    zero     : 0.00001,       // 為何不用 0 ?
    max      : 0.5,
    sustained: 0.05,
  };
  
  // ⭐️ overall gain (volumn)
  const noteGainNode = audioContext.createGain();   // ?
  noteGainNode.connect(audioContext.destination);   // ?
  noteGainNode.gain.value = GAIN.zero;              // 音量 ?

  // ⭐️ attack: 
  //    how quickly a sound goes from nothing to max volume
  noteGainNode.gain.exponentialRampToValueAtTime(GAIN.max, t + 0.01);
  
  // ⭐️ decay: 
  //    time taken from peak volume to sustained volume
  noteGainNode.gain.exponentialRampToValueAtTime(GAIN.sustained, t + 1);

  // ⭐️ release: 
  //    how long it takes to fade to nothing
  noteGainNode.gain.exponentialRampToValueAtTime(GAIN.zero, t + 2);

  // ⭐️ a constant tone
  const osc = audioContext.createOscillator();      // ?
  osc.connect(noteGainNode);    // ?
  osc.type = "triangle";        // ⭐️ timbre (音色) of the sound
  osc.frequency.value = freq;   // ⭐️ set pitch (音高)

  // ⭐️ "pressed" state (改變外觀)
  keys[key].element.classList.add("pressed");
  
  // ⭐️ 
  pressedNotes.set(key, osc);
  pressedNotes.get(key).start();
};

// ⭐️ usage: stopKey('A')
const stopKey = (key) => {
  
  // no such key
  if (!keys[key]) {
    console.log(`no such key: ${key}`)
    return;
  }
  
  // ⭐️ remove "pressed" status
  keys[key].element.classList.remove("pressed");
  
  const osc = pressedNotes.get(key);

  if (osc) {
    setTimeout(() =>  osc.stop(), 2000);
    pressedNotes.delete(key);
  }
};

// "keydown" event
document.addEventListener("keydown", (e) => {
  let key = e.key.toUpperCase();
  if (pressedNotes.get(key)) return;    // already playing?
  playKey(key);
});

// "keyup" event
document.addEventListener("keyup", (e) => {
  let key = e.key.toUpperCase();
  stopKey(key);
});

// mouse events
for (const [key, { element }] of Object.entries(keys)) {
  element.addEventListener("mousedown", () => {
    playKey(key);
    clickedKey = key;
  });
}

document.addEventListener("mouseup", () => {
  stopKey(clickedKey);
});

⟩ ,

The gain is a unitless value, changing with time, that is multiplied to each corresponding sample of all input channels. If modified, the new gain is instantly applied, causing unaesthetic 'clicks' in the resulting audio. To prevent this from happening, never change the value directly but use the exponential interpolation methods on the interface. 📘

💾

🍒
💼
AudioParam
GainNode
replit
How to Code a Playable Synth Keyboard
八度
currentTime
createOscillator()
OscillatorNode
createGain()
AudioContext
OscillatorNode
GainNode
gain
AudioParam
exponentialRampToValueAtTime()
AudioParam
user-select
Understanding CSS z-index
音程
音名
音域
半音
頻率
CSS
position
synth keyboard
z-index