Arvel  Miller

Arvel Miller

1599762180

Setup a Simple Server-Side Application for Your Game Using Strapi.js

In the previous part, we successfully installed and ran a Strapi application. Now it is time to build the API. But first let’s take a close look at what a game server like this can provide us:

  • It can authenticate users.
  • We can implement game logics.
  • Users can see leaderboads.
  • We can change some of the game elements through the server.
  • and lots of other functionalities.

Controllers, Services and Routes

For building an API in Strapi, you need to understand 3 main concepts.

**Services: **Services serve as global methods which you can use everywhere in your application. Their main job is to reduce the use of some repeatable functions by being available globally.

**Controllers: **Controllers are the main part of your API. The main functions go here.

**Routes: **Routes are bounded to controller methods. They are actually Urls which are pointing to a specific method, so each time you call that Url the method gets executed.

Know that you’re familiar with these 3 concepts, we are ready to create a remote config system for our game.

Remote Config

Creating Model

Let’s say we have an RPG game with different heroes, hero types, buildings, maps, items and etc. Each hero has its own specifications such as damage power (if it is melee), range (if it’s of range type), health, mana and so many other parameters. These things need to be balanced and tweaked by game designers frequently. So it is not a good idea to put them inside the client. The best solution is to get all of those data from your server at the very beginning of the game and keep them for later use.

For creating such a functionality, the very first step is to create a model of data. It should be one single model to cover everything that need a config in the game, such as heroes, hero types, items and etc. So we need these fields:

  • **Name **(it defines to what specific part of the game, this object belongs)
  • **Type **(it tells us the type of this object)
  • **Data **(the main data that we want to tweak or adjust later)

Now that we have a model in mind, we open the Strapi’s admin panel:

Image for post

Strapi admin panel

here you can see that Strapi has already made a collection (or content-type) called Users. We need something like that for our Remote Config. A collection that stores our config data.

open the Content-Types Builder:

Image for post

under the Collection Types in the grey column, you can see the blue text saying Create new collection type. Click on it:

Image for post

a window pops open. In the Display name write Remote Config and press Continue. Now you can see this window:

Image for post

here you should create those 3 fields that we talked about. Name,_Type _and Data. For name you can choose _Text _or UID. I recommend you to select _UID _because it guarantees that the content of that field is unique in entire collection. So I select the UID:

Image for post

inside the Name field write name (with small letter because it’s better :) )

and click on +Add another field, For our _Type _field you can select Text:

Image for post

Image for post

#strapi #games #javascript #game-server #nodejs

What is GEEK

Buddha Community

Setup a Simple Server-Side Application for Your Game Using Strapi.js
Chloe  Butler

Chloe Butler

1667425440

Pdf2gerb: Perl Script Converts PDF Files to Gerber format

pdf2gerb

Perl script converts PDF files to Gerber format

Pdf2Gerb generates Gerber 274X photoplotting and Excellon drill files from PDFs of a PCB. Up to three PDFs are used: the top copper layer, the bottom copper layer (for 2-sided PCBs), and an optional silk screen layer. The PDFs can be created directly from any PDF drawing software, or a PDF print driver can be used to capture the Print output if the drawing software does not directly support output to PDF.

The general workflow is as follows:

  1. Design the PCB using your favorite CAD or drawing software.
  2. Print the top and bottom copper and top silk screen layers to a PDF file.
  3. Run Pdf2Gerb on the PDFs to create Gerber and Excellon files.
  4. Use a Gerber viewer to double-check the output against the original PCB design.
  5. Make adjustments as needed.
  6. Submit the files to a PCB manufacturer.

Please note that Pdf2Gerb does NOT perform DRC (Design Rule Checks), as these will vary according to individual PCB manufacturer conventions and capabilities. Also note that Pdf2Gerb is not perfect, so the output files must always be checked before submitting them. As of version 1.6, Pdf2Gerb supports most PCB elements, such as round and square pads, round holes, traces, SMD pads, ground planes, no-fill areas, and panelization. However, because it interprets the graphical output of a Print function, there are limitations in what it can recognize (or there may be bugs).

See docs/Pdf2Gerb.pdf for install/setup, config, usage, and other info.


pdf2gerb_cfg.pm

#Pdf2Gerb config settings:
#Put this file in same folder/directory as pdf2gerb.pl itself (global settings),
#or copy to another folder/directory with PDFs if you want PCB-specific settings.
#There is only one user of this file, so we don't need a custom package or namespace.
#NOTE: all constants defined in here will be added to main namespace.
#package pdf2gerb_cfg;

use strict; #trap undef vars (easier debug)
use warnings; #other useful info (easier debug)


##############################################################################################
#configurable settings:
#change values here instead of in main pfg2gerb.pl file

use constant WANT_COLORS => ($^O !~ m/Win/); #ANSI colors no worky on Windows? this must be set < first DebugPrint() call

#just a little warning; set realistic expectations:
#DebugPrint("${\(CYAN)}Pdf2Gerb.pl ${\(VERSION)}, $^O O/S\n${\(YELLOW)}${\(BOLD)}${\(ITALIC)}This is EXPERIMENTAL software.  \nGerber files MAY CONTAIN ERRORS.  Please CHECK them before fabrication!${\(RESET)}", 0); #if WANT_DEBUG

use constant METRIC => FALSE; #set to TRUE for metric units (only affect final numbers in output files, not internal arithmetic)
use constant APERTURE_LIMIT => 0; #34; #max #apertures to use; generate warnings if too many apertures are used (0 to not check)
use constant DRILL_FMT => '2.4'; #'2.3'; #'2.4' is the default for PCB fab; change to '2.3' for CNC

use constant WANT_DEBUG => 0; #10; #level of debug wanted; higher == more, lower == less, 0 == none
use constant GERBER_DEBUG => 0; #level of debug to include in Gerber file; DON'T USE FOR FABRICATION
use constant WANT_STREAMS => FALSE; #TRUE; #save decompressed streams to files (for debug)
use constant WANT_ALLINPUT => FALSE; #TRUE; #save entire input stream (for debug ONLY)

#DebugPrint(sprintf("${\(CYAN)}DEBUG: stdout %d, gerber %d, want streams? %d, all input? %d, O/S: $^O, Perl: $]${\(RESET)}\n", WANT_DEBUG, GERBER_DEBUG, WANT_STREAMS, WANT_ALLINPUT), 1);
#DebugPrint(sprintf("max int = %d, min int = %d\n", MAXINT, MININT), 1); 

#define standard trace and pad sizes to reduce scaling or PDF rendering errors:
#This avoids weird aperture settings and replaces them with more standardized values.
#(I'm not sure how photoplotters handle strange sizes).
#Fewer choices here gives more accurate mapping in the final Gerber files.
#units are in inches
use constant TOOL_SIZES => #add more as desired
(
#round or square pads (> 0) and drills (< 0):
    .010, -.001,  #tiny pads for SMD; dummy drill size (too small for practical use, but needed so StandardTool will use this entry)
    .031, -.014,  #used for vias
    .041, -.020,  #smallest non-filled plated hole
    .051, -.025,
    .056, -.029,  #useful for IC pins
    .070, -.033,
    .075, -.040,  #heavier leads
#    .090, -.043,  #NOTE: 600 dpi is not high enough resolution to reliably distinguish between .043" and .046", so choose 1 of the 2 here
    .100, -.046,
    .115, -.052,
    .130, -.061,
    .140, -.067,
    .150, -.079,
    .175, -.088,
    .190, -.093,
    .200, -.100,
    .220, -.110,
    .160, -.125,  #useful for mounting holes
#some additional pad sizes without holes (repeat a previous hole size if you just want the pad size):
    .090, -.040,  #want a .090 pad option, but use dummy hole size
    .065, -.040, #.065 x .065 rect pad
    .035, -.040, #.035 x .065 rect pad
#traces:
    .001,  #too thin for real traces; use only for board outlines
    .006,  #minimum real trace width; mainly used for text
    .008,  #mainly used for mid-sized text, not traces
    .010,  #minimum recommended trace width for low-current signals
    .012,
    .015,  #moderate low-voltage current
    .020,  #heavier trace for power, ground (even if a lighter one is adequate)
    .025,
    .030,  #heavy-current traces; be careful with these ones!
    .040,
    .050,
    .060,
    .080,
    .100,
    .120,
);
#Areas larger than the values below will be filled with parallel lines:
#This cuts down on the number of aperture sizes used.
#Set to 0 to always use an aperture or drill, regardless of size.
use constant { MAX_APERTURE => max((TOOL_SIZES)) + .004, MAX_DRILL => -min((TOOL_SIZES)) + .004 }; #max aperture and drill sizes (plus a little tolerance)
#DebugPrint(sprintf("using %d standard tool sizes: %s, max aper %.3f, max drill %.3f\n", scalar((TOOL_SIZES)), join(", ", (TOOL_SIZES)), MAX_APERTURE, MAX_DRILL), 1);

#NOTE: Compare the PDF to the original CAD file to check the accuracy of the PDF rendering and parsing!
#for example, the CAD software I used generated the following circles for holes:
#CAD hole size:   parsed PDF diameter:      error:
#  .014                .016                +.002
#  .020                .02267              +.00267
#  .025                .026                +.001
#  .029                .03167              +.00267
#  .033                .036                +.003
#  .040                .04267              +.00267
#This was usually ~ .002" - .003" too big compared to the hole as displayed in the CAD software.
#To compensate for PDF rendering errors (either during CAD Print function or PDF parsing logic), adjust the values below as needed.
#units are pixels; for example, a value of 2.4 at 600 dpi = .0004 inch, 2 at 600 dpi = .0033"
use constant
{
    HOLE_ADJUST => -0.004 * 600, #-2.6, #holes seemed to be slightly oversized (by .002" - .004"), so shrink them a little
    RNDPAD_ADJUST => -0.003 * 600, #-2, #-2.4, #round pads seemed to be slightly oversized, so shrink them a little
    SQRPAD_ADJUST => +0.001 * 600, #+.5, #square pads are sometimes too small by .00067, so bump them up a little
    RECTPAD_ADJUST => 0, #(pixels) rectangular pads seem to be okay? (not tested much)
    TRACE_ADJUST => 0, #(pixels) traces seemed to be okay?
    REDUCE_TOLERANCE => .001, #(inches) allow this much variation when reducing circles and rects
};

#Also, my CAD's Print function or the PDF print driver I used was a little off for circles, so define some additional adjustment values here:
#Values are added to X/Y coordinates; units are pixels; for example, a value of 1 at 600 dpi would be ~= .002 inch
use constant
{
    CIRCLE_ADJUST_MINX => 0,
    CIRCLE_ADJUST_MINY => -0.001 * 600, #-1, #circles were a little too high, so nudge them a little lower
    CIRCLE_ADJUST_MAXX => +0.001 * 600, #+1, #circles were a little too far to the left, so nudge them a little to the right
    CIRCLE_ADJUST_MAXY => 0,
    SUBST_CIRCLE_CLIPRECT => FALSE, #generate circle and substitute for clip rects (to compensate for the way some CAD software draws circles)
    WANT_CLIPRECT => TRUE, #FALSE, #AI doesn't need clip rect at all? should be on normally?
    RECT_COMPLETION => FALSE, #TRUE, #fill in 4th side of rect when 3 sides found
};

#allow .012 clearance around pads for solder mask:
#This value effectively adjusts pad sizes in the TOOL_SIZES list above (only for solder mask layers).
use constant SOLDER_MARGIN => +.012; #units are inches

#line join/cap styles:
use constant
{
    CAP_NONE => 0, #butt (none); line is exact length
    CAP_ROUND => 1, #round cap/join; line overhangs by a semi-circle at either end
    CAP_SQUARE => 2, #square cap/join; line overhangs by a half square on either end
    CAP_OVERRIDE => FALSE, #cap style overrides drawing logic
};
    
#number of elements in each shape type:
use constant
{
    RECT_SHAPELEN => 6, #x0, y0, x1, y1, count, "rect" (start, end corners)
    LINE_SHAPELEN => 6, #x0, y0, x1, y1, count, "line" (line seg)
    CURVE_SHAPELEN => 10, #xstart, ystart, x0, y0, x1, y1, xend, yend, count, "curve" (bezier 2 points)
    CIRCLE_SHAPELEN => 5, #x, y, 5, count, "circle" (center + radius)
};
#const my %SHAPELEN =
#Readonly my %SHAPELEN =>
our %SHAPELEN =
(
    rect => RECT_SHAPELEN,
    line => LINE_SHAPELEN,
    curve => CURVE_SHAPELEN,
    circle => CIRCLE_SHAPELEN,
);

#panelization:
#This will repeat the entire body the number of times indicated along the X or Y axes (files grow accordingly).
#Display elements that overhang PCB boundary can be squashed or left as-is (typically text or other silk screen markings).
#Set "overhangs" TRUE to allow overhangs, FALSE to truncate them.
#xpad and ypad allow margins to be added around outer edge of panelized PCB.
use constant PANELIZE => {'x' => 1, 'y' => 1, 'xpad' => 0, 'ypad' => 0, 'overhangs' => TRUE}; #number of times to repeat in X and Y directions

# Set this to 1 if you need TurboCAD support.
#$turboCAD = FALSE; #is this still needed as an option?

#CIRCAD pad generation uses an appropriate aperture, then moves it (stroke) "a little" - we use this to find pads and distinguish them from PCB holes. 
use constant PAD_STROKE => 0.3; #0.0005 * 600; #units are pixels
#convert very short traces to pads or holes:
use constant TRACE_MINLEN => .001; #units are inches
#use constant ALWAYS_XY => TRUE; #FALSE; #force XY even if X or Y doesn't change; NOTE: needs to be TRUE for all pads to show in FlatCAM and ViewPlot
use constant REMOVE_POLARITY => FALSE; #TRUE; #set to remove subtractive (negative) polarity; NOTE: must be FALSE for ground planes

#PDF uses "points", each point = 1/72 inch
#combined with a PDF scale factor of .12, this gives 600 dpi resolution (1/72 * .12 = 600 dpi)
use constant INCHES_PER_POINT => 1/72; #0.0138888889; #multiply point-size by this to get inches

# The precision used when computing a bezier curve. Higher numbers are more precise but slower (and generate larger files).
#$bezierPrecision = 100;
use constant BEZIER_PRECISION => 36; #100; #use const; reduced for faster rendering (mainly used for silk screen and thermal pads)

# Ground planes and silk screen or larger copper rectangles or circles are filled line-by-line using this resolution.
use constant FILL_WIDTH => .01; #fill at most 0.01 inch at a time

# The max number of characters to read into memory
use constant MAX_BYTES => 10 * M; #bumped up to 10 MB, use const

use constant DUP_DRILL1 => TRUE; #FALSE; #kludge: ViewPlot doesn't load drill files that are too small so duplicate first tool

my $runtime = time(); #Time::HiRes::gettimeofday(); #measure my execution time

print STDERR "Loaded config settings from '${\(__FILE__)}'.\n";
1; #last value must be truthful to indicate successful load


#############################################################################################
#junk/experiment:

#use Package::Constants;
#use Exporter qw(import); #https://perldoc.perl.org/Exporter.html

#my $caller = "pdf2gerb::";

#sub cfg
#{
#    my $proto = shift;
#    my $class = ref($proto) || $proto;
#    my $settings =
#    {
#        $WANT_DEBUG => 990, #10; #level of debug wanted; higher == more, lower == less, 0 == none
#    };
#    bless($settings, $class);
#    return $settings;
#}

#use constant HELLO => "hi there2"; #"main::HELLO" => "hi there";
#use constant GOODBYE => 14; #"main::GOODBYE" => 12;

#print STDERR "read cfg file\n";

#our @EXPORT_OK = Package::Constants->list(__PACKAGE__); #https://www.perlmonks.org/?node_id=1072691; NOTE: "_OK" skips short/common names

#print STDERR scalar(@EXPORT_OK) . " consts exported:\n";
#foreach(@EXPORT_OK) { print STDERR "$_\n"; }
#my $val = main::thing("xyz");
#print STDERR "caller gave me $val\n";
#foreach my $arg (@ARGV) { print STDERR "arg $arg\n"; }

Download Details:

Author: swannman
Source Code: https://github.com/swannman/pdf2gerb

License: GPL-3.0 license

#perl 

Arvel  Miller

Arvel Miller

1599762180

Setup a Simple Server-Side Application for Your Game Using Strapi.js

In the previous part, we successfully installed and ran a Strapi application. Now it is time to build the API. But first let’s take a close look at what a game server like this can provide us:

  • It can authenticate users.
  • We can implement game logics.
  • Users can see leaderboads.
  • We can change some of the game elements through the server.
  • and lots of other functionalities.

Controllers, Services and Routes

For building an API in Strapi, you need to understand 3 main concepts.

**Services: **Services serve as global methods which you can use everywhere in your application. Their main job is to reduce the use of some repeatable functions by being available globally.

**Controllers: **Controllers are the main part of your API. The main functions go here.

**Routes: **Routes are bounded to controller methods. They are actually Urls which are pointing to a specific method, so each time you call that Url the method gets executed.

Know that you’re familiar with these 3 concepts, we are ready to create a remote config system for our game.

Remote Config

Creating Model

Let’s say we have an RPG game with different heroes, hero types, buildings, maps, items and etc. Each hero has its own specifications such as damage power (if it is melee), range (if it’s of range type), health, mana and so many other parameters. These things need to be balanced and tweaked by game designers frequently. So it is not a good idea to put them inside the client. The best solution is to get all of those data from your server at the very beginning of the game and keep them for later use.

For creating such a functionality, the very first step is to create a model of data. It should be one single model to cover everything that need a config in the game, such as heroes, hero types, items and etc. So we need these fields:

  • **Name **(it defines to what specific part of the game, this object belongs)
  • **Type **(it tells us the type of this object)
  • **Data **(the main data that we want to tweak or adjust later)

Now that we have a model in mind, we open the Strapi’s admin panel:

Image for post

Strapi admin panel

here you can see that Strapi has already made a collection (or content-type) called Users. We need something like that for our Remote Config. A collection that stores our config data.

open the Content-Types Builder:

Image for post

under the Collection Types in the grey column, you can see the blue text saying Create new collection type. Click on it:

Image for post

a window pops open. In the Display name write Remote Config and press Continue. Now you can see this window:

Image for post

here you should create those 3 fields that we talked about. Name,_Type _and Data. For name you can choose _Text _or UID. I recommend you to select _UID _because it guarantees that the content of that field is unique in entire collection. So I select the UID:

Image for post

inside the Name field write name (with small letter because it’s better :) )

and click on +Add another field, For our _Type _field you can select Text:

Image for post

Image for post

#strapi #games #javascript #game-server #nodejs

NBB: Ad-hoc CLJS Scripting on Node.js

Nbb

Not babashka. Node.js babashka!?

Ad-hoc CLJS scripting on Node.js.

Status

Experimental. Please report issues here.

Goals and features

Nbb's main goal is to make it easy to get started with ad hoc CLJS scripting on Node.js.

Additional goals and features are:

  • Fast startup without relying on a custom version of Node.js.
  • Small artifact (current size is around 1.2MB).
  • First class macros.
  • Support building small TUI apps using Reagent.
  • Complement babashka with libraries from the Node.js ecosystem.

Requirements

Nbb requires Node.js v12 or newer.

How does this tool work?

CLJS code is evaluated through SCI, the same interpreter that powers babashka. Because SCI works with advanced compilation, the bundle size, especially when combined with other dependencies, is smaller than what you get with self-hosted CLJS. That makes startup faster. The trade-off is that execution is less performant and that only a subset of CLJS is available (e.g. no deftype, yet).

Usage

Install nbb from NPM:

$ npm install nbb -g

Omit -g for a local install.

Try out an expression:

$ nbb -e '(+ 1 2 3)'
6

And then install some other NPM libraries to use in the script. E.g.:

$ npm install csv-parse shelljs zx

Create a script which uses the NPM libraries:

(ns script
  (:require ["csv-parse/lib/sync$default" :as csv-parse]
            ["fs" :as fs]
            ["path" :as path]
            ["shelljs$default" :as sh]
            ["term-size$default" :as term-size]
            ["zx$default" :as zx]
            ["zx$fs" :as zxfs]
            [nbb.core :refer [*file*]]))

(prn (path/resolve "."))

(prn (term-size))

(println (count (str (fs/readFileSync *file*))))

(prn (sh/ls "."))

(prn (csv-parse "foo,bar"))

(prn (zxfs/existsSync *file*))

(zx/$ #js ["ls"])

Call the script:

$ nbb script.cljs
"/private/tmp/test-script"
#js {:columns 216, :rows 47}
510
#js ["node_modules" "package-lock.json" "package.json" "script.cljs"]
#js [#js ["foo" "bar"]]
true
$ ls
node_modules
package-lock.json
package.json
script.cljs

Macros

Nbb has first class support for macros: you can define them right inside your .cljs file, like you are used to from JVM Clojure. Consider the plet macro to make working with promises more palatable:

(defmacro plet
  [bindings & body]
  (let [binding-pairs (reverse (partition 2 bindings))
        body (cons 'do body)]
    (reduce (fn [body [sym expr]]
              (let [expr (list '.resolve 'js/Promise expr)]
                (list '.then expr (list 'clojure.core/fn (vector sym)
                                        body))))
            body
            binding-pairs)))

Using this macro we can look async code more like sync code. Consider this puppeteer example:

(-> (.launch puppeteer)
      (.then (fn [browser]
               (-> (.newPage browser)
                   (.then (fn [page]
                            (-> (.goto page "https://clojure.org")
                                (.then #(.screenshot page #js{:path "screenshot.png"}))
                                (.catch #(js/console.log %))
                                (.then #(.close browser)))))))))

Using plet this becomes:

(plet [browser (.launch puppeteer)
       page (.newPage browser)
       _ (.goto page "https://clojure.org")
       _ (-> (.screenshot page #js{:path "screenshot.png"})
             (.catch #(js/console.log %)))]
      (.close browser))

See the puppeteer example for the full code.

Since v0.0.36, nbb includes promesa which is a library to deal with promises. The above plet macro is similar to promesa.core/let.

Startup time

$ time nbb -e '(+ 1 2 3)'
6
nbb -e '(+ 1 2 3)'   0.17s  user 0.02s system 109% cpu 0.168 total

The baseline startup time for a script is about 170ms seconds on my laptop. When invoked via npx this adds another 300ms or so, so for faster startup, either use a globally installed nbb or use $(npm bin)/nbb script.cljs to bypass npx.

Dependencies

NPM dependencies

Nbb does not depend on any NPM dependencies. All NPM libraries loaded by a script are resolved relative to that script. When using the Reagent module, React is resolved in the same way as any other NPM library.

Classpath

To load .cljs files from local paths or dependencies, you can use the --classpath argument. The current dir is added to the classpath automatically. So if there is a file foo/bar.cljs relative to your current dir, then you can load it via (:require [foo.bar :as fb]). Note that nbb uses the same naming conventions for namespaces and directories as other Clojure tools: foo-bar in the namespace name becomes foo_bar in the directory name.

To load dependencies from the Clojure ecosystem, you can use the Clojure CLI or babashka to download them and produce a classpath:

$ classpath="$(clojure -A:nbb -Spath -Sdeps '{:aliases {:nbb {:replace-deps {com.github.seancorfield/honeysql {:git/tag "v2.0.0-rc5" :git/sha "01c3a55"}}}}}')"

and then feed it to the --classpath argument:

$ nbb --classpath "$classpath" -e "(require '[honey.sql :as sql]) (sql/format {:select :foo :from :bar :where [:= :baz 2]})"
["SELECT foo FROM bar WHERE baz = ?" 2]

Currently nbb only reads from directories, not jar files, so you are encouraged to use git libs. Support for .jar files will be added later.

Current file

The name of the file that is currently being executed is available via nbb.core/*file* or on the metadata of vars:

(ns foo
  (:require [nbb.core :refer [*file*]]))

(prn *file*) ;; "/private/tmp/foo.cljs"

(defn f [])
(prn (:file (meta #'f))) ;; "/private/tmp/foo.cljs"

Reagent

Nbb includes reagent.core which will be lazily loaded when required. You can use this together with ink to create a TUI application:

$ npm install ink

ink-demo.cljs:

(ns ink-demo
  (:require ["ink" :refer [render Text]]
            [reagent.core :as r]))

(defonce state (r/atom 0))

(doseq [n (range 1 11)]
  (js/setTimeout #(swap! state inc) (* n 500)))

(defn hello []
  [:> Text {:color "green"} "Hello, world! " @state])

(render (r/as-element [hello]))

Promesa

Working with callbacks and promises can become tedious. Since nbb v0.0.36 the promesa.core namespace is included with the let and do! macros. An example:

(ns prom
  (:require [promesa.core :as p]))

(defn sleep [ms]
  (js/Promise.
   (fn [resolve _]
     (js/setTimeout resolve ms))))

(defn do-stuff
  []
  (p/do!
   (println "Doing stuff which takes a while")
   (sleep 1000)
   1))

(p/let [a (do-stuff)
        b (inc a)
        c (do-stuff)
        d (+ b c)]
  (prn d))
$ nbb prom.cljs
Doing stuff which takes a while
Doing stuff which takes a while
3

Also see API docs.

Js-interop

Since nbb v0.0.75 applied-science/js-interop is available:

(ns example
  (:require [applied-science.js-interop :as j]))

(def o (j/lit {:a 1 :b 2 :c {:d 1}}))

(prn (j/select-keys o [:a :b])) ;; #js {:a 1, :b 2}
(prn (j/get-in o [:c :d])) ;; 1

Most of this library is supported in nbb, except the following:

  • destructuring using :syms
  • property access using .-x notation. In nbb, you must use keywords.

See the example of what is currently supported.

Examples

See the examples directory for small examples.

Also check out these projects built with nbb:

API

See API documentation.

Migrating to shadow-cljs

See this gist on how to convert an nbb script or project to shadow-cljs.

Build

Prequisites:

  • babashka >= 0.4.0
  • Clojure CLI >= 1.10.3.933
  • Node.js 16.5.0 (lower version may work, but this is the one I used to build)

To build:

  • Clone and cd into this repo
  • bb release

Run bb tasks for more project-related tasks.

Download Details:
Author: borkdude
Download Link: Download The Source Code
Official Website: https://github.com/borkdude/nbb 
License: EPL-1.0

#node #javascript

Setup a Simple Server-Side Application for Your Game Using Strapi.js — Part 1

“Note that this tutorial is done in Windows OS. For Linux you may need to make some changes and modifications ;)”

It’s a fact that having a server-side application, can help developers to add lots of functionalities to their games. They can have a score leaderboard, some game configs they want to change without client updates, occasional events, handling online asset bundles, validating purchases, or even implementing game logic on the server! And that’s just a few of the functionalities I’m talking about!

Today I’m going to introduce something that can help you meet your very basic needs for a game web application. Something that you can easily deploy on a server (Windows/Linux) and use it in a game, no matter what engine or tool you’re using (Unity, Unreal, Game Maker, …).

#unity #strapi #game-server #nodejs #web-applications

Zachary Palmer

Zachary Palmer

1555901576

CSS Flexbox Tutorial | Build a Chat Application

Creating the conversation sidebar and main chat section

In this article we are going to focus on building a basic sidebar, and the main chat window inside our chat shell. See below.

Chat shell with a fixed width sidebar and expanded chat window

This is the second article in this series. You can check out the previous article for setting up the shell OR you can just check out the chat-shell branch from the following repository.

https://github.com/lyraddigital/flexbox-chat-app.git

Open up the chat.html file. You should have the following HTML.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Chat App</title>
    <link rel="stylesheet" type="text/css" media="screen" href="css/chat.css" />
</head>
<body>
    <div id="chat-container">
    </div>
</body>
</html>

Now inside of the chat-container div add the following HTML.

<div id="side-bar">
</div>
<div id="chat-window">
</div>

Now let’s also add the following CSS under the #chat-container selector in the chat.css file.

#side-bar {
    background: #0048AA;
    border-radius: 10px 0 0 10px;
}
#chat-window {
    background: #999;
    border-radius: 0 10px 10px 0;
}

Now reload the page. You should see the following:-

So what happened? Where is our sidebar and where is our chat window? I expected to see a blue side bar and a grey chat window, but it’s no where to be found. Well it’s all good. This is because we have no content inside of either element, so it can be 0 pixels wide.

Sizing Flex Items

So now that we know that our items are 0 pixels wide, let’s attempt to size them. We’ll attempt to try this first using explicit widths.

Add the following width property to the #side-bar rule, then reload the page.

width: 275px;

Hmm. Same result. It’s still a blank shell. Oh wait I have to make sure the height is 100% too. So we better do that too. Once again add the following property to the #side-bar rule, then reload the page.

height: 100%;

So now we have our sidebar that has grown to be exactly 275 pixels wide, and is 100% high. So that’s it. We’re done right? Wrong. Let me ask you a question. How big is the chat window? Let’s test that by adding some text to it. Try this yourself just add some text. You should see something similar to this.

So as you can see the chat window is only as big as the text that’s inside of it, and it is not next to the side bar. And this makes sense because up until now the chat shell is not a flex container, and just a regular block level element.

So let’s make our chat shell a flex container. Set the following display property for the #chat-window selector. Then reload the page.

display: flex;

So as you can see by the above illustration, we can see it’s now next to the side bar, and not below it. But as you can see currently it’s only as wide as the text that’s inside of it.

But we want it to take up the remaining space of the chat shell. Well we know how to do this, as we did it in the previous article. Set the flex-grow property to 1 on the #chat-window selector. Basically copy and paste the property below and reload the page.

flex-grow: 1;

So now we have the chat window taking up the remaining space of the chat shell. Next, let’s remove the background property, and also remove all text inside the chat-window div if any still exists. You should now see the result below.

But are we done? Technically yes, but before we move on, let’s improve things a little bit.

Understanding the default alignment

If you remember, before we had defined our chat shell to be a flex container, we had to make sure we set the height of the side bar to be 100%. Otherwise it was 0 pixels high, and as a result nothing was displayed. With that said, try removing the height property from the #side-bar selector and see what happens when you reload the page. Yes that’s right, it still works. The height of the sidebar is still 100% high.

So what happened here? Why do we no longer have to worry about setting the height to 100%? Well this is one of the cool things Flexbox gives you for free. By default every flex item will stretch vertically to fill in the entire height of the flex container. We can in fact change this behaviour, and we will see how this is done in a future article.

Setting the size of the side bar properly

So another feature of Flexbox is being able to set the size of a flex item by using the flex-basis property. The flex-basis property allows you to specify an initial size of a flex item, before any growing or shrinking takes place. We’ll understand more about this in an upcoming article.

For now I just want you to understand one important thing. And that is using width to specify the size of the sidebar is not a good idea. Let’s see why.

Say that potentially, if the screen is mobile we want the side bar to now appear across the top of the chat shell, acting like a top bar instead. We can do this by changing the direction flex items can flex inside a flex container. For example, add the following CSS to the #chat-container selector. Then reload the page.

flex-direction: column;

So as you can see we are back to a blank shell. So firstly let’s understand what we actually did here. By setting the flex-direction property to column, we changed the direction of how the flex items flex. By default flex items will flex from left to right. However when we set flex-direction to column, it changes this behaviour forcing flex items to flex from top to bottom instead. On top of this, when the direction of flex changes, the sizing and alignment of flex items changes as well.

When flexing from left to right, we get a height of 100% for free as already mentioned, and then we made sure the side bar was set to be 275 pixels wide, by setting the width property.

However now that we a flexing from top to bottom, the width of the flex item by default would be 100% wide, and you would need to specify the height instead. So try this. Add the following property to the #side-bar selector to set the height of the side bar. Then reload the page.

height: 275px;

Now we are seeing the side bar again, as we gave it a fixed height too. But we still have that fixed width. That’s not what we wanted. We want the side bar (ie our new top bar) here to now be 100% wide. Comment out the width for a moment and reload the page again.

So now we were able to move our side bar so it appears on top instead, acting like a top bar. Which as previously mentioned might be suited for mobile device widths. But to do this we had to swap the value of width to be the value of height. Wouldn’t it be great if this size was preserved regardless of which direction our items are flexing.

Try this, remove all widths and height properties from the #side-bar selector and write the following instead. Then reload the page.

flex-basis: 275px;

As you can see we get the same result. Now remove the flex-direction property from the #chat-container selector. Then once again reload the page.

Once again we are back to our final output. But now we also have the flexibility to easily change the side bar to be a top bar if we need to, by just changing the direction items can flow. Regardless of the direction of flex, the size of our side bar / top bar is preserved.

Conclusion

Ok so once again we didn’t build much, but we did cover a lot of concepts about Flexbox around sizing. 

#css #programming #webdev