genomix: avatar studio
This commit is contained in:
parent
9d48e4977e
commit
94624866e2
|
@ -0,0 +1,117 @@
|
||||||
|
"""
|
||||||
|
This file implements an avatar studio
|
||||||
|
"""
|
||||||
|
import py_avataaars as pa
|
||||||
|
from py_avataaars import PyAvataaar as Avatar
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
import transport
|
||||||
|
from transport import providers
|
||||||
|
from enum import Enum
|
||||||
|
import io
|
||||||
|
import base64
|
||||||
|
import copy
|
||||||
|
|
||||||
|
|
||||||
|
# _map = {'eye type':pa.EyesType,'frame style':pa.AvatarStyle,'race':pa.SkinColor,'hair color':pa.HairColor,'facial hair':pa.FacialHairType, 'facial hair color':pa.HairColor,'hair dress':pa.TopType,'mouth':pa.MouthType,'nose':pa.NoseType,'eyebrows':pa.EyebrowType }
|
||||||
|
# _vmap= {'eye type':'eye_type','frame style':'style','race':'skin_color','hair color':'hair_color','facial hair color':'facial_hair_color','facial hair':'facial_hair_type','hair dress':'top_type','eyebrows':'eye_brow','nose':'nose_type','mouth':'mouth_type'}
|
||||||
|
# _omap = {'eye_type':pa.EyesType,'style':pa.AvatarStyle}
|
||||||
|
_df = [['eye type','eye_type',pa.EyesType],['frame style','style',pa.AvatarStyle],['hair color','hair_color',pa.HairColor],['race','skin_color',pa.SkinColor],['facial hair','facial_hair_type',pa.FacialHairType],
|
||||||
|
['facial hair color','facial_hair_color',pa.Color],['mouth','mouth_type',pa.MouthType],['hat color','hat_color',pa.Color],['accessory','accessories_type',pa.AccessoriesType],['nose','nose_type',pa.NoseType],['eyebrows','eyebrow_type',pa.EyebrowType],
|
||||||
|
['hair dress','top_type',pa.TopType],['clothes', 'clothe_type', pa.ClotheType],['clothe color','clothe_color', pa.Color],['clothe graphics','clothe_graphic_type',pa.ClotheGraphicType]
|
||||||
|
]
|
||||||
|
|
||||||
|
_df = pd.DataFrame(_df,columns=['label','variable','values'])
|
||||||
|
_df.to_csv('/home/steve/me.avatar.csv',index=False)
|
||||||
|
def _parameters():
|
||||||
|
_out = {'basic':{},'face':{},'clothes':{}}
|
||||||
|
for _index in np.arange(_df.shape[0]) :
|
||||||
|
row = _df.iloc[_index]
|
||||||
|
key = row['label']
|
||||||
|
if key in ['race','nose','mouth','eyebrows','eye type'] :
|
||||||
|
_id = 'basic'
|
||||||
|
elif 'clothe' in key or key=='accessory':
|
||||||
|
_id = 'clothes'
|
||||||
|
else:
|
||||||
|
_id = 'face'
|
||||||
|
if len( list(row['values'])) < 2 :
|
||||||
|
continue
|
||||||
|
_out[_id][key] = {'values': [{'name':_item.name.replace('_', ' '),'value':_item.value} for _item in row['values']],'variable':row['variable']}
|
||||||
|
|
||||||
|
|
||||||
|
return _out
|
||||||
|
def cast(_args) :
|
||||||
|
_params = {}
|
||||||
|
for key in _args :
|
||||||
|
value = int(_args[key])
|
||||||
|
|
||||||
|
_info = _df[_df.variable == key].copy()
|
||||||
|
if _info.shape[0] > 0 :
|
||||||
|
_params[key] = list(_info['values'].tolist()[0])[value]
|
||||||
|
# _params[key] = _info['values'].tolist()[value]
|
||||||
|
return _params
|
||||||
|
# def _xparameters() :
|
||||||
|
# """
|
||||||
|
# This function returns parameters to be used within an HTML context
|
||||||
|
# """
|
||||||
|
# _orgout = {'basic':{},'extended':{}}
|
||||||
|
# _out = {}
|
||||||
|
# for _key in _map :
|
||||||
|
|
||||||
|
# # _out[_key] = {'class':_map[_key].__name__,'values':[],"variable":_vmap[_key]}
|
||||||
|
# # _out[_key]['values'] = [{'name':_item.name.replace('_', ' '),'value':_item.value} for _item in _map[_key]]
|
||||||
|
# if _key == 'nose' :
|
||||||
|
# continue
|
||||||
|
# if _key in ['race','nose','mouth','eyebrows','eye type'] :
|
||||||
|
# _out = _orgout['basic']
|
||||||
|
# else:
|
||||||
|
# _out = _orgout['extended']
|
||||||
|
# _out[_key] = {'class':_map[_key].__name__,'values':[],"variable":_vmap[_key]}
|
||||||
|
# _out[_key]['values'] = [{'name':_item.name.replace('_', ' '),'value':_item.value} for _item in _map[_key]]
|
||||||
|
|
||||||
|
# # return _out
|
||||||
|
# return _orgout
|
||||||
|
|
||||||
|
def _build (_args):
|
||||||
|
"""
|
||||||
|
This function builds the avatar with a set of arguments
|
||||||
|
"""
|
||||||
|
|
||||||
|
_args = cast(_args)
|
||||||
|
if _args :
|
||||||
|
|
||||||
|
_avatar = Avatar(**_args)
|
||||||
|
_stream = _avatar.render_png()
|
||||||
|
_stream =io.BytesIO(_stream)
|
||||||
|
|
||||||
|
_stream = base64.encodebytes(_stream.getvalue()).decode('ascii')
|
||||||
|
else:
|
||||||
|
_stream = None
|
||||||
|
return _stream
|
||||||
|
def _save(_args):
|
||||||
|
"""
|
||||||
|
This function will save the data/candidate to the database
|
||||||
|
:_args {alias,email,stream}
|
||||||
|
"""
|
||||||
|
|
||||||
|
writer = transport.factory.instance(provider=providers.MONGO,context='write',db='genomix',doc='participants')
|
||||||
|
reader = transport.factory.instance(provider=providers.MONGO,context='read',db='genomix',doc='participants')
|
||||||
|
|
||||||
|
#
|
||||||
|
# Let us make sure the candidate doesn't exist
|
||||||
|
_df = reader.read(mongo={"find":"participants","filter":{"alias":_args['alias']},"projection":{"_id":0}})
|
||||||
|
_info = None
|
||||||
|
try:
|
||||||
|
if _df.shape[0] == 0 :
|
||||||
|
writer.write(_args)
|
||||||
|
else:
|
||||||
|
writer.set(_args)
|
||||||
|
_info = "1"
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
return _info
|
||||||
|
|
||||||
|
def _participants ():
|
||||||
|
reader = transport.factory.instance(provider=providers.MONGO,context='read',db='genomix',doc='participants')
|
||||||
|
_df = reader.read(mongo={"find":"participants","limit":10,"projection":{"_id":0}})
|
||||||
|
return _df.to_dict(orient='records')
|
|
@ -0,0 +1,40 @@
|
||||||
|
<style>
|
||||||
|
.dialog {min-width:500px}
|
||||||
|
.dialog .title-bar {display: grid; grid-template-columns: auto 48px; gap:2px;
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
align-items:center;
|
||||||
|
padding:4px;
|
||||||
|
text-transform:capitalize;
|
||||||
|
}
|
||||||
|
.button {width:60%; margin-left:20%; background-color:#f3f3f3; }
|
||||||
|
.message {display:grid; grid-template-columns: 48px auto; gap:2px; align-items: center; padding:8px}
|
||||||
|
.fa-xmark { color:maroon}
|
||||||
|
.fa-triangle-exclamation {color:#FF6500}
|
||||||
|
.icon {font-size:48px;}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="dialog">
|
||||||
|
<div class="title-bar">
|
||||||
|
<div class="bold border-right" ><i></i>:title</div>
|
||||||
|
<div align="center" class="active" onclick="$('.jxmodal').slideUp()" style="background-color: #f3f3f3;">
|
||||||
|
<i class="fa fa-xmark"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
<div class="message">
|
||||||
|
<div class="icon"><i class=":icon"></i></div>
|
||||||
|
<span>:message</span>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
<div class="button border-round border" align="center">
|
||||||
|
<div class="active"><i class="fa-solid fa-check"></i> Okay</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,166 @@
|
||||||
|
<style>
|
||||||
|
.studio-pane {
|
||||||
|
height:99%;
|
||||||
|
}
|
||||||
|
.bold {font-weight:bold}
|
||||||
|
.studio {
|
||||||
|
display:grid;
|
||||||
|
grid-template-columns: 45% auto;
|
||||||
|
gap:10px;
|
||||||
|
align-content: unset;
|
||||||
|
height:90%;
|
||||||
|
|
||||||
|
}
|
||||||
|
.studio-menu {
|
||||||
|
display:grid;
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
gap:2px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.studio-menu div {background-color: #f3f3f3;;}
|
||||||
|
.studio-menu {
|
||||||
|
display:grid;
|
||||||
|
grid-template-columns: repeat(3,1fr) 48px; gap:2px;
|
||||||
|
padding:4px;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
.section {display:none}
|
||||||
|
.choice {
|
||||||
|
padding:4px;
|
||||||
|
margin:4px;
|
||||||
|
display:grid;
|
||||||
|
grid-template-columns:30% auto; gap:2px;
|
||||||
|
|
||||||
|
cursor:pointer;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choice select {width:98%; border-color:transparent; padding:4px;}
|
||||||
|
|
||||||
|
.choice .label {
|
||||||
|
|
||||||
|
text-align: left;;
|
||||||
|
font-weight:bold; text-transform: capitalize;}
|
||||||
|
|
||||||
|
.avatar-frame {
|
||||||
|
padding:8px;
|
||||||
|
display:grid;
|
||||||
|
grid-template-rows: auto 32px;
|
||||||
|
gap:10px;
|
||||||
|
align-items:center;
|
||||||
|
align-content: center;;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-check {color:green}
|
||||||
|
.fa-xmark {color:maroon}
|
||||||
|
|
||||||
|
.login .form input {
|
||||||
|
padding:8px;
|
||||||
|
border-color:transparent;
|
||||||
|
background-color:#f3f3f3;
|
||||||
|
width:90%;
|
||||||
|
margin:4px;
|
||||||
|
outline: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="static/js/studio.js"></script>
|
||||||
|
<div class="studio-pane">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="studio">
|
||||||
|
<div class=" avatar-frame">
|
||||||
|
<!-- Image goes here -->
|
||||||
|
<div class="border-right"><img id="image"/></div>
|
||||||
|
<div class="button">
|
||||||
|
<div class=" border-round border" onclick="_open('login')">
|
||||||
|
<div class="active bold">
|
||||||
|
<i class="fa-solid fa-floppy-disk"></i>
|
||||||
|
Save & Continue
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="">
|
||||||
|
|
||||||
|
{%set _params = routes['api/studio/_parameters']() %}
|
||||||
|
{%set sections = _params.keys() %}
|
||||||
|
<div class="studio-menu">
|
||||||
|
{%for _name in sections %}
|
||||||
|
<div class="active" onclick="_open('{{_name|safe}}')">{{_name}}</div>
|
||||||
|
{%endfor%}
|
||||||
|
<div class="active" onclick="_reset()"><i class="fa fa-xmark"></i></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<div id="section-label" class="large-text" align="left" style="font-weight:bold; text-transform:capitalize"></div>
|
||||||
|
</p>
|
||||||
|
{%for _key in _params %}
|
||||||
|
|
||||||
|
{%set _iparams = _params[_key] %}
|
||||||
|
<div class="">
|
||||||
|
|
||||||
|
<div class="{{_key}} section border border-round">
|
||||||
|
{%for _name in _iparams%}
|
||||||
|
|
||||||
|
<div class="choice">
|
||||||
|
<div class="label">{{_name|safe}}</div>
|
||||||
|
{%set values = _iparams[_name]['values'] %}
|
||||||
|
<div class="selection">
|
||||||
|
<select class="selected_item" name="{{_iparams[_name]['variable']}}" onchange="_build()">
|
||||||
|
{%for _item in values %}
|
||||||
|
<option value={{_item.value|int}}>{{_item.name}}</option>
|
||||||
|
{%endfor%}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{%endfor%}
|
||||||
|
</div>
|
||||||
|
{% if loop.index == 3 %}
|
||||||
|
<script>
|
||||||
|
// _open('{{_key|safe}}')
|
||||||
|
// _build()
|
||||||
|
_reset()
|
||||||
|
</script>
|
||||||
|
{%endif%}
|
||||||
|
</div>
|
||||||
|
{%endfor%}
|
||||||
|
<!-- Login Form-->
|
||||||
|
<div class="login section border-round border">
|
||||||
|
<p>
|
||||||
|
<div align="left">
|
||||||
|
<ul>
|
||||||
|
<li>Cancel to make changes</li>
|
||||||
|
<li>Continue to the experiment</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<div class="form">
|
||||||
|
<input type="text" id="alias" placeholder="Name/Alias"/>
|
||||||
|
<input type="text" id="email" placeholder="[Email]"/>
|
||||||
|
</div>
|
||||||
|
<div style="margin-left:3%; margin-right:3%;margin-top:2%; margin-bottom:2%; display:grid; grid-template-columns:auto auto; gap:10px;">
|
||||||
|
<div class="border-round border">
|
||||||
|
<div class="active bold" onclick="_open('basic')">
|
||||||
|
<i class="fa-solid fa-xmark"></i>
|
||||||
|
Cancel
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="border-round border">
|
||||||
|
<div class="active bold" onclick="_save()">
|
||||||
|
<i class="fa-solid fa-check"></i>
|
||||||
|
Continue
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- End of Login Form-->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
|
||||||
|
<link href="{{context}}/static/css/default.css" type="text/css" rel="stylesheet">
|
||||||
|
<link href="{{context}}/static/css/border.css" type="text/css" rel="stylesheet">
|
||||||
|
<link href="{{context}}/static/css/border.css" type="text/css" rel="stylesheet">
|
||||||
|
<script src="{{system.context}}/static/js/fontawesome/js/all.js"></script>
|
||||||
|
<script src="{{system.context}}/static/js/jquery/jquery.js"></script>
|
||||||
|
<script src="{{system.context}}/static/js/search.js"></script>
|
||||||
|
<script src="{{system.context}}/static/js/jx/dom.js"></script>
|
||||||
|
<script src="{{system.context}}/static/js/jx/utils.js"></script>
|
||||||
|
<style>
|
||||||
|
.album {
|
||||||
|
height:75%;
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.album-pane {display:grid; grid-template-columns: repeat(2,1fr); gap:4px;
|
||||||
|
font-weight:lighter;
|
||||||
|
min-height:101%;
|
||||||
|
|
||||||
|
}
|
||||||
|
.album img {width:150px; margin:4px;}
|
||||||
|
|
||||||
|
.search {padding:4px; display:grid; grid-template-columns: auto 32px 48px; gap:2px; align-items:center;;}
|
||||||
|
.search input[type=text] {padding:4px; outline:0px; border-color:transparent; background-color:#f3f3f3; width:100%;}
|
||||||
|
.search .found {color:maroon; font-family:courier; font-size:14px; }
|
||||||
|
</style>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
{%set _participants = routes['api/studio/_participants']()%}
|
||||||
|
<div class="search border-bottom">
|
||||||
|
<div>
|
||||||
|
<input type="text" id="search" class="search" placeholder="[search by alias]" onkeypress="search.find('album-pane','search')"/>
|
||||||
|
</div>
|
||||||
|
<div class="active" align="center" style="background-color:#f3f3f3" onclick="jx.dom.set.value('search',''); search.find('album-pane','search')">
|
||||||
|
<i class="fa-solid fa-trash"></i>
|
||||||
|
</div>
|
||||||
|
<div class="found" align="center" style="display:grid; align-items:center; background-color:#f3f3f3; height:100%; text-align: center">
|
||||||
|
<div id="found">{{_participants|length}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="album" >
|
||||||
|
|
||||||
|
<div class="album-pane" id="album-pane">
|
||||||
|
|
||||||
|
{%for _user in _participants %}
|
||||||
|
|
||||||
|
<div data="{{_user.alias|safe}}" style=";">
|
||||||
|
<div align="center">
|
||||||
|
<img src="{{_user.png|safe}}"/>
|
||||||
|
</div>
|
||||||
|
<div class="border-top">
|
||||||
|
<div class="bold" >{{_user.alias}}</div>
|
||||||
|
<div class="small">{{_user.email}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{%endfor%}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
Binary file not shown.
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 5.0 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 8.1 KiB |
|
@ -0,0 +1,99 @@
|
||||||
|
var _build = function(){
|
||||||
|
var _nodes = $('.selected_item :selected')
|
||||||
|
var _body = {}
|
||||||
|
jx.utils.patterns.visitor(_nodes,function(_item){
|
||||||
|
if (_item.selected == true){
|
||||||
|
var _name = _item.parentNode.name ;
|
||||||
|
var _value = _item.value
|
||||||
|
_body[_name] = parseInt(_value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//
|
||||||
|
// Let us submit the payload and and render the image
|
||||||
|
var http = HttpClient.instance()
|
||||||
|
http.setHeader('Content-Type','application/json')
|
||||||
|
http.setData (JSON.stringify(_body))
|
||||||
|
http.post('/api/studio/_build',function(x){
|
||||||
|
stream = 'data:image/png;base64,' + x.responseText
|
||||||
|
jx.dom.set.attribute('image','src',stream)
|
||||||
|
// jx.dom.set.attribute('_avatar2','src',stream)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var _open = function(_id){
|
||||||
|
$('.studio .section').hide()
|
||||||
|
$('.studio .'+_id.trim()).slideDown()
|
||||||
|
jx.dom.set.value('section-label',_id)
|
||||||
|
if (_id == 'login'){
|
||||||
|
$('.button').hide()
|
||||||
|
}else{
|
||||||
|
$('.button').show()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_save = function(){
|
||||||
|
var _stream = jx.dom.get.attribute('image','src')
|
||||||
|
var _alias = jx.dom.get.value('alias').trim().toLowerCase()
|
||||||
|
var _email= jx.dom.get.value('email').trim().toLowerCase()
|
||||||
|
var _body = {email:_email,alias:_alias,png:_stream,'_args':{}}
|
||||||
|
var _nodes = $('.selected_item :selected')
|
||||||
|
if (_alias.match(/^[a-z]{3,}$/) == null || _email.match(/^[a-z,0-9,.,-]+\@[a-z,0-9,-]{2,}\.[a-z]{2,3}$/) == null){
|
||||||
|
_message = (['The alias and/or email are invlaid, Please enter correct alias and/or email','<ul><li>alias must be at least 3 characters</li><li>Email must be properly formatted</li></ul>']).join('')
|
||||||
|
_dialog('Error found','fa-solid fa-xmark',_message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
jx.utils.patterns.visitor(_nodes,function(_item){
|
||||||
|
if (_item.selected == true){
|
||||||
|
var _name = _item.parentNode.name ;
|
||||||
|
var _value = _item.value
|
||||||
|
_body._args[_name] = parseInt(_value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
http = HttpClient.instance()
|
||||||
|
http.setHeader('content-type','application/json')
|
||||||
|
http.setData(JSON.stringify(_body))
|
||||||
|
http.post('/api/studio/_save',function(x){
|
||||||
|
if(x.status == 200){
|
||||||
|
//
|
||||||
|
//
|
||||||
|
_message = (['An avatar for ',_alias,'has been saved/updated']).join(' ')
|
||||||
|
|
||||||
|
_icon = 'fa-solid fa-floppy-disk'
|
||||||
|
_pointer = function(){_reset(); $('.jxmodal').slideUp()}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
_message = (['An avatar for ',_alias,'has failed to be added']).join(' ')
|
||||||
|
_icon = 'fa-solid fa-xmark'
|
||||||
|
_pointer = null;
|
||||||
|
}
|
||||||
|
_dialog('New Avatar',_icon,_message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dialog = function(title,icon,msg,_pointer){
|
||||||
|
var http = HttpClient.instance()
|
||||||
|
http.setHeader('uri','dialog.html')
|
||||||
|
http.setHeader('dom','_dialog')
|
||||||
|
http.post('/page',function(x){
|
||||||
|
var _html = x.responseText.replace(/:title/,title).replace(/:message/,msg).replace(/:icon/,icon)
|
||||||
|
jx.modal.show({html:_html,id:'_dialog'})
|
||||||
|
if (_pointer == null){
|
||||||
|
_pointer = function(){$('.jxmodal').slideUp()}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$('.dialog .button').on('click',function(){
|
||||||
|
_pointer()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _reset = function(){
|
||||||
|
$("option:selected").prop("selected", false)
|
||||||
|
// jx.dom.set.attribute('image','src','')
|
||||||
|
_open('basic')
|
||||||
|
_build()
|
||||||
|
}
|
|
@ -1,10 +1,26 @@
|
||||||
<div class="border border-round">
|
|
||||||
<div class="bold">Latest News</div>
|
<div class="border-round border">
|
||||||
</div>
|
<div class="bold">New here ?</div>
|
||||||
<p></p>
|
<ul>
|
||||||
<div class="border border-round">
|
<li>Create an Avatar</li>
|
||||||
<div class="bold">
|
<li>Save the avatar, and continue to the experiment</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
_anouncement
|
<p></p>
|
||||||
|
<div class="border-round border">
|
||||||
|
<div class="bold">About Genomix Privacy</div>
|
||||||
|
<ul>
|
||||||
|
<li>Experiments around decision making</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<p></p>
|
||||||
|
<style>
|
||||||
|
_iframe {border:0; width:100%; height:400px;}
|
||||||
|
</style>
|
||||||
|
<div class="border-round border">
|
||||||
|
<div class="bold">Existing Avatars</div>
|
||||||
|
<iframe width="100%" height="255px" scrolling="no" src="/page?uri=participants.html" frameborder="0" allowfullscreen></iframe>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue