lightbend / paradox Goto Github PK
View Code? Open in Web Editor NEWMarkdown documentation
Home Page: https://developer.lightbend.com/docs/paradox/current
License: Apache License 2.0
Markdown documentation
Home Page: https://developer.lightbend.com/docs/paradox/current
License: Apache License 2.0
We need a custom directive for akka-http for a customization of @snip
to include scala signatures from files. This is possible to do by adapting the paradoxProcessor
key like this:
val paradoxWithSignatureDirective = Seq(
paradoxProcessor in Compile ~= { _ =>
// FIXME: this is a HACK so far that copies stuff over from paradox
// it would be better if the plugin has a way of specifying extra directives through normal sbt mechanisms
new ParadoxProcessor(writer =
new Writer(serializerPlugins = context =>
Seq(
new ActiveLinkSerializer,
new AnchorLinkSerializer,
new DirectiveSerializer(Writer.defaultDirectives(context) :+
new SignatureDirective(context.location.tree.label) // <-- only line that is no boilerplate
))))
}
)
It would be nice if custom directives could be specified by just adding them to key.
Simple console output is often included in the docs as
output here
For some reason Paradox attempts to syntax highlight these.
E.g.
@ref:[Mailing List](../support.md#mailing-list)
Asking here, hope you don't mind :)
Is current behaviour to fail if @@snip
did not find a snippet?
Try using without themes
java.lang.NullPointerException
at com.lightbend.paradox.template.PageTemplate.write(PageTemplate.scala:35)
at com.lightbend.paradox.ParadoxProcessor.com$lightbend$paradox$ParadoxProcessor$$render$1(ParadoxProcessor.scala:56)
at com.lightbend.paradox.ParadoxProcessor$$anonfun$process$1.apply(ParadoxProcessor.scala:60)
at com.lightbend.paradox.ParadoxProcessor$$anonfun$process$1.apply(ParadoxProcessor.scala:60)
at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251)
at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251)
at scala.collection.immutable.List.foreach(List.scala:318)
templates.getInstanceOf(name) is null
Display an error message.
Currently paradox output in paradox docs is presented as images which enable misdocumentation like this: #72
Add pull request validation. Could be on Travis now that this is open sourced. Previously under Lightbend CI.
The documentation on the page http://developer.lightbend.com/docs/paradox/latest/features/theming.html#create-local-templates is not working. I have this build.sbt
:
name := "Foo Bar"
scalaVersion := "2.12.1"
enablePlugins(ParadoxSitePlugin)
paradoxTheme := None
But when I run sbt previewSite
, it doesn't find the template:
java.lang.RuntimeException: StringTemplate 'page' was not found for '/home/hhrutz/IEM/Projektantraege2014/website/target/paradox/paradox/html/index.html'. Create a template or set a theme that contains one.
at scala.sys.package$.error(package.scala:27)
at com.lightbend.paradox.template.PageTemplate.write(PageTemplateSystem.scala:55)
I have copied the generic theme:
$ ls -la src/main/paradox/_template/
total 48
drwxr-xr-x 4 hhrutz hhrutz 4096 Jan 30 16:25 .
drwxr-xr-x 3 hhrutz hhrutz 4096 Jan 30 16:28 ..
drwxr-xr-x 3 hhrutz hhrutz 4096 Jan 30 16:20 css
drwxr-xr-x 2 hhrutz hhrutz 4096 Jan 30 16:20 js
-rw-r--r-- 1 hhrutz hhrutz 622 Jan 30 16:20 menu.st
-rw-r--r-- 1 hhrutz hhrutz 298 Jan 30 16:25 navigation.st
-rw-r--r-- 1 hhrutz hhrutz 3990 Jan 30 16:20 page.st
-rw-r--r-- 1 hhrutz hhrutz 145 Jan 30 16:20 source.st
-rw-r--r-- 1 hhrutz hhrutz 42 Jan 30 16:20 title.st
or maybe just document how that is possible. It should be a layered approach where some things can be just configured (like footer HTML) while others things would need complete replacements of parts of a template.
0.2.4 tag (and the jars in the maven central) does not have the fixes mentioned in the release docs.
* 5b38595 (HEAD -> master, origin/master, origin/HEAD) 0.2.4
* dd99f80 0.2.3 notes
* ae3ac26 0.2.2 notes
* 3c7a5dd Merge pull request #34 from gsechaud/refErrorMessage
|\
| * b78916d Fix and add tests
| * 420aabd Fix ref bug with anchor
* | 93818c2 Merge pull request #30 from gsechaud/fixTheme
|\ \
| |/
|/|
| * 2f14457 Modify unexpected behaviour of property getter
| * 17ac0f9 Add directory in template caching
| * 7ab8fc3 Fix css/js theme generation bug
| | * 1900af5 (tag: v0.2.4) 0.2.4
| | * 20bc85b 0.2.3 notes
| | * d94de8d 0.2.2 notes
| |/
|/|
* | bca0487 0.2.4-SNAPSHOT
* | 002a20b (tag: v0.2.3) 0.2.3
* | fbcc979 Merge pull request #32 from jrudolph/patch-1
|\ \
| |/
|/|
| * a7149d9 disable pegdown HARDWRAPS option, fixes #31
|/
* 0fdbdac Merge pull request #28 from gsechaud/propFrontMatter
In releasing 0.2.7 I ran release
, but then had to make the following changes:
bintrayRelease
publishSigned
(which required adding sbt-pgp)Linking to javadocs with the @scaladoc directive doesn't work properly as the format of deep-links differs between javadoc and scaladoc sites.
For example with this configuration
"scaladoc.org.reactivestreams.base_url" -> "http://www.reactive-streams.org/reactive-streams-1.0.0-javadoc/"
this snippet
@scaladoc:[Publisher](org.reactivestreams.Publisher)
gets rendered as
http://www.reactive-streams.org/reactive-streams-1.0.0-javadoc/#org.reactivestreams.Publisher
when it should be rendered as
http://www.reactive-streams.org/reactive-streams-1.0.0-javadoc/org/reactivestreams/Publisher.html
Depends on #11 (about switching all tabs)
If I'm a Java or Scala person, I always want to go to a page and keep seeing the Java (or Scala) snippets, so I don't get angry about clicking those tabs all the time ;-)
Very important feature to not make users angry about the tabs IMO.
For example, I have the following in a markdown document:
- [All Platforms](https://github.com/Sciss/ScalaColliderSwing/releases/download/v@var:[scalacollider-swing.version]/scalacolliderswing-@var:[scalacollider-swing.version]-universal.zip)
And in build.sbt
:
paradoxProperties in Compile +=
"scalacollider-swing.version" -> "1.32.0"
I'm expecting the link to be resolved as
- [All Platforms](https://github.com/Sciss/ScalaColliderSwing/releases/download/v1.32.0/scalacolliderswing-1.32.0-universal.zip)
before rendering. Can this be done?
Paradox seems to add the HARDWRAPS option to pegdown (by using Extensions.ALL
as the default in the Reader
constructor) which will introduce line breaks (<br/>
) for each line break in the source.
This is a behavior that was introduced in Github and which may make sense if input is mainly entered through text input fields that automatically wrap long lines. However, for reading text files that are usually manually wrapped it makes more sense to join lines as intended by the original markdown definition.
See akka/akka-http#382 as an example where hard-wraps where unexpected.
Demo here: https://andreatp.github.io/akkadoc-poc/
Was implemented PoC by @andreaTP here: andreaTP@e7037d4
As noted here: akka/akka-http@f349d90
There's a strange thing with how the Pegdown parser handles content
inside a container directives (@@@
) where it will honour the new lines
if there's no empty line between the directive marker and the first
text.
It would be nice if Paradox would render
@@@ note
A
B
@@@
and
@@@ note
A
B
@@@
in the same way.
It would be nice if paradox comes with a built-in indexed documentation search. The Lagom documentation is using docsearch.js for it. With that, any documentation page is listed, incl. the sub section that contains the search term.
Many of our users/readers perfer to have a PDF version. We should have some options for this, maybe as simple as emitting LaTeX from the DOM.
With built in:
val root = project.in(file("."))
.enablePlugins(ParadoxPlugin)
.settings(
name := "Foo Bar",
scalaVersion := "2.12.1",
paradoxTheme := Some(builtinParadoxTheme("generic"))
)
Looks right:
Now changing to custom:
val root = project.in(file("."))
.enablePlugins(ParadoxPlugin)
.settings(
name := "Foo Bar",
scalaVersion := "2.12.1",
paradoxTheme := None
)
copying the generic theme from the paradox repository:
cp -r ../paradox/themes/generic/src/main/assets src/main/paradox/_template
We get weird result:
It would be great if paradox could track the source files (custom template, input markdown etc.) and automatically re-render when running as sbt ~paradox
and one edits a file, e.g. page.st
.
Would need to be aware of which version it is, and where scaladoc is located.
Linking to the 2.12 style scaladoc does not work. New scaladoc does have frames and does not suport #akka.stream....
at the end of the links. For the new scaladoc the url should be
http://developer.lightbend.com/docs/api/alpakka/latest/akka/stream/alpakka/amqp/QueueDeclaration.html
instead of
http://developer.lightbend.com/docs/api/alpakka/latest/#akka.stream.alpakka.amqp.QueueDeclaration
This could be implemented as a new directive (e.g. @nscaladoc
, for new scaladoc).
Or we could make the current @scaladoc
directive smarter to automatically determine if there is old or new sclaladoc at the end of the link. Could be a foundation for (or result of) #53.
I want to be able to pass in template values at the page level like this:
---
layout: something
out: foo.html
---
I've implemented that for Pamflet similar to Jekyll's YAML front matter, and it's pretty useful.
On Lagom, we generate docs as unstyled HTML snippets with an index, this then gets included in the main Lagom website source, which then puts the current Lagom theme around all the snippets from every version, and is able to do smart linking between versions (change the version and it goes to the current page in that version, but only if it exists, otherwise it goes to the index). By doing this, we ensure that if we update the Lagom website in future, we don't need to go back and regenerate the docs for old versions, and we don't end up in a situation like Akka where old versions use the old styling. This approach also avoids a situation like Play has where it has to support 3 different types of documentation because it generates the documentation on the fly from the original sources for all versions.
However, when we're developing the docs, we don't want snippets, we want them styled with navigation, so we need to be able to easily use one theme for development, and one theme when we generate the docs for inclusion in the Lagom website.
(version 0.2.7)
The docs here says (http://developer.lightbend.com/docs/paradox/latest/features/snippet-inclusion.html):
sbt
: @@snip [build.sbt](/../../../build.sbt) { #setup_example }
Maven
: @@snip [pom.xml](../../../pom.xml) { #setup_example }
But in reality you need a newline:
sbt
: @@snip [build.sbt](/../../../build.sbt) { #setup_example }
Maven
: @@snip [pom.xml](../../../pom.xml) { #setup_example }
In the Akka docs a lot of snippets refer to multiple sections, e.g. to list imports along with the code, either using multiple labels:
.. includecode:: code/docs/actorlambda/MyActor.java
:include: imports,my-actor
or by using the same label multiple times:
//#example
import a.A
//#example
object B {
//#example
def b(a: A): Int = ???
//#example
}
For akka/akka-http#1, the second case is more important and currently causes a block not closed
error.
Currently each page requires H1 level header.
Allow the first h2, h3, or h4 to be a title too.
Currently newlines introduce <br>
s. Is it possible to customize it/make it follow basic MD behavior, i.e., hard breaks are inserted only when the line terminates with >2 spaces ?
Using "API reference guides" for lack of a better word describing documentation which is tightly coupled to the implementation but higher level than Scaladoc and Javadoc and more like UNIX man pages containing both API and example code snippets etc.
A good example is Akka HTTPs directive documentation and the related ticket akka/akka-http#25:
Scaladoc and Javadoc doesn't allow to easily organize and create such references. Furthermore, Scaladoc (up until 2.12) is not very search engine friendly, which is crucial for this type of documentation.
The question is if this is out of scope for Paradox itself since it would require some tight integration with scaladoc and/or javadoc generators. However this is also the case if cross references to source code is a goal as suggested in #25.
The [Lightbend theme](https://github.com/typesafehub/paradox-theme-lightbend) is a good example of what should look like a paradox theme repository.
Often we have to provide two sets of documentation, one for Java users, and one for Scala users. There are some pages that end up being shared between them. Attempts to include these in a single manual result in weird things like in Akka, it's very easy when navigating through the Java documentation to end up at the Scala documentation because you clicked a link to a shared page, and then clicked the next link which took you to something Scala specific.
Paradox should provide something that allows keeping the rendered manuals entirely separate, but allows sharing pages describing concepts, installation instructions, etc, between the two manuals. My suggestion would be to allow having a common directory, and then to "overlay" that directory with the language specific documentation. So for example:
manual
- common
- index.md
- gettingstarted
- installation.md
- getting-started.md
- java
- actions
- actions.md
- routing.md
- scala
- actions
- actions.md
- routing.md
If done right, this can actually be very useful beyond just providing multiple programming languages to share resources, it can also be used for providing translations, as the translations can simply overlay the original, allowing things like code snippets from the original to be reused in the translations. We have successfully applied this approach in the Play documentation.
According to the docs, this should be possible:
In build.sbt
:
paradoxProperties in Compile ++= Map(
"image.base_url" -> "assets/images",
"foo" -> """<span class="special">bar</span>"""
)
In test.md
:
$foo$ should read bar with special CSS.
But it simply renders $foo$
instead of bar
inside a <SPAN>
.
Or am I doing something wrong?
The paradox sbt plugin should provide a task for validating docs. This should include:
An additional task should be provided that checks for dead external links - this should be an additional task, since a task that calls out to many external websites will cause problems if run from CI, both in terms of false negatives and also it's not playing nicely on the web. Instead the intent would be to run this task manually every so often.
This is an offshoot of #64 and lightbend/ssl-config#51.
Use Generic theme and put the following in the body:
```
curl https://financialcryptography.com # uses cacert.org as a CA
```
The syntax highlighting here is too aggressive, and doesn't really make sense to me.
This also manifests itself when there are single quotes used in the middle of the text as apostrophe.
Kramdown / Redcarpet or whatever that implements GFM uses ```
to indicate plain text without any special postfix. We should do the same.
https://help.github.com/articles/creating-and-highlighting-code-blocks/
Currently, it is not possible to include a Snippet whose id starts with a number. For example:
@@snip [Fooscala](path/to/Foo.scala) { #0id }
won't include the code surrounded by //#0id
For project documentation with deeply nested pages it would be helpful to support referencing files using absolute paths which resolve against for example the project root.
An example from Akka HTTP docs:
file: /docs/src/main/paradox/scala/http/common/http-model.md
## Instead of:
@@snip [ModeledCustomHeaderSpec.scala](../../../../../../../akka-http-tests/src/test/scala/akka/http/scaladsl/server/ModeledCustomHeaderSpec.scala) {
## Use the following:
@@snip [ModeledCustomHeaderSpec.scala](/akka-http-tests/src/test/scala/akka/http/scaladsl/server/ModeledCustomHeaderSpec.scala) {
The root could be configurable via the SBT plugin. The main downside is that links won't be "GitHub friendly".
The alternative is to not nest documentation files inside src/main/paradox
but instead in for example /docs/
and example source code somewhere other than /docs/src/main/scala
.
paradox currently builds upon pegdown
as the underlying markdown parser. Although pegdown has a number of serious issues it comes with quite a large feature-set and has long been one of the few "go-to" markdown-parsing solutions on the JVM.
Unfortunately, pegdown is essentially unmaintained with crucial bugs not being fixed. Also its parsing performance is relatively bad. Parser runtime can sometimes even become exponential, which means that the parser either appears to "hang" completely or abort processing after a time-out.
These deficiencies, along with the availability of newer, more modern and better maintained alternatives, should be sufficient motivation to consider a switch to another underlying parser solution.
I'd recommend we look at commonmark-java
and flexmark-java
and evaluate, which one works better.
From his involvement with pegdown I know @vsch (the author of flexmark-java
) as being very friendly and responsive, so I'd trust him with responsible maintenance for the foreseeable future.
commonmark-java
on the other hand is maintained by Atlassian, which is certainly not bad either.
My impression is that either alternative will provide a much better foundation for all future work on paradox than pegdown.
How would the paradox sbt plugin be able to do:
dependencyBrowseGraph <<= (dependencyBrowseGraphHTML, streams).map { (uri, streams) โ
streams.log.info("Opening in browser...")
java.awt.Desktop.getDesktop.browse(uri)
uri
},
As a Java developer, I would find it very annoying to flip all tabs one-by-one to Java for example.
In order to totally move away from page-per-language we'd need something like the below (pseudo code):
So this is some thing, we'll explain how to use it... Lorem ipsum, lorem ipsum, lorem ipsum,
lorem ipsum, lorem ipsum, lorem ipsum, lorem ipsum, lorem ipsum, lorem ipsum...
@@snip-text[example-snippet, Scala]
In scala the thing is provided via an implicit parameter, yay!
@@snip-text
@@snip-text[example-snippet, Java]
In java you gave to get the thing via Get.getTheThing, simple.
@@snip-text
Scala
: @@snip [example-snippet](/../../../build.sbt) { #setup_example }
Java
: @@snip [example-snippet](../../../pom.xml) { #setup_example }
If you see what I'm getting at. This way for either language the text would "feel right".
Just putting the text into the snippet does not feel right, we'd randomly have bits inside the tab and others not.
Lagom (and several other projects) render links back to the original markdown source files in GitHub to facilitate user contributions, see the bottom of this page for an example:
http://www.lagomframework.com/documentation/1.2.x/java/WhatDoesLagomMean.html
Paradox needs to support this such that a theme can render that link.
I get the following when trying out Paradox on Windows:
[error] (akka-docs-new/compile:paradoxMarkdownToHtml) java.net.URISyntaxException: Illegal character in opaque part at index 2: C:\Users\Varga\workspace\akka\akka-docs-new\src\main\paradox\
I guess it is the backslashes?
Support cross references (with validation) to document nodes and optionally show the text of the referenced node. The @ref
directive should validate link anchors and if a link anchor is used it should allow to use the title text as the link text similar to how links inside @@@ index
behave.
Given a snippet marker like the following:
diff --git i/plugin/src/sbt-test/paradox/snippets/src/main/paradox/multiple.md w/plugin/src/sbt-test/paradox/snippets/src/main/paradox/multiple.md
index c8b7cb3..9c9b082 100644
--- i/plugin/src/sbt-test/paradox/snippets/src/main/paradox/multiple.md
+++ w/plugin/src/sbt-test/paradox/snippets/src/main/paradox/multiple.md
@@ -1 +1,3 @@
@@ snip [multiple snippet](../../test/scala/Multiple.scala) { #multiple }
+
+@@ snip [comma separated snippet](../../test/scala/Multiple.scala) { #parseint-imports,parseint-def }
An error is logged in the wrong file:
[info] com.lightbend.paradox.markdown.Snippet$SnippetException: Label [parseint-imports] not found in [.../sbt_4232344d/snippets/src/main/paradox/../../test/resources/reference.conf]
Expected behaviour would be to fail with "invalid marker" or read multiple sections (as in #21)
We're using note / warning boxes a lot in Akka docs, so we'll want paradox to support those too :)
I hope to contribute this sometime soon ๐
Paradox should provide a command that runs an HTTP server, and then runs the documentation generation task in watch sources mode. sbt code that does this using an embedded python http server can be found here:
https://github.com/lagom/lagom.github.io/blob/template/build.sbt#L31
Currently, we are getting errors like this:
java.util.NoSuchElementException: key not found: ../client-side/index.md#http-client-side-java
at scala.collection.MapLike$class.default(MapLike.scala:228)
at scala.collection.AbstractMap.default(Map.scala:58)
at scala.collection.MapLike$class.apply(MapLike.scala:141)
at scala.collection.AbstractMap.apply(Map.scala:58)
at com.lightbend.paradox.markdown.RefDirective.render(Directive.scala:91)
at com.lightbend.paradox.markdown.DirectiveSerializer.visit(Directive.scala:39)
at org.pegdown.ToHtmlSerializer.visit(ToHtmlSerializer.java:386)
at org.pegdown.ast.DirectiveNode.accept(DirectiveNode.java:58)
at org.pegdown.ToHtmlSerializer.visitChildren(ToHtmlSerializer.java:397)
at org.pegdown.ToHtmlSerializer.visit(ToHtmlSerializer.java:381)
at org.pegdown.ast.SuperNode.accept(SuperNode.java:43)
at org.pegdown.ToHtmlSerializer.visitChildren(ToHtmlSerializer.java:397)
at org.pegdown.ToHtmlSerializer.printTag(ToHtmlSerializer.java:418)
at org.pegdown.ToHtmlSerializer.printBreakBeforeTag(ToHtmlSerializer.java:425)
at org.pegdown.ToHtmlSerializer.visit(ToHtmlSerializer.java:190)
at org.pegdown.ast.ParaNode.accept(ParaNode.java:35)
at org.pegdown.ToHtmlSerializer.visitChildren(ToHtmlSerializer.java:397)
at org.pegdown.ToHtmlSerializer.visit(ToHtmlSerializer.java:89)
at org.pegdown.ast.RootNode.accept(RootNode.java:51)
at org.pegdown.ToHtmlSerializer.toHtml(ToHtmlSerializer.java:70)
at com.lightbend.paradox.markdown.Writer.write(Writer.scala:43)
at com.lightbend.paradox.ParadoxProcessor$PageContents.<init>(ParadoxProcessor.scala:80)
at com.lightbend.paradox.ParadoxProcessor.com$lightbend$paradox$ParadoxProcessor$$render$1(ParadoxProcessor.scala:60)
at com.lightbend.paradox.ParadoxProcessor$$anonfun$process$1.apply(ParadoxProcessor.scala:68)
at com.lightbend.paradox.ParadoxProcessor$$anonfun$process$1.apply(ParadoxProcessor.scala:68)
at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251)
at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251)
at scala.collection.immutable.List.foreach(List.scala:318)
at scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:251)
at scala.collection.AbstractTraversable.flatMap(Traversable.scala:105)
at com.lightbend.paradox.ParadoxProcessor.process(ParadoxProcessor.scala:68)
at com.lightbend.paradox.sbt.ParadoxPlugin$$anonfun$paradoxSettings$25.apply(ParadoxPlugin.scala:94)
at com.lightbend.paradox.sbt.ParadoxPlugin$$anonfun$paradoxSettings$25.apply(ParadoxPlugin.scala:92)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:40)
at sbt.std.Transform$$anon$4.work(System.scala:63)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
at sbt.Execute.work(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:28)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
[error] (docs/compile:paradoxMarkdownToHtml) java.util.NoSuchElementException: key not found: ../client-side/index.md#http-client-side-java
Would be nice to know what source and target files and lines are (and maybe even a suggestion what needs to be fixed).
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.