GithubHelp home page GithubHelp logo

termloop's Introduction

Termloop

Join the chat at https://gitter.im/JoelOtter/termloop GoDoc

Termloop is a pure Go game engine for the terminal, built on top of the excellent Termbox. It provides a simple render loop for building games in the terminal, and is focused on making terminal game development as easy and as fun as possible.

Termloop is still under active development so changes may be breaking. I add any breaking changes to the Changelog - hopefully at this stage there shouldn't be too many. Pull requests and issues are very welcome, and do feel free to ask any questions you might have on the Gitter. I hope you enjoy using Termloop; I've had a blast making it.

Installing

Install and update with go get -u github.com/JoelOtter/termloop

Features

  • Keyboard and mouse input
  • Collision detection
  • Render timers
  • Level offsets to simulate 'camera' movement
  • Debug logging
  • Built-in entity types such as:
  • Framerate counters
  • Rectangles
  • Text
  • Loading entities from ASCII art
  • Loading colour maps from images
  • Loading level maps from JSON
  • Optional 'pixel mode' - draw two 'pixels' to a terminal character, doubling screen height at the expense of being able to render text.
  • Pure Go - easy portability of compiled games, and cross-compilation built right in.

To see what's on the roadmap, have a look at the issue tracker.

termloop/extra

The Termloop extras are a collection of types and functions, the use of which will not result in a fully portable binary - that is, they have some external dependencies. However, if you're willing to require these dependencies in your project, they should integrate quite nicely with the rest of Termloop. Some of the included examples use these extras.

  • Audio playback
  • audio.go
  • Requirements: PortAudio and libsndfile

Cool stuff built with Termloop

Feel free to add yours with a pull request!

Tutorial

More full documentation will be added to the Wiki soon. In the meantime, check out this tutorial, the GoDoc, or the included examples. If you get stuck during this tutorial, worry not, the full source is here.

Creating a blank Termloop game is as simple as:

package main

import tl "github.com/JoelOtter/termloop"

func main() {
	game := tl.NewGame()
	game.Start()
}

We can press Ctrl+C to exit. It's just a blank screen - let's make it a little more interesting.

Let's make a green background, because grass is really nice to run around on. We create a new level like so:

level := tl.NewBaseLevel(tl.Cell{
	Bg: tl.ColorGreen,
	Fg: tl.ColorBlack,
	Ch: 'v',
})

Cell is a struct that represents one cell on the terminal. We can set its background and foreground colours, and the character that is displayed. Creating a BaseLevel in this way will fill the level with this Cell.

Let's make a nice pretty lake, too. We'll use a Rectangle for this. We'll put the lake at position (10, 10), with width 50 and height 20. All measurements are in terminal characters! The last argument is the colour of the Rectangle.

level.AddEntity(tl.NewRectangle(10, 10, 50, 20, tl.ColorBlue))

We don't need to use a Level - we can add entities directly to the Screen! This is great for building a HUD, or a very simple app. However, if we want camera scrolling or collision detection, we're going to need to use a Level.

Putting together what we have so far:

package main

import tl "github.com/JoelOtter/termloop"

func main() {
	game := tl.NewGame()
	level := tl.NewBaseLevel(tl.Cell{
		Bg: tl.ColorGreen,
		Fg: tl.ColorBlack,
		Ch: 'v',
	})
	level.AddEntity(tl.NewRectangle(10, 10, 50, 20, tl.ColorBlue))
	game.Screen().SetLevel(level)
	game.Start()
}

When we run it with go run tutorial.go, it looks like this:

Pretty! Ish. OK, let's create a character that can walk around the environment. We're going to use object composition here - we'll create a new struct type, which extends an Entity.

To have Termloop draw our new type, we need to implement the Drawable interface, which means we need two methods: Draw() and Tick(). The Draw method defines how our type is drawn to the Screen (Termloop's internal drawing surface), and the Tick method defines how we handle input.

We don't need to do anything special for Draw, and it's already handled by Entity, so we just need a Tick:

type Player struct {
	*tl.Entity
}

func (player *Player) Tick(event tl.Event) {
	if event.Type == tl.EventKey { // Is it a keyboard event?
		x, y := player.Position()
		switch event.Key { // If so, switch on the pressed key.
		case tl.KeyArrowRight:
			player.SetPosition(x+1, y)
		case tl.KeyArrowLeft:
			player.SetPosition(x-1, y)
		case tl.KeyArrowUp:
			player.SetPosition(x, y-1)
		case tl.KeyArrowDown:
			player.SetPosition(x, y+1)
		}
	}
}

Now that we've built our Player type, let's add one to the level. I'm going to use the character '옷', because I think it looks a bit like a stick man.

player := Player{tl.NewEntity(1, 1, 1, 1)}
// Set the character at position (0, 0) on the entity.
player.SetCell(0, 0, &tl.Cell{Fg: tl.ColorRed, Ch: '옷'})
level.AddEntity(&player)

Running the game again, we see that we can now move around the map using the arrow keys. Neato! However, we can stroll across the lake just as easily as the grass. Our character isn't the Messiah, he's a very naughty boy, so let's add some collisions.

In Termloop, we have two interfaces that are used for collisions. Here they are.

// Physical represents something that can collide with another
// Physical, but cannot process its own collisions.
// Optional addition to Drawable.
type Physical interface {
	Position() (int, int) // Return position, x and y
	Size() (int, int)     // Return width and height
}

// DynamicPhysical represents something that can process its own collisions.
// Implementing this is an optional addition to Drawable.
type DynamicPhysical interface {
	Position() (int, int) // Return position, x and y
	Size() (int, int)     // Return width and height
	Collide(Physical)     // Handle collisions with another Physical
}

It's pretty simple - if we want our object to be 'solid', then we implement Physical. If we want a solid object that actually does some processing on its own collisions, we implement DynamicPhysical! Essentially this just involves adding one more method to your type.

Note that, for performance reasons, you should try and have as few DynamicPhysicals as possible - for example, our Player will be one, but the lake need only be a Physical.

The Rectangle type already implements Physical, so we don't actually need to do anything. As well, Player already implements DynamicPhysical because of the embedded Entity. However, we want custom behaviour for Collide, so let's implement that method. For that, we'll have to modify our struct and Tick method, to keep track of the Player's previous position so we can move it back there if it collides with something.

type Player struct {
	*tl.Entity
	prevX  int
	prevY  int
}

func (player *Player) Tick(event tl.Event) {
	if event.Type == tl.EventKey { // Is it a keyboard event?
		player.prevX, player.prevY = player.Position()
		switch event.Key { // If so, switch on the pressed key.
		case tl.KeyArrowRight:
			player.SetPosition(player.prevX+1, player.prevY)
		case tl.KeyArrowLeft:
			player.SetPosition(player.prevX-1, player.prevY)
		case tl.KeyArrowUp:
			player.SetPosition(player.prevX, player.prevY-1)
		case tl.KeyArrowDown:
			player.SetPosition(player.prevX, player.prevY+1)
		}
	}
}

func (player *Player) Collide(collision tl.Physical) {
	// Check if it's a Rectangle we're colliding with
	if _, ok := collision.(*tl.Rectangle); ok {
		player.SetPosition(player.prevX, player.prevY)
	}
}

Not too much extra code! We can now see that the Player can't walk out into the lake. If you see the Player overlap the lake slightly on one side, that's likely because the 'stick man' character we used isn't quite standard width.

We've now got something that looks a bit like a very simple exploration game. There's one more thing to add - let's have the camera scroll to keep the Player in the centre of the screen!

There isn't really a 'camera' in Termloop, like you might find in another graphics library. Instead, we set an offset, and the Screen draws our level appropriately. In our case it's really simple - all we need is for the Player to have a pointer to the Level, so we can make calls on it. Then we simply modify our Draw method, like so:

type Player struct {
	*tl.Entity
	prevX  int
	prevY  int
	level  *tl.BaseLevel
}

func (player *Player) Draw(screen *tl.Screen) {
	screenWidth, screenHeight := screen.Size()
	x, y := player.Position()
	player.level.SetOffset(screenWidth/2-x, screenHeight/2-y)
  // We need to make sure and call Draw on the underlying Entity.
	player.Entity.Draw(screen)
}


// in func main
player := Player{
	Entity:   tl.NewEntity(1, 1, 1, 1),
	level: level,
}

That's all it takes. We should now see the camera moving. Of course, due to the static, repeating background, this doesn't look terribly convincing - it kind of looks like the player is standing still and everything else is moving! We could remedy this by, for example, only updating the offset when the player is closer to the edge of the screen. I'll leave it up to you as a challenge.

We've now reached the end of our tutorial - I hope it's been useful! If you'd like to learn a little more about Termloop, more comprehensive documentation is coming on the Wiki. In the meantime, you can check out the GoDoc, or the included examples. I'll be hanging out on the Gitter too, if you have any questions. Have fun, and please do show me if you make something cool!

termloop's People

Contributors

afagundes avatar aquilax avatar ariemeth avatar bmatsuo avatar buckley-w-david avatar cam73 avatar davidlarsketch avatar fern4lvarez avatar fokoenecke avatar gitter-badger avatar gmoshkin avatar jodizzle avatar joelotter avatar kschmit90 avatar lucasew avatar mattkelly avatar ryanbaer avatar scottbrooks avatar svera avatar swapagarwal avatar terrysolar avatar tristangoossens avatar zladovan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

termloop's Issues

Termloop abruptly stops

Sometimes Termloop will simply stop, outputting no useful information, even if debugging is turned on.

If you've noticed this happening, please post your configuration as a comment. Here's mine:

OS: Mac OS X 10.10.5 (Yosemite)
Go version: 1.5
Terminal: iTerm2 + tmux

Investigate performance enhancements

Termloop's performance is acceptable for most applications, but that doesn't mean we shouldn't try and make it better. Let's use this issue to track ideas for improving performance. A couple of potential things to investigate:

  • Use a pointer to an Event instead of an Event in Tick methods. This may save some extraneous copying.
  • Process Tick events in parallel using a worker pool (can't do this for Draw as the order matters for rendering 'depth')

Feel free to add more in comments.

Key events not working

Having a weird issue.
I'm trying the examples on Linux. With collision.go, key events work. Esc exits, arrow keys move.
With movingtext.go however, I cannot exit with Esc, and arrow keys don't work. I'm also going through the tutorial, and there Esc doesn't exit either. It's as if the Entity's Tick never gets called.

CJK Text cannot been displayed correctly

when using the Text component, if the text string is CJK, eg "你好啊", it will only show "你啊". As far as I understand, this is because CJK need two Cell to render. if what i understand is right, i'll make a pull request to fix this.

Update mouse handling

Termbox has added support for additional mouse events, including mouse wheel and release detection.
Support for this should be added to Termloop - however, as these new features are currently not supported on Windows, it might be better to add them to termloop/extras, or simply wait.

can not update entity position safely outside Tick()

This is the current game loop for BaseLevel:

1. Tick
2. Check Collisions
3. Draw

However, Tick() is only called if there is an event. This means I can not update the entity position based on frame time. For example, I want to move an entity forward every X frames. This would currently only be possible in Draw() which is called after collision checks, so it is unsafe. Moving an entity inside Draw() allows it to be inside another entity, although collision checks should prevent that.

Since BaseLevel has a lot of features I would like to use, I don't want to write my own. I think this should be fixed and BaseLevel should call Tick on all its entities on every frame and let the entity decide if it wants to react on keyboard input or just the frame being updated.

Same goes for Screen.Tick()

Is there any specific reason you drop all EventNone events?

Update transparent cells for the entity canvas

Hi! I am trying to learn some Go and love your terminal libraries for starting some fun projects. Thank You!

I am creating an entity that has different orientations depending on which direction it is facing. That entity has some transparent pixels on it. On loading the entity, I create a new canvas for every orientation and keep a pointer to them. If the orientation of my entity changes, I use ApplyCanvas() to apply the according canvas to the underlying entity's canvas. Unfortunately, when the orientation changes, the transparent pixel won't apply, if there is already a color defined (renderCell() in screen.go). So the previous color for that pixel shows up, where a transparent one should be.

I understand why it's necessary to do this when drawing on a background, but would it be possible to use another function, that applies all pixels (including transparent) when not rendering to the screen, but on an internal(~sprite) canvas? What I did as a workaround, is using a special "Sprite" render Method and use this in ApplyCanvas().

func renderSpriteCell(old, new_ *Cell) {
	old.Ch = new_.Ch
	old.Bg = new_.Bg
	old.Fg = new_.Fg
}

func (e *Entity) ApplyCanvas(c *Canvas) {
	for i := 0; i < min(len(e.canvas), len(*c)); i++ {
		for j := 0; j < min(len(e.canvas[0]), len((*c)[0])); j++ {
			renderSpriteCell(&e.canvas[i][j], &(*c)[i][j])
		}
	}
}

In a real solution you wold need to use that in all relevant functions, I guess. Unfortunately I don't understand the implications of such change and don't feel confident in supplying a pull request.

Greetings!

crash on SetPostion

#i have a program that changes some text's position, from a go routine, and occasionally i get this crash;

panic: runtime error: index out of range

goroutine 1 [running]:
github.com/JoelOtter/termloop.(*Text).Draw(0xc420014500, 0xc420092000)
/home/simon/gocode/src/github.com/JoelOtter/termloop/text.go:39 +0xdd
github.com/JoelOtter/termloop.(*Screen).Draw(0xc420092000)
/home/simon/gocode/src/github.com/JoelOtter/termloop/screen.go:54 +0xb9
github.com/JoelOtter/termloop.(*Game).Start(0xc420012510)
/home/simon/gocode/src/github.com/JoelOtter/termloop/game.go:115 +0x3f9
main.main()
/home/simon/Dropbox/github/working/moving/text.go:31 +0xfa

code.....

package main

import "github.com/JoelOtter/termloop"
import "github.com/splace/joysticks"
import "fmt"

func main() {
	g := termloop.NewGame()
	m:=termloop.NewText(60, 20, "<0,0>", termloop.ColorWhite, termloop.ColorBlue)
	g.Screen().AddEntity(m)


	go func(){
		evtChans := joysticks.Capture(
			joysticks.Channel{1, joysticks.HID.OnMove},
			joysticks.Channel{1, joysticks.HID.OnClose},
		)
		pos:=joysticks.PositionFromVelocity(evtChans[0])
		for{
			select {
			case evt:= <-pos:
				posEvt:=evt.(joysticks.CoordsEvent)
				m.SetText(fmt.Sprintf("<%1.2f,%1.2f>",posEvt.X,posEvt.Y))
				m.SetPosition(int(posEvt.X*80+60), int(posEvt.Y*80+20))
			case <-evtChans[1]:
				return
			}
		}	
	}()
	g.SetEndKey(termloop.KeyEnd)
	g.Start()
}

Expose Entities slice in Screen/BaseLevel

After discussion with community members on Gitter, it was decided that this would be a very useful feature to have - for example, one would be able to reorder entities, thereby dictating which is drawn on top of which.

Drawing a Rectangle after game.start()?

Hello,

I want to draw a border around the screen by using Rectangles. Depending on the screen size the rectangles have to be placed.
Because game.Screen().Size() returns (0,0) if it's called before game.start(), I have to add the Rectangles afterwards.

But the rectangles don't show up after I add them with AddEntity() to the level.
I also tried to call the Draw() method but it doesn't show any effect.

What is the correct way to draw new entities after game.Start() was called?

my code:

package main


import tl "github.com/JoelOtter/termloop"                                                                                  
import "fmt"                                                                                                               

func main() {                                                                                                              
        game := tl.NewGame()                                                                                               
        game.SetDebugOn(true)                                                                                              
        level := tl.NewBaseLevel(tl.Cell{                                                                                  
                Bg: tl.ColorBlack,                                                                                         
                Fg: tl.ColorWhite,                                                                                         
        })                                                                                                                 
        game.Screen().SetLevel(level)                                                                                      

        //x, y := game.Screen().Size()                                                                                     
        //fmt.Printf("before start x: %v, y: %v\n", x, y)                                                                  
        game.Start()                                                                                                       
        x, y = game.Screen().Size()                                                                                        
        //fmt.Printf("after start x: %v, y: %v\n", x, y)                                                                   

        r := tl.NewRectangle(x, y, 1, 1, tl.ColorRed)                                                                      
        level.AddEntity(r)                                                                                                 
        //r.Draw(game.Screen())                                                                                            
        //game.Screen().Draw()                                                                                             
}   

Incorrect mouse handling in pixel mode.

As far as I understand, mouse event coordinates correspond to the terminal cell positions, and no support for pixel mode (where every terminal cell contains two pixels) was implemented. The problem can be observed buy enabling the pixel mode in the click.go example.

Example throwing error : Image.go

panic: runtime error: index out of range

goroutine 1 [running]:
github.com/nsf/termbox-go.cell_to_char_info(0x59000000000000, 0x0)
        C:/Users/#/Documents/GoProjects/src/github.com/nsf/termbox-go/termbox_windows.go:526 +0x18b
github.com/nsf/termbox-go.append_diff_line(0xe, 0x78)
        C:/Users/#/Documents/GoProjects/src/github.com/nsf/termbox-go/termbox_windows.go:466 +0xe0
github.com/nsf/termbox-go.prepare_diff_messages()
        C:/Users/#/Documents/GoProjects/src/github.com/nsf/termbox-go/termbox_windows.go:510 +0x265
github.com/nsf/termbox-go.Flush(0x0, 0x0)
        C:/Users/#/Documents/GoProjects/src/github.com/nsf/termbox-go/api_windows.go:109 +0x42
github.com/JoelOtter/termloop.(*Screen).Draw(0xc082010090)
        C:/Users/#/Documents/GoProjects/src/github.com/JoelOtter/termloop/screen.go:65 +0x32f
github.com/JoelOtter/termloop.(*Game).Start(0xc08204e4b0)
        C:/Users/#/Documents/GoProjects/src/github.com/JoelOtter/termloop/game.go:115 +0x51f
main.main()
        C:/Users/#/Documents/GoProjects/src/Delilah/main.go:54 +0x220

goroutine 13 [chan send]:
github.com/JoelOtter/termloop.poll(0xc082006740)
        C:/Users/#/Documents/GoProjects/src/github.com/JoelOtter/termloop/input.go:33 +0x9a
created by github.com/JoelOtter/termloop.(*input).start
        C:/Users/#/Documents/GoProjects/src/github.com/JoelOtter/termloop/input.go:19 +0x3c

Above Error encountered when running the image.go example. Used random png, jpeg files. Nothing worked. Thank you :)

Screen size before game.Start()

I hit an existential chicken-egg issue. Is there a way to get the screen size before game.Start()? game.Screen().Size() returns 0, 0

Canvas background and foreground colors

I can't choose cell's foreground and background colors when loading canvas from string. Wouldn't it be interesting to add two colors arguments to the function ?

Programatic way to stop termloop

Is there a way to programatically stop a termloop Game object? There is a Start function but no stop far as I can tell. Only way is to press key so far.

Testing Termloop

We don't really have any tests other than running the included examples. If anyone has any ideas about the best way to go about this, please say!

Termloop tutorial

The tutorial in the README, along with the GoDoc, serve as a reasonable introduction. However, I think it'd be useful to have some more comprehensive documentation written, along with several tutorials on how to use Termloop's perhaps more-obscure features. We could host on GitHub Pages, which would keep it as part of this repo (just uses a separate branch).

How to Have Fixed Position Text

I'm trying to create an in-game hud using a Text object that's position is always fixed to the top-left corner of the screen.

I can get the text to the correct position sorta but it will not be perfectly fixed. It moves to the desired position when the whole screen updates next but it creates this laggy looking effect where part of the grid coordinates gets cut off or appear off screen for a short time.

Here's what I got in code so far (its chopped out but here is the important bits):

type GridCoordinates struct {
	*tl.Text
}

// positions the coords Text object in top-left.
func (m *GridCoordinates) Tick(ev tl.Event) {
	// plr is the player object
	mx, my := m.Position()
	x, y := plr.Position()
	sx, sy := game.Screen().Size()
	finx := x - sx/2
	finy := y - sy/2
	if finx != mx || finy != my {
		crd := "x" + strconv.Itoa(x) + ",y" + strconv.Itoa(y)
		m.SetPosition(x-sx/2, y-sy/2)
		m.SetText(crd)
	}
}

GridText := tl.NewText(0, 0, "x0,y0", tl.ColorWhite, tl.ColorBlue)
coords = GridCoordinates{GridText}
level.AddEntity(&coords)

This is the visual result:

image

How could I get some Text to always stay fixed in the upper left hand corner?

not escaping

for me, go1.8, this doesn't stop when hitting esc key.

package main
import "github.com/JoelOtter/termloop"
func main() {
	g := termloop.NewGame()
	m:=termloop.NewText(0, 0, "<=0=>", termloop.ColorWhite, termloop.ColorBlue)
	g.Screen().AddEntity(m)
	g.Start()
}

Basic audio playback

Probably using PortAudio for cross-platform compatibility. Should be able to:

  • Load sounds into memory
  • Play sounds
  • Stop playback
  • Loop

Change background color?

I'm trying to implement a Day/Night cycle (right now by simply cycling green from 55 to 255), but it is unclear to me how to change the Background color.

This is my code currently (run as a goroutine), but unfortunately it does not work...

func DayNight(level tl.Level, l *tl.Cell, s *tl.Screen) { // "l" is the background for "level"
        ticker := time.NewTicker(100 * time.Millisecond)
        sunRise := true
        sunSet := false

        color := 55

        for {
                select {
                case <- ticker.C:
                        if color >= 255 {
                                sunRise = false
                                sunSet = true
                        }
                        if color <= 55 {
                                sunRise = true
                                sunSet = false
                        }
                        if sunRise == true {
                                color = color + 1
                        }
                        if sunSet == true {
                                color = color - 1
                        }
                        l.Bg = tl.RgbTo256Color(0, color, 0)
                        level.DrawBackground(s)
                }
        }
}
func main() {
        g := tl.NewGame()
        levelCell := tl.Cell {
                Bg: tl.RgbTo256Color(0, 51, 0),
                Fg: tl.ColorBlack,
                Ch: 'v',
        }
        level := tl.NewBaseLevel(levelCell)
        go DayNight(level, &levelCell, g.Screen())
        level.AddEntity(tl.NewRectangle(10, 10, 50, 20, tl.ColorBlue))
        g.Screen().SetLevel(level)
        g.Start()
}

Some UTF-8 Runes take up more than one position horizontally.

For example, let's assume we decode the following rune for a TREE and set it into a cell:

				r, _ := utf8.DecodeRuneInString("\xF0\x9F\x8C\xB2")
				cell = tl.Cell{Fg: tl.ColorWhite, Ch: r}

What happens is that the true will fill in two spaces horizontally. If you attempt to insert two trees next to one another you will only see the tree on the left. I think this has something to do with the code taking into account the length of the rune in bytes as opposed to the glyph. The later takes up only one location on the screen.

Incidentally I appreciate your work here. Great work. I just wanted you to know. Thanks you!

Not possible to get screen width and height before game.Start() is called

I want to create monsters randomly on the field. But game.Screen().Size() has zeros as width and height and I cannot call rand with width and height as parameters. They are get defined only after termbox.Init() and this is done in the Start() method, so I need to wait till game is started.

Is it made on purpose? Can we init term at the moment of game creation or split Start() method onto Init() and Run() ?

Entity creation from asset files

Defining entities cell-by-cell in code is irritating. Ideally, one should be able to provide a pre-made file, which Termloop could read and create entities from.

Possible asset types:

  • Text files for characters
  • Images for colours; could have a foreground and background image. One pixel == one terminal character's colour.
  • Possibly some kind of map representation, similar to TMX.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.