tonaljs / tonal Goto Github PK
View Code? Open in Web Editor NEWA functional music theory library for Javascript
Home Page: https://tonaljs.github.io/tonal/docs
A functional music theory library for Javascript
Home Page: https://tonaljs.github.io/tonal/docs
I am trying to use Chord.supersets()
to generate a list of subnames that produce computable chord names when joined into a string.
I would expect, for example, 'AMaj7'
to give 'AMaj7add13'
as a subset. Removing the original chord from this string leaves me with 'add13'
which would be used to populate a select-button.
But 'AMaj7add13'
is actually 'AM7add13'
in the tonal library.
Wondering if this was done for any reason besides brevity...
I'm considering forking and having 'Maj'
be the only representation used. Do you forsee any complications with this?
Fantastic work, thank you for this awesome contribution to npm!
Are there any functions for creating a note from abc notation?
The docs for chord.parse say it returns an Array but it returns an Object.
Speaking of chord.parse, it'd be cool if the returned object contained more granular information about the parsed chord. Right now I'm using tonal in conjunction with another package called chord-magic which does basically the same thing, except its chord parser also gives the following:
If tonal's chord.parse gave that kind of information I'd only have to depend on one library for chord parsing!
Hey @danigb,
I just noticed that when I try to run your library from mobile Safari, it throws an error:
"SyntaxError: Unexpected keyword 'const'. Const declarations are not supported in strict mode."
I don't know if the problem is iOS (9.3.5) not supporting ES6 or if strict mode should't be specified in each of your modules.
I'm using tonal in combination with Midiguchi, and one thing that is happening for me right now, which i think is an issue with the library.
I'm using tonal.chord.detect([notes])
to get the chord name and then later on i use tonal.chord.parse([chordname that i got from detect])
to get the chord type.
This all works fine, but one issues i'm having right now is that whenever tonal.chord.notes()
encounters a 7something chord (7sus4, 7sus2, 7add6) it won't return notes (it'll just return an empty array) and when i try to parse it i get back { type: 'add6', tonic: 'Eb7' }
(if the chord was a "Eb7add6").
Is there anything i can do to fix this?
Thanks
Looks like there's a lot of missing pages in the GitHub.io docs ๐
Is this a mistake, or is the documentation incomplete?
There's a bug detecting diminisheds in harmonize
. The example from the README states:
tonal.harmonize('P1 m3 d5', 'C') // => ['C', 'Eb', 'Gb']
yet only ['C', 'Eb']
is yielded
I'll just copy the terminal commands I used:
git clone -b tonal-0.50.x --single-branch https://github.com/danigb/tonal.git
cd tonal
npm install
npm test
this resulted in
65 passing (125ms)
3 failing
1) collections filter filter lists:
TypeError: undefined is not a function
at Array.filter (native)
at dist/tonal.js:616:68
at Object.filter (dist/tonal.js:616:43)
at Context.<anonymous> (test/collections-test.js:86:26)
2) intervals isIntervalStr test if its interval string:
TypeError: _.isIntervalStr is not a function
at Context.<anonymous> (test/interval-test.js:12:22)
3) intervals isIntervalStr interval strings are recognized:
TypeError: undefined is not a function
at Array.map (native)
at dist/tonal.js:603:65
at Context.<anonymous> (test/interval-test.js:18:24)
then I continued with:
npm run packages-install
npm run packages-build
npm run packages-test
which gives this error:
module.js:339
throw err;
^
Error: Cannot find module 'tonal-pitches'
at Function.Module._resolveFilename (module.js:337:15)
at Function.Module._load (module.js:287:25)
at Module.require (module.js:366:17)
at require (module.js:385:17)
There used to be a documentation site: https://danigb.github.io/tonal/api/index.html
Why is it gone?
I am a bit lost about where to find the old tonal.note.enharmonics
. I see you made enharmonics package in extensions, but this is not in the final release? Do you plan to add it?
thanks
NPM has version 0.50.5
and the package.json on here says 0.50.0
. The docs seem to be outdated on both GitHub and NPM since there is no scale.get
but a scale.scale
function.
Thanks for this amazing library of useful bits!
I was wondering how the main tonal/lib/tonal.js
file relates to the individual packages. I don't see how they are connected. Will usage be like:
import tonal from 'tonal'
const myScale = tonal.scales.scale('major', 'A4')
and/or:
import { scale } from 'tonal-scales'
const myScale = scale('major', 'A4')
Hi
When I log the example Tonal.chord.detect('g f# d b')
,
I got the following warning pcset.chromaModes deprecated. Renamed to pcset.modes
Sounds not so good... and a bit lost
How can I handle it?
Thank you
The manual gives the following example:
import { tranposeBy } from "tonal-distance"
transposeBy("3m", "5P") // => "7m"
Which won't work with two intervals. One should use add instead.
hello again
Tonal.Chord.tokenize('C11') // ["C11", ""]
Tonal.Chord.tokenize('aug') // ["A", "ug"]
The following functions are also associated.
Chord.intervals
Tonal.Chord.intervals('C13no5') // []
Tonal.Chord.intervals('aug') // []
I'm looking for a way to convert a set of intervals to the chords they make (the inverse of chord.intervals)
Instinctively I've tried tonal.chord.detect('1P 3M 5P')
but it didn't work.
It looks like all the information is there but I'm not sure the api allows me to do this. Is there a clever way to do this I didn't see ?
Thanks !
Working beautifully on my app in the key of C. Registral errors occurring when tranposing to other keys. Console logged some of these out:
Interval structure returned is correct.
myscale = Tonal.scale('major');
=>["1P", "2M", "3M", "4P", "5P", "6M", "7M"]
Great in the key of C.
myscale.map(Tonal.transpose('C2'));
=>["C2", "D2", "E2", "F2", "G2", "A2", "B2"]
We start to see registral problems when transposing to other keys.
myscale.map(Tonal.transpose('D2'));
=> ["D2", "E2", "F#2", "G2", "A2", "B2", "C#3"]
myscale.map(Tonal.transpose('E2'));
=> ["E2", "F#2", "G#2", "A2", "B2", "C#3", "D#3"]
etc...
Can't wait to introduce this functionality to my app! Thanks again!
With latest versions from NPM:
> range = require('tonal-ranges')
> range.scale('C D E F G A B', 'C3', 'C2')
[ 'C3', 'B2', 'A2', 'G2', 'F2', 'E2', 'D2', 'C2' ]
> tonal = require('tonal']
> tonal.scaleRange('C D E F G A B', 'C3', 'C2')
[ 'C3' ]
Hi there,
I was wondering about the note-range package. It appears it is not part of the current npm install of tonal and has the 'npm invalid' tag. Will it be included in a next release, or is there another way I can use it?
thanks
I'm replacing some of my half-baked code by your awesome tonal but converting my tests I'm getting puzzled by the output of scale detect. Here's what I'm doing:
`tonal = require("tonal");
processChordList = function(chordArray)
{
var notes = [];
chordArray.forEach(function(chordName)
{
var chordNotes = tonal.chord.notes(chordName);
notes = notes.concat(chordNotes);
})
result = tonal.scale.detect(notes);
console.log("-----------------------------------------------------");
console.log("Input chords: " + chordArray.join());
console.log("Notes: " + notes.join());
console.log("");
console.log("Resulting scales");
console.log(result);
}
processChordList(["cm"]);
processChordList(["cm", "a#"]);
processChordList(["cm", "a#", "fm"]);
processChordList(["cm", "a#", "fm", "g#"]);
processChordList(["cm", "bb", "fm", "ab"]);
`
That leads to
Input chords: cm
Notes: C,Eb,G
Input chords: cm,a#
Notes: C,Eb,G,A#,C##,E#
Input chords: cm,a#,fm
Notes: C,Eb,G,A#,C##,E#,F,Ab,C
Input chords: cm,a#,fm,g#
Notes: C,Eb,G,A#,C##,E#,F,Ab,C,G#,B#,D#
Input chords: cm,bb,fm,ab
Notes: C,Eb,G,Bb,D,F,F,Ab,C,Ab,C,Eb
Resulting scales
[ 'C aeolian',
'C locrian',
'C major',
'D dorian',
'Eb phrygian',
'Eb lydian',
'F mixolydian' ]
`
I'm expecting c minor to show everytime and certainly not C Major to show up.
Am I doing something wrong ?
Currently Array.compact and Array.cMap filters 0, but it shouldn't.
When I use yarn link
in the root of the tonal package, it links tonal-core
. I can import tonal-core
in my own project, and it works, but is this the expected behaviour?
If I cd to packages/tonal
and link there, it links tonal, but when I import * as tonal from 'tonal'
in my project I get:
dev/experiments/tonal-exp/node_modules/tonal/node_modules/tonal-array/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import { midi, name } from "tonal-note";
^^^^^^
SyntaxError: Unexpected token import
at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/ScriptTransformer.js:289:17)
at Object.<anonymous> (node_modules/tonal/build/transpiled.js:5:13)
at Object.<anonymous> (src/tests/index.test.js:3:13)
This also happens when I use const tonal = require('tonal')
As requested by @danigb in #57 (comment)
#57 addresses two main issues with Note.midi
.
First, it fixes a few bugs with the current Note.midi
implementation:
Note.midi(0)
returns null
. It should return 0
.Note.midi("c-1")
returns null
. It should return 0
.Note.midi(true)
returns 1
. It should return null
.Second, it changes Note.midi
to only return numbers in the range of 0 to 127. Currently, Note.midi
returns numbers outside this range, which I consider to be a bug. For example:
Note.midi(128)
returns 128
. It should return null
.Does that make sense?
Sorry for the possibly n00b question but after a npm install tonal
I don't seem to be able to use the 'extensions'. I'm after Tonal.Key and Tonal.Detect...
Do I need to to anything special in order to use them ?
Thanks !
Hi. When doing note.alt('C#2')
, I see the following warning:
note.props() is deprecated. Use: note.step(), note.alt() or note.oct()
Am I doing something wrong?
Hey there, thanks for the great library!
I'm wondering if there is a way to transpose a note through multiple registers (ex: C3 -> C5, etc) using Tonal.transpose().
I'm making an app that dynamically generates tables of numbers and assigns notes to the numbers using modular arithmetic. Note names are right, just need to find a way to scale them to their proper register :)
I can't seem to figure out how to convert the results from Scale.notes('Bb lydian')
to MIDI values.
The results from Scale.notes('Bb lydian')
are in the form ["Bb", "C", "D" ...]
. There's no pitch data . This is causing an issue because I need the MIDI values of this scale. midi(...)
doesn't seem to work unless there's a pitch associated with the note.
I have also tried toNote
from tonal-abc-notation
but the following fails: toNote("Bb")
. It returns null
for the flat notes. Not sure if that's a bug or intended.
Is there an easier way to get the scale values as midi number as opposed to ABC strings?
Hi, trying to use the minified js file and getting this error:
Uncaught TypeError: Cannot read property 'toFreq' of undefined
at tonal.min.js:1
at tonal.min.js:1
at tonal.min.js:1
Any advice?
Occurrences of note Cb in a scale in the scale app, drops one octave. Similarly any B# is raised an octave. Or so it seems, I did not check all the scales and keys, but found this:
B# turns out to be raised in...
... E bebop major
... F# and A hungarian major
... E ionian augmented
...
Cb is dropped in...
... Db, Eb, and Ab aolean
... Eb, Ab, and Bb balinese
... Db and Ab dorian
... Db egyptian
... Ab flat three pentatonic
... Db hungarian major
... Eb and Bb kumoijoshi
...
I try to understand how to detect chords from a group of notes.
I am using the simple method Tonal.chords.detect(notes)
var test= [
Tonal.chord.detect('g f# d b'),
Tonal.chord.detect('g5 f5# d5 b5')
];
console.log(test);
Output:
["GMaj7"]
["GM","Bm#5"]
Why dont we get the union of the two in each case?
Note : if there is useful litterature/links on the subjects, I am willing to study it and try implemting something.
First of all @danigb thanks for this awesome library.
I'd like to propose a small addition that I would find useful. Adding a set
function to the tonal-note module
The docs for such a function would be somewhat like this:
(static, constant) set
Given a note (string) and an object with props, return the note that results from overriding the given note with those props
Example:
Note.set("C4", {alt: 1, oct: 3}) // => "C#3"
Happy to make a PR with the change if you find it useful. I'm thinking the implementation of this as a combination of build
and props
Hi @danigb
cross-posting from this issue : danigb/tonal.chord#1
as I'm a bit confused, tonal-chord was usable client side, but it seems that tonal is nodejs based and supposed to run server-side am I right ? is there a client-side distribution ?
tonal-scale
seems to rely on rollup-plugin-json. the only thing is that since I'm using rollup in my project, I had to figure out that I needed to use rollup-plugin-json in my rollup configuration too. This seems like a funky area with rollup/es6 modules.
Hi! I just wanted to try out your library but ran into an error during npm install.
The error I get is this:
npm ERR! 404 Registry returned 404 for GET on https://registry.npmjs.org/note-transpose
npm ERR! 404
npm ERR! 404 'note-transpose' is not in the npm registry.
From your NPM registry page I found that the note-transpose
module has an npm invalid flag.
Also the link to the repository is no longer available on github.
Hello @danigb,
Thank you for this amazing library!
Very impressive piece of work.
Is there a way to convert a list of notes to a scale?
e.g. I have the following array:
["a", "c", "e", "g"]
and what I'd like to achieve is
["A4", "C5", "E5", "G5"]
Thank you again!
Hi,
are modes implemented (o can they) in any way?
From a computing point it could simply be a circular shift of a scale notes array, possibly having a name (but not necessarily, for the library purpose, could be up to the programmer to associate e.g. "Aeolian" name - also in different languages - to the Scale.mode(6).
This could be applied to any scale (programmer has to be aware of what he's doing)...
so that if a C major scale is [C, D, E, F, G, A, B]
with two circular shift we could obtain a Phrygian scale
like: C_major_scale.mode(3) = [E, F, G, A, B, C, D]
this could be used mainly for the common scales (major, melodic minor, harmonic minor, harmonic major) but since it'd be a generic mechanism, it could be applied to any scale, so that
Any_Major_scale.mode(6) = Aeolian array scale (natural minor)
Any_Aeolian_scale.mode(2) = Ionian array scale (major scale)
Any_Melodic_minor_scale.mode(4) = Lydian augmented array scale
.. etc etc...
Moreover, comes in mind a scale transformation function, to obtain parallel modes by dropping the right degrees, so that, e.g. you can obtain a melodic minor scale by flatting the 3rd degree of any major scale object...
I'll take some time to browse through the code, although I think my JS skills still are still lacking a bit...
Hi, are there any plans to support solfege/solfa notation?
I recently started using Tonal in a project at SightReadingMastery, and it would be very useful there. I can imagine it would be in many other applications as well. I noticed Teoria supports this feature as well.
Tonal is a fantastic library! Kudos to everyone who has made it possible.
I want to transpose notes an octave down and tried tonal.transpose(note, '-P8');
but that didn't work and I couldn't find anything in the docs pertaining to direction of the interval you wish to transpose by.
Hi @devboell,
I would like to have a tonal-fretboard module, and I thought maybe we can share some ideas before. The API I was thinking is something like this:
tuning(name)
: return an array of notes with the strings in open position. For example, for tuning('guitar')
it would return ['E2', 'A2', 'D3', 'G3', 'B3', 'E4']
. A kind of dictionary of corded instruments tunings.build(tuning, first, last)
: build a fretboard with the given tuning, from first
fret number to last
fret number. It returns an array of arrays, one for each string.buildSet(tuning, set, first, last)
: the same of above, but nulls instead of note names for the notes that doesn't belong to the set.What do you think? Do you find useful? Anything missing?
Cheers,
Dani
Calling chord detection returns the '64' form for major chords which I found confusing as I had no idea what it meant.
Detect.chord([ '1P', '3M', '5P' ])
=> detected C64,Em#5
The example given here is broken.
> Bjorns-MacBook-Pro:zeitgeber bjornwestergard$ node
> var tonal = require('tonal')
undefined
> tonal.chord('C7')
TypeError: tonal.chord is not a function
at repl:1:7
at REPLServer.defaultEval (repl.js:252:27)
at bound (domain.js:287:14)
at REPLServer.runBound [as eval] (domain.js:300:12)
at REPLServer.<anonymous> (repl.js:417:12)
at emitOne (events.js:82:20)
at REPLServer.emit (events.js:169:7)
at REPLServer.Interface._onLine (readline.js:211:10)
at REPLServer.Interface._line (readline.js:550:8)
at REPLServer.Interface._ttyWrite (readline.js:827:14)
Hi Dani, how are you?
I thought I'd try the new version, but I get an error when I import tonal.
F.i. if I try to use the tonal-note
package,
import * as tonal from 'tonal'
console.log('tonal.note.midi', tonal.note.midi('C3'))
I get:
dev/experiments/tonal-exp/node_modules/tonal-note/index.js:36
export function tokenize(str) {
^^^^^^
SyntaxError: Unexpected token export
at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/ScriptTransformer.js:289:17)
at Object.<anonymous> (node_modules/tonal/build/index.js:5:13)
at Object.<anonymous> (src/tests/index.test.js:2:14)
It seems that tonal/index.js
is exporting the tonal-note/index.js
, and not the transpiled tonal-note/build/index.js
. Could that be the reason?
Currently, there are too many functions to learn. Some of them are not relevant to end user, so they should be removed from API. Some other are too obscure features (pcset-dft
, for example) than should be moved to a less noisy place.
Focus: some functional functions are provided (like map
). That's not the scope of tonal.
All the core should be stable. Extensions should be stable. Incubator packages are allowed to be unstable.
note.split('Eb major')
note.parse('Eb')
note.names() // => ["C", "C#/Db", "D", "D#/Eb", "E", "F", "F#/Gb", ...]
note.name('c3') // => 'C3'
note.chroma('D4') // => 2
note.freq(note)
note.midi(note)
note.octave(note)
note.fromFreq(freq)
note.fromMidi(69) // => 'A4'
note.inOctave(5, "C#3") // => "C#5"
interval.name("3m") // => "3m"
interval.name("m3") // => "3m"
interval.name("P3") // => null
interval.num("m9") // => 9
inteval.num("9M") // => 9
interval.type("A4") // => "perfectable"
interval.semitones("5P") // => 7
interval.simplify("9M") // => "2M"
interval.invert("2M") // => "7m"
distance.transpose(note, interval)
distance.transposeBy(interval, note)
distance.interval(from, to)
distance.intervalTo(to, from)
distance.add("2M", "2m") // => "3m"
distance.subtract("2M", "5P") // => "4P"
array.split(arr) strings to arrays
array.notes(arr) remove all but notes
array.pcset(arr) pcset, ordered starting from C
array.scale(arr) pcset, ordered, the first note is preserved
array.chord(arr) sorted, remove repetitions
// utility
array.sort(notes)
array.rotate(notes, preserveOctaves: boolean)
// range(['C4', 'C5'], [filter])
range(['C4', 'C5'])
range(['C4', 'C5', 'C3'])
range('C4 C5 C3');
range('C4 C5', 'c d e f g a b')
// filterBy(notes)
const inC = filterBy('c d e f g a b') // => function
inC('C4') // => true
inC('C#4') // => false
cycle('P5', 'C4', 4)
type scale = note[]
// types(aliases)
types(false) // => ['major', 'melodic minor', ...]
// fromName(name, [tonic]) // tonic === null => intervals
fromName('C major') // => ['C', 'D', ...]
fromName('major', 'C') // => ['C', 'D', ...]
fromName('major') // => ['1P', '2M', ...]
// find(notes) => { exact: "", modes: [], includedIn: [], extendedBy: [] }
find('c d e f g') // => {
// exact: null,
// modes: [],
// included: ['C major', ...],
// extendedBy: []
// }
// degree(name)(step)
type chord = note[]
types(false) // => ['major', 'melodic minor', ...]
fromName('Cmaj7') // => ['C', 'E', 'G', 'B']
fromName('maj7', 'C') // => ['C', 'E', 'G', 'B']
fromName('maj7') // => ['1P', '3M', ..]
// find(notes)
// triad(notes)(length)
triad('c d e f g a b c', 3) // => ['C', 'E', 'G']
triad('c d e f g a b c', 3) // => ['C', 'E', 'G']
type key = string
altered('F major') // => ['Bb']
signature(name) // ### or bbb
scales() // => ["C major"] , ["A minor", "A melodic minor", "A harmonic minor" ]
names() // ionian, dorian (major, minor are aliases)
relative(mode, type)
scale(mode)
chord(mode)
modes(mode) // modes("C major") // => ["D dorian", ...]
harmony() => [
{ tonic: "C", degree: 'I', types: ["M", "Maj7", "M9", f: "tonic" },
{ tonic: "D", degree: 'I', types: ["m", "m7"], f: "subdominant" },
...
]
Hello.
Great repo, is there any support for slash chords? https://en.wikipedia.org/wiki/Slash_chord
I couldn't find anything in the docs.
Like, D/F#
?
I'd like to transpose it but I get something like ["E", null, "G#"]
๐บ
Hey @danigb what do you think about adding a second, boolean, parameter to Key.chords
to return the triad chords instead of the seventh chords.
I believe that, as an exception, for the case of a major scale, the 5th grade should still be returned as a seventh chord to keep its dominant quality
So something like:
Key.chords('A minor', true) // [ 'Am', 'Bmb5', 'C', 'Dm', 'Em', 'F', 'G' ]
Key.chords('C minor', true) // [ 'C', 'Dm', 'Em', 'F', 'G7', 'Am', 'Bmb5' ]
What do you think? As always, if you like the feature, I can do a PR to include it
I have a particular use case for enharmonics. I find enharmonics tricky because you can have more than one accidental. For my case I am only interested in getting the enharmonic for one accidental, and if the note has no accidental it should return the note itself. (I hope this makes sense).
for example:
C => C
C3 => C3
C# => Db
C#3 => Db3
Db3 => C#3
I made a method that could fit in tonal.note. I called it equiv (from equivalent), but that is probably not the right name.
export const equiv = (str) => {
const a = alt(str)
const s = step(str)
const o = oct(str) || undefined // convert null to undefined
return build({step: a + s, alt: -a, oct: o})
}
with two test cases:
test("equiv pc", () => {
const FLATS = "C Db D Eb E F Gb G Ab A Bb B".split(" ");
const SHARPS = "C C# D D# E F F# G G# A A# B".split(" ");
const flatEquivs = FLATS.map(note.equiv)
const sharpEquivs = SHARPS.map(note.equiv)
expect(flatEquivs).toEqual(SHARPS)
expect(sharpEquivs).toEqual(FLATS)
});
test("equiv pitch", () => {
const FLATS = "C3 Db3 D3 Eb3 E3 F3 Gb3 G3 Ab3 A3 Bb3 B3".split(" ");
const SHARPS = "C3 C#3 D3 D#3 E3 F3 F#3 G3 G#3 A3 A#3 B3".split(" ");
const flatEquivs = FLATS.map(note.equiv)
const sharpEquivs = SHARPS.map(note.equiv)
expect(flatEquivs).toEqual(SHARPS)
expect(sharpEquivs).toEqual(FLATS)
});
I am not suggesting this should be in tonal, but I am curious what your thoughts are about this. Does this somehow correspond to a concept in music theory, or does it go against the logic of enharmonics, and maybe shouldn't be handled this way?
thanks
@danigb I found a little bug:
progression.concrete('I II III IV V VI VII', 'C')
returns:
['C', 'D', 'E', 'F', 'G', 'A', 'null']
Love tonal, thanks for sharing!
Saludos ๐บ
hi @danigb
The problem was discovered a week later.
aug\Dom\dim chords can't get notes
Chord.notes("Caug") // []
Chord.notes("C","aug") // []
I've found that this function does a little bit more processing
Chord.tokenize("aug") // ["A", "ug"]
tokenize
This function is executed twice
...
export const intervals = name => props(tokenize(name)[1]).intervals;
export function notes(nameOrTonic, name) {
const p = tokenize(nameOrTonic);
name = name || p[1];
return intervals(name).map(transpose(p[0]));
}
The output of Key.chords("C major")
is CMaj7, Dm7, Em7, FMaj7, G7, Am7, Bm7b5
.
Why are the 7th chords used? Shouldn't it be C, Dm, Em, F, G, Am, Bdim
like for instance here https://www.theguitarlesson.com/guitar-theory/guitar-chords/key-c-major/?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.