diff -urN rt_v50/cool_car.yaml rt_v51/cool_car.yaml
--- rt_v50/cool_car.yaml	1970-01-01 09:00:00.000000000 +0900
+++ rt_v51/cool_car.yaml	2018-06-14 00:58:53.000000000 +0900
@@ -0,0 +1,148 @@
+defs:
+  mov4: IMG_3999_4.mov
+  rtd_A: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 }
+  rtd_a: { base: 0.1, diff: 0.3, reflect: 0.5, reflact: 0.2, density: 2 }
+  rtd_B: { base: 0.7, diff: 0.3 }
+  rtd_C: { base: 0.7, diff: 0.3, reflect: 0.5 }
+  dark: [50,50,50]
+  red: [50,50,200]
+
+big_ball:
+- kind: ball
+  rtd: { diff: 0.3 }
+  maps:
+  - fn: '*mov4'
+    fn_r: '*mov4'
+    t2m: [ ax.zoom_all(2), ax.rot_x(90) ]
+  - fn: '*mov4'
+    fn_r: '*mov4'
+    t2m: [ ax.zoom_all(2), ax.rot_x(90), ax.rot_z(180) ]
+  m2g: [ ax.zoom_all(1000) ]
+
+body:
+- kind: and
+
+  # ship
+  args:
+  - kind: ball
+    rtd: '*rtd_a'
+    def_col: '*red'
+    m2g:
+    - 'ax.zoom([200,100,25])'
+  - kind: ball
+    rtd: '*rtd_a'
+    def_col: '*red'
+    m2g:
+    - 'ax.zoom([130,140,100])'
+  - kind: ball
+    rtd: '*rtd_a'
+    def_col: '*red'
+    m2g:
+    - 'ax.zoom([500,70,50])'
+
+  # bottom
+  - kind: cube
+    rtd: '*rtd_C'
+    def_col: '*dark'
+    m2g:
+    - 'ax.zoom([160,120,50])'
+    - ax.slide_z(30)
+
+  # room
+  - kind: and
+    not: True
+    args:
+    - kind: cube
+      rtd: '*rtd_C'
+      def_col: '*dark'
+      m2g:
+      - 'ax.zoom([40,55,25])'
+      - 'ax.slide([-10,0,10])'
+    - kind: pipe
+      rtd: '*rtd_C'
+      def_col: '*dark'
+      m2g:
+      - ax.zoom_all(1.1)
+      - 'ax.zoom([40,55,50])'
+      - 'ax.slide([-10,0,10])'
+
+  # tire house
+  - kind: pipe
+    not: True
+    rtd: '*rtd_C'
+    def_col: '*dark'
+    m2g:
+    - ax.zoom_z(0.8)
+    - ax.rot_x(90)
+    - ax.zoom_all(24)
+    - 'ax.slide([90,55,-10])'
+    rxs:
+    - [ m2g, append, 2, [ ax.zoom_y(-1) ] ]
+    - [ m2g, append, 2, [ ax.zoom_x(-1) ] ]
+
+tire:
+- kind: pipe
+  rtd: '*rtd_a'
+  def_col: '*dark'
+  m2g:
+  - ax.zoom_z(0.6)
+  - ax.rot_x(90)
+  - ax.zoom_all(20)
+  - 'ax.slide([90,55,-10])'
+  rxs:
+  - [ m2g, append, 2, [ ax.zoom_y(-1) ] ]
+  - [ m2g, append, 2, [ ax.zoom_x(-1) ] ]
+
+shield:
+- kind: and
+  args:
+  - kind: ball
+    rtd: '*rtd_A'
+    m2g:
+    - ax.zoom_all(170)
+  - kind: ball
+    not: True
+    rtd: '*rtd_a'
+    m2g:
+    - ax.zoom_all(168)
+  - kind: cube
+    m2g:
+    - 'ax.zoom([100,50,20])'
+    - ax.rot_y(-20)
+    - 'ax.slide([100,0,120])'
+  m2g:
+  - 'ax.slide([-80,0,-90])'
+
+lamp:
+- kind: pipe
+  rtd: '*rtd_A'
+  m2g:
+  - 'ax.zoom([10,10,3])'
+  - ax.rot_y(90)
+  - 'ax.slide([125,50,0])'
+  rxs:
+  - [ m2g, append, 2, [ ax.zoom_y(-1) ] ]
+
+cool_car:
+- kind: export
+  export: body
+
+- kind: export
+  export: tire
+
+- kind: export
+  export: shield
+
+- kind: export
+  export: lamp
+
+all:
+- kind: export
+  export: big_ball
+
+- kind: export
+  export: cool_car
+  m2g:
+  - ax.zoom_all(0.2)
+
+# EOF
diff -urN rt_v50/cross.c rt_v51/cross.c
--- rt_v50/cross.c	2018-06-11 23:11:26.000000000 +0900
+++ rt_v51/cross.c	2018-06-14 01:04:12.000000000 +0900
@@ -328,6 +328,7 @@
 	case KIND_SQUARE:
 	case KIND_CIRCLE:
 	case KIND_TRIANGLE:
+		v_set(nv, v_z1);
 		break;
 	case KIND_BALL:
 		unit(ret->p, nv);
@@ -352,15 +353,24 @@
 		break;
 	}
 
-	if(is_plane(kind_idx)){
-		struct line x, y;;
-		lstx_tr_line(l2g, L2G, &line_x1, &x);
-		lstx_tr_line(l2g, L2G, &line_y1, &y);
-		cross_product_unit(x.v, y.v, ret->l_nv_g.v);
-		lstx_tr_p(l2g, L2G, ret->p, ret->l_nv_g.p);
-	}else{
-		line_new(&l_nv, ret->p, nv);
-		lstx_tr_line(l2g, L2G, &l_nv, &ret->l_nv_g);
+	line_new(&l_nv, ret->p, nv);
+	lstx_tr_line(l2g, L2G, &l_nv, &ret->l_nv_g);
+	if(kind_idx != KIND_BALL){
+		double *p = ret->l_nv_g.p;
+		double *v = ret->l_nv_g.v;
+		double z[3];
+		struct vecs vs;
+	
+		if(is_plane(kind_idx)){
+			v_set(z, v_x1);
+		}else if(kind_idx == KIND_PIPE_SIDE){
+			v_add(p, v_z1, z);
+		}else{ /* KIND_CONE_SIDE */
+			v_set(z, v_z1);
+		}
+		lstx_tr_p(l2g, L2G, z, z);
+		v_sub(z, p, z);
+		vecs_by_fix_ref(&vs, 'z', z, 'y', v);
 	}
 
 	if(rev){
@@ -442,6 +452,9 @@
 			continue;
 		}
 		d = &data->lst[j];
+		if(d->hide){
+			continue;
+		}
 
 		if( is_op(d->kind) ){
 			cross_op(l_g, prev_idx, data, j, &a);
@@ -516,7 +529,7 @@
 	for(i=0; i<data->n; i++){
 		struct data_one *d = &data->lst[i];
 
-		if(d->parent >= 0){
+		if(d->parent >= 0 || d->hide){
 			continue;
 		}
 
diff -urN rt_v50/dat.c rt_v51/dat.c
--- rt_v50/dat.c	2018-06-11 21:52:43.000000000 +0900
+++ rt_v51/dat.c	2018-06-14 01:14:50.000000000 +0900
@@ -108,6 +108,7 @@
 	bp = unpack_maps(bp, &d->maps);
 	bp = unpack_rtd(bp, &d->rtd);
 	bp = COPY_FROM_BP(bp, d->not);
+	bp = COPY_FROM_BP(bp, d->hide);
 
 	bp = COPY_FROM_BP(bp, d->id);
 	bp = COPY_FROM_BP(bp, d->parent);
diff -urN rt_v50/dat.h rt_v51/dat.h
--- rt_v50/dat.h	2018-06-11 21:52:48.000000000 +0900
+++ rt_v51/dat.h	2018-06-14 01:14:50.000000000 +0900
@@ -42,6 +42,7 @@
 	struct maps maps;
 	struct rtd rtd;
 	int not;
+	int hide;
 
 	int id;
 	int parent;
diff -urN rt_v50/dat.py rt_v51/dat.py
--- rt_v50/dat.py	2018-06-11 22:57:03.000000000 +0900
+++ rt_v51/dat.py	2018-06-14 01:39:46.000000000 +0900
@@ -19,6 +19,8 @@
 	{ 'p': mt.arr( [-1,1,1] ) * 30, 'e': 2.5 },
 ]
 
+if_has_pop = lambda d, k, def_v=None: d.pop(k) if k in d else def_v
+
 def if_not_set_opt(d, k, v):
 	ut.if_not_set(d, k, v)
 	ut.dic_set( d, k, lstx.opt( d.get(k) ) )
@@ -38,18 +40,27 @@
 	if k in d:
 		d[k] = ds_copy( d.get(k, []) )
 
+def lst_copy_r(lst):
+	return ut.map_lst( lambda v: lst_copy_r(v) if type(v) == list else v, lst )
+
 def lst_copy_k(d, k):
 	if k in d:
-		d[k] = d.get(k, [])[:]
+		d[k] = lst_copy_r( d.get(k) )
 
 def d_copy(d):
 	d = d.copy()
 	ds_copy_k(d, 'maps')
 	lst_copy_k(d, 'rxs')
+
+	k = 'args'
+	if k in d:
+		d[k] = ut.map_lst( d_copy, d.get(k) )
+
 	return d
 
 def m_setup(d, m):
-	# 'fn' in d
+	# 'fn' in m
+	# use d.get('m2g', [])
 
 	if_not_set_idx( m, 'fn' )
 	if_not_set_idx( m, 'fn_r' )
@@ -66,7 +77,7 @@
 		if_not_set_opt( m, 'xyz2t', lst )
 
 	if_not_set_opt( m, 't2m', [] )
-	if_not_set_opt( m, 't2g', m.get('t2m') + d.get('m2g') )
+	if_not_set_opt( m, 't2g', m.get('t2m') + d.get('m2g', []) )
 	if_not_set_opt( m, 'xyz2g', m.get('xyz2t') + m.get('t2g') )
 	if_not_set_opt( m, 'wh2g', m.get('wh2xyz') + m.get('xyz2g') )
 
@@ -88,19 +99,19 @@
 
 	return dict( map( lambda k: ( k, f_lst( yd.get(k) ) ), yd.keys() ) )
 
-def setup_ydic(o, sec):
+def setup_eval_ax(o, sec):
 	t = type(o)
 	if t == list:
-		return list( map( lambda o: setup_ydic(o, sec), o ) )
+		return list( map( lambda o: setup_eval_ax(o, sec), o ) )
 	if t == dict:
 		tm_sft = o.get('tm_sft', 0)
-		f = lambda k: ( k, setup_ydic( o.get(k), sec + tm_sft ) )
+		f = lambda k: ( k, setup_eval_ax( o.get(k), sec + tm_sft ) )
 		return dict( map( f, o.keys() ) )
 	if t == str and o.startswith('ax.'):
 		return eval(o)
 	return o
 
-ydic = {}
+ydic = {} # for export
 
 def new_get_id():
 	e = ut.Empty()
@@ -113,15 +124,31 @@
 
 get_id = new_get_id()
 
+ops = [ 'and', 'or', 'xor' ]
+kinds = [ 'square', 'circle', 'triangle', 'ball', 'pipe_side', 'cone_side' ]
+kinds += ops
+
+def data_setup_exp(data, in_op):
+	return sum( map( lambda d: d_setup(d, in_op), data ), [] )
+
 def d_setup(d, in_op=False):
 	# return lst [d]
 
-	for_op_not = lambda : d.pop('not') if in_op and 'not' in d else False
+	def for_op(): # naming ...
+		f = {}
+		if in_op:
+			for k in [ 'not', 'rxs' ]:
+				if k in d:
+					f[k] = d.pop(k)
+		return f
 
 	def ret_lst(lst, f):
 		if in_op:
-			return d_setup( { 'kind': 'and', 'args': lst, 'not': f }, in_op )
-		return sum( map( d_setup, lst ), [] )
+			t = { 'kind': 'and', 'args': lst }
+			t.update(f)
+			return d_setup( t, in_op )
+
+		return data_setup_exp( lst, in_op )
 
 	kind = d.get('kind')
 
@@ -140,63 +167,63 @@
 		def poly_n_f(i):
 			d_ = d_copy(d)
 			d_['kind'] = 'triangle'
-			d_['l2m'] = [ ax.slide_y(-1), ax.zoom([b,h,1]), ax.rot_z(deg*i)  ] + d_.get( 'l2m', [] )
+			d_['l2m'] = [ 'ax.slide_y(-1)', 'ax.zoom([{},{},1])'.format(b,h), 'ax.rot_z({})'.format(deg*i)  ] + d_.get( 'l2m', [] )
 			return d_setup( d_ )
 
 		return sum( map( poly_n_f, range(n) ), [] )
 
 	if kind == 'cube':
-		f = for_op_not()
+		f = for_op()
 
 		def cube_f(l, deg):
 			d_ = d_copy(d)
 			d_['kind'] = 'square'
-			d_['l2m'] = [ ax.slide_z(1), ax.rot(l, deg) ] + d_.get( 'l2m', [] )
+			d_['l2m'] = [ 'ax.slide_z(1)', 'ax.rot({},{})'.format(l, deg) ] + d_.get( 'l2m', [] )
 			return d_
 		rots = [
-			(line.x1, 0), (line.x1, 90), (line.x1, 180), (line.x1, -90),
-			(line.y1, 90), (line.y1, -90)
+			('line.x1', 0), ('line.x1', 90), ('line.x1', 180), ('line.x1', -90),
+			('line.y1', 90), ('line.y1', -90)
 		]
 
 		lst = ut.map_up_lst( cube_f, rots )
 		return ret_lst(lst, f)
 
 	if kind == 'tri_prism_side':
-		f = for_op_not()
+		f = for_op()
 
 		d0 = d_copy(d)
 		d0['kind'] = 'square'
-		d0['l2m'] = [ ax.rot_x(90) ] + d0.get( 'l2m', [] )
+		d0['l2m'] = [ 'ax.rot_x(90)' ] + d0.get( 'l2m', [] )
 
 		d1 = d_copy(d)
 		d1['kind'] = 'square'
 		zm = math.sqrt(2) / 2
-		d1['l2m'] = [ ax.rot_x(-90), ax.slide_x(-1), ax.zoom_x(zm), ax.rot_z(-45), ax.slide_x(1) ] + d1.get( 'l2m', [] )
+		d1['l2m'] = [ 'ax.rot_x(-90)', 'ax.slide_x(-1)', 'ax.zoom_x({})'.format(zm), 'ax.rot_z(-45)', 'ax.slide_x(1)' ] + d1.get( 'l2m', [] )
 
 		d2 = d_copy(d)
 		d2['kind'] = 'square'
-		d2['l2m'] = [ ax.rot_x(-90), ax.slide_x(1), ax.zoom_x(zm), ax.rot_z(45), ax.slide_x(-1) ] + d2.get( 'l2m', [] )
+		d2['l2m'] = [ 'ax.rot_x(-90)', 'ax.slide_x(1)', 'ax.zoom_x({})'.format(zm), 'ax.rot_z(45)', 'ax.slide_x(-1)' ] + d2.get( 'l2m', [] )
 
 		return ret_lst( [d0,d1,d2], f )
 
 	if kind == 'tri_prism':
-		f = for_op_not()
+		f = for_op()
 
 		d0 = d_copy(d)
 		d0['kind'] = 'tri_prism_side'
 
 		d1 = d_copy(d)
 		d1['kind'] = 'triangle'
-		d1['l2m'] = [ ax.slide_z(1) ] + d1.get( 'l2m', [] )
+		d1['l2m'] = [ 'ax.slide_z(1)' ] + d1.get( 'l2m', [] )
 
 		d2 = d_copy(d)
 		d2['kind'] = 'triangle'
-		d2['l2m'] = [ ax.slide_z(1), ax.rot_y(180) ] + d2.get( 'l2m', [] )
+		d2['l2m'] = [ 'ax.slide_z(1)', 'ax.rot_y(180)' ] + d2.get( 'l2m', [] )
 
 		return ret_lst( [d0,d1,d2], f )
 
 	if kind == 'poly_n_prism_side':
-		f = for_op_not()
+		f = for_op()
 
 		n = d.get('n', 3)
 		deg = 360.0 / n
@@ -207,30 +234,30 @@
 		def poly_n_prism_side_f(i):
 			d_ = d_copy(d)
 			d_['kind'] = 'square'
-			d_['l2m'] = [ ax.rot_x(90), ax.zoom_x(b), ax.slide_y(-h), ax.rot_z(deg*i) ] + d_.get( 'l2m', [] )
+			d_['l2m'] = [ 'ax.rot_x(90)', 'ax.zoom_x({})'.format(b), 'ax.slide_y({})'.format(-h), 'ax.rot_z({})'.format(deg*i) ] + d_.get( 'l2m', [] )
 			return d_
 
 		lst = ut.map_lst( poly_n_prism_side_f, range(n) )
 		return ret_lst(lst, f)
 
 	if kind == 'poly_n_prism':
-		f = for_op_not()
+		f = for_op()
 
 		d0 = d_copy(d)
 		d0['kind'] = 'poly_n_prism_side'
 
 		d1 = d_copy(d)
 		d1['kind'] = 'poly_n'
-		d1['l2m'] = [ ax.slide_z(1) ] + d1.get( 'l2m', [] )
+		d1['l2m'] = [ 'ax.slide_z(1)' ] + d1.get( 'l2m', [] )
 
 		d2 = d_copy(d)
 		d2['kind'] = 'poly_n'
-		d2['l2m'] = [ ax.slide_z(1), ax.rot_y(180) ] + d2.get( 'l2m', [] )
+		d2['l2m'] = [ 'ax.slide_z(1)', 'ax.rot_y(180)' ] + d2.get( 'l2m', [] )
 
 		return ret_lst( [d0,d1,d2], f )
 
 	if kind == 'four_pyramid_side':
-		f = for_op_not()
+		f = for_op()
 
 		n = 4
 		zm = math.sqrt(2)
@@ -238,30 +265,30 @@
 		def four_pyramid_side_f(i):
 			d_ = d_copy(d)
 			d_['kind'] = 'triangle'
-			d_['l2m'] = [ ax.zoom_y(zm), ax.rot_x(45), ax.slide_y(-1), ax.rot_z(90*i) ] + d_.get( 'l2m', [] )
+			d_['l2m'] = [ 'ax.zoom_y({})'.format(zm), 'ax.rot_x(45)', 'ax.slide_y(-1)', 'ax.rot_z({})'.format(90*i) ] + d_.get( 'l2m', [] )
 			return d_
 
 		lst = ut.map_lst( four_pyramid_side_f, range(n) )
 		return ret_lst(lst, f)
 
 	if kind == 'four_pyramid':
-		f = for_op_not()
+		f = for_op()
 
 		d0 = d_copy(d)
 		d0['kind'] = 'four_pyramid_side'
 
 		d1 = d_copy(d)
 		d1['kind'] = 'square'
-		d1['l2m'] = [ ax.rot_y(180) ] + d1.get( 'l2m', [] )
+		d1['l2m'] = [ 'ax.rot_y(180)' ] + d1.get( 'l2m', [] )
 
 		return ret_lst( [d0,d1], f )
 
 	if kind == 'tri_pyramid_side':
-		f = for_op_not()
+		f = for_op()
 
 		d0 = d_copy(d)
 		d0['kind'] = 'triangle'
-		d0['l2m'] = [ ax.rot_x(90) ] + d0.get( 'l2m', [] )
+		d0['l2m'] = [ 'ax.rot_x(90)' ] + d0.get( 'l2m', [] )
 
 		h = math.sqrt( 1 + 0.5 )
 		b = math.sqrt(2)/2
@@ -269,28 +296,28 @@
 
 		d1 = d_copy(d)
 		d1['kind'] = 'triangle'
-		d1['l2m'] = [ ax.zoom([b,h,1]), ax.rot_x(deg), ax.rot_z(90+45), ax.slide([0.5,0.5,0]) ] + d1.get( 'l2m', [] )
+		d1['l2m'] = [ 'ax.zoom([{},{},1])'.format(b,h), 'ax.rot_x({})'.format(deg), 'ax.rot_z(90+45)', 'ax.slide([0.5,0.5,0])' ] + d1.get( 'l2m', [] )
 
 		d2 = d_copy(d)
 		d2['kind'] = 'triangle'
-		d2['l2m'] = [ ax.zoom([b,h,1]), ax.rot_x(deg), ax.rot_z(-90-45), ax.slide([-0.5,0.5,0]) ] + d2.get( 'l2m', [] )
+		d2['l2m'] = [ 'ax.zoom([{},{},1])'.format(b,h), 'ax.rot_x({})'.format(deg), 'ax.rot_z(-90-45)', 'ax.slide([-0.5,0.5,0])' ] + d2.get( 'l2m', [] )
 
 		return ret_lst( [d0,d1,d2], f )
 
 	if kind == 'tri_pyramid':
-		f = for_op_not()
+		f = for_op()
 
 		d0 = d_copy(d)
 		d0['kind'] = 'tri_pyramid_side'
 
 		d1 = d_copy(d)
 		d1['kind'] = 'triangle'
-		d1['l2m'] = [ ax.rot_y(180) ] + d1.get( 'l2m', [] )
+		d1['l2m'] = [ 'ax.rot_y(180)' ] + d1.get( 'l2m', [] )
 
 		return ret_lst( [d0,d1], f )
 
 	if kind == 'poly_n_pyramid_side':
-		f = for_op_not()
+		f = for_op()
 
 		n = d.get('n', 3)
 		deg = 360.0 / n
@@ -303,135 +330,96 @@
 		def poly_n_pyramid_side_f(i):
 			d_ = d_copy(d)
 			d_['kind'] = 'triangle'
-			d_['l2m'] = [ ax.zoom([b,h2,1]), ax.rot_x(deg2), ax.slide_y(-h), ax.rot_z(deg*i) ] + d_.get( 'l2m', [] )
+			d_['l2m'] = [ 'ax.zoom([{},{},1])'.format(b,h2), 'ax.rot_x({})'.format(deg2), 'ax.slide_y({})'.format(-h), 'ax.rot_z({})'.format(deg*i) ] + d_.get( 'l2m', [] )
 			return d_
 
 		lst = ut.map_lst( poly_n_pyramid_side_f, range(n) )
 		return ret_lst(lst, f)
 
 	if kind == 'poly_n_pyramid':
-		f = for_op_not()
+		f = for_op()
 
 		d0 = d_copy(d)
 		d0['kind'] = 'poly_n_pyramid_side'
 
 		d1 = d_copy(d)
 		d1['kind'] = 'poly_n'
-		d1['l2m'] = [ ax.rot_y(180) ] + d1.get( 'l2m', [] )
+		d1['l2m'] = [ 'ax.rot_y(180)' ] + d1.get( 'l2m', [] )
 
 		return ret_lst( [d0,d1], f )
 
 	if kind == 'pipe':
-		f = for_op_not()
+		f = for_op()
 
 		d0 = d_copy(d)
 		d0['kind'] = 'pipe_side'
 
 		d1 = d_copy(d)
 		d1['kind'] = 'circle'
-		d1['l2m'] = [ ax.slide_z(1) ] + d1.get( 'l2m', [] )
+		d1['l2m'] = [ 'ax.slide_z(1)' ] + d1.get( 'l2m', [] )
 
 		d2 = d_copy(d)
 		d2['kind'] = 'circle'
-		d2['l2m'] = [ ax.slide_z(1), ax.rot_y(180) ] + d2.get( 'l2m', [] )
+		d2['l2m'] = [ 'ax.slide_z(1)', 'ax.rot_y(180)' ] + d2.get( 'l2m', [] )
 
 		return ret_lst( [d0,d1,d2], f )
 
 	if kind == 'cone':
-		f = for_op_not()
+		f = for_op()
 
 		d0 = d_copy(d)
 		d0['kind'] = 'cone_side'
 
 		d1 = d_copy(d)
 		d1['kind'] = 'circle'
-		d1['l2m'] = [ ax.rot_y(180) ] + d1.get( 'l2m', [] )
+		d1['l2m'] = [ 'ax.rot_y(180)' ] + d1.get( 'l2m', [] )
 
 		return ret_lst( [d0,d1], f )
 	###
 
-	if_not_set_opt( d, 'l2m', [] )
-	if_not_set_opt( d, 'm2g', [] )
-	if_not_set_opt( d, 'l2g', d.get('l2m') + d.get('m2g') )
-
-	if 'def_col' not in d:
-		d['def_col'] = [128,128,128]
-	if 'def_col_r' not in d:
-		d['def_col_r'] = d.get('def_col')
-
-	if 'maps' not in d:
-		d['maps'] = []
-	for m in d.get('maps'):
-		m_setup(d, m)
-
-	def_rtd = { 'base': 0.3, 'diff': 0.9, 'reflect': 0, 'reflact': 0, 'density': 1.0, 'reflect_backside': False }
-	if 'rtd' not in d:
-		d['rtd'] = def_rtd
-	rtd = d.get('rtd')
-	for k in def_rtd.keys():
-		if k not in rtd:
-			rtd[k] = def_rtd.get(k)
-
-	if 'not' not in d:
-		d['not'] = False
-
-	d['id'] = get_id()
-	d['parent'] = -1
-	d['children'] = []
-
-	###
-
-	if kind == 'export' and 'export' in d:
-		data = ydic.get( d.get('export'), [] )
-		data = ut.map_lst( d_copy, data )
-		ds = []
-		for d_ in data:
-			d_['m2g'] = d_.get('m2g', []) + d.get('l2g')
-			if 'rxs' in d:
-				d_['rxs'] = d_.get('rxs', []) + d.get('rxs')
-			ds += d_setup(d_)
-		for d_ in ds:
-			d_['maps'] = d_.get('maps', []) + d.get('maps', [])
-		return ds
+	if kind == 'export':
+		lst = ydic.get( if_has_pop(d, 'export', ''), [] )
+		d['kind'] = 'or'
+		d['args'] = lst
+		return d_setup(d, in_op)
 	###
 
 	if 'rxs' in d:
 		rxs = d.get('rxs')
 		if not rxs:
 			d.pop('rxs')
-			return d_setup(d)
+			return d_setup(d, in_op)
 		(targ_k, i_a, n, lx) = rxs.pop(0)
 
 		targ = d.get(targ_k, [])
-		d.pop('l2g')
 		ds = []
 		for i in range(n):
 			d_ = d_copy(d)
 			d_[targ_k] = targ[:]
 			ds.append(d_)
 			targ = lx + targ if i_a == 'insert' else targ + lx
-		return sum( map( d_setup, ds ), [] )
-	###
 
-	kinds = [ 'square', 'circle', 'triangle', 'ball', 'pipe_side', 'cone_side' ]
-	ops = [ 'and', 'or', 'xor' ]
-	kinds += ops
-	if not val.cli.has_prop('kinds'):
-		val.cli.set_prop( 'kinds', '[str]', kinds )
-	kind = d.get('kind')
-	if type(kind) != int:
-		d['kind'] = kinds.index(kind)
+		return data_setup_exp(ds, in_op)
+
 	###
 
+	if 'id' not in d:
+		d['id'] = get_id()
+
 	if kind in ops:
+		args = if_has_pop(d, 'args', [])
+
 		ds = []
-		args = d.pop('args') if 'args' in d else []
 		for d_ in args:
-			d_['m2g'] = d_.get('m2g', []) + d.get('l2g')
+			#d_['m2g'] = d_.get('m2g', []) + l2g
+			d_['maps'] = d_.get('maps', []) + d.get('maps', [])
 			ds += d_setup(d_, True)
+
+		if 'children' not in d: # !
+			d['children'] = []
+
 		for d_ in ds:
-			d_['maps'] = d_.get('maps', []) + d.get('maps', [])
-			if d_.get('parent', -1) < 0:
+			if 'parent' not in d_:
 				d_['parent'] = d.get('id')
 				d['children'].append( d_.get('id') )
 		return [d] + ds
@@ -439,9 +427,85 @@
 
 	return [d]
 
+def setup_m2g(data, d):
+
+	def find_id(id):
+		for d_ in data:
+			if d_.get('id', -1) == id:
+				return d_
+		return None
+
+	if 'children' not in d:
+		return
+
+	l2g = if_has_pop(d, 'l2m', []) + if_has_pop(d, 'm2g', [])
+
+	for cid in d.get('children'):
+		d_ = find_id(cid)
+		if d_:
+			d_['m2g'] = d_.get('m2g', []) + l2g
+			setup_m2g(data, d_)
+
+def setup_kind(d):
+	if not val.cli.has_prop('kinds'):
+		val.cli.set_prop( 'kinds', '[str]', kinds )
+	kind = d.get('kind')
+	if type(kind) != int:
+		d['kind'] = kinds.index(kind)
+	return d
+
+def setup_ids(d):
+	k = 'id'
+	if k not in d:
+		d[k] = get_id()
+	k = 'parent'
+	if k not in d:
+		d[k] = -1
+	k = 'children'
+	if k not in d:
+		d[k] = []
+	return d
+
+def setup_def_col(d):
+	if 'def_col' not in d:
+		d['def_col'] = [128,128,128]
+	if 'def_col_r' not in d:
+		d['def_col_r'] = d.get('def_col')
+	return d
+
+def setup_rtd(d):
+	def_rtd = { 'base': 0.3, 'diff': 0.9, 'reflect': 0, 'reflact': 0, 'density': 1.0, 'reflect_backside': False }
+	if 'rtd' not in d:
+		d['rtd'] = def_rtd
+	rtd = d.get('rtd')
+	for k in def_rtd.keys():
+		if k not in rtd:
+			rtd[k] = def_rtd.get(k)
+	return d
+
+def setup_not_hide(d):
+	for k in ['not', 'hide']:
+		if k not in d:
+			d[k] = False # default
+	return d
+
+def setup_maps(d):
+	if 'maps' not in d:
+		d['maps'] = []
+	for m in d.get('maps'):
+		m_setup(d, m)
+	return d
+
+def setup_opt(d):
+	if_not_set_opt( d, 'l2m', [] )
+	if_not_set_opt( d, 'm2g', [] )
+	if_not_set_opt( d, 'l2g', d.get('l2m') + d.get('m2g') )
+	return d
+
+typ_col = 'def_col:col,def_col_r:col'
 typ_map = '{xyz2g:lx,fn:i4,fn_r:i4,wh2xyz:lx,rep:(i4,i4)}'
 typ_ids = 'id:i4,parent:i4,children:[i4]'
-typ_d = '{{kind:i4,l2g:lx,def_col:col,def_col_r:col,maps:[{}],rtd:rtd,not:bool,{}}}'.format(typ_map, typ_ids)
+typ_d = '{{kind:i4,l2g:lx,{},maps:[{}],rtd:rtd,not:bool,hide:bool,{}}}'.format(typ_col, typ_map, typ_ids)
 typ_data = '[{}]'.format(typ_d)
 
 def setup(sec):
@@ -450,12 +514,28 @@
 	yd = ut.yaml_load(fn, {})
 	yd = ut.defs_eval(yd)
 	yd = tm_sft_copy(yd)
-	yd = setup_ydic(yd, sec)
+
 	ydic.clear()
 	ydic.update(yd)
 	data = ydic.get(data_name, [])
-	data = sum( map( d_setup, data ), [] )
-	#print('data={}'.format(data))
+
+	data = data_setup_exp(data, False)
+
+	for d in data:
+		if 'parent' not in d:
+			setup_m2g(data, d)
+
+	#print('data={}'.format( ut.yaml_dump( ut.dic_to_items(data) ) ) )
+
+	data = ut.map_lst( setup_kind, data )
+	data = ut.map_lst( setup_ids, data )
+	data = ut.map_lst( setup_def_col, data )
+	data = ut.map_lst( setup_rtd, data )
+	data = ut.map_lst( setup_not_hide, data )
+	data = ut.map_lst( setup_maps, data )
+	data = setup_eval_ax(data, sec)
+	data = ut.map_lst( setup_opt, data )
+
 	val.cli.set_prop('data', typ_data, data)
 	val.cli.set_prop('lights', '[ltd]', lights)
 	return ut.cmd_exec( "grep '\<sec\>' " + fn ) != ''
diff -urN rt_v50/img.py rt_v51/img.py
--- rt_v50/img.py	2018-05-29 21:41:28.000000000 +0900
+++ rt_v51/img.py	2018-06-14 01:14:23.000000000 +0900
@@ -221,7 +221,8 @@
 	writer = cv2.VideoWriter( fn, fourcc, fps, (vw, vh) )
 
 	def add_img():
-		writer.write( resize( e.img, vw, vh ) )
+		if fps >= 1: # for err in writer at fps < 1
+			writer.write( resize( e.img, vw, vh ) )
 		e.i += 1
 	e.add_img = add_img
 
diff -urN rt_v50/ut.py rt_v51/ut.py
--- rt_v50/ut.py	2018-06-05 22:43:02.000000000 +0900
+++ rt_v51/ut.py	2018-06-14 00:00:31.000000000 +0900
@@ -273,6 +273,25 @@
 def yaml_save(fname, v, default_flow_style=False):
 	file_write( fname, yaml_dump(v) )
 
+def dic_to_items(o):
+	magic = '### items ###'
+	t = type(o)
+	if t == list:
+		return map_lst( dic_to_items, o )
+	if t == dict:
+		ks = sorted( o.keys() )
+		return [ magic ] + map_lst( lambda k: [ k, dic_to_items( o.get(k) ) ], ks )
+	return o
+
+def items_to_dic(o):
+	magic = '### items ###'
+	t = type(o)
+	if t == list:
+		if lst_get(o, 0) == magic:
+			return dict( map( lambda kv: ( kv[0], items_to_dic( kv[1] ) ), o[1:] ) )
+		return map_lst( items_to_dic, o )
+	return o
+
 def defs_eval(d):
 	#	sample yaml
 	#
diff -urN rt_v50/vecs.c rt_v51/vecs.c
--- rt_v50/vecs.c	2018-04-13 20:24:38.000000000 +0900
+++ rt_v51/vecs.c	2018-06-14 01:15:00.000000000 +0900
@@ -235,4 +235,12 @@
 	vecs_init(vs);
 }
 
+double *
+vecs_get_by_name(struct vecs *vs, char name)
+{
+	/* name: 'x', 'y' or 'z' */
+	int i = name - 'x';
+	return &VECS_ACC(vs, i, 0);
+}
+
 /* EOF */
diff -urN rt_v50/vecs.h rt_v51/vecs.h
--- rt_v50/vecs.h	2018-04-29 17:18:38.000000000 +0900
+++ rt_v51/vecs.h	2018-06-14 01:15:00.000000000 +0900
@@ -40,5 +40,6 @@
 
 void vecs_by_fix_ref(struct vecs *vs, char fix_nm, double *fix, char ref_nm, double *ref);
 void vecs_rot_y(struct vecs *vs, double deg);
+double *vecs_get_by_name(struct vecs *vs, char name);
 
 #endif
