├── .circleci
└── config.yml
├── .gitignore
├── .sbtopts
├── .scalafmt.conf
├── LICENSE
├── angular
├── README.md
├── src
│ └── main
│ │ ├── js
│ │ ├── index.html
│ │ └── styling.css
│ │ └── scala
│ │ └── demo
│ │ ├── AppComponent.scala
│ │ ├── AppModule.scala
│ │ ├── AppRoutingModule.scala
│ │ ├── Main.scala
│ │ ├── heroeditor
│ │ ├── DashboardComponent.scala
│ │ ├── Hero.scala
│ │ ├── HeroDetailComponent.scala
│ │ ├── HeroService.scala
│ │ ├── HeroesComponent.scala
│ │ ├── MessageService.scala
│ │ ├── MessagesComponent.scala
│ │ └── MockHeroes.scala
│ │ └── package.scala
└── yarn.lock
├── build.sbt
├── chart
├── src
│ └── main
│ │ ├── js
│ │ └── index.html
│ │ └── scala
│ │ └── demo.scala
└── yarn.lock
├── custom.webpack.config.js
├── cypress
├── cypress.json
├── cypress
│ ├── plugins
│ │ └── index.js
│ ├── support
│ │ ├── commands.js
│ │ └── index.js
│ └── videos
│ │ └── main.js.mp4
├── src
│ └── main
│ │ └── scala
│ │ └── demo.scala
└── yarn.lock
├── d3
├── src
│ └── main
│ │ ├── js
│ │ └── index.html
│ │ └── scala
│ │ └── demo.scala
└── yarn.lock
├── docs
├── angular
│ ├── angular-opt-bundle.js
│ └── index.html
├── chart
│ ├── chart-opt-bundle.js
│ └── index.html
├── d3
│ ├── d3-opt-bundle.js
│ └── index.html
├── google-maps
│ ├── google-maps-opt-bundle.js
│ └── index.html
├── jquery
│ ├── 05d14cb826bafefd5b46fa2e3be5c952.png
│ ├── 0f8012f9214f21e71d2e09dd59620cff.png
│ ├── 3676d240bfc41073d4b9a3886dbb2c2d.png
│ ├── 3e7b25be8db5575f37ef732e60ea6eb4.png
│ ├── 546138d93ba6d3da76e1cefdd3493b25.png
│ ├── 5c18c7c3b45a9e304e1da3da3f6c517f.png
│ ├── 5e67153340a01757d1ee073aa6fdbdd8.png
│ ├── 6451ae9a01ac65bd0fd7eb118e7770f1.png
│ ├── 6616f7b7e32f5346b03964406a933d49.png
│ ├── 6b0513b86cddf85f3764609bbfedfd79.png
│ ├── 7ebbd63f8c28bf02ab557026bb078116.png
│ ├── aabe52d4b720fc416d5fa1bf79849f8c.png
│ ├── b159d479704de144f3bde7eb8c232ce5.png
│ ├── b5c094c2859bb622056ba7a883112aec.png
│ ├── index.html
│ └── jquery-opt-bundle.js
├── leaflet
│ ├── index.html
│ └── leaflet-opt-bundle.js
├── onsenui
│ ├── index.html
│ └── onsenui-opt-bundle.js
├── p5
│ ├── index.html
│ └── p5-opt-bundle.js
├── phaser
│ ├── 4c749ba5f2242b64e37fa7439ece8c98.png
│ ├── ff69a6fb51aef4d4950ff9398136e979.jsn
│ ├── index.html
│ └── phaser-opt-bundle.js
├── pixi
│ ├── 27905594c5fb6a699e83e2a33ac4594f.jpg
│ ├── 3cd1bac088de1f0141a2d2b460f5e604.jpeg
│ ├── 4570873d87d3a0f6e5ac1cb8fe25e0d3.mp4
│ ├── 4570873d87d3a0f6e5ac1cb8fe25e0d3.png
│ ├── 671dfaa933552f588d943ca39375807e.png
│ ├── 70f6dd03a1f4a89b372199a507d13413.mp4
│ ├── 81caa7d77cd7fe45112c79d65902fe6f.jpg
│ ├── 8bfb7c2cc94d5e2fe3e9eb8766c2143c.png
│ ├── 98caa6066cf537444105787d26f45c13.jpg
│ ├── 9cc4b590bde4d70f18cb9ba64776ae2b.png
│ ├── ae108d533b303b523de5393a7e0f4b0e.jpeg
│ ├── c79a9d4407a11aa2611443c9d8ea7d70.png
│ ├── e6485b0aaa9ff710c4454df3a144efb1.png
│ ├── index.html
│ └── pixi-opt-bundle.js
├── reveal
│ ├── 10560fb6663a782589a3f7f8926bae05.eot
│ ├── 18847feae8b114c355f01927e6b734bb.eot
│ ├── 1cb8e94f1185f1131a0c895165998f2b.woff
│ ├── 2da39ecf9246383937da11b44b7bd9b4.ttf
│ ├── 6b058fc2634b01d837c3432316c3141f.woff
│ ├── 80fbb267a50233879359bdf53b671515.eot
│ ├── 8256cfd7e4017a7690814879409212cd.ttf
│ ├── c2491edf9e2b71393eeb226d6f3198fc.eot
│ ├── c7e698a4d0956f4a939f42a05685bbf5.ttf
│ ├── e74f0128884561828ce8c9cf5c284ab8.woff
│ ├── e7acc589bb558fe58936a853f570193c.woff
│ ├── f3565095e6c9158140444970f5a2c5ed.ttf
│ ├── index.html
│ └── reveal-opt-bundle.js
├── three
│ ├── ebf4afeb87874d0a1487e7ea687fb529.glb
│ ├── index.html
│ └── three-opt-bundle.js
└── vue
│ ├── index.html
│ └── vue-opt-bundle.js
├── electron
├── package.json
├── src
│ └── main
│ │ ├── resources
│ │ ├── index.html
│ │ └── package.json
│ │ └── scala
│ │ └── mainprocess
│ │ └── MainProcess.scala
└── yarn.lock
├── google-maps
├── src
│ └── main
│ │ ├── js
│ │ └── index.html
│ │ └── scala
│ │ └── demo.scala
└── yarn.lock
├── jquery
├── src
│ └── main
│ │ ├── js
│ │ └── index.html
│ │ └── scala
│ │ └── demo.scala
└── yarn.lock
├── leaflet
├── src
│ └── main
│ │ ├── js
│ │ └── index.html
│ │ └── scala
│ │ └── demo.scala
└── yarn.lock
├── lodash
├── src
│ └── main
│ │ └── scala
│ │ └── demo.scala
└── yarn.lock
├── node-express
├── src
│ └── main
│ │ └── scala
│ │ └── demo.scala
└── yarn.lock
├── onsenui
├── src
│ └── main
│ │ ├── js
│ │ └── index.html
│ │ └── scala
│ │ └── demo.scala
└── yarn.lock
├── p5
├── src
│ └── main
│ │ ├── js
│ │ └── index.html
│ │ └── scala
│ │ └── demo.scala
└── yarn.lock
├── phaser
├── src
│ └── main
│ │ ├── js
│ │ ├── gems.jsn
│ │ ├── gems.png
│ │ └── index.html
│ │ └── scala
│ │ └── demo.scala
└── yarn.lock
├── pixi
├── src
│ └── main
│ │ ├── js
│ │ ├── a11y-light.css
│ │ ├── assets
│ │ │ ├── bg_grass.jpg
│ │ │ ├── bg_scene_rotate.jpg
│ │ │ ├── bunny.png
│ │ │ ├── eggHead.png
│ │ │ ├── p2.jpeg
│ │ │ ├── pixi-filters
│ │ │ │ ├── displacement_map_repeat.jpg
│ │ │ │ └── flag.png
│ │ │ ├── star.png
│ │ │ ├── trail.png
│ │ │ └── video.mp4
│ │ ├── index.html
│ │ └── styles.css
│ │ └── scala
│ │ └── demo
│ │ ├── assets.scala
│ │ ├── demosadvanced
│ │ ├── MouseTrail.scala
│ │ └── StarWarp.scala
│ │ ├── demosbasic
│ │ ├── Basics.scala
│ │ ├── ContainerPivot.scala
│ │ ├── Containers.scala
│ │ └── Tinting.scala
│ │ ├── filtersbasic
│ │ └── DisplacementMapFlag.scala
│ │ ├── graphics
│ │ └── Simple.scala
│ │ ├── interaction
│ │ └── Click.scala
│ │ ├── meshandshaders
│ │ └── Uniform.scala
│ │ ├── monkeypatching
│ │ └── PIXIPatching.scala
│ │ ├── pixi
│ │ ├── ExampleSelector.scala
│ │ └── PIXIExample.scala
│ │ ├── pluginfilters
│ │ └── Outline.scala
│ │ └── sprite
│ │ ├── TilingSpriteExample.scala
│ │ └── VideoExample.scala
└── yarn.lock
├── project
├── build.properties
├── plugins.sbt
└── scalafmt.sbt
├── readme.md
├── reveal
├── src
│ └── main
│ │ ├── js
│ │ └── index.html
│ │ └── scala
│ │ └── demo
│ │ ├── Demo.scala
│ │ ├── MyTalk.scala
│ │ └── PresentationUtil.scala
└── yarn.lock
├── three
├── src
│ └── main
│ │ ├── js
│ │ ├── Horse.glb
│ │ └── index.html
│ │ └── scala
│ │ └── demo.scala
└── yarn.lock
├── typescript
├── src
│ └── main
│ │ ├── resources
│ │ ├── bad.js
│ │ ├── bad.ts
│ │ ├── good.js
│ │ └── good.ts
│ │ └── scala
│ │ └── demo.scala
└── yarn.lock
└── vue
├── src
└── main
│ ├── js
│ └── index.html
│ └── scala
│ └── demo.scala
└── yarn.lock
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Scala CircleCI 2.0 configuration file
2 | #
3 | # Check https://circleci.com/docs/2.0/sample-config/ for more details
4 | #
5 | version: 2
6 | jobs:
7 | build:
8 | docker:
9 | # specify the version you desire here
10 | - image: circleci/openjdk:8-jdk-node
11 | # Specify service dependencies here if necessary
12 | # CircleCI maintains a library of pre-built images
13 | # documented at https://circleci.com/docs/2.0/circleci-images/
14 | # - image: circleci/postgres:9.4
15 |
16 | working_directory: ~/repo
17 |
18 | environment:
19 | # Customize the JVM maximum heap limit
20 | JVM_OPTS: -Xmx3200m
21 | TERM: dumb
22 |
23 | steps:
24 | - checkout
25 |
26 | # Download and cache dependencies
27 | - restore_cache:
28 | keys:
29 | - v1-dependencies-4-{{ checksum "build.sbt" }}
30 | # fallback to using the latest cache if no exact match is found
31 | - v1-dependencies-4-
32 |
33 | # ideally we would bundle and run things, but the diversity of the demos makes it a bit difficult.
34 | # might revisit this later
35 | - run: cat /dev/null | sbt stPublishCache compile
36 |
37 | - save_cache:
38 | paths:
39 | - ~/.sbt
40 | - ~/.ivy2/cache
41 | - ~/.ivy2/local
42 | - ~/.cache/scalablytyped
43 | key: v1-dependencies-4-{{ checksum "build.sbt" }}
44 |
45 | # # run scalafmt!
46 | # - run: cat /dev/null | sbt scalafmtCheck
47 |
48 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | target/
3 | .bloop/
4 | node_modules/
5 | .gradle/
6 | build/
7 | local.properties
8 | .expo/
9 | .metals
10 | project/metals.sbt
11 |
--------------------------------------------------------------------------------
/.sbtopts:
--------------------------------------------------------------------------------
1 | -J-XX:+UseG1GC
2 | -J-Xmx4g
3 |
--------------------------------------------------------------------------------
/.scalafmt.conf:
--------------------------------------------------------------------------------
1 | version=3.0.0-RC5
2 | runner.dialect = scala3
3 | style = default
4 | danglingParentheses.preset = true
5 | align {
6 | tokens.add = [":", "="]
7 | }
8 | maxColumn = 120
9 | rewrite {
10 | rules = [SortImports, RedundantBraces, RedundantParens, PreferCurlyFors]
11 | scala3 = {
12 | convertToNewSyntax = true,
13 | removeOptionalBraces: yes,
14 | insertEndMarkerMinLines = 10
15 | }
16 | }
17 | project.excludeFilters = [
18 | node_modules,
19 | target
20 | ]
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 ScalablyTyped
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/angular/README.md:
--------------------------------------------------------------------------------
1 | # Angular Scala POC
2 |
3 | Use [Angular](https://angular.io/) 7 with [Scala](https://www.scala-lang.org/) and [Scala.js](https://www.scala-js.org/).
4 |
5 | The beginning of the "Tour of Heroes" tutorial is implemented.
6 |
7 | ## TypeScript decorators
8 |
9 | Scala.js compiles to pure JavaScript, and not TypeScript. Unfortunately, decorators do not exist in JS and we have to
10 | translate them. The way it's supposed to be done is explained
11 | [here](https://v2.angular.io/docs/ts/latest/cookbook/ts-to-js.html).
12 |
13 | In Scala.js, that translate to the decorated class having a companion object, that has a val `annotations` that is a
14 | `js.Array` that contains a Component, or a NgModule...
15 |
16 | ## Scala.js Angular specificities
17 |
18 | ### Decorators
19 |
20 | [This page](https://v2.angular.io/docs/ts/latest/cookbook/ts-to-js.html) explains how TypeScript decorators have to be
21 | translated into JavaScript. Essentially, for
22 | ```typescript
23 | @SomeDecorator({ ... })
24 | class Foo {}
25 | ```
26 | there has to be a JS array `annotations` on the object `Foo`.
27 | In Scala, this will be translated by setting a value
28 | `annotations: js.Array[Decorator]` to the companion object, and annotate it by `@JSExportStatic`.
29 |
30 | ### Injectables
31 |
32 | Injectables must be
33 |
34 | - set as providers within the NgModule
35 | - have their companion object have an `annotations` js-exported static field, which is a `js.Array[Injectable]`
36 | - be specified in the static js-exported `parameters` of the companion object in which they must be injected
37 |
38 | ### External templates and style sheets
39 |
40 | For HTML templates and CSS style sheets that are associated to a component via its decorator, the specified path has to
41 | be relative to the `index.html` file.
42 |
43 | ## Things to do
44 |
45 | - Find better way to handle the decorators
46 |
--------------------------------------------------------------------------------
/angular/src/main/js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Angular with Scala.js
7 |
8 |
9 | Sorry, angular demo is currently broken
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/angular/src/main/js/styling.css:
--------------------------------------------------------------------------------
1 | /* Master Styles */
2 | h1 {
3 | color: #369;
4 | font-family: Arial, Helvetica, sans-serif;
5 | font-size: 250%;
6 | }
7 | h2, h3 {
8 | color: #444;
9 | font-family: Arial, Helvetica, sans-serif;
10 | font-weight: lighter;
11 | }
12 | body {
13 | margin: 2em;
14 | }
15 | body, input[text], button {
16 | color: #888;
17 | font-family: Cambria, Georgia;
18 | }
19 | a {
20 | cursor: pointer;
21 | cursor: hand;
22 | }
23 | button {
24 | font-family: Arial;
25 | background-color: #eee;
26 | border: none;
27 | padding: 5px 10px;
28 | border-radius: 4px;
29 | cursor: pointer;
30 | cursor: hand;
31 | }
32 | button:hover {
33 | background-color: #cfd8dc;
34 | }
35 | button:disabled {
36 | background-color: #eee;
37 | color: #aaa;
38 | cursor: auto;
39 | }
40 |
41 | /* Navigation link styles */
42 | nav a {
43 | padding: 5px 10px;
44 | text-decoration: none;
45 | margin-right: 10px;
46 | margin-top: 10px;
47 | display: inline-block;
48 | background-color: #eee;
49 | border-radius: 4px;
50 | }
51 | nav a:visited, a:link {
52 | color: #607D8B;
53 | }
54 | nav a:hover {
55 | color: #039be5;
56 | background-color: #CFD8DC;
57 | }
58 | nav a.active {
59 | color: #039be5;
60 | }
61 |
62 | /* everywhere else */
63 | * {
64 | font-family: Arial, Helvetica, sans-serif;
65 | }
66 |
--------------------------------------------------------------------------------
/angular/src/main/scala/demo/AppComponent.scala:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import typings.angularCore.mod.{Component, ComponentCls, OnInit}
4 |
5 | import scala.scalajs.js
6 | import scala.scalajs.js.annotation.JSExportStatic
7 |
8 | /** An example of a component. The @Component decorator is taken care of in the companion object, under annotations.
9 | *
10 | * AppComponent extends from [[OnInit]] so that it does stuff when initiated.
11 | */
12 | final class AppComponent extends OnInit:
13 | val title: String = "Angular with Scala.js"
14 |
15 | def subtitle(): String = "This is a subtitle"
16 |
17 | override def ngOnInit(): Unit = println("AppComponent")
18 | end AppComponent
19 |
20 | object AppComponent:
21 |
22 | /** The @Component decorator for AppComponent.
23 | */
24 | @JSExportStatic
25 | val annotations = js.Array(
26 | new ComponentCls(
27 | new Component {}
28 | .setSelector("app-root")
29 | .setTemplate("""
30 | {{ title }}
31 |
32 | Dashboard
33 | Heroes
34 |
35 |
36 |
37 |
38 | """).setStylesVarargs("""
39 | h1 {
40 | font-size: 1.2em;
41 | color: #999;
42 | margin-bottom: 0;
43 | }
44 | h2 {
45 | font-size: 2em;
46 | margin-top: 0;
47 | padding-top: 0;
48 | }
49 | nav a {
50 | padding: 5px 10px;
51 | text-decoration: none;
52 | margin-top: 10px;
53 | display: inline-block;
54 | background-color: #eee;
55 | border-radius: 4px;
56 | }
57 | nav a:visited, a:link {
58 | color: #607d8b;
59 | }
60 | nav a:hover {
61 | color: #039be5;
62 | background-color: #cfd8dc;
63 | }
64 | nav a.active {
65 | color: #039be5;
66 | }
67 | """)
68 | )
69 | )
70 | end AppComponent
71 |
--------------------------------------------------------------------------------
/angular/src/main/scala/demo/AppModule.scala:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import demo.heroeditor.*
4 | import typings.angularCore.mod.{NgModule, NgModuleCls}
5 | import typings.angularForms.mod.FormsModule
6 | import typings.angularPlatformBrowser.mod.BrowserModule
7 |
8 | import scala.scalajs.js
9 | import scala.scalajs.js.annotation.JSExportStatic
10 |
11 | /** The @NgModule Decorator is implemented in the companion object, under annotations static field.
12 | */
13 | final class AppModule extends js.Object
14 |
15 | object AppModule:
16 |
17 | @JSExportStatic
18 | val annotations = js.Array(
19 | new NgModuleCls(
20 | new NgModule {}
21 | .setImportsVarargs(
22 | typeOf[BrowserModule],
23 | typeOf[FormsModule],
24 | typeOf[AppRoutingModule]
25 | )
26 | .setDeclarationsVarargs(
27 | typeOf[AppComponent],
28 | typeOf[HeroesComponent],
29 | typeOf[HeroDetailComponent],
30 | typeOf[MessagesComponent],
31 | typeOf[DashboardComponent]
32 | )
33 | .setBootstrapVarargs(typeOf[AppComponent])
34 | .setProvidersVarargs(typeOf[HeroService], typeOf[MessageService])
35 | )
36 | )
37 | end AppModule
38 |
--------------------------------------------------------------------------------
/angular/src/main/scala/demo/AppRoutingModule.scala:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import typings.angularCore.mod.{NgModule, NgModuleCls}
4 | import typings.angularRouter.mod.{Route, RouterModule, Routes}
5 |
6 | import scala.scalajs.js
7 | import scala.scalajs.js.annotation.JSExportStatic
8 |
9 | final class AppRoutingModule extends js.Object
10 |
11 | object AppRoutingModule:
12 |
13 | @JSExportStatic
14 | val annotations =
15 | js.Array(
16 | new NgModuleCls(
17 | new NgModule {}
18 | .setImportsVarargs(unspecify(RouterModule.forRoot(routes)))
19 | .setExports(js.Array(typeOf[RouterModule]))
20 | )
21 | )
22 |
23 | def routes: Routes = js.Array(
24 | Route().setPath("heroes").setComponent(typeOf[heroeditor.HeroesComponent]),
25 | Route().setPath("dashboard").setComponent(typeOf[heroeditor.DashboardComponent]),
26 | Route().setPath("").setRedirectTo("/dashboard").setPathMatch("full"),
27 | Route().setPath("detail/:id").setComponent(typeOf[heroeditor.HeroDetailComponent])
28 | )
29 | end AppRoutingModule
30 |
--------------------------------------------------------------------------------
/angular/src/main/scala/demo/Main.scala:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import org.scalajs.dom.{document, Event}
4 | import typings.angularCore.mod as Core
5 | import typings.angularPlatformBrowserDynamic.mod.platformBrowserDynamic
6 |
7 | import scala.scalajs.js
8 | import scala.scalajs.js.annotation.JSImport
9 |
10 | @js.native @JSImport("./styling.css", JSImport.Namespace)
11 | object Style extends js.Object
12 |
13 | /* rejoice this line, it took longer to write than the rest of the demo >: */
14 | @js.native @JSImport("core-js/client/shim.min.js", JSImport.Namespace)
15 | object coreJsCustomRequire extends js.Object
16 |
17 | @main
18 | def main: Unit =
19 | /* touch to require */
20 | coreJsCustomRequire
21 | typings.tslib.tslibRequire
22 | typings.zoneJs.zoneJsRequire
23 | Style
24 |
25 | /** Waiting the DOM to be loaded otherwise the CSS selectors won't exist.
26 | */
27 | document.addEventListener[Event](
28 | "DOMContentLoaded",
29 | (_: Event) =>
30 | if !scala.scalajs.LinkingInfo.developmentMode then
31 |
32 | /** Syncing Angular production mode with Scala.js production mode.
33 | */
34 | Core.enableProdMode()
35 |
36 | println("Charging App")
37 | platformBrowserDynamic().bootstrapModule(typeOf[AppModule])
38 | )
39 | end main
40 |
--------------------------------------------------------------------------------
/angular/src/main/scala/demo/heroeditor/DashboardComponent.scala:
--------------------------------------------------------------------------------
1 | package demo
2 | package heroeditor
3 |
4 | import typings.angularCore.mod.{Component, ComponentCls, OnInit}
5 |
6 | import scala.scalajs.js
7 | import scala.scalajs.js.annotation.JSExportStatic
8 |
9 | final class DashboardComponent(heroService: HeroService) extends OnInit:
10 | var heroes: js.Array[Hero] = MockHeroes.heroes.slice(1, 5)
11 |
12 | override def ngOnInit(): Unit =
13 | getHeroes()
14 |
15 | def getHeroes(): Unit =
16 | heroService.heroes.subscribe(hs => heroes = hs.slice(1, 5))
17 |
18 | object DashboardComponent:
19 |
20 | @JSExportStatic
21 | val annotations = js.Array(
22 | new ComponentCls(
23 | new Component {}
24 | .setSelector("app-dashboard")
25 | .setTemplate(
26 | """
27 | |Top Heroes
28 | |
36 | |
37 | """.stripMargin
38 | )
39 | .setStylesVarargs("""
40 | |/* DashboardComponent's private CSS styles */
41 | |[class*='col-'] {
42 | | float: left;
43 | | padding-right: 20px;
44 | | padding-bottom: 20px;
45 | |}
46 | |[class*='col-']:last-of-type {
47 | | padding-right: 0;
48 | |}
49 | |a {
50 | | text-decoration: none;
51 | |}
52 | |*, *:after, *:before {
53 | | -webkit-box-sizing: border-box;
54 | | -moz-box-sizing: border-box;
55 | | box-sizing: border-box;
56 | |}
57 | |h3 {
58 | | text-align: center; margin-bottom: 0;
59 | |}
60 | |h4 {
61 | | position: relative;
62 | |}
63 | |.grid {
64 | | margin: 0;
65 | |}
66 | |.col-1-4 {
67 | | width: 25%;
68 | |}
69 | |.module {
70 | | padding: 20px;
71 | | text-align: center;
72 | | color: #eee;
73 | | max-height: 120px;
74 | | min-width: 120px;
75 | | background-color: #607d8b;
76 | | border-radius: 2px;
77 | |}
78 | |.module:hover {
79 | | background-color: #eee;
80 | | cursor: pointer;
81 | | color: #607d8b;
82 | |}
83 | |.grid-pad {
84 | | padding: 10px 0;
85 | |}
86 | |.grid-pad > [class*='col-']:last-of-type {
87 | | padding-right: 20px;
88 | |}
89 | |@media (max-width: 600px) {
90 | | .module {
91 | | font-size: 10px;
92 | | max-height: 75px; }
93 | |}
94 | |@media (max-width: 1024px) {
95 | | .grid {
96 | | margin: 0;
97 | | }
98 | | .module {
99 | | min-width: 60px;
100 | | }
101 | |}
102 | """.stripMargin)
103 | )
104 | )
105 |
106 | @JSExportStatic
107 | val parameters = js.Array(typeOf[HeroService])
108 | end DashboardComponent
109 |
--------------------------------------------------------------------------------
/angular/src/main/scala/demo/heroeditor/Hero.scala:
--------------------------------------------------------------------------------
1 | package demo.heroeditor
2 |
3 | import scala.scalajs.js
4 |
5 | class Hero(val id: Int, val name: String) extends js.Object
6 |
--------------------------------------------------------------------------------
/angular/src/main/scala/demo/heroeditor/HeroDetailComponent.scala:
--------------------------------------------------------------------------------
1 | package demo
2 | package heroeditor
3 |
4 | import typings.angularCommon.mod.Location
5 | import typings.angularCore.mod.{Component, ComponentCls, OnInit, Type}
6 | import typings.angularRouter.mod.ActivatedRoute
7 |
8 | import scala.scalajs.js
9 | import scala.scalajs.js.annotation.JSExportStatic
10 |
11 | final class HeroDetailComponent(route: ActivatedRoute, heroService: HeroService, location: Location) extends OnInit:
12 |
13 | var hero: js.UndefOr[Hero] = js.undefined
14 |
15 | def getHero(): Unit =
16 | asOption(route.snapshot.paramMap.get("id")) match
17 | case Some(id) if id.forall(_.isDigit) =>
18 | hero = heroService.getHero(id.toInt)
19 | case _ => ()
20 |
21 | override def ngOnInit(): Unit =
22 | getHero()
23 | println(hero)
24 |
25 | def goBack(): Unit =
26 | location.back()
27 | end HeroDetailComponent
28 |
29 | object HeroDetailComponent:
30 | @JSExportStatic
31 | val annotations = js.Array(
32 | new ComponentCls(
33 | new Component {}
34 | .setSelector("app-hero-detail")
35 | .setInputsVarargs("hero")
36 | .setTemplate("""
37 |
38 |
{{hero.name | uppercase}} Details
39 |
id: {{hero.id}}
40 |
41 | name:
42 |
43 |
44 |
45 |
go back
46 |
""")
47 | .setStylesVarargs("""
48 | /* HeroDetailComponent's private CSS styles */
49 | label {
50 | display: inline-block;
51 | width: 3em;
52 | margin: .5em 0;
53 | color: #607D8B;
54 | font-weight: bold;
55 | }
56 | input {
57 | height: 2em;
58 | font-size: 1em;
59 | padding-left: .4em;
60 | }
61 | button {
62 | margin-top: 20px;
63 | font-family: Arial;
64 | background-color: #eee;
65 | border: none;
66 | padding: 5px 10px;
67 | border-radius: 4px;
68 | cursor: pointer; cursor: hand;
69 | }
70 | button:hover {
71 | background-color: #cfd8dc;
72 | }
73 | button:disabled {
74 | background-color: #eee;
75 | color: #ccc;
76 | cursor: auto;
77 | }
78 | """)
79 | )
80 | )
81 |
82 | @JSExportStatic
83 | val parameters: js.Array[Type[?]] = js.Array(
84 | typeOf[ActivatedRoute],
85 | typeOf[HeroService],
86 | typeOf[Location]
87 | )
88 | end HeroDetailComponent
89 |
--------------------------------------------------------------------------------
/angular/src/main/scala/demo/heroeditor/HeroService.scala:
--------------------------------------------------------------------------------
1 | package demo
2 | package heroeditor
3 |
4 | import typings.angularCore.mod.InjectableCls
5 | import typings.rxjs.internalObservableMod.Observable
6 | import typings.rxjs.mod as rxjs
7 |
8 | import scala.scalajs.js
9 | import scala.scalajs.js.JSConverters.*
10 | import scala.scalajs.js.annotation.JSExportStatic
11 |
12 | final class HeroService(messageService: MessageService) extends js.Object:
13 | def heroes: Observable[js.Array[Hero]] =
14 | messageService.add("HeroService: fetched heroes")
15 | rxjs.of(MockHeroes.heroes)
16 |
17 | def getHero(id: Int): js.UndefOr[Hero] =
18 | messageService.add(s"HeroService: fetched hero id=$id")
19 | MockHeroes.heroes.find(_.id == id).orUndefined
20 |
21 | object HeroService:
22 | @JSExportStatic
23 | val annotations = js.Array(new InjectableCls)
24 |
25 | @JSExportStatic
26 | val parameters = js.Array(typeOf[MessageService])
27 |
--------------------------------------------------------------------------------
/angular/src/main/scala/demo/heroeditor/HeroesComponent.scala:
--------------------------------------------------------------------------------
1 | package demo
2 | package heroeditor
3 |
4 | import typings.angularCore.mod.{Component, ComponentCls, OnInit}
5 |
6 | import scala.scalajs.js
7 | import scala.scalajs.js.annotation.JSExportStatic
8 |
9 | final class HeroesComponent(heroService: HeroService) extends OnInit:
10 |
11 | var heroes: js.Array[Hero] = _
12 |
13 | def getHeroes(): Unit =
14 | heroService.heroes.subscribe(hs => heroes = hs)
15 | heroes = MockHeroes.heroes
16 |
17 | override def ngOnInit(): Unit =
18 | println("Heroes Component")
19 |
20 | getHeroes()
21 | end HeroesComponent
22 |
23 | object HeroesComponent:
24 | @JSExportStatic
25 | val annotations = js.Array(
26 | new ComponentCls(
27 | new Component {}
28 | .setSelector("app-heroes")
29 | .setTemplate(
30 | """
31 | |
32 | |My Heroes
33 | |
34 | |
41 | """.stripMargin
42 | )
43 | .setStylesVarargs(
44 | """
45 | |/* HeroesComponent's private CSS styles */
46 | |.selected {
47 | | background-color: #CFD8DC !important;
48 | | color: white;
49 | |}
50 | |.heroes {
51 | | margin: 0 0 2em 0;
52 | | list-style-type: none;
53 | | padding: 0;
54 | | width: 15em;
55 | |}
56 | |.heroes li {
57 | | cursor: pointer;
58 | | position: relative;
59 | | left: 0;
60 | | background-color: #EEE;
61 | | margin: .5em;
62 | | padding: .3em 0;
63 | | height: 1.6em;
64 | | border-radius: 4px;
65 | |}
66 | |.heroes li.selected:hover {
67 | | background-color: #BBD8DC !important;
68 | | color: white;
69 | |}
70 | |.heroes li:hover {
71 | | color: #607D8B;
72 | | background-color: #DDD;
73 | | left: .1em;
74 | |}
75 | |.heroes .text {
76 | | position: relative;
77 | | top: -3px;
78 | |}
79 | |.heroes .badge {
80 | | display: inline-block;
81 | | font-size: small;
82 | | color: white;
83 | | padding: 0.8em 0.7em 0 0.7em;
84 | | background-color: #607D8B;
85 | | line-height: 1em;
86 | | position: relative;
87 | | left: -1px;
88 | | top: -4px;
89 | | height: 1.8em;
90 | | min-width: 16px;
91 | | text-align: right;
92 | | margin-right: .8em;
93 | | border-radius: 4px 0 0 4px;
94 | |}
95 | """.stripMargin
96 | )
97 | )
98 | )
99 |
100 | @JSExportStatic
101 | val parameters = js.Array(typeOf[HeroService])
102 | end HeroesComponent
103 |
--------------------------------------------------------------------------------
/angular/src/main/scala/demo/heroeditor/MessageService.scala:
--------------------------------------------------------------------------------
1 | package demo.heroeditor
2 |
3 | import typings.angularCore.mod.InjectableCls
4 |
5 | import scala.scalajs.js
6 | import scala.scalajs.js.annotation.JSExportStatic
7 |
8 | final class MessageService extends js.Object:
9 | val messages: js.Array[String] = js.Array()
10 |
11 | def add(message: String): Unit =
12 | messages.push(message)
13 |
14 | def clear(): Unit =
15 | messages.clear()
16 |
17 | object MessageService:
18 | @JSExportStatic
19 | val annotations = js.Array(new InjectableCls)
20 |
--------------------------------------------------------------------------------
/angular/src/main/scala/demo/heroeditor/MessagesComponent.scala:
--------------------------------------------------------------------------------
1 | package demo
2 | package heroeditor
3 |
4 | import typings.angularCore.mod.{Component, ComponentCls}
5 |
6 | import scala.scalajs.js
7 | import scala.scalajs.js.annotation.JSExportStatic
8 |
9 | final class MessagesComponent(val messageService: MessageService) extends js.Object:
10 | def ngOnInit(): Unit = ()
11 |
12 | object MessagesComponent:
13 | @JSExportStatic
14 | val annotations =
15 | js.Array(
16 | new ComponentCls(
17 | new Component {}
18 | .setSelector("app-messages")
19 | .setTemplate("""
20 |
21 |
22 |
Messages
23 |
clear
25 |
{{message}}
26 |
27 |
""")
28 | .setStylesVarargs("""
29 | h2 {
30 | color: red;
31 | font-family: Arial, Helvetica, sans-serif;
32 | font-weight: lighter;
33 | }
34 | body {
35 | margin: 2em;
36 | }
37 | body, input[text], button {
38 | color: crimson;
39 | font-family: Cambria, Georgia;
40 | }
41 |
42 | button.clear {
43 | font-family: Arial;
44 | background-color: #eee;
45 | border: none;
46 | padding: 5px 10px;
47 | border-radius: 4px;
48 | cursor: pointer;
49 | cursor: hand;
50 | }
51 | button:hover {
52 | background-color: #cfd8dc;
53 | }
54 | button:disabled {
55 | background-color: #eee;
56 | color: #aaa;
57 | cursor: auto;
58 | }
59 | button.clear {
60 | color: #888;
61 | margin-bottom: 12px;
62 | }
63 | """)
64 | )
65 | )
66 |
67 | @JSExportStatic
68 | val parameters = js.Array(typeOf[MessageService])
69 | end MessagesComponent
70 |
--------------------------------------------------------------------------------
/angular/src/main/scala/demo/heroeditor/MockHeroes.scala:
--------------------------------------------------------------------------------
1 | package demo.heroeditor
2 |
3 | import scala.scalajs.js
4 |
5 | object MockHeroes:
6 |
7 | private val names = js.Array(
8 | "Mr. Nice",
9 | "Narco",
10 | "Bombasto",
11 | "Celeritas",
12 | "Magneta",
13 | "RubberMan",
14 | "Dynama",
15 | "Dr IQ",
16 | "Magma",
17 | "Tornado"
18 | )
19 |
20 | val heroes: js.Array[Hero] =
21 | names.zipWithIndex.map { case (n, index) => new Hero(index + 11, n) }
22 | end MockHeroes
23 |
--------------------------------------------------------------------------------
/angular/src/main/scala/demo/package.scala:
--------------------------------------------------------------------------------
1 | import typings.angularCore.mod.Type
2 |
3 | import scala.language.higherKinds
4 | import scala.scalajs.js
5 | import scala.scalajs.js.|
6 |
7 | package object demo:
8 |
9 | /** Get the Type[T] of a Class, by calling js.constructorOf
10 | */
11 | @inline def typeOf[T <: js.Any](implicit tag: js.ConstructorTag[T]): Type[Any] =
12 | tag.constructor.asInstanceOf[Type[Any]]
13 |
14 | /* pretend that the world is contravariant */
15 | @inline def unspecify[M[_], T <: js.Object](mt: M[T]): M[js.Object] =
16 | mt.asInstanceOf[M[js.Object]]
17 |
18 | @inline def asOption[T](ot: T | Null): Option[T] =
19 | Option(ot.asInstanceOf[T])
20 | end demo
21 |
--------------------------------------------------------------------------------
/build.sbt:
--------------------------------------------------------------------------------
1 | import java.nio.file.Files
2 | import java.nio.file.StandardCopyOption.REPLACE_EXISTING
3 |
4 | import org.scalajs.jsenv.nodejs.NodeJSEnv
5 |
6 | import scala.sys.process.Process
7 |
8 | onLoad in Global := {
9 | println(
10 | """*
11 | |* Welcome to ScalablyTyped demos!
12 | |*
13 | |* For documentation see https://scalablytyped.org .
14 | |*
15 | |* Note that the first time you import/compile the projects it'll take a while for the dependencies to build
16 | |*""".stripMargin
17 | )
18 | (onLoad in Global).value
19 | }
20 |
21 | Global / stRemoteCache := RemoteCache.S3Aws(
22 | bucket = "scalablytyped-demos",
23 | region = "eu-central-1",
24 | prefix = Some("st-cache")
25 | )
26 |
27 | /**
28 | * Custom task to start demo with webpack-dev-server, use as `/start`.
29 | * Just `start` also works, and starts all frontend demos
30 | *
31 | * After that, the incantation is this to watch and compile on change:
32 | * `~/fastOptJS::webpack`
33 | */
34 | lazy val start = TaskKey[Unit]("start")
35 |
36 | /** Say just `dist` or `/dist` to make a production bundle in
37 | * `docs` for github publishing
38 | */
39 | lazy val dist = TaskKey[File]("dist")
40 |
41 | lazy val vue =
42 | project
43 | .enablePlugins(ScalablyTypedConverterPlugin)
44 | .configure(baseSettings, bundlerSettings, browserProject)
45 | .settings(
46 | Compile / npmDependencies ++= Seq("vue" -> "2.6.11"),
47 | useYarn := true,
48 | webpackDevServerPort := 8004
49 | )
50 |
51 | lazy val three =
52 | project
53 | .enablePlugins(ScalablyTypedConverterPlugin)
54 | .configure(baseSettings, bundlerSettings, browserProject, withCssLoading)
55 | .settings(
56 | Compile / npmDependencies ++= Seq("three" -> "0.112.1"),
57 | stUseScalaJsDom := false,
58 | webpackDevServerPort := 8005,
59 | useYarn := true
60 | )
61 |
62 | lazy val d3 = project
63 | .enablePlugins(ScalablyTypedConverterPlugin)
64 | .configure(baseSettings, bundlerSettings, browserProject)
65 | .settings(
66 | Compile / npmDependencies ++= Seq(
67 | "d3" -> "5.15",
68 | "@types/d3" -> "5.7.2"
69 | ),
70 | /* we use a bit of functionality which can't be found in scala-js-dom */
71 | stUseScalaJsDom := false,
72 | useYarn := true,
73 | webpackDevServerPort := 8001
74 | )
75 |
76 | lazy val jquery = project
77 | .enablePlugins(ScalablyTypedConverterPlugin)
78 | .configure(baseSettings, bundlerSettings, browserProject, withCssLoading)
79 | .settings(
80 | Compile / npmDependencies ++= Seq(
81 | "jquery" -> "3.3",
82 | "@types/jquery" -> "3.3.31",
83 | "jqueryui" -> "1.11.1",
84 | "@types/jqueryui" -> "1.12.10"
85 | ),
86 | useYarn := true,
87 | webpackDevServerPort := 8003
88 | )
89 |
90 | lazy val `google-maps` = project
91 | .enablePlugins(ScalablyTypedConverterPlugin)
92 | .configure(baseSettings, bundlerSettings, browserProject)
93 | .settings(
94 | Compile / npmDependencies ++= Seq(
95 | "@types/googlemaps" -> "3.39.2"
96 | ),
97 | webpackDevServerPort := 8002,
98 | useYarn := true
99 | )
100 |
101 | lazy val reveal = project
102 | .enablePlugins(ScalablyTypedConverterPlugin)
103 | .configure(baseSettings, bundlerSettings, browserProject, withCssLoading)
104 | .settings(
105 | Compile / npmDependencies ++= Seq(
106 | "@types/highlight.js" -> "9.12.3",
107 | "@types/reveal" -> "3.3.33",
108 | "highlight.js" -> "9.12",
109 | "reveal.js" -> "3.7.0",
110 | "react" -> "16.9",
111 | "react-dom" -> "16.9"
112 | ),
113 | // note: this demo is not a react demo. It doesn't use any typescript react components, it's just used to render
114 | stIgnore ++= List("react", "react-dom", "reveal.js"),
115 | stFlavour := Flavour.ScalajsReact,
116 | useYarn := true,
117 | webpackDevServerPort := 8006
118 | )
119 |
120 | lazy val chart = project
121 | .enablePlugins(ScalablyTypedConverterPlugin)
122 | .configure(baseSettings, bundlerSettings, browserProject)
123 | .settings(
124 | Compile / npmDependencies ++= Seq(
125 | "@types/chart.js" -> "2.9.11",
126 | "chart.js" -> "2.9.3"
127 | ),
128 | stUseScalaJsDom := false,
129 | useYarn := true,
130 | webpackDevServerPort := 8007
131 | )
132 |
133 | lazy val p5 = project
134 | .enablePlugins(ScalablyTypedConverterPlugin)
135 | .configure(baseSettings, bundlerSettings, browserProject)
136 | .settings(
137 | Compile / npmDependencies ++= Seq(
138 | "@types/p5" -> "0.9.0",
139 | "p5" -> "0.9"
140 | ),
141 | useYarn := true,
142 | webpackDevServerPort := 8009
143 | )
144 |
145 | lazy val leaflet = project
146 | .enablePlugins(ScalablyTypedConverterPlugin)
147 | .configure(baseSettings, bundlerSettings, browserProject)
148 | .settings(
149 | Compile / npmDependencies ++= Seq(
150 | "leaflet" -> "1.9.2",
151 | "@types/leaflet" -> "1.9.0"
152 | ),
153 | useYarn := true,
154 | webpackDevServerPort := 8010
155 | )
156 |
157 | lazy val angular = project
158 | .enablePlugins(ScalablyTypedConverterPlugin)
159 | .configure(baseSettings, bundlerSettings, browserProject, withCssLoading)
160 | .settings(
161 | Compile / npmDependencies ++= Seq(
162 | "@angular/common" -> "8.2.14",
163 | "@angular/compiler" -> "8.2.14",
164 | "@angular/core" -> "8.2.14",
165 | "@angular/forms" -> "8.2.14",
166 | "@angular/platform-browser-dynamic" -> "8.2.14",
167 | "@angular/platform-browser" -> "8.2.14",
168 | "@angular/router" -> "8.2.14",
169 | "core-js" -> "2.6.8",
170 | "rxjs" -> "6.5.4",
171 | "tslib" -> "1.10.0",
172 | "zone.js" -> "0.9.1"
173 | ),
174 | stEnableScalaJsDefined := Selection.NoneExcept("@angular/core"),
175 | stIgnore := List(
176 | /* this shouldn't be used directly */
177 | "@angular/compiler",
178 | /* not very interesting */
179 | "core-js"
180 | ),
181 | useYarn := true,
182 | webpackDevServerPort := 8008
183 | )
184 |
185 | lazy val onsenui =
186 | project
187 | .enablePlugins(ScalablyTypedConverterPlugin)
188 | .configure(baseSettings, bundlerSettings, browserProject)
189 | .settings(
190 | Compile / npmDependencies ++= Seq(
191 | "@types/jquery" -> "3.3.31",
192 | "jquery" -> "3.3",
193 | "onsenui" -> "2.10.10"
194 | ),
195 | useYarn := true,
196 | webpackDevServerPort := 8011
197 | )
198 |
199 | lazy val phaser =
200 | project
201 | .enablePlugins(ScalablyTypedConverterPlugin)
202 | .configure(baseSettings, bundlerSettings, browserProject, withCssLoading)
203 | .settings(
204 | Compile / npmDependencies ++= Seq("phaser" -> "3.22.0"),
205 | useYarn := true,
206 | webpackDevServerPort := 8012
207 | )
208 |
209 | lazy val pixi = project
210 | .enablePlugins(ScalablyTypedConverterPlugin)
211 | .configure(baseSettings, bundlerSettings, browserProject, withCssLoading)
212 | .settings(
213 | Compile / npmDependencies ++= Seq(
214 | "pixi.js" -> "5.2.1",
215 | "pixi-filters" -> "3.1.0",
216 | "@types/highlight.js" -> "9.12.3",
217 | "highlight.js" -> "9.12"
218 | ),
219 | useYarn := true,
220 | webpackDevServerPort := 8013
221 | )
222 |
223 | lazy val cypress = project
224 | .enablePlugins(ScalablyTypedConverterPlugin)
225 | .configure(baseSettings, bundlerSettings)
226 | .settings(
227 | Compile / npmDependencies ++= Seq(
228 | "cypress" -> "8.5.0",
229 | ),
230 | useYarn := true,
231 | run := {
232 | (Compile / npmInstallDependencies).value
233 | (Compile / fastOptJS).value
234 | val cypressRunner: File = (Compile / npmUpdate / crossTarget).value / "node_modules" / ".bin" / "cypress"
235 | if (Process(s"$cypressRunner run", baseDirectory.value).run().exitValue() != 0) throw new RuntimeException("failed")
236 | }
237 | )
238 |
239 | lazy val electron = project
240 | .enablePlugins(ScalablyTypedConverterExternalNpmPlugin)
241 | .configure(baseSettings)
242 | .settings(
243 | stStdlib := List("es5"), // doesn't include DOM
244 | /**
245 | * ScalablyTypedConverterExternalNpmPlugin requires that we define how to install node dependencies and where they are
246 | *
247 | * Since we run yarn ourselves the dependencies live in electron/package.json
248 | *
249 | * Invoking yarn is somewhat awkward, because for instance sbt started through intellij won't have a proper PATH set.
250 | * try to start an interactive shell to read the necessary dot files
251 | */
252 | externalNpm := {
253 | if (scala.util.Properties.isWin) Process("yarn", baseDirectory.value).run()
254 | else Process("bash -ci 'yarn'", baseDirectory.value).run()
255 | baseDirectory.value
256 | },
257 | jsEnv := new NodeJSEnv(
258 | NodeJSEnv
259 | .Config()
260 | .withExecutable("electron/node_modules/.bin/electron")
261 | .withArgs(List((Compile / classDirectory).value.toString))
262 | )
263 | )
264 |
265 | lazy val lodash =
266 | project
267 | .enablePlugins(ScalablyTypedConverterPlugin)
268 | .configure(baseSettings, bundlerSettings, nodeProject)
269 | .settings(
270 | Compile / npmDependencies ++= Seq(
271 | "@types/lodash" -> "4.14.149",
272 | "lodash" -> "4.17.11"
273 | ),
274 | useYarn := true
275 | )
276 |
277 | lazy val `node-express` =
278 | project
279 | .enablePlugins(ScalablyTypedConverterPlugin)
280 | .configure(baseSettings, bundlerSettings, nodeProject)
281 | .settings(
282 | Compile / npmDependencies ++= Seq(
283 | "@types/express" -> "4.17.14",
284 | "express" -> "4.18.2"
285 | ),
286 | useYarn := true
287 | )
288 |
289 | lazy val typescript =
290 | project
291 | .enablePlugins(ScalablyTypedConverterPlugin)
292 | .configure(baseSettings, bundlerSettings, nodeProject)
293 | .settings(
294 | Compile / npmDependencies ++= Seq(
295 | "typescript" -> "3.8.3"
296 | ),
297 | /* typescript is implicitly added by the plugin since that's where we get the files for stdlib, and also implicitly ignored */
298 | stIgnore ~= (_.filterNot(_ == "typescript")),
299 | useYarn := true
300 | )
301 |
302 | lazy val baseSettings: Project => Project =
303 | _.enablePlugins(ScalaJSPlugin)
304 | .settings(
305 | scalaVersion := "3.3.0",
306 | version := "0.1-SNAPSHOT",
307 | scalacOptions ++= Seq("-deprecation", "-feature", "-unchecked"),
308 | scalaJSUseMainModuleInitializer := true,
309 | scalaJSLinkerConfig ~= (_
310 | /* disabled because it somehow triggers many warnings */
311 | .withSourceMap(false)
312 | .withModuleKind(ModuleKind.CommonJSModule))
313 | )
314 |
315 | lazy val bundlerSettings: Project => Project =
316 | _.settings(
317 | webpackCliVersion := "4.10.0",
318 | webpack / version := "5.88.2",
319 | Compile / fastOptJS / webpackExtraArgs += "--mode=development",
320 | Compile / fullOptJS / webpackExtraArgs += "--mode=production",
321 | Compile / fastOptJS / webpackDevServerExtraArgs += "--mode=development",
322 | Compile / fullOptJS / webpackDevServerExtraArgs += "--mode=production"
323 | )
324 |
325 | val nodeProject: Project => Project =
326 | _.settings(
327 | jsEnv := new org.scalajs.jsenv.nodejs.NodeJSEnv,
328 | // this doesn't include DOM, which we don't have access to in node. It does, however use BigInt, which is needed
329 | stStdlib := List("esnext"),
330 | stUseScalaJsDom := false,
331 | Compile / npmDependencies ++= Seq(
332 | "@types/node" -> "18.11.9"
333 | )
334 | )
335 |
336 | lazy val withCssLoading: Project => Project =
337 | _.settings(
338 | /* custom webpack file to include css */
339 | webpackConfigFile := Some((ThisBuild / baseDirectory).value / "custom.webpack.config.js"),
340 | Compile / npmDevDependencies ++= Seq(
341 | "webpack-merge" -> "5.9.0",
342 | "css-loader" -> "6.8.1",
343 | "style-loader" -> "3.3.3",
344 | "file-loader" -> "6.2.0",
345 | "url-loader" -> "4.1.1"
346 | )
347 | )
348 |
349 | /**
350 | * Implement the `start` and `dist` tasks defined above.
351 | * Most of this is really just to copy the index.html file around.
352 | */
353 | lazy val browserProject: Project => Project =
354 | _.settings(
355 | start := {
356 | (Compile / fastOptJS / startWebpackDevServer).value
357 | },
358 | dist := {
359 | val artifacts = (Compile / fullOptJS / webpack).value
360 | val artifactFolder = (Compile / fullOptJS / crossTarget).value
361 | val distFolder = (ThisBuild / baseDirectory).value / "docs" / moduleName.value
362 |
363 | distFolder.mkdirs()
364 | artifacts.foreach { artifact =>
365 | val target = artifact.data.relativeTo(artifactFolder) match {
366 | case None => distFolder / artifact.data.name
367 | case Some(relFile) => distFolder / relFile.toString
368 | }
369 |
370 | Files.copy(artifact.data.toPath, target.toPath, REPLACE_EXISTING)
371 | }
372 |
373 | val indexFrom = baseDirectory.value / "src/main/js/index.html"
374 | val indexTo = distFolder / "index.html"
375 |
376 | val indexPatchedContent = {
377 | import collection.JavaConverters._
378 | Files
379 | .readAllLines(indexFrom.toPath, IO.utf8)
380 | .asScala
381 | .map(_.replaceAllLiterally("-fastopt-", "-opt-"))
382 | .mkString("\n")
383 | }
384 |
385 | Files.write(indexTo.toPath, indexPatchedContent.getBytes(IO.utf8))
386 | distFolder
387 | }
388 | )
389 |
--------------------------------------------------------------------------------
/chart/src/main/js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Chart.js demo
6 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/chart/src/main/scala/demo.scala:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import typings.chartJs.mod.{^ as Chart, *}
4 | import typings.moment.mod.Moment
5 | import typings.std.global.document
6 | import typings.std.{stdStrings, Date, HTMLButtonElement, HTMLCanvasElement, HTMLDivElement, MouseEvent}
7 |
8 | import scala.scalajs.js
9 | import scala.scalajs.js.|
10 | import scala.util.Random
11 |
12 | val random = new Random()
13 |
14 | @main
15 | def main(): Unit =
16 | val section = document.createElement_section(stdStrings.section)
17 | section.className = "w"
18 | section.append(
19 | chart(chartConfig(ChartType.bar, randomData(100, random.nextInt()))),
20 | chart(chartConfig(ChartType.pie, randomData(100, random.nextInt()))),
21 | chart(chartConfig(ChartType.polarArea, randomData(100, random.nextInt()))),
22 | chart(chartConfig(ChartType.line, randomData(100, random.nextInt())))
23 | )
24 |
25 | document.body.append(section)
26 | end main
27 |
28 | def chartConfig(tpe: ChartType, Data: js.Array[js.UndefOr[ChartPoint | Double | Null]]): ChartConfiguration =
29 | ChartConfiguration()
30 | .setType(tpe)
31 | .setData(
32 | ChartData()
33 | .setLabels(Labels)
34 | .setDatasets(
35 | js.Array(
36 | ChartDataSets()
37 | .setLabel("Dataset 1")
38 | .setData(Data)
39 | .setBorderWidth(1)
40 | .setBackgroundColor(BackgroundColor)
41 | .setBorderColor(BorderColor)
42 | )
43 | )
44 | )
45 | .setOptions(ChartOptions().setResponsive(true))
46 |
47 | def chart(config: ChartConfiguration): HTMLDivElement =
48 | val div: HTMLDivElement = document.createElement_div(stdStrings.div)
49 | val canvas: HTMLCanvasElement = document.createElement_canvas(stdStrings.canvas)
50 | val chart: Chart = new Chart(canvas, config)
51 |
52 | def dataSetsU: js.UndefOr[js.Array[ChartDataSets]] =
53 | config.data.flatMap(_.datasets)
54 |
55 | val randomizeBtn = button("Randomize Data") { (_, _) =>
56 | dataSetsU.foreach(_.foreach(dataset => dataset.data = randomData(100, random.nextInt())))
57 | chart.update()
58 | }
59 |
60 | val addDataSet = button("Add Dataset") { (_, _) =>
61 | val newDataset = ChartDataSets()
62 | .setLabel("Dataset " + dataSetsU.fold(0)(_.length + 1))
63 | .setData(randomData(100, random.nextInt()))
64 | .setBorderWidth(1)
65 | .setBackgroundColor(BackgroundColor)
66 | .setBorderColor(BorderColor)
67 |
68 | dataSetsU.foreach(_.push(newDataset))
69 | chart.update()
70 | }
71 |
72 | val removeDataset = button("Remove dataset") { (_, _) =>
73 | dataSetsU.foreach(_.splice(0, 1))
74 | chart.update()
75 | }
76 |
77 | div.append(canvas, randomizeBtn, addDataSet, removeDataset)
78 | div
79 | end chart
80 |
81 | def button(title: String)(onClick: js.ThisFunction1[HTMLButtonElement, MouseEvent, js.Any]): HTMLButtonElement =
82 | val btn = document.createElement_button(stdStrings.button)
83 | btn.textContent = title
84 | btn.addEventListener_click(stdStrings.click, onClick)
85 | btn
86 | end button
87 |
88 | def randomData(max: Int, seed: Int): js.Array[js.UndefOr[ChartPoint | Double | scala.Null]] =
89 | val random = new Random(seed)
90 | js.Array[js.UndefOr[ChartPoint | Double | Null]](
91 | random.nextInt(max),
92 | random.nextInt(max),
93 | random.nextInt(max),
94 | random.nextInt(max),
95 | random.nextInt(max),
96 | random.nextInt(max)
97 | )
98 | end randomData
99 |
100 | val Labels: js.Array[String | js.Array[js.Date | Double | Moment | String] | Double | js.Date | Moment] =
101 | js.Array("Red", "Blue", "Yellow", "Green", "Purple", "Orange")
102 |
103 | val BackgroundColor: ChartColor =
104 | js.Array(
105 | color(54, 162, 235, 0.2),
106 | color(255, 206, 86, 0.2),
107 | color(75, 192, 192, 0.2),
108 | color(153, 102, 255, 0.2),
109 | color(255, 159, 64, 0.2)
110 | )
111 |
112 | val BorderColor: ChartColor =
113 | js.Array(
114 | color(255, 99, 132, 1),
115 | color(54, 162, 235, 1),
116 | color(255, 206, 86, 1),
117 | color(75, 192, 192, 1),
118 | color(153, 102, 255, 1),
119 | color(255, 159, 64, 1)
120 | )
121 |
122 | def color(r: Int, g: Int, b: Int, a: Double): String =
123 | s"rgba($r, $g, $b, $a)"
124 |
--------------------------------------------------------------------------------
/custom.webpack.config.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge').merge;
2 | var generated = require('./scalajs.webpack.config');
3 | var path = require('path');
4 |
5 | var local = {
6 | module: {
7 | rules: [
8 | {
9 | test: /\.css$/,
10 | use: ['style-loader', 'css-loader']
11 | },
12 | {
13 | test: /\.(ttf|eot|woff|png|glb|jpeg|jpg|mp4|jsn)$/,
14 | use: 'file-loader'
15 | },
16 | {
17 | test: /\.(eot)$/,
18 | use: 'url-loader'
19 | }
20 | ]
21 | }
22 | };
23 |
24 | module.exports = merge(generated, local);
25 |
--------------------------------------------------------------------------------
/cypress/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "integrationFolder": "target/scala-3.1.0/cypress-fastopt",
3 | "testFiles": "main.js"
4 | }
5 |
--------------------------------------------------------------------------------
/cypress/cypress/plugins/index.js:
--------------------------------------------------------------------------------
1 | ///
2 | // ***********************************************************
3 | // This example plugins/index.js can be used to load plugins
4 | //
5 | // You can change the location of this file or turn off loading
6 | // the plugins file with the 'pluginsFile' configuration option.
7 | //
8 | // You can read more here:
9 | // https://on.cypress.io/plugins-guide
10 | // ***********************************************************
11 |
12 | // This function is called when a project is opened or re-opened (e.g. due to
13 | // the project's config changing)
14 |
15 | /**
16 | * @type {Cypress.PluginConfig}
17 | */
18 | // eslint-disable-next-line no-unused-vars
19 | module.exports = (on, config) => {
20 | // `on` is used to hook into various events Cypress emits
21 | // `config` is the resolved Cypress config
22 | }
23 |
--------------------------------------------------------------------------------
/cypress/cypress/support/commands.js:
--------------------------------------------------------------------------------
1 | // ***********************************************
2 | // This example commands.js shows you how to
3 | // create various custom commands and overwrite
4 | // existing commands.
5 | //
6 | // For more comprehensive examples of custom
7 | // commands please read more here:
8 | // https://on.cypress.io/custom-commands
9 | // ***********************************************
10 | //
11 | //
12 | // -- This is a parent command --
13 | // Cypress.Commands.add('login', (email, password) => { ... })
14 | //
15 | //
16 | // -- This is a child command --
17 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
18 | //
19 | //
20 | // -- This is a dual command --
21 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
22 | //
23 | //
24 | // -- This will overwrite an existing command --
25 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
26 |
--------------------------------------------------------------------------------
/cypress/cypress/support/index.js:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/index.js is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.js using ES2015 syntax:
17 | import './commands'
18 |
19 | // Alternatively you can use CommonJS syntax:
20 | // require('./commands')
21 |
--------------------------------------------------------------------------------
/cypress/cypress/videos/main.js.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/cypress/cypress/videos/main.js.mp4
--------------------------------------------------------------------------------
/cypress/src/main/scala/demo.scala:
--------------------------------------------------------------------------------
1 | import typings.cypress.global.{describe, it, cy}
2 |
3 | @main
4 | def main: Unit =
5 | describe("My First Test", (suite) => {
6 | it("finds the content 'type'", (ctx, done) => {
7 | cy.visit("https://example.cypress.io");
8 | cy.contains("type")
9 | done(())
10 | })
11 | })
12 | end main
13 |
--------------------------------------------------------------------------------
/d3/src/main/js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | D3 demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/d3/src/main/scala/demo.scala:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import typings.d3.mod as d3Mod
4 | import typings.d3Geo.mod.{GeoContext, GeoPermissibleObjects, GeoProjection_, GeoPath_}
5 | import typings.geojson.geojsonStrings
6 | import typings.geojson.mod.{LineString, Position}
7 | import typings.std.global.{console, document, window}
8 | import typings.std.{CanvasRenderingContext2D, FrameRequestCallback, HTMLCanvasElement, stdStrings}
9 |
10 | import scala.scalajs.js
11 | import scala.scalajs.js.|
12 |
13 | // where is my `?.` :( :(
14 | extension [T](ot: T | Null)
15 | def andThen[U](f: T => U | Null): U | Null =
16 | if ot != null then f(ot.asInstanceOf[T]) else null // todo: revisit with explicit nulls
17 |
18 | // this conforms structurally
19 | def isGeoContext(ctx: CanvasRenderingContext2D): GeoContext =
20 | ctx.asInstanceOf[GeoContext]
21 |
22 | @main
23 | def main(): Unit =
24 | val maybeContext: CanvasRenderingContext2D | Null =
25 | document
26 | .getElementsByTagName_canvas(stdStrings.canvas)
27 | .item(0)
28 | .andThen(_.getContext_2d(stdStrings.`2d`))
29 |
30 | if maybeContext != null then start(maybeContext)
31 | else sys.error("Cannot get 2d context")
32 | end main
33 |
34 | def start(context: CanvasRenderingContext2D): Double =
35 | context.lineWidth = 0.4
36 | context.strokeStyle = "rgba(255, 255, 255, 0.6)"
37 |
38 | val width = window.innerWidth
39 | val height = window.innerHeight
40 | val size = width min height
41 |
42 | d3Mod
43 | .select("#content")
44 | .attr("width", s"${width}px")
45 | .attr("height", s"${height}px")
46 |
47 | val projection: GeoProjection_ =
48 | d3Mod
49 | .geoOrthographic()
50 | .scale(0.45 * size)
51 | .translate(js.Tuple2(0.5 * width, 0.5 * height))
52 |
53 | val geoGenerator: GeoPath_[Any, GeoPermissibleObjects] =
54 | d3Mod.geoPath(projection, isGeoContext(context))
55 |
56 | val geometry = LineString(coordinates = js.Array[Position]())
57 |
58 | def rndLon = -180 + Math.random() * 360
59 | def rndLat = -90 + Math.random() * 180
60 |
61 | def addPoint(): Unit =
62 | geometry.coordinates.push(js.Array(rndLon, rndLat))
63 |
64 | def update: FrameRequestCallback =
65 | (time: Double) =>
66 | if geometry.coordinates.length < 6000 then addPoint()
67 |
68 | projection.rotate(js.Tuple2(time / 100, 1.0))
69 |
70 | context.clearRect(0, 0, width, height)
71 | context.beginPath()
72 |
73 | geoGenerator(geometry, null.asInstanceOf[js.Any])
74 | context.stroke()
75 |
76 | window.requestAnimationFrame(update)
77 |
78 | window.requestAnimationFrame(update)
79 | end start
80 |
--------------------------------------------------------------------------------
/docs/angular/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Angular with Scala.js
7 |
8 |
9 | Sorry, angular demo is currently broken
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/chart/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Chart.js demo
6 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/docs/d3/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | D3 demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/google-maps/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Google maps demo 3
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/jquery/05d14cb826bafefd5b46fa2e3be5c952.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/jquery/05d14cb826bafefd5b46fa2e3be5c952.png
--------------------------------------------------------------------------------
/docs/jquery/0f8012f9214f21e71d2e09dd59620cff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/jquery/0f8012f9214f21e71d2e09dd59620cff.png
--------------------------------------------------------------------------------
/docs/jquery/3676d240bfc41073d4b9a3886dbb2c2d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/jquery/3676d240bfc41073d4b9a3886dbb2c2d.png
--------------------------------------------------------------------------------
/docs/jquery/3e7b25be8db5575f37ef732e60ea6eb4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/jquery/3e7b25be8db5575f37ef732e60ea6eb4.png
--------------------------------------------------------------------------------
/docs/jquery/546138d93ba6d3da76e1cefdd3493b25.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/jquery/546138d93ba6d3da76e1cefdd3493b25.png
--------------------------------------------------------------------------------
/docs/jquery/5c18c7c3b45a9e304e1da3da3f6c517f.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/jquery/5c18c7c3b45a9e304e1da3da3f6c517f.png
--------------------------------------------------------------------------------
/docs/jquery/5e67153340a01757d1ee073aa6fdbdd8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/jquery/5e67153340a01757d1ee073aa6fdbdd8.png
--------------------------------------------------------------------------------
/docs/jquery/6451ae9a01ac65bd0fd7eb118e7770f1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/jquery/6451ae9a01ac65bd0fd7eb118e7770f1.png
--------------------------------------------------------------------------------
/docs/jquery/6616f7b7e32f5346b03964406a933d49.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/jquery/6616f7b7e32f5346b03964406a933d49.png
--------------------------------------------------------------------------------
/docs/jquery/6b0513b86cddf85f3764609bbfedfd79.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/jquery/6b0513b86cddf85f3764609bbfedfd79.png
--------------------------------------------------------------------------------
/docs/jquery/7ebbd63f8c28bf02ab557026bb078116.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/jquery/7ebbd63f8c28bf02ab557026bb078116.png
--------------------------------------------------------------------------------
/docs/jquery/aabe52d4b720fc416d5fa1bf79849f8c.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/jquery/aabe52d4b720fc416d5fa1bf79849f8c.png
--------------------------------------------------------------------------------
/docs/jquery/b159d479704de144f3bde7eb8c232ce5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/jquery/b159d479704de144f3bde7eb8c232ce5.png
--------------------------------------------------------------------------------
/docs/jquery/b5c094c2859bb622056ba7a883112aec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/jquery/b5c094c2859bb622056ba7a883112aec.png
--------------------------------------------------------------------------------
/docs/jquery/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Jquery demo
6 |
7 |
8 |
9 |
Value is ...
10 |
11 |
12 |
Jqueryui accordion:
13 |
14 |
Section 1
15 |
16 |
17 | Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer
18 | ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit
19 | amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut
20 | odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate.
21 |
22 |
23 |
Section 2
24 |
25 |
26 | Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet
27 | purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor
28 | velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In
29 | suscipit faucibus urna.
30 |
31 |
32 |
Section 3
33 |
34 |
35 | Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis.
36 | Phasellus pellentesque purus in massa. Aenean in pede. Phasellus ac libero
37 | ac tellus pellentesque semper. Sed ac felis. Sed commodo, magna quis
38 | lacinia ornare, quam ante aliquam nisi, eu iaculis leo purus venenatis dui.
39 |
40 |
41 | List item one
42 | List item two
43 | List item three
44 |
45 |
46 |
Section 4
47 |
48 |
49 | Cras dictum. Pellentesque habitant morbi tristique senectus et netus
50 | et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in
51 | faucibus orci luctus et ultrices posuere cubilia Curae; Aenean lacinia
52 | mauris vel est.
53 |
54 |
55 | Suspendisse eu nisl. Nullam ut libero. Integer dignissim consequat lectus.
56 | Class aptent taciti sociosqu ad litora torquent per conubia nostra, per
57 | inceptos himenaeos.
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/docs/leaflet/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | leaflet demo
6 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/onsenui/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Click me!
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/p5/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | P5 demo
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/phaser/4c749ba5f2242b64e37fa7439ece8c98.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/phaser/4c749ba5f2242b64e37fa7439ece8c98.png
--------------------------------------------------------------------------------
/docs/phaser/ff69a6fb51aef4d4950ff9398136e979.jsn:
--------------------------------------------------------------------------------
1 | {"frames": {
2 |
3 | "diamond_0000":
4 | {
5 | "frame": {"x":2,"y":2,"w":64,"h":64},
6 | "rotated": false,
7 | "trimmed": false,
8 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
9 | "sourceSize": {"w":64,"h":64},
10 | "pivot": {"x":0.5,"y":0.5}
11 | },
12 | "diamond_0001":
13 | {
14 | "frame": {"x":2,"y":68,"w":64,"h":64},
15 | "rotated": false,
16 | "trimmed": false,
17 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
18 | "sourceSize": {"w":64,"h":64},
19 | "pivot": {"x":0.5,"y":0.5}
20 | },
21 | "diamond_0002":
22 | {
23 | "frame": {"x":2,"y":134,"w":64,"h":64},
24 | "rotated": false,
25 | "trimmed": false,
26 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
27 | "sourceSize": {"w":64,"h":64},
28 | "pivot": {"x":0.5,"y":0.5}
29 | },
30 | "diamond_0003":
31 | {
32 | "frame": {"x":68,"y":2,"w":64,"h":64},
33 | "rotated": false,
34 | "trimmed": false,
35 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
36 | "sourceSize": {"w":64,"h":64},
37 | "pivot": {"x":0.5,"y":0.5}
38 | },
39 | "diamond_0004":
40 | {
41 | "frame": {"x":68,"y":68,"w":64,"h":64},
42 | "rotated": false,
43 | "trimmed": false,
44 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
45 | "sourceSize": {"w":64,"h":64},
46 | "pivot": {"x":0.5,"y":0.5}
47 | },
48 | "diamond_0005":
49 | {
50 | "frame": {"x":68,"y":134,"w":64,"h":64},
51 | "rotated": false,
52 | "trimmed": false,
53 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
54 | "sourceSize": {"w":64,"h":64},
55 | "pivot": {"x":0.5,"y":0.5}
56 | },
57 | "diamond_0006":
58 | {
59 | "frame": {"x":134,"y":2,"w":64,"h":64},
60 | "rotated": false,
61 | "trimmed": false,
62 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
63 | "sourceSize": {"w":64,"h":64},
64 | "pivot": {"x":0.5,"y":0.5}
65 | },
66 | "diamond_0007":
67 | {
68 | "frame": {"x":134,"y":68,"w":64,"h":64},
69 | "rotated": false,
70 | "trimmed": false,
71 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
72 | "sourceSize": {"w":64,"h":64},
73 | "pivot": {"x":0.5,"y":0.5}
74 | },
75 | "diamond_0008":
76 | {
77 | "frame": {"x":134,"y":134,"w":64,"h":64},
78 | "rotated": false,
79 | "trimmed": false,
80 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
81 | "sourceSize": {"w":64,"h":64},
82 | "pivot": {"x":0.5,"y":0.5}
83 | },
84 | "diamond_0009":
85 | {
86 | "frame": {"x":200,"y":2,"w":64,"h":64},
87 | "rotated": false,
88 | "trimmed": false,
89 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
90 | "sourceSize": {"w":64,"h":64},
91 | "pivot": {"x":0.5,"y":0.5}
92 | },
93 | "diamond_0010":
94 | {
95 | "frame": {"x":200,"y":68,"w":64,"h":64},
96 | "rotated": false,
97 | "trimmed": false,
98 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
99 | "sourceSize": {"w":64,"h":64},
100 | "pivot": {"x":0.5,"y":0.5}
101 | },
102 | "diamond_0011":
103 | {
104 | "frame": {"x":200,"y":134,"w":64,"h":64},
105 | "rotated": false,
106 | "trimmed": false,
107 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
108 | "sourceSize": {"w":64,"h":64},
109 | "pivot": {"x":0.5,"y":0.5}
110 | },
111 | "diamond_0012":
112 | {
113 | "frame": {"x":266,"y":2,"w":64,"h":64},
114 | "rotated": false,
115 | "trimmed": false,
116 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
117 | "sourceSize": {"w":64,"h":64},
118 | "pivot": {"x":0.5,"y":0.5}
119 | },
120 | "diamond_0013":
121 | {
122 | "frame": {"x":266,"y":68,"w":64,"h":64},
123 | "rotated": false,
124 | "trimmed": false,
125 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
126 | "sourceSize": {"w":64,"h":64},
127 | "pivot": {"x":0.5,"y":0.5}
128 | },
129 | "diamond_0014":
130 | {
131 | "frame": {"x":266,"y":134,"w":64,"h":64},
132 | "rotated": false,
133 | "trimmed": false,
134 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
135 | "sourceSize": {"w":64,"h":64},
136 | "pivot": {"x":0.5,"y":0.5}
137 | },
138 | "diamond_0015":
139 | {
140 | "frame": {"x":332,"y":2,"w":64,"h":64},
141 | "rotated": false,
142 | "trimmed": false,
143 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
144 | "sourceSize": {"w":64,"h":64},
145 | "pivot": {"x":0.5,"y":0.5}
146 | },
147 | "prism_0000":
148 | {
149 | "frame": {"x":332,"y":68,"w":64,"h":64},
150 | "rotated": false,
151 | "trimmed": false,
152 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
153 | "sourceSize": {"w":64,"h":64},
154 | "pivot": {"x":0.5,"y":0.5}
155 | },
156 | "prism_0001":
157 | {
158 | "frame": {"x":332,"y":134,"w":64,"h":64},
159 | "rotated": false,
160 | "trimmed": false,
161 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
162 | "sourceSize": {"w":64,"h":64},
163 | "pivot": {"x":0.5,"y":0.5}
164 | },
165 | "prism_0002":
166 | {
167 | "frame": {"x":398,"y":2,"w":64,"h":64},
168 | "rotated": false,
169 | "trimmed": false,
170 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
171 | "sourceSize": {"w":64,"h":64},
172 | "pivot": {"x":0.5,"y":0.5}
173 | },
174 | "prism_0003":
175 | {
176 | "frame": {"x":398,"y":68,"w":64,"h":64},
177 | "rotated": false,
178 | "trimmed": false,
179 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
180 | "sourceSize": {"w":64,"h":64},
181 | "pivot": {"x":0.5,"y":0.5}
182 | },
183 | "prism_0004":
184 | {
185 | "frame": {"x":398,"y":134,"w":64,"h":64},
186 | "rotated": false,
187 | "trimmed": false,
188 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
189 | "sourceSize": {"w":64,"h":64},
190 | "pivot": {"x":0.5,"y":0.5}
191 | },
192 | "prism_0005":
193 | {
194 | "frame": {"x":464,"y":2,"w":64,"h":64},
195 | "rotated": false,
196 | "trimmed": false,
197 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
198 | "sourceSize": {"w":64,"h":64},
199 | "pivot": {"x":0.5,"y":0.5}
200 | },
201 | "prism_0006":
202 | {
203 | "frame": {"x":464,"y":68,"w":64,"h":64},
204 | "rotated": false,
205 | "trimmed": false,
206 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
207 | "sourceSize": {"w":64,"h":64},
208 | "pivot": {"x":0.5,"y":0.5}
209 | },
210 | "ruby_0000":
211 | {
212 | "frame": {"x":464,"y":134,"w":64,"h":64},
213 | "rotated": false,
214 | "trimmed": false,
215 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
216 | "sourceSize": {"w":64,"h":64},
217 | "pivot": {"x":0.5,"y":0.5}
218 | },
219 | "ruby_0001":
220 | {
221 | "frame": {"x":530,"y":2,"w":64,"h":64},
222 | "rotated": false,
223 | "trimmed": false,
224 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
225 | "sourceSize": {"w":64,"h":64},
226 | "pivot": {"x":0.5,"y":0.5}
227 | },
228 | "ruby_0002":
229 | {
230 | "frame": {"x":530,"y":68,"w":64,"h":64},
231 | "rotated": false,
232 | "trimmed": false,
233 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
234 | "sourceSize": {"w":64,"h":64},
235 | "pivot": {"x":0.5,"y":0.5}
236 | },
237 | "ruby_0003":
238 | {
239 | "frame": {"x":530,"y":134,"w":64,"h":64},
240 | "rotated": false,
241 | "trimmed": false,
242 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
243 | "sourceSize": {"w":64,"h":64},
244 | "pivot": {"x":0.5,"y":0.5}
245 | },
246 | "ruby_0004":
247 | {
248 | "frame": {"x":596,"y":2,"w":64,"h":64},
249 | "rotated": false,
250 | "trimmed": false,
251 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
252 | "sourceSize": {"w":64,"h":64},
253 | "pivot": {"x":0.5,"y":0.5}
254 | },
255 | "ruby_0005":
256 | {
257 | "frame": {"x":596,"y":68,"w":64,"h":64},
258 | "rotated": false,
259 | "trimmed": false,
260 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
261 | "sourceSize": {"w":64,"h":64},
262 | "pivot": {"x":0.5,"y":0.5}
263 | },
264 | "ruby_0006":
265 | {
266 | "frame": {"x":596,"y":134,"w":64,"h":64},
267 | "rotated": false,
268 | "trimmed": false,
269 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
270 | "sourceSize": {"w":64,"h":64},
271 | "pivot": {"x":0.5,"y":0.5}
272 | },
273 | "square_0000":
274 | {
275 | "frame": {"x":662,"y":2,"w":64,"h":64},
276 | "rotated": false,
277 | "trimmed": false,
278 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
279 | "sourceSize": {"w":64,"h":64},
280 | "pivot": {"x":0.5,"y":0.5}
281 | },
282 | "square_0001":
283 | {
284 | "frame": {"x":662,"y":68,"w":64,"h":64},
285 | "rotated": false,
286 | "trimmed": false,
287 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
288 | "sourceSize": {"w":64,"h":64},
289 | "pivot": {"x":0.5,"y":0.5}
290 | },
291 | "square_0002":
292 | {
293 | "frame": {"x":662,"y":134,"w":64,"h":64},
294 | "rotated": false,
295 | "trimmed": false,
296 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
297 | "sourceSize": {"w":64,"h":64},
298 | "pivot": {"x":0.5,"y":0.5}
299 | },
300 | "square_0003":
301 | {
302 | "frame": {"x":728,"y":2,"w":64,"h":64},
303 | "rotated": false,
304 | "trimmed": false,
305 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
306 | "sourceSize": {"w":64,"h":64},
307 | "pivot": {"x":0.5,"y":0.5}
308 | },
309 | "square_0004":
310 | {
311 | "frame": {"x":728,"y":68,"w":64,"h":64},
312 | "rotated": false,
313 | "trimmed": false,
314 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
315 | "sourceSize": {"w":64,"h":64},
316 | "pivot": {"x":0.5,"y":0.5}
317 | },
318 | "square_0005":
319 | {
320 | "frame": {"x":728,"y":134,"w":64,"h":64},
321 | "rotated": false,
322 | "trimmed": false,
323 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
324 | "sourceSize": {"w":64,"h":64},
325 | "pivot": {"x":0.5,"y":0.5}
326 | },
327 | "square_0006":
328 | {
329 | "frame": {"x":794,"y":2,"w":64,"h":64},
330 | "rotated": false,
331 | "trimmed": false,
332 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
333 | "sourceSize": {"w":64,"h":64},
334 | "pivot": {"x":0.5,"y":0.5}
335 | },
336 | "square_0007":
337 | {
338 | "frame": {"x":860,"y":2,"w":64,"h":64},
339 | "rotated": false,
340 | "trimmed": false,
341 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
342 | "sourceSize": {"w":64,"h":64},
343 | "pivot": {"x":0.5,"y":0.5}
344 | },
345 | "square_0008":
346 | {
347 | "frame": {"x":926,"y":2,"w":64,"h":64},
348 | "rotated": false,
349 | "trimmed": false,
350 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
351 | "sourceSize": {"w":64,"h":64},
352 | "pivot": {"x":0.5,"y":0.5}
353 | },
354 | "square_0009":
355 | {
356 | "frame": {"x":794,"y":68,"w":64,"h":64},
357 | "rotated": false,
358 | "trimmed": false,
359 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
360 | "sourceSize": {"w":64,"h":64},
361 | "pivot": {"x":0.5,"y":0.5}
362 | },
363 | "square_0010":
364 | {
365 | "frame": {"x":794,"y":134,"w":64,"h":64},
366 | "rotated": false,
367 | "trimmed": false,
368 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
369 | "sourceSize": {"w":64,"h":64},
370 | "pivot": {"x":0.5,"y":0.5}
371 | },
372 | "square_0011":
373 | {
374 | "frame": {"x":860,"y":68,"w":64,"h":64},
375 | "rotated": false,
376 | "trimmed": false,
377 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
378 | "sourceSize": {"w":64,"h":64},
379 | "pivot": {"x":0.5,"y":0.5}
380 | },
381 | "square_0012":
382 | {
383 | "frame": {"x":926,"y":68,"w":64,"h":64},
384 | "rotated": false,
385 | "trimmed": false,
386 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
387 | "sourceSize": {"w":64,"h":64},
388 | "pivot": {"x":0.5,"y":0.5}
389 | },
390 | "square_0013":
391 | {
392 | "frame": {"x":860,"y":134,"w":64,"h":64},
393 | "rotated": false,
394 | "trimmed": false,
395 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
396 | "sourceSize": {"w":64,"h":64},
397 | "pivot": {"x":0.5,"y":0.5}
398 | },
399 | "square_0014":
400 | {
401 | "frame": {"x":926,"y":134,"w":64,"h":64},
402 | "rotated": false,
403 | "trimmed": false,
404 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
405 | "sourceSize": {"w":64,"h":64},
406 | "pivot": {"x":0.5,"y":0.5}
407 | }},
408 | "meta": {
409 | "app": "http://www.codeandweb.com/texturepacker",
410 | "version": "1.0",
411 | "image": "gems.png",
412 | "format": "RGBA8888",
413 | "size": {"w":992,"h":200},
414 | "scale": "1",
415 | "smartupdate": "$TexturePacker:SmartUpdate:5dfda9c839d3ca51c00faf9458ba1fca:0b0be3727c36efcd76ae8acf6abbf211:81fc68276d1596f8f7ad75d59a9ce9b5$"
416 | }
417 | }
418 |
--------------------------------------------------------------------------------
/docs/phaser/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | phaser demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/pixi/27905594c5fb6a699e83e2a33ac4594f.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/pixi/27905594c5fb6a699e83e2a33ac4594f.jpg
--------------------------------------------------------------------------------
/docs/pixi/3cd1bac088de1f0141a2d2b460f5e604.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/pixi/3cd1bac088de1f0141a2d2b460f5e604.jpeg
--------------------------------------------------------------------------------
/docs/pixi/4570873d87d3a0f6e5ac1cb8fe25e0d3.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/pixi/4570873d87d3a0f6e5ac1cb8fe25e0d3.mp4
--------------------------------------------------------------------------------
/docs/pixi/4570873d87d3a0f6e5ac1cb8fe25e0d3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/pixi/4570873d87d3a0f6e5ac1cb8fe25e0d3.png
--------------------------------------------------------------------------------
/docs/pixi/671dfaa933552f588d943ca39375807e.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/pixi/671dfaa933552f588d943ca39375807e.png
--------------------------------------------------------------------------------
/docs/pixi/70f6dd03a1f4a89b372199a507d13413.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/pixi/70f6dd03a1f4a89b372199a507d13413.mp4
--------------------------------------------------------------------------------
/docs/pixi/81caa7d77cd7fe45112c79d65902fe6f.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/pixi/81caa7d77cd7fe45112c79d65902fe6f.jpg
--------------------------------------------------------------------------------
/docs/pixi/8bfb7c2cc94d5e2fe3e9eb8766c2143c.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/pixi/8bfb7c2cc94d5e2fe3e9eb8766c2143c.png
--------------------------------------------------------------------------------
/docs/pixi/98caa6066cf537444105787d26f45c13.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/pixi/98caa6066cf537444105787d26f45c13.jpg
--------------------------------------------------------------------------------
/docs/pixi/9cc4b590bde4d70f18cb9ba64776ae2b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/pixi/9cc4b590bde4d70f18cb9ba64776ae2b.png
--------------------------------------------------------------------------------
/docs/pixi/ae108d533b303b523de5393a7e0f4b0e.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/pixi/ae108d533b303b523de5393a7e0f4b0e.jpeg
--------------------------------------------------------------------------------
/docs/pixi/c79a9d4407a11aa2611443c9d8ea7d70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/pixi/c79a9d4407a11aa2611443c9d8ea7d70.png
--------------------------------------------------------------------------------
/docs/pixi/e6485b0aaa9ff710c4454df3a144efb1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/pixi/e6485b0aaa9ff710c4454df3a144efb1.png
--------------------------------------------------------------------------------
/docs/pixi/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pixi.js with Scala.js
7 |
8 |
9 |
12 |
13 |
14 |
Pixi.js with Scala.js!
15 |
16 |
17 | Click in the menu on the left to see the examples from the official website translated into
18 | Scala, using Scala.js and ScalablyTyped.
19 |
20 |
21 | This project uses version 5 of Pixi.
22 |
23 |
24 |
25 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/docs/reveal/1cb8e94f1185f1131a0c895165998f2b.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/reveal/1cb8e94f1185f1131a0c895165998f2b.woff
--------------------------------------------------------------------------------
/docs/reveal/2da39ecf9246383937da11b44b7bd9b4.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/reveal/2da39ecf9246383937da11b44b7bd9b4.ttf
--------------------------------------------------------------------------------
/docs/reveal/6b058fc2634b01d837c3432316c3141f.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/reveal/6b058fc2634b01d837c3432316c3141f.woff
--------------------------------------------------------------------------------
/docs/reveal/8256cfd7e4017a7690814879409212cd.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/reveal/8256cfd7e4017a7690814879409212cd.ttf
--------------------------------------------------------------------------------
/docs/reveal/c7e698a4d0956f4a939f42a05685bbf5.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/reveal/c7e698a4d0956f4a939f42a05685bbf5.ttf
--------------------------------------------------------------------------------
/docs/reveal/e74f0128884561828ce8c9cf5c284ab8.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/reveal/e74f0128884561828ce8c9cf5c284ab8.woff
--------------------------------------------------------------------------------
/docs/reveal/e7acc589bb558fe58936a853f570193c.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/reveal/e7acc589bb558fe58936a853f570193c.woff
--------------------------------------------------------------------------------
/docs/reveal/f3565095e6c9158140444970f5a2c5ed.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/reveal/f3565095e6c9158140444970f5a2c5ed.ttf
--------------------------------------------------------------------------------
/docs/reveal/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Reveal.js demo
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/three/ebf4afeb87874d0a1487e7ea687fb529.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/docs/three/ebf4afeb87874d0a1487e7ea687fb529.glb
--------------------------------------------------------------------------------
/docs/three/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Three.js demo
7 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/docs/vue/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Scala.js+Vue.js sample application!
5 |
6 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | Title=
45 |
46 |
47 |
48 |
49 | {{todo.content}}
50 | Remove
51 |
52 |
53 |
54 |
55 | Tasks# {{todos.length}}
56 | N={{n}}
57 |
58 |
data JSON: {{$data | json 2}}
59 |
60 |
61 | Using a v-text directive title=
62 |
Smooth CSS animation:
63 |
64 |
65 |
66 |
67 |
68 |
Title reversed={{title | reverse}}
69 |
Title wrapper={{title | wrap('<<','>>')}}
70 |
xx
71 |
Special content
72 |
73 |
Call clickHandler in Scala
74 |
Increment N
75 |
76 |
Add Task
77 |
Change 1st
78 |
Remove 1st
79 |
Flip All
80 | Todos computed: {{ todosComputed }}
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/electron/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "@types/node": "^18.11.9",
4 | "electron": "^21.2.2",
5 | "typescript": "^4.8.4"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/electron/src/main/resources/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hello World!
6 |
7 |
8 | Hello World!
9 | We are using node ,
10 | Chrome ,
11 | and Electron .
12 |
13 |
14 |
--------------------------------------------------------------------------------
/electron/src/main/resources/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "your-app",
3 | "version" : "0.1.0",
4 | "main" : "../electron-fastopt/main.js"
5 | }
6 |
--------------------------------------------------------------------------------
/electron/src/main/scala/mainprocess/MainProcess.scala:
--------------------------------------------------------------------------------
1 | package mainprocess
2 |
3 | import typings.electron.Electron.BrowserWindowConstructorOptions
4 | import typings.electron.electronStrings
5 | import typings.electron.mod.{BrowserWindow, app}
6 | import typings.node.{urlMod, pathMod as path}
7 | import typings.node.urlMod.UrlObject
8 |
9 | import scala.collection.mutable
10 | import scala.scalajs.js
11 | import scala.scalajs.js.annotation.JSImport
12 |
13 | @JSImport("electron", "BrowserWindow")
14 | @js.native
15 | class FixedBrowserWindow(options: BrowserWindowConstructorOptions) extends typings.electron.mod.BrowserWindow
16 |
17 | /** This object represents the translation into Scala.js of the main.js file presented in the Electron Quick Start
18 | * guide, available at https://electron.atom.io/docs/tutorial/quick-start/
19 | */
20 | /** Every created windows will be put into the windows mutable.Set. */
21 | val windows: mutable.Set[BrowserWindow] = mutable.Set()
22 |
23 | def createWindow(): Unit =
24 |
25 | /** Printing "hello" in the main process, just to see it in action. */
26 | println("hello")
27 |
28 | /** Creating the BrowserWindow object, with the desired options.
29 | */
30 | val window = new FixedBrowserWindow(
31 | BrowserWindowConstructorOptions().setHeight(600).setWidth(800)
32 | )
33 | window.loadURL(
34 | urlMod.format(
35 | UrlObject().setPathname(path.join(app.getAppPath(), "index.html")).setProtocol("file:").setSlashes(true)
36 | )
37 | )
38 |
39 | /** In Scala.js, you have two modes for compiling your code. A fast and a full optimized way. Fast optimisation should
40 | * be used in development only. Compilation time is significantly shorted, and to a lesser extent, produces more
41 | * "human readable" JavaScript code in case you really want to have a look. Full optimized compilation leads to more
42 | * optimized JavaScript code, as well as lighter JavaScript files.
43 | *
44 | * As a result, Scala.js also allows you to perform snippets of codes depending on the mode of compilation you chose.
45 | * In this case, we only want to open the dev tools of a window if we are in development mode, but it is something
46 | * that you clearly want to avoid in production code.
47 | */
48 | if scala.scalajs.LinkingInfo.developmentMode then window.webContents.openDevTools()
49 | end if
50 |
51 | window.on_closed(electronStrings.closed, () => windows -= window)
52 |
53 | windows += window
54 | end createWindow
55 |
56 | /** The main method is called automatically when the JavaScript file is loaded, thanks to the sbt setting
57 | * scalaJSUseMainModuleInitializer := true in the build.sbt file. Removing this method will fail at compile time.
58 | */
59 | @main
60 | def main: Unit =
61 | app.on_ready(electronStrings.ready, (event, launchInfo) => createWindow())
62 | app.on_windowallclosed(electronStrings.`window-all-closed`, () => app.quit())
63 | end main
64 |
--------------------------------------------------------------------------------
/google-maps/src/main/js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Google maps demo 3
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/google-maps/src/main/scala/demo.scala:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import org.scalajs.dom.document
4 | import org.scalajs.dom.raw.Element
5 | import typings.googlemaps.google.maps.{MapOptions, ReadonlyMarkerOptions}
6 | import typings.googlemaps.global.google.maps
7 |
8 | val beaches: Map[String, maps.LatLng] =
9 | Map(
10 | "Bondi Beach" -> new maps.LatLng(-33.890542, 151.274856),
11 | "Coogee Beach" -> new maps.LatLng(-33.923036, 151.259052),
12 | "Cronulla Beach" -> new maps.LatLng(-34.028249, 151.157507),
13 | "Manly Beach" -> new maps.LatLng(-33.80010128657071, 151.28747820854187)
14 | )
15 |
16 | @main
17 | def main: Unit =
18 | val container = document.getElementById("content")
19 | val m: maps.Map[Element] = new maps.Map(
20 | container,
21 | MapOptions().setCenter(new maps.LatLng(-33.9, 151.2)).setZoom(4)
22 | )
23 |
24 | val info = new maps.InfoWindow
25 |
26 | beaches.foreach { case (beach, pos) =>
27 | val marker = new maps.Marker(ReadonlyMarkerOptions().setPosition(pos).setTitle(beach).setMap(m))
28 |
29 | maps.event.addListener(
30 | marker,
31 | "click",
32 | _ =>
33 | info.setContent(s"This is $beach ")
34 | info.open(m, marker)
35 | )
36 | }
37 | end main
38 |
--------------------------------------------------------------------------------
/jquery/src/main/js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Jquery demo
6 |
7 |
8 |
9 |
Value is ...
10 |
11 |
12 |
Jqueryui accordion:
13 |
14 |
Section 1
15 |
16 |
17 | Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer
18 | ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit
19 | amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut
20 | odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate.
21 |
22 |
23 |
Section 2
24 |
25 |
26 | Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet
27 | purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor
28 | velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In
29 | suscipit faucibus urna.
30 |
31 |
32 |
Section 3
33 |
34 |
35 | Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis.
36 | Phasellus pellentesque purus in massa. Aenean in pede. Phasellus ac libero
37 | ac tellus pellentesque semper. Sed ac felis. Sed commodo, magna quis
38 | lacinia ornare, quam ante aliquam nisi, eu iaculis leo purus venenatis dui.
39 |
40 |
41 | List item one
42 | List item two
43 | List item three
44 |
45 |
46 |
Section 4
47 |
48 |
49 | Cras dictum. Pellentesque habitant morbi tristique senectus et netus
50 | et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in
51 | faucibus orci luctus et ultrices posuere cubilia Curae; Aenean lacinia
52 | mauris vel est.
53 |
54 |
55 | Suspendisse eu nisl. Nullam ut libero. Integer dignissim consequat lectus.
56 | Class aptent taciti sociosqu ad litora torquent per conubia nostra, per
57 | inceptos himenaeos.
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/jquery/src/main/scala/demo.scala:
--------------------------------------------------------------------------------
1 | import org.scalajs.dom.document
2 | import org.scalajs.dom.html.{Button, Label}
3 | import org.scalajs.dom.raw.Element
4 | import typings.jquery.{JQuery, JQueryEventObject, mod as $}
5 | import typings.jqueryui
6 | import typings.jqueryui.jqueryuiRequire
7 |
8 | import scala.language.implicitConversions
9 | import scala.scalajs.js
10 | import scala.scalajs.js.annotation.JSImport
11 |
12 | @JSImport("jqueryui/jquery-ui.css", JSImport.Namespace)
13 | @js.native
14 | object JqueryUiCss extends js.Object
15 |
16 | /* fake interface augmentation. This is done automatically in typescript. */
17 | given [T]: Conversion[JQuery[T], typings.jqueryui.JQuery] with
18 | override def apply(x: JQuery[T]): jqueryui.JQuery = x.asInstanceOf[typings.jqueryui.JQuery]
19 |
20 | @main
21 | def main: Unit =
22 | // trigger loading of global library and CSS
23 | jqueryuiRequire
24 | JqueryUiCss
25 |
26 | var counter = 1
27 | val renderLabel: js.Function1[ /* event */ JQueryEventObject, scala.Unit] = eo =>
28 | counter += 1
29 | $[Label]("#label").text(s"Value is $counter")
30 |
31 | $[Button]("#button")
32 | .text("bumpit")
33 | .on("click", renderLabel)
34 |
35 | $("#accordion").accordion()
36 | end main
37 |
--------------------------------------------------------------------------------
/leaflet/src/main/js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | leaflet demo
6 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/leaflet/src/main/scala/demo.scala:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import org.scalajs.dom.{document, html}
4 | import typings.leaflet.mod as L
5 |
6 | import scala.scalajs.js
7 |
8 | val TileLayerUri =
9 | "https://tile.openstreetmap.org/{z}/{x}/{y}.png"
10 |
11 | @main
12 | def main: Unit =
13 | val el = document.getElementById("content").asInstanceOf[html.Element]
14 | val map = L.map(el).setView(L.LatLngLiteral(51.505, -0.09), zoom = 13)
15 |
16 | L.tileLayer(
17 | TileLayerUri,
18 | L.TileLayerOptions()
19 | .setId("mapbox.streets")
20 | .setMaxZoom(19)
21 | .setAttribution(
22 | """Map data © OpenStreetMap contributors,
23 | |CC-BY-SA ,
24 | |Imagery © Mapbox """.stripMargin
25 | )
26 | ).addTo(map)
27 |
28 | L.marker(L.LatLngLiteral(51.5, -0.09), L.MarkerOptions().setTitle("I am a marker"))
29 | .bindPopup("I am a popup")
30 | .addTo(map)
31 |
32 | L.circle(
33 | L.LatLngLiteral(51.508, -0.11),
34 | L.CircleMarkerOptions().setColor("red").setFillColor("#f03").setFillOpacity(0.5).setRadius(500)
35 | ).bindPopup("I am a circle")
36 | .addTo(map)
37 |
38 | L.circle(
39 | L.LatLngLiteral(51.516, -0.11),
40 | L.CircleMarkerOptions().setColor("green").setFillColor("#f03").setFillOpacity(0.5).setRadius(200)
41 | ).addTo(map)
42 |
43 | L.polygon(js.Array(L.LatLngLiteral(51.509, -0.08), L.LatLngLiteral(51.503, -0.06), L.LatLngLiteral(51.51, -0.047)))
44 | .bindPopup("I am a polygon")
45 | .addTo(map)
46 |
47 | L.popup()
48 | .setLatLng(L.LatLngLiteral(51.5, -0.09))
49 | .setContent("I am a standalone popup.")
50 | .openOn(map)
51 | end main
52 |
--------------------------------------------------------------------------------
/lodash/src/main/scala/demo.scala:
--------------------------------------------------------------------------------
1 | import org.scalablytyped.runtime.NumberDictionary
2 | import typings.lodash.fpMod as Fp
3 | import typings.lodash.mod.{ArrayIterator, MemoListIterator, ^ as L}
4 | import typings.node.global.console
5 | import typings.std.ArrayLike
6 |
7 | import scala.scalajs.js
8 |
9 | class Person(val name: String, val age: Int) extends js.Object
10 |
11 | val Fiona = new Person("Fiona First", 1)
12 | val Sam = new Person("Sam Second", 101)
13 | val Persons = js.Array(Fiona, Sam)
14 |
15 | // matches structurally
16 | def isArrayLike[T](ts: js.Array[T]): ArrayLike[T] =
17 | ts.asInstanceOf[ArrayLike[T]]
18 |
19 | @main
20 | def main: Unit =
21 |
22 | val summarizeNames: MemoListIterator[Person, String, js.Array[Person]] =
23 | (prev, curr, idx, all) => prev + " and " + curr.name
24 |
25 | val value2 = L.reduce(Persons, summarizeNames, "")
26 | console.log("Summarized names of two persons", value2)
27 |
28 | val value3 = L.reduce(js.Array[Person](), summarizeNames, "")
29 | console.log("Summarized names of no persons", value3)
30 |
31 | val toAge: ArrayIterator[Person, Int] =
32 | (curr, _, _) => curr.age
33 |
34 | console.log("Ages for persons", L.map(Persons.asInstanceOf[NumberDictionary[Double]], toAge))
35 |
36 | console.log("fields for Fiona", L.entriesIn(Fiona))
37 |
38 | console.log("Dropped first", Fp.^.drop(1, isArrayLike(Persons)))
39 | end main
40 |
--------------------------------------------------------------------------------
/node-express/src/main/scala/demo.scala:
--------------------------------------------------------------------------------
1 | import typings.express.mod as e
2 | import typings.expressServeStaticCore.mod.*
3 | import typings.node.global.console
4 | import typings.node.processMod.^ as process
5 |
6 | import scala.scalajs.js
7 |
8 | object WelcomeController:
9 |
10 | val Router: Router =
11 | e.Router()
12 |
13 | val Index: RequestHandler[Unit, String, Unit, Unit, Unit] =
14 | (_, res, _) => res.send("Hello, World!")
15 |
16 | trait HasName extends js.Object:
17 | val name: js.UndefOr[String]
18 |
19 | val Name: RequestHandler[HasName, String, Unit, Unit, Unit] = (req, res, next) =>
20 | res.send(s"Hello, ${req.params.name.getOrElse("No Name")}!")
21 |
22 | Router
23 | .get[Unit, String, Unit, Unit, Unit]("/", Index)
24 | .get[HasName, String, Unit, Unit, Unit]("/:name", Name)
25 |
26 | end WelcomeController
27 |
28 | @main
29 | def main: Unit =
30 | val app = e()
31 | val port = process.env.get("PORT").flatMap(_.toOption).fold(3000)(_.toInt)
32 | app.use("/welcome", WelcomeController.Router)
33 |
34 | app.listen(port, () => console.log(s"Listening at http://localhost:$port/"))
35 | end main
36 |
--------------------------------------------------------------------------------
/onsenui/src/main/js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Click me!
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/onsenui/src/main/scala/demo.scala:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import typings.jquery.{JQueryEventObject, mod as $}
4 | import typings.onsenui.mod as ons
5 |
6 | import scala.scalajs.js
7 |
8 | @main
9 | def main: Unit =
10 |
11 | /** Note, using `on` with the jquery typings is very frustrating. It'll be fixed eventually, but for now I would
12 | * copy/paste the facade and delete a bunch of lines to make it simpler
13 | */
14 | val f: js.Function1[JQueryEventObject, Unit] = _ => ons.notification.alert("Button is tapped!")
15 |
16 | $("ons-button").on("click", f)
17 | end main
18 |
19 |
--------------------------------------------------------------------------------
/p5/src/main/js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | P5 demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/p5/src/main/scala/demo.scala:
--------------------------------------------------------------------------------
1 | import org.scalajs.dom.console
2 | import typings.p5.mod.{p5InstanceExtensions, ^ as P5}
3 |
4 | import scala.scalajs.js
5 |
6 | @main
7 | def main: Unit =
8 | val sketch = P5Facade { p =>
9 | val x = 100
10 | val y = 100
11 |
12 | p.setup = () => p.createCanvas(700, 410)
13 |
14 | p.draw = () =>
15 | p.background(0)
16 | p.fill(255)
17 | p.rect(x, y, 50, 50)
18 | }
19 | console.warn(sketch.windowHeight)
20 | end main
21 |
22 |
23 | object P5Facade:
24 |
25 | /** We need this because the function `sketch` provided to `P5` has not been specified well in typescript
26 | *
27 | * @param sketch
28 | * a closure that can set optional preload(), setup(), and/or draw() properties on the given p5 instance
29 | */
30 | def apply(sketch: js.Function1[P5Config with p5InstanceExtensions, Unit]): P5 =
31 | new P5(sketch.asInstanceOf[js.Function1[Any, Any]])
32 |
33 | /** We need this because in the `p5` trait, the functions have been translated to methods, so we can't change them
34 | */
35 | @js.native
36 | trait P5Config extends js.Object:
37 | var draw: js.Function0[Unit] = js.native
38 | var preload: js.Function0[Unit] = js.native
39 | var remove: js.Function0[Unit] = js.native
40 | var setup: js.Function0[Unit] = js.native
41 | end P5Config
42 | end P5Facade
43 |
--------------------------------------------------------------------------------
/phaser/src/main/js/gems.jsn:
--------------------------------------------------------------------------------
1 | {"frames": {
2 |
3 | "diamond_0000":
4 | {
5 | "frame": {"x":2,"y":2,"w":64,"h":64},
6 | "rotated": false,
7 | "trimmed": false,
8 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
9 | "sourceSize": {"w":64,"h":64},
10 | "pivot": {"x":0.5,"y":0.5}
11 | },
12 | "diamond_0001":
13 | {
14 | "frame": {"x":2,"y":68,"w":64,"h":64},
15 | "rotated": false,
16 | "trimmed": false,
17 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
18 | "sourceSize": {"w":64,"h":64},
19 | "pivot": {"x":0.5,"y":0.5}
20 | },
21 | "diamond_0002":
22 | {
23 | "frame": {"x":2,"y":134,"w":64,"h":64},
24 | "rotated": false,
25 | "trimmed": false,
26 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
27 | "sourceSize": {"w":64,"h":64},
28 | "pivot": {"x":0.5,"y":0.5}
29 | },
30 | "diamond_0003":
31 | {
32 | "frame": {"x":68,"y":2,"w":64,"h":64},
33 | "rotated": false,
34 | "trimmed": false,
35 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
36 | "sourceSize": {"w":64,"h":64},
37 | "pivot": {"x":0.5,"y":0.5}
38 | },
39 | "diamond_0004":
40 | {
41 | "frame": {"x":68,"y":68,"w":64,"h":64},
42 | "rotated": false,
43 | "trimmed": false,
44 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
45 | "sourceSize": {"w":64,"h":64},
46 | "pivot": {"x":0.5,"y":0.5}
47 | },
48 | "diamond_0005":
49 | {
50 | "frame": {"x":68,"y":134,"w":64,"h":64},
51 | "rotated": false,
52 | "trimmed": false,
53 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
54 | "sourceSize": {"w":64,"h":64},
55 | "pivot": {"x":0.5,"y":0.5}
56 | },
57 | "diamond_0006":
58 | {
59 | "frame": {"x":134,"y":2,"w":64,"h":64},
60 | "rotated": false,
61 | "trimmed": false,
62 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
63 | "sourceSize": {"w":64,"h":64},
64 | "pivot": {"x":0.5,"y":0.5}
65 | },
66 | "diamond_0007":
67 | {
68 | "frame": {"x":134,"y":68,"w":64,"h":64},
69 | "rotated": false,
70 | "trimmed": false,
71 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
72 | "sourceSize": {"w":64,"h":64},
73 | "pivot": {"x":0.5,"y":0.5}
74 | },
75 | "diamond_0008":
76 | {
77 | "frame": {"x":134,"y":134,"w":64,"h":64},
78 | "rotated": false,
79 | "trimmed": false,
80 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
81 | "sourceSize": {"w":64,"h":64},
82 | "pivot": {"x":0.5,"y":0.5}
83 | },
84 | "diamond_0009":
85 | {
86 | "frame": {"x":200,"y":2,"w":64,"h":64},
87 | "rotated": false,
88 | "trimmed": false,
89 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
90 | "sourceSize": {"w":64,"h":64},
91 | "pivot": {"x":0.5,"y":0.5}
92 | },
93 | "diamond_0010":
94 | {
95 | "frame": {"x":200,"y":68,"w":64,"h":64},
96 | "rotated": false,
97 | "trimmed": false,
98 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
99 | "sourceSize": {"w":64,"h":64},
100 | "pivot": {"x":0.5,"y":0.5}
101 | },
102 | "diamond_0011":
103 | {
104 | "frame": {"x":200,"y":134,"w":64,"h":64},
105 | "rotated": false,
106 | "trimmed": false,
107 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
108 | "sourceSize": {"w":64,"h":64},
109 | "pivot": {"x":0.5,"y":0.5}
110 | },
111 | "diamond_0012":
112 | {
113 | "frame": {"x":266,"y":2,"w":64,"h":64},
114 | "rotated": false,
115 | "trimmed": false,
116 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
117 | "sourceSize": {"w":64,"h":64},
118 | "pivot": {"x":0.5,"y":0.5}
119 | },
120 | "diamond_0013":
121 | {
122 | "frame": {"x":266,"y":68,"w":64,"h":64},
123 | "rotated": false,
124 | "trimmed": false,
125 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
126 | "sourceSize": {"w":64,"h":64},
127 | "pivot": {"x":0.5,"y":0.5}
128 | },
129 | "diamond_0014":
130 | {
131 | "frame": {"x":266,"y":134,"w":64,"h":64},
132 | "rotated": false,
133 | "trimmed": false,
134 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
135 | "sourceSize": {"w":64,"h":64},
136 | "pivot": {"x":0.5,"y":0.5}
137 | },
138 | "diamond_0015":
139 | {
140 | "frame": {"x":332,"y":2,"w":64,"h":64},
141 | "rotated": false,
142 | "trimmed": false,
143 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
144 | "sourceSize": {"w":64,"h":64},
145 | "pivot": {"x":0.5,"y":0.5}
146 | },
147 | "prism_0000":
148 | {
149 | "frame": {"x":332,"y":68,"w":64,"h":64},
150 | "rotated": false,
151 | "trimmed": false,
152 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
153 | "sourceSize": {"w":64,"h":64},
154 | "pivot": {"x":0.5,"y":0.5}
155 | },
156 | "prism_0001":
157 | {
158 | "frame": {"x":332,"y":134,"w":64,"h":64},
159 | "rotated": false,
160 | "trimmed": false,
161 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
162 | "sourceSize": {"w":64,"h":64},
163 | "pivot": {"x":0.5,"y":0.5}
164 | },
165 | "prism_0002":
166 | {
167 | "frame": {"x":398,"y":2,"w":64,"h":64},
168 | "rotated": false,
169 | "trimmed": false,
170 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
171 | "sourceSize": {"w":64,"h":64},
172 | "pivot": {"x":0.5,"y":0.5}
173 | },
174 | "prism_0003":
175 | {
176 | "frame": {"x":398,"y":68,"w":64,"h":64},
177 | "rotated": false,
178 | "trimmed": false,
179 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
180 | "sourceSize": {"w":64,"h":64},
181 | "pivot": {"x":0.5,"y":0.5}
182 | },
183 | "prism_0004":
184 | {
185 | "frame": {"x":398,"y":134,"w":64,"h":64},
186 | "rotated": false,
187 | "trimmed": false,
188 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
189 | "sourceSize": {"w":64,"h":64},
190 | "pivot": {"x":0.5,"y":0.5}
191 | },
192 | "prism_0005":
193 | {
194 | "frame": {"x":464,"y":2,"w":64,"h":64},
195 | "rotated": false,
196 | "trimmed": false,
197 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
198 | "sourceSize": {"w":64,"h":64},
199 | "pivot": {"x":0.5,"y":0.5}
200 | },
201 | "prism_0006":
202 | {
203 | "frame": {"x":464,"y":68,"w":64,"h":64},
204 | "rotated": false,
205 | "trimmed": false,
206 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
207 | "sourceSize": {"w":64,"h":64},
208 | "pivot": {"x":0.5,"y":0.5}
209 | },
210 | "ruby_0000":
211 | {
212 | "frame": {"x":464,"y":134,"w":64,"h":64},
213 | "rotated": false,
214 | "trimmed": false,
215 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
216 | "sourceSize": {"w":64,"h":64},
217 | "pivot": {"x":0.5,"y":0.5}
218 | },
219 | "ruby_0001":
220 | {
221 | "frame": {"x":530,"y":2,"w":64,"h":64},
222 | "rotated": false,
223 | "trimmed": false,
224 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
225 | "sourceSize": {"w":64,"h":64},
226 | "pivot": {"x":0.5,"y":0.5}
227 | },
228 | "ruby_0002":
229 | {
230 | "frame": {"x":530,"y":68,"w":64,"h":64},
231 | "rotated": false,
232 | "trimmed": false,
233 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
234 | "sourceSize": {"w":64,"h":64},
235 | "pivot": {"x":0.5,"y":0.5}
236 | },
237 | "ruby_0003":
238 | {
239 | "frame": {"x":530,"y":134,"w":64,"h":64},
240 | "rotated": false,
241 | "trimmed": false,
242 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
243 | "sourceSize": {"w":64,"h":64},
244 | "pivot": {"x":0.5,"y":0.5}
245 | },
246 | "ruby_0004":
247 | {
248 | "frame": {"x":596,"y":2,"w":64,"h":64},
249 | "rotated": false,
250 | "trimmed": false,
251 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
252 | "sourceSize": {"w":64,"h":64},
253 | "pivot": {"x":0.5,"y":0.5}
254 | },
255 | "ruby_0005":
256 | {
257 | "frame": {"x":596,"y":68,"w":64,"h":64},
258 | "rotated": false,
259 | "trimmed": false,
260 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
261 | "sourceSize": {"w":64,"h":64},
262 | "pivot": {"x":0.5,"y":0.5}
263 | },
264 | "ruby_0006":
265 | {
266 | "frame": {"x":596,"y":134,"w":64,"h":64},
267 | "rotated": false,
268 | "trimmed": false,
269 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
270 | "sourceSize": {"w":64,"h":64},
271 | "pivot": {"x":0.5,"y":0.5}
272 | },
273 | "square_0000":
274 | {
275 | "frame": {"x":662,"y":2,"w":64,"h":64},
276 | "rotated": false,
277 | "trimmed": false,
278 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
279 | "sourceSize": {"w":64,"h":64},
280 | "pivot": {"x":0.5,"y":0.5}
281 | },
282 | "square_0001":
283 | {
284 | "frame": {"x":662,"y":68,"w":64,"h":64},
285 | "rotated": false,
286 | "trimmed": false,
287 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
288 | "sourceSize": {"w":64,"h":64},
289 | "pivot": {"x":0.5,"y":0.5}
290 | },
291 | "square_0002":
292 | {
293 | "frame": {"x":662,"y":134,"w":64,"h":64},
294 | "rotated": false,
295 | "trimmed": false,
296 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
297 | "sourceSize": {"w":64,"h":64},
298 | "pivot": {"x":0.5,"y":0.5}
299 | },
300 | "square_0003":
301 | {
302 | "frame": {"x":728,"y":2,"w":64,"h":64},
303 | "rotated": false,
304 | "trimmed": false,
305 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
306 | "sourceSize": {"w":64,"h":64},
307 | "pivot": {"x":0.5,"y":0.5}
308 | },
309 | "square_0004":
310 | {
311 | "frame": {"x":728,"y":68,"w":64,"h":64},
312 | "rotated": false,
313 | "trimmed": false,
314 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
315 | "sourceSize": {"w":64,"h":64},
316 | "pivot": {"x":0.5,"y":0.5}
317 | },
318 | "square_0005":
319 | {
320 | "frame": {"x":728,"y":134,"w":64,"h":64},
321 | "rotated": false,
322 | "trimmed": false,
323 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
324 | "sourceSize": {"w":64,"h":64},
325 | "pivot": {"x":0.5,"y":0.5}
326 | },
327 | "square_0006":
328 | {
329 | "frame": {"x":794,"y":2,"w":64,"h":64},
330 | "rotated": false,
331 | "trimmed": false,
332 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
333 | "sourceSize": {"w":64,"h":64},
334 | "pivot": {"x":0.5,"y":0.5}
335 | },
336 | "square_0007":
337 | {
338 | "frame": {"x":860,"y":2,"w":64,"h":64},
339 | "rotated": false,
340 | "trimmed": false,
341 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
342 | "sourceSize": {"w":64,"h":64},
343 | "pivot": {"x":0.5,"y":0.5}
344 | },
345 | "square_0008":
346 | {
347 | "frame": {"x":926,"y":2,"w":64,"h":64},
348 | "rotated": false,
349 | "trimmed": false,
350 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
351 | "sourceSize": {"w":64,"h":64},
352 | "pivot": {"x":0.5,"y":0.5}
353 | },
354 | "square_0009":
355 | {
356 | "frame": {"x":794,"y":68,"w":64,"h":64},
357 | "rotated": false,
358 | "trimmed": false,
359 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
360 | "sourceSize": {"w":64,"h":64},
361 | "pivot": {"x":0.5,"y":0.5}
362 | },
363 | "square_0010":
364 | {
365 | "frame": {"x":794,"y":134,"w":64,"h":64},
366 | "rotated": false,
367 | "trimmed": false,
368 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
369 | "sourceSize": {"w":64,"h":64},
370 | "pivot": {"x":0.5,"y":0.5}
371 | },
372 | "square_0011":
373 | {
374 | "frame": {"x":860,"y":68,"w":64,"h":64},
375 | "rotated": false,
376 | "trimmed": false,
377 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
378 | "sourceSize": {"w":64,"h":64},
379 | "pivot": {"x":0.5,"y":0.5}
380 | },
381 | "square_0012":
382 | {
383 | "frame": {"x":926,"y":68,"w":64,"h":64},
384 | "rotated": false,
385 | "trimmed": false,
386 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
387 | "sourceSize": {"w":64,"h":64},
388 | "pivot": {"x":0.5,"y":0.5}
389 | },
390 | "square_0013":
391 | {
392 | "frame": {"x":860,"y":134,"w":64,"h":64},
393 | "rotated": false,
394 | "trimmed": false,
395 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
396 | "sourceSize": {"w":64,"h":64},
397 | "pivot": {"x":0.5,"y":0.5}
398 | },
399 | "square_0014":
400 | {
401 | "frame": {"x":926,"y":134,"w":64,"h":64},
402 | "rotated": false,
403 | "trimmed": false,
404 | "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
405 | "sourceSize": {"w":64,"h":64},
406 | "pivot": {"x":0.5,"y":0.5}
407 | }},
408 | "meta": {
409 | "app": "http://www.codeandweb.com/texturepacker",
410 | "version": "1.0",
411 | "image": "gems.png",
412 | "format": "RGBA8888",
413 | "size": {"w":992,"h":200},
414 | "scale": "1",
415 | "smartupdate": "$TexturePacker:SmartUpdate:5dfda9c839d3ca51c00faf9458ba1fca:0b0be3727c36efcd76ae8acf6abbf211:81fc68276d1596f8f7ad75d59a9ce9b5$"
416 | }
417 | }
418 |
--------------------------------------------------------------------------------
/phaser/src/main/js/gems.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/phaser/src/main/js/gems.png
--------------------------------------------------------------------------------
/phaser/src/main/js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | phaser demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/phaser/src/main/scala/demo.scala:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import org.scalablytyped.runtime.{StringDictionary, TopLevel}
4 | import typings.phaser.Phaser.Types.Animations.{Animation, GenerateFrameNames}
5 | import typings.phaser.Phaser.Types.Core.GameConfig
6 | import typings.phaser.Phaser.Types.GameObjects.GameObjectConfig
7 | import typings.phaser.Phaser.Types.GameObjects.Sprite.SpriteConfig
8 | import typings.phaser.Phaser.Types.Scenes.CreateSceneFromObjectConfig
9 | import typings.phaser.mod.{Game, Scene}
10 | import typings.phaser.mod as Phaser
11 |
12 | import scala.scalajs.js
13 | import scala.scalajs.js.annotation.JSImport
14 | import scala.util.Random
15 |
16 | @JSImport("./gems.png", JSImport.Default)
17 | @js.native
18 | val GemsPng: String = js.native
19 |
20 | /* file renamed from .json because of https://github.com/webpack/webpack/issues/6586 */
21 | @JSImport("./gems.jsn", JSImport.Default)
22 | @js.native
23 | val GemsJson: String = js.native
24 |
25 | val preload: js.ThisFunction0[Scene, Unit] =
26 | _.load.atlas("gems", GemsPng, GemsJson, js.undefined, js.undefined)
27 |
28 | val create: js.ThisFunction1[Scene, js.Object, Unit] = (scene, data) =>
29 | // Define the animations first
30 | scene.anims.create(
31 | Animation()
32 | .setKey("ruby")
33 | .setFrames(
34 | scene.anims.generateFrameNames("gems", GenerateFrameNames().setPrefix("ruby_").setEnd(6).setZeroPad(4))
35 | )
36 | .setRepeat(-1)
37 | );
38 |
39 | scene.anims.create(
40 | Animation()
41 | .setKey("square")
42 | .setFrames(
43 | scene.anims.generateFrameNames("gems", GenerateFrameNames().setPrefix("square_").setEnd(14).setZeroPad(4))
44 | )
45 | .setRepeat(-1)
46 | )
47 |
48 | // Make 16 sprites using the config above
49 | 0 to 16 foreach { _ =>
50 | // The Sprite config
51 | val config = SpriteConfig()
52 | .setKey("gems")
53 | .setX(Random.nextInt(800))
54 | .setY(Random.nextInt(300))
55 | .setScale(Random.between(0.5, 1.5))
56 | /* add a member describing the annotation which is completely unchecked in typescript */
57 | .set("anims", "ruby")
58 | scene.make.sprite(config)
59 | }
60 |
61 | // Make 16 sprites using the config above
62 | 0 to 16 foreach { _ =>
63 | // A more complex animation config object.
64 | // This time with a call to delayedPlay that's a function.
65 | val config = SpriteConfig()
66 | .setKey("gems")
67 | .setX(Random.nextInt(800))
68 | .setY(Random.nextInt(300) + 300)
69 | .setScale(Random.between(0.5, 1.5))
70 | .set(
71 | "anims",
72 | StringDictionary[js.Any](
73 | "key" -> "square",
74 | "repeat" -> -1,
75 | "repeatDelay" -> (1 + Random.nextInt(3)),
76 | "delayedPlay" -> (() => Math.random() * 6)
77 | )
78 | )
79 | scene.make.sprite(config);
80 | }
81 |
82 | val config = GameConfig()
83 | .setType(Phaser.AUTO: Double)
84 | .setParent("phaser-example")
85 | .setWidth(800)
86 | .setHeight(600)
87 | .setScene(createScene(preload = preload, create = create))
88 |
89 | @main
90 | def main: Unit =
91 | new Game(config)
92 |
93 | /* note that we could probably have refactored this whole thing to use classes to not avoid this.
94 | * To keep in line with the example I changed CreateSceneFromObjectConfig to take `ThisFunction`s.
95 | *
96 | * The only reason it's not already there is that it's not specified in typescript,
97 | * leaving it completely unchecked.
98 | *
99 | * Unfortunately `js.ThisFunctionN` is not a subtype of the corresponding `js.FunctionN`
100 | */
101 | @scala.inline
102 | def createScene(
103 | create: /* data */ js.ThisFunction1[Scene, js.Object, Unit] = null,
104 | extend: js.Any = null,
105 | extendDotdata: js.Any = null,
106 | init: /* data */ js.ThisFunction1[Scene, js.Object, Unit] = null,
107 | preload: js.ThisFunction0[Scene, Unit] = null,
108 | update: js.ThisFunction0[Scene, Unit] = null
109 | ): CreateSceneFromObjectConfig =
110 | val __obj = js.Dynamic.literal()
111 | if create != null then __obj.updateDynamic("create")(create)
112 | if extend != null then __obj.updateDynamic("extend")(extend.asInstanceOf[js.Any])
113 | if extendDotdata != null then __obj.updateDynamic("extend.data")(extendDotdata.asInstanceOf[js.Any])
114 | if init != null then __obj.updateDynamic("init")(init)
115 | if preload != null then __obj.updateDynamic("preload")(preload)
116 | if update != null then __obj.updateDynamic("update")(update.asInstanceOf[js.Any])
117 | __obj.asInstanceOf[CreateSceneFromObjectConfig]
118 | end createScene
119 |
--------------------------------------------------------------------------------
/pixi/src/main/js/a11y-light.css:
--------------------------------------------------------------------------------
1 | /* a11y-light theme */
2 | /* Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/master/src/styles/tomorrow-night-eighties.css */
3 | /* @author: ericwbailey */
4 |
5 | /* Comment */
6 | .hljs-comment,
7 | .hljs-quote {
8 | color: #696969;
9 | }
10 |
11 | /* Red */
12 | .hljs-variable,
13 | .hljs-template-variable,
14 | .hljs-tag,
15 | .hljs-name,
16 | .hljs-selector-id,
17 | .hljs-selector-class,
18 | .hljs-regexp,
19 | .hljs-deletion {
20 | color: #d91e18;
21 | }
22 |
23 | /* Orange */
24 | .hljs-number,
25 | .hljs-built_in,
26 | .hljs-builtin-name,
27 | .hljs-literal,
28 | .hljs-type,
29 | .hljs-params,
30 | .hljs-meta,
31 | .hljs-link {
32 | color: #aa5d00;
33 | }
34 |
35 | /* Yellow */
36 | .hljs-attribute {
37 | color: #aa5d00;
38 | }
39 |
40 | /* Green */
41 | .hljs-string,
42 | .hljs-symbol,
43 | .hljs-bullet,
44 | .hljs-addition {
45 | color: #008000;
46 | }
47 |
48 | /* Blue */
49 | .hljs-title,
50 | .hljs-section {
51 | color: #007faa;
52 | }
53 |
54 | /* Purple */
55 | .hljs-keyword,
56 | .hljs-selector-tag {
57 | color: #7928a1;
58 | }
59 |
60 | .hljs {
61 | display: block;
62 | overflow-x: auto;
63 | background: #fefefe;
64 | color: #545454;
65 | padding: 0.5em;
66 | }
67 |
68 | .hljs-emphasis {
69 | font-style: italic;
70 | }
71 |
72 | .hljs-strong {
73 | font-weight: bold;
74 | }
75 |
76 | @media screen and (-ms-high-contrast: active) {
77 | .hljs-addition,
78 | .hljs-attribute,
79 | .hljs-built_in,
80 | .hljs-builtin-name,
81 | .hljs-bullet,
82 | .hljs-comment,
83 | .hljs-link,
84 | .hljs-literal,
85 | .hljs-meta,
86 | .hljs-number,
87 | .hljs-params,
88 | .hljs-string,
89 | .hljs-symbol,
90 | .hljs-type,
91 | .hljs-quote {
92 | color: highlight;
93 | }
94 |
95 | .hljs-keyword,
96 | .hljs-selector-tag {
97 | font-weight: bold;
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/pixi/src/main/js/assets/bg_grass.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/pixi/src/main/js/assets/bg_grass.jpg
--------------------------------------------------------------------------------
/pixi/src/main/js/assets/bg_scene_rotate.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/pixi/src/main/js/assets/bg_scene_rotate.jpg
--------------------------------------------------------------------------------
/pixi/src/main/js/assets/bunny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/pixi/src/main/js/assets/bunny.png
--------------------------------------------------------------------------------
/pixi/src/main/js/assets/eggHead.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/pixi/src/main/js/assets/eggHead.png
--------------------------------------------------------------------------------
/pixi/src/main/js/assets/p2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/pixi/src/main/js/assets/p2.jpeg
--------------------------------------------------------------------------------
/pixi/src/main/js/assets/pixi-filters/displacement_map_repeat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/pixi/src/main/js/assets/pixi-filters/displacement_map_repeat.jpg
--------------------------------------------------------------------------------
/pixi/src/main/js/assets/pixi-filters/flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/pixi/src/main/js/assets/pixi-filters/flag.png
--------------------------------------------------------------------------------
/pixi/src/main/js/assets/star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/pixi/src/main/js/assets/star.png
--------------------------------------------------------------------------------
/pixi/src/main/js/assets/trail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/pixi/src/main/js/assets/trail.png
--------------------------------------------------------------------------------
/pixi/src/main/js/assets/video.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/pixi/src/main/js/assets/video.mp4
--------------------------------------------------------------------------------
/pixi/src/main/js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pixi.js with Scala.js
7 |
8 |
9 |
12 |
13 |
14 |
Pixi.js with Scala.js!
15 |
16 |
17 | Click in the menu on the left to see the examples from the official website translated into
18 | Scala, using Scala.js and ScalablyTyped.
19 |
20 |
21 | This project uses version 5 of Pixi.
22 |
23 |
24 |
25 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/pixi/src/main/js/styles.css:
--------------------------------------------------------------------------------
1 | #menu {
2 | position: fixed;
3 | height: 100%;
4 | top: 0px;
5 | left: 0px;
6 | background-color: #000099;
7 | color: white;
8 | width: 200px;
9 | padding: 10px;
10 | overflow-y: auto;
11 | }
12 |
13 | .menu-section {
14 | border-bottom: 1px solid white;
15 | margin-bottom: 10px;
16 | }
17 |
18 | .section-header {
19 | font-weight: bold;
20 | font-size: 16;
21 | }
22 |
23 | .example-option {
24 | padding: 5px;
25 | cursor: pointer;
26 | }
27 |
28 | pre code {
29 | border: 1px solid black;
30 | }
31 |
32 | #code-container {
33 | width: 800px;
34 | }
35 |
36 | #overall-container {
37 | margin-left: 250px;
38 | display: none
39 | }
40 |
41 | #welcome-message {
42 | margin-left: 250px;
43 | }
44 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/assets.scala:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import org.scalablytyped.runtime.TopLevel
4 |
5 | import scala.scalajs.js
6 | import scala.scalajs.js.annotation.JSImport
7 |
8 | object assets:
9 | object pixiFilters:
10 | @js.native
11 | @JSImport("./assets/pixi-filters/displacement_map_repeat.jpg", JSImport.Default)
12 | object DisplacementMapRepeat extends TopLevel[String]
13 |
14 | @js.native
15 | @JSImport("./assets/pixi-filters/flag.png", JSImport.Default)
16 | object FlagImage extends TopLevel[String]
17 |
18 | @js.native
19 | @JSImport("./assets/bg_grass.jpg", JSImport.Default)
20 | object BackgroundGrass extends TopLevel[String]
21 |
22 | @js.native
23 | @JSImport("./assets/bg_scene_rotate.jpg", JSImport.Default)
24 | object BackgroundSceneRotate extends TopLevel[String]
25 |
26 | @js.native
27 | @JSImport("./assets/bunny.png", JSImport.Default)
28 | object BunnyImage extends TopLevel[String]
29 |
30 | @js.native
31 | @JSImport("./assets/eggHead.png", JSImport.Default)
32 | object EggHeadImage extends TopLevel[String]
33 |
34 | @js.native
35 | @JSImport("./assets/p2.jpeg", JSImport.Default)
36 | object P2Image extends TopLevel[String]
37 |
38 | @js.native
39 | @JSImport("./assets/star.png", JSImport.Default)
40 | object StarImage extends TopLevel[String]
41 |
42 | @js.native
43 | @JSImport("./assets/video.mp4", JSImport.Default)
44 | object TheVideo extends TopLevel[String]
45 |
46 | @js.native
47 | @JSImport("./assets/trail.png", JSImport.Default)
48 | object TrailImage extends TopLevel[String]
49 | end assets
50 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/demosadvanced/MouseTrail.scala:
--------------------------------------------------------------------------------
1 | package demo.demosadvanced
2 |
3 | import demo.assets.TrailImage
4 | import demo.pixi.PIXIExample
5 | import typings.pixiJs.mod.interaction.InteractionManager
6 | import typings.pixiJs.mod.{Application, BLEND_MODES, Point, SimpleRope, Texture}
7 | import demo.monkeypatching.PIXIPatching.*
8 | import typings.pixiJs.anon.Antialias as ApplicationOptions
9 |
10 | import scala.collection.mutable
11 | import scala.scalajs.js
12 | import scala.scalajs.js.JSConverters.*
13 |
14 | case object MouseTrail extends PIXIExample:
15 |
16 | val name: String = "Mouse trail"
17 |
18 | val pixiUrl: String =
19 | "https://pixijs.io/examples/#/demos-advanced/mouse-trail.js"
20 |
21 | def newApplication(): Application =
22 | val app = new Application(ApplicationOptions().setBackgroundColor(0x1099bb))
23 |
24 | //Get the texture for rope.
25 | val trailTexture = Texture.from(TrailImage)
26 | val historyX = mutable.Queue[Double]()
27 | val historyY = mutable.Queue[Double]()
28 | //historySize determines how long the trail will be.
29 | val historySize = 20
30 | //ropeSize determines how smooth the trail will be.
31 | val ropeSize = 100
32 |
33 | //Create history array.
34 | for _ <- 0 until historySize do
35 | historyX += 0
36 | historyY += 0
37 |
38 | //Create rope points.
39 | val points: Vector[typings.pixiJs.PIXI.Point] =
40 | (for (_ <- 0 until ropeSize) yield new Point(0, 0)).toVector // sadly js.Array is invariant
41 |
42 | //Create the rope
43 | val rope = new SimpleRope(trailTexture, points.toJSArray)
44 |
45 | //Set the blendmode
46 | rope.blendMode = BLEND_MODES.ADD
47 |
48 | app.stage.addChild(rope)
49 |
50 | def ticker(): Unit =
51 | // Read mouse points, this could be done also in mousemove/touchmove update.
52 | // For simplicity it is done here for now.
53 | // When implementing this properly, make sure to implement touchmove as interaction plugins mouse might not update
54 | // on certain devices.
55 | val mousePosition =
56 | app.renderer.plugins
57 | .asInstanceOf[js.Dynamic]
58 | .interaction
59 | .asInstanceOf[InteractionManager]
60 | .mouse
61 | .global
62 |
63 | //Update the mouse values to history
64 | historyX.dequeue()
65 | historyX += mousePosition.x
66 | historyY.dequeue()
67 | historyY += mousePosition.y
68 | //Update the points to correspond with history.
69 | for i <- 0 until ropeSize do
70 | val p = points(i)
71 |
72 | //Smooth the curve with cubic interpolation to prevent sharp edges.
73 | val ix =
74 | cubicInterpolation(
75 | historyX.toList,
76 | i.toDouble / ropeSize * historySize
77 | )
78 | val iy =
79 | cubicInterpolation(
80 | historyY.toList,
81 | i.toDouble / ropeSize * historySize
82 | )
83 |
84 | p.x = ix
85 | p.y = iy
86 | end for
87 | end ticker
88 |
89 | // Listen for animate update
90 | app.ticker.add(() => ticker())
91 |
92 | /** Cubic interpolation based on https://github.com/osuushi/Smooth.js
93 | */
94 | def clipInput[T](k: Int, arr: Seq[T]): T =
95 | arr(math.max(0, math.min(arr.size - 1, k)))
96 |
97 | def getTangent(k: Int, factor: Double, array: Seq[Double]): Double =
98 | factor * (clipInput(k + 1, array) - clipInput(k - 1, array)) / 2
99 |
100 | def cubicInterpolation(array: Seq[Double], t: Double, tangentFactor: Double = 1): Double =
101 |
102 | val k = Math.floor(t).toInt
103 | val m = Seq(
104 | getTangent(k, tangentFactor, array),
105 | getTangent(k + 1, tangentFactor, array)
106 | )
107 | val p = Seq(clipInput(k, array), clipInput(k + 1, array))
108 | val u = t - k
109 | val t2 = u * u
110 | val t3 = u * t2
111 | (2 * t3 - 3 * t2 + 1) * p.head + (t3 - 2 * t2 + u) * m.head + (-2 * t3 + 3 * t2) * p(
112 | 1
113 | ) + (t3 - t2) * m(1)
114 | end cubicInterpolation
115 |
116 | app
117 | end newApplication
118 | end MouseTrail
119 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/demosadvanced/StarWarp.scala:
--------------------------------------------------------------------------------
1 | package demo.demosadvanced
2 |
3 | import demo.assets.StarImage
4 | import demo.pixi.PIXIExample
5 | import typings.pixiJs.anon.Antialias as ApplicationOptions
6 | import typings.pixiJs.mod.{Application, Sprite, Texture}
7 | import demo.monkeypatching.PIXIPatching.*
8 |
9 | import scala.scalajs.js.timers.setInterval
10 |
11 | case object StarWarp extends PIXIExample:
12 |
13 | val name: String = "Star warp"
14 |
15 | val pixiUrl: String =
16 | "https://pixijs.io/examples/#/demos-advanced/star-warp.js"
17 |
18 | def newApplication(): Application =
19 | val app = new Application(ApplicationOptions().setBackgroundColor(0))
20 |
21 | //Get the texture for rope.
22 | val starTexture = Texture.from(StarImage)
23 |
24 | val starAmount = 1000
25 | var cameraZ = 0.0
26 | val fov = 20.0
27 | val baseSpeed = 0.025
28 | var speed = 0.0
29 | var warpSpeed = 0.0
30 | val starStretch = 5.0
31 | val starBaseSize = 0.05
32 |
33 | final class Star:
34 | val sprite: Sprite = new Sprite(starTexture)
35 | var z: Double = 0
36 | var x: Double = 0
37 | var y: Double = 0
38 |
39 | def randomizeStar(star: Star, initial: Boolean): Unit =
40 | star.z =
41 | if initial then Math.random() * 2000
42 | else cameraZ + Math.random() * 1000 + 2000
43 |
44 | //Calculate star positions with radial random coordinate so no star hits the camera.
45 | val deg = Math.random() * Math.PI * 2
46 | val distance = Math.random() * 50 + 1
47 | star.x = Math.cos(deg) * distance
48 | star.y = Math.sin(deg) * distance
49 | end randomizeStar
50 |
51 | //Create the stars
52 | val stars = for (_ <- 0 until starAmount) yield
53 | val star = new Star
54 | star.sprite.anchor.x = 0.5
55 | star.sprite.anchor.y = 0.7
56 | randomizeStar(star, initial = true)
57 | app.stage.addChild(star.sprite)
58 | star
59 |
60 | //Change flight speed every 5 seconds
61 | setInterval(5000) {
62 | warpSpeed = 1 - warpSpeed
63 | }
64 |
65 | def ticker(delta: Double): Unit =
66 | //Simple easing. This should be changed to proper easing function when used for real.
67 | speed += (warpSpeed - speed) / 20
68 | cameraZ += delta * 10 * (speed + baseSpeed)
69 | for star <- stars do
70 | if star.z < cameraZ then randomizeStar(star, initial = false)
71 |
72 | //Map star 3d position to 2d with really simple projection
73 | val z = star.z - cameraZ
74 | star.sprite.x = star.x * (fov / z) * app.renderer.screen.width + app.renderer.screen.width / 2
75 | star.sprite.y = star.y * (fov / z) * app.renderer.screen.width + app.renderer.screen.height / 2
76 |
77 | //Calculate star scale & rotation.
78 | val dxCenter = star.sprite.x - app.renderer.screen.width / 2
79 | val dyCenter = star.sprite.y - app.renderer.screen.height / 2
80 | val distanceCenter =
81 | Math.sqrt(dxCenter * dxCenter + dyCenter + dyCenter)
82 | val distanceScale = Math.max(0, (2000 - z) / 2000)
83 | star.sprite.scale.x = distanceScale * starBaseSize
84 | //Star is looking towards center so that y axis is towards center.
85 | //Scale the star depending on how fast we are moving, what the stretchfactor is and depending on how far away
86 | // it is from the center.
87 | star.sprite.scale.y = distanceScale * starBaseSize +
88 | distanceScale * speed * starStretch * distanceCenter / app.renderer.screen.width
89 | star.sprite.rotation = Math.atan2(dyCenter, dxCenter) + Math.PI / 2
90 | end for
91 | end ticker
92 |
93 | // Listen for animate update
94 | app.ticker.add(ticker(_: Double))
95 |
96 | app
97 | end newApplication
98 | end StarWarp
99 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/demosbasic/Basics.scala:
--------------------------------------------------------------------------------
1 | package demo.demosbasic
2 |
3 | import demo.assets.BunnyImage
4 | import demo.pixi.PIXIExample
5 | import demo.monkeypatching.PIXIPatching.*
6 | import typings.pixiJs.anon.Antialias as ApplicationOptions
7 | import typings.pixiJs.mod.{Application, Sprite, Texture}
8 |
9 | case object Basics extends PIXIExample:
10 |
11 | val name: String = "Basics"
12 |
13 | val pixiUrl: String = "https://pixijs.io/examples/#/sprite/basic.js"
14 |
15 | def newApplication(): Application =
16 | val app = new Application(ApplicationOptions().setBackgroundColor(0x1099bb))
17 |
18 | val texture = Texture.from(BunnyImage)
19 |
20 | // create a new Sprite from an image path
21 | val bunny: Sprite = new Sprite(texture)
22 |
23 | // center the sprite's anchor point
24 | bunny.anchor.set(0.5)
25 |
26 | // move the sprite to the center of the screen
27 | bunny.x = app.screen.width / 2
28 | bunny.y = app.screen.height / 2
29 |
30 | app.stage.addChild(bunny)
31 |
32 | val ticker = (delta: Double) =>
33 | // just for fun, let's rotate mr rabbit a little
34 | // delta is 1 if running at 100% performance
35 | // creates frame-independent transformation
36 | bunny.rotation += 0.1 * delta
37 |
38 | // Listen for animate update
39 | app.ticker.add(ticker)
40 |
41 | app
42 | end newApplication
43 | end Basics
44 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/demosbasic/ContainerPivot.scala:
--------------------------------------------------------------------------------
1 | package demo.demosbasic
2 |
3 | import demo.assets.BunnyImage
4 | import demo.monkeypatching.PIXIPatching.*
5 | import demo.pixi.PIXIExample
6 | import typings.pixiJs.anon.Antialias as ApplicationOptions
7 | import typings.pixiJs.mod.{Application, Container, Sprite, Texture}
8 |
9 | case object ContainerPivot extends PIXIExample:
10 |
11 | val name: String = "Container Pivot"
12 |
13 | val pixiUrl: String = "https://pixijs.io/examples/#/demos-basic/container.js"
14 |
15 | def newApplication(): Application =
16 | val app = new Application(ApplicationOptions().setBackgroundColor(0x1099bb))
17 |
18 | val container = new Container()
19 |
20 | app.stage.addChild(container)
21 |
22 | // Create a new texture
23 | val texture = Texture.from(BunnyImage)
24 |
25 | // Create a 5x5 grid of bunnies
26 | for i <- 0 until 25 do
27 | val bunny = new Sprite(texture)
28 | bunny.anchor.set(0.5)
29 | bunny.x = (i % 5) * 40
30 | bunny.y = i / 5 * 40
31 | container.addChild(bunny)
32 |
33 | // Move container to the center
34 | container.x = app.screen.width / 2
35 | container.y = app.screen.height / 2
36 |
37 | // Center bunny sprite in local container coordinates
38 | container.pivot.x = container.width / 2
39 | container.pivot.y = container.height / 2
40 |
41 | val tickerF = (delta: Double) =>
42 | // rotate the container!
43 | // use delta to create frame-independent transform
44 | container.rotation -= 0.01 * delta
45 |
46 | // Listen for animate update
47 | app.ticker.add(tickerF)
48 |
49 | app
50 | end newApplication
51 | end ContainerPivot
52 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/demosbasic/Containers.scala:
--------------------------------------------------------------------------------
1 | package demo.demosbasic
2 |
3 | import demo.assets.BunnyImage
4 | import demo.pixi.PIXIExample
5 | import typings.pixiJs.anon.Antialias as ApplicationOptions
6 | import typings.pixiJs.mod.{Application, Container, Sprite, Texture}
7 |
8 | case object Containers extends PIXIExample:
9 |
10 | val name: String = "Container"
11 |
12 | val pixiUrl: String = "https://pixijs.io/examples/#/basics/container.js"
13 |
14 | def newApplication(): Application =
15 |
16 | val app = new Application(ApplicationOptions().setBackgroundColor(0x1099bb))
17 |
18 | val container = new Container()
19 |
20 | app.stage.addChild(container)
21 |
22 | val texture = Texture.from(BunnyImage)
23 |
24 | // Create a 5x5 grid of bunnies
25 | for i <- 0 until 25 do
26 | val bunny = new Sprite(texture)
27 | bunny.anchor.set(0.5)
28 | bunny.x = (i % 5) * 40
29 | bunny.y = i / 5 * 40
30 | container.addChild(bunny)
31 |
32 | // Center on the screen
33 | container.x = (app.screen.width - container.width) / 2
34 | container.y = (app.screen.height - container.height) / 2
35 |
36 | app
37 | end newApplication
38 | end Containers
39 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/demosbasic/Tinting.scala:
--------------------------------------------------------------------------------
1 | package demo.demosbasic
2 |
3 | import demo.assets.EggHeadImage
4 | import demo.pixi.PIXIExample
5 | import typings.pixiJs.mod.{Application, Rectangle, Sprite, Texture}
6 |
7 | import demo.monkeypatching.PIXIPatching.*
8 |
9 | case object Tinting extends PIXIExample:
10 |
11 | val name: String = "Tinting"
12 |
13 | val pixiUrl: String = "https://pixijs.io/examples/#/demos-basic/tinting.js"
14 |
15 | def newApplication(): Application =
16 | val app = new Application()
17 |
18 | val totalDudes = 20
19 |
20 | final class Dude:
21 |
22 | // create a new Sprite that uses the image name that we just generated as its source
23 | val dude: Sprite = new Sprite(Texture.from(EggHeadImage))
24 |
25 | // set the anchor point so the texture is centerd on the sprite
26 | dude.anchor.set(0.5)
27 |
28 | // set a random scale for the dude - no point them all being the same size!
29 | dude.scale.set(0.8 + Math.random() * 0.3)
30 |
31 | // finally lets set the dude to be at a random position..
32 | dude.x = Math.random() * app.screen.width
33 | dude.y = Math.random() * app.screen.height
34 |
35 | dude.tint = Math.random() * 0xffffff
36 |
37 | // create some extra properties that will control movement :
38 | // create a random direction in radians. This is a number between 0 and PI*2 which is the equivalent of 0 - 360 degrees
39 | var direction: Double = Math.random() * Math.PI * 2
40 |
41 | // this number will be used to modify the direction of the dude over time
42 | var turningSpeed: Double = Math.random() - 0.8
43 |
44 | // create a random speed for the dude between 0 - 2
45 | var speed: Double = 2 + Math.random() * 2
46 |
47 | app.stage.addChild(dude)
48 | end Dude
49 |
50 | val aliens = (0 until totalDudes).map(_ => new Dude)
51 |
52 | // create a bounding box for the little dudes
53 | val dudeBoundsPadding = 100
54 | val dudeBounds = new Rectangle(
55 | -dudeBoundsPadding,
56 | -dudeBoundsPadding,
57 | app.screen.width + dudeBoundsPadding * 2,
58 | app.screen.height + dudeBoundsPadding * 2
59 | )
60 |
61 | app.ticker.add { (_: Double) =>
62 | // iterate through the dudes and update their position
63 | for dude <- aliens do
64 |
65 | dude.direction += dude.turningSpeed * 0.01
66 | dude.dude.x += Math.sin(dude.direction) * dude.speed
67 | dude.dude.y += Math.cos(dude.direction) * dude.speed
68 | dude.dude.rotation = -dude.direction - Math.PI / 2
69 |
70 | // wrap the dudes by testing their bounds...
71 | if dude.dude.x < dudeBounds.x then dude.dude.x += dudeBounds.width
72 | else if dude.dude.x > dudeBounds.x + dudeBounds.width then dude.dude.x -= dudeBounds.width
73 |
74 | if dude.dude.y < dudeBounds.y then dude.dude.y += dudeBounds.height
75 | else if dude.dude.y > dudeBounds.y + dudeBounds.height then dude.dude.y -= dudeBounds.height
76 |
77 | }
78 |
79 | app
80 | end newApplication
81 | end Tinting
82 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/filtersbasic/DisplacementMapFlag.scala:
--------------------------------------------------------------------------------
1 | package demo.filtersbasic
2 |
3 | import demo.assets.pixiFilters.{DisplacementMapRepeat, FlagImage}
4 | import demo.pixi.PIXIExample
5 | import typings.pixiJs.mod.{filters, Application, Container, Sprite, WRAP_MODES}
6 | import demo.monkeypatching.PIXIPatching.*
7 |
8 | import scala.scalajs.js
9 |
10 | case object DisplacementMapFlag extends PIXIExample:
11 | val name: String = "Displacement Map - Flag"
12 | val pixiUrl: String =
13 | "https://pixijs.io/examples/#/filters-basic/displacement-map-flag.js"
14 |
15 | protected def newApplication(): Application =
16 |
17 | val app = new Application()
18 |
19 | app.stage.interactive = true
20 |
21 | val container = new Container
22 | app.stage.addChild(container)
23 |
24 | val flag = Sprite.from(FlagImage)
25 | container.addChild(flag)
26 | flag.x = 100
27 | flag.y = 100
28 |
29 | val displacementSprite = Sprite.from(DisplacementMapRepeat)
30 | // Make sure the sprite is wrapping.
31 | displacementSprite.texture.baseTexture.wrapMode = WRAP_MODES.REPEAT
32 | val displacementFilter =
33 | new filters.DisplacementFilter(displacementSprite)
34 | displacementFilter.padding = 10
35 |
36 | displacementSprite.position = flag.position
37 |
38 | app.stage.addChild(displacementSprite)
39 |
40 | flag.filters = js.Array(displacementFilter)
41 |
42 | displacementFilter.scale.x = 30
43 | displacementFilter.scale.y = 60
44 |
45 | app.ticker.add { () =>
46 | // Offset the sprite position to make vFilterCoord update to larger value. Repeat wrapping makes sure there's still pixels on the coordinates.
47 | displacementSprite.x += 1
48 | // Reset x to 0 when it's over width to keep values from going to very huge numbers.
49 | if displacementSprite.x > displacementSprite.width then displacementSprite.x = 0
50 |
51 | }
52 |
53 | app
54 | end newApplication
55 | end DisplacementMapFlag
56 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/graphics/Simple.scala:
--------------------------------------------------------------------------------
1 | package demo.graphics
2 |
3 | import demo.pixi.PIXIExample
4 | import typings.pixiJs.PIXI.Point
5 | import typings.pixiJs.anon.Antialias as ApplicationOptions
6 | import typings.pixiJs.mod.{Application, Graphics}
7 |
8 | import scala.scalajs.js
9 | import scala.scalajs.js.|
10 |
11 | case object Simple extends PIXIExample:
12 |
13 | val name: String = "Simple"
14 |
15 | val pixiUrl: String = "https://pixijs.io/examples/#/graphics/simple.js"
16 |
17 | override def newApplication(): Application =
18 | val app = new Application(ApplicationOptions().setAntialias(true))
19 |
20 | val graphics = new Graphics()
21 |
22 | // Rectangle
23 | graphics.beginFill(0xde3249)
24 | graphics.drawRect(50, 50, 100, 100)
25 | graphics.endFill()
26 |
27 | // Rectangle + line style 1
28 | graphics.lineStyle(2, 0xfeeb77, 1)
29 | graphics.beginFill(0x650a5a)
30 | graphics.drawRect(200, 50, 100, 100)
31 | graphics.endFill()
32 |
33 | // Rectangle + line style 2
34 | graphics.lineStyle(10, 0xffbd01, 1)
35 | graphics.beginFill(0xc34288)
36 | graphics.drawRect(350, 50, 100, 100)
37 | graphics.endFill()
38 |
39 | // Rectangle 2
40 | graphics.lineStyle(2, 0xffffff, 1)
41 | graphics.beginFill(0xaa4f08)
42 | graphics.drawRect(530, 50, 140, 100)
43 | graphics.endFill()
44 |
45 | // Circle
46 | graphics.lineStyle(0) // draw a circle, set the lineStyle to zero so the circle doesn't have an outline
47 | graphics.beginFill(0xde3249, 1)
48 | graphics.drawCircle(100, 250, 50)
49 | graphics.endFill()
50 |
51 | // Circle + line style 1
52 | graphics.lineStyle(2, 0xfeeb77, 1)
53 | graphics.beginFill(0x650a5a, 1)
54 | graphics.drawCircle(250, 250, 50)
55 | graphics.endFill()
56 |
57 | // Circle + line style 2
58 | graphics.lineStyle(10, 0xffbd01, 1)
59 | graphics.beginFill(0xc34288, 1)
60 | graphics.drawCircle(400, 250, 50)
61 | graphics.endFill()
62 |
63 | // Ellipse + line style 2
64 | graphics.lineStyle(2, 0xffffff, 1)
65 | graphics.beginFill(0xaa4f08, 1)
66 | graphics.drawEllipse(600, 250, 80, 50)
67 | graphics.endFill()
68 |
69 | // draw a shape
70 | graphics.beginFill(0xff3300)
71 | graphics.lineStyle(4, 0xffd900, 1)
72 | graphics.moveTo(50, 350)
73 | graphics.lineTo(250, 350)
74 | graphics.lineTo(100, 400)
75 | graphics.lineTo(50, 350)
76 | graphics.closePath()
77 | graphics.endFill()
78 |
79 | // draw a rounded rectangle
80 | graphics.lineStyle(2, 0xff00ff, 1)
81 | graphics.beginFill(0x650a5a, 0.25)
82 | graphics.drawRoundedRect(50, 440, 100, 100, 16)
83 | graphics.endFill()
84 |
85 | // draw star
86 | graphics.lineStyle(2, 0xffffff)
87 | graphics.beginFill(0x35cc5a, 1)
88 | graphics.drawStar(360, 370, 5, 50, 5)
89 | graphics.endFill()
90 |
91 | // draw star 2
92 | graphics.lineStyle(2, 0xffffff)
93 | graphics.beginFill(0xffcc5a, 1)
94 | graphics.drawStar(280, 510, 7, 50, 5)
95 | graphics.endFill()
96 |
97 | // draw star 3
98 | graphics.lineStyle(4, 0xffffff)
99 | graphics.beginFill(0x55335a, 1)
100 | graphics.drawStar(470, 450, 4, 50, 5)
101 | graphics.endFill()
102 |
103 | // draw polygon
104 | val path: js.Array[Double | Point] =
105 | js.Array(600, 370, 700, 460, 780, 420, 730, 570, 590, 520)
106 |
107 | graphics.lineStyle(0)
108 | graphics.beginFill(0x3500fa, 1)
109 | graphics.drawPolygon(path)
110 | graphics.endFill()
111 |
112 | app.stage.addChild(graphics)
113 |
114 | app
115 | end newApplication
116 | end Simple
117 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/interaction/Click.scala:
--------------------------------------------------------------------------------
1 | package demo.interaction
2 |
3 | import demo.assets.BunnyImage
4 | import demo.pixi.PIXIExample
5 | import typings.pixiJs.anon.Antialias as ApplicationOptions
6 | import typings.pixiJs.mod.*
7 |
8 | import scala.scalajs.js
9 |
10 | case object Click extends PIXIExample:
11 |
12 | val name: String = "Click"
13 |
14 | val pixiUrl: String = "https://pixijs.io/examples/#/interaction/click.js"
15 |
16 | def newApplication(): Application =
17 |
18 | val app = new Application(ApplicationOptions().setBackgroundColor(0x1099bb))
19 |
20 | // Scale mode for all textures, will retain pixelation
21 | settings.SCALE_MODE = SCALE_MODES.NEAREST
22 |
23 | val texture = Texture.from(BunnyImage)
24 | val sprite = new Sprite(texture)
25 |
26 | // Set the initial position
27 | sprite.anchor.set(0.5)
28 | sprite.x = app.screen.width / 2
29 | sprite.y = app.screen.height / 2
30 |
31 | // Opt-in to interactivity
32 | sprite.interactive = true
33 |
34 | // Shows hand cursor
35 | sprite.buttonMode = true
36 |
37 | // Pointers normalize touch and mouse
38 | sprite.on("pointerdown", (_: js.Any) => onClick())
39 |
40 | // Alternatively, use the mouse & touch events:
41 | // sprite.on('click', onClick); // mouse-only
42 | // sprite.on('tap', onClick); // touch-only
43 |
44 | app.stage.addChild(sprite)
45 |
46 | def onClick(): Unit =
47 | sprite.scale.x *= 1.25
48 | sprite.scale.y *= 1.25
49 |
50 | app
51 | end newApplication
52 | end Click
53 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/meshandshaders/Uniform.scala:
--------------------------------------------------------------------------------
1 | package demo.meshandshaders
2 |
3 | import demo.assets.BackgroundSceneRotate
4 | import demo.pixi.PIXIExample
5 | import typings.pixiJs.mod.{Application, Geometry, Mesh, Shader, Texture}
6 | import typings.pixiJs.PIXI.Buffer
7 | import demo.monkeypatching.PIXIPatching.*
8 |
9 | import scala.scalajs.js
10 | import scala.scalajs.js.|
11 |
12 | case object Uniform extends PIXIExample:
13 | val name: String = "Uniform"
14 | val pixiUrl: String = "https://pixijs.io/examples/#/mesh-and-shaders/uniforms.js"
15 |
16 | protected def newApplication(): Application =
17 |
18 | val app = new Application()
19 |
20 | val geometry = new Geometry()
21 | .addAttribute(
22 | "aVertexPosition", // the attribute name
23 | js.Array(-100.0, -100, // x, y
24 | 100, -100, // x, y
25 | 100, 100, -100, 100)
26 | .asInstanceOf[js.UndefOr[js.Array[Double] | Buffer]], // x, y
27 | 2,
28 | js.undefined,
29 | js.undefined,
30 | js.undefined,
31 | js.undefined
32 | ) // the size of the attribute
33 | .addAttribute(
34 | "aUvs", // the attribute name
35 | js.Array(0.0, 0, // u, v
36 | 1, 0, // u, v
37 | 1, 1, 0, 1)
38 | .asInstanceOf[js.UndefOr[js.Array[Double] | Buffer]], // u, v
39 | 2,
40 | js.undefined,
41 | js.undefined,
42 | js.undefined,
43 | js.undefined
44 | ) // the size of the attribute
45 | .addIndex(js.Array(0.0, 1, 2, 0, 2, 3))
46 |
47 | val vertexSrc =
48 | """
49 | |precision mediump float;
50 | |
51 | | attribute vec2 aVertexPosition;
52 | | attribute vec2 aUvs;
53 | |
54 | | uniform mat3 translationMatrix;
55 | | uniform mat3 projectionMatrix;
56 | |
57 | | varying vec2 vUvs;
58 | |
59 | | void main() {
60 | |
61 | | vUvs = aUvs;
62 | | gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
63 | |
64 | | }
65 | |""".stripMargin
66 |
67 | val fragmentSrc = """
68 | |precision mediump float;
69 | |
70 | | varying vec2 vUvs;
71 | |
72 | | uniform sampler2D uSampler2;
73 | | uniform float time;
74 | |
75 | | void main() {
76 | |
77 | | gl_FragColor = texture2D(uSampler2, vUvs + sin( (time + (vUvs.x) * 14.) ) * 0.1 );
78 | | }
79 | """.stripMargin
80 |
81 | class Uniform(val uSampler2: Texture, var time: Double) extends js.Object
82 |
83 | val uniforms = new Uniform(
84 | Texture.from(BackgroundSceneRotate).asInstanceOf[typings.pixiJs.mod.Texture],
85 | time = 0
86 | )
87 |
88 | val shader = Shader.from(vertexSrc, fragmentSrc, uniforms)
89 |
90 | val quad = new Mesh(geometry, shader)
91 |
92 | quad.position.set(400, 300)
93 | quad.scale.set(2)
94 |
95 | app.stage.addChild(quad)
96 |
97 | app.ticker.add { () =>
98 | quad.rotation += 0.01
99 | quad.shader.asInstanceOf[Shader].uniforms.asInstanceOf[Uniform].time += 0.1
100 | }
101 |
102 | app
103 | end newApplication
104 | end Uniform
105 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/monkeypatching/PIXIPatching.scala:
--------------------------------------------------------------------------------
1 | package demo.monkeypatching
2 |
3 | import typings.pixiJs.PIXI.Ticker
4 |
5 | import scala.language.implicitConversions
6 | import scala.scalajs.js
7 |
8 | object PIXIPatching:
9 |
10 | implicit class TickerWithDoubleAdd(ticker: Ticker):
11 | def add(fn: Double => Unit): Ticker = ticker.add(fn.asInstanceOf[Any => Any])
12 |
13 | def add(fn: () => Unit): Ticker = ticker.add(_ => fn())
14 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/pixi/ExampleSelector.scala:
--------------------------------------------------------------------------------
1 | package demo.pixi
2 |
3 | import org.scalajs.dom
4 | import org.scalajs.dom.html
5 | import org.scalajs.dom.raw.XMLHttpRequest
6 | import typings.highlightJs.mod.{highlightBlock, Node}
7 |
8 | import scala.scalajs.js.timers.setTimeout
9 | import scala.scalajs.js
10 | import scala.scalajs.js.annotation.JSImport
11 |
12 | /** This object is dedicated to display the correct example chosen by the user. When the user changes an example, we
13 | * stop the current animation, we load the next one and we fetch the Scala source code from Github, displaying it with
14 | * syntax highlighting using highlight.js
15 | */
16 | object ExampleSelector:
17 |
18 | private val overallContainer: html.Div = dom.document
19 | .getElementById("overall-container")
20 | .asInstanceOf[html.Div]
21 |
22 | private val welcomeContainer: html.Div = dom.document
23 | .getElementById("welcome-message")
24 | .asInstanceOf[html.Div]
25 |
26 | private val titleH1: html.Heading =
27 | dom.document.getElementById("title").asInstanceOf[html.Heading]
28 |
29 | private val codeDiv: html.Div =
30 | dom.document.getElementById("code-container").asInstanceOf[html.Div]
31 |
32 | private val canvasContainer: html.Div = dom.document
33 | .getElementById("canvas-container")
34 | .asInstanceOf[html.Div]
35 |
36 | private val pixiUrlLink: html.Anchor = dom.document
37 | .getElementById("pixi-url")
38 | .asInstanceOf[html.Anchor]
39 |
40 | def loadAndDisplayCode(example: PIXIExample, pkg: String): Unit =
41 | val request = new XMLHttpRequest
42 |
43 | def display(): Unit =
44 | // checking if the page is still the same when we receive the response
45 | if titleH1.textContent == example.name & request.readyState == 4 & request.status == 200 then
46 | val code = request.responseText
47 |
48 | codeDiv.innerHTML = s"""$code
"""
49 | setTimeout(1) {
50 |
51 | highlightBlock(codeDiv.firstChild.firstChild.asInstanceOf[Node])
52 | }
53 |
54 | request.open("GET", example.githubUrl(pkg))
55 | request.send()
56 |
57 | request.onreadystatechange = (_: dom.Event) => display()
58 | end loadAndDisplayCode
59 |
60 | /** Removes the content of the canvas-container div, and puts a new html.Canvas into it.
61 | */
62 | def changeCanvas(example: PIXIExample): html.Canvas =
63 | val children = canvasContainer.children
64 | for idx <- 0 until children.length do canvasContainer.removeChild(children(idx))
65 |
66 | titleH1.textContent = example.name
67 | pixiUrlLink.href = example.pixiUrl
68 | canvasContainer.appendChild(example.canvas)
69 | example.canvas
70 | end changeCanvas
71 |
72 | private val menu: html.Div =
73 | dom.document.getElementById("menu").asInstanceOf[html.Div]
74 |
75 | def makeSection(title: String, examples: List[PIXIExample]): Unit =
76 | menu.appendChild {
77 | val div = dom.document.createElement("div").asInstanceOf[html.Div]
78 | div.className = "menu-section"
79 |
80 | val exampleContainer =
81 | dom.document.createElement("div").asInstanceOf[html.Div]
82 | exampleContainer.style.display = "none"
83 | for example <- examples do
84 | val option = dom.document.createElement("div").asInstanceOf[html.Option]
85 | option.className = "example-option"
86 | option.textContent = example.name
87 | option.value = example.name
88 |
89 | option.onclick = (_: dom.MouseEvent) =>
90 | println(s"Running example ${example.name}")
91 | welcomeContainer.innerHTML = ""
92 | example.run(title.toLowerCase.filterNot(_ == '-').filterNot(_ == ' '))
93 | overallContainer.style.display = "block"
94 |
95 | exampleContainer.appendChild(option)
96 | end for
97 |
98 | val titleDiv = dom.document.createElement("div").asInstanceOf[html.Div]
99 | titleDiv.className = "section-header"
100 | titleDiv.textContent = title
101 | titleDiv.style.cursor = "pointer"
102 | titleDiv.onclick = (_: dom.MouseEvent) =>
103 | if exampleContainer.style.display == "none" then exampleContainer.style.display = "block"
104 | else exampleContainer.style.display = "none"
105 |
106 | div.appendChild(titleDiv)
107 | div.appendChild(exampleContainer)
108 |
109 | div
110 | }
111 |
112 | @js.native @JSImport("./styles.css", JSImport.Namespace)
113 | object Style extends js.Object
114 |
115 | @js.native @JSImport("./a11y-light.css", JSImport.Namespace)
116 | object `a11y-light.css` extends js.Object
117 |
118 | @main
119 | def main: Unit =
120 |
121 | /** Touch to load */
122 | Style
123 | `a11y-light.css`
124 |
125 | PIXIExample.allExamples.foreach { case (title, examples) =>
126 | makeSection(title, examples)
127 | }
128 | end main
129 | end ExampleSelector
130 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/pixi/PIXIExample.scala:
--------------------------------------------------------------------------------
1 | package demo.pixi
2 |
3 | import demo.demosadvanced.*
4 | import demo.demosbasic.*
5 | import demo.filtersbasic.DisplacementMapFlag
6 | import demo.graphics.Simple
7 | import demo.interaction.Click
8 | import demo.meshandshaders.Uniform
9 | import demo.pluginfilters.Outline
10 | import demo.sprite.{TilingSpriteExample, VideoExample}
11 | import org.scalajs.dom.html
12 | import typings.pixiJs.anon.BaseTexture as StageOptions
13 | import typings.pixiJs.mod.Application
14 |
15 | trait PIXIExample:
16 |
17 | val name: String
18 |
19 | val pixiUrl: String
20 |
21 | def githubUrl(pkg: String): String =
22 | s"""https://raw.githubusercontent.com/ScalablyTyped/Demos/master/pixi/src/main/scala/demo/$pkg/$toString.scala"""
23 |
24 | private var pixiApp: Option[Application] = None
25 |
26 | private def stop(): Unit =
27 | pixiApp match
28 | case Some(app) =>
29 | app.destroy(
30 | removeView = true,
31 | stageOptions = StageOptions().setBaseTexture(true)
32 | )
33 | case None =>
34 | end match
35 | pixiApp = None
36 | end stop
37 |
38 | protected def newApplication(): Application
39 |
40 | def run(pkg: String): Unit =
41 | PIXIExample.stopAll()
42 | pixiApp = Some(newApplication())
43 | ExampleSelector.changeCanvas(this)
44 | ExampleSelector.loadAndDisplayCode(this, pkg)
45 | end run
46 |
47 | def canvas: html.Canvas = pixiApp.get.view
48 | end PIXIExample
49 |
50 | object PIXIExample:
51 |
52 | val allExamples: Map[String, List[PIXIExample]] = Map(
53 | "DEMOS-BASIC" -> List(Basics, Containers, ContainerPivot, Tinting),
54 | "DEMOS-ADVANCED" -> List(MouseTrail, StarWarp),
55 | "SPRITE" -> List(TilingSpriteExample, VideoExample),
56 | "GRAPHICS" -> List(Simple),
57 | "INTERACTION" -> List(Click),
58 | "MESH-AND-SHADERS" -> List(Uniform),
59 | "FILTERS-BASIC" -> List(DisplacementMapFlag),
60 | "PLUGIN-FILTERS" -> List(Outline)
61 | )
62 |
63 | def stopAll(): Unit =
64 | allExamples.values.flatten.foreach(_.stop())
65 | end PIXIExample
66 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/pluginfilters/Outline.scala:
--------------------------------------------------------------------------------
1 | package demo.pluginfilters
2 |
3 | import demo.assets.BunnyImage
4 | import demo.pixi.PIXIExample
5 | import typings.pixiFilterGlow.PIXI.filters.GlowFilterOptions
6 | import typings.pixiFilterGlow.mod.{GlowFilter}
7 | import typings.pixiFilterOutline.mod.OutlineFilter
8 | import typings.pixiJs.mod.{Application, Sprite, Texture}
9 |
10 | import scala.scalajs.js
11 |
12 | case object Outline extends PIXIExample:
13 | val name: String = "Outline"
14 | val pixiUrl: String = "https://pixijs.io/examples/#/plugin-filters/outline.js"
15 |
16 | protected def newApplication(): Application =
17 | val app = new Application()
18 |
19 | app.stage.position.set(400, 300)
20 |
21 | val outlineFilterBlue = new OutlineFilter(2, 0x99ff99)
22 | val outlineFilterRed = new GlowFilter(
23 | GlowFilterOptions()
24 | .setOuterStrength(15)
25 | .setDistance(2)
26 | .setInnerStrength(1)
27 | .setColor(0xff9999)
28 | .setQuality(0.5)
29 | )
30 |
31 | def filterOn(sprite: Sprite): Unit =
32 | sprite.filters = js.Array(outlineFilterRed)
33 |
34 | def filterOff(sprite: Sprite): Unit =
35 | sprite.filters = js.Array(outlineFilterBlue)
36 |
37 | val texture = Texture.from(BunnyImage)
38 |
39 | for _ <- 0 until 20 do
40 | val bunny = new Sprite(texture)
41 | bunny.interactive = true
42 | bunny.position.set((Math.random() * 2 - 1) * 300, (Math.random() * 2 - 1) * 200)
43 | bunny.scale.x = (Math.random() * 3) + 1
44 | bunny
45 | .on("pointerover", () => filterOn(bunny))
46 | .on("pointerout", () => filterOff(bunny))
47 | filterOff(bunny)
48 | app.stage.addChild(bunny)
49 | end for
50 |
51 | app
52 | end newApplication
53 | end Outline
54 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/sprite/TilingSpriteExample.scala:
--------------------------------------------------------------------------------
1 | package demo.sprite
2 |
3 | import demo.assets.P2Image
4 | import demo.pixi.PIXIExample
5 | import typings.pixiJs.mod.{Application, Texture, TilingSprite}
6 | import demo.monkeypatching.PIXIPatching.*
7 |
8 | case object TilingSpriteExample extends PIXIExample:
9 |
10 | val name: String = "Tiling Sprite"
11 |
12 | val pixiUrl: String = "https://pixijs.io/examples/#/sprite/tiling-sprite.js"
13 |
14 | def newApplication(): Application =
15 |
16 | val app = new Application()
17 |
18 | // create a texture from an image path
19 | val texture = Texture.from(P2Image)
20 |
21 | /* create a tiling sprite ...
22 | * requires a texture, a width and a height
23 | * in WebGL the image size should preferably be a power of two
24 | */
25 | val tilingSprite =
26 | new TilingSprite(texture, app.screen.width, app.screen.height)
27 | app.stage.addChild(tilingSprite)
28 |
29 | var count: Double = 0
30 |
31 | app.ticker.add { () =>
32 |
33 | count += 0.005
34 |
35 | tilingSprite.tileScale.x = 2 + Math.sin(count)
36 | tilingSprite.tileScale.y = 2 + Math.cos(count)
37 |
38 | tilingSprite.tilePosition.x += 1
39 | tilingSprite.tilePosition.y += 1
40 |
41 | }
42 |
43 | app
44 | end newApplication
45 | end TilingSpriteExample
46 |
--------------------------------------------------------------------------------
/pixi/src/main/scala/demo/sprite/VideoExample.scala:
--------------------------------------------------------------------------------
1 | package demo.sprite
2 |
3 | import demo.assets.TheVideo
4 | import demo.pixi.PIXIExample
5 | import typings.pixiJs.anon.Antialias as ApplicationOptions
6 | import typings.pixiJs.mod.{Application, Graphics, Sprite, Texture}
7 |
8 | import scala.scalajs.js
9 |
10 | case object VideoExample extends PIXIExample:
11 |
12 | val name: String = "Video"
13 |
14 | val pixiUrl: String = "https://pixijs.io/examples/#/sprite/video.js"
15 |
16 | override def newApplication(): Application =
17 | val app = new Application(ApplicationOptions().setTransparent(true))
18 |
19 | // Create play button that can be used to trigger the video
20 | val button = new Graphics()
21 | .beginFill(0x0, 0.5)
22 | .drawRoundedRect(0, 0, 100, 100, 10)
23 | .endFill()
24 | .beginFill(0xffffff)
25 | .moveTo(36, 30)
26 | .lineTo(36, 70)
27 | .lineTo(70, 50)
28 |
29 | // Position the button
30 | button.x = (app.screen.width - button.width) / 2
31 | button.y = (app.screen.height - button.height) / 2
32 |
33 | // Enable interactivity on the button
34 | button.interactive = true
35 | button.buttonMode = true
36 |
37 | // Add to the stage
38 | app.stage.addChild(button)
39 |
40 | // Listen for a click/tap event to start playing the video
41 | // this is useful for some mobile platforms. For example:
42 | // ios9 and under cannot render videos in PIXI without a
43 | // polyfill - https://github.com/bfred-it/iphone-inline-video
44 | // ios10 and above require a click/tap event to render videos
45 | // that contain audio in PIXI. Videos with no audio track do
46 | // not have this requirement
47 | button.on("pointertap", (_: js.Any) => onPlayVideo())
48 |
49 | def onPlayVideo() =
50 |
51 | // Don't need the button anymore
52 | button.destroy()
53 |
54 | // create a video texture from a path
55 | val texture = Texture.from(TheVideo)
56 |
57 | // create a new Sprite using the video texture (yes it's that easy)
58 | val videoSprite = new Sprite(texture)
59 |
60 | // Stetch the fullscreen
61 | videoSprite.width = app.screen.width
62 | videoSprite.height = app.screen.height
63 |
64 | app.stage.addChild(videoSprite)
65 | end onPlayVideo
66 |
67 | app
68 | end newApplication
69 | end VideoExample
70 |
--------------------------------------------------------------------------------
/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version=1.9.0
--------------------------------------------------------------------------------
/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.13.1")
2 | addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.21.1")
3 | addSbtPlugin("org.scalablytyped.converter" % "sbt-converter" % "1.0.0-beta44")
--------------------------------------------------------------------------------
/project/scalafmt.sbt:
--------------------------------------------------------------------------------
1 | addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.0.0")
2 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Demos for ScalablyTyped
2 |
3 | This is a collection of tiny demo projects to show off how we can use javascript libraries from scala.js
4 |
5 | ## React demos
6 |
7 | All react demos are now moved to separate repositories by the react library they use.
8 | See slinky demos [here](https://github.com/ScalablyTyped/SlinkyTypedDemos)
9 |
10 | ## Browser demos
11 |
12 | ### d3
13 | [Demo](https://scalablytyped.github.io/Demos/d3/)
14 |
15 | It uses d3 to generate a rather fancy spinning globe. Demo is converted from [here](https://bl.ocks.org/animateddata/1f6522d3fcec29c01e7f4a5894e1fd94)
16 |
17 | `sbt> d3/start` starts a webpack-dev-server at http://localhost:8001 .
18 |
19 | ### google-maps
20 | [Demo](https://scalablytyped.github.io/Demos/google-maps/)
21 |
22 | The demo loads the google maps javascript as distributed by google (see [index.html](./google-maps/assets/index.html) ).
23 | It's very simple usage, it just shows the location of a few beaches.
24 |
25 | `sbt> google-maps/start` starts a webpack-dev-server at http://localhost:8002 .
26 |
27 | ### jquery
28 | [Demo](https://scalablytyped.github.io/Demos/jquery/)
29 |
30 | This demo shows how to interact with old-style javascript.
31 | Jqueryui is a global library (as in, not a module), so you'll see the code touches an object to include it.
32 | It also extends jquery with more functionality, so you'll see an explicit cast to tell the compiler about this.
33 | This is poor mans interface augmentation (a mechanism by which typescript does this automatically)
34 |
35 | #### Libraries used
36 |
37 | - jquery
38 | - jqueryui
39 |
40 | `sbt> jquery/start` starts a webpack-dev-server at http://localhost:8003 .
41 |
42 | ### Vue
43 | [Demo](https://scalablytyped.github.io/Demos/vue/)
44 |
45 | This demo showcases a pretty simple todo app (stolen and adapted from [scalajs-vue](https://github.com/fancellu/scalajs-vue/)).
46 | Some templating is done in [index.html](./vue/assets/index.html), while a bunch of stuff is done in Scala.
47 |
48 | From its design it's pretty clear that Vue was designed by javascript people.
49 | Trying to obtain type safety in this mess will probably never be worth it,
50 | but at least now you can try! :)
51 | `sbt> vue/start` starts a webpack-dev-server at http://localhost:8004 .
52 |
53 |
54 | ### Three.js
55 | [Demo](https://scalablytyped.github.io/Demos/three/)
56 |
57 | A fancy animation of a horse, stolen from [three.js demos](https://github.com/mrdoob/three.js/blob/master/examples/webgl_morphtargets_horse.html).
58 | `sbt> three/start` starts a webpack-dev-server at http://localhost:8005 .
59 |
60 | ### Reveal.js
61 | [Demo](https://scalablytyped.github.io/Demos/reveal/)
62 |
63 | Write your talks in scala.js! This uses highlight.js and reveal.js along with
64 | scalajs-react. adapted from [scala-reveal-js](https://github.com/pheymann/scala-reveal-js),
65 | `sbt> reveal/start` starts a webpack-dev-server at http://localhost:8006 .
66 |
67 | ### Chart.js
68 | [Demo](https://scalablytyped.github.io/Demos/chart/)
69 |
70 | Simple charting using canvas elements. Shows off how to work with the DOM as well
71 | as how to use chart.js. Heavily adapted from the [retyped demo](https://github.com/Retyped/Demos/tree/master/ChartJsDemo),
72 | `sbt> chart/start` starts a webpack-dev-server at http://localhost:8007 .
73 |
74 | ### Angular 8
75 | [Demo](https://scalablytyped.github.io/Demos/angular/)
76 |
77 | Let's be nice and say that Angular is a reasonable alternative for creating a frontend app.
78 | If you agree, now is your chance to use it with Scala.js.
79 |
80 | Adapted from [sherpal's prototype](https://github.com/sherpal/AngularScalaPOC).
81 | `sbt> angular/start` starts a webpack-dev-server at http://localhost:8008 .
82 |
83 | ### P5
84 | [Demo](https://scalablytyped.github.io/Demos/p5/index.html)
85 |
86 | Demo adapted from [documentation](https://p5js.org/examples/instance-mode-instantiation.html)
87 | `sbt> p5/start` starts a webpack-dev-server at http://localhost:8009 .
88 |
89 | ### Leaflet
90 | [Demo](https://scalablytyped.github.io/Demos/leaflet/index.html)
91 |
92 | Demo adapted from [scalajs-leaflet](https://github.com/fancellu/scalajs-leaflet/blob/master/example/src/main/scala/example/QuickStartLeaflet.scala)
93 | `sbt> leaflet/start` starts a webpack-dev-server at http://localhost:8010 .
94 |
95 |
96 | ### Onsenui
97 | [Demo](https://scalablytyped.github.io/Demos/onsenui/index.html)
98 | Adapted from [documentation](https://onsen.io/v2/guide/jquery/)
99 |
100 | `sbt> onsenui/start` starts a webpack-dev-server at http://localhost:8011 .
101 |
102 | ### phaser
103 | [Demo](https://scalablytyped.github.io/Demos/phaser/index.html)
104 | Adapted from [animation/create-from-sprite-config example](http://phaser.io/examples/v3/view/animation/create-from-sprite-config)
105 |
106 | `sbt> phaser/start` starts a webpack-dev-server at http://localhost:8012 .
107 |
108 | ### Pixi
109 | [Demo](https://scalablytyped.github.io/Demos/pixi/index.html)
110 | This is the translation of some of the [examples](https://pixijs.io/examples) into Scala.
111 |
112 | [Pixi.js](https://pixijs.io) is a library to render blazingly fast 2D animations on Canvas, using WebGL under the hood.
113 |
114 | `sbt> pixi/start` starts a webpack-dev-server at http://localhost:8013 .
115 |
116 | You will be presented with a menu that has the same structure as the examples from the Pixi website.
117 |
118 | ## Electron
119 | Implements the backend/mainprocess part of an Electron app in Scala.js,
120 | though it would be easy to do the frontend as well (in another module).
121 |
122 | Start the project like this:
123 |
124 | ```
125 | sbt>electron/run
126 | ```
127 |
128 | Again adapted from [sherpal's work](https://github.com/sherpal/Scala.js-Electron-App-Example).
129 |
130 | ## Node demos
131 |
132 | ### lodash
133 | This is a very simple app which uses a few functions from lodash.
134 | `sbt> lodash/run` runs the demo in node.
135 |
136 | ### node-express
137 | This demo is a HTTP endpoint written in express, which runs on node.
138 | Adapted from [this](https://github.com/BrianDGLS/express-ts)
139 |
140 | `sbt> node-express/run` will start it.
141 |
142 | You'll need for instance `curl` to test it:
143 | ```bash
144 | > curl http://localhost:3000/welcome
145 | #Hello, World!
146 |
147 | > curl http://localhost:3000/welcome/foo
148 | # Hello, foo!
149 | ```
150 |
151 | ### typescript
152 |
153 | `sbt> typescript/run` runs the typescript compiler on two files (one of which is meant to fail).
154 | It accepts parameters to specify other files if you want to play around.
155 |
156 | ### cypress
157 |
158 | `sbt> cypress/run` runs a basic test
159 |
160 | ## Your demo here! :)
161 | Pull requests most welcome!
162 |
--------------------------------------------------------------------------------
/reveal/src/main/js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Reveal.js demo
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/reveal/src/main/scala/demo/Demo.scala:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import org.scalajs.dom
4 | import typings.highlightJs.mod.initHighlightingOnLoad
5 | import typings.reveal.{RevealOptions, RevealStatic}
6 |
7 | import scala.scalajs.js
8 | import scala.scalajs.js.annotation.JSImport
9 |
10 | object Demo:
11 | @main
12 | def main: Unit =
13 | // Touch to load
14 | Includes.HighlightingCss
15 | Includes.WhiteThemeCss
16 | Includes.RevealCss
17 | Includes.Reveal
18 | Includes.ZoomJs
19 |
20 | /* initialize highlight.js */
21 | initHighlightingOnLoad()
22 |
23 | /* render talk before we initialize Reveal */
24 | MyTalk.Talk.applyGeneric(())().renderIntoDOM(dom.document.body)
25 |
26 | Includes.Reveal.initialize(
27 | RevealOptions()
28 | .setWidth("80%")
29 | .setHeight("100%")
30 | .setControls(false)
31 | .setProgress(false)
32 | .setHistory(false)
33 | .setCenter(true)
34 | .setTransition("none")
35 | )
36 | end main
37 | end Demo
38 |
39 | object Includes:
40 |
41 | /* customize import and use as module, even though the typings originally were global */
42 | @JSImport("reveal.js/js/reveal.js", JSImport.Namespace)
43 | @js.native
44 | object Reveal extends RevealStatic
45 |
46 | @JSImport("reveal.js/plugin/zoom-js/zoom.js", JSImport.Namespace)
47 | @js.native
48 | object ZoomJs extends RevealStatic
49 |
50 | @JSImport("reveal.js/lib/css/zenburn.css", JSImport.Namespace)
51 | @js.native
52 | object HighlightingCss extends js.Object
53 |
54 | @JSImport("reveal.js/css/theme/white.css", JSImport.Namespace)
55 | @js.native
56 | object WhiteThemeCss extends js.Object
57 |
58 | @JSImport("reveal.js/css/reveal.css", JSImport.Namespace)
59 | @js.native
60 | object RevealCss extends js.Object
61 | end Includes
62 |
--------------------------------------------------------------------------------
/reveal/src/main/scala/demo/MyTalk.scala:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import demo.PresentationUtil.Enumeration.*
4 | import demo.PresentationUtil.*
5 | import japgolly.scalajs.react.component.Scala.Component
6 | import japgolly.scalajs.react.{CtorType, ScalaComponent}
7 | import japgolly.scalajs.react.vdom.html_<^.*
8 |
9 | object MyTalk:
10 |
11 | val chapter1 = chapter(
12 | chapterSlide(
13 | <.h2("Build your presentations with ScalaJS + reveal.js"),
14 | <.br,
15 | <.h4("move down (down-arrow)")
16 | ),
17 | headerSlide(
18 | "reveal.js commands",
19 | <.p("Press 'f' to go full-screen and ESC to see an overview of your slides."),
20 | <.br,
21 | <.p("You can navigate to the right and down.")
22 | ),
23 | headerSlide(
24 | "My Header",
25 | <.h3("Headers everywhere")
26 | ),
27 | headerSlide(
28 | "Enumeration",
29 | Enumeration(
30 | Item.stable("always show this item"),
31 | Item.fadeIn("I fade in"),
32 | Item.stable("I am also always here")
33 | )
34 | ),
35 | headerSlide(
36 | "Code, so much code",
37 | scalaC("""
38 | def main(args: Array[String]): Unit = {
39 | println("hello, world")
40 | }
41 | """),
42 | scalaFragment("""
43 | def moreSideEffects(): Unit = {
44 | println("pop in")
45 | }
46 | """)
47 | ),
48 | noHeaderSlide(
49 | <.h3("Or have a blank slide")
50 | )
51 | )
52 |
53 | val chapter2 = chapter(
54 | chapterSlide(
55 | <.h2("Where can I find more information?")
56 | ),
57 | headerSlide(
58 | "about reveal.js",
59 | <.a(
60 | ^.href := "https://github.com/hakimel/reveal.js/",
61 | "reveal.js"
62 | )
63 | ),
64 | headerSlide(
65 | "about ScalaJS",
66 | <.a(
67 | ^.href := "https://www.scala-js.org",
68 | "ScalaJS"
69 | )
70 | )
71 | )
72 |
73 | val Talk: Component[Unit, Unit, Unit, CtorType.Nullary] = ScalaComponent
74 | .builder[Unit]("Presentation")
75 | .renderStatic(
76 | <.div(
77 | ^.cls := "reveal",
78 | <.div(
79 | ^.cls := "slides",
80 | chapter1,
81 | chapter2
82 | )
83 | )
84 | )
85 | .build
86 | end MyTalk
87 |
--------------------------------------------------------------------------------
/reveal/src/main/scala/demo/PresentationUtil.scala:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import japgolly.scalajs.react.vdom.TagOf
4 | import japgolly.scalajs.react.vdom.html_<^.*
5 | import org.scalajs.dom
6 | import org.scalajs.dom.raw.HTMLElement
7 |
8 | object PresentationUtil:
9 |
10 | val font = HtmlTag("font")
11 |
12 | val dataBackground = VdomAttr("data-background")
13 | val dataBackgroundColor = VdomAttr("data-background-color")
14 | val dataBackgroundSize = VdomAttr("data-background-size")
15 | val dataTrim = VdomAttr("data-trim") := ""
16 | val dataNoEscape = VdomAttr("data-noescape") := ""
17 |
18 | def chapter(slides: TagMod*): TagOf[HTMLElement] = <.section(slides*)
19 |
20 | def header(text: String, cls: String): TagOf[HTMLElement] =
21 | <.div(
22 | ^.cls := cls,
23 | <.p(text)
24 | )
25 |
26 | // 100% side-effect full
27 | private def removeHeader(): Unit =
28 | val headerElements = dom.document.getElementsByClassName("slide-header")
29 |
30 | (0 until headerElements.length).foreach { id =>
31 | val element = headerElements(id)
32 |
33 | element.parentNode.removeChild(element)
34 | }
35 | end removeHeader
36 |
37 | private def cleanSlide(content: TagOf[HTMLElement]): TagOf[HTMLElement] =
38 | removeHeader()
39 |
40 | content
41 | end cleanSlide
42 |
43 | private val ChapterSlideProps = Seq(
44 | (dataBackgroundColor := "#363633"),
45 | (dataBackgroundSize := "30%")
46 | )
47 |
48 | def chapterSlide(content: TagMod*): TagOf[HTMLElement] = cleanSlide(
49 | <.section(
50 | (ChapterSlideProps ++: content)*
51 | )
52 | )
53 |
54 | def noHeaderSlide(content: TagOf[HTMLElement]*): TagOf[HTMLElement] = cleanSlide(
55 | <.section(
56 | content*
57 | )
58 | )
59 |
60 | def headerSlide(headerStr: String, content: TagOf[HTMLElement]*): TagOf[HTMLElement] = cleanSlide(
61 | <.section(
62 | (header(headerStr, "slide-header") +: content)*
63 | )
64 | )
65 |
66 | private def rawCode(language: String, codeStr: String): TagOf[HTMLElement] =
67 | <.code(
68 | ^.cls := language,
69 | dataTrim,
70 | dataNoEscape,
71 | codeStr
72 | )
73 |
74 | def bash(codeStr: String): TagOf[HTMLElement] = <.pre(rawCode("Bash", codeStr))
75 | def scalaC(codeStr: String): TagOf[HTMLElement] = <.pre(rawCode("Scala", codeStr))
76 | def haskell(codeStr: String): TagOf[HTMLElement] = <.pre(rawCode("Haskell", codeStr))
77 | def lisp(codeStr: String): TagOf[HTMLElement] = <.pre(rawCode("Lisp", codeStr))
78 |
79 | private def rawCodeFragment(language: String, codeStr: String): TagOf[HTMLElement] =
80 | <.pre(
81 | ^.cls := "fragment fade-in",
82 | rawCode(language, codeStr)
83 | )
84 |
85 | def scalaFragment(codeStr: String): TagOf[HTMLElement] = rawCodeFragment("Scala", codeStr)
86 | def haskellFragment(codeStr: String): TagOf[HTMLElement] = rawCodeFragment("Haskell", codeStr)
87 | def lispFragment(codeStr: String): TagOf[HTMLElement] = rawCodeFragment("Lisp", codeStr)
88 |
89 | object Enumeration:
90 |
91 | object Item:
92 |
93 | def stable(content: TagOf[HTMLElement]): TagOf[HTMLElement] = <.li(content)
94 | def stable(content: String): TagOf[HTMLElement] = <.li(<.p(content))
95 | def fadeIn(content: TagOf[HTMLElement]): TagOf[HTMLElement] = <.li(^.cls := "fragment fade-in", content)
96 | def fadeIn(content: String): TagOf[HTMLElement] = <.li(^.cls := "fragment fade-in", <.p(content))
97 | end Item
98 |
99 | def apply(head: TagOf[HTMLElement], tail: TagOf[HTMLElement]*): TagOf[HTMLElement] =
100 | <.ul((head +: tail)*)
101 | end Enumeration
102 | end PresentationUtil
103 |
--------------------------------------------------------------------------------
/three/src/main/js/Horse.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScalablyTyped/Demos/558213f6e21e6afbc6f015e06d053038f3a4e66f/three/src/main/js/Horse.glb
--------------------------------------------------------------------------------
/three/src/main/js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Three.js demo
7 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/three/src/main/scala/demo.scala:
--------------------------------------------------------------------------------
1 | import org.scalablytyped.runtime.TopLevel
2 | import typings.std.global.{document, requestAnimationFrame, window}
3 | import typings.std.{FrameRequestCallback, HTMLDivElement, UIEvent, Window, stdStrings}
4 | import typings.three.mod.{Math as ThreeMath, *}
5 |
6 | import scala.scalajs.js
7 | import scala.scalajs.js.Date
8 | import scala.scalajs.js.annotation.JSImport
9 |
10 | val radius = 600
11 |
12 | @main
13 | def main: Unit =
14 |
15 | val container: HTMLDivElement = document.createElement_div(stdStrings.div)
16 | document.body.appendChild(container)
17 |
18 | val info: HTMLDivElement = document.createElement_div(stdStrings.div)
19 | info.style.position = "absolute"
20 | info.style.top = "10px"
21 | info.style.width = "100%"
22 | info.style.textAlign = "center"
23 | info.innerHTML =
24 | """three.js webgl - morph targets - horse. model by mirada from rome """
25 | container.appendChild(info)
26 |
27 | val camera = new PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000)
28 | camera.position.y = 300
29 | val target = new Vector3(0, 150, 0)
30 |
31 | val scene = new Scene()
32 | scene.background = new Color(0xf0f0f0)
33 |
34 | val light1 = new DirectionalLight(0xefefff, 1.5)
35 | light1.position.set(1, 1, 1).normalize()
36 | scene.add(light1)
37 |
38 | val light2 = new DirectionalLight(0xffefef, 1.5)
39 | light2.position.set(-1, -1, -1).normalize()
40 | scene.add(light2)
41 |
42 | var mixerOpt: js.UndefOr[AnimationMixer] = js.undefined
43 |
44 | typings.std.global.console.warn(HorseModel)
45 | new GLTFLoader().load(
46 | HorseModel,
47 | gltf =>
48 | val mesh = gltf.scene.children(0)
49 | mesh.scale.set(1.5, 1.5, 1.5)
50 | scene.add(mesh)
51 | val mixer = new AnimationMixer(mesh)
52 | mixer.clipAction(gltf.animations(0)).setDuration(1).play()
53 | mixerOpt = mixer
54 | )
55 |
56 | val renderer = new WebGLRenderer()
57 | renderer.setPixelRatio(window.devicePixelRatio)
58 | renderer.setSize(window.innerWidth, window.innerHeight)
59 | container.appendChild(renderer.domElement)
60 |
61 | val onWindowResize: js.ThisFunction1[Window, UIEvent, js.Any] = (window, _) =>
62 | camera.aspect = window.innerWidth / window.innerHeight
63 | camera.updateProjectionMatrix()
64 | renderer.setSize(window.innerWidth, window.innerHeight)
65 |
66 | window.addEventListener_resize(stdStrings.resize, onWindowResize, false)
67 |
68 | var prevTime = Date.now()
69 | var theta = 0.0
70 |
71 | def animate: FrameRequestCallback = time =>
72 | theta += 0.1
73 |
74 | camera.position.x = radius * Math.sin(ThreeMath.degToRad(theta))
75 | camera.position.z = radius * Math.cos(ThreeMath.degToRad(theta))
76 |
77 | camera.lookAt(target)
78 |
79 | mixerOpt.foreach { mixer =>
80 | mixer.update((time - prevTime) * 0.001)
81 | prevTime = time;
82 | }
83 |
84 | renderer.render(scene, camera)
85 | requestAnimationFrame(animate)
86 |
87 | animate(0)
88 | end main
89 |
90 | /* Somewhat awkward that a bunch of the needed code live in `examples/`, which we don't currently convert */
91 | @JSImport("three/examples/jsm/loaders/GLTFLoader", "GLTFLoader")
92 | @js.native
93 | class GLTFLoader() extends Loader:
94 | def load(url: String, onLoad: js.Function1[GLTF, Unit]): Unit = js.native
95 |
96 | trait GLTF extends js.Object:
97 | val animations: js.Array[AnimationClip]
98 | val scene: Scene
99 | val scenes: js.Array[Scene]
100 | val cameras: js.Array[Camera]
101 | val asset: js.Object
102 | end GLTF
103 |
104 |
105 | @JSImport("./Horse.glb", JSImport.Default)
106 | @js.native
107 | object HorseModel extends TopLevel[String]
108 |
--------------------------------------------------------------------------------
/typescript/src/main/resources/bad.js:
--------------------------------------------------------------------------------
1 | var bad = function (num) { return console.log("number was " + num); };
2 | bad_name(42);
3 |
--------------------------------------------------------------------------------
/typescript/src/main/resources/bad.ts:
--------------------------------------------------------------------------------
1 | const bad = (num: number) => console.log(`number was ${num}`);
2 |
3 | bad_name(42);
--------------------------------------------------------------------------------
/typescript/src/main/resources/good.js:
--------------------------------------------------------------------------------
1 | var good = function (num) { return console.log("number was " + num); };
2 | good(42);
3 |
--------------------------------------------------------------------------------
/typescript/src/main/resources/good.ts:
--------------------------------------------------------------------------------
1 | const good = (num: number) => console.log(`number was ${num}`);
2 |
3 | good(42);
--------------------------------------------------------------------------------
/typescript/src/main/scala/demo.scala:
--------------------------------------------------------------------------------
1 | import typings.node.global.console
2 | import typings.node.processMod.^ as process
3 | import typings.typescript.mod as ts
4 |
5 | import scala.scalajs.js
6 | import scala.scalajs.js.|
7 |
8 | def compile(fileNames: js.Array[String], options: ts.CompilerOptions): Unit =
9 | val program: ts.Program = ts.createProgram(fileNames, options)
10 | val emitResult = program.emit()
11 |
12 | val allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics)
13 |
14 | allDiagnostics.foreach { diagnostic =>
15 | val baseMessage = ts.flattenDiagnosticMessageText(Knowledge.force(diagnostic.messageText), "\n")
16 |
17 | val message = diagnostic.file.fold(baseMessage) { file =>
18 | val pos = file.getLineAndCharacterOfPosition(diagnostic.start.get)
19 | s"${diagnostic.file.get.fileName} (${pos.line + 1},${pos.character + 1}): $baseMessage"
20 | }
21 | console.log(message)
22 | }
23 |
24 | val exitCode = if emitResult.emitSkipped then 1 else 0
25 | console.log(s"Process exiting with code '$exitCode'.")
26 | process.exit(exitCode)
27 | end compile
28 |
29 | @main def main: Unit =
30 | val files: js.Array[String] =
31 | process.argv.drop(2) match
32 | case empty if empty.length == 0 =>
33 | js.Array(
34 | "typescript/src/main/resources/good.ts",
35 | "typescript/src/main/resources/bad.ts"
36 | )
37 | case nonEmpty => nonEmpty
38 |
39 | compile(
40 | files,
41 | ts.CompilerOptions().setNoEmitOnError(true).setNoImplicitAny(true).setOutDir("typescript/target/temp")
42 | )
43 | end main
44 |
45 | object Knowledge:
46 | def force(a: String | ts.DiagnosticMessageChain): ts.DiagnosticMessageChain =
47 | a.asInstanceOf[ts.DiagnosticMessageChain]
48 |
--------------------------------------------------------------------------------
/vue/src/main/js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Scala.js+Vue.js sample application!
5 |
6 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | Title=
45 |
46 |
47 |
48 |
49 | {{todo.content}}
50 | Remove
51 |
52 |
53 |
54 |
55 | Tasks# {{todos.length}}
56 | N={{n}}
57 |
58 |
data JSON: {{$data | json 2}}
59 |
60 |
61 | Using a v-text directive title=
62 |
Smooth CSS animation:
63 |
64 |
65 |
66 |
67 |
68 |
Title reversed={{title | reverse}}
69 |
Title wrapper={{title | wrap('<<','>>')}}
70 |
xx
71 |
Special content
72 |
73 |
Call clickHandler in Scala
74 |
Increment N
75 |
76 |
Add Task
77 |
Change 1st
78 |
Remove 1st
79 |
Flip All
80 | Todos computed: {{ todosComputed }}
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/vue/src/main/scala/demo.scala:
--------------------------------------------------------------------------------
1 | import Knowledge.*
2 | import org.scalablytyped.runtime.StringDictionary
3 | import typings.vue.typesOptionsMod.*
4 | import typings.vue.typesVnodeMod.VNodeDirective
5 | import typings.vue.typesVueMod.CombinedVueInstance
6 |
7 | import scala.scalajs.js
8 | import scala.scalajs.js.ThisFunction0
9 | import scala.scalajs.js.annotation.JSImport
10 |
11 | @js.native
12 | trait DemoVue extends Vue:
13 | var title: String = js.native
14 | var n: Double = js.native
15 | var todos: js.Array[DemoVueTodo] = js.native
16 | end DemoVue
17 |
18 | trait DemoVueTodo extends js.Object:
19 | var done: Boolean
20 | val content: String
21 |
22 | trait Methods extends js.Object:
23 | val clickHandler: js.ThisFunction0[DemoVue, Unit]
24 | val addTask: js.ThisFunction0[DemoVue, Unit]
25 | val change1st: js.ThisFunction0[DemoVue, Unit]
26 | val remove: js.ThisFunction1[DemoVue, Int, Unit]
27 | val flipAll: js.ThisFunction0[DemoVue, Unit]
28 | end Methods
29 |
30 | trait Data extends js.Object:
31 | val message: String
32 | val title: String
33 | val todos: js.Array[DemoVueTodo]
34 | val barValue: Int
35 | val n: Int
36 | end Data
37 |
38 | trait Computed extends js.Object:
39 | val todosComputed: js.ThisFunction0[DemoVue, js.Array[String]]
40 |
41 | @main
42 | def main: Unit =
43 |
44 | val tasks = js.Array("Learn JavaScript", "Learn Vue.js", "Learn Scala.js")
45 |
46 | def ts = new java.util.Date().toString
47 |
48 | Vue.component(
49 | "my-component",
50 | ComponentOptions[
51 | DemoVue,
52 | ThisFunction0[DemoVue, Data],
53 | Methods,
54 | Computed,
55 | PropsDefinition[DemoVue],
56 | DefaultProps
57 | ]()
58 | .setProps(js.Array("myMsg"))
59 | .setTemplate("A custom component with msg {{myMsg}} default content
")
60 | )
61 |
62 | Vue.directive(
63 | "mydirective",
64 | DirectiveOptions().setUpdate { (el, directive, _, _) =>
65 | val dir = directive.asInstanceOf[VNodeDirective]
66 | el.innerHTML = "This comes from my-directive with contents " + dir.value + " and expression " + dir.expression
67 | }
68 | )
69 |
70 | val demoOpt =
71 | ComponentOptions[DemoVue, ThisFunction0[DemoVue, Data], Methods, Computed, PropsDefinition[
72 | DemoVue
73 | ], DefaultProps]()
74 | .setEl("#demo")
75 | .setData(_ =>
76 | new Data:
77 | val message = "Hello Vue.js!!!!!"
78 | val title = "Todo App"
79 | val todos = tasks.map(c =>
80 | new DemoVueTodo:
81 | var done = c == tasks.head
82 | val content = c
83 | )
84 | val barValue = 100
85 | val n = 0
86 | )
87 | .setMethods(new Methods:
88 | val clickHandler = demoVue => demoVue.n -= 1
89 |
90 | val addTask = demoVue =>
91 | demoVue.todos.append(new DemoVueTodo:
92 | var done = false
93 | val content = s"new $ts"
94 | )
95 |
96 | val change1st = demoVue =>
97 | Vue.set(
98 | demoVue.todos,
99 | 0,
100 | new DemoVueTodo:
101 | var done = false
102 | val content = ts
103 | )
104 |
105 | val remove = (demoVue, idx) => Vue.delete(demoVue.todos, idx)
106 |
107 | val flipAll = demoVue => demoVue.todos.foreach(td => td.done = !td.done)
108 | )
109 | .setComputed(
110 | Knowledge.isAccessors(
111 | new Computed:
112 | val todosComputed = (demoVue: DemoVue) => demoVue.todos.map(_.content)
113 | )
114 | )
115 | .setFilters(new StringDictionary[js.Function]:
116 | val reverse: js.Function1[js.Any, String] =
117 | _.toString.reverse
118 | val wrap: js.Function3[js.Any, String, String, String] =
119 | (value: js.Any, begin: String, end: String) => begin + value.toString + end
120 | val extract: js.Function2[js.UndefOr[js.Array[js.Dynamic]], String, js.UndefOr[js.Array[js.Dynamic]]] =
121 | (array, field) => array.map(_.map(_.selectDynamic(field)))
122 | )
123 |
124 | val demo = new VueClass(demoOpt).value
125 |
126 | demo.$watch("title", (_: demo.type, newValue, _) => println("changed " + newValue))
127 | end main
128 |
129 | object Knowledge:
130 | type Vue = typings.vue.typesVueMod.Vue
131 |
132 | /** We need a custom import because the normal module doesn't include
133 | * a... compiler or something. Seems we're running code at runtime which could have ran at build time.
134 | *
135 | * Discussion at https://github.com/vuejs-templates/webpack/issues/215
136 | */
137 | @JSImport("vue/dist/vue", JSImport.Namespace)
138 | @js.native
139 | object Vue extends typings.vue.typesVueMod.VueConstructor[typings.vue.typesVueMod.Vue]
140 |
141 | /** Needs the same custom import as above (it's the same object)
142 | *
143 | * In the ScalablyTyped encoding the constructor ended up as an `Instantiable`, which means it has lost its type
144 | * parameters. We recreate it here to avoid casting.
145 | *
146 | * Finally, the shape of the Vue object is hard to rewrite into a Scala class, because the return type is an
147 | * intersection type (can't extend from that). That's what's fixed by the `.value` ceremony
148 | */
149 | @JSImport("vue/dist/vue", JSImport.Namespace)
150 | @js.native
151 | class VueClass[V <: Vue, Data, Methods, Computed, PropsDef, Props](
152 | options: ComponentOptions[V, Data, Methods, Computed, PropsDef, Props]
153 | ) extends js.Object
154 |
155 | object VueClass:
156 | @inline implicit class VueClassOps[V <: Vue, Data, Methods, Computed, PropsDef, Props](
157 | val instance: VueClass[V, Data, Methods, Computed, PropsDef, Props]
158 | ) extends AnyVal:
159 | @inline def value: CombinedVueInstance[V, Data, Methods, Computed, Props] =
160 | instance.asInstanceOf[CombinedVueInstance[V, Data, Methods, Computed, Props]]
161 | end VueClassOps
162 | end VueClass
163 |
164 | def isAccessors[T](t: T): Accessors[T] =
165 | t.asInstanceOf[Accessors[T]]
166 | end Knowledge
167 |
--------------------------------------------------------------------------------