diff --git a/cmd/tools/modules/testing/common.v b/cmd/tools/modules/testing/common.v
index 68d0c5d276..f350582364 100644
--- a/cmd/tools/modules/testing/common.v
+++ b/cmd/tools/modules/testing/common.v
@@ -209,7 +209,7 @@ pub fn v_build_failing(zargs string, folder string) bool {
 	return v_build_failing_skipped(zargs, folder, [])
 }
 
-pub fn v_build_failing_skipped(zargs string, folder string, skipped []string) bool {
+pub fn v_build_failing_skipped(zargs string, folder string, oskipped []string) bool {
 	main_label := 'Building $folder ...'
 	finish_label := 'building $folder'
 	vexe := pref.vexe_path()
@@ -221,6 +221,7 @@ pub fn v_build_failing_skipped(zargs string, folder string, skipped []string) bo
 	mut session := new_test_session(vargs)
 	files := os.walk_ext(os.join_path(parent_dir, folder), '.v')
 	mut mains := []string{}
+	mut skipped := oskipped
 	for f in files {
 		if !f.contains('modules') && !f.contains('preludes') {
 			//$if !linux {
@@ -240,6 +241,13 @@ pub fn v_build_failing_skipped(zargs string, folder string, skipped []string) bo
 					continue
 				}
 			}
+			c := os.read_file(f) or { panic(err) }
+			maxc := if c.len > 300 { 300 } else { c.len }
+			start := c[0..maxc]
+			if start.contains('module ') && !start.contains('module main') {
+				skipped_f := f.replace(os.join_path(parent_dir,''), '')
+				skipped << skipped_f
+			}
 			mains << f
 		}
 	}
diff --git a/examples/sokol/particles/main.v b/examples/sokol/particles/main.v
new file mode 100644
index 0000000000..6a721fca9b
--- /dev/null
+++ b/examples/sokol/particles/main.v
@@ -0,0 +1,138 @@
+// Copyright(C) 2019 Lars Pontoppidan. All rights reserved.
+// Use of this source code is governed by an MIT license file distributed with this software package
+module main
+
+import time
+import sokol
+import sokol.sapp
+import sokol.gfx
+import sokol.sgl
+import particle
+
+const (
+	used_import = sokol.used_import
+)
+
+fn main() {
+	app := &App{
+		width: 800
+		height: 400
+		pass_action: gfx.create_clear_pass(0.1, 0.1, 0.1, 1.0)
+	}
+	app.init()
+	app.run()
+}
+
+struct App {
+	pass_action C.sg_pass_action
+mut:
+	width       int
+	height      int
+	frame       i64
+	last        i64
+	ps          particle.System
+}
+
+fn (mut a App) init() {
+	a.frame = 0
+	a.last = time.ticks()
+	a.ps = particle.System{a.width, a.height}
+	a.ps.init(particle.SystemConfig{
+		pool: 20000
+	})
+}
+
+fn (mut a App) cleanup() {
+	a.ps.free()
+}
+
+fn (a App) run() {
+	title := 'V Particle Example'
+	desc := C.sapp_desc {
+		width: a.width
+		height: a.height
+		user_data: &a
+		init_userdata_cb: init
+		frame_userdata_cb: frame
+		event_userdata_cb: event
+		window_title: title.str
+		html5_canvas_name: title.str
+		cleanup_userdata_cb: cleanup
+	}
+	sapp.run(&desc)
+}
+
+fn (a App) draw() {
+	a.ps.draw()
+}
+
+fn init(user_data voidptr) {
+	desc := C.sg_desc {
+		mtl_device: sapp.metal_get_device()
+		mtl_renderpass_descriptor_cb: sapp.metal_get_renderpass_descriptor
+		mtl_drawable_cb: sapp.metal_get_drawable
+		d3d11_device: sapp.d3d11_get_device()
+		d3d11_device_context: sapp.d3d11_get_device_context()
+		d3d11_render_target_view_cb: sapp.d3d11_get_render_target_view
+		d3d11_depth_stencil_view_cb: sapp.d3d11_get_depth_stencil_view
+	}
+	gfx.setup(&desc)
+	sgl_desc := C.sgl_desc_t{
+		max_vertices: 50 * 65536
+	}
+	sgl.setup(&sgl_desc)
+}
+
+fn cleanup(user_data voidptr) {
+	mut app := &App(user_data)
+	app.cleanup()
+	gfx.shutdown()
+}
+
+fn frame(user_data voidptr) {
+	mut app := &App(user_data)
+	app.width = sapp.width()
+	app.height = sapp.height()
+	t := time.ticks()
+	dt := f64(t - app.last) / 1000.0
+	app.ps.update(dt)
+	draw(app)
+	gfx.begin_default_pass(&app.pass_action, app.width, app.height)
+	sgl.draw()
+	gfx.end_pass()
+	gfx.commit()
+	app.frame++
+	app.last = t
+}
+
+fn event(ev &C.sapp_event, user_data voidptr) {
+	mut app := &App(user_data)
+	if ev.@type == .mouse_move {
+		app.ps.explode(ev.mouse_x, ev.mouse_y)
+	}
+	if ev.@type == .mouse_up || ev.@type == .mouse_down {
+		if ev.mouse_button == .left {
+			is_pressed := ev.@type == .mouse_down
+			if is_pressed {
+				app.ps.explode(ev.mouse_x, ev.mouse_y)
+			}
+		}
+	}
+	if ev.@type == .key_up || ev.@type == .key_down {
+		if ev.key_code == .r {
+			is_pressed := ev.@type == .key_down
+			if is_pressed {
+				app.ps.reset()
+			}
+		}
+	}
+}
+
+fn draw(a &App) {
+	sgl.defaults()
+	sgl.matrix_mode_projection()
+	sgl.ortho(0, f32(sapp.width()), f32(sapp.height()), 0.0, -1.0, 1.0)
+	sgl.push_matrix()
+	a.draw()
+	sgl.pop_matrix()
+}
diff --git a/examples/sokol/particles/particle/LICENSE b/examples/sokol/particles/particle/LICENSE
new file mode 100644
index 0000000000..1595a57ad2
--- /dev/null
+++ b/examples/sokol/particles/particle/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Lars Pontoppidan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/examples/sokol/particles/particle/color.v b/examples/sokol/particles/particle/color.v
new file mode 100644
index 0000000000..813958a3e3
--- /dev/null
+++ b/examples/sokol/particles/particle/color.v
@@ -0,0 +1,15 @@
+// Copyright(C) 2019 Lars Pontoppidan. All rights reserved.
+// Use of this source code is governed by an MIT license file distributed with this software package
+
+module particle
+
+/*
+* Color
+*/
+pub struct Color {
+mut:
+	r byte
+	g byte
+	b byte
+	a byte
+}
diff --git a/examples/sokol/particles/particle/particle.v b/examples/sokol/particles/particle/particle.v
new file mode 100644
index 0000000000..66564a308a
--- /dev/null
+++ b/examples/sokol/particles/particle/particle.v
@@ -0,0 +1,99 @@
+// Copyright(C) 2019 Lars Pontoppidan. All rights reserved.
+// Use of this source code is governed by an MIT license file distributed with this software package
+
+module particle
+
+import vec2
+import sokol.sgl
+
+const (
+	default_life_time = 1000
+	default_v_color = Color{93, 136, 193, 255 }
+)
+
+/*
+* Module public
+*/
+pub fn new(location vec2.Vec2) &Particle {
+
+	p := &Particle {
+		location: location,
+		velocity: vec2.Vec2{0,0}
+		acceleration: vec2.Vec2{0,0}
+
+		color: default_v_color
+
+		life_time: default_life_time
+		life_time_init: default_life_time
+	}
+	return p
+}
+
+fn remap(v, min, max, new_min, new_max f64) f64 {
+	return (((v - min) * (new_max - new_min)) / (max - min)) + new_min
+}
+
+/*
+* Particle
+*/
+pub struct Particle {
+
+mut:
+	location		vec2.Vec2
+	velocity		vec2.Vec2
+	acceleration	vec2.Vec2
+
+	color			Color
+
+	life_time		f64
+	life_time_init	f64
+}
+
+pub fn (mut p Particle) update(dt f64) {
+	mut acc := p.acceleration
+	acc.multiply_f64(dt)
+	p.velocity = p.velocity.add(acc)
+	p.location = p.location.add(p.velocity)
+
+	lt := p.life_time - (1000 * dt)
+	if lt > 0 {
+		p.life_time = lt
+
+		p.color.r = p.color.r - 1 //byte(remap(p.life_time,0.0,p.life_time_init,0,p.color.r))
+		p.color.g = p.color.g - 1 //byte(remap(p.life_time,0.0,p.life_time_init,0,p.color.g))
+		p.color.b = p.color.b - 1 //byte(remap(p.life_time,0.0,p.life_time_init,0,p.color.b))
+
+		//p.color.a = byte(remap(p.life_time,0.0,p.life_time_init,0,255))
+	} else {
+		p.life_time = 0
+	}
+}
+
+pub fn (p Particle) is_dead() bool {
+	return p.life_time <= 0.0
+}
+
+pub fn (p Particle) draw() {
+	l := p.location
+
+	sgl.c4b(p.color.r, p.color.g, p.color.b, p.color.a)
+
+	lx := f32(l.x)
+	ly := f32(l.y)
+	sgl.v2f(lx, ly)
+	sgl.v2f(lx + 2, ly)
+	sgl.v2f(lx + 2, ly + 2)
+	sgl.v2f(lx, ly + 2)
+}
+
+pub fn (mut p Particle) reset() {
+	p.location.zero()
+	p.acceleration.zero()
+	p.velocity.zero()
+
+	//p.color = Color{93, 136, 193, 255}
+	p.color = default_v_color
+
+	p.life_time = default_life_time
+	p.life_time_init = p.life_time
+}
diff --git a/examples/sokol/particles/particle/system.v b/examples/sokol/particles/particle/system.v
new file mode 100644
index 0000000000..2f419dc285
--- /dev/null
+++ b/examples/sokol/particles/particle/system.v
@@ -0,0 +1,109 @@
+// Copyright(C) 2019 Lars Pontoppidan. All rights reserved.
+// Use of this source code is governed by an MIT license file distributed with this software package
+
+module particle
+import vec2
+import rand
+import sokol.sgl
+
+pub struct SystemConfig {
+	pool	int
+}
+
+pub struct System {
+	width			int
+	height			int
+mut:
+	pool			[]&Particle
+	bin				[]&Particle
+}
+
+pub fn (mut s System) init(sc SystemConfig) {
+	for i := 0; i < sc.pool; i++ {
+		p := particle.new( vec2.Vec2{f32(s.width)*0.5, f32(s.height)*0.5} )
+		s.pool << p
+	}
+}
+
+pub fn (mut s System) update(dt f64) {
+
+	mut p := &Particle(0)
+	for i := 0; i < s.pool.len; i++ {
+		p = s.pool[i]
+
+		p.update(dt)
+
+		if p.is_dead() {
+			s.bin << p
+			s.pool.delete(i)
+		}
+	}
+}
+
+pub fn (s System) draw() {
+	sgl.begin_quads()
+	for p in s.pool {
+		p.draw()
+	}
+	sgl.end()
+}
+
+pub fn (mut s System) reset() {
+	for p in s.pool {
+		p.reset()
+		p.life_time = 0
+	}
+	for p_ in s.bin {
+		p_.reset()
+		p_.life_time = 0
+	}
+}
+
+pub fn (mut s System) explode(x f32, y f32) {
+
+	mut reserve := 500
+
+	center := vec2.Vec2{x,y}
+
+	mut p := &Particle(0)
+	for i := 0; i < s.bin.len && reserve > 0; i++ {
+		p = s.bin[i]
+
+		p.reset()
+
+		p.location.from(center)
+		p.acceleration = vec2.Vec2{rand.f32_in_range(-0.5,0.5),rand.f32_in_range(-0.5,0.5)}
+		p.velocity = vec2.Vec2{rand.f32_in_range(-0.5,0.5),rand.f32_in_range(-0.5,0.5)}
+		p.life_time = rand.f64_in_range(500,2000)
+
+		s.pool << p
+		s.bin.delete(i)
+
+		reserve--
+	}
+}
+
+pub fn (mut s System) free() {
+	for p in s.pool {
+		if p == 0 {
+			print(ptr_str(p)+' ouch')
+			continue
+		}
+		unsafe{
+			free(p)
+		}
+	}
+	s.pool.clear()
+	for p in s.bin {
+		if p == 0 {
+			print(ptr_str(p)+' ouch')
+			continue
+		}
+
+		unsafe{
+			//println('Freeing from bin')
+			free(p)
+		}
+	}
+	s.bin.clear()
+}
\ No newline at end of file
diff --git a/examples/sokol/particles/particle/v.mod b/examples/sokol/particles/particle/v.mod
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/examples/sokol/particles/particle/vec2/v.mod b/examples/sokol/particles/particle/vec2/v.mod
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/examples/sokol/particles/particle/vec2/vec2.v b/examples/sokol/particles/particle/vec2/vec2.v
new file mode 100644
index 0000000000..2fdfa7a88d
--- /dev/null
+++ b/examples/sokol/particles/particle/vec2/vec2.v
@@ -0,0 +1,99 @@
+// Copyright(C) 2019 Lars Pontoppidan. All rights reserved.
+// Use of this source code is governed by an MIT license file distributed with this software package
+
+module vec2
+
+pub struct Vec2 {
+pub mut:
+    x f64
+    y f64
+}
+
+pub fn (mut v Vec2) zero() {
+    v.x = 0.0
+    v.y = 0.0
+}
+
+pub fn (mut v Vec2) from(src Vec2) {
+    v.x = src.x
+    v.y = src.y
+}
+
+/*
+ * Addition
+ */
+
+// + operator overload. Adds two vectors
+pub fn (v1 Vec2) + (v2 Vec2) Vec2 {
+    return Vec2{v1.x + v2.x, v1.y + v2.y}
+}
+
+pub fn (v Vec2) add(vector Vec2) Vec2 {
+    return Vec2{ v.x + vector.x, v.y + vector.y }
+}
+
+pub fn (v Vec2) add_f64(scalar f64) Vec2 {
+    return Vec2{ v.x + scalar, v.y + scalar }
+}
+
+pub fn (mut v Vec2) plus(vector Vec2) {
+    v.x += vector.x
+    v.y += vector.y
+}
+
+pub fn (mut v Vec2) plus_f64(scalar f64) {
+    v.x += scalar
+    v.y += scalar
+}
+
+
+/*
+ * Subtraction
+ */
+pub fn (v1 Vec2) - (v2 Vec2) Vec2 {
+    return Vec2{v1.x - v2.x, v1.y - v2.y}
+}
+
+pub fn (v Vec2) sub(vector Vec2) Vec2 {
+    return Vec2{ v.x - vector.x, v.y - vector.y }
+}
+
+pub fn (v Vec2) sub_f64(scalar f64) Vec2 {
+    return Vec2{ v.x - scalar, v.y - scalar }
+}
+
+pub fn (mut v Vec2) subtract(vector Vec2) {
+    v.x -= vector.x
+    v.y -= vector.y
+}
+
+pub fn (mut v Vec2) subtract_f64(scalar f64) {
+    v.x -= scalar
+    v.y -= scalar
+}
+
+/*
+ * Multiplication
+ */
+pub fn (v1 Vec2) * (v2 Vec2) Vec2 {
+    return Vec2{v1.x * v2.x, v1.y * v2.y}
+}
+
+
+pub fn (v Vec2) mul(vector Vec2) Vec2 {
+    return Vec2{ v.x * vector.x, v.y * vector.y }
+}
+
+pub fn (v Vec2) mul_f64(scalar f64) Vec2 {
+    return Vec2{ v.x * scalar, v.y * scalar }
+}
+
+pub fn (mut v Vec2) multiply(vector Vec2) {
+    v.x *= vector.x
+    v.y *= vector.y
+}
+
+pub fn (mut v Vec2) multiply_f64(scalar f64) {
+    v.x *= scalar
+    v.y *= scalar
+}
\ No newline at end of file