"ruby.wasmでブラウザを酷使してみよう " 松江Ruby会議10での登壇資料です。 https://matsue.rubyist.net/matrk10/
当日使用したデモページはこちら https://lnit.github.io/ruby-wasm-pages/engine/
SVCZXBTNͰϒϥβΛࠅͯ͠ΈΑ͏দߐ3VCZձٞ!MOJ@5ϧχ
View Slide
ࣗݾհw 5XJUUFS 9*%!MOJ@5w ډॅ౦ژw 3VCZྺʙݱࡏw 3VCZd3VCZw 3VCZͬͯΔ͚ͲদߐʹདྷΔͷॳͰ͢ʂ
͓͠͝ͱ .FE1FFSαʔόʔαΠυϦʔυΤϯδχΞ ۀ༰ SBJMTOFX͔ΒσϓϩΠอक·ͰରԠ ୂ͕ෆ͍ͯ͠Δࣄۀʹೖͬͯ ͳΜ͔ྑ͍ײ͡ʹՐফ͠Λͯ͠ϦϦʔε ศར͞Μঢ়ଶʂ
ࠓSVCZXBTNͷΛ͠·͢
SVCZXBTN͓͞Β͍
SVCZXBTN͓͞Β͍IUUQTSVCZLBJHJPSHQSFTFOUBUJPOTLBUFJOPJHBLVLVOIUNM
SVCZXBTNͱ ϒϥβ্Ͱ3VCZ͕ಈ͘ ͦͷଞ8FC"TTFNCMZϥϯλΠϜͰ3VCZ͕ಈ͘
3VCZͷ8BTN࣮ߦϑϩʔSVCZXBTN3VCZΠϯλϓϦλ$3VCZϒϥβBQQSC
3VCZͱڞʹॳϦϦʔε
SVCZXBTN WϦϦʔε "1*Ճ҆ఆੑ্
SVCZXBTN WϦϦʔε ػೳՃɺTUBDLTJ[Fؔ࿈Τϥʔͷվળ
͓͞Β͍ɹ͓ΘΓ
ࠓͷ͓
SVCZXBTNͰϒϥβΛࠅͯ͠ΈΑ͏
ͳͥࠅ͢Δͷ͔
SVCZXBTN "1*ͷՃͱɺ҆ఆੑͷվળͱɺόάमਖ਼
SVCZXBTN "1*ͷՃͱɺ҆ఆੑͷվળͱɺόάमਖ਼ ;ʔΜͦ͏ͳͷ͔ʜʜ
Կ͕มΘ͔ͬͨ ͔Βͳ͍
ͨΊͦ͏ʂ
%FNP
%FNPw IUUQTMOJUHJUIVCJPSVCZXBTNQBHFTEFNPw Ξχϝʔγϣϯ Τϥʔେྔw IUUQTMOJUHJUIVCJPSVCZXBTNQBHFTEFNPMBUFTUIUNMw Ξχϝʔγϣϯ Τϥʔݮগ
࣮ݧ݁Ռ 3VCZ,BJHJ࣌ͷSVCZXBTN େྔʹFWBM͢Δͱͳ͔ͥΤϥʔ͕ൃੜ͢Δ
࣮ݧ݁Ռ ࠷৽൛ʹ͢Δ͚ͩͰվળ͞ΕͯΔʂ ҆ఆੑͷ্
ࠅ͢Δͱ͔Δ͜ͱ͕͋Δ
͔Βͳ͍͜ͱ͕͔Δͱʜʜͨͷ͍͠ʂ
͍ࠐΜͰΈΑ͏
SVCZXBTNೖ
νϡʔτϦΞϧIUUQTHJUIVCDPNSVCZSVCZXBTN
νϡʔτϦΞϧw OQNͰఏڙ͞Ε͍ͯΔTDSJQUΛಡΈࠐΉw TDSJQUλάʹSVCZΛॻ͘ɹҎ্ʂ<br/>puts "Hello, world!"<br/>
νϡʔτϦΞϧ SCϑΝΠϧΛTSDʹ͢Δ͜ͱՄೳ
3VCZ͔Β+4ͷੈքΛૢ࡞ SFRVJSFKT͢Δrequire "js"window = JS.global[:window]window.alert "Hello, world!"
४උສʂ͍Ζ͍ΖͬͯΈΑ͏
ϒϥβͷΠϕϯτΛरͬͯΈΑ͏
%FNPw IUUQTMOJUHJUIVCJPSVCZXBTNQBHFTEFNPw JOQVUͷDIBOHFΠϕϯτΛर͏σϞ
ೖྗʹԠ͢ΔόϦσʔγϣϯ͕Ͱ͖ͨ
EPDVNFOUΛ͏ ʮEPDVNFOUʯʹΞΫηεͰ͖ΔΑ͏ʹ͢Δ +4HMPCBM<EPDVNFOU>
BEE&WFOU-JTUFOFS EPDVNFOUܦ༝Ͱऔಘͨ͠ΦϒδΣΫτʹ BEE&WFOU-JTUFOFSͰ͖Δ
BEE&WFOU-JTUFOFS όϦσʔγϣϯॲཧΛ࣮͢Εʂ
·ͩ·ͩংͷޱ
ϒϥβͷ"1*Λୟ͍ͯΈΑ͏
ϒϥβͷ"1*Λ࣮ߦ
DBOWBTΛѻ͏ʹ )5.-$BOWBT&MFNFOUHFU$POUFYU Λ࣮ߦ͢Δඞཁ͕͋Δ
DBOWBTΛѻ͏ʹ ͜ΕͰඳը༻ͷϝιου͕͍Ζ͍Ζ͑ΔΑ͏ʹͳΔ
ը໘ඳը͠์
ผͷ"1*ୟ͍ͯΈΑ͏
%FNPw IUUQTMOJUHJUIVCJPSVCZXBTNQBHFTEFNPw Ի͕ͳΔϘλϯ
3VCZͰԻΛ໐Β͢
8FC"VEJP"1* 8FC"VEJP"1* Σϒ্ͰԻΛѻ͏ͨΊͷڧྗͳγεςϜΛఏڙ Իͷ߹ɺಛघޮՌ ΤίʔͳͲͳͲ͕Ͱ͖Δ BVEJPλάΑΓߴػೳ
8FC"VEJP"1* +BWB4DSJQUͰ͏߹ɺ "VEJP$POUFYUͷΠϯελϯε͕ඞཁʹͳΔconst ctx = new AudioContext();
͔͠͠ࠔͬͨ͜ͱ͕
8FC"VEJP"1* +BWB4DSJQUͰ͏߹ɺ OFXԋࢉࢠͰΠϯελϯεΛ࡞͢Δ ͔͠͠ɺ3VCZʹOFX͕ͳ͍ʂconst ctx = new AudioContext();
͞Βʹࠔͬͨ͜ͱ͕
ԻΛμϯϩʔυ +BWB4DSJQUͷ߹ԻσʔλΛ 'FUDIͯ͠σίʔυ͢Δ͜ͱͰ࠶ੜՄೳconst response =await fetch("sound.mp3");const arrayBuffer =await response.arrayBuffer();const audioBuffer =await ctx.decodeAudioData(arrayBuffer);
ԻΛμϯϩʔυ +BWB4DSJQUͷ߹ԻσʔλΛ 'FUDIͯ͠σίʔυ͢Δ͜ͱͰ࠶ੜՄೳ ɹɹˢ+BWB4DSJQUʹ1SPNJTF͕͋Δ͕ ɹɹɹ3VCZʹ1SPNJTF͕ͳ͍ʂconst response =await fetch("sound.mp3");
3VCZੈքͱ+4ੈքͷִͨΓ͕ͭΒ͍
ղܾ͍ͯ͘͠
3VCZͰAOFXA͢Δ +4FWBMΛ͏͜ͱͰ+4ͷΠϯελϯεΛऔಘՄೳ OFXແ͍͜ΕͰճආՄೳ@ctx = JS.eval('return new AudioContext')
3VCZͰAOFXA͢Δ ͜ͷSVCZXBTNWͰղফ͞Εͯ FWBMͳ͠ͰOFXͰ͖ΔΑ͏ʹͳΓ·ͨ͠ʂ@ctx = JS.global[:AudioContext].new
3VCZͰABXBJUA͢Δ +BWB4DSJQU͔ΒFWBM"TZODͰ࣮ߦ͢Δ͜ͱͰ ʮBXBJUʯ͕Ͱ͖ΔΑ͏ʹͳ͍ͬͯΔ ͕ɺΊΜͲ͏͍͘͞ʜwindow.rubyVM.evalAsync(`path = "sound.mp3"JS.global.fetch(path).await`)
3VCZͰABXBJUA͢Δ SVCZXBTNͰ TDSJQUʹEBUBFWBMBTZODΛ͚ͭΔ͜ͱͰ BXBJU͕͑ΔΑ͏ʹͳͬͨʂdata-eval="async">
ͱ͍͏͜ͱͰ
3VCZͰԻ͕໐ΒͤΔʂ "VEJP$POUFYUͷΠϯελϯεΛ OFXϝιουͰ࡞
3VCZͰԻ͕໐ΒͤΔʂ BXBJUΛͬͯԻσʔλΛGFUDIͯ͠σίʔυ
3VCZͰԻ͕໐ΒͤΔʂ σίʔυͨ͠ԻΛग़ྗʹܨ͍Ͱ࠶ੜ͢Εྃʂ
SVCZXBTNʹʹػೳ͕૿͍͑ͯ·͢
࠷৽ػೳ࠷৽ϦϦʔεʹ 63-Ͱλά໊Λࢦఆͯ͠ར༻͢Δ͜ͱͰɺ ৗʹ࠷৽൛Λ͏͜ͱ͕Ͱ͖Δ MBUFTUW ຊ࣌ OFYU࠷৽ϦϦʔεόʔδϣϯ
OFYUΛ͏͜ͱͰ࠷େݶͷࠅ͕Մೳʹʂ&EHFWFSTJPO࠷ߴʂ
͜Ε·Ͱ࣮ݱͨ͠ͷ Ϣʔβʔૢ࡞Λड͚औΔ ը૾Λग़ྗ͢Δ ԻΛग़ྗ͢Δ
Έ߹ΘͤΔͱʜʜ
%FNPw IUUQTMOJUHJUIVCJPSVCZXBTNQBHFTFOHJOFw SVCZXBTNͷήʔϜʂ
গ͚ͩ͠ੜKTΛར༻ Ξχϝʔγϣϯ͢ΔΑ͏ϒϥβʹ͑Δ͜ͱͰ ϝΠϯϧʔϓΛ࣮async function main( tFrame ) {const stopMain =window.requestAnimationFrame( main );vm.eval(`$scene.main`)}
ϒϥβº3VCZͰ͍Ζ͍ΖͰ͖Δʂ
͓ΘΓʹ
ϒϥβͷࠅͷͨΊʹ ·ͣ3&"%.&ʹैͬͯ ϒϥβͰ3VCZ͕ಈ͘Α͏ʹͯ͠ΈΑ͏ʂ SVCZίʔυ্ͰSFRVJSFKT͠Α͏ʂ ࠷৽൛ͷػೳΛ׆༻͠Α͏ʂ 3VCZͰ͖ͳॲཧΛ࣮͠Α͏ʂ
ϒϥβͰ3VCZΛ͏ͱͨͷ͍͠ʂ
એʂ ࠓޙͷొஃ༧ఆ ,BJHJPO3BJMT ۚ 5VSCPͰਝʹαʔϏεΛ্ཱͪ͛Δ
ΤϯδχΞ৬ͷํɹੵۃ࠾༻தʂҰॹʹϝυϐΞͷࣄۀΛ৳͍͖͍ͯͨ͠ΤϯδχΞͷํɺ͓͓ͪͯ͠Γ·͢ʂςοΫϒϩάIUUQTISNPTDPQBHFTNFEQFFSKPCTϦʔυΤϯδχΞʢαʔόʔαΠυʣ ΤϯδχΞհIUUQTFOHJOFFSNFEQFFSDPKQ IUUQTUFDINFEQFFSDPKQٻਓ ϒϩά