Three.js Tutorial For Absolute Beginners

Поделиться
HTML-код
  • Опубликовано: 31 дек 2024

Комментарии •

  • @WaelYasmina
    @WaelYasmina  2 года назад +40

    • Looking back *I don't recommend* that you use that method of importing models.
    Here's a way better method (the first half of the video): ruclips.net/video/f1RbD_wkGpc/видео.html
    *An even better way is to just use Vite*
    • Article: waelyasmina.net/articles/three-js-tutorial-for-absolute-beginners/
    • To run the server you need to run *npx parcel ./src/index.html* now instead of parcel ./src/index.html
    • Three.js r155 updates:
    1. You need way higher values for light intensity.
    example:
    const spotLight = new THREE.SpotLight(0xFFFFFF, 5000);
    2. For better output results, ensure to set the colorSpace property of the textures.
    Check out this video to learn more about color spaces: ruclips.net/video/6XvqaokjuYU/видео.html
    • The CubeTextureLoader requires images to have a 1:1 aspect ratio, meaning *each image should have the same height and width* .
    • This is the boilerplate that I'm using in my tutorials: github.com/WaelYasmina/ThreeBoilerplate

    • @SuperEdits-y5d
      @SuperEdits-y5d Год назад

      I can't do this parcel./src/index.html

    • @WaelYasmina
      @WaelYasmina  Год назад +1

      @@SuperEdits-y5d It's npx parcel ./src/index.html

    • @SuperEdits-y5d
      @SuperEdits-y5d Год назад

      @@WaelYasmina everything worked out thanks

    • @SuperEdits-y5d
      @SuperEdits-y5d Год назад

      @@WaelYasmina do you happen to have any telegrams

    • @SuperEdits-y5d
      @SuperEdits-y5d Год назад

      @@WaelYasmina I have something stopped working can you help

  • @helloWorld432Hz
    @helloWorld432Hz 2 года назад +30

    you don't know how hungry I was for these content dude... THANKS!! I'm lovin it!!!

  • @rgabriel5043
    @rgabriel5043 Год назад +8

    I like those kind of tutorial. Simple, explicit, but straight to the point. No stoopid intro, camera or cringe transitions

  • @here2code
    @here2code Год назад +22

    This is absolute gold! Thanks for putting this playlist together. This is now my entire learning journey for the next few months 🙌

  • @kubamatuszczak5619
    @kubamatuszczak5619 2 года назад +15

    I'm halfway through the tutorial and can definitely say it's the best three.js I've ever followed by far! Tried to get into it several times, even with some paid ones some time ago but just couldn't wrap my head around it.
    This one is super thorough and easy to follow, big kudos to You.

    • @mohammedhashim6242
      @mohammedhashim6242 Год назад

      Hey, did you face any issue with the spotlight not hitting the subject

    • @egedesolomon7454
      @egedesolomon7454 11 месяцев назад

      thanks for the review, was useful

    • @MikeBooger
      @MikeBooger 10 месяцев назад

      I faced the same problem, set spotLight.decay to 0 then voila; it cast lights now@@mohammedhashim6242

  • @icanada4
    @icanada4 2 года назад +15

    I am not very new to Three JS - but this video has definitely inspired me to do some more stuff in Three JS. Thank you!

  • @toannew
    @toannew 2 года назад +13

    4:00 how to remove the scrollbar in google chrome
    29:00 how to take the correct shadow
    31:10 solve the pixelaton of spotlight (pixelation: the shadow is not as expected)

  • @TinyMaths
    @TinyMaths 9 месяцев назад

    This video is a time saver; if only I watched this before I jumped into three.js a few days ago. I could have saved myself some headaches. Learned my lesson.
    I'm here to get a good grounding in the basics. Thank you!

  • @DarijanAvric
    @DarijanAvric 3 месяца назад

    Excellent channel, very clearly explained. You definitely deserve more subscribers and likes! Keep up the good work

  • @VivekTR
    @VivekTR 2 года назад +6

    Very well explained!!! You go into the meaning of every parameter and explain it with simple illustrations. Thank you for your effort.

  • @ttyu1999
    @ttyu1999 Год назад +2

    29:21 regarding the spotLight section,
    increasing the intensity value will result in a lighting effect.
    const spotLight = new THREE.SpotLight(0xFFFFFF);
    spotLight.position.set(-100, 100, 0);
    spotLight.castShadow = true;
    scene.add(spotLight);
    const options = {
    sphereColor: '#ffea00',
    wireframe: false,
    speed: 0.01,
    angle: 0.03,
    penumbra: 0.5,
    intensity: 50000
    };
    gui.add(options, 'intensity', 0, 100000);

  • @ColinRichardson
    @ColinRichardson 9 месяцев назад

    28:30 - DirectionalLightHelper(light) and CameraHelper(light.shadow.camera) are single handedly the best things I have learnt from all of this..
    This answered SO SO many questions I had been having and had given up on because it was "just acting weird"... Now I can SEE what is happening, and now I can see the camera was too big, and far/near was just all wrong..

  • @dzengiztafa510
    @dzengiztafa510 2 года назад +6

    This is by far the best tutorial on the subject. The allround 3d part was really helpful.
    Just found yr channel. I'm def following the entire series!

  • @d1mmat
    @d1mmat 9 месяцев назад

    This is how a tutorial should be. Thank you! Keep up the good work.

  • @tonyartz
    @tonyartz 2 года назад +35

    For those confused about their cube texture not working, make sure your texture is in 1:1 ratio, as in, it must be a square image and rectangles don't work, thought I would clarify since the source images provided are not square and you must crop it to make it work, hope it helps

    • @khantzawhein2605
      @khantzawhein2605 2 года назад +1

      Bro how do you solve that error?

    • @khantzawhein2605
      @khantzawhein2605 2 года назад +1

      My cube texture also not working.

    • @tonyartz
      @tonyartz 2 года назад

      @@khantzawhein2605 which texture are you using ?

    • @thespiritcode4006
      @thespiritcode4006 2 года назад +7

      You're a life saver man. I was stuck on this!

    • @kyrregjerstad
      @kyrregjerstad Год назад +1

      Thanks for this, couldn't figure out why it didn't load!

  • @thihahtunnaing5999
    @thihahtunnaing5999 2 года назад +4

    Only half-way through the video and I already understand what three.js is capable of.
    Very nice explanation and this is a really brilliant video. You got a new subscriber!
    Please keep up videos like this.

  • @abrahamsito
    @abrahamsito 2 года назад +7

    Excellent tutorial, a very complete introduction to this incredible library :)

    • @WaelYasmina
      @WaelYasmina  2 года назад +1

      I'm glad you think so, thank you Abraham!

  • @AhmedIbrahim-fi2so
    @AhmedIbrahim-fi2so 3 года назад +2

    thanks a lot .. 💙
    free three js tutorials are very rare on youtub

    • @WaelYasmina
      @WaelYasmina  3 года назад +7

      Keep an eye on the channel, because I'll make sure they will not stay as rare as they have been ;)

  • @darkside3ng
    @darkside3ng Год назад +1

    this is an amazing job!!!!! Your really clearly explained very well and I loved the evolution of the content description.
    Thank you so much. :) :) :)

  • @ahmadbasemalhakimshiham7827
    @ahmadbasemalhakimshiham7827 2 года назад

    TNice tutorials is THE most helpful tutorial on RUclips imo. I am starting production in Hardstyle, and I find soft soft really useful

  • @arabicman866
    @arabicman866 Год назад

    I just clicked your video, and my god, did i skip anything? You did succeed helping me understand this amazing library ❤

  • @김규태-n7f
    @김규태-n7f 8 месяцев назад +4

    About spot light, current documentation clearly states that the default decay is 1, and if you want a constant intensity irrespective of distance, you should set decay to 0.

    • @xt3rm1nat0r8
      @xt3rm1nat0r8 7 месяцев назад

      Is that why lights seem kinda darker at my side than his? everything looks lot darker than it looks in the video

    • @etab4424
      @etab4424 7 месяцев назад

      Thank sir

  • @muzi-the-bushi4516
    @muzi-the-bushi4516 Год назад +1

    I thank you so much for what you are doing, this has been the most helpful source material to learn Three. Js

  • @matinsurchi2986
    @matinsurchi2986 Год назад

    this is the most perfect tutorial I've ever seen, great work!

  • @Arkvis10
    @Arkvis10 Год назад

    simply the best three.js tutorial out there! thanks man.

  • @mohamadrayan
    @mohamadrayan 2 года назад

    شكرا جزيلا يا بيه
    This is so great brother straight to the point and very organized/informational.

  • @sanarahman6996
    @sanarahman6996 Год назад

    perfect tutorial for learning, just play with the values to get a better idea

  • @nando4070
    @nando4070 Месяц назад

    What a great intro! Thank you!

  • @b3rt1e13
    @b3rt1e13 2 года назад +3

    Fantastic tutorial, well explained/organized. thanks so much

  • @_sonu_
    @_sonu_ 2 года назад +1

    I really Love this video how he have explained, camera, Sean, position, look at etc ❣❤❤❤

  • @valentinkrajzelman4649
    @valentinkrajzelman4649 Год назад +8

    for those who are having touble with the mouse recognition, the code in the video is slightly wrong, maybe it was corrected afterwards and i didnt see it, but to get the mouse position in the screen is:
    const mousePosition = new three.Vector2;
    window.addEventListener('mousemove', function(e){
    mousePosition.x = (e.clientX / window.innerWidth) * 2 - 1;
    mousePosition.y = (e.clientY / window.innerHeight ) * -2 + 1;
    })
    notice the -2 that was missing before, also make sure the size of the renderer is the same as the window, if not, this snippet is useless

    • @basilekamm3329
      @basilekamm3329 Год назад

      Thanks a lot for that

    • @JimmyJazz5964
      @JimmyJazz5964 11 месяцев назад

      For some unknown reason, on refresh, I get (phantom arrays) an 'intersects' array of length 10 and then a series of array lengths 8, even though my mouse was off the page. My sphere was included in these arrays which meant it coloured red from the start. I had to hack this workaround before I could get it to work :-
      if (intersects.length < 8) {
      for (let i = 0; i < intersects.length; i++) {
      if (intersects[i].object.uuid === sphereId) {
      intersects[i].object.material.color.set(0xFF0000);
      };
      };
      };
      Maybe if someone knows why I'm getting these phantom arrays in the first place, I can remove my hack.

    • @JimmyJazz5964
      @JimmyJazz5964 11 месяцев назад

      These phantom arrays continue until I move the cursor across the page. It then reverts to an empty array untill I move the cursor over an object(s).

    • @gbadamosimateen940
      @gbadamosimateen940 8 месяцев назад

      Thanks so much, you're a life saver. I was on the verge on giving up when I saw your comment. I can't thank you enough

    • @valentinkrajzelman4649
      @valentinkrajzelman4649 8 месяцев назад

      @@gbadamosimateen940 👍

  • @jonathanmaquenhem6351
    @jonathanmaquenhem6351 9 месяцев назад +1

    Hello, thanks for your video ! Have just a problem for shadow and light for (first) plane in moment you change MeshBasicMaterial into MeshStandardMaterial. My scene is very dark and i dont see shadow to sphere.

  • @ya_boj
    @ya_boj 9 дней назад

    You helped me out a lot. Thank you very much!

  • @hanhtrangtvt227
    @hanhtrangtvt227 Год назад +1

    25:35 after add(directionalLight) my plane color doesnt turn to light, it's gray and grid show on bottom plane ???

    • @romasbitinas643
      @romasbitinas643 10 месяцев назад +1

      There were some breaking changes in three.js, apparently, because your issue is related to newer versions. A possible solution is to downgrade to 0.133.0 version by run command "npm install three@0.133.0"

  • @rizqyhbb
    @rizqyhbb 2 года назад

    This is so so deep, detail and complete lesson, thankyou for providing this

  • @clydeeisenbeis8625
    @clydeeisenbeis8625 Год назад

    The "parcel ./src/index.html" did not work (3:17). The "npx parcel src/index.html" did work. Excellent video! The only YT video, I found, that actually works!

    • @ottaviano007
      @ottaviano007 7 месяцев назад

      I used the comand but it still didnt worked. It tells me "Failed to resolve 'main.css' from './src/index.html' even after i deleted the css

  • @MuhammadHammad-n3g
    @MuhammadHammad-n3g 7 месяцев назад

    Thank You sir! Your teaching method is amazing. I have learnt a lot.

  • @toannew
    @toannew 2 года назад +1

    Thank you very much ! Very helpful !
    Please make next serie on the immediate or advanced levels.

  • @RmaNYouTube
    @RmaNYouTube Год назад

    this really looks cumbersome in oppose to game engines or 3D applications. such a headacge for simple tasls.

  • @atleast_me
    @atleast_me Месяц назад

    Yes sir, you succeeded to teach us. Thanks so much

  • @ridhamsharma618
    @ridhamsharma618 2 года назад

    Thankyou brother i found the best tutorial for three js now.

  • @anarmusayev.4
    @anarmusayev.4 7 месяцев назад

    Great tips and insights here- Thanks for sharing!

  • @davisnoah8079
    @davisnoah8079 Год назад +16

    I had to add an intensity to the spotlight manually as it is undefined by default.
    I added it by initializing the spotlight like this:
    const spotLight = new THREE.SpotLight(0xFFFFFF, 100000);
    spotLight.position.set(-100, 100, 0);
    I hope this helps someone.

  • @LeanVasconcellosoficial
    @LeanVasconcellosoficial Год назад

    Thanks for this tutorial! It's amazing. You made my day!

  • @psy237
    @psy237 Год назад

    it's like using a 3D software! fantastic beginning of the tutorial! sad it stops when it gets interesting, hehe, but really good introduction, thanks a lot.
    edit:after having tried to get other peoples implementations i have to say, your tutorial rocks!! with all others I had quite problems often to even get it running in the first place, with another solution code-autocomplete didn't work, etc! Great Job on this tutorial :)

  • @AhmedMostafa-fc1od
    @AhmedMostafa-fc1od 2 года назад

    I think if this content translated to Arabic it will be one of the most successful content for Arab keep going and thanks for the way you explain every point

  • @trapma
    @trapma Год назад +1

    thank you very much for the tutorial, I think I found a small mistake. on the video "39:42", on the graph where the original coordinates are shown, instead of (480, 0) it should be (480, 476)

  • @phamvanmy2972
    @phamvanmy2972 2 года назад

    Thank you so much for this course, it's really great, good luck in your life!

  • @riddler112
    @riddler112 10 месяцев назад

    Could someone please explain why in "Selecting Objects from the scene" 40:27 he's put negative (-) at the beginning of the value for mousePosition.y? Why couldn't the value be the same as mousePositiong.x but having innerHeight instead of innerWidth, why did he have to put negative?

    • @jamesjames21215
      @jamesjames21215 10 месяцев назад

      I think because the direction of of window Y axis is reverse of the Camera

  • @danielraviv3914
    @danielraviv3914 Год назад +1

    hi great tutorial! i have trouble in 28:18 i did every thing like you did but i still cant see the shadow

    • @iilyaa
      @iilyaa Год назад

      Me too, did u find the issue?

  • @lionelguaregua820
    @lionelguaregua820 2 года назад

    Wow, this is amazing and well explained, good job here

  • @ashoketiwari2653
    @ashoketiwari2653 Год назад

    for the question at 30:55
    yes it still gives pixelated issue it was not ur computer performance issue

  • @rajsarojkerketta4590
    @rajsarojkerketta4590 2 месяца назад +1

    9:11 I don't know why when i want to use camera.position.z , there is no position property in the drop-down list
    Someone kindly help 🙏😭

    • @WaelYasmina
      @WaelYasmina  2 месяца назад +1

      Type it like that, save, then open the console and see if this gives you an error.

    • @rajsarojkerketta4590
      @rajsarojkerketta4590 2 месяца назад

      @@WaelYasmina yes it worked thank you very much 🙏♥️

  • @theman7050
    @theman7050 2 года назад

    You nailed it brother!!
    I suggest you please take some topics from Yuri Artiukh's channel and teach us those advanced Three.js concepts too down the line. Yuri explains well, but he does live sessions so his videos are all over 1 hour based on trial and error and not possible for the average man to devote time for. And the npm install thing he uses at the beginning gives a boiler plate with that rainbow coloured plain which he builds over. That I fail to understand.
    Thanks again and wishing you a bright future :D

    • @WaelYasmina
      @WaelYasmina  2 года назад +1

      Thank you!
      I'm actually not an expert, I started learning Three.js 10 or 11 months ago. The main idea of the channel is to share what I'm learning with other fellow beginners. And that by creating videos as answers/solutions to questions/problems I once faced. Which makes it easier for them to find the solution instead of putting their time into researching.
      Having said that, yes as long as I continue learning and experimenting the level will eventually slowly increase. Thus, I will be creating some cool unique stuff.

    • @theman7050
      @theman7050 2 года назад

      @@WaelYasmina awesome!!

    • @VivekTR
      @VivekTR 2 года назад

      ​@@WaelYasmina I was facing some of the same problems. You presented all the solutions I needed. I really appreciate you for doing this.

  • @mdiqbalhossain5330
    @mdiqbalhossain5330 2 года назад

    This is a very good tutorial i ever seen . many many thanks

  • @Florian-6464
    @Florian-6464 11 месяцев назад

    Thanks a lot for this very complete tutorial !

  • @mdamirul8518
    @mdamirul8518 2 года назад

    Thanks for the video, very helpful and well explained. Off to make so soft

  • @nguyendactung
    @nguyendactung 10 месяцев назад

    I dont even skip anything. Very wow tutorial

  • @g-git
    @g-git 10 месяцев назад

    Thank You very much! You are an amazing teacher!

  • @alihammad8667
    @alihammad8667 3 года назад +2

    Thank you so much for this amazing tutorial

  • @Nani-wq6th
    @Nani-wq6th Год назад

    This videos so helpful, thank you so much!!

  • @HuynhLuong227
    @HuynhLuong227 Год назад

    Last this video I hear you speak vertex shader and fragment, wait you make it. Thanks🎉🎉🎉

  • @Rock_Film
    @Rock_Film 11 месяцев назад

    Awesome! You are my precursor.

  • @msee254
    @msee254 Год назад

    I needed this. Thank you

  • @Artem-u5e9c
    @Artem-u5e9c Год назад

    Very useful! Thanks a lot, man!

  • @manjeshkumarsharma
    @manjeshkumarsharma 10 месяцев назад +1

    amazing tutorial

  • @LulululuZzzz
    @LulululuZzzz Год назад +1

    Why when I type npm init in the terminal it says the term npm is not recognized as the name of a cmdlet…

  • @ddthemaste
    @ddthemaste Год назад +1

    my package.json is :
    "devDependencies": {
    "parcel": "^2.8.3"
    },
    "dependencies": {
    "three": "^0.149.0"
    }
    however I still get error whenever I put CSS into my HTML. Could anyone tell me why?

  • @deepakgadwal008
    @deepakgadwal008 Год назад +1

    can anyone tell how they get black background which i dont get

  • @helloWorld432Hz
    @helloWorld432Hz 2 года назад

    about the spotlight shadow at 30:50, I know from blender that whats happening there is that its proyecting a bunch of shadows, as when u see the shadow of a large tubular fluorescent light that u get different shadows bc of the different points where light is emmited. At blender you cand fix this by getting the spotlight ratio to 1, idk if there is a way in threejs..

  • @yurinativo
    @yurinativo 2 года назад

    Awesome tutorial, great work man!

  • @taufiqibrahim
    @taufiqibrahim Год назад

    Very helpful explanation! Thanks

  • @ClovisNeto
    @ClovisNeto Год назад +2

    That is an amaaaaaazing explanation which covers everything I wanted to know about threejs. Thanks man!
    Ps: for who is struggling in understand the concepts of camera, lights raycasting and shaders, maybe taking a look on game development with Unity3d or Unreal might helps you to understand the basics. Agaubs tgabjs Wael, very nice video!

  • @glitched_code
    @glitched_code 2 года назад

    Very well made tutorial, thank you!

  • @karennunrein4320
    @karennunrein4320 2 года назад +1

    now i am in a good mood

  • @AjaxMinecraft16.
    @AjaxMinecraft16. 4 месяца назад

    great tutorial btw im using sublime text 4 and the browser sync extension and it works great. edit1:
    at 35:24 i had some issues with loading the images because im not using parcel so instead of doing import name from img file i instead did let name = img file.

  • @sghayeroumayma8506
    @sghayeroumayma8506 2 года назад

    Very good tutorial, clear and to the point.

  • @formidableFocus
    @formidableFocus Год назад

    Love this tutorial, thank you.

  • @Hacks536
    @Hacks536 2 месяца назад

    Great Tutorial!!

  • @here2code
    @here2code Год назад +1

    Any assistance will be hugely appreciated - at 3:20 it says to type "parcel ./src/index.html" in the terminal but when i press enter, it doesn't create a dist folder and says "zsh: command not found: parcel"? I've checked npm list and parcel is definitely loaded so unsure what the problem could be? it shows as parcel@2.8.3

    • @here2code
      @here2code Год назад +3

      if anyone else has run into this issue, I found the fix. instead of just running "parcel ./src/index.html" run "npx parcel ./src/index.html" instead and all will work fine

    • @ottaviano007
      @ottaviano007 7 месяцев назад

      ​@@here2code for me it didn't worked

  • @orxion
    @orxion 5 месяцев назад

    when in terminal, i dont see the left part .. with tabs, explorer, etc .. just the stuff like cmd

  • @djohnworthy1040
    @djohnworthy1040 10 месяцев назад

    Hey man I loved your content. I have a question? Are we able to get the wireframe from an object that we imported to the scene ? Also in 13:10 I want to use the wireframe and the completed object. So, the wireframe will wrap the ball. I think I am going to create 2 identical object one with wireframe and the other not, right?

  • @noer-man
    @noer-man Год назад +1

    many people helped with your tutorial, can you add a tutorial on adding custom animation from mixzamo to three js

  • @Jonasmelonas
    @Jonasmelonas 2 года назад +1

    Very nice tutorial, excellent visually. A tip for future videos is to make your voice a bit less monotone/sound less like youre talking from a script. And "talked" is not pronounced "tal-ked", its "taakt" :)

    • @WaelYasmina
      @WaelYasmina  2 года назад +1

      I'm actually reading from a script. It's hard for me to explain without one because I have to think how to say this in English and also what's going on in the video which so hard for someone who's not a native speaker unfortunately.
      But I'll try to fix that.
      Thank you for the tip!

  • @esgicoding.8555
    @esgicoding.8555 2 года назад

    I have follow an Udemy course and it's well explained as this one, also it's good that you use the helper, I have no idea what it's for previously

  • @agustinronchi6420
    @agustinronchi6420 Год назад

    When I use the type="module" on the script i have a problem in the website with cors, something about a policy, how can I fix that?? 1:55

  • @omnimathic
    @omnimathic Год назад

    Hello there, 31:00 I have the same pixeling of shadow with spot light

  • @tharindusandeepa4462
    @tharindusandeepa4462 2 года назад

    you are a good teacher ❤❤🙌🙌

  • @sporkspork8556
    @sporkspork8556 Год назад +1

    I am unable to load the .glb file and no instance of it is created in the dist folder when I save it.

    • @Lofibree
      @Lofibree Год назад

      You should try to import file intead of using URL class. At least It worked for me.

  • @dipankarsahoo7119
    @dipankarsahoo7119 2 года назад

    Thank you so much brother this is a great three.js tutorial

  • @cricorio3966
    @cricorio3966 14 дней назад

    Great tutorial♥♥♥

  • @erfanazkat2133
    @erfanazkat2133 2 года назад +1

    love it please make more advanced video

  • @ImperioAme
    @ImperioAme 2 года назад

    excellent tutorial. Thank you!

  • @AdityaKumar-cp7we
    @AdityaKumar-cp7we 5 месяцев назад +1

    I want to ask if I am learning web development is it helpful for me?

  • @satyamkilor6726
    @satyamkilor6726 3 месяца назад

    Can three js be used with node js and express? Because I tried to render models on ejs pages using node and express but I couldn't do it.

  • @halotroop2288
    @halotroop2288 Год назад

    I'm so confused as to why only MeshBasicMaterial works in the newest version of the library (0.157.0). If I changed it to any other Material, like MeshStandardMaterial or MeshPhongMaterial, my IDE tells me there's a type error (which should be impossible since it's not typescript?) and it doesn't render when I reload the page.

  • @sufyanali837
    @sufyanali837 Год назад

    in your videos , new feature of youtube audio track is not find.. why?

  • @webmasterashishgaur
    @webmasterashishgaur 2 года назад +1

    I was waiting for this type of tutorial series for so long thanks bro keep posting your good work, only I am unable to render cube geometry

  • @user-hm7pm3gp4w
    @user-hm7pm3gp4w 2 года назад

    Nice tutorial.... Very helpful

  • @elmapping6879
    @elmapping6879 2 года назад

    Really nice and helpful... Thanks!